diff options
Diffstat (limited to 'core/modules.rs')
-rw-r--r-- | core/modules.rs | 238 |
1 files changed, 82 insertions, 156 deletions
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()) - ); - } } |