diff --git a/core/examples/op2.js b/core/examples/op2.js new file mode 100644 index 000000000..5ff215361 --- /dev/null +++ b/core/examples/op2.js @@ -0,0 +1,3 @@ +globalThis.op2_sample = { + "use_state": (f) => Deno.core.ops.op_use_state(f), +}; diff --git a/core/examples/op2.rs b/core/examples/op2.rs new file mode 100644 index 000000000..101e1800a --- /dev/null +++ b/core/examples/op2.rs @@ -0,0 +1,68 @@ +use anyhow::Context; +use deno_core::anyhow::Error; +use deno_core::extension; +use deno_core::op2; +use deno_core::resolve_path; +use deno_core::v8; +use deno_core::FsModuleLoader; +use deno_core::JsRuntime; +use deno_core::OpState; +use std::rc::Rc; + +#[op2] +fn op_use_state( + state: &mut OpState, + #[global] callback: v8::Global, +) -> Result<(), Error> { + state.put(callback); + Ok(()) +} + +extension!( + op2_sample, + ops = [op_use_state], + esm_entry_point = "ext:op2_sample/op2.js", + esm = [ dir "examples", "op2.js" ], + docs = "A small example demonstrating op2 usage.", "Contains one op." +); + +fn main() -> Result<(), Error> { + let module_name = "test.js"; + let module_code = " + op2_sample.use_state(() => { + console.log('Hello World'); + }); + " + .to_string(); + + let mut js_runtime = JsRuntime::new(deno_core::RuntimeOptions { + module_loader: Some(Rc::new(FsModuleLoader)), + extensions: vec![op2_sample::init_ops_and_esm()], + ..Default::default() + }); + + let main_module = resolve_path( + module_name, + &std::env::current_dir() + .context("Unable to get current working directory")?, + )?; + + let future = async move { + let mod_id = js_runtime + .load_main_module( + &main_module, + Some(deno_core::FastString::from(module_code)), + ) + .await?; + + let result = js_runtime.mod_evaluate(mod_id); + js_runtime.run_event_loop(false).await?; + result.await? + }; + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(future) +} diff --git a/core/extensions.rs b/core/extensions.rs index 64f89d528..2cd0ec690 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -232,6 +232,7 @@ macro_rules! or { /// my_extension, /// ops = [ op_xyz ], /// esm = [ "my_script.js" ], +/// docs = "A small sample extension" /// ); /// ``` /// @@ -249,6 +250,7 @@ macro_rules! or { /// * event_loop_middleware: an event-loop middleware function (see [`ExtensionBuilder::event_loop_middleware`]) /// * global_template_middleware: a global template middleware function (see [`ExtensionBuilder::global_template_middleware`]) /// * global_object_middleware: a global object middleware function (see [`ExtensionBuilder::global_object_middleware`]) +/// * docs: comma separated list of toplevel #[doc=...] tags to be applied to the extension's resulting struct #[macro_export] macro_rules! extension { ( @@ -269,11 +271,24 @@ macro_rules! extension { $(, global_object_middleware = $global_object_middleware_fn:expr )? $(, external_references = [ $( $external_reference:expr ),* $(,)? ] )? $(, customizer = $customizer_fn:expr )? + $(, docs = $($docblocks:expr),+)? $(,)? ) => { - /// Extension struct for - #[doc = stringify!($name)] - /// . + $( $(#[doc = $docblocks])+ )? + /// + /// An extension for use with the Deno JS runtime. + /// To use it, provide it as an argument when instantiating your runtime: + /// + /// ```rust,ignore + /// use deno_core::{ JsRuntime, RuntimeOptions }; + /// + #[doc = concat!("let mut extensions = vec![", stringify!($name), "::init_ops_and_esm()];")] + /// let mut js_runtime = JsRuntime::new(RuntimeOptions { + /// extensions, + /// ..Default::default() + /// }); + /// ``` + /// #[allow(non_camel_case_types)] pub struct $name { } @@ -358,6 +373,12 @@ macro_rules! extension { } #[allow(dead_code)] + /// Legacy function for extension instantiation. + /// Please use `init_ops_and_esm` or `init_ops` instead + /// + /// # Returns + /// an Extension object that can be used during instantiation of a JsRuntime + #[deprecated(since="0.216.0", note="please use `init_ops_and_esm` or `init_ops` instead")] pub fn init_js_only $( < $( $param : $type + 'static ),* > )? () -> $crate::Extension $( where $( $bound : $bound_type ),+ )? { @@ -368,6 +389,13 @@ macro_rules! extension { } #[allow(dead_code)] + /// Initialize this extension for runtime or snapshot creation. Use this + /// function if the runtime or snapshot is not created from a (separate) + /// snapshot, or that snapshot does not contain this extension. Otherwise + /// use `init_ops()` instead. + /// + /// # Returns + /// an Extension object that can be used during instantiation of a JsRuntime pub fn init_ops_and_esm $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension $( where $( $bound : $bound_type ),+ )? { @@ -379,6 +407,13 @@ macro_rules! extension { } #[allow(dead_code)] + /// Initialize this extension for runtime or snapshot creation, excluding + /// its JavaScript sources and evaluation. This is used when the runtime + /// or snapshot is created from a (separate) snapshot which includes this + /// extension in order to avoid evaluating the JavaScript twice. + /// + /// # Returns + /// an Extension object that can be used during instantiation of a JsRuntime pub fn init_ops $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension $( where $( $bound : $bound_type ),+ )? {