diff options
10 files changed, 73 insertions, 6 deletions
diff --git a/cli/graph_util.rs b/cli/graph_util.rs index a9fcfd83d..f3ac64a43 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -724,12 +724,25 @@ impl ModuleGraphBuilder { pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String { let mut message = format_deno_graph_error(error); - if let Some(specifier) = get_resolution_error_bare_node_specifier(error) { + let maybe_hint = if let Some(specifier) = + get_resolution_error_bare_node_specifier(error) + { if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS { - message.push_str(&format!( - "\nIf you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\")." - )); + Some(format!("If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\").")) + } else { + None } + } else { + get_import_prefix_missing_error(error).map(|specifier| { + format!( + "If you want to use a JSR or npm package, try running `deno add {}`", + specifier + ) + }) + }; + + if let Some(hint) = maybe_hint { + message.push_str(&format!("\n {} {}", colors::cyan("hint:"), hint)); } message @@ -864,6 +877,45 @@ fn get_resolution_error_bare_specifier( } } +fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> { + let mut maybe_specifier = None; + if let ResolutionError::InvalidSpecifier { + error: SpecifierError::ImportPrefixMissing { specifier, .. }, + .. + } = error + { + maybe_specifier = Some(specifier); + } else if let ResolutionError::ResolverError { error, .. } = error { + match error.as_ref() { + ResolveError::Specifier(specifier_error) => { + if let SpecifierError::ImportPrefixMissing { specifier, .. } = + specifier_error + { + maybe_specifier = Some(specifier); + } + } + ResolveError::Other(other_error) => { + if let Some(SpecifierError::ImportPrefixMissing { specifier, .. }) = + other_error.downcast_ref::<SpecifierError>() + { + maybe_specifier = Some(specifier); + } + } + } + } + + // NOTE(bartlomieju): For now, return None if a specifier contains a dot or a space. This is because + // suggesting to `deno add bad-module.ts` makes no sense and is worse than not providing + // a suggestion at all. This should be improved further in the future + if let Some(specifier) = maybe_specifier { + if specifier.contains('.') || specifier.contains(' ') { + return None; + } + } + + maybe_specifier.map(|s| s.as_str()) +} + /// Gets if any of the specified root's "file:" dependents are in the /// provided changed set. pub fn has_graph_root_local_dependent_changed( diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 4f0f8a985..78e526085 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -8905,7 +8905,7 @@ fn lsp_completions_node_builtin() { "severity": 1, "code": "import-node-prefix-missing", "source": "deno", - "message": "Relative import path \"fs\" not prefixed with / or ./ or ../\nIf you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:fs\").", + "message": "Relative import path \"fs\" not prefixed with / or ./ or ../\n \u{1b}[0m\u{1b}[36mhint:\u{1b}[0m If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:fs\").", "data": { "specifier": "fs" }, diff --git a/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out b/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out index 2668a6e08..50daf8041 100644 --- a/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out +++ b/tests/specs/cache/with_bare_import/095_cache_with_bare_import.ts.out @@ -1,2 +1,3 @@ [WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add foo` at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD] diff --git a/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out b/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out index 2668a6e08..50daf8041 100644 --- a/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out +++ b/tests/specs/check/with_bare_import/095_cache_with_bare_import.ts.out @@ -1,2 +1,3 @@ [WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add foo` at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD] diff --git a/tests/specs/run/bare_specifier_without_import/__test__.jsonc b/tests/specs/run/bare_specifier_without_import/__test__.jsonc new file mode 100644 index 000000000..7b5c5e1b6 --- /dev/null +++ b/tests/specs/run/bare_specifier_without_import/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "run main.ts", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/run/bare_specifier_without_import/main.out b/tests/specs/run/bare_specifier_without_import/main.out new file mode 100644 index 000000000..a873f2727 --- /dev/null +++ b/tests/specs/run/bare_specifier_without_import/main.out @@ -0,0 +1,3 @@ +error: Relative import path "@std/dotenv/load" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add @std/dotenv/load` + at [WILDCARD]bare_specifier_without_import/main.ts:1:8 diff --git a/tests/specs/run/bare_specifier_without_import/main.ts b/tests/specs/run/bare_specifier_without_import/main.ts new file mode 100644 index 000000000..67e57b26b --- /dev/null +++ b/tests/specs/run/bare_specifier_without_import/main.ts @@ -0,0 +1,3 @@ +import "@std/dotenv/load"; + +console.log(Deno.env.get("GREETING")); // hello world diff --git a/tests/testdata/run/error_type_definitions.ts.out b/tests/testdata/run/error_type_definitions.ts.out index d60d4d483..7a71b4ebe 100644 --- a/tests/testdata/run/error_type_definitions.ts.out +++ b/tests/testdata/run/error_type_definitions.ts.out @@ -1,2 +1,3 @@ [WILDCARD]error: Failed resolving types. Relative import path "baz" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add baz` at [WILDCARD]/type_definitions/bar.d.ts:[WILDCARD] diff --git a/tests/testdata/run/node_prefix_missing/main.ts.out b/tests/testdata/run/node_prefix_missing/main.ts.out index fd19ed55f..48b4e37e2 100644 --- a/tests/testdata/run/node_prefix_missing/main.ts.out +++ b/tests/testdata/run/node_prefix_missing/main.ts.out @@ -1,3 +1,3 @@ error: Relative import path "fs" not prefixed with / or ./ or ../ -If you want to use a built-in Node module, add a "node:" prefix (ex. "node:fs"). + hint: If you want to use a built-in Node module, add a "node:" prefix (ex. "node:fs"). at file:///[WILDCARD]/main.ts:1:16 diff --git a/tests/testdata/run/with_package_json/with_stop/main.out b/tests/testdata/run/with_package_json/with_stop/main.out index f5eb79ca6..afab4910c 100644 --- a/tests/testdata/run/with_package_json/with_stop/main.out +++ b/tests/testdata/run/with_package_json/with_stop/main.out @@ -1,4 +1,5 @@ [WILDCARD]Config file found at '[WILDCARD]with_package_json[WILDCARD]with_stop[WILDCARD]some[WILDCARD]nested[WILDCARD]deno.json' [WILDCARD] error: Relative import path "chalk" not prefixed with / or ./ or ../ + hint: If you want to use a JSR or npm package, try running `deno add chalk` at file:///[WILDCARD]with_package_json/with_stop/some/nested/dir/main.ts:3:19 |