summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/build.rs2
-rw-r--r--cli/graph_util.rs5
-rw-r--r--cli/lsp/diagnostics.rs2
-rw-r--r--cli/lsp/documents.rs2
-rw-r--r--cli/module_loader.rs12
-rw-r--r--cli/standalone/mod.rs6
-rw-r--r--cli/tests/testdata/run/extension_dynamic_import.ts.out10
-rw-r--r--cli/tests/testdata/run/extension_import.ts.out2
-rw-r--r--cli/tsc/mod.rs2
-rw-r--r--core/extensions.rs10
-rw-r--r--core/lib.rs1
-rw-r--r--core/modules.rs238
-rw-r--r--core/runtime.rs131
-rw-r--r--ext/node/lib.rs1
-rw-r--r--ext/node/polyfill.rs226
-rw-r--r--runtime/web_worker.rs2
-rw-r--r--runtime/worker.rs12
17 files changed, 261 insertions, 403 deletions
diff --git a/cli/build.rs b/cli/build.rs
index 2b2181bae..72b8e7818 100644
--- a/cli/build.rs
+++ b/cli/build.rs
@@ -40,7 +40,7 @@ mod ts {
let node_built_in_module_names = SUPPORTED_BUILTIN_NODE_MODULES
.iter()
- .map(|s| s.name)
+ .map(|p| p.module_name())
.collect::<Vec<&str>>();
let build_libs = state.borrow::<Vec<&str>>();
json!({
diff --git a/cli/graph_util.rs b/cli/graph_util.rs
index 90c4f8b38..976c2aeca 100644
--- a/cli/graph_util.rs
+++ b/cli/graph_util.rs
@@ -378,9 +378,8 @@ pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
pub fn get_resolution_error_bare_node_specifier(
error: &ResolutionError,
) -> Option<&str> {
- get_resolution_error_bare_specifier(error).filter(|specifier| {
- deno_node::resolve_builtin_node_module(specifier).is_ok()
- })
+ get_resolution_error_bare_specifier(error)
+ .filter(|specifier| deno_node::is_builtin_node_module(specifier))
}
fn get_resolution_error_bare_specifier(
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs
index a5e9d7bf8..6af6c92b3 100644
--- a/cli/lsp/diagnostics.rs
+++ b/cli/lsp/diagnostics.rs
@@ -1023,7 +1023,7 @@ fn diagnose_resolution(
}
} else if let Some(module_name) = specifier.as_str().strip_prefix("node:")
{
- if deno_node::resolve_builtin_node_module(module_name).is_err() {
+ if !deno_node::is_builtin_node_module(module_name) {
diagnostics
.push(DenoDiagnostic::InvalidNodeSpecifier(specifier.clone()));
} else if let Some(npm_resolver) = &snapshot.maybe_npm_resolver {
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index 4bfb9342a..d088e01c0 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -1090,7 +1090,7 @@ impl Documents {
}
}
if let Some(module_name) = specifier.strip_prefix("node:") {
- if deno_node::resolve_builtin_node_module(module_name).is_ok() {
+ if deno_node::is_builtin_node_module(module_name) {
// return itself for node: specifiers because during type checking
// we resolve to the ambient modules in the @types/node package
// rather than deno_std/node
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index 73fd2f5f4..cc416970f 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -47,7 +47,6 @@ use deno_graph::Module;
use deno_graph::Resolution;
use deno_lockfile::Lockfile;
use deno_runtime::deno_fs;
-use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::NodeResolver;
@@ -496,9 +495,7 @@ impl ModuleLoader for CliModuleLoader {
.shared
.npm_module_loader
.resolve_nv_ref(&module.nv_reference, permissions),
- Some(Module::Node(module)) => {
- deno_node::resolve_builtin_node_module(&module.module_name)
- }
+ Some(Module::Node(module)) => Ok(module.specifier.clone()),
Some(Module::Esm(module)) => Ok(module.specifier.clone()),
Some(Module::Json(module)) => Ok(module.specifier.clone()),
Some(Module::External(module)) => {
@@ -517,11 +514,6 @@ impl ModuleLoader for CliModuleLoader {
}
}
- // Built-in Node modules
- if let Some(module_name) = specifier.strip_prefix("node:") {
- return deno_node::resolve_builtin_node_module(module_name);
- }
-
// FIXME(bartlomieju): this is a hacky way to provide compatibility with REPL
// and `Deno.core.evalContext` API. Ideally we should always have a referrer filled
// but sadly that's not the case due to missing APIs in V8.
@@ -802,8 +794,6 @@ impl NpmModuleLoader {
if let NodeResolution::CommonJs(specifier) = &response {
// remember that this was a common js resolution
self.cjs_resolutions.insert(specifier.clone());
- } else if let NodeResolution::BuiltIn(specifier) = &response {
- return deno_node::resolve_builtin_node_module(specifier);
}
Ok(response.into_url())
}
diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs
index 16f4c9e65..c7f595e17 100644
--- a/cli/standalone/mod.rs
+++ b/cli/standalone/mod.rs
@@ -39,7 +39,6 @@ use deno_core::ModuleType;
use deno_core::ResolutionKind;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs;
-use deno_runtime::deno_node;
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_tls::rustls::RootCertStore;
@@ -128,11 +127,6 @@ impl ModuleLoader for EmbeddedModuleLoader {
.resolve_req_reference(&reference, permissions);
}
- // Built-in Node modules
- if let Some(module_name) = specifier_text.strip_prefix("node:") {
- return deno_node::resolve_builtin_node_module(module_name);
- }
-
match maybe_mapped {
Some(resolved) => Ok(resolved),
None => deno_core::resolve_import(specifier, referrer.as_str())
diff --git a/cli/tests/testdata/run/extension_dynamic_import.ts.out b/cli/tests/testdata/run/extension_dynamic_import.ts.out
index 081318960..4414ad923 100644
--- a/cli/tests/testdata/run/extension_dynamic_import.ts.out
+++ b/cli/tests/testdata/run/extension_dynamic_import.ts.out
@@ -1,4 +1,10 @@
-error: Uncaught (in promise) TypeError: Cannot load extension module from external code
+error: Uncaught (in promise) TypeError: Unsupported scheme "ext" for module "ext:runtime/01_errors.js". Supported schemes: [
+ "data",
+ "blob",
+ "file",
+ "http",
+ "https",
+]
await import("ext:runtime/01_errors.js");
^
- at [WILDCARD]/extension_dynamic_import.ts:1:1
+ at async [WILDCARD]/extension_dynamic_import.ts:1:1
diff --git a/cli/tests/testdata/run/extension_import.ts.out b/cli/tests/testdata/run/extension_import.ts.out
index f1d9d5eb2..88039a9ce 100644
--- a/cli/tests/testdata/run/extension_import.ts.out
+++ b/cli/tests/testdata/run/extension_import.ts.out
@@ -5,4 +5,4 @@ error: Unsupported scheme "ext" for module "ext:runtime/01_errors.js". Supported
"http",
"https",
]
- at [WILDCARD]
+ at [WILDCARD]/extension_import.ts:1:8
diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs
index b77f39fd5..2b8a210ab 100644
--- a/cli/tsc/mod.rs
+++ b/cli/tsc/mod.rs
@@ -538,7 +538,7 @@ fn op_resolve(
};
for specifier in args.specifiers {
if let Some(module_name) = specifier.strip_prefix("node:") {
- if deno_node::resolve_builtin_node_module(module_name).is_ok() {
+ if deno_node::is_builtin_node_module(module_name) {
// return itself for node: specifiers because during type checking
// we resolve to the ambient modules in the @types/node package
// rather than deno_std/node
diff --git a/core/extensions.rs b/core/extensions.rs
index ba151da3d..a8b52eb3b 100644
--- a/core/extensions.rs
+++ b/core/extensions.rs
@@ -471,16 +471,6 @@ impl Extension {
pub fn disable(self) -> Self {
self.enabled(false)
}
-
- pub(crate) fn find_esm(
- &self,
- specifier: &str,
- ) -> Option<&ExtensionFileSource> {
- self
- .get_esm_sources()?
- .iter()
- .find(|s| s.specifier == specifier)
- }
}
// Provides a convenient builder pattern to declare Extensions
diff --git a/core/lib.rs b/core/lib.rs
index 58140bb22..8edc8be18 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -79,7 +79,6 @@ pub use crate::module_specifier::resolve_url;
pub use crate::module_specifier::resolve_url_or_path;
pub use crate::module_specifier::ModuleResolutionError;
pub use crate::module_specifier::ModuleSpecifier;
-pub use crate::modules::ExtModuleLoader;
pub use crate::modules::ExtModuleLoaderCb;
pub use crate::modules::FsModuleLoader;
pub use crate::modules::ModuleCode;
diff --git a/core/modules.rs b/core/modules.rs
index 2acc14684..5a9226b6c 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -12,8 +12,8 @@ use crate::snapshot_util::SnapshottedData;
use crate::Extension;
use crate::JsRuntime;
use crate::OpState;
+use anyhow::anyhow;
use anyhow::Error;
-use core::panic;
use futures::future::FutureExt;
use futures::stream::FuturesUnordered;
use futures::stream::Stream;
@@ -385,154 +385,90 @@ impl ModuleLoader for NoopModuleLoader {
pub type ExtModuleLoaderCb =
Box<dyn Fn(&ExtensionFileSource) -> Result<ModuleCode, Error>>;
-pub struct ExtModuleLoader {
- module_loader: Rc<dyn ModuleLoader>,
- extensions: Rc<RefCell<Vec<Extension>>>,
- ext_resolution_allowed: RefCell<bool>,
- used_esm_sources: RefCell<HashMap<String, bool>>,
- maybe_load_callback: Option<ExtModuleLoaderCb>,
-}
-
-impl Default for ExtModuleLoader {
- fn default() -> Self {
- Self {
- module_loader: Rc::new(NoopModuleLoader),
- extensions: Default::default(),
- ext_resolution_allowed: Default::default(),
- used_esm_sources: RefCell::new(HashMap::default()),
- maybe_load_callback: None,
- }
- }
+pub(crate) struct ExtModuleLoader {
+ maybe_load_callback: Option<Rc<ExtModuleLoaderCb>>,
+ sources: RefCell<HashMap<String, ExtensionFileSource>>,
+ used_specifiers: RefCell<HashSet<String>>,
}
impl ExtModuleLoader {
pub fn new(
- module_loader: Option<Rc<dyn ModuleLoader>>,
- extensions: Rc<RefCell<Vec<Extension>>>,
- maybe_load_callback: Option<ExtModuleLoaderCb>,
+ extensions: &[Extension],
+ maybe_load_callback: Option<Rc<ExtModuleLoaderCb>>,
) -> Self {
- let used_esm_sources: HashMap<String, bool> = extensions
- .borrow()
- .iter()
- .flat_map(|e| e.get_esm_sources())
- .flatten()
- .map(|file_source| (file_source.specifier.to_string(), false))
- .collect();
-
+ let mut sources = HashMap::new();
+ sources.extend(
+ extensions
+ .iter()
+ .flat_map(|e| e.get_esm_sources())
+ .flatten()
+ .map(|s| (s.specifier.to_string(), s.clone())),
+ );
ExtModuleLoader {
- module_loader: module_loader.unwrap_or_else(|| Rc::new(NoopModuleLoader)),
- extensions,
- ext_resolution_allowed: Default::default(),
- used_esm_sources: RefCell::new(used_esm_sources),
maybe_load_callback,
+ sources: RefCell::new(sources),
+ used_specifiers: Default::default(),
}
}
+}
- pub fn resolve(
+impl ModuleLoader for ExtModuleLoader {
+ fn resolve(
&self,
specifier: &str,
referrer: &str,
- kind: ResolutionKind,
+ _kind: ResolutionKind,
) -> Result<ModuleSpecifier, Error> {
- if specifier.starts_with("ext:") {
- if !referrer.starts_with("ext:") && referrer != "."
- || !*self.ext_resolution_allowed.borrow()
- {
- return Err(generic_error(
- "Cannot load extension module from external code",
- ));
- }
- return Ok(ModuleSpecifier::parse(specifier)?);
- }
- self.module_loader.resolve(specifier, referrer, kind)
+ Ok(resolve_import(specifier, referrer)?)
}
- pub fn load(
+ fn load(
&self,
- module_specifier: &ModuleSpecifier,
- maybe_referrer: Option<&ModuleSpecifier>,
- is_dyn_import: bool,
+ specifier: &ModuleSpecifier,
+ _maybe_referrer: Option<&ModuleSpecifier>,
+ _is_dyn_import: bool,
) -> Pin<Box<ModuleSourceFuture>> {
- if module_specifier.scheme() != "ext" {
- return self.module_loader.load(
- module_specifier,
- maybe_referrer,
- is_dyn_import,
- );
- }
-
- let specifier = module_specifier.to_string();
- let extensions = self.extensions.borrow();
- let maybe_file_source = extensions
- .iter()
- .find_map(|e| e.find_esm(module_specifier.as_str()));
-
- if let Some(file_source) = maybe_file_source {
- {
- let mut used_esm_sources = self.used_esm_sources.borrow_mut();
- let used = used_esm_sources.get_mut(file_source.specifier).unwrap();
- *used = true;
- }
-
- let result = if let Some(load_callback) = &self.maybe_load_callback {
- load_callback(file_source)
- } else {
- file_source.load()
- };
-
- match result {
- Ok(code) => {
- let res =
- ModuleSource::new(ModuleType::JavaScript, code, module_specifier);
- return futures::future::ok(res).boxed_local();
- }
- Err(err) => return futures::future::err(err).boxed_local(),
+ let sources = self.sources.borrow();
+ let source = match sources.get(specifier.as_str()) {
+ Some(source) => source,
+ None => return futures::future::err(anyhow!("Specifier \"{}\" was not passed as an extension module and was not included in the snapshot.", specifier)).boxed_local(),
+ };
+ self
+ .used_specifiers
+ .borrow_mut()
+ .insert(specifier.to_string());
+ let result = if let Some(load_callback) = &self.maybe_load_callback {
+ load_callback(source)
+ } else {
+ source.load()
+ };
+ match result {
+ Ok(code) => {
+ let res = ModuleSource::new(ModuleType::JavaScript, code, specifier);
+ return futures::future::ok(res).boxed_local();
}
+ Err(err) => return futures::future::err(err).boxed_local(),
}
-
- async move {
- Err(generic_error(format!(
- "Cannot find extension module source for specifier {specifier}"
- )))
- }
- .boxed_local()
}
- pub fn prepare_load(
+ fn prepare_load(
&self,
- op_state: Rc<RefCell<OpState>>,
- module_specifier: &ModuleSpecifier,
- maybe_referrer: Option<String>,
- is_dyn_import: bool,
+ _op_state: Rc<RefCell<OpState>>,
+ _specifier: &ModuleSpecifier,
+ _maybe_referrer: Option<String>,
+ _is_dyn_import: bool,
) -> Pin<Box<dyn Future<Output = Result<(), Error>>>> {
- if module_specifier.scheme() == "ext" {
- return async { Ok(()) }.boxed_local();
- }
-
- self.module_loader.prepare_load(
- op_state,
- module_specifier,
- maybe_referrer,
- is_dyn_import,
- )
- }
-
- pub fn allow_ext_resolution(&self) {
- *self.ext_resolution_allowed.borrow_mut() = true;
- }
-
- pub fn disallow_ext_resolution(&self) {
- *self.ext_resolution_allowed.borrow_mut() = false;
+ async { Ok(()) }.boxed_local()
}
}
impl Drop for ExtModuleLoader {
fn drop(&mut self) {
- let used_esm_sources = self.used_esm_sources.get_mut();
- let unused_modules: Vec<_> = used_esm_sources
+ let sources = self.sources.get_mut();
+ let used_specifiers = self.used_specifiers.get_mut();
+ let unused_modules: Vec<_> = sources
.iter()
- .filter(|(_s, v)| !*v)
- .map(|(s, _)| s)
+ .filter(|(k, _)| !used_specifiers.contains(k.as_str()))
.collect();
if !unused_modules.is_empty() {
@@ -541,7 +477,7 @@ impl Drop for ExtModuleLoader {
.to_string();
for m in unused_modules {
msg.push_str(" - ");
- msg.push_str(m);
+ msg.push_str(m.0);
msg.push('\n');
}
panic!("{}", msg);
@@ -634,7 +570,7 @@ pub(crate) struct RecursiveModuleLoad {
// These three fields are copied from `module_map_rc`, but they are cloned
// ahead of time to avoid already-borrowed errors.
op_state: Rc<RefCell<OpState>>,
- loader: Rc<ExtModuleLoader>,
+ loader: Rc<dyn ModuleLoader>,
}
impl RecursiveModuleLoad {
@@ -1060,7 +996,7 @@ pub(crate) struct ModuleMap {
pub(crate) next_load_id: ModuleLoadId,
// Handling of futures for loading module sources
- pub loader: Rc<ExtModuleLoader>,
+ pub loader: Rc<dyn ModuleLoader>,
op_state: Rc<RefCell<OpState>>,
pub(crate) dynamic_import_map:
HashMap<ModuleLoadId, v8::Global<v8::PromiseResolver>>,
@@ -1369,7 +1305,7 @@ impl ModuleMap {
}
pub(crate) fn new(
- loader: Rc<ExtModuleLoader>,
+ loader: Rc<dyn ModuleLoader>,
op_state: Rc<RefCell<OpState>>,
) -> ModuleMap {
Self {
@@ -1556,6 +1492,29 @@ impl ModuleMap {
Ok(id)
}
+ pub(crate) fn clear(&mut self) {
+ *self = Self::new(self.loader.clone(), self.op_state.clone())
+ }
+
+ pub(crate) fn get_handle_by_name(
+ &self,
+ name: impl AsRef<str>,
+ ) -> Option<v8::Global<v8::Module>> {
+ let id = self
+ .get_id(name.as_ref(), AssertedModuleType::JavaScriptOrWasm)
+ .or_else(|| self.get_id(name.as_ref(), AssertedModuleType::Json))?;
+ self.get_handle(id)
+ }
+
+ pub(crate) fn inject_handle(
+ &mut self,
+ name: ModuleName,
+ module_type: ModuleType,
+ handle: v8::Global<v8::Module>,
+ ) {
+ self.create_module_info(name, module_type, handle, false, vec![]);
+ }
+
fn create_module_info(
&mut self,
name: FastString,
@@ -3005,37 +2964,4 @@ if (import.meta.url != 'file:///main_with_code.js') throw Error();
)
.unwrap();
}
-
- #[test]
- fn ext_resolution() {
- let loader = ExtModuleLoader::default();
- loader.allow_ext_resolution();
- loader
- .resolve("ext:core.js", "ext:referrer.js", ResolutionKind::Import)
- .unwrap();
- loader
- .resolve("ext:core.js", ".", ResolutionKind::Import)
- .unwrap();
- }
-
- #[test]
- fn ext_resolution_failure() {
- let loader = ExtModuleLoader::default();
- loader.allow_ext_resolution();
- assert_eq!(
- loader
- .resolve("ext:core.js", "file://bar", ResolutionKind::Import,)
- .err()
- .map(|e| e.to_string()),
- Some("Cannot load extension module from external code".to_string())
- );
- loader.disallow_ext_resolution();
- assert_eq!(
- loader
- .resolve("ext:core.js", "ext:referrer.js", ResolutionKind::Import,)
- .err()
- .map(|e| e.to_string()),
- Some("Cannot load extension module from external code".to_string())
- );
- }
}
diff --git a/core/runtime.rs b/core/runtime.rs
index dcadd6639..be3ae4355 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -9,6 +9,7 @@ use crate::extensions::OpEventLoopFn;
use crate::inspector::JsRuntimeInspector;
use crate::module_specifier::ModuleSpecifier;
use crate::modules::AssertedModuleType;
+use crate::modules::ExtModuleLoader;
use crate::modules::ExtModuleLoaderCb;
use crate::modules::ModuleCode;
use crate::modules::ModuleError;
@@ -16,6 +17,7 @@ use crate::modules::ModuleId;
use crate::modules::ModuleLoadId;
use crate::modules::ModuleLoader;
use crate::modules::ModuleMap;
+use crate::modules::ModuleName;
use crate::ops::*;
use crate::realm::ContextState;
use crate::realm::JsRealm;
@@ -24,6 +26,7 @@ use crate::snapshot_util;
use crate::source_map::SourceMapCache;
use crate::source_map::SourceMapGetter;
use crate::Extension;
+use crate::ModuleType;
use crate::NoopModuleLoader;
use crate::OpMiddlewareFn;
use crate::OpResult;
@@ -88,6 +91,7 @@ pub struct JsRuntime {
// a safety issue with SnapshotCreator. See JsRuntime::drop.
v8_isolate: Option<v8::OwnedIsolate>,
snapshot_options: snapshot_util::SnapshotOptions,
+ snapshot_module_load_cb: Option<Rc<ExtModuleLoaderCb>>,
allocations: IsolateAllocations,
extensions: Rc<RefCell<Vec<Extension>>>,
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
@@ -506,13 +510,6 @@ impl JsRuntime {
}
}
}
- let num_extensions = options.extensions.len();
- let extensions = Rc::new(RefCell::new(options.extensions));
- let ext_loader = Rc::new(crate::modules::ExtModuleLoader::new(
- Some(loader.clone()),
- extensions.clone(),
- options.snapshot_module_load_cb,
- ));
{
let global_realm = JsRealmInner::new(
@@ -530,8 +527,7 @@ impl JsRuntime {
Self::STATE_DATA_OFFSET,
Rc::into_raw(state_rc.clone()) as *mut c_void,
);
- let module_map_rc =
- Rc::new(RefCell::new(ModuleMap::new(ext_loader, op_state)));
+ let module_map_rc = Rc::new(RefCell::new(ModuleMap::new(loader, op_state)));
if let Some(snapshotted_data) = maybe_snapshotted_data {
let scope =
&mut v8::HandleScope::with_context(&mut isolate, global_context);
@@ -546,11 +542,12 @@ impl JsRuntime {
let mut js_runtime = Self {
v8_isolate: Some(isolate),
snapshot_options,
+ snapshot_module_load_cb: options.snapshot_module_load_cb.map(Rc::new),
allocations: IsolateAllocations::default(),
- event_loop_middlewares: Vec::with_capacity(num_extensions),
- extensions,
+ event_loop_middlewares: Vec::with_capacity(options.extensions.len()),
+ extensions: Rc::new(RefCell::new(options.extensions)),
state: state_rc,
- module_map: Some(module_map_rc.clone()),
+ module_map: Some(module_map_rc),
is_main: options.is_main,
};
@@ -558,9 +555,7 @@ impl JsRuntime {
// available during the initialization process.
js_runtime.init_extension_ops().unwrap();
let realm = js_runtime.global_realm();
- module_map_rc.borrow().loader.allow_ext_resolution();
js_runtime.init_extension_js(&realm).unwrap();
- module_map_rc.borrow().loader.disallow_ext_resolution();
js_runtime
}
@@ -666,21 +661,7 @@ impl JsRuntime {
JsRealm::new(realm)
};
- self
- .module_map
- .as_ref()
- .unwrap()
- .borrow()
- .loader
- .allow_ext_resolution();
self.init_extension_js(&realm)?;
- self
- .module_map
- .as_ref()
- .unwrap()
- .borrow()
- .loader
- .disallow_ext_resolution();
Ok(realm)
}
@@ -735,6 +716,15 @@ impl JsRuntime {
// 2. Iterate through all extensions:
// a. If an extension has a `esm_entry_point`, execute it.
+ // TODO(nayeemrmn): Module maps should be per-realm.
+ let module_map = self.module_map.as_ref().unwrap();
+ let loader = module_map.borrow().loader.clone();
+ let ext_loader = Rc::new(ExtModuleLoader::new(
+ &self.extensions.borrow(),
+ self.snapshot_module_load_cb.clone(),
+ ));
+ module_map.borrow_mut().loader = ext_loader;
+
let mut esm_entrypoints = vec![];
// Take extensions to avoid double-borrow
@@ -816,6 +806,7 @@ impl JsRuntime {
// Restore extensions
self.extensions = extensions;
+ self.module_map.as_ref().unwrap().borrow_mut().loader = loader;
Ok(())
}
@@ -1865,6 +1856,29 @@ impl JsRuntime {
receiver
}
+ /// Clear the module map, meant to be used after initializing extensions.
+ /// Optionally pass a list of exceptions `(old_name, new_name)` representing
+ /// specifiers which will be renamed and preserved in the module map.
+ pub fn clear_module_map(
+ &self,
+ exceptions: impl Iterator<Item = (&'static str, &'static str)>,
+ ) {
+ let mut module_map = self.module_map.as_ref().unwrap().borrow_mut();
+ let handles = exceptions
+ .map(|(old_name, new_name)| {
+ (module_map.get_handle_by_name(old_name).unwrap(), new_name)
+ })
+ .collect::<Vec<_>>();
+ module_map.clear();
+ for (handle, new_name) in handles {
+ module_map.inject_handle(
+ ModuleName::from_static(new_name),
+ ModuleType::JavaScript,
+ handle,
+ )
+ }
+ }
+
fn dynamic_import_reject(
&mut self,
id: ModuleLoadId,
@@ -4774,67 +4788,6 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", {
.is_ok());
}
- #[tokio::test]
- async fn cant_load_internal_module_when_snapshot_is_loaded_and_not_snapshotting(
- ) {
- #[derive(Default)]
- struct ModsLoader;
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- assert_eq!(specifier, "file:///main.js");
- assert_eq!(referrer, ".");
- let s = crate::resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- let code = r#"
- // This module doesn't really exist, just verifying that we'll get
- // an error when specifier starts with "ext:".
- import { core } from "ext:core.js";
- "#;
-
- async move { Ok(ModuleSource::for_test(code, "file:///main.js")) }
- .boxed_local()
- }
- }
-
- let snapshot = {
- let runtime = JsRuntime::new(RuntimeOptions {
- will_snapshot: true,
- ..Default::default()
- });
- let snap: &[u8] = &runtime.snapshot();
- Vec::from(snap).into_boxed_slice()
- };
-
- let mut runtime2 = JsRuntime::new(RuntimeOptions {
- module_loader: Some(Rc::new(ModsLoader)),
- startup_snapshot: Some(Snapshot::Boxed(snapshot)),
- ..Default::default()
- });
-
- let err = runtime2
- .load_main_module(&crate::resolve_url("file:///main.js").unwrap(), None)
- .await
- .unwrap_err();
- assert_eq!(
- err.to_string(),
- "Cannot load extension module from external code"
- );
- }
-
#[cfg(debug_assertions)]
#[test]
#[should_panic(expected = "Found ops with duplicate names:")]
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index c8242992a..6ac64eb2e 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -33,7 +33,6 @@ mod resolution;
pub use package_json::PackageJson;
pub use path::PathClean;
pub use polyfill::is_builtin_node_module;
-pub use polyfill::resolve_builtin_node_module;
pub use polyfill::NodeModulePolyfill;
pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES;
pub use resolution::NodeModuleKind;
diff --git a/ext/node/polyfill.rs b/ext/node/polyfill.rs
index 3d4a1a9fc..434c20b03 100644
--- a/ext/node/polyfill.rs
+++ b/ext/node/polyfill.rs
@@ -1,229 +1,217 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_core::error::generic_error;
-use deno_core::error::AnyError;
-use deno_core::url::Url;
-use deno_core::ModuleSpecifier;
-
-// TODO(bartlomieju): seems super wasteful to parse the specifier each time
-pub fn resolve_builtin_node_module(module_name: &str) -> Result<Url, AnyError> {
- if let Some(module) = find_builtin_node_module(module_name) {
- return Ok(ModuleSpecifier::parse(module.specifier).unwrap());
- }
-
- Err(generic_error(format!(
- "Unknown built-in \"node:\" module: {module_name}"
- )))
-}
-
-fn find_builtin_node_module(module_name: &str) -> Option<&NodeModulePolyfill> {
+/// e.g. `is_builtin_node_module("assert")`
+pub fn is_builtin_node_module(module_name: &str) -> bool {
SUPPORTED_BUILTIN_NODE_MODULES
.iter()
- .find(|m| m.name == module_name)
-}
-
-pub fn is_builtin_node_module(module_name: &str) -> bool {
- find_builtin_node_module(module_name).is_some()
+ .any(|m| m.module_name() == module_name)
}
pub struct NodeModulePolyfill {
/// Name of the module like "assert" or "timers/promises"
- pub name: &'static str,
pub specifier: &'static str,
+ pub ext_specifier: &'static str,
+}
+
+impl NodeModulePolyfill {
+ pub fn module_name(&self) -> &'static str {
+ debug_assert!(self.specifier.starts_with("node:"));
+ &self.specifier[5..]
+ }
}
// NOTE(bartlomieju): keep this list in sync with `ext/node/polyfills/01_require.js`
pub static SUPPORTED_BUILTIN_NODE_MODULES: &[NodeModulePolyfill] = &[
NodeModulePolyfill {
- name: "assert",
- specifier: "ext:deno_node/assert.ts",
+ specifier: "node:assert",
+ ext_specifier: "ext:deno_node/assert.ts",
},
NodeModulePolyfill {
- name: "assert/strict",
- specifier: "ext:deno_node/assert/strict.ts",
+ specifier: "node:assert/strict",
+ ext_specifier: "ext:deno_node/assert/strict.ts",
},
NodeModulePolyfill {
- name: "async_hooks",
- specifier: "ext:deno_node/async_hooks.ts",
+ specifier: "node:async_hooks",
+ ext_specifier: "ext:deno_node/async_hooks.ts",
},
NodeModulePolyfill {
- name: "buffer",
- specifier: "ext:deno_node/buffer.ts",
+ specifier: "node:buffer",
+ ext_specifier: "ext:deno_node/buffer.ts",
},
NodeModulePolyfill {
- name: "child_process",
- specifier: "ext:deno_node/child_process.ts",
+ specifier: "node:child_process",
+ ext_specifier: "ext:deno_node/child_process.ts",
},
NodeModulePolyfill {
- name: "cluster",
- specifier: "ext:deno_node/cluster.ts",
+ specifier: "node:cluster",
+ ext_specifier: "ext:deno_node/cluster.ts",
},
NodeModulePolyfill {
- name: "console",
- specifier: "ext:deno_node/console.ts",
+ specifier: "node:console",
+ ext_specifier: "ext:deno_node/console.ts",
},
NodeModulePolyfill {
- name: "constants",
- specifier: "ext:deno_node/constants.ts",
+ specifier: "node:constants",
+ ext_specifier: "ext:deno_node/constants.ts",
},
NodeModulePolyfill {
- name: "crypto",
- specifier: "ext:deno_node/crypto.ts",
+ specifier: "node:crypto",
+ ext_specifier: "ext:deno_node/crypto.ts",
},
NodeModulePolyfill {
- name: "dgram",
- specifier: "ext:deno_node/dgram.ts",
+ specifier: "node:dgram",
+ ext_specifier: "ext:deno_node/dgram.ts",
},
NodeModulePolyfill {
- name: "diagnostics_channel",
- specifier: "ext:deno_node/diagnostics_channel.ts",
+ specifier: "node:diagnostics_channel",
+ ext_specifier: "ext:deno_node/diagnostics_channel.ts",
},
NodeModulePolyfill {
- name: "dns",
- specifier: "ext:deno_node/dns.ts",
+ specifier: "node:dns",
+ ext_specifier: "ext:deno_node/dns.ts",
},
NodeModulePolyfill {
- name: "dns/promises",
- specifier: "ext:deno_node/dns/promises.ts",
+ specifier: "node:dns/promises",
+ ext_specifier: "ext:deno_node/dns/promises.ts",
},
NodeModulePolyfill {
- name: "domain",
- specifier: "ext:deno_node/domain.ts",
+ specifier: "node:domain",
+ ext_specifier: "ext:deno_node/domain.ts",
},
NodeModulePolyfill {
- name: "events",
- specifier: "ext:deno_node/events.ts",
+ specifier: "node:events",
+ ext_specifier: "ext:deno_node/events.ts",
},
NodeModulePolyfill {
- name: "fs",
- specifier: "ext:deno_node/fs.ts",
+ specifier: "node:fs",
+ ext_specifier: "ext:deno_node/fs.ts",
},
NodeModulePolyfill {
- name: "fs/promises",
- specifier: "ext:deno_node/fs/promises.ts",
+ specifier: "node:fs/promises",
+ ext_specifier: "ext:deno_node/fs/promises.ts",
},
NodeModulePolyfill {
- name: "http",
- specifier: "ext:deno_node/http.ts",
+ specifier: "node:http",
+ ext_specifier: "ext:deno_node/http.ts",
},
NodeModulePolyfill {
- name: "http2",
- specifier: "ext:deno_node/http2.ts",
+ specifier: "node:http2",
+ ext_specifier: "ext:deno_node/http2.ts",
},
NodeModulePolyfill {
- name: "https",
- specifier: "ext:deno_node/https.ts",
+ specifier: "node:https",
+ ext_specifier: "ext:deno_node/https.ts",
},
NodeModulePolyfill {
- name: "module",
- specifier: "ext:deno_node/01_require.js",
+ specifier: "node:module",
+ ext_specifier: "ext:deno_node/01_require.js",
},
NodeModulePolyfill {
- name: "net",
- specifier: "ext:deno_node/net.ts",
+ specifier: "node:net",
+ ext_specifier: "ext:deno_node/net.ts",
},
NodeModulePolyfill {
- name: "os",
- specifier: "ext:deno_node/os.ts",
+ specifier: "node:os",
+ ext_specifier: "ext:deno_node/os.ts",
},
NodeModulePolyfill {
- name: "path",
- specifier: "ext:deno_node/path.ts",
+ specifier: "node:path",
+ ext_specifier: "ext:deno_node/path.ts",
},
NodeModulePolyfill {
- name: "path/posix",
- specifier: "ext:deno_node/path/posix.ts",
+ specifier: "node:path/posix",
+ ext_specifier: "ext:deno_node/path/posix.ts",
},
NodeModulePolyfill {
- name: "path/win32",
- specifier: "ext:deno_node/path/win32.ts",
+ specifier: "node:path/win32",
+ ext_specifier: "ext:deno_node/path/win32.ts",
},
NodeModulePolyfill {
- name: "perf_hooks",
- specifier: "ext:deno_node/perf_hooks.ts",
+ specifier: "node:perf_hooks",
+ ext_specifier: "ext:deno_node/perf_hooks.ts",
},
NodeModulePolyfill {
- name: "process",
- specifier: "ext:deno_node/process.ts",
+ specifier: "node:process",
+ ext_specifier: "ext:deno_node/process.ts",
},
NodeModulePolyfill {
- name: "punycode",
- specifier: "ext:deno_node/punycode.ts",
+ specifier: "node:punycode",
+ ext_specifier: "ext:deno_node/punycode.ts",
},
NodeModulePolyfill {
- name: "querystring",
- specifier: "ext:deno_node/querystring.ts",
+ specifier: "node:querystring",
+ ext_specifier: "ext:deno_node/querystring.ts",
},
NodeModulePolyfill {
- name: "readline",
- specifier: "ext:deno_node/readline.ts",
+ specifier: "node:readline",
+ ext_specifier: "ext:deno_node/readline.ts",
},
NodeModulePolyfill {
- name: "stream",
- specifier: "ext:deno_node/stream.ts",
+ specifier: "node:stream",
+ ext_specifier: "ext:deno_node/stream.ts",
},
NodeModulePolyfill {
- name: "stream/consumers",
- specifier: "ext:deno_node/stream/consumers.mjs",
+ specifier: "node:stream/consumers",
+ ext_specifier: "ext:deno_node/stream/consumers.mjs",
},
NodeModulePolyfill {
- name: "stream/promises",
- specifier: "ext:deno_node/stream/promises.mjs",
+ specifier: "node:stream/promises",
+ ext_specifier: "ext:deno_node/stream/promises.mjs",
},
NodeModulePolyfill {
- name: "stream/web",
- specifier: "ext:deno_node/stream/web.ts",
+ specifier: "node:stream/web",
+ ext_specifier: "ext:deno_node/stream/web.ts",
},
NodeModulePolyfill {
- name: "string_decoder",
- specifier: "ext:deno_node/string_decoder.ts",
+ specifier: "node:string_decoder",
+ ext_specifier: "ext:deno_node/string_decoder.ts",
},
NodeModulePolyfill {
- name: "sys",
- specifier: "ext:deno_node/sys.ts",
+ specifier: "node:sys",
+ ext_specifier: "ext:deno_node/sys.ts",
},
NodeModulePolyfill {
- name: "timers",
- specifier: "ext:deno_node/timers.ts",
+ specifier: "node:timers",
+ ext_specifier: "ext:deno_node/timers.ts",
},
NodeModulePolyfill {
- name: "timers/promises",
- specifier: "ext:deno_node/timers/promises.ts",
+ specifier: "node:timers/promises",
+ ext_specifier: "ext:deno_node/timers/promises.ts",
},
NodeModulePolyfill {
- name: "tls",
- specifier: "ext:deno_node/tls.ts",
+ specifier: "node:tls",
+ ext_specifier: "ext:deno_node/tls.ts",
},
NodeModulePolyfill {
- name: "tty",
- specifier: "ext:deno_node/tty.ts",
+ specifier: "node:tty",
+ ext_specifier: "ext:deno_node/tty.ts",
},
NodeModulePolyfill {
- name: "url",
- specifier: "ext:deno_node/url.ts",
+ specifier: "node:url",
+ ext_specifier: "ext:deno_node/url.ts",
},
NodeModulePolyfill {
- name: "util",
- specifier: "ext:deno_node/util.ts",
+ specifier: "node:util",
+ ext_specifier: "ext:deno_node/util.ts",
},
NodeModulePolyfill {
- name: "util/types",
- specifier: "ext:deno_node/util/types.ts",
+ specifier: "node:util/types",
+ ext_specifier: "ext:deno_node/util/types.ts",
},
NodeModulePolyfill {
- name: "v8",
- specifier: "ext:deno_node/v8.ts",
+ specifier: "node:v8",
+ ext_specifier: "ext:deno_node/v8.ts",
},
NodeModulePolyfill {
- name: "vm",
- specifier: "ext:deno_node/vm.ts",
+ specifier: "node:vm",
+ ext_specifier: "ext:deno_node/vm.ts",
},
NodeModulePolyfill {
- name: "worker_threads",
- specifier: "ext:deno_node/worker_threads.ts",
+ specifier: "node:worker_threads",
+ ext_specifier: "ext:deno_node/worker_threads.ts",
},
NodeModulePolyfill {
- name: "zlib",
- specifier: "ext:deno_node/zlib.ts",
+ specifier: "node:zlib",
+ ext_specifier: "ext:deno_node/zlib.ts",
},
];
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index 01262abcf..36f9718b5 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -4,6 +4,7 @@ use crate::inspector_server::InspectorServer;
use crate::ops;
use crate::permissions::PermissionsContainer;
use crate::tokio_util::create_and_run_current_thread;
+use crate::worker::init_runtime_module_map;
use crate::worker::FormatJsErrorFn;
use crate::BootstrapOptions;
use deno_broadcast_channel::InMemoryBroadcastChannel;
@@ -495,6 +496,7 @@ impl WebWorker {
inspector: options.maybe_inspector_server.is_some(),
..Default::default()
});
+ init_runtime_module_map(&mut js_runtime);
if let Some(server) = options.maybe_inspector_server.clone() {
server.register_inspector(
diff --git a/runtime/worker.rs b/runtime/worker.rs
index ae6bd717f..0e62decb4 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -57,6 +57,17 @@ impl ExitCode {
self.0.store(code, Relaxed);
}
}
+
+/// Clear extension modules from the module map, except preserve `ext:deno_node`
+/// modules as `node:` specifiers.
+pub fn init_runtime_module_map(js_runtime: &mut JsRuntime) {
+ js_runtime.clear_module_map(
+ deno_node::SUPPORTED_BUILTIN_NODE_MODULES
+ .iter()
+ .map(|p| (p.ext_specifier, p.specifier)),
+ );
+}
+
/// This worker is created and used by almost all
/// subcommands in Deno executable.
///
@@ -319,6 +330,7 @@ impl MainWorker {
is_main: true,
..Default::default()
});
+ init_runtime_module_map(&mut js_runtime);
if let Some(server) = options.maybe_inspector_server.clone() {
server.register_inspector(