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.rs154
1 files changed, 145 insertions, 9 deletions
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index cf94a4767..8da205907 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -1,20 +1,36 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use crate::emit::emit_parsed_source;
use crate::emit::TsTypeLib;
+use crate::graph_util::ModuleEntry;
use crate::proc_state::ProcState;
+use crate::text_encoding::code_without_source_map;
+use crate::text_encoding::source_map_from_code;
+use deno_ast::MediaType;
+use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::futures::future::FutureExt;
use deno_core::futures::Future;
+use deno_core::resolve_url;
use deno_core::ModuleLoader;
+use deno_core::ModuleSource;
use deno_core::ModuleSpecifier;
+use deno_core::ModuleType;
use deno_core::OpState;
+use deno_core::SourceMapGetter;
use deno_runtime::permissions::Permissions;
use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc;
use std::str;
+struct ModuleCodeSource {
+ pub code: String,
+ pub found_url: ModuleSpecifier,
+ pub media_type: MediaType,
+}
+
pub struct CliModuleLoader {
pub lib: TsTypeLib,
/// The initial set of permissions used to resolve the static imports in the
@@ -40,6 +56,65 @@ impl CliModuleLoader {
ps,
})
}
+
+ fn load_prepared_module(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Result<ModuleCodeSource, AnyError> {
+ let graph_data = self.ps.graph_data.read();
+ let found_url = graph_data.follow_redirect(specifier);
+ match graph_data.get(&found_url) {
+ Some(ModuleEntry::Module {
+ code,
+ media_type,
+ maybe_parsed_source,
+ ..
+ }) => {
+ let code = match media_type {
+ MediaType::JavaScript
+ | MediaType::Unknown
+ | MediaType::Cjs
+ | MediaType::Mjs
+ | MediaType::Json => {
+ if let Some(source) = graph_data.get_cjs_esm_translation(specifier)
+ {
+ source.to_owned()
+ } else {
+ code.to_string()
+ }
+ }
+ MediaType::Dts | MediaType::Dcts | MediaType::Dmts => "".to_string(),
+ MediaType::TypeScript
+ | MediaType::Mts
+ | MediaType::Cts
+ | MediaType::Jsx
+ | MediaType::Tsx => {
+ // get emit text
+ let parsed_source = maybe_parsed_source.as_ref().unwrap(); // should always be set
+ emit_parsed_source(
+ &self.ps.emit_cache,
+ &found_url,
+ parsed_source,
+ &self.ps.emit_options,
+ self.ps.emit_options_hash,
+ )?
+ }
+ MediaType::TsBuildInfo | MediaType::Wasm | MediaType::SourceMap => {
+ panic!("Unexpected media type {} for {}", media_type, found_url)
+ }
+ };
+ Ok(ModuleCodeSource {
+ code,
+ found_url,
+ media_type: *media_type,
+ })
+ }
+ _ => Err(anyhow!(
+ "Loading unprepared module: {}",
+ specifier.to_string()
+ )),
+ }
+ }
}
impl ModuleLoader for CliModuleLoader {
@@ -54,18 +129,35 @@ impl ModuleLoader for CliModuleLoader {
fn load(
&self,
- module_specifier: &ModuleSpecifier,
- maybe_referrer: Option<ModuleSpecifier>,
- is_dynamic: bool,
+ specifier: &ModuleSpecifier,
+ _maybe_referrer: Option<ModuleSpecifier>,
+ _is_dynamic: bool,
) -> Pin<Box<deno_core::ModuleSourceFuture>> {
- let module_specifier = module_specifier.clone();
- let ps = self.ps.clone();
-
// NOTE: this block is async only because of `deno_core` interface
// requirements; module was already loaded when constructing module graph
- // during call to `prepare_load`.
- async move { ps.load(module_specifier, maybe_referrer, is_dynamic) }
- .boxed_local()
+ // during call to `prepare_load` so we can load it synchronously.
+ let result = self.load_prepared_module(specifier).map(|code_source| {
+ let code = if self.ps.options.is_inspecting() {
+ // we need the code with the source map in order for
+ // it to work with --inspect or --inspect-brk
+ code_source.code
+ } else {
+ // reduce memory and throw away the source map
+ // because we don't need it
+ code_without_source_map(code_source.code)
+ };
+ ModuleSource {
+ code: code.into_bytes().into_boxed_slice(),
+ module_url_specified: specifier.to_string(),
+ module_url_found: code_source.found_url.to_string(),
+ module_type: match code_source.media_type {
+ MediaType::Json => ModuleType::Json,
+ _ => ModuleType::JavaScript,
+ },
+ }
+ });
+
+ Box::pin(deno_core::futures::future::ready(result))
}
fn prepare_load(
@@ -103,3 +195,47 @@ impl ModuleLoader for CliModuleLoader {
.boxed_local()
}
}
+
+impl SourceMapGetter for CliModuleLoader {
+ fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>> {
+ if let Ok(specifier) = resolve_url(file_name) {
+ match specifier.scheme() {
+ // we should only be looking for emits for schemes that denote external
+ // modules, which the disk_cache supports
+ "wasm" | "file" | "http" | "https" | "data" | "blob" => (),
+ _ => return None,
+ }
+ if let Ok(source) = self.load_prepared_module(&specifier) {
+ source_map_from_code(&source.code)
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ fn get_source_line(
+ &self,
+ file_name: &str,
+ line_number: usize,
+ ) -> Option<String> {
+ let graph_data = self.ps.graph_data.read();
+ let specifier = graph_data.follow_redirect(&resolve_url(file_name).ok()?);
+ let code = match graph_data.get(&specifier) {
+ Some(ModuleEntry::Module { code, .. }) => code,
+ _ => return None,
+ };
+ // Do NOT use .lines(): it skips the terminating empty line.
+ // (due to internally using_terminator() instead of .split())
+ let lines: Vec<&str> = code.split('\n').collect();
+ if line_number >= lines.len() {
+ Some(format!(
+ "{} Couldn't format source line: Line {} is out of bounds (source may have changed at runtime)",
+ crate::colors::yellow("Warning"), line_number + 1,
+ ))
+ } else {
+ Some(lines[line_number].to_string())
+ }
+ }
+}