summaryrefslogtreecommitdiff
path: root/cli/module_loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/module_loader.rs')
-rw-r--r--cli/module_loader.rs160
1 files changed, 160 insertions, 0 deletions
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
new file mode 100644
index 000000000..3cbcade2a
--- /dev/null
+++ b/cli/module_loader.rs
@@ -0,0 +1,160 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+use crate::import_map::ImportMap;
+use crate::permissions::Permissions;
+use crate::program_state::ProgramState;
+use crate::tsc::TargetLib;
+use deno_core::error::AnyError;
+use deno_core::futures::future::FutureExt;
+use deno_core::futures::Future;
+use deno_core::ModuleLoadId;
+use deno_core::ModuleLoader;
+use deno_core::ModuleSpecifier;
+use deno_core::OpState;
+use std::cell::RefCell;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::str;
+use std::sync::Arc;
+
+pub struct CliModuleLoader {
+ /// When flags contains a `.import_map_path` option, the content of the
+ /// import map file will be resolved and set.
+ pub import_map: Option<ImportMap>,
+ pub target_lib: TargetLib,
+ pub is_main: bool,
+}
+
+impl CliModuleLoader {
+ pub fn new(maybe_import_map: Option<ImportMap>) -> Rc<Self> {
+ Rc::new(CliModuleLoader {
+ import_map: maybe_import_map,
+ target_lib: TargetLib::Main,
+ is_main: true,
+ })
+ }
+
+ pub fn new_for_worker() -> Rc<Self> {
+ Rc::new(CliModuleLoader {
+ import_map: None,
+ target_lib: TargetLib::Worker,
+ is_main: false,
+ })
+ }
+}
+
+impl ModuleLoader for CliModuleLoader {
+ fn resolve(
+ &self,
+ op_state: Rc<RefCell<OpState>>,
+ specifier: &str,
+ referrer: &str,
+ is_main: bool,
+ ) -> Result<ModuleSpecifier, AnyError> {
+ let program_state = {
+ let state = op_state.borrow();
+ state.borrow::<Arc<ProgramState>>().clone()
+ };
+
+ // FIXME(bartlomieju): hacky way to provide compatibility with repl
+ let referrer = if referrer.is_empty() && program_state.flags.repl {
+ "<unknown>"
+ } else {
+ referrer
+ };
+
+ if !is_main {
+ if let Some(import_map) = &self.import_map {
+ let result = import_map.resolve(specifier, referrer)?;
+ if let Some(r) = result {
+ return Ok(r);
+ }
+ }
+ }
+
+ let module_specifier =
+ ModuleSpecifier::resolve_import(specifier, referrer)?;
+
+ Ok(module_specifier)
+ }
+
+ fn load(
+ &self,
+ op_state: Rc<RefCell<OpState>>,
+ module_specifier: &ModuleSpecifier,
+ maybe_referrer: Option<ModuleSpecifier>,
+ _is_dyn_import: bool,
+ ) -> Pin<Box<deno_core::ModuleSourceFuture>> {
+ let module_specifier = module_specifier.to_owned();
+ let module_url_specified = module_specifier.to_string();
+ let program_state = {
+ let state = op_state.borrow();
+ state.borrow::<Arc<ProgramState>>().clone()
+ };
+
+ // TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param
+ let fut = async move {
+ let compiled_module = program_state
+ .fetch_compiled_module(module_specifier, maybe_referrer)
+ .await?;
+ Ok(deno_core::ModuleSource {
+ // Real module name, might be different from initial specifier
+ // due to redirections.
+ code: compiled_module.code,
+ module_url_specified,
+ module_url_found: compiled_module.name,
+ })
+ };
+
+ fut.boxed_local()
+ }
+
+ fn prepare_load(
+ &self,
+ op_state: Rc<RefCell<OpState>>,
+ _load_id: ModuleLoadId,
+ module_specifier: &ModuleSpecifier,
+ maybe_referrer: Option<String>,
+ is_dyn_import: bool,
+ ) -> Pin<Box<dyn Future<Output = Result<(), AnyError>>>> {
+ let module_specifier = module_specifier.clone();
+ let target_lib = self.target_lib.clone();
+ let maybe_import_map = self.import_map.clone();
+ let state = op_state.borrow();
+
+ // Only "main" module is loaded without permission check,
+ // ie. module that is associated with "is_main" state
+ // and is not a dynamic import.
+ let permissions = if self.is_main && !is_dyn_import {
+ Permissions::allow_all()
+ } else {
+ state.borrow::<Permissions>().clone()
+ };
+ let program_state = state.borrow::<Arc<ProgramState>>().clone();
+ drop(state);
+
+ // TODO(bartlomieju): I'm not sure if it's correct to ignore
+ // bad referrer - this is the case for `Deno.core.evalContext()` where
+ // `ref_str` is `<unknown>`.
+ let maybe_referrer = if let Some(ref_str) = maybe_referrer {
+ ModuleSpecifier::resolve_url(&ref_str).ok()
+ } else {
+ None
+ };
+
+ // TODO(bartlomieju): `prepare_module_load` should take `load_id` param
+ async move {
+ program_state
+ .prepare_module_load(
+ module_specifier,
+ maybe_referrer,
+ target_lib,
+ permissions,
+ is_dyn_import,
+ maybe_import_map,
+ )
+ .await
+ }
+ .boxed_local()
+ }
+}