diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2021-12-15 19:22:36 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-15 19:22:36 +0100 |
commit | a1f0796fccfafee19b2fe06155efe746da2e9654 (patch) | |
tree | 01942b1bc202352418c88dbf8a1c447e72f6f976 /core/bindings.rs | |
parent | ec7d90666f68ae0bf6036a6915296622adc9b65c (diff) |
feat: Add support for import assertions and JSON modules (#12866)
This commit adds proper support for import assertions and JSON modules.
Implementation of "core/modules.rs" was changed to account for multiple possible
module types, instead of always assuming that the code is an "ES module". In
effect "ModuleMap" now has knowledge about each modules' type (stored via
"ModuleType" enum). Module loading pipeline now stores information about
expected module type for each request and validates that expected type matches
discovered module type based on file's "MediaType".
Relevant tests were added to "core/modules.rs" and integration tests,
additionally multiple WPT tests were enabled.
There are still some rough edges in the implementation and not all WPT were
enabled, due to:
a) unclear BOM handling in source code by "FileFetcher"
b) design limitation of Deno's "FileFetcher" that doesn't download the same
module multiple times in a single run
Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Diffstat (limited to 'core/bindings.rs')
-rw-r--r-- | core/bindings.rs | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/core/bindings.rs b/core/bindings.rs index 06791b248..5f1806e4b 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -1,6 +1,10 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use crate::error::is_instance_of_error; +use crate::modules::get_module_type_from_assertions; +use crate::modules::parse_import_assertions; +use crate::modules::validate_import_assertions; +use crate::modules::ImportAssertionsKind; use crate::modules::ModuleMap; use crate::resolve_url_or_path; use crate::JsRuntime; @@ -243,7 +247,7 @@ pub extern "C" fn host_import_module_dynamically_callback( context: v8::Local<v8::Context>, referrer: v8::Local<v8::ScriptOrModule>, specifier: v8::Local<v8::String>, - _import_assertions: v8::Local<v8::FixedArray>, + import_assertions: v8::Local<v8::FixedArray>, ) -> *mut v8::Promise { let scope = &mut unsafe { v8::CallbackScope::new(context) }; @@ -267,6 +271,22 @@ pub extern "C" fn host_import_module_dynamically_callback( let resolver = v8::PromiseResolver::new(scope).unwrap(); let promise = resolver.get_promise(scope); + let assertions = parse_import_assertions( + scope, + import_assertions, + ImportAssertionsKind::DynamicImport, + ); + + { + let tc_scope = &mut v8::TryCatch::new(scope); + validate_import_assertions(tc_scope, &assertions); + if tc_scope.has_caught() { + let e = tc_scope.exception().unwrap(); + resolver.reject(tc_scope, e); + } + } + let module_type = get_module_type_from_assertions(&assertions); + let resolver_handle = v8::Global::new(scope, resolver); { let state_rc = JsRuntime::state(scope); @@ -280,6 +300,7 @@ pub extern "C" fn host_import_module_dynamically_callback( module_map_rc, &specifier_str, &referrer_name_str, + module_type, resolver_handle, ); state_rc.borrow_mut().notify_new_dynamic_import(); @@ -294,13 +315,29 @@ pub extern "C" fn host_import_module_dynamically_callback( _rv: v8::ReturnValue| { let arg = args.get(0); if is_instance_of_error(scope, arg) { + let e: crate::error::NativeJsError = + serde_v8::from_v8(scope, arg).unwrap(); + let name = e.name.unwrap_or_else(|| "Error".to_string()); let message = v8::Exception::create_message(scope, arg); if message.get_stack_trace(scope).unwrap().get_frame_count() == 0 { let arg: v8::Local<v8::Object> = arg.try_into().unwrap(); let message_key = v8::String::new(scope, "message").unwrap(); let message = arg.get(scope, message_key.into()).unwrap(); - let exception = - v8::Exception::type_error(scope, message.try_into().unwrap()); + let exception = match name.as_str() { + "RangeError" => { + v8::Exception::range_error(scope, message.try_into().unwrap()) + } + "TypeError" => { + v8::Exception::type_error(scope, message.try_into().unwrap()) + } + "SyntaxError" => { + v8::Exception::syntax_error(scope, message.try_into().unwrap()) + } + "ReferenceError" => { + v8::Exception::reference_error(scope, message.try_into().unwrap()) + } + _ => v8::Exception::error(scope, message.try_into().unwrap()), + }; let code_key = v8::String::new(scope, "code").unwrap(); let code_value = v8::String::new(scope, "ERR_MODULE_NOT_FOUND").unwrap(); @@ -1311,7 +1348,7 @@ fn create_host_object( pub fn module_resolve_callback<'s>( context: v8::Local<'s, v8::Context>, specifier: v8::Local<'s, v8::String>, - _import_assertions: v8::Local<'s, v8::FixedArray>, + import_assertions: v8::Local<'s, v8::FixedArray>, referrer: v8::Local<'s, v8::Module>, ) -> Option<v8::Local<'s, v8::Module>> { let scope = &mut unsafe { v8::CallbackScope::new(context) }; @@ -1328,8 +1365,17 @@ pub fn module_resolve_callback<'s>( let specifier_str = specifier.to_rust_string_lossy(scope); - let maybe_module = - module_map.resolve_callback(scope, &specifier_str, &referrer_name); + let assertions = parse_import_assertions( + scope, + import_assertions, + ImportAssertionsKind::StaticImport, + ); + let maybe_module = module_map.resolve_callback( + scope, + &specifier_str, + &referrer_name, + assertions, + ); if let Some(module) = maybe_module { return Some(module); } |