summaryrefslogtreecommitdiff
path: root/core/modules/map.rs
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-07-01 18:00:14 -0600
committerGitHub <noreply@github.com>2023-07-02 00:00:14 +0000
commite746b6d80654ba4e4e26370fe6e4f784ce841d92 (patch)
tree153ffad92a96126b9ab8e906dcdabf7648755931 /core/modules/map.rs
parentb9c0e7cd550ab14fa7da7e33ed87cbeeeb9785a0 (diff)
refactor(core): Extract deno_core (#19658)
`deno_core` is moving out! You'll find it at https://github.com/denoland/deno_core/ once this PR lands.
Diffstat (limited to 'core/modules/map.rs')
-rw-r--r--core/modules/map.rs1014
1 files changed, 0 insertions, 1014 deletions
diff --git a/core/modules/map.rs b/core/modules/map.rs
deleted file mode 100644
index 786772e5b..000000000
--- a/core/modules/map.rs
+++ /dev/null
@@ -1,1014 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::exception_to_err_result;
-use crate::error::generic_error;
-use crate::error::throw_type_error;
-use crate::fast_string::FastString;
-use crate::modules::get_asserted_module_type_from_assertions;
-use crate::modules::parse_import_assertions;
-use crate::modules::validate_import_assertions;
-use crate::modules::ImportAssertionsKind;
-use crate::modules::ModuleCode;
-use crate::modules::ModuleError;
-use crate::modules::ModuleId;
-use crate::modules::ModuleInfo;
-use crate::modules::ModuleLoadId;
-use crate::modules::ModuleLoader;
-use crate::modules::ModuleName;
-use crate::modules::ModuleRequest;
-use crate::modules::ModuleType;
-use crate::modules::NoopModuleLoader;
-use crate::modules::PrepareLoadFuture;
-use crate::modules::RecursiveModuleLoad;
-use crate::modules::ResolutionKind;
-use crate::runtime::JsRuntime;
-use crate::runtime::SnapshottedData;
-use anyhow::Error;
-use futures::future::FutureExt;
-use futures::stream::FuturesUnordered;
-use futures::stream::StreamFuture;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::pin::Pin;
-use std::rc::Rc;
-
-use super::AssertedModuleType;
-
-pub const BOM_CHAR: &[u8] = &[0xef, 0xbb, 0xbf];
-
-/// Strips the byte order mark from the provided text if it exists.
-fn strip_bom(source_code: &[u8]) -> &[u8] {
- if source_code.starts_with(BOM_CHAR) {
- &source_code[BOM_CHAR.len()..]
- } else {
- source_code
- }
-}
-
-/// A symbolic module entity.
-#[derive(Debug, PartialEq)]
-pub(crate) enum SymbolicModule {
- /// This module is an alias to another module.
- /// This is useful such that multiple names could point to
- /// the same underlying module (particularly due to redirects).
- Alias(ModuleName),
- /// This module associates with a V8 module by id.
- Mod(ModuleId),
-}
-
-/// A collection of JS modules.
-pub(crate) struct ModuleMap {
- // Handling of specifiers and v8 objects
- pub handles: Vec<v8::Global<v8::Module>>,
- pub info: Vec<ModuleInfo>,
- pub(crate) by_name_js: HashMap<ModuleName, SymbolicModule>,
- pub(crate) by_name_json: HashMap<ModuleName, SymbolicModule>,
- pub(crate) next_load_id: ModuleLoadId,
-
- // Handling of futures for loading module sources
- pub loader: Rc<dyn ModuleLoader>,
- pub(crate) dynamic_import_map:
- HashMap<ModuleLoadId, v8::Global<v8::PromiseResolver>>,
- pub(crate) preparing_dynamic_imports:
- FuturesUnordered<Pin<Box<PrepareLoadFuture>>>,
- pub(crate) pending_dynamic_imports:
- FuturesUnordered<StreamFuture<RecursiveModuleLoad>>,
-
- // This store is used temporarily, to forward parsed JSON
- // value from `new_json_module` to `json_module_evaluation_steps`
- json_value_store: HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
-}
-
-impl ModuleMap {
- pub fn collect_modules(
- &self,
- ) -> Vec<(AssertedModuleType, &ModuleName, &SymbolicModule)> {
- let mut output = vec![];
- for module_type in [
- AssertedModuleType::JavaScriptOrWasm,
- AssertedModuleType::Json,
- ] {
- output.extend(
- self
- .by_name(module_type)
- .iter()
- .map(|x| (module_type, x.0, x.1)),
- )
- }
- output
- }
-
- #[cfg(debug_assertions)]
- pub(crate) fn assert_all_modules_evaluated(
- &self,
- scope: &mut v8::HandleScope,
- ) {
- let mut not_evaluated = vec![];
-
- for (i, handle) in self.handles.iter().enumerate() {
- let module = v8::Local::new(scope, handle);
- if !matches!(module.get_status(), v8::ModuleStatus::Evaluated) {
- not_evaluated.push(self.info[i].name.as_str().to_string());
- }
- }
-
- if !not_evaluated.is_empty() {
- let mut msg = "Following modules were not evaluated; make sure they are imported from other code:\n".to_string();
- for m in not_evaluated {
- msg.push_str(&format!(" - {}\n", m));
- }
- panic!("{}", msg);
- }
- }
-
- pub fn serialize_for_snapshotting(
- &self,
- scope: &mut v8::HandleScope,
- ) -> SnapshottedData {
- let array = v8::Array::new(scope, 3);
-
- let next_load_id = v8::Integer::new(scope, self.next_load_id);
- array.set_index(scope, 0, next_load_id.into());
-
- let info_arr = v8::Array::new(scope, self.info.len() as i32);
- for (i, info) in self.info.iter().enumerate() {
- let module_info_arr = v8::Array::new(scope, 5);
-
- let id = v8::Integer::new(scope, info.id as i32);
- module_info_arr.set_index(scope, 0, id.into());
-
- let main = v8::Boolean::new(scope, info.main);
- module_info_arr.set_index(scope, 1, main.into());
-
- let name = info.name.v8(scope);
- module_info_arr.set_index(scope, 2, name.into());
-
- let array_len = 2 * info.requests.len() as i32;
- let requests_arr = v8::Array::new(scope, array_len);
- for (i, request) in info.requests.iter().enumerate() {
- let specifier = v8::String::new_from_one_byte(
- scope,
- request.specifier.as_bytes(),
- v8::NewStringType::Normal,
- )
- .unwrap();
- requests_arr.set_index(scope, 2 * i as u32, specifier.into());
-
- let asserted_module_type =
- v8::Integer::new(scope, request.asserted_module_type as i32);
- requests_arr.set_index(
- scope,
- (2 * i) as u32 + 1,
- asserted_module_type.into(),
- );
- }
- module_info_arr.set_index(scope, 3, requests_arr.into());
-
- let module_type = v8::Integer::new(scope, info.module_type as i32);
- module_info_arr.set_index(scope, 4, module_type.into());
-
- info_arr.set_index(scope, i as u32, module_info_arr.into());
- }
- array.set_index(scope, 1, info_arr.into());
-
- let by_name = self.collect_modules();
- let by_name_array = v8::Array::new(scope, by_name.len() as i32);
- {
- for (i, (module_type, name, module)) in by_name.into_iter().enumerate() {
- let arr = v8::Array::new(scope, 3);
-
- let specifier = name.v8(scope);
- arr.set_index(scope, 0, specifier.into());
-
- let asserted_module_type = v8::Integer::new(scope, module_type as i32);
- arr.set_index(scope, 1, asserted_module_type.into());
-
- let symbolic_module: v8::Local<v8::Value> = match module {
- SymbolicModule::Alias(alias) => {
- let alias = v8::String::new_from_one_byte(
- scope,
- alias.as_bytes(),
- v8::NewStringType::Normal,
- )
- .unwrap();
- alias.into()
- }
- SymbolicModule::Mod(id) => {
- let id = v8::Integer::new(scope, *id as i32);
- id.into()
- }
- };
- arr.set_index(scope, 2, symbolic_module);
-
- by_name_array.set_index(scope, i as u32, arr.into());
- }
- }
- array.set_index(scope, 2, by_name_array.into());
-
- let array_global = v8::Global::new(scope, array);
-
- let handles = self.handles.clone();
- SnapshottedData {
- module_map_data: array_global,
- module_handles: handles,
- }
- }
-
- pub fn update_with_snapshotted_data(
- &mut self,
- scope: &mut v8::HandleScope,
- snapshotted_data: SnapshottedData,
- ) {
- let local_data: v8::Local<v8::Array> =
- v8::Local::new(scope, snapshotted_data.module_map_data);
-
- {
- let next_load_id = local_data.get_index(scope, 0).unwrap();
- assert!(next_load_id.is_int32());
- let integer = next_load_id.to_integer(scope).unwrap();
- let val = integer.int32_value(scope).unwrap();
- self.next_load_id = val;
- }
-
- {
- let info_val = local_data.get_index(scope, 1).unwrap();
-
- let info_arr: v8::Local<v8::Array> = info_val.try_into().unwrap();
- let len = info_arr.length() as usize;
- // Over allocate so executing a few scripts doesn't have to resize this vec.
- let mut info = Vec::with_capacity(len + 16);
-
- for i in 0..len {
- let module_info_arr: v8::Local<v8::Array> = info_arr
- .get_index(scope, i as u32)
- .unwrap()
- .try_into()
- .unwrap();
- let id = module_info_arr
- .get_index(scope, 0)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value() as ModuleId;
-
- let main = module_info_arr
- .get_index(scope, 1)
- .unwrap()
- .to_boolean(scope)
- .is_true();
-
- let name = module_info_arr
- .get_index(scope, 2)
- .unwrap()
- .to_rust_string_lossy(scope)
- .into();
-
- let requests_arr: v8::Local<v8::Array> = module_info_arr
- .get_index(scope, 3)
- .unwrap()
- .try_into()
- .unwrap();
- let len = (requests_arr.length() as usize) / 2;
- let mut requests = Vec::with_capacity(len);
- for i in 0..len {
- let specifier = requests_arr
- .get_index(scope, (2 * i) as u32)
- .unwrap()
- .to_rust_string_lossy(scope);
- let asserted_module_type_no = requests_arr
- .get_index(scope, (2 * i + 1) as u32)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value();
- let asserted_module_type = match asserted_module_type_no {
- 0 => AssertedModuleType::JavaScriptOrWasm,
- 1 => AssertedModuleType::Json,
- _ => unreachable!(),
- };
- requests.push(ModuleRequest {
- specifier,
- asserted_module_type,
- });
- }
-
- let module_type_no = module_info_arr
- .get_index(scope, 4)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value();
- let module_type = match module_type_no {
- 0 => ModuleType::JavaScript,
- 1 => ModuleType::Json,
- _ => unreachable!(),
- };
-
- let module_info = ModuleInfo {
- id,
- main,
- name,
- requests,
- module_type,
- };
- info.push(module_info);
- }
-
- self.info = info;
- }
-
- self
- .by_name_mut(AssertedModuleType::JavaScriptOrWasm)
- .clear();
- self.by_name_mut(AssertedModuleType::Json).clear();
-
- {
- let by_name_arr: v8::Local<v8::Array> =
- local_data.get_index(scope, 2).unwrap().try_into().unwrap();
- let len = by_name_arr.length() as usize;
-
- for i in 0..len {
- let arr: v8::Local<v8::Array> = by_name_arr
- .get_index(scope, i as u32)
- .unwrap()
- .try_into()
- .unwrap();
-
- let specifier =
- arr.get_index(scope, 0).unwrap().to_rust_string_lossy(scope);
- let asserted_module_type = match arr
- .get_index(scope, 1)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value()
- {
- 0 => AssertedModuleType::JavaScriptOrWasm,
- 1 => AssertedModuleType::Json,
- _ => unreachable!(),
- };
-
- let symbolic_module_val = arr.get_index(scope, 2).unwrap();
- let val = if symbolic_module_val.is_number() {
- SymbolicModule::Mod(
- symbolic_module_val
- .to_integer(scope)
- .unwrap()
- .value()
- .try_into()
- .unwrap(),
- )
- } else {
- SymbolicModule::Alias(
- symbolic_module_val.to_rust_string_lossy(scope).into(),
- )
- };
-
- self
- .by_name_mut(asserted_module_type)
- .insert(specifier.into(), val);
- }
- }
-
- self.handles = snapshotted_data.module_handles;
- }
-
- pub(crate) fn new(loader: Rc<dyn ModuleLoader>) -> ModuleMap {
- Self {
- handles: vec![],
- info: vec![],
- by_name_js: HashMap::new(),
- by_name_json: HashMap::new(),
- next_load_id: 1,
- loader,
- dynamic_import_map: HashMap::new(),
- preparing_dynamic_imports: FuturesUnordered::new(),
- pending_dynamic_imports: FuturesUnordered::new(),
- json_value_store: HashMap::new(),
- }
- }
-
- /// Get module id, following all aliases in case of module specifier
- /// that had been redirected.
- pub(crate) fn get_id(
- &self,
- name: impl AsRef<str>,
- asserted_module_type: AssertedModuleType,
- ) -> Option<ModuleId> {
- let map = self.by_name(asserted_module_type);
- let first_symbolic_module = map.get(name.as_ref())?;
- let mut mod_name = match first_symbolic_module {
- SymbolicModule::Mod(mod_id) => return Some(*mod_id),
- SymbolicModule::Alias(target) => target,
- };
- loop {
- let symbolic_module = map.get(mod_name.as_ref())?;
- match symbolic_module {
- SymbolicModule::Alias(target) => {
- debug_assert!(mod_name != target);
- mod_name = target;
- }
- SymbolicModule::Mod(mod_id) => return Some(*mod_id),
- }
- }
- }
-
- pub(crate) fn new_json_module(
- &mut self,
- scope: &mut v8::HandleScope,
- name: ModuleName,
- source: ModuleCode,
- ) -> Result<ModuleId, ModuleError> {
- let name_str = name.v8(scope);
- let source_str = v8::String::new_from_utf8(
- scope,
- strip_bom(source.as_bytes()),
- v8::NewStringType::Normal,
- )
- .unwrap();
-
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let parsed_json = match v8::json::parse(tc_scope, source_str) {
- Some(parsed_json) => parsed_json,
- None => {
- assert!(tc_scope.has_caught());
- let exception = tc_scope.exception().unwrap();
- let exception = v8::Global::new(tc_scope, exception);
- return Err(ModuleError::Exception(exception));
- }
- };
-
- let export_names = [v8::String::new(tc_scope, "default").unwrap()];
- let module = v8::Module::create_synthetic_module(
- tc_scope,
- name_str,
- &export_names,
- json_module_evaluation_steps,
- );
-
- let handle = v8::Global::<v8::Module>::new(tc_scope, module);
- let value_handle = v8::Global::<v8::Value>::new(tc_scope, parsed_json);
- self.json_value_store.insert(handle.clone(), value_handle);
-
- let id =
- self.create_module_info(name, ModuleType::Json, handle, false, vec![]);
-
- Ok(id)
- }
-
- /// Create and compile an ES module.
- pub(crate) fn new_es_module(
- &mut self,
- scope: &mut v8::HandleScope,
- main: bool,
- name: ModuleName,
- source: ModuleCode,
- is_dynamic_import: bool,
- ) -> Result<ModuleId, ModuleError> {
- let name_str = name.v8(scope);
- let source_str = source.v8(scope);
-
- let origin = module_origin(scope, name_str);
- let source = v8::script_compiler::Source::new(source_str, Some(&origin));
-
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let maybe_module = v8::script_compiler::compile_module(tc_scope, source);
-
- if tc_scope.has_caught() {
- assert!(maybe_module.is_none());
- let exception = tc_scope.exception().unwrap();
- let exception = v8::Global::new(tc_scope, exception);
- return Err(ModuleError::Exception(exception));
- }
-
- let module = maybe_module.unwrap();
-
- let mut requests: Vec<ModuleRequest> = vec![];
- let module_requests = module.get_module_requests();
- for i in 0..module_requests.length() {
- let module_request = v8::Local::<v8::ModuleRequest>::try_from(
- module_requests.get(tc_scope, i).unwrap(),
- )
- .unwrap();
- let import_specifier = module_request
- .get_specifier()
- .to_rust_string_lossy(tc_scope);
-
- let import_assertions = module_request.get_import_assertions();
-
- let assertions = parse_import_assertions(
- tc_scope,
- import_assertions,
- ImportAssertionsKind::StaticImport,
- );
-
- // FIXME(bartomieju): there are no stack frames if exception
- // is thrown here
- validate_import_assertions(tc_scope, &assertions);
- if tc_scope.has_caught() {
- let exception = tc_scope.exception().unwrap();
- let exception = v8::Global::new(tc_scope, exception);
- return Err(ModuleError::Exception(exception));
- }
-
- let module_specifier = match self.loader.resolve(
- &import_specifier,
- name.as_ref(),
- if is_dynamic_import {
- ResolutionKind::DynamicImport
- } else {
- ResolutionKind::Import
- },
- ) {
- Ok(s) => s,
- Err(e) => return Err(ModuleError::Other(e)),
- };
- let asserted_module_type =
- get_asserted_module_type_from_assertions(&assertions);
- let request = ModuleRequest {
- specifier: module_specifier.to_string(),
- asserted_module_type,
- };
- requests.push(request);
- }
-
- if main {
- let maybe_main_module = self.info.iter().find(|module| module.main);
- if let Some(main_module) = maybe_main_module {
- return Err(ModuleError::Other(generic_error(
- format!("Trying to create \"main\" module ({:?}), when one already exists ({:?})",
- name.as_ref(),
- main_module.name,
- ))));
- }
- }
-
- let handle = v8::Global::<v8::Module>::new(tc_scope, module);
- let id = self.create_module_info(
- name,
- ModuleType::JavaScript,
- handle,
- main,
- requests,
- );
-
- Ok(id)
- }
-
- pub(crate) fn instantiate_module(
- &mut self,
- scope: &mut v8::HandleScope,
- id: ModuleId,
- ) -> Result<(), v8::Global<v8::Value>> {
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let module = self
- .get_handle(id)
- .map(|handle| v8::Local::new(tc_scope, handle))
- .expect("ModuleInfo not found");
-
- if module.get_status() == v8::ModuleStatus::Errored {
- return Err(v8::Global::new(tc_scope, module.get_exception()));
- }
-
- tc_scope.set_slot(self as *const _);
- let instantiate_result =
- module.instantiate_module(tc_scope, Self::module_resolve_callback);
- tc_scope.remove_slot::<*const Self>();
- if instantiate_result.is_none() {
- let exception = tc_scope.exception().unwrap();
- return Err(v8::Global::new(tc_scope, exception));
- }
-
- Ok(())
- }
-
- /// Called by V8 during `JsRuntime::instantiate_module`. This is only used internally, so we use the Isolate's annex
- /// to propagate a &Self.
- fn module_resolve_callback<'s>(
- context: v8::Local<'s, v8::Context>,
- specifier: v8::Local<'s, v8::String>,
- import_assertions: v8::Local<'s, v8::FixedArray>,
- referrer: v8::Local<'s, v8::Module>,
- ) -> Option<v8::Local<'s, v8::Module>> {
- // SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
- let scope = &mut unsafe { v8::CallbackScope::new(context) };
-
- let module_map =
- // SAFETY: We retrieve the pointer from the slot, having just set it a few stack frames up
- unsafe { scope.get_slot::<*const Self>().unwrap().as_ref().unwrap() };
-
- let referrer_global = v8::Global::new(scope, referrer);
-
- let referrer_info = module_map
- .get_info(&referrer_global)
- .expect("ModuleInfo not found");
- let referrer_name = referrer_info.name.as_str();
-
- let specifier_str = specifier.to_rust_string_lossy(scope);
-
- 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);
- }
-
- let msg = format!(
- r#"Cannot resolve module "{specifier_str}" from "{referrer_name}""#
- );
- throw_type_error(scope, msg);
- None
- }
-
- /// Called by `module_resolve_callback` during module instantiation.
- fn resolve_callback<'s>(
- &self,
- scope: &mut v8::HandleScope<'s>,
- specifier: &str,
- referrer: &str,
- import_assertions: HashMap<String, String>,
- ) -> Option<v8::Local<'s, v8::Module>> {
- let resolved_specifier = self
- .loader
- .resolve(specifier, referrer, ResolutionKind::Import)
- .expect("Module should have been already resolved");
-
- let module_type =
- get_asserted_module_type_from_assertions(&import_assertions);
-
- if let Some(id) = self.get_id(resolved_specifier.as_str(), module_type) {
- if let Some(handle) = self.get_handle(id) {
- return Some(v8::Local::new(scope, handle));
- }
- }
-
- None
- }
-
- pub(crate) fn clear(&mut self) {
- *self = Self::new(self.loader.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,
- module_type: ModuleType,
- handle: v8::Global<v8::Module>,
- main: bool,
- requests: Vec<ModuleRequest>,
- ) -> ModuleId {
- let id = self.handles.len();
- let (name1, name2) = name.into_cheap_copy();
- self
- .by_name_mut(module_type.into())
- .insert(name1, SymbolicModule::Mod(id));
- self.handles.push(handle);
- self.info.push(ModuleInfo {
- id,
- main,
- name: name2,
- requests,
- module_type,
- });
-
- id
- }
-
- pub(crate) fn get_requested_modules(
- &self,
- id: ModuleId,
- ) -> Option<&Vec<ModuleRequest>> {
- self.info.get(id).map(|i| &i.requests)
- }
-
- fn is_registered(
- &self,
- specifier: impl AsRef<str>,
- asserted_module_type: AssertedModuleType,
- ) -> bool {
- if let Some(id) = self.get_id(specifier.as_ref(), asserted_module_type) {
- let info = self.get_info_by_id(id).unwrap();
- return asserted_module_type == info.module_type.into();
- }
-
- false
- }
-
- pub(crate) fn by_name(
- &self,
- asserted_module_type: AssertedModuleType,
- ) -> &HashMap<ModuleName, SymbolicModule> {
- match asserted_module_type {
- AssertedModuleType::Json => &self.by_name_json,
- AssertedModuleType::JavaScriptOrWasm => &self.by_name_js,
- }
- }
-
- pub(crate) fn by_name_mut(
- &mut self,
- asserted_module_type: AssertedModuleType,
- ) -> &mut HashMap<ModuleName, SymbolicModule> {
- match asserted_module_type {
- AssertedModuleType::Json => &mut self.by_name_json,
- AssertedModuleType::JavaScriptOrWasm => &mut self.by_name_js,
- }
- }
-
- pub(crate) fn alias(
- &mut self,
- name: FastString,
- asserted_module_type: AssertedModuleType,
- target: FastString,
- ) {
- debug_assert_ne!(name, target);
- self
- .by_name_mut(asserted_module_type)
- .insert(name, SymbolicModule::Alias(target));
- }
-
- #[cfg(test)]
- pub(crate) fn is_alias(
- &self,
- name: &str,
- asserted_module_type: AssertedModuleType,
- ) -> bool {
- let cond = self.by_name(asserted_module_type).get(name);
- matches!(cond, Some(SymbolicModule::Alias(_)))
- }
-
- pub(crate) fn get_handle(
- &self,
- id: ModuleId,
- ) -> Option<v8::Global<v8::Module>> {
- self.handles.get(id).cloned()
- }
-
- pub(crate) fn get_info(
- &self,
- global: &v8::Global<v8::Module>,
- ) -> Option<&ModuleInfo> {
- if let Some(id) = self.handles.iter().position(|module| module == global) {
- return self.info.get(id);
- }
-
- None
- }
-
- pub(crate) fn get_info_by_id(&self, id: ModuleId) -> Option<&ModuleInfo> {
- self.info.get(id)
- }
-
- pub(crate) async fn load_main(
- module_map_rc: Rc<RefCell<ModuleMap>>,
- specifier: impl AsRef<str>,
- ) -> Result<RecursiveModuleLoad, Error> {
- let load =
- RecursiveModuleLoad::main(specifier.as_ref(), module_map_rc.clone());
- load.prepare().await?;
- Ok(load)
- }
-
- pub(crate) async fn load_side(
- module_map_rc: Rc<RefCell<ModuleMap>>,
- specifier: impl AsRef<str>,
- ) -> Result<RecursiveModuleLoad, Error> {
- let load =
- RecursiveModuleLoad::side(specifier.as_ref(), module_map_rc.clone());
- load.prepare().await?;
- Ok(load)
- }
-
- // Initiate loading of a module graph imported using `import()`.
- pub(crate) fn load_dynamic_import(
- module_map_rc: Rc<RefCell<ModuleMap>>,
- specifier: &str,
- referrer: &str,
- asserted_module_type: AssertedModuleType,
- resolver_handle: v8::Global<v8::PromiseResolver>,
- ) {
- let load = RecursiveModuleLoad::dynamic_import(
- specifier,
- referrer,
- asserted_module_type,
- module_map_rc.clone(),
- );
- module_map_rc
- .borrow_mut()
- .dynamic_import_map
- .insert(load.id, resolver_handle);
-
- let loader = module_map_rc.borrow().loader.clone();
- let resolve_result =
- loader.resolve(specifier, referrer, ResolutionKind::DynamicImport);
- let fut = match resolve_result {
- Ok(module_specifier) => {
- if module_map_rc
- .borrow()
- .is_registered(module_specifier, asserted_module_type)
- {
- async move { (load.id, Ok(load)) }.boxed_local()
- } else {
- async move { (load.id, load.prepare().await.map(|()| load)) }
- .boxed_local()
- }
- }
- Err(error) => async move { (load.id, Err(error)) }.boxed_local(),
- };
- module_map_rc
- .borrow_mut()
- .preparing_dynamic_imports
- .push(fut);
- }
-
- pub(crate) fn has_pending_dynamic_imports(&self) -> bool {
- !(self.preparing_dynamic_imports.is_empty()
- && self.pending_dynamic_imports.is_empty())
- }
-
- /// Returns the namespace object of a module.
- ///
- /// This is only available after module evaluation has completed.
- /// This function panics if module has not been instantiated.
- pub fn get_module_namespace(
- &self,
- scope: &mut v8::HandleScope,
- module_id: ModuleId,
- ) -> Result<v8::Global<v8::Object>, Error> {
- let module_handle =
- self.get_handle(module_id).expect("ModuleInfo not found");
-
- let module = module_handle.open(scope);
-
- if module.get_status() == v8::ModuleStatus::Errored {
- let exception = module.get_exception();
- return exception_to_err_result(scope, exception, false);
- }
-
- assert!(matches!(
- module.get_status(),
- v8::ModuleStatus::Instantiated | v8::ModuleStatus::Evaluated
- ));
-
- let module_namespace: v8::Local<v8::Object> =
- v8::Local::try_from(module.get_module_namespace())
- .map_err(|err: v8::DataError| generic_error(err.to_string()))?;
-
- Ok(v8::Global::new(scope, module_namespace))
- }
-
- /// 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(
- &mut self,
- exceptions: impl Iterator<Item = (&'static str, &'static str)>,
- ) {
- let handles = exceptions
- .map(|(old_name, new_name)| {
- (self.get_handle_by_name(old_name).unwrap(), new_name)
- })
- .collect::<Vec<_>>();
- self.clear();
- for (handle, new_name) in handles {
- self.inject_handle(
- ModuleName::from_static(new_name),
- ModuleType::JavaScript,
- handle,
- )
- }
- }
-
- fn get_stalled_top_level_await_message_for_module(
- &self,
- scope: &mut v8::HandleScope,
- module_id: ModuleId,
- ) -> Vec<v8::Global<v8::Message>> {
- let module_handle = self.handles.get(module_id).unwrap();
-
- let module = v8::Local::new(scope, module_handle);
- let stalled = module.get_stalled_top_level_await_message(scope);
- let mut messages = vec![];
- for (_, message) in stalled {
- messages.push(v8::Global::new(scope, message));
- }
- messages
- }
-
- pub(crate) fn find_stalled_top_level_await(
- &self,
- scope: &mut v8::HandleScope,
- ) -> Vec<v8::Global<v8::Message>> {
- // First check if that's root module
- let root_module_id =
- self.info.iter().filter(|m| m.main).map(|m| m.id).next();
-
- if let Some(root_module_id) = root_module_id {
- let messages = self
- .get_stalled_top_level_await_message_for_module(scope, root_module_id);
- if !messages.is_empty() {
- return messages;
- }
- }
-
- // It wasn't a top module, so iterate over all modules and try to find
- // any with stalled top level await
- for module_id in 0..self.handles.len() {
- let messages =
- self.get_stalled_top_level_await_message_for_module(scope, module_id);
- if !messages.is_empty() {
- return messages;
- }
- }
-
- unreachable!()
- }
-}
-
-impl Default for ModuleMap {
- fn default() -> Self {
- Self::new(Rc::new(NoopModuleLoader))
- }
-}
-
-// Clippy thinks the return value doesn't need to be an Option, it's unaware
-// of the mapping that MapFnFrom<F> does for ResolveModuleCallback.
-#[allow(clippy::unnecessary_wraps)]
-fn json_module_evaluation_steps<'a>(
- context: v8::Local<'a, v8::Context>,
- module: v8::Local<v8::Module>,
-) -> Option<v8::Local<'a, v8::Value>> {
- // SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
- let scope = &mut unsafe { v8::CallbackScope::new(context) };
- let tc_scope = &mut v8::TryCatch::new(scope);
- let module_map = JsRuntime::module_map_from(tc_scope);
-
- let handle = v8::Global::<v8::Module>::new(tc_scope, module);
- let value_handle = module_map
- .borrow_mut()
- .json_value_store
- .remove(&handle)
- .unwrap();
- let value_local = v8::Local::new(tc_scope, value_handle);
-
- let name = v8::String::new(tc_scope, "default").unwrap();
- // This should never fail
- assert!(
- module.set_synthetic_module_export(tc_scope, name, value_local)
- == Some(true)
- );
- assert!(!tc_scope.has_caught());
-
- // Since TLA is active we need to return a promise.
- let resolver = v8::PromiseResolver::new(tc_scope).unwrap();
- let undefined = v8::undefined(tc_scope);
- resolver.resolve(tc_scope, undefined.into());
- Some(resolver.get_promise(tc_scope).into())
-}
-
-pub fn module_origin<'a>(
- s: &mut v8::HandleScope<'a>,
- resource_name: v8::Local<'a, v8::String>,
-) -> v8::ScriptOrigin<'a> {
- let source_map_url = v8::String::empty(s);
- v8::ScriptOrigin::new(
- s,
- resource_name.into(),
- 0,
- 0,
- false,
- 123,
- source_map_url.into(),
- true,
- false,
- true,
- )
-}