summaryrefslogtreecommitdiff
path: root/cli/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/main.rs')
-rw-r--r--cli/main.rs365
1 files changed, 216 insertions, 149 deletions
diff --git a/cli/main.rs b/cli/main.rs
index 4ffa8340c..8a85cacfb 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -2,6 +2,7 @@
mod ast;
mod auth_tokens;
+mod cache;
mod checksum;
mod compat;
mod config_file;
@@ -9,6 +10,7 @@ mod deno_dir;
mod diagnostics;
mod diff;
mod disk_cache;
+mod emit;
mod errors;
mod file_fetcher;
mod file_watcher;
@@ -18,16 +20,14 @@ mod fmt_errors;
mod fs_util;
mod http_cache;
mod http_util;
-mod info;
mod lockfile;
mod logger;
mod lsp;
-mod module_graph;
mod module_loader;
mod ops;
mod proc_state;
+mod resolver;
mod source_maps;
-mod specifier_handler;
mod standalone;
mod text_encoding;
mod tokio_util;
@@ -59,8 +59,8 @@ use crate::flags::UpgradeFlags;
use crate::fmt_errors::PrettyJsError;
use crate::module_loader::CliModuleLoader;
use crate::proc_state::ProcState;
+use crate::resolver::ImportMapResolver;
use crate::source_maps::apply_source_map;
-use crate::specifier_handler::FetchHandler;
use crate::tools::installer::infer_name_from_url;
use deno_ast::MediaType;
use deno_core::error::generic_error;
@@ -68,7 +68,6 @@ use deno_core::error::AnyError;
use deno_core::futures::future::FutureExt;
use deno_core::futures::Future;
use deno_core::located_script_name;
-use deno_core::parking_lot::Mutex;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::serde_json::json;
@@ -299,7 +298,7 @@ where
fn print_cache_info(
state: &ProcState,
json: bool,
- location: Option<deno_core::url::Url>,
+ location: Option<&deno_core::url::Url>,
) -> Result<(), AnyError> {
let deno_dir = &state.dir.root;
let modules_cache = &state.file_fetcher.get_http_cache_location();
@@ -402,19 +401,9 @@ async fn compile_command(
"An executable name was not provided. One could not be inferred from the URL. Aborting.",
))?;
- let module_graph = create_module_graph_and_maybe_check(
- module_specifier.clone(),
- ps.clone(),
- debug,
- )
- .await?;
-
- info!(
- "{} {}",
- colors::green("Bundle"),
- module_specifier.to_string()
- );
- let bundle_str = bundle_module_graph(module_graph, ps.clone(), flags, debug)?;
+ let graph =
+ create_graph_and_maybe_check(module_specifier.clone(), &ps, debug).await?;
+ let (bundle_str, _) = bundle_module_graph(graph.as_ref(), &ps, &flags)?;
info!(
"{} {}",
@@ -449,36 +438,38 @@ async fn info_command(
flags: Flags,
info_flags: InfoFlags,
) -> Result<(), AnyError> {
- let location = flags.location.clone();
let ps = ProcState::build(flags).await?;
if let Some(specifier) = info_flags.file {
let specifier = resolve_url_or_path(&specifier)?;
- let handler = Arc::new(Mutex::new(specifier_handler::FetchHandler::new(
- &ps,
- // info accesses dynamically imported modules just for their information
- // so we allow access to all of them.
+ let mut cache = cache::FetchCacher::new(
+ ps.dir.gen_cache.clone(),
+ ps.file_fetcher.clone(),
Permissions::allow_all(),
Permissions::allow_all(),
- )?));
- let mut builder = module_graph::GraphBuilder::new(
- handler,
- ps.maybe_import_map.clone(),
- ps.lockfile.clone(),
);
- builder.add(&specifier, false).await?;
- builder.analyze_config_file(&ps.maybe_config_file).await?;
- let graph = builder.get_graph();
- let info = graph.info()?;
+ let maybe_locker = lockfile::as_maybe_locker(ps.lockfile.clone());
+ let maybe_resolver =
+ ps.maybe_import_map.as_ref().map(ImportMapResolver::new);
+ let graph = deno_graph::create_graph(
+ vec![specifier],
+ false,
+ None,
+ &mut cache,
+ maybe_resolver.as_ref().map(|r| r.as_resolver()),
+ maybe_locker,
+ None,
+ )
+ .await;
if info_flags.json {
- write_json_to_stdout(&json!(info))
+ write_json_to_stdout(&json!(graph))
} else {
- write_to_stdout_ignore_sigpipe(info.to_string().as_bytes())
+ write_to_stdout_ignore_sigpipe(graph.to_string().as_bytes())
.map_err(|err| err.into())
}
} else {
// If it was just "deno info" print location of caches and exit
- print_cache_info(&ps, info_flags.json, location)
+ print_cache_info(&ps, info_flags.json, ps.flags.location.as_ref())
}
}
@@ -541,23 +532,25 @@ async fn cache_command(
cache_flags: CacheFlags,
) -> Result<(), AnyError> {
let lib = if flags.unstable {
- module_graph::TypeLib::UnstableDenoWindow
+ emit::TypeLib::UnstableDenoWindow
} else {
- module_graph::TypeLib::DenoWindow
+ emit::TypeLib::DenoWindow
};
let ps = ProcState::build(flags).await?;
for file in cache_flags.files {
let specifier = resolve_url_or_path(&file)?;
ps.prepare_module_load(
- specifier,
+ vec![specifier],
+ false,
lib.clone(),
Permissions::allow_all(),
Permissions::allow_all(),
- false,
- ps.maybe_import_map.clone(),
)
.await?;
+ if let Some(graph_error) = ps.maybe_graph_error.lock().take() {
+ return Err(graph_error.into());
+ }
}
Ok(())
@@ -567,8 +560,10 @@ async fn eval_command(
flags: Flags,
eval_flags: EvalFlags,
) -> Result<(), AnyError> {
- // Force TypeScript compile.
- let main_module = resolve_url_or_path("./$deno$eval.ts").unwrap();
+ // deno_graph works off of extensions for local files to determine the media
+ // type, and so our "fake" specifier needs to have the proper extension.
+ let main_module =
+ resolve_url_or_path(&format!("./$deno$eval.{}", eval_flags.ext)).unwrap();
let permissions = Permissions::from_options(&flags.clone().into());
let ps = ProcState::build(flags.clone()).await?;
let mut worker =
@@ -584,15 +579,7 @@ async fn eval_command(
let file = File {
local: main_module.clone().to_file_path().unwrap(),
maybe_types: None,
- media_type: if eval_flags.ext.as_str() == "ts" {
- MediaType::TypeScript
- } else if eval_flags.ext.as_str() == "tsx" {
- MediaType::Tsx
- } else if eval_flags.ext.as_str() == "js" {
- MediaType::JavaScript
- } else {
- MediaType::Jsx
- },
+ media_type: MediaType::Unknown,
source: Arc::new(String::from_utf8(source_code)?),
specifier: main_module.clone(),
maybe_headers: None,
@@ -603,9 +590,7 @@ async fn eval_command(
ps.file_fetcher.insert_cached(file);
debug!("main_module {}", &main_module);
if flags.compat {
- worker
- .execute_side_module(&compat::get_node_globals_url())
- .await?;
+ worker.execute_side_module(&compat::GLOBAL_URL).await?;
}
worker.execute_main_module(&main_module).await?;
worker.execute_script(
@@ -620,75 +605,133 @@ async fn eval_command(
Ok(())
}
-async fn create_module_graph_and_maybe_check(
- module_specifier: ModuleSpecifier,
- ps: ProcState,
+async fn create_graph_and_maybe_check(
+ root: ModuleSpecifier,
+ ps: &ProcState,
debug: bool,
-) -> Result<module_graph::Graph, AnyError> {
- let handler = Arc::new(Mutex::new(FetchHandler::new(
- &ps,
- // when bundling, dynamic imports are only access for their type safety,
- // therefore we will allow the graph to access any module.
+) -> Result<Arc<deno_graph::ModuleGraph>, AnyError> {
+ let mut cache = cache::FetchCacher::new(
+ ps.dir.gen_cache.clone(),
+ ps.file_fetcher.clone(),
Permissions::allow_all(),
Permissions::allow_all(),
- )?));
- let mut builder = module_graph::GraphBuilder::new(
- handler,
- ps.maybe_import_map.clone(),
- ps.lockfile.clone(),
);
- builder.add(&module_specifier, false).await?;
- builder.analyze_config_file(&ps.maybe_config_file).await?;
- let module_graph = builder.get_graph();
+ let maybe_locker = lockfile::as_maybe_locker(ps.lockfile.clone());
+ let maybe_imports = ps
+ .maybe_config_file
+ .as_ref()
+ .map(|cf| cf.to_maybe_imports())
+ .flatten();
+ let maybe_resolver = ps.maybe_import_map.as_ref().map(ImportMapResolver::new);
+ let graph = Arc::new(
+ deno_graph::create_graph(
+ vec![root],
+ false,
+ maybe_imports,
+ &mut cache,
+ maybe_resolver.as_ref().map(|r| r.as_resolver()),
+ maybe_locker,
+ None,
+ )
+ .await,
+ );
+
+ // Ensure that all non-dynamic, non-type only imports are properly loaded and
+ // if not, error with the first issue encountered.
+ graph.valid().map_err(emit::GraphError::from)?;
+ // If there was a locker, validate the integrity of all the modules in the
+ // locker.
+ emit::lock(graph.as_ref());
if !ps.flags.no_check {
- // TODO(@kitsonk) support bundling for workers
+ graph.valid_types_only().map_err(emit::GraphError::from)?;
let lib = if ps.flags.unstable {
- module_graph::TypeLib::UnstableDenoWindow
+ emit::TypeLib::UnstableDenoWindow
} else {
- module_graph::TypeLib::DenoWindow
+ emit::TypeLib::DenoWindow
};
- let result_info =
- module_graph.clone().check(module_graph::CheckOptions {
- debug,
- emit: false,
+ let (ts_config, maybe_ignored_options) = emit::get_ts_config(
+ emit::ConfigType::Check {
+ tsc_emit: false,
lib,
- maybe_config_file: ps.maybe_config_file.clone(),
- reload: ps.flags.reload,
- ..Default::default()
- })?;
-
- debug!("{}", result_info.stats);
- if let Some(ignored_options) = result_info.maybe_ignored_options {
+ },
+ ps.maybe_config_file.as_ref(),
+ None,
+ )?;
+ log::info!("{} {}", colors::green("Check"), graph.roots[0]);
+ if let Some(ignored_options) = maybe_ignored_options {
eprintln!("{}", ignored_options);
}
- if !result_info.diagnostics.is_empty() {
- return Err(generic_error(result_info.diagnostics.to_string()));
+ let maybe_config_specifier = ps
+ .maybe_config_file
+ .as_ref()
+ .map(|cf| ModuleSpecifier::from_file_path(&cf.path).unwrap());
+ let check_result = emit::check_and_maybe_emit(
+ graph.clone(),
+ &mut cache,
+ emit::CheckOptions {
+ debug,
+ emit_with_diagnostics: false,
+ maybe_config_specifier,
+ ts_config,
+ },
+ )?;
+ debug!("{}", check_result.stats);
+ if !check_result.diagnostics.is_empty() {
+ return Err(check_result.diagnostics.into());
}
}
- Ok(module_graph)
+ Ok(graph)
}
fn bundle_module_graph(
- module_graph: module_graph::Graph,
- ps: ProcState,
- flags: Flags,
- debug: bool,
-) -> Result<String, AnyError> {
- let (bundle, stats, maybe_ignored_options) =
- module_graph.bundle(module_graph::BundleOptions {
- debug,
- maybe_config_file: ps.maybe_config_file.clone(),
- })?;
- match maybe_ignored_options {
- Some(ignored_options) if flags.no_check => {
+ graph: &deno_graph::ModuleGraph,
+ ps: &ProcState,
+ flags: &Flags,
+) -> Result<(String, Option<String>), AnyError> {
+ info!("{} {}", colors::green("Bundle"), graph.roots[0]);
+
+ let (ts_config, maybe_ignored_options) = emit::get_ts_config(
+ emit::ConfigType::Bundle,
+ ps.maybe_config_file.as_ref(),
+ None,
+ )?;
+ if flags.no_check {
+ if let Some(ignored_options) = maybe_ignored_options {
eprintln!("{}", ignored_options);
}
- _ => {}
}
- debug!("{}", stats);
- Ok(bundle)
+
+ emit::bundle(
+ graph,
+ emit::BundleOptions {
+ bundle_type: emit::BundleType::Module,
+ ts_config,
+ },
+ )
+}
+
+/// A function that converts a float to a string the represents a human
+/// readable version of that number.
+fn human_size(size: f64) -> String {
+ let negative = if size.is_sign_positive() { "" } else { "-" };
+ let size = size.abs();
+ let units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
+ if size < 1_f64 {
+ return format!("{}{}{}", negative, size, "B");
+ }
+ let delimiter = 1024_f64;
+ let exponent = std::cmp::min(
+ (size.ln() / delimiter.ln()).floor() as i32,
+ (units.len() - 1) as i32,
+ );
+ let pretty_bytes = format!("{:.2}", size / delimiter.powi(exponent))
+ .parse::<f64>()
+ .unwrap()
+ * 1_f64;
+ let unit = units[exponent as usize];
+ format!("{}{}{}", negative, pretty_bytes, unit)
}
async fn bundle_command(
@@ -707,17 +750,18 @@ async fn bundle_command(
debug!(">>>>> bundle START");
let ps = ProcState::build(flags.clone()).await?;
- let module_graph = create_module_graph_and_maybe_check(
- module_specifier,
- ps.clone(),
- debug,
- )
- .await?;
+ let graph =
+ create_graph_and_maybe_check(module_specifier, &ps, debug).await?;
- let mut paths_to_watch: Vec<PathBuf> = module_graph
- .get_modules()
+ let mut paths_to_watch: Vec<PathBuf> = graph
+ .specifiers()
.iter()
- .filter_map(|specifier| specifier.to_file_path().ok())
+ .filter_map(|(_, r)| {
+ r.as_ref()
+ .ok()
+ .map(|(s, _)| s.to_file_path().ok())
+ .flatten()
+ })
.collect();
if let Some(import_map) = ps.flags.import_map_path.as_ref() {
@@ -725,12 +769,12 @@ async fn bundle_command(
.push(fs_util::resolve_from_cwd(std::path::Path::new(import_map))?);
}
- Ok((paths_to_watch, module_graph, ps))
+ Ok((paths_to_watch, graph, ps))
}
.map(move |result| match result {
- Ok((paths_to_watch, module_graph, ps)) => ResolutionResult::Restart {
+ Ok((paths_to_watch, graph, ps)) => ResolutionResult::Restart {
paths_to_watch,
- result: Ok((ps, module_graph)),
+ result: Ok((ps, graph)),
},
Err(e) => ResolutionResult::Restart {
paths_to_watch: vec![PathBuf::from(source_file2)],
@@ -739,28 +783,43 @@ async fn bundle_command(
})
};
- let operation = |(ps, module_graph): (ProcState, module_graph::Graph)| {
+ let operation = |(ps, graph): (ProcState, Arc<deno_graph::ModuleGraph>)| {
let flags = flags.clone();
let out_file = bundle_flags.out_file.clone();
async move {
- info!("{} {}", colors::green("Bundle"), module_graph.info()?.root);
-
- let output = bundle_module_graph(module_graph, ps, flags, debug)?;
-
+ let (bundle_emit, maybe_bundle_map) =
+ bundle_module_graph(graph.as_ref(), &ps, &flags)?;
debug!(">>>>> bundle END");
if let Some(out_file) = out_file.as_ref() {
- let output_bytes = output.as_bytes();
+ let output_bytes = bundle_emit.as_bytes();
let output_len = output_bytes.len();
fs_util::write_file(out_file, output_bytes, 0o644)?;
info!(
"{} {:?} ({})",
colors::green("Emit"),
out_file,
- colors::gray(&info::human_size(output_len as f64))
+ colors::gray(human_size(output_len as f64))
);
+ if let Some(bundle_map) = maybe_bundle_map {
+ let map_bytes = bundle_map.as_bytes();
+ let map_len = map_bytes.len();
+ let ext = if let Some(curr_ext) = out_file.extension() {
+ format!("{}.map", curr_ext.to_string_lossy())
+ } else {
+ "map".to_string()
+ };
+ let map_out_file = out_file.with_extension(ext);
+ fs_util::write_file(&map_out_file, map_bytes, 0o644)?;
+ info!(
+ "{} {:?} ({})",
+ colors::green("Emit"),
+ map_out_file,
+ colors::gray(human_size(map_len as f64))
+ );
+ }
} else {
- println!("{}", output);
+ println!("{}", bundle_emit);
}
Ok(())
@@ -825,9 +884,7 @@ async fn run_repl(flags: Flags, repl_flags: ReplFlags) -> Result<(), AnyError> {
let mut worker =
create_main_worker(&ps, main_module.clone(), permissions, None);
if flags.compat {
- worker
- .execute_side_module(&compat::get_node_globals_url())
- .await?;
+ worker.execute_side_module(&compat::GLOBAL_URL).await?;
}
worker.run_event_loop(false).await?;
@@ -858,9 +915,7 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> {
debug!("main_module {}", main_module);
if flags.compat {
- worker
- .execute_side_module(&compat::get_node_globals_url())
- .await?;
+ worker.execute_side_module(&compat::GLOBAL_URL).await?;
}
worker.execute_main_module(&main_module).await?;
worker.execute_script(
@@ -883,25 +938,42 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> {
async move {
let main_module = resolve_url_or_path(&script1)?;
let ps = ProcState::build(flags).await?;
- let handler = Arc::new(Mutex::new(FetchHandler::new(
- &ps,
+ let mut cache = cache::FetchCacher::new(
+ ps.dir.gen_cache.clone(),
+ ps.file_fetcher.clone(),
Permissions::allow_all(),
Permissions::allow_all(),
- )?));
- let mut builder = module_graph::GraphBuilder::new(
- handler,
- ps.maybe_import_map.clone(),
- ps.lockfile.clone(),
);
- builder.add(&main_module, false).await?;
- builder.analyze_config_file(&ps.maybe_config_file).await?;
- let module_graph = builder.get_graph();
+ let maybe_locker = lockfile::as_maybe_locker(ps.lockfile.clone());
+ let maybe_imports = ps
+ .maybe_config_file
+ .as_ref()
+ .map(|cf| cf.to_maybe_imports())
+ .flatten();
+ let maybe_resolver =
+ ps.maybe_import_map.as_ref().map(ImportMapResolver::new);
+ let graph = deno_graph::create_graph(
+ vec![main_module.clone()],
+ false,
+ maybe_imports,
+ &mut cache,
+ maybe_resolver.as_ref().map(|r| r.as_resolver()),
+ maybe_locker,
+ None,
+ )
+ .await;
+ graph.valid()?;
// Find all local files in graph
- let mut paths_to_watch: Vec<PathBuf> = module_graph
- .get_modules()
+ let mut paths_to_watch: Vec<PathBuf> = graph
+ .specifiers()
.iter()
- .filter_map(|specifier| specifier.to_file_path().ok())
+ .filter_map(|(_, r)| {
+ r.as_ref()
+ .ok()
+ .map(|(s, _)| s.to_file_path().ok())
+ .flatten()
+ })
.collect();
if let Some(import_map) = ps.flags.import_map_path.as_ref() {
@@ -948,10 +1020,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> {
main_module: &ModuleSpecifier,
) -> Result<(), AnyError> {
if self.compat {
- self
- .worker
- .execute_side_module(&compat::get_node_globals_url())
- .await?;
+ self.worker.execute_side_module(&compat::GLOBAL_URL).await?;
}
self.worker.execute_main_module(main_module).await?;
self.worker.execute_script(
@@ -1046,9 +1115,7 @@ async fn run_command(
debug!("main_module {}", main_module);
if flags.compat {
- worker
- .execute_side_module(&compat::get_node_globals_url())
- .await?;
+ worker.execute_side_module(&compat::GLOBAL_URL).await?;
}
worker.execute_main_module(&main_module).await?;
worker.execute_script(