From 05a770486755178064478adef26c255ac926b7d8 Mon Sep 17 00:00:00 2001 From: XantreGodlike Date: Thu, 11 Jan 2024 12:09:22 +0100 Subject: [PATCH] added meaningful error description --- .../import/no_named_as_default_member.rs | 55 +++++++++++++------ .../snapshots/no_named_as_default_member.snap | 16 +++--- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/crates/oxc_linter/src/rules/import/no_named_as_default_member.rs b/crates/oxc_linter/src/rules/import/no_named_as_default_member.rs index 21ee073243ab33..544988db14fe2f 100644 --- a/crates/oxc_linter/src/rules/import/no_named_as_default_member.rs +++ b/crates/oxc_linter/src/rules/import/no_named_as_default_member.rs @@ -17,9 +17,9 @@ use oxc_syntax::module_record::ImportImportName; use crate::{context::LintContext, rule::Rule}; #[derive(Debug, Error, Diagnostic)] -#[error("eslint-plugin-import(no-named-as-default-member): ")] -#[diagnostic(severity(warning), help(""))] -struct NoNamedAsDefaultMemberDignostic(#[label] pub Span); +#[error("eslint-plugin-import(no-named-as-default-member): {1:?} also has a named export {2:?}")] +#[diagnostic(severity(warning), help("Check if you meant to write `import {{{2:}}} from {3:?}`"))] +struct NoNamedAsDefaultMemberDignostic(#[label] pub Span, String, String, String); /// #[derive(Debug, Default, Clone)] @@ -49,7 +49,7 @@ impl Rule for NoNamedAsDefaultMember { fn run_once(&self, ctx: &LintContext<'_>) { let module_record = ctx.semantic().module_record(); - let mut has_members_map: HashMap<&Atom, Ref<'_, Atom, _, _>> = HashMap::default(); + let mut has_members_map: HashMap<&Atom, (Ref<'_, Atom, _, _>, String)> = HashMap::default(); for import_entry in &module_record.import_entries { let ImportImportName::Default(_) = import_entry.import_name else { continue; @@ -61,17 +61,24 @@ impl Rule for NoNamedAsDefaultMember { }; if !remote_module_record_ref.exported_bindings.is_empty() { - has_members_map.insert(import_entry.local_name.name(), remote_module_record_ref); + has_members_map.insert( + import_entry.local_name.name(), + (remote_module_record_ref, import_entry.module_request.name().to_string()), + ); } } if has_members_map.is_empty() { return; }; - let external_module_has_entry = |module_name: &Atom, entry_name: &Atom| { - has_members_map - .get(&module_name) - .map_or(false, |it| it.exported_bindings.contains_key(entry_name)) + let get_external_module_name_if_has_entry = |module_name: &Atom, entry_name: &Atom| { + has_members_map.get(&module_name).and_then(|it| { + if it.0.exported_bindings.contains_key(entry_name) { + Some(it.1.clone()) + } else { + None + } + }) }; let process_member_expr = |member_expr: &MemberExpression| { @@ -81,12 +88,19 @@ impl Rule for NoNamedAsDefaultMember { let Some(prop_str) = member_expr.static_property_name() else { return; }; - if external_module_has_entry(&ident.name, &Atom::new_inline(prop_str)) { - ctx.diagnostic(NoNamedAsDefaultMemberDignostic(match member_expr { - MemberExpression::ComputedMemberExpression(it) => it.span, - MemberExpression::StaticMemberExpression(it) => it.span, - MemberExpression::PrivateFieldExpression(it) => it.span, - })); + if let Some(module_name) = + get_external_module_name_if_has_entry(&ident.name, &Atom::new_inline(prop_str)) + { + ctx.diagnostic(NoNamedAsDefaultMemberDignostic( + match member_expr { + MemberExpression::ComputedMemberExpression(it) => it.span, + MemberExpression::StaticMemberExpression(it) => it.span, + MemberExpression::PrivateFieldExpression(it) => it.span, + }, + ident.name.to_string(), + prop_str.to_string(), + module_name, + )); }; }; @@ -107,8 +121,15 @@ impl Rule for NoNamedAsDefaultMember { for prop in &*object_pattern.properties { let Some(name) = prop.key.static_name() else { return }; - if external_module_has_entry(&ident.name, &name) { - ctx.diagnostic(NoNamedAsDefaultMemberDignostic(decl.span)); + if let Some(module_name) = + get_external_module_name_if_has_entry(&ident.name, &name) + { + ctx.diagnostic(NoNamedAsDefaultMemberDignostic( + decl.span, + ident.name.to_string(), + name.to_string(), + module_name, + )); } } } diff --git a/crates/oxc_linter/src/snapshots/no_named_as_default_member.snap b/crates/oxc_linter/src/snapshots/no_named_as_default_member.snap index 6101b142f415e4..c006b377a00de4 100644 --- a/crates/oxc_linter/src/snapshots/no_named_as_default_member.snap +++ b/crates/oxc_linter/src/snapshots/no_named_as_default_member.snap @@ -3,32 +3,32 @@ source: crates/oxc_linter/src/tester.rs assertion_line: 154 expression: no_named_as_default_member --- - ⚠ eslint-plugin-import(no-named-as-default-member): + ⚠ eslint-plugin-import(no-named-as-default-member): `"baz"` also has a named export `"a"` ╭─[index.js:1:1] 1 │ import baz from "./named-exports"; const a = baz.a; · ───── ╰──── - help: + help: Check if you meant to write `import {a} from "./named-exports"` - ⚠ eslint-plugin-import(no-named-as-default-member): + ⚠ eslint-plugin-import(no-named-as-default-member): `"baz"` also has a named export `"a"` ╭─[index.js:1:1] 1 │ import baz from "./named-exports"; const a = baz["a"]; · ──────── ╰──── - help: + help: Check if you meant to write `import {a} from "./named-exports"` - ⚠ eslint-plugin-import(no-named-as-default-member): + ⚠ eslint-plugin-import(no-named-as-default-member): `"baz"` also has a named export `"a"` ╭─[index.js:1:1] 1 │ import baz from "./named-exports"; baz.a(); · ───── ╰──── - help: + help: Check if you meant to write `import {a} from "./named-exports"` - ⚠ eslint-plugin-import(no-named-as-default-member): + ⚠ eslint-plugin-import(no-named-as-default-member): `"baz"` also has a named export `"a"` ╭─[index.js:1:1] 1 │ import baz, { bar } from "./named-exports"; const {a} = baz · ───────── ╰──── - help: + help: Check if you meant to write `import {a} from "./named-exports"`