diff --git a/Cargo.lock b/Cargo.lock index 09bbe771c16243..038bc2cf38e9b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,6 +984,7 @@ dependencies = [ "http-body-util", "hyper 1.6.0", "hyper-util", + "lazy-regex", "nix 0.27.1", "ntest_timeout", "once_cell", @@ -1891,9 +1892,9 @@ dependencies = [ [[package]] name = "deno_core" -version = "0.365.0" +version = "0.366.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4edcf35188e732cb73ff771837979486365e71ae7be846a27dc204042f42da" +checksum = "93c7e5b8c90f0c994a13b00642a83a855311443a5a475ff093a0167ef58f8725" dependencies = [ "anyhow", "az", @@ -2614,9 +2615,9 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.241.0" +version = "0.242.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea267839bedd06aec8dc61c3da679c1a3fc9f0c752ae98ddb2391d34a02da18c" +checksum = "ffebc17daa35ef11ed0ba7758cdc61366a6df4f40b7a8d21c4f03078ae81939a" dependencies = [ "indexmap 2.9.0", "proc-macro-rules", @@ -8250,9 +8251,9 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.274.0" +version = "0.275.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b496748402f50bfdcb5a5a160af7b7062561f150c947b27cf70e5eb9ce2de6ef" +checksum = "d1683de6d6a1436ad708b17f56081b31f3944eb4539dbc1e755eab832852364c" dependencies = [ "deno_error", "num-bigint", diff --git a/Cargo.toml b/Cargo.toml index 9522d34958e717..0ecbb939a4c3f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ repository = "https://github.com/denoland/deno" [workspace.dependencies] deno_ast = { version = "=0.50.3", features = ["transpiling"] } -deno_core = { version = "0.365.0" } +deno_core = { version = "0.366.0" } deno_cache_dir = "=0.25.0" deno_doc = "=0.186.0" diff --git a/cli/args/flags.rs b/cli/args/flags.rs index aaa133b5345b36..e3e8f8c26b57d8 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -757,6 +757,7 @@ pub struct InternalFlags { #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct Flags { + pub initial_cwd: Option, /// Vector of CLI arguments - these are user script arguments, all Deno /// specific flags are removed. pub argv: Vec, @@ -1392,8 +1393,15 @@ static DENO_HELP: &str = cstr!( Discord: https://discord.gg/deno "); -/// Main entry point for parsing deno's command line flags. pub fn flags_from_vec(args: Vec) -> clap::error::Result { + flags_from_vec_with_initial_cwd(args, None) +} + +/// Main entry point for parsing deno's command line flags. +pub fn flags_from_vec_with_initial_cwd( + args: Vec, + initial_cwd: Option, +) -> clap::error::Result { let mut app = clap_root(); let mut matches = app @@ -1420,7 +1428,10 @@ pub fn flags_from_vec(args: Vec) -> clap::error::Result { _ => e, })?; - let mut flags = Flags::default(); + let mut flags = Flags { + initial_cwd, + ..Default::default() + }; // to pass all flags, even help and if matches.subcommand_matches("deploy").is_some() { @@ -1484,6 +1495,7 @@ pub fn flags_from_vec(args: Vec) -> clap::error::Result { } help_parse(&mut flags, subcommand); + return Ok(flags); } diff --git a/cli/factory.rs b/cli/factory.rs index 5c24a1b08e9df0..37468f956ff812 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -651,10 +651,16 @@ impl CliFactory { self.services.workspace_factory.get_or_try_init(|| { let initial_cwd = match self.overrides.initial_cwd.clone() { Some(v) => v, - None => self - .sys() - .env_current_dir() - .with_context(|| "Failed getting cwd.")?, + None => { + if let Some(initial_cwd) = self.flags.initial_cwd.clone() { + initial_cwd + } else { + self + .sys() + .env_current_dir() + .with_context(|| "Failed getting cwd.")? + } + } }; let options = new_workspace_factory_options(&initial_cwd, &self.flags); let mut factory = @@ -1135,6 +1141,9 @@ impl CliFactory { no_legacy_abort: cli_options.no_legacy_abort(), startup_snapshot: deno_snapshots::CLI_SNAPSHOT, enable_raw_imports: cli_options.unstable_raw_imports(), + maybe_initial_cwd: Some(deno_path_util::url_from_directory_path( + cli_options.initial_cwd(), + )?), }) } @@ -1154,11 +1163,15 @@ impl CliFactory { }; let maybe_coverage_dir = cli_options.coverage_dir(); + let initial_cwd = + deno_path_util::url_from_directory_path(cli_options.initial_cwd())?; + Ok(CliMainWorkerOptions { needs_test_modules: cli_options.sub_command().needs_test(), create_hmr_runner, maybe_coverage_dir, default_npm_caching_strategy: cli_options.default_npm_caching_strategy(), + maybe_initial_cwd: Some(Arc::new(initial_cwd)), }) } diff --git a/cli/lib/worker.rs b/cli/lib/worker.rs index 09daee86b52195..f27800c4521fde 100644 --- a/cli/lib/worker.rs +++ b/cli/lib/worker.rs @@ -350,6 +350,7 @@ pub struct LibMainWorkerOptions { pub startup_snapshot: Option<&'static [u8]>, pub serve_port: Option, pub serve_host: Option, + pub maybe_initial_cwd: Option, } #[derive(Default, Clone)] @@ -462,6 +463,7 @@ impl LibWorkerFactorySharedState { ), permissions: args.permissions, }; + let maybe_initial_cwd = shared.options.maybe_initial_cwd.clone(); let options = WebWorkerOptions { name: args.name, main_module: args.main_module.clone(), @@ -503,7 +505,9 @@ impl LibWorkerFactorySharedState { .clone(), seed: shared.options.seed, create_web_worker_cb, - format_js_error_fn: Some(Arc::new(format_js_error)), + format_js_error_fn: Some(Arc::new(move |a| { + format_js_error(a, maybe_initial_cwd.as_ref()) + })), worker_type: args.worker_type, stdio: stdio.clone(), cache_storage_dir, @@ -657,6 +661,8 @@ impl LibMainWorkerFactory { bundle_provider: shared.bundle_provider.clone(), }; + let maybe_initial_cwd = shared.options.maybe_initial_cwd.clone(); + let options = WorkerOptions { bootstrap: BootstrapOptions { deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(), @@ -694,7 +700,9 @@ impl LibMainWorkerFactory { .unsafely_ignore_certificate_errors .clone(), seed: shared.options.seed, - format_js_error_fn: Some(Arc::new(format_js_error)), + format_js_error_fn: Some(Arc::new(move |e| { + format_js_error(e, maybe_initial_cwd.as_ref()) + })), create_web_worker_cb: shared.create_web_worker_callback(stdio.clone()), maybe_inspector_server: shared.maybe_inspector_server.clone(), should_break_on_first_statement: shared.options.inspect_brk, diff --git a/cli/main.rs b/cli/main.rs index e3097eccadbc34..a1061621e72803 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -63,7 +63,7 @@ use self::util::draw_thread::DrawThread; use crate::args::CompletionsFlags; use crate::args::DenoSubcommand; use crate::args::Flags; -use crate::args::flags_from_vec; +use crate::args::flags_from_vec_with_initial_cwd; use crate::args::get_default_v8_flags; use crate::util::display; use crate::util::v8::get_v8_flags_from_env; @@ -558,9 +558,13 @@ fn exit_with_message(message: &str, code: i32) -> ! { deno_runtime::exit(code); } -fn exit_for_error(error: AnyError) -> ! { +fn exit_for_error(error: AnyError, initial_cwd: Option<&std::path::Path>) -> ! { let error_string = match js_error_downcast_ref(&error) { - Some(e) => format_js_error(e), + Some(e) => { + let initial_cwd = initial_cwd + .and_then(|cwd| deno_path_util::url_from_directory_path(cwd).ok()); + format_js_error(e, initial_cwd.as_ref()) + } None => format!("{error:?}"), }; @@ -615,6 +619,15 @@ pub fn main() { .unwrap(); let args: Vec<_> = env::args_os().collect(); + let initial_cwd = + match std::env::current_dir().with_context(|| "Failed getting cwd.") { + Ok(cwd) => Some(cwd), + Err(err) => { + log::error!("Failed getting cwd: {err}"); + None + } + }; + let initial_cwd_clone = initial_cwd.clone(); let future = async move { let roots = LibWorkerFactoryRoots::default(); @@ -641,7 +654,7 @@ pub fn main() { // NOTE(lucacasonato): due to new PKU feature introduced in V8 11.6 we need to // initialize the V8 platform on a parent thread of all threads that will spawn // V8 isolates. - let flags = resolve_flags_and_init(args).await?; + let flags = resolve_flags_and_init(args, initial_cwd_clone).await?; if waited_unconfigured_runtime.is_none() { init_v8(&flags); @@ -657,12 +670,13 @@ pub fn main() { match result { Ok(exit_code) => deno_runtime::exit(exit_code), - Err(err) => exit_for_error(err), + Err(err) => exit_for_error(err, initial_cwd.as_deref()), } } async fn resolve_flags_and_init( args: Vec, + initial_cwd: Option, ) -> Result { // this env var is used by clap to enable dynamic completions, it's set by the shell when // executing deno to get dynamic completions. @@ -671,17 +685,18 @@ async fn resolve_flags_and_init( deno_runtime::exit(0); } - let mut flags = match flags_from_vec(args) { - Ok(flags) => flags, - Err(err @ clap::Error { .. }) - if err.kind() == clap::error::ErrorKind::DisplayVersion => - { - // Ignore results to avoid BrokenPipe errors. - let _ = err.print(); - deno_runtime::exit(0); - } - Err(err) => exit_for_error(AnyError::from(err)), - }; + let mut flags = + match flags_from_vec_with_initial_cwd(args, initial_cwd.clone()) { + Ok(flags) => flags, + Err(err @ clap::Error { .. }) + if err.kind() == clap::error::ErrorKind::DisplayVersion => + { + // Ignore results to avoid BrokenPipe errors. + let _ = err.print(); + deno_runtime::exit(0); + } + Err(err) => exit_for_error(AnyError::from(err), initial_cwd.as_deref()), + }; // preserve already loaded env variables if flags.subcommand.watch_flags().is_some() { WatchEnvTracker::snapshot(); @@ -706,7 +721,10 @@ async fn resolve_flags_and_init( // Tunnel sets up env vars and OTEL, so connect before everything else. if flags.tunnel { if let Err(err) = initialize_tunnel(&flags).await { - exit_for_error(err.context("Failed to start with tunnel")); + exit_for_error( + err.context("Failed to start with tunnel"), + initial_cwd.as_deref(), + ); } // SAFETY: We're doing this before any threads are created. unsafe { diff --git a/cli/rt/main.rs b/cli/rt/main.rs index 40f5ac272cd78e..f7a5c234780135 100644 --- a/cli/rt/main.rs +++ b/cli/rt/main.rs @@ -44,7 +44,7 @@ fn unwrap_or_exit(result: Result) -> T { Ok(value) => value, Err(error) => { let error_string = match js_error_downcast_ref(&error) { - Some(js_error) => format_js_error(js_error), + Some(js_error) => format_js_error(js_error, None), None => format!("{:?}", error), }; diff --git a/cli/rt/run.rs b/cli/rt/run.rs index e6d93e840030e6..bdba2b6775f26f 100644 --- a/cli/rt/run.rs +++ b/cli/rt/run.rs @@ -1030,6 +1030,7 @@ pub async fn run( no_legacy_abort: false, startup_snapshot: deno_snapshots::CLI_SNAPSHOT, enable_raw_imports: metadata.unstable_config.raw_imports, + maybe_initial_cwd: None, }; let worker_factory = LibMainWorkerFactory::new( Arc::new(BlobStore::default()), diff --git a/cli/tools/compile.rs b/cli/tools/compile.rs index 5cf90ed581bb23..79ae3a003fbc74 100644 --- a/cli/tools/compile.rs +++ b/cli/tools/compile.rs @@ -72,11 +72,27 @@ pub async fn compile( graph }; + let initial_cwd = + deno_path_util::url_from_directory_path(cli_options.initial_cwd())?; + log::info!( "{} {} to {}", colors::green("Compile"), - entrypoint, - output_path.display(), + crate::util::path::relative_specifier_path_for_display( + &initial_cwd, + entrypoint + ), + { + if let Ok(output_path) = deno_path_util::url_from_file_path(&output_path) + { + crate::util::path::relative_specifier_path_for_display( + &initial_cwd, + &output_path, + ) + } else { + output_path.display().to_string() + } + } ); validate_output_path(&output_path)?; diff --git a/cli/tools/lint/reporters.rs b/cli/tools/lint/reporters.rs index 045dc38f305a2b..56459ca0248eee 100644 --- a/cli/tools/lint/reporters.rs +++ b/cli/tools/lint/reporters.rs @@ -55,7 +55,7 @@ impl LintReporter for PrettyLintReporter { fn visit_error(&mut self, file_path: &str, err: &AnyError) { log::error!("Error linting: {file_path}"); let text = match js_error_downcast_ref(err) { - Some(js_error) => format_js_error(js_error), + Some(js_error) => format_js_error(js_error, None), None => format!("{err:#}"), }; for line in text.split('\n') { diff --git a/cli/tools/test/fmt.rs b/cli/tools/test/fmt.rs index 7a801ff4f877c9..fdc7972d3f409a 100644 --- a/cli/tools/test/fmt.rs +++ b/cli/tools/test/fmt.rs @@ -91,7 +91,7 @@ pub fn format_test_error( if options.hide_stacktraces { return js_error.exception_message; } - format_js_error(&js_error) + format_js_error(&js_error, options.initial_cwd.as_ref()) } pub fn format_sanitizer_diff( diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs index 917710af6ecd9d..242d0a50ee4004 100644 --- a/cli/tools/test/mod.rs +++ b/cli/tools/test/mod.rs @@ -306,6 +306,7 @@ impl From<&TestDescription> for TestFailureDescription { #[derive(Debug, Default, Clone, PartialEq)] pub struct TestFailureFormatOptions { pub hide_stacktraces: bool, + pub initial_cwd: Option, } #[allow(clippy::derive_partial_eq_without_eq)] @@ -605,6 +606,7 @@ fn get_test_reporter(options: &TestSpecifiersOptions) -> Box { let parallel = options.concurrent_jobs.get() > 1; let failure_format_options = TestFailureFormatOptions { hide_stacktraces: options.hide_stacktraces, + initial_cwd: Some(options.cwd.clone()), }; let reporter: Box = match &options.reporter { TestReporterConfig::Dot => Box::new(DotTestReporter::new( @@ -637,6 +639,7 @@ fn get_test_reporter(options: &TestSpecifiersOptions) -> Box { junit_path.to_string(), TestFailureFormatOptions { hide_stacktraces: options.hide_stacktraces, + initial_cwd: Some(options.cwd.clone()), }, )); return Box::new(CompoundTestReporter::new(vec![reporter, junit])); diff --git a/cli/type_checker.rs b/cli/type_checker.rs index 1d4079d0ac99f2..81906d803417ef 100644 --- a/cli/type_checker.rs +++ b/cli/type_checker.rs @@ -44,7 +44,6 @@ use crate::sys::CliSys; use crate::tsc; use crate::tsc::Diagnostics; use crate::tsc::TypeCheckingCjsTracker; -use crate::util::path::to_percent_decoded_str; #[derive(Debug, thiserror::Error, deno_error::JsError)] #[class(type)] @@ -255,6 +254,10 @@ impl TypeChecker { code_cache: self.code_cache.clone(), tsgo_path: self.tsgo_path.clone(), initial_cwd: self.cli_options.initial_cwd().to_path_buf(), + current_dir: deno_path_util::url_from_directory_path( + self.cli_options.initial_cwd(), + ) + .map_err(|e| CheckError::Other(JsErrorBox::from_err(e)))?, }), )) } @@ -385,6 +388,7 @@ struct DiagnosticsByFolderRealIterator<'a> { code_cache: Option>, tsgo_path: Option, initial_cwd: PathBuf, + current_dir: Url, } impl Iterator for DiagnosticsByFolderRealIterator<'_> { @@ -441,12 +445,15 @@ impl DiagnosticsByFolderRealIterator<'_> { &self, check_group: &CheckGroup, ) -> Result { - fn log_provided_roots(provided_roots: &[Url]) { + fn log_provided_roots(provided_roots: &[Url], current_dir: &Url) { for root in provided_roots { log::info!( "{} {}", colors::green("Check"), - to_percent_decoded_str(root.as_str()) + crate::util::path::relative_specifier_path_for_display( + current_dir, + root + ), ); } } @@ -483,7 +490,7 @@ impl DiagnosticsByFolderRealIterator<'_> { if root_names.is_empty() { if missing_diagnostics.has_diagnostic() { - log_provided_roots(&check_group.roots); + log_provided_roots(&check_group.roots, &self.current_dir); } return Ok(missing_diagnostics); } @@ -499,7 +506,7 @@ impl DiagnosticsByFolderRealIterator<'_> { } // log out the roots that we're checking - log_provided_roots(&check_group.roots); + log_provided_roots(&check_group.roots, &self.current_dir); // the first root will always either be the specifier that the user provided // or the first specifier in a directory diff --git a/cli/util/file_watcher.rs b/cli/util/file_watcher.rs index 2df445840c3c8e..1b625c2cdacbea 100644 --- a/cli/util/file_watcher.rs +++ b/cli/util/file_watcher.rs @@ -13,6 +13,7 @@ use deno_config::glob::PathOrPatternSet; use deno_core::error::AnyError; use deno_core::futures::FutureExt; use deno_core::parking_lot::Mutex; +use deno_core::url::Url; use deno_lib::util::result::js_error_downcast_ref; use deno_runtime::fmt_errors::format_js_error; use deno_signals; @@ -77,14 +78,14 @@ impl DebouncedReceiver { } } -async fn error_handler(watch_future: F) -> bool +async fn error_handler(watch_future: F, initial_cwd: Option<&Url>) -> bool where F: Future>, { let result = watch_future.await; if let Err(err) = result { let error_string = match js_error_downcast_ref(&err) { - Some(e) => format_js_error(e), + Some(e) => format_js_error(e, initial_cwd), None => format!("{err:?}"), }; log::error!( @@ -299,6 +300,9 @@ where ) -> Result, F: Future>, { + let initial_cwd = std::env::current_dir() + .ok() + .and_then(|path| deno_path_util::url_from_directory_path(&path).ok()); let exclude_set = flags.resolve_watch_exclude_set()?; let (paths_to_watch_tx, mut paths_to_watch_rx) = tokio::sync::mpsc::unbounded_channel(); @@ -359,11 +363,14 @@ where add_paths_to_watcher(&mut watcher, &maybe_paths.unwrap(), &exclude_set); } }; - let operation_future = error_handler(operation( - flags.clone(), - watcher_communicator.clone(), - changed_paths.borrow_mut().take(), - )?); + let operation_future = error_handler( + operation( + flags.clone(), + watcher_communicator.clone(), + changed_paths.borrow_mut().take(), + )?, + initial_cwd.as_ref(), + ); // don't reload dependencies after the first run if flags.reload { diff --git a/cli/util/path.rs b/cli/util/path.rs index 1d90cfb34b3aad..eb55d1519bcf12 100644 --- a/cli/util/path.rs +++ b/cli/util/path.rs @@ -99,25 +99,9 @@ pub fn relative_specifier( return Some("./".to_string()); } - // workaround using parent directory until https://github.com/servo/rust-url/pull/754 is merged - let from = if !from.path().ends_with('/') { - if let Some(end_slash) = from.path().rfind('/') { - let mut new_from = from.clone(); - new_from.set_path(&from.path()[..end_slash + 1]); - Cow::Owned(new_from) - } else { - Cow::Borrowed(from) - } - } else { - Cow::Borrowed(from) - }; - // workaround for url crate not adding a trailing slash for a directory // it seems to be fixed once a version greater than 2.2.2 is released - let mut text = from.make_relative(to)?; - if is_dir && !text.ends_with('/') && to.query().is_none() { - text.push('/'); - } + let text = from.make_relative(to)?; let text = if text.starts_with("../") || text.starts_with("./") { text @@ -127,6 +111,25 @@ pub fn relative_specifier( Some(to_percent_decoded_str(&text)) } +pub fn relative_specifier_path_for_display( + from: &ModuleSpecifier, + to: &ModuleSpecifier, +) -> String { + if to.scheme() == "file" && from.scheme() == "file" { + let relative_specifier = relative_specifier(from, to) + .map(Cow::Owned) + .unwrap_or_else(|| Cow::Borrowed(to.as_str())); + let relative_specifier = if relative_specifier.starts_with("../../../") { + to.as_str() + } else { + relative_specifier.trim_start_matches("./") + }; + to_percent_decoded_str(relative_specifier) + } else { + to_percent_decoded_str(to.as_str()) + } +} + /// Slightly different behaviour than the default matching /// where an exact path needs to be matched to be opted-in /// rather than just a partial directory match. diff --git a/cli/worker.rs b/cli/worker.rs index 143056ef764e2d..24ad323722ba6f 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -43,6 +43,7 @@ pub struct CliMainWorkerOptions { pub maybe_coverage_dir: Option, pub default_npm_caching_strategy: NpmCachingStrategy, pub needs_test_modules: bool, + pub maybe_initial_cwd: Option>, } /// Data shared between the factory and workers. @@ -50,6 +51,7 @@ struct SharedState { pub create_hmr_runner: Option, pub maybe_coverage_dir: Option, pub maybe_file_watcher_communicator: Option>, + pub maybe_initial_cwd: Option>, } pub struct CliMainWorker { @@ -314,6 +316,7 @@ impl CliMainWorkerFactory { create_hmr_runner: options.create_hmr_runner, maybe_coverage_dir: options.maybe_coverage_dir, maybe_file_watcher_communicator, + maybe_initial_cwd: options.maybe_initial_cwd, }), default_npm_caching_strategy: options.default_npm_caching_strategy, needs_test_modules: options.needs_test_modules, @@ -450,6 +453,13 @@ impl CliMainWorkerFactory { ); } + if let Some(initial_cwd) = &self.shared.maybe_initial_cwd { + let op_state = worker.js_runtime().op_state(); + op_state + .borrow_mut() + .put(deno_core::error::InitialCwd(initial_cwd.clone())); + } + Ok(CliMainWorker { worker, shared: self.shared.clone(), diff --git a/fail.txt b/fail.txt new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/runtime/fmt_errors.rs b/runtime/fmt_errors.rs index 1415998a18fea6..1342cf489f7551 100644 --- a/runtime/fmt_errors.rs +++ b/runtime/fmt_errors.rs @@ -6,6 +6,7 @@ use color_print::cformat; use color_print::cstr; use deno_core::error::JsError; use deno_core::error::format_frame; +use deno_core::url::Url; use deno_terminal::colors; #[derive(Debug, Clone)] @@ -90,6 +91,7 @@ impl deno_core::error::ErrorFormat for AnsiColors { } LineNumber | ColumnNumber => colors::yellow(s).to_string().into(), FunctionName | PromiseAll => colors::italic_bold(s).to_string().into(), + WorkingDirPath => colors::gray(s).to_string().into(), } } } @@ -170,6 +172,7 @@ fn find_recursive_cause(js_error: &JsError) -> Option> { fn format_aggregated_error( aggregated_errors: &Vec, circular_reference_index: usize, + initial_cwd: Option<&Url>, ) -> String { let mut s = String::new(); let mut nested_circular_reference_index = circular_reference_index; @@ -187,6 +190,7 @@ fn format_aggregated_error( }), false, vec![], + initial_cwd, ); for line in error_string.trim_start_matches("Uncaught ").lines() { @@ -202,6 +206,7 @@ fn format_js_error_inner( circular: Option, include_source_code: bool, suggestions: Vec, + initial_cwd: Option<&Url>, ) -> String { let mut s = String::new(); @@ -221,6 +226,7 @@ fn format_js_error_inner( .as_ref() .map(|circular| circular.index) .unwrap_or(0), + initial_cwd, ); s.push_str(&aggregated_message); } @@ -239,7 +245,12 @@ fn format_js_error_inner( 0, )); for frame in &js_error.frames { - write!(s, "\n at {}", format_frame::(frame, None)).unwrap(); + write!( + s, + "\n at {}", + format_frame::(frame, initial_cwd) + ) + .unwrap(); } if let Some(cause) = &js_error.cause { let is_caused_by_circular = circular @@ -251,7 +262,7 @@ fn format_js_error_inner( colors::cyan(format!("[Circular *{}]", circular.unwrap().index)) .to_string() } else { - format_js_error_inner(cause, circular, false, vec![]) + format_js_error_inner(cause, circular, false, vec![], initial_cwd) }; write!( @@ -465,14 +476,17 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec> { } /// Format a [`JsError`] for terminal output. -pub fn format_js_error(js_error: &JsError) -> String { +pub fn format_js_error( + js_error: &JsError, + initial_cwd: Option<&Url>, +) -> String { let circular = find_recursive_cause(js_error).map(|reference| IndexedErrorReference { reference, index: 1, }); let suggestions = get_suggestions_for_terminal_errors(js_error); - format_js_error_inner(js_error, circular, true, suggestions) + format_js_error_inner(js_error, circular, true, suggestions, initial_cwd) } #[cfg(test)] diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 264e490c0c79c4..b14f80f65e9284 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -46,6 +46,7 @@ http.workspace = true http-body-util.workspace = true hyper.workspace = true hyper-util.workspace = true +lazy-regex.workspace = true ntest_timeout.workspace = true once_cell.workspace = true os_pipe.workspace = true diff --git a/tests/integration/check_tests.rs b/tests/integration/check_tests.rs index ecf461ffb13180..2cbd8dc2798c2b 100644 --- a/tests/integration/check_tests.rs +++ b/tests/integration/check_tests.rs @@ -122,7 +122,7 @@ fn ts_no_recheck_on_redirect() { // run once let output = check_command.run(); - output.assert_matches_text("[WILDCARD]Check file://[WILDCARD]"); + output.assert_matches_text("[WILDCARD]Check [WILDCARD]"); // run again let output = check_command.run(); diff --git a/tests/integration/compile_tests.rs b/tests/integration/compile_tests.rs index b58c279651ef9b..08164b8881b399 100644 --- a/tests/integration/compile_tests.rs +++ b/tests/integration/compile_tests.rs @@ -823,7 +823,9 @@ testing[WILDCARD]this .args("compile --output binary main.ts") .run() .assert_exit_code(0) - .assert_matches_text("Check file:///[WILDLINE]/main.ts\nCompile file:///[WILDLINE]/main.ts to binary[WILDLINE]\n"); + .assert_matches_text( + "Check main.ts\nCompile main.ts to binary[WILDLINE]\n", + ); context .new_command() @@ -1104,8 +1106,8 @@ console.log(getValue());"#, r#"Download http://localhost:4260/@denotest%2fesm-basic Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz Initialize @denotest/esm-basic@1.0.0 -Check file:///[WILDCARD]/main.ts -Compile file:///[WILDCARD]/main.ts to [WILDCARD] +Check main.ts +Compile main.ts to [WILDCARD] Warning Failed resolving symlink. Ignoring. Path: [WILDCARD] Message: [WILDCARD]) diff --git a/tests/integration/jsr_tests.rs b/tests/integration/jsr_tests.rs index e2258af6446dec..71fb0c8e86b44a 100644 --- a/tests/integration/jsr_tests.rs +++ b/tests/integration/jsr_tests.rs @@ -96,7 +96,7 @@ fn fast_check_cache() { .args("check --all main.ts") .run() .assert_matches_text( - "Check file:///[WILDCARD]main.ts + "Check main.ts TS2322 [ERROR]: Type 'string' is not assignable to type 'number'. export function asdf(a: number) { let err: number = ''; return Math.random(); } ~~~ diff --git a/tests/integration/npm_tests.rs b/tests/integration/npm_tests.rs index 99c90fb9c44e0d..97b94db3886726 100644 --- a/tests/integration/npm_tests.rs +++ b/tests/integration/npm_tests.rs @@ -1433,8 +1433,7 @@ console.log(getKind()); "#, ); let output = test_context.new_command().args("run --check main.ts").run(); - output - .assert_matches_text("Check file:///[WILDCARD]/main.ts\n2\n1\n2\nesm\n"); + output.assert_matches_text("Check main.ts\n2\n1\n2\nesm\n"); // should not have created the .deno directory assert!(!dir.path().join("node_modules/.deno").exists()); @@ -1529,7 +1528,7 @@ console.log(getValue()); let output = test_context.new_command().args("run main.ts").run(); output.assert_matches_text("5\n"); let output = test_context.new_command().args("check main.ts").run(); - output.assert_matches_text("Check file:///[WILDCARD]/main.ts\n"); + output.assert_matches_text("Check main.ts\n"); } #[test] @@ -1653,7 +1652,7 @@ console.log(add(1, 2)); .new_command() .args("check ./project-b/main.ts") .run(); - output.assert_matches_text("Check file:///[WILDCARD]/project-b/main.ts\n"); + output.assert_matches_text("Check project-b/main.ts\n"); // Now a file in the main directory should just be able to // import it via node resolution even though a package.json @@ -1670,7 +1669,7 @@ console.log(getValue()); let output = test_context.new_command().args("run main.ts").run(); output.assert_matches_text("7\n"); let output = test_context.new_command().args("check main.ts").run(); - output.assert_matches_text("Check file:///[WILDCARD]/main.ts\n"); + output.assert_matches_text("Check main.ts\n"); } #[test] @@ -1752,7 +1751,7 @@ console.log(add(1, 2)); .new_command() .args("check ./project-b/main.ts") .run(); - output.assert_matches_text("Check file:///[WILDCARD]/project-b/main.ts\n"); + output.assert_matches_text("Check project-b/main.ts\n"); // Now a file in the main directory should just be able to // import it via node resolution even though a package.json @@ -1769,7 +1768,7 @@ console.log(getValue()); let output = test_context.new_command().args("run main.ts").run(); output.assert_matches_text("7\n"); let output = test_context.new_command().args("check main.ts").run(); - output.assert_matches_text("Check file:///[WILDCARD]/main.ts\n"); + output.assert_matches_text("Check main.ts\n"); } #[test] @@ -1784,7 +1783,7 @@ fn check_css_package_json_exports() { .new_command() .args("check main.ts") .run() - .assert_matches_text("Download [WILDCARD]css-export\nDownload [WILDCARD]css-export/1.0.0.tgz\nCheck [WILDCARD]/main.ts\n") + .assert_matches_text("Download [WILDCARD]css-export\nDownload [WILDCARD]css-export/1.0.0.tgz\nCheck main.ts\n") .assert_exit_code(0); } diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index 2ca0aa07c2e8ad..c1afade8512c71 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -2374,7 +2374,7 @@ async fn test_resolve_dns() { let out = String::from_utf8_lossy(&output.stdout); println!("{err}"); assert!(output.status.success()); - assert!(err.starts_with("Check file")); + assert!(err.starts_with("Check run/resolve_dns.ts")); let expected = std::fs::read_to_string( util::testdata_path().join("run/resolve_dns.ts.out"), @@ -2403,7 +2403,7 @@ async fn test_resolve_dns() { eprintln!("stderr: {err}"); } assert!(output.status.success()); - assert!(err.starts_with("Check file")); + assert!(err.starts_with("Check run/resolve_dns.ts")); let expected = std::fs::read_to_string( util::testdata_path().join("run/resolve_dns.ts.out"), @@ -2429,7 +2429,7 @@ async fn test_resolve_dns() { let err = String::from_utf8_lossy(&output.stderr); let out = String::from_utf8_lossy(&output.stdout); assert!(!output.status.success()); - assert!(err.starts_with("Check file")); + assert!(err.starts_with("Check run/resolve_dns.ts")); assert!(err.contains(r#"error: Uncaught (in promise) NotCapable: Requires net access to "127.0.0.1:4553""#)); assert!(out.is_empty()); } @@ -2450,7 +2450,7 @@ async fn test_resolve_dns() { let err = String::from_utf8_lossy(&output.stderr); let out = String::from_utf8_lossy(&output.stdout); assert!(!output.status.success()); - assert!(err.starts_with("Check file")); + assert!(err.starts_with("Check run/resolve_dns.ts")); assert!(err.contains(r#"error: Uncaught (in promise) NotCapable: Requires net access to "127.0.0.1:4553""#)); assert!(out.is_empty()); } diff --git a/tests/integration/watcher_tests.rs b/tests/integration/watcher_tests.rs index 05575460aba060..b2309ddb9afa5d 100644 --- a/tests/integration/watcher_tests.rs +++ b/tests/integration/watcher_tests.rs @@ -1144,10 +1144,8 @@ async fn test_watch_doc() { "#, ); - assert_eq!( - skip_restarting_line(&mut stderr_lines).await, - format!("Check {foo_file_url}$3-6.ts") - ); + let file_regex = lazy_regex::lazy_regex!(r"Check [^\n]*foo\.ts\$3-6\.ts"); + assert!(file_regex.is_match(&skip_restarting_line(&mut stderr_lines).await),); assert_eq!( next_line(&mut stderr_lines).await.unwrap(), "TS2322 [ERROR]: Type 'number' is not assignable to type 'string'." @@ -1214,10 +1212,9 @@ async fn test_watch_doc() { ); wait_contains("running 1 test from", &mut stdout_lines).await; - assert_contains!( - next_line(&mut stdout_lines).await.unwrap(), - &format!("{foo_file_url}$3-8.ts ... ok") - ); + + let file_regex = lazy_regex::lazy_regex!(r"[^\n]*foo\.ts\$3-8\.ts"); + assert!(file_regex.is_match(&next_line(&mut stdout_lines).await.unwrap())); wait_contains("ok | 1 passed | 0 failed", &mut stdout_lines).await; wait_contains("Test finished", &mut stderr_lines).await; diff --git a/tests/testdata/compile/node_modules_symlink_outside/main_compile_file.out b/tests/testdata/compile/node_modules_symlink_outside/main_compile_file.out index a96f1f71e17f4e..05384d29f151ed 100644 --- a/tests/testdata/compile/node_modules_symlink_outside/main_compile_file.out +++ b/tests/testdata/compile/node_modules_symlink_outside/main_compile_file.out @@ -1,4 +1,4 @@ -Compile file:///[WILDCARD]/node_modules_symlink_outside/main.ts to [WILDCARD] +Compile main.ts to [WILDCARD] Embedded Files diff --git a/tests/testdata/compile/node_modules_symlink_outside/main_compile_folder.out b/tests/testdata/compile/node_modules_symlink_outside/main_compile_folder.out index b6083bdd6dc4db..16abe3c131b31a 100644 --- a/tests/testdata/compile/node_modules_symlink_outside/main_compile_folder.out +++ b/tests/testdata/compile/node_modules_symlink_outside/main_compile_folder.out @@ -1,8 +1,8 @@ Download http://localhost:4260/@denotest%2fesm-basic Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz Initialize @denotest/esm-basic@1.0.0 -Check file:///[WILDCARD]/node_modules_symlink_outside/main.ts -Compile file:///[WILDCARD]/node_modules_symlink_outside/main.ts to [WILDLINE] +Check main.ts +Compile main.ts to [WILDLINE] Embedded Files diff --git a/tests/testdata/publish/successful_provenance.out b/tests/testdata/publish/successful_provenance.out index dfc827544830da..63f63deeac5afa 100644 --- a/tests/testdata/publish/successful_provenance.out +++ b/tests/testdata/publish/successful_provenance.out @@ -1,6 +1,6 @@ -Check file:///[WILDCARD]/publish/successful/mod.ts +Check mod.ts Checking for slow types in the public API... -Check file:///[WILDCARD]/publish/successful/mod.ts +Check mod.ts Publishing @foo/bar@1.0.0 ... Provenance transparency log available at https://search.sigstore.dev/?logIndex=42069 Successfully published @foo/bar@1.0.0