diff --git a/Cargo.lock b/Cargo.lock index 7fffd4d5a0..eaf124b1ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1151,9 +1151,9 @@ dependencies = [ [[package]] name = "deno_core" -version = "0.245.0" +version = "0.246.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c820d7e4712b7519dac7b03c338d0c666a77f4122aa956c630a4a888371b206e" +checksum = "1b3f3a882e1772e941a50936935e5bede7ce94a173e51a0f7403ade7961d948f" dependencies = [ "anyhow", "bit-set", @@ -1593,9 +1593,9 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.121.0" +version = "0.122.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe00963c45b37cc9494d134a34b72b708a8702f52024c6155958664d042ba6d" +checksum = "ea3f11df272673bb7e78942a594843c38138b9c76cd69596a74a43ad4b3d1736" dependencies = [ "proc-macro-rules", "proc-macro2", @@ -1663,7 +1663,7 @@ dependencies = [ "tokio", "tokio-metrics", "uuid", - "which", + "which 4.4.2", "winapi", "windows-sys 0.48.0", "winres", @@ -2535,9 +2535,9 @@ dependencies = [ [[package]] name = "fslock" -version = "0.1.8" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57eafdd0c16f57161105ae1b98a1238f97645f2f588438b2949c99a2af9616bf" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" dependencies = [ "libc", "winapi", @@ -4540,7 +4540,7 @@ dependencies = [ "regex", "syn 1.0.109", "tempfile", - "which", + "which 4.4.2", ] [[package]] @@ -5276,9 +5276,9 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.154.0" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3748eaed607f7dd2b5800100e5fe7c6babe9941492974d55d0bd08775f66ebbd" +checksum = "0c80510f3f42dbbf749b122e38c1ce07fa1b8dd62ce2636867a0d2c416a0d63e" dependencies = [ "bytes", "derive_more", @@ -6718,14 +6718,14 @@ dependencies = [ [[package]] name = "v8" -version = "0.82.0" +version = "0.83.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f53dfb242f4c0c39ed3fc7064378a342e57b5c9bd774636ad34ffe405b808121" +checksum = "546dcbb978f58aea3ad9286bd1df553f4ab7bbdc2e191cd4ae6c9a98fa95d1cd" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "fslock", "once_cell", - "which", + "which 5.0.0", ] [[package]] @@ -6990,6 +6990,19 @@ dependencies = [ "rustix", ] +[[package]] +name = "which" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "whoami" version = "1.4.1" diff --git a/Cargo.toml b/Cargo.toml index 1c6113a1d4..36345b656f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ repository = "https://github.com/denoland/deno" [workspace.dependencies] deno_ast = { version = "1.0.1", features = ["transpiling"] } -deno_core = { version = "0.245.0" } +deno_core = { version = "0.246.0" } deno_runtime = { version = "0.140.0", path = "./runtime" } napi_sym = { version = "0.62.0", path = "./cli/napi/sym" } diff --git a/cli/module_loader.rs b/cli/module_loader.rs index dc7b2b9b67..21ceee1097 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -41,6 +41,7 @@ use deno_core::ModuleSource; use deno_core::ModuleSourceCode; use deno_core::ModuleSpecifier; use deno_core::ModuleType; +use deno_core::RequestedModuleType; use deno_core::ResolutionKind; use deno_core::SourceMapGetter; use deno_graph::source::ResolutionMode; @@ -471,6 +472,7 @@ impl CliModuleLoader { specifier: &ModuleSpecifier, maybe_referrer: Option<&ModuleSpecifier>, is_dynamic: bool, + requested_module_type: RequestedModuleType, ) -> Result { let permissions = if is_dynamic { &self.dynamic_permissions @@ -498,11 +500,21 @@ impl CliModuleLoader { // because we don't need it code_without_source_map(code_source.code) }; + let module_type = match code_source.media_type { + MediaType::Json => ModuleType::Json, + _ => ModuleType::JavaScript, + }; + + // If we loaded a JSON file, but the "requested_module_type" (that is computed from + // import attributes) is not JSON we need to fail. + if module_type == ModuleType::Json + && requested_module_type != RequestedModuleType::Json + { + return Err(generic_error("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement.")); + } + Ok(ModuleSource::new_with_redirect( - match code_source.media_type { - MediaType::Json => ModuleType::Json, - _ => ModuleType::JavaScript, - }, + module_type, ModuleSourceCode::String(code), specifier, &code_source.found_url, @@ -640,6 +652,7 @@ impl ModuleLoader for CliModuleLoader { specifier: &ModuleSpecifier, maybe_referrer: Option<&ModuleSpecifier>, is_dynamic: bool, + requested_module_type: RequestedModuleType, ) -> Pin> { // NOTE: this block is async only because of `deno_core` interface // requirements; module was already loaded when constructing module graph @@ -648,6 +661,7 @@ impl ModuleLoader for CliModuleLoader { specifier, maybe_referrer, is_dynamic, + requested_module_type, ))) } diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 47a660fe1c..55c3db48ce 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -41,6 +41,7 @@ use deno_core::ModuleLoader; use deno_core::ModuleSourceCode; use deno_core::ModuleSpecifier; use deno_core::ModuleType; +use deno_core::RequestedModuleType; use deno_core::ResolutionKind; use deno_runtime::deno_fs; use deno_runtime::deno_node::analyze::NodeCodeTranslator; @@ -148,6 +149,7 @@ impl ModuleLoader for EmbeddedModuleLoader { original_specifier: &ModuleSpecifier, maybe_referrer: Option<&ModuleSpecifier>, is_dynamic: bool, + _requested_module_type: RequestedModuleType, ) -> Pin> { let is_data_uri = get_source_from_data_url(original_specifier).ok(); if let Some((source, _)) = is_data_uri { diff --git a/cli/tests/testdata/import_attributes/dynamic_error.out b/cli/tests/testdata/import_attributes/dynamic_error.out index 3dc79ba6bf..24f29de72d 100644 --- a/cli/tests/testdata/import_attributes/dynamic_error.out +++ b/cli/tests/testdata/import_attributes/dynamic_error.out @@ -1,4 +1,4 @@ -error: Uncaught (in promise) TypeError: Expected a "None" module but loaded a "JSON" module. +error: Uncaught (in promise) TypeError: Attempted to load JSON module without specifying "type": "json" attribute in the import statement. const data = await import("./data.json"); ^ at async [WILDCARD]dynamic_error.ts:1:14 diff --git a/cli/tests/unit/console_test.ts b/cli/tests/unit/console_test.ts index 031512f792..219b6ab077 100644 --- a/cli/tests/unit/console_test.ts +++ b/cli/tests/unit/console_test.ts @@ -490,12 +490,12 @@ Deno.test(function consoleTestStringifyFunctionWithProperties() { [some]: [Function: some] { [length]: 1, [name]: "some" }, [reduce]: [Function: reduce] { [length]: 1, [name]: "reduce" }, [reduceRight]: [Function: reduceRight] { [length]: 1, [name]: "reduceRight" }, - [toLocaleString]: [Function: toLocaleString] { [length]: 0, [name]: "toLocaleString" }, - [toString]: [Function: toString] { [length]: 0, [name]: "toString" }, [toReversed]: [Function: toReversed] { [length]: 0, [name]: "toReversed" }, [toSorted]: [Function: toSorted] { [length]: 1, [name]: "toSorted" }, [toSpliced]: [Function: toSpliced] { [length]: 2, [name]: "toSpliced" }, [with]: [Function: with] { [length]: 2, [name]: "with" }, + [toLocaleString]: [Function: toLocaleString] { [length]: 0, [name]: "toLocaleString" }, + [toString]: [Function: toString] { [length]: 0, [name]: "toString" }, [Symbol(Symbol.iterator)]: [Function: values] { [length]: 0, [name]: "values" }, [Symbol(Symbol.unscopables)]: [Object: null prototype] { at: true, @@ -510,10 +510,10 @@ Deno.test(function consoleTestStringifyFunctionWithProperties() { flatMap: true, includes: true, keys: true, - values: true, toReversed: true, toSorted: true, - toSpliced: true + toSpliced: true, + values: true } ], [isArray]: [Function: isArray] { [length]: 1, [name]: "isArray" }, diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 11bcd328ae..de32e39945 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -6,6 +6,7 @@ use crate::permissions::PermissionsContainer; use crate::shared::runtime; use crate::tokio_util::create_and_run_current_thread; use crate::worker::import_meta_resolve_callback; +use crate::worker::validate_import_attributes_callback; use crate::worker::FormatJsErrorFn; use crate::BootstrapOptions; use deno_broadcast_channel::InMemoryBroadcastChannel; @@ -547,6 +548,9 @@ impl WebWorker { import_meta_resolve_callback: Some(Box::new( import_meta_resolve_callback, )), + validate_import_attributes_cb: Some(Box::new( + validate_import_attributes_callback, + )), ..Default::default() }); diff --git a/runtime/worker.rs b/runtime/worker.rs index 1fac28c6a9..2cb1ab4915 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -1,4 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::collections::HashMap; use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicI32; @@ -62,6 +63,32 @@ pub fn import_meta_resolve_callback( ) } +// TODO(bartlomieju): temporary measurement until we start supporting more +// module types +pub fn validate_import_attributes_callback( + scope: &mut v8::HandleScope, + attributes: &HashMap, +) { + for (key, value) in attributes { + let msg = if key != "type" { + Some(format!("\"{key}\" attribute is not supported.")) + } else if value != "json" { + Some(format!("\"{value}\" is not a valid module type.")) + } else { + None + }; + + let Some(msg) = msg else { + continue; + }; + + let message = v8::String::new(scope, &msg).unwrap(); + let exception = v8::Exception::type_error(scope, message); + scope.throw_exception(exception); + return; + } +} + #[derive(Clone, Default)] pub struct ExitCode(Arc); @@ -469,6 +496,9 @@ impl MainWorker { import_meta_resolve_callback: Some(Box::new( import_meta_resolve_callback, )), + validate_import_attributes_cb: Some(Box::new( + validate_import_attributes_callback, + )), ..Default::default() });