From 1964172bf6b2e64f4522f6d6b2a68d02bc495014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 13 Mar 2023 21:12:09 -0400 Subject: [PATCH] refactor(core): resolve_url_or_path and resolve_url_or_path_deprecated (#18170) This commit changes current "deno_core::resolve_url_or_path" API to "resolve_url_or_path_deprecated" and adds new "resolve_url_or_path" API that requires to explicitly pass the directory from which paths should be resolved to. Some of the call sites were updated to use the new API, the reminder of them will be updated in a follow up PR. Towards landing https://github.com/denoland/deno/pull/15454 --- cli/args/config_file.rs | 2 +- cli/args/flags.rs | 29 +++++++-------- cli/args/mod.rs | 65 ++++++++++++++++++++++++++-------- cli/proc_state.rs | 9 +++-- cli/standalone.rs | 4 +-- cli/tests/unit/process_test.ts | 2 +- cli/tools/bench.rs | 3 +- cli/tools/bundle.rs | 4 +-- cli/tools/coverage/mod.rs | 6 ++-- cli/tools/doc.rs | 8 ++--- cli/tools/info.rs | 2 +- cli/tools/installer.rs | 5 +-- cli/tools/repl/mod.rs | 8 ++--- cli/tools/repl/session.rs | 8 +++-- cli/tools/run.rs | 12 ++++--- cli/tools/standalone.rs | 44 ++++++++++++++--------- cli/tools/test.rs | 5 +-- cli/tools/vendor/mod.rs | 2 +- cli/tsc/mod.rs | 4 +-- cli/worker.rs | 3 +- core/lib.rs | 1 + core/module_specifier.rs | 33 +++++++++++++---- core/ops_builtin_v8.rs | 4 +-- 23 files changed, 169 insertions(+), 94 deletions(-) diff --git a/cli/args/config_file.rs b/cli/args/config_file.rs index b5ee8c50ae..6df06da5e2 100644 --- a/cli/args/config_file.rs +++ b/cli/args/config_file.rs @@ -506,7 +506,7 @@ impl ConfigFile { Ok(Some(ConfigFile::read(&config_path)?)) } ConfigFlag::Discover => { - if let Some(config_path_args) = flags.config_path_args() { + if let Some(config_path_args) = flags.config_path_args(cwd) { let mut checked = HashSet::new(); for f in config_path_args { if let Some(cf) = Self::discover_from(&f, &mut checked)? { diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 26cf497f6a..883a4d0342 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -6,6 +6,7 @@ use clap::ColorChoice; use clap::Command; use clap::ValueHint; use deno_core::error::AnyError; +use deno_core::resolve_url_or_path; use deno_core::url::Url; use deno_runtime::permissions::parse_sys_kind; use log::debug; @@ -16,6 +17,7 @@ use std::net::SocketAddr; use std::num::NonZeroU32; use std::num::NonZeroU8; use std::num::NonZeroUsize; +use std::path::Path; use std::path::PathBuf; use std::str::FromStr; @@ -474,16 +476,17 @@ impl Flags { /// Extract path arguments for config search paths. /// If it returns Some(vec), the config should be discovered - /// from the current dir after trying to discover from each entry in vec. + /// from the passed `current_dir` after trying to discover from each entry in + /// the returned vector. /// If it returns None, the config file shouldn't be discovered at all. - pub fn config_path_args(&self) -> Option> { + pub fn config_path_args(&self, current_dir: &Path) -> Option> { use DenoSubcommand::*; match &self.subcommand { Fmt(FmtFlags { files, .. }) => Some(files.include.clone()), Lint(LintFlags { files, .. }) => Some(files.include.clone()), Run(RunFlags { script }) => { - if let Ok(module_specifier) = deno_core::resolve_url_or_path(script) { + if let Ok(module_specifier) = resolve_url_or_path(script, current_dir) { if module_specifier.scheme() == "file" || module_specifier.scheme() == "npm" { @@ -520,12 +523,12 @@ impl Flags { /// from the `path` dir. /// If it returns None, the `package.json` file shouldn't be discovered at /// all. - pub fn package_json_search_dir(&self) -> Option { + pub fn package_json_search_dir(&self, current_dir: &Path) -> Option { use DenoSubcommand::*; match &self.subcommand { Run(RunFlags { script }) => { - let module_specifier = deno_core::resolve_url_or_path(script).ok()?; + let module_specifier = resolve_url_or_path(script, current_dir).ok()?; if module_specifier.scheme() == "file" { let p = module_specifier .to_file_path() @@ -540,7 +543,7 @@ impl Flags { } } Task(TaskFlags { cwd: Some(cwd), .. }) => { - deno_core::resolve_url_or_path(cwd) + resolve_url_or_path(cwd, current_dir) .ok()? .to_file_path() .ok() @@ -6338,30 +6341,28 @@ mod tests { #[test] fn test_config_path_args() { let flags = flags_from_vec(svec!["deno", "run", "foo.js"]).unwrap(); - assert_eq!( - flags.config_path_args(), - Some(vec![std::env::current_dir().unwrap().join("foo.js")]) - ); + let cwd = std::env::current_dir().unwrap(); + assert_eq!(flags.config_path_args(&cwd), Some(vec![cwd.join("foo.js")])); let flags = flags_from_vec(svec!["deno", "run", "https://example.com/foo.js"]) .unwrap(); - assert_eq!(flags.config_path_args(), None); + assert_eq!(flags.config_path_args(&cwd), None); let flags = flags_from_vec(svec!["deno", "lint", "dir/a.js", "dir/b.js"]).unwrap(); assert_eq!( - flags.config_path_args(), + flags.config_path_args(&cwd), Some(vec![PathBuf::from("dir/a.js"), PathBuf::from("dir/b.js")]) ); let flags = flags_from_vec(svec!["deno", "lint"]).unwrap(); - assert!(flags.config_path_args().unwrap().is_empty()); + assert!(flags.config_path_args(&cwd).unwrap().is_empty()); let flags = flags_from_vec(svec!["deno", "fmt", "dir/a.js", "dir/b.js"]).unwrap(); assert_eq!( - flags.config_path_args(), + flags.config_path_args(&cwd), Some(vec![PathBuf::from("dir/a.js"), PathBuf::from("dir/b.js")]) ); } diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 5be5fc7ab3..25a1514f39 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -385,11 +385,12 @@ fn resolve_lint_rules_options( fn discover_package_json( flags: &Flags, maybe_stop_at: Option, + current_dir: &Path, ) -> Result, AnyError> { // TODO(bartlomieju): discover for all subcommands, but print warnings that // `package.json` is ignored in bundle/compile/etc. - if let Some(package_json_dir) = flags.package_json_search_dir() { + if let Some(package_json_dir) = flags.package_json_search_dir(current_dir) { let package_json_dir = canonicalize_path_maybe_not_exists(&package_json_dir)?; return package_json::discover_from(&package_json_dir, maybe_stop_at); @@ -509,6 +510,7 @@ pub struct CliOptions { // the source of the options is a detail the rest of the // application need not concern itself with, so keep these private flags: Flags, + initial_cwd: PathBuf, maybe_node_modules_folder: Option, maybe_config_file: Option, maybe_package_json: Option, @@ -549,6 +551,7 @@ impl CliOptions { Ok(Self { flags, + initial_cwd, maybe_config_file, maybe_lockfile, maybe_package_json, @@ -577,10 +580,11 @@ impl CliOptions { .parent() .map(|p| p.to_path_buf()); - maybe_package_json = discover_package_json(&flags, maybe_stop_at)?; + maybe_package_json = + discover_package_json(&flags, maybe_stop_at, &initial_cwd)?; } } else { - maybe_package_json = discover_package_json(&flags, None)?; + maybe_package_json = discover_package_json(&flags, None, &initial_cwd)?; } let maybe_lock_file = @@ -594,6 +598,11 @@ impl CliOptions { ) } + #[inline(always)] + pub fn initial_cwd(&self) -> &Path { + &self.initial_cwd + } + pub fn maybe_config_file_specifier(&self) -> Option { self.maybe_config_file.as_ref().map(|f| f.specifier.clone()) } @@ -641,6 +650,7 @@ impl CliOptions { None => resolve_import_map_specifier( self.flags.import_map_path.as_deref(), self.maybe_config_file.as_ref(), + &self.initial_cwd, ), } } @@ -1071,6 +1081,7 @@ fn resolve_local_node_modules_folder( fn resolve_import_map_specifier( maybe_import_map_path: Option<&str>, maybe_config_file: Option<&ConfigFile>, + current_dir: &Path, ) -> Result, AnyError> { if let Some(import_map_path) = maybe_import_map_path { if let Some(config_file) = &maybe_config_file { @@ -1078,8 +1089,9 @@ fn resolve_import_map_specifier( log::warn!("{} the configuration file \"{}\" contains an entry for \"importMap\" that is being ignored.", colors::yellow("Warning"), config_file.specifier); } } - let specifier = deno_core::resolve_url_or_path(import_map_path) - .context(format!("Bad URL (\"{import_map_path}\") for import map."))?; + let specifier = + deno_core::resolve_url_or_path(import_map_path, current_dir) + .context(format!("Bad URL (\"{import_map_path}\") for import map."))?; return Ok(Some(specifier)); } else if let Some(config_file) = &maybe_config_file { // if the config file is an import map we prefer to use it, over `importMap` @@ -1171,7 +1183,11 @@ mod test { let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); - let actual = resolve_import_map_specifier(None, Some(&config_file)); + let actual = resolve_import_map_specifier( + None, + Some(&config_file), + &PathBuf::from("/"), + ); assert!(actual.is_ok()); let actual = actual.unwrap(); assert_eq!( @@ -1188,7 +1204,11 @@ mod test { let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); - let actual = resolve_import_map_specifier(None, Some(&config_file)); + let actual = resolve_import_map_specifier( + None, + Some(&config_file), + &PathBuf::from("/"), + ); assert!(actual.is_ok()); let actual = actual.unwrap(); assert_eq!( @@ -1207,7 +1227,11 @@ mod test { let config_specifier = ModuleSpecifier::parse("https://example.com/deno.jsonc").unwrap(); let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); - let actual = resolve_import_map_specifier(None, Some(&config_file)); + let actual = resolve_import_map_specifier( + None, + Some(&config_file), + &PathBuf::from("/"), + ); assert!(actual.is_ok()); let actual = actual.unwrap(); assert_eq!( @@ -1223,13 +1247,16 @@ mod test { let config_text = r#"{ "importMap": "import_map.json" }"#; + let cwd = &PathBuf::from("/"); let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); - let actual = - resolve_import_map_specifier(Some("import-map.json"), Some(&config_file)); - let import_map_path = - std::env::current_dir().unwrap().join("import-map.json"); + let actual = resolve_import_map_specifier( + Some("import-map.json"), + Some(&config_file), + cwd, + ); + let import_map_path = cwd.join("import-map.json"); let expected_specifier = ModuleSpecifier::from_file_path(import_map_path).unwrap(); assert!(actual.is_ok()); @@ -1246,7 +1273,11 @@ mod test { let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); - let actual = resolve_import_map_specifier(None, Some(&config_file)); + let actual = resolve_import_map_specifier( + None, + Some(&config_file), + &PathBuf::from("/"), + ); assert!(actual.is_ok()); let actual = actual.unwrap(); assert_eq!(actual, Some(config_specifier)); @@ -1258,7 +1289,11 @@ mod test { let config_specifier = ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); - let actual = resolve_import_map_specifier(None, Some(&config_file)); + let actual = resolve_import_map_specifier( + None, + Some(&config_file), + &PathBuf::from("/"), + ); assert!(actual.is_ok()); let actual = actual.unwrap(); assert_eq!(actual, None); @@ -1266,7 +1301,7 @@ mod test { #[test] fn resolve_import_map_no_config() { - let actual = resolve_import_map_specifier(None, None); + let actual = resolve_import_map_specifier(None, None, &PathBuf::from("/")); assert!(actual.is_ok()); let actual = actual.unwrap(); assert_eq!(actual, None); diff --git a/cli/proc_state.rs b/cli/proc_state.rs index eb43e75d73..4d8acf5249 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -459,7 +459,7 @@ impl ProcState { let specifiers = files .iter() - .map(|file| resolve_url_or_path(file)) + .map(|file| resolve_url_or_path(file, self.options.initial_cwd())) .collect::, _>>()?; self .prepare_module_load( @@ -495,7 +495,7 @@ impl ProcState { referrer: &str, permissions: &mut PermissionsContainer, ) -> Result { - if let Ok(referrer) = deno_core::resolve_url_or_path(referrer) { + if let Ok(referrer) = deno_core::resolve_url_or_path_deprecated(referrer) { if self.npm_resolver.in_npm_package(&referrer) { // we're in an npm package, so use node resolution return self @@ -565,10 +565,9 @@ impl ProcState { // but sadly that's not the case due to missing APIs in V8. let is_repl = matches!(self.options.sub_command(), DenoSubcommand::Repl(_)); let referrer = if referrer.is_empty() && is_repl { - let cwd = std::env::current_dir().context("Unable to get CWD")?; - deno_core::resolve_path("./$deno$repl.ts", &cwd)? + deno_core::resolve_path("./$deno$repl.ts", self.options.initial_cwd())? } else { - deno_core::resolve_url_or_path(referrer)? + deno_core::resolve_url_or_path_deprecated(referrer)? }; // FIXME(bartlomieju): this is another hack way to provide NPM specifier diff --git a/cli/standalone.rs b/cli/standalone.rs index ecf2959247..7e0658165a 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -140,9 +140,9 @@ impl ModuleLoader for EmbeddedModuleLoader { // Try to follow redirects when resolving. let referrer = match self.eszip.get_module(referrer) { Some(eszip::Module { ref specifier, .. }) => { - deno_core::resolve_url_or_path(specifier)? + deno_core::resolve_url_or_path_deprecated(specifier)? } - None => deno_core::resolve_url_or_path(referrer)?, + None => deno_core::resolve_url_or_path_deprecated(referrer)?, }; self.maybe_import_map_resolver.as_ref().map_or_else( diff --git a/cli/tests/unit/process_test.ts b/cli/tests/unit/process_test.ts index e79365a6df..1799a01905 100644 --- a/cli/tests/unit/process_test.ts +++ b/cli/tests/unit/process_test.ts @@ -658,6 +658,6 @@ Deno.test( p.close(); p.stdout.close(); assertStrictEquals(code, 1); - assertStringIncludes(stderr, "Unable to get CWD"); + assertStringIncludes(stderr, "No such file or directory"); }, ); diff --git a/cli/tools/bench.rs b/cli/tools/bench.rs index 578b72adfb..70fc34ca1f 100644 --- a/cli/tools/bench.rs +++ b/cli/tools/bench.rs @@ -692,7 +692,8 @@ pub async fn run_benchmarks_with_watch( if let Some(changed) = &changed { for path in changed.iter().filter_map(|path| { - deno_core::resolve_url_or_path(&path.to_string_lossy()).ok() + deno_core::resolve_url_or_path_deprecated(&path.to_string_lossy()) + .ok() }) { if modules.contains(&path) { modules_to_reload.push(specifier); diff --git a/cli/tools/bundle.rs b/cli/tools/bundle.rs index d75da5ec76..c1d4befb12 100644 --- a/cli/tools/bundle.rs +++ b/cli/tools/bundle.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use deno_core::error::AnyError; use deno_core::futures::FutureExt; -use deno_core::resolve_url_or_path; +use deno_core::resolve_url_or_path_deprecated; use deno_graph::Module; use deno_runtime::colors; @@ -40,7 +40,7 @@ pub async fn bundle( let source_file1 = &bundle_flags.source_file; let source_file2 = &bundle_flags.source_file; async move { - let module_specifier = resolve_url_or_path(source_file1)?; + let module_specifier = resolve_url_or_path_deprecated(source_file1)?; log::debug!(">>>>> bundle START"); let ps = ProcState::from_options(cli_options).await?; diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs index c7a4d58da7..05ad853f86 100644 --- a/cli/tools/coverage/mod.rs +++ b/cli/tools/coverage/mod.rs @@ -655,8 +655,10 @@ pub async fn cover_files( }; for script_coverage in script_coverages { - let module_specifier = - deno_core::resolve_url_or_path(&script_coverage.url)?; + let module_specifier = deno_core::resolve_url_or_path( + &script_coverage.url, + ps.options.initial_cwd(), + )?; let maybe_file = if module_specifier.scheme() == "file" { ps.file_fetcher.get_source(&module_specifier) diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 2ee80f6b7f..38553e9ffa 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -12,7 +12,6 @@ use crate::proc_state::ProcState; use crate::tsc::get_types_declaration_file_text; use deno_ast::MediaType; use deno_core::anyhow::bail; -use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::resolve_path; use deno_core::resolve_url_or_path; @@ -62,12 +61,13 @@ pub async fn print_docs( doc_parser.parse_module(&source_file_specifier)?.definitions } DocSourceFileFlag::Path(source_file) => { - let cwd = std::env::current_dir().context("Unable to get CWD")?; - let module_specifier = resolve_url_or_path(&source_file)?; + let module_specifier = + resolve_url_or_path(&source_file, ps.options.initial_cwd())?; // If the root module has external types, the module graph won't redirect it, // so instead create a dummy file which exports everything from the actual file being documented. - let root_specifier = resolve_path("./$deno$doc.ts", &cwd).unwrap(); + let root_specifier = + resolve_path("./$deno$doc.ts", ps.options.initial_cwd()).unwrap(); let root = File { local: PathBuf::from("./$deno$doc.ts"), maybe_types: None, diff --git a/cli/tools/info.rs b/cli/tools/info.rs index f7284154a8..1cc60286d3 100644 --- a/cli/tools/info.rs +++ b/cli/tools/info.rs @@ -34,7 +34,7 @@ use crate::util::checksum; pub async fn info(flags: Flags, info_flags: InfoFlags) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; if let Some(specifier) = info_flags.file { - let specifier = resolve_url_or_path(&specifier)?; + let specifier = resolve_url_or_path(&specifier, ps.options.initial_cwd())?; let mut loader = ps.create_graph_loader(); loader.enable_loading_cache_info(); // for displaying the cache information let graph = ps diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index a43ec84d54..86291b2c9a 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -308,7 +308,8 @@ async fn resolve_shim_data( let installation_dir = root.join("bin"); // Check if module_url is remote - let module_url = resolve_url_or_path(&install_flags.module_url)?; + let cwd = std::env::current_dir().context("Unable to get CWD")?; + let module_url = resolve_url_or_path(&install_flags.module_url, &cwd)?; let name = if install_flags.name.is_some() { install_flags.name.clone() @@ -408,7 +409,7 @@ async fn resolve_shim_data( } if let Some(import_map_path) = &flags.import_map_path { - let import_map_url = resolve_url_or_path(import_map_path)?; + let import_map_url = resolve_url_or_path(import_map_path, &cwd)?; executable_args.push("--import-map".to_string()); executable_args.push(import_map_url.to_string()); } diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs index 99dab62614..7224eb45f7 100644 --- a/cli/tools/repl/mod.rs +++ b/cli/tools/repl/mod.rs @@ -5,7 +5,6 @@ use crate::args::ReplFlags; use crate::colors; use crate::proc_state::ProcState; use crate::worker::create_main_worker; -use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::resolve_path; use deno_runtime::permissions::Permissions; @@ -70,7 +69,8 @@ async fn read_eval_file( ps: &ProcState, eval_file: &str, ) -> Result { - let specifier = deno_core::resolve_url_or_path(eval_file)?; + let specifier = + deno_core::resolve_url_or_path(eval_file, ps.options.initial_cwd())?; let file = ps .file_fetcher @@ -81,9 +81,9 @@ async fn read_eval_file( } pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result { - let cwd = std::env::current_dir().context("Unable to get CWD")?; - let main_module = resolve_path("./$deno$repl.ts", &cwd).unwrap(); let ps = ProcState::build(flags).await?; + let main_module = + resolve_path("./$deno$repl.ts", ps.options.initial_cwd()).unwrap(); let mut worker = create_main_worker( &ps, main_module, diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index 1cd67fc97d..3cd9730a7f 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -11,7 +11,6 @@ use deno_ast::swc::visit::VisitWith; use deno_ast::DiagnosticsError; use deno_ast::ImportsNotUsedAsValues; use deno_ast::ModuleSpecifier; -use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::futures::channel::mpsc::UnboundedReceiver; use deno_core::futures::FutureExt; @@ -144,8 +143,11 @@ impl ReplSession { } assert_ne!(context_id, 0); - let cwd = std::env::current_dir().context("Unable to get CWD")?; - let referrer = deno_core::resolve_path("./$deno$repl.ts", &cwd).unwrap(); + let referrer = deno_core::resolve_path( + "./$deno$repl.ts", + proc_state.options.initial_cwd(), + ) + .unwrap(); let mut repl_session = ReplSession { proc_state, diff --git a/cli/tools/run.rs b/cli/tools/run.rs index d949a1cdb2..04ddcb4d99 100644 --- a/cli/tools/run.rs +++ b/cli/tools/run.rs @@ -9,6 +9,7 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::resolve_path; use deno_core::resolve_url_or_path; +use deno_core::resolve_url_or_path_deprecated; use deno_graph::npm::NpmPackageReqReference; use deno_runtime::permissions::Permissions; use deno_runtime::permissions::PermissionsContainer; @@ -56,7 +57,7 @@ To grant permissions, set them before the script argument. For example: if NpmPackageReqReference::from_str(&run_flags.script).is_ok() { ModuleSpecifier::parse(&run_flags.script)? } else { - resolve_url_or_path(&run_flags.script)? + resolve_url_or_path(&run_flags.script, ps.options.initial_cwd())? }; let permissions = PermissionsContainer::new(Permissions::from_options( &ps.options.permissions_options(), @@ -103,7 +104,7 @@ pub async fn run_from_stdin(flags: Flags) -> Result { // code properly. async fn run_with_watch(flags: Flags, script: String) -> Result { let flags = Arc::new(flags); - let main_module = resolve_url_or_path(&script)?; + let main_module = resolve_url_or_path_deprecated(&script)?; let (sender, receiver) = tokio::sync::mpsc::unbounded_channel(); let mut ps = ProcState::build_for_file_watcher((*flags).clone(), sender.clone()).await?; @@ -142,10 +143,11 @@ pub async fn eval_command( ) -> Result { // 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 cwd = std::env::current_dir().context("Unable to get CWD")?; - let main_module = - resolve_path(&format!("./$deno$eval.{}", eval_flags.ext), &cwd)?; let ps = ProcState::build(flags).await?; + let main_module = resolve_path( + &format!("./$deno$eval.{}", eval_flags.ext), + ps.options.initial_cwd(), + )?; let permissions = PermissionsContainer::new(Permissions::from_options( &ps.options.permissions_options(), )?); diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs index 4573717a37..f0f53d417e 100644 --- a/cli/tools/standalone.rs +++ b/cli/tools/standalone.rs @@ -39,11 +39,15 @@ pub async fn compile( compile_flags: CompileFlags, ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; - let module_specifier = resolve_url_or_path(&compile_flags.source_file)?; + let module_specifier = + resolve_url_or_path(&compile_flags.source_file, ps.options.initial_cwd())?; let deno_dir = &ps.dir; - let output_path = - resolve_compile_executable_output_path(&compile_flags).await?; + let output_path = resolve_compile_executable_output_path( + &compile_flags, + ps.options.initial_cwd(), + ) + .await?; let graph = Arc::try_unwrap( create_graph_and_maybe_check(module_specifier.clone(), &ps).await?, @@ -282,8 +286,10 @@ async fn write_standalone_binary( async fn resolve_compile_executable_output_path( compile_flags: &CompileFlags, + current_dir: &Path, ) -> Result { - let module_specifier = resolve_url_or_path(&compile_flags.source_file)?; + let module_specifier = + resolve_url_or_path(&compile_flags.source_file, current_dir)?; let mut output = compile_flags.output.clone(); @@ -339,12 +345,15 @@ mod test { #[tokio::test] async fn resolve_compile_executable_output_path_target_linux() { - let path = resolve_compile_executable_output_path(&CompileFlags { - source_file: "mod.ts".to_string(), - output: Some(PathBuf::from("./file")), - args: Vec::new(), - target: Some("x86_64-unknown-linux-gnu".to_string()), - }) + let path = resolve_compile_executable_output_path( + &CompileFlags { + source_file: "mod.ts".to_string(), + output: Some(PathBuf::from("./file")), + args: Vec::new(), + target: Some("x86_64-unknown-linux-gnu".to_string()), + }, + &std::env::current_dir().unwrap(), + ) .await .unwrap(); @@ -356,12 +365,15 @@ mod test { #[tokio::test] async fn resolve_compile_executable_output_path_target_windows() { - let path = resolve_compile_executable_output_path(&CompileFlags { - source_file: "mod.ts".to_string(), - output: Some(PathBuf::from("./file")), - args: Vec::new(), - target: Some("x86_64-pc-windows-msvc".to_string()), - }) + let path = resolve_compile_executable_output_path( + &CompileFlags { + source_file: "mod.ts".to_string(), + output: Some(PathBuf::from("./file")), + args: Vec::new(), + target: Some("x86_64-pc-windows-msvc".to_string()), + }, + &std::env::current_dir().unwrap(), + ) .await .unwrap(); assert_eq!(path.file_name().unwrap(), "file.exe"); diff --git a/cli/tools/test.rs b/cli/tools/test.rs index 1feb83ca31..12f5d7c1f9 100644 --- a/cli/tools/test.rs +++ b/cli/tools/test.rs @@ -799,7 +799,7 @@ fn extract_files_from_regex_blocks( writeln!(file_source, "{}", text.as_str()).unwrap(); } - let file_specifier = deno_core::resolve_url_or_path(&format!( + let file_specifier = deno_core::resolve_url_or_path_deprecated(&format!( "{}${}-{}{}", specifier, file_line_index + line_offset + 1, @@ -1428,7 +1428,8 @@ pub async fn run_tests_with_watch( if let Some(changed) = &changed { for path in changed.iter().filter_map(|path| { - deno_core::resolve_url_or_path(&path.to_string_lossy()).ok() + deno_core::resolve_url_or_path_deprecated(&path.to_string_lossy()) + .ok() }) { if modules.contains(&path) { modules_to_reload.push(specifier); diff --git a/cli/tools/vendor/mod.rs b/cli/tools/vendor/mod.rs index e3536a00d7..3198348e37 100644 --- a/cli/tools/vendor/mod.rs +++ b/cli/tools/vendor/mod.rs @@ -268,7 +268,7 @@ async fn create_graph( let entry_points = flags .specifiers .iter() - .map(|p| resolve_url_or_path(p)) + .map(|p| resolve_url_or_path(p, ps.options.initial_cwd())) .collect::, _>>()?; ps.create_graph(entry_points).await diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 6add7d1fda..010d65a416 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -13,7 +13,7 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::located_script_name; use deno_core::op; -use deno_core::resolve_url_or_path; +use deno_core::resolve_url_or_path_deprecated; use deno_core::serde::Deserialize; use deno_core::serde::Deserializer; use deno_core::serde::Serialize; @@ -402,7 +402,7 @@ impl State { } fn normalize_specifier(specifier: &str) -> Result { - resolve_url_or_path(specifier).map_err(|err| err.into()) + resolve_url_or_path_deprecated(specifier).map_err(|err| err.into()) } #[derive(Debug, Deserialize)] diff --git a/cli/worker.rs b/cli/worker.rs index 151f70f053..3643a43162 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -729,7 +729,6 @@ fn create_web_worker_callback( mod tests { use super::*; use deno_core::resolve_path; - use deno_core::resolve_url_or_path; use deno_core::FsModuleLoader; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_web::BlobStore; @@ -787,7 +786,7 @@ mod tests { #[tokio::test] async fn execute_mod_esm_imports_a() { let p = test_util::testdata_path().join("runtime/esm_imports_a.js"); - let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap(); + let module_specifier = ModuleSpecifier::from_file_path(&p).unwrap(); let mut worker = create_test_worker(); let result = worker.execute_main_module(&module_specifier).await; if let Err(err) = result { diff --git a/core/lib.rs b/core/lib.rs index 08df6e44dc..b48a77f693 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -72,6 +72,7 @@ pub use crate::module_specifier::resolve_import; pub use crate::module_specifier::resolve_path; pub use crate::module_specifier::resolve_url; pub use crate::module_specifier::resolve_url_or_path; +pub use crate::module_specifier::resolve_url_or_path_deprecated; pub use crate::module_specifier::ModuleResolutionError; pub use crate::module_specifier::ModuleSpecifier; pub use crate::module_specifier::DUMMY_SPECIFIER; diff --git a/core/module_specifier.rs b/core/module_specifier.rs index 72d6937230..6c6dbad952 100644 --- a/core/module_specifier.rs +++ b/core/module_specifier.rs @@ -123,7 +123,7 @@ pub fn resolve_url( /// e.g. 'http:' or 'file:' or 'git+ssh:'. If not, it's interpreted as a /// file path; if it is a relative path it's resolved relative to the current /// working directory. -pub fn resolve_url_or_path( +pub fn resolve_url_or_path_deprecated( specifier: &str, ) -> Result { if specifier_has_uri_scheme(specifier) { @@ -135,9 +135,26 @@ pub fn resolve_url_or_path( } } +/// Takes a string representing either an absolute URL or a file path, +/// as it may be passed to deno as a command line argument. +/// The string is interpreted as a URL if it starts with a valid URI scheme, +/// e.g. 'http:' or 'file:' or 'git+ssh:'. If not, it's interpreted as a +/// file path; if it is a relative path it's resolved relative to passed +/// `current_dir`. +pub fn resolve_url_or_path( + specifier: &str, + current_dir: &Path, +) -> Result { + if specifier_has_uri_scheme(specifier) { + resolve_url(specifier) + } else { + resolve_path(specifier, current_dir) + } +} + /// Converts a string representing a relative or absolute path into a -/// ModuleSpecifier. A relative path is considered relative to the current -/// working directory. +/// ModuleSpecifier. A relative path is considered relative to the passed +/// `current_dir`. pub fn resolve_path( path_str: &str, current_dir: &Path, @@ -344,7 +361,7 @@ mod tests { } #[test] - fn test_resolve_url_or_path() { + fn test_resolve_url_or_path_deprecated() { // Absolute URL. let mut tests: Vec<(&str, String)> = vec![ ( @@ -440,13 +457,15 @@ mod tests { } for (specifier, expected_url) in tests { - let url = resolve_url_or_path(specifier).unwrap().to_string(); + let url = resolve_url_or_path_deprecated(specifier) + .unwrap() + .to_string(); assert_eq!(url, expected_url); } } #[test] - fn test_resolve_url_or_path_error() { + fn test_resolve_url_or_path_deprecated_error() { use url::ParseError::*; use ModuleResolutionError::*; @@ -460,7 +479,7 @@ mod tests { } for (specifier, expected_err) in tests { - let err = resolve_url_or_path(specifier).unwrap_err(); + let err = resolve_url_or_path_deprecated(specifier).unwrap_err(); assert_eq!(err, expected_err); } } diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs index c3c4ec092f..e00ed5a297 100644 --- a/core/ops_builtin_v8.rs +++ b/core/ops_builtin_v8.rs @@ -6,7 +6,7 @@ use crate::error::range_error; use crate::error::type_error; use crate::error::JsError; use crate::ops_builtin::WasmStreamingResource; -use crate::resolve_url_or_path; +use crate::resolve_url_or_path_deprecated; use crate::serde_v8::from_v8; use crate::source_map::apply_source_map as apply_source_map_; use crate::JsRealm; @@ -165,7 +165,7 @@ fn op_eval_context<'a>( let source = v8::Local::::try_from(source.v8_value) .map_err(|_| type_error("Invalid source"))?; let specifier = match specifier { - Some(s) => resolve_url_or_path(&s)?.to_string(), + Some(s) => resolve_url_or_path_deprecated(&s)?.to_string(), None => crate::DUMMY_SPECIFIER.to_string(), }; let specifier = v8::String::new(tc_scope, &specifier).unwrap();