summaryrefslogtreecommitdiff
path: root/cli/graph_util.rs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2024-09-05 07:25:56 +0100
committerGitHub <noreply@github.com>2024-09-05 08:25:56 +0200
commitacd01eb2b41e37a480943f79cfa28fc220c4baca (patch)
treea9808419bc88099fc811162d000007f6b2c30f9d /cli/graph_util.rs
parent105c2e336a4312ed1714ab893c57eae2a19068c7 (diff)
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>
Diffstat (limited to 'cli/graph_util.rs')
-rw-r--r--cli/graph_util.rs60
1 files changed, 56 insertions, 4 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(