mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat: Add a hint on error about 'Relative import path ... not prefixed with ...' (#25430)
Running a file like: ``` import "@std/dotenv/load"; ``` Without a mapping in `imports` field of `deno.json` or `dependencies` of `package.json` will now error out with a hint: ``` error: Relative import path "@std/dotenv/load" not prefixed with / or ./ or ../ hint: Try running `deno add @std/dotenv/load` at [WILDCARD]bare_specifier_without_import/main.ts:1:8 ``` Closes https://github.com/denoland/deno/issues/24699 --------- Co-authored-by: David Sherret <dsherret@users.noreply.github.com>
This commit is contained in:
parent
105c2e336a
commit
acd01eb2b4
10 changed files with 73 additions and 6 deletions
|
@ -724,12 +724,25 @@ impl ModuleGraphBuilder {
|
||||||
pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
|
pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
|
||||||
let mut message = format_deno_graph_error(error);
|
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 {
|
if !*DENO_DISABLE_PEDANTIC_NODE_WARNINGS {
|
||||||
message.push_str(&format!(
|
Some(format!("If you want to use a built-in Node module, add a \"node:\" prefix (ex. \"node:{specifier}\")."))
|
||||||
"\nIf 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
|
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
|
/// Gets if any of the specified root's "file:" dependents are in the
|
||||||
/// provided changed set.
|
/// provided changed set.
|
||||||
pub fn has_graph_root_local_dependent_changed(
|
pub fn has_graph_root_local_dependent_changed(
|
||||||
|
|
|
@ -8905,7 +8905,7 @@ fn lsp_completions_node_builtin() {
|
||||||
"severity": 1,
|
"severity": 1,
|
||||||
"code": "import-node-prefix-missing",
|
"code": "import-node-prefix-missing",
|
||||||
"source": "deno",
|
"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": {
|
"data": {
|
||||||
"specifier": "fs"
|
"specifier": "fs"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../
|
[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]
|
at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD]
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../
|
[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]
|
at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD]
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"args": "run main.ts",
|
||||||
|
"output": "main.out",
|
||||||
|
"exitCode": 1
|
||||||
|
}
|
3
tests/specs/run/bare_specifier_without_import/main.out
Normal file
3
tests/specs/run/bare_specifier_without_import/main.out
Normal file
|
@ -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
|
3
tests/specs/run/bare_specifier_without_import/main.ts
Normal file
3
tests/specs/run/bare_specifier_without_import/main.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import "@std/dotenv/load";
|
||||||
|
|
||||||
|
console.log(Deno.env.get("GREETING")); // hello world
|
|
@ -1,2 +1,3 @@
|
||||||
[WILDCARD]error: Failed resolving types. Relative import path "baz" not prefixed with / or ./ or ../
|
[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]
|
at [WILDCARD]/type_definitions/bar.d.ts:[WILDCARD]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
error: Relative import path "fs" not prefixed with / or ./ or ../
|
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
|
at file:///[WILDCARD]/main.ts:1:16
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[WILDCARD]Config file found at '[WILDCARD]with_package_json[WILDCARD]with_stop[WILDCARD]some[WILDCARD]nested[WILDCARD]deno.json'
|
[WILDCARD]Config file found at '[WILDCARD]with_package_json[WILDCARD]with_stop[WILDCARD]some[WILDCARD]nested[WILDCARD]deno.json'
|
||||||
[WILDCARD]
|
[WILDCARD]
|
||||||
error: Relative import path "chalk" not prefixed with / or ./ or ../
|
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
|
at file:///[WILDCARD]with_package_json/with_stop/some/nested/dir/main.ts:3:19
|
||||||
|
|
Loading…
Reference in a new issue