diff --git a/src/binding.cc b/src/binding.cc index 433bd5e2..cdba8e6b 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -82,10 +82,14 @@ void v8__Isolate__SetPromiseRejectCallback(v8::Isolate* isolate, void v8__Isolate__SetCaptureStackTraceForUncaughtExceptions( v8::Isolate* isolate, bool capture, int frame_limit) { - // Note: StackTraceOptions are deprecated so we don't bother to bind to it. isolate->SetCaptureStackTraceForUncaughtExceptions(capture, frame_limit); } +void v8__Isolate__SetHostInitializeImportMetaObjectCallback( + v8::Isolate* isolate, v8::HostInitializeImportMetaObjectCallback callback) { + isolate->SetHostInitializeImportMetaObjectCallback(callback); +} + bool v8__Isolate__AddMessageListener(v8::Isolate& isolate, v8::MessageCallback callback) { return isolate.AddMessageListener(callback); diff --git a/src/isolate.rs b/src/isolate.rs index 21d09d0a..2b0ee068 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -4,8 +4,11 @@ use crate::promise::PromiseRejectMessage; use crate::support::Delete; use crate::support::Opaque; use crate::support::UniqueRef; +use crate::Context; use crate::Local; use crate::Message; +use crate::Module; +use crate::Object; use crate::StartupData; use crate::Value; use std::ops::Deref; @@ -16,6 +19,9 @@ type MessageCallback = extern "C" fn(Local, Local); type PromiseRejectCallback = extern "C" fn(PromiseRejectMessage); +type HostInitializeImportMetaObjectCallback = + extern "C" fn(Local, Local, Local); + extern "C" { fn v8__Isolate__New(params: *mut CreateParams) -> *mut Isolate; fn v8__Isolate__Dispose(this: *mut Isolate); @@ -34,6 +40,10 @@ extern "C" { isolate: *mut Isolate, callback: PromiseRejectCallback, ); + fn v8__Isolate__SetHostInitializeImportMetaObjectCallback( + isolate: *mut Isolate, + callback: HostInitializeImportMetaObjectCallback, + ); fn v8__Isolate__ThrowException( isolate: &Isolate, exception: &Value, @@ -131,6 +141,16 @@ impl Isolate { ) { unsafe { v8__Isolate__SetPromiseRejectCallback(self, callback) } } + /// This specifies the callback called by the upcoming importa.meta + /// language feature to retrieve host-defined meta data for a module. + pub fn set_host_initialize_import_meta_object_callback( + &mut self, + callback: HostInitializeImportMetaObjectCallback, + ) { + unsafe { + v8__Isolate__SetHostInitializeImportMetaObjectCallback(self, callback) + } + } /// Schedules an exception to be thrown when returning to JavaScript. When an /// exception has been scheduled it is illegal to invoke any JavaScript diff --git a/tests/test_api.rs b/tests/test_api.rs index 63d4a06b..f0ffb4dd 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -307,7 +307,7 @@ fn throw_exception() { } #[test] -fn isolate_add_message_listener() { +fn add_message_listener() { let g = setup(); let mut params = v8::Isolate::create_params(); params.set_array_buffer_allocator(v8::Allocator::new_default_allocator()); @@ -344,6 +344,62 @@ fn isolate_add_message_listener() { drop(g); } +fn unexpected_module_resolve_callback( + _context: v8::Local, + _specifier: v8::Local, + _referrer: v8::Local, +) -> *mut v8::Module { + unreachable!() +} + +#[test] +fn set_host_initialize_import_meta_object_callback() { + let g = setup(); + let mut params = v8::Isolate::create_params(); + params.set_array_buffer_allocator(v8::Allocator::new_default_allocator()); + let mut isolate = v8::Isolate::new(params); + + use std::sync::atomic::{AtomicUsize, Ordering}; + static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); + + extern "C" fn callback( + mut context: Local, + _module: Local, + meta: Local, + ) { + CALL_COUNT.fetch_add(1, Ordering::SeqCst); + let key = v8::String::new(&mut *context, "foo").unwrap(); + let value = v8::String::new(&mut *context, "bar").unwrap(); + meta.create_data_property(context, cast(key), value.into()); + } + isolate.set_host_initialize_import_meta_object_callback(callback); + + let mut locker = v8::Locker::new(&isolate); + v8::HandleScope::enter(&mut locker, |s| { + let mut context = v8::Context::new(s); + context.enter(); + + let source = mock_source(s, "google.com", "import.meta;"); + let mut module = + v8::script_compiler::compile_module(&isolate, source).unwrap(); + let result = + module.instantiate_module(context, unexpected_module_resolve_callback); + assert!(result.is_some()); + let meta = module.evaluate(context).unwrap(); + assert!(meta.is_object()); + let meta: Local = cast(meta); + let key = v8::String::new(&mut *context, "foo").unwrap(); + let expected = v8::String::new(&mut *context, "bar").unwrap(); + let actual = meta.get(context, key.into()).unwrap(); + assert!(expected.strict_equals(actual)); + assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1); + + context.exit(); + }); + drop(locker); + drop(g); +} + #[test] fn script_compile_and_run() { setup(); @@ -794,6 +850,15 @@ fn mock_script_origin<'sc>( ) } +fn mock_source( + isolate: &mut impl AsMut, + resource_name: &str, + source: &str, +) -> v8::script_compiler::Source { + let script_origin = mock_script_origin(isolate, resource_name); + v8::script_compiler::Source::new(v8_str(isolate, source), &script_origin) +} + #[test] fn script_compiler_source() { let g = setup();