From 5fd4df650d7977b81e78082fddeeb7271e716336 Mon Sep 17 00:00:00 2001 From: Guillaume Piedigrossi Date: Mon, 16 Dec 2024 21:47:28 +0100 Subject: [PATCH 1/2] feat(linter): add the import/no-named-default rule --- crates/oxc_linter/src/rules.rs | 2 + .../src/rules/import/no_named_default.rs | 74 +++++++++++++++++++ .../snapshots/import_no_named_default.snap | 24 ++++++ 3 files changed, 100 insertions(+) create mode 100644 crates/oxc_linter/src/rules/import/no_named_default.rs create mode 100644 crates/oxc_linter/src/snapshots/import_no_named_default.snap diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 8a1c0686db7b7..4245090ed683e 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -23,6 +23,7 @@ mod import { pub mod no_dynamic_require; pub mod no_named_as_default; pub mod no_named_as_default_member; + pub mod no_named_default; pub mod no_namespace; pub mod no_self_import; pub mod no_webpack_loader_syntax; @@ -643,6 +644,7 @@ oxc_macros::declare_all_lint_rules! { import::default, import::export, import::first, + import::no_named_default, import::no_namespace, import::max_dependencies, import::named, diff --git a/crates/oxc_linter/src/rules/import/no_named_default.rs b/crates/oxc_linter/src/rules/import/no_named_default.rs new file mode 100644 index 0000000000000..287e3709b8313 --- /dev/null +++ b/crates/oxc_linter/src/rules/import/no_named_default.rs @@ -0,0 +1,74 @@ +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_span::Span; + +use crate::{context::LintContext, module_record::ImportImportName, rule::Rule}; + +fn no_named_default_diagnostic(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("Replace default import with named import.") + .with_help("Forbid named default exports.") + .with_label(span) +} + +#[derive(Debug, Default, Clone)] +pub struct NoNamedDefault; + +declare_oxc_lint!( + /// ### What it does + /// Reports use of a default export as a locally named import. + /// + /// ### Why is this bad? + /// Rationale: the syntax exists to import default exports expressively, let's use it. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```js + /// // message: Using exported name 'bar' as identifier for default export. + /// import { default as foo } from './foo.js'; + /// import { default as foo, bar } from './foo.js'; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```js + /// import foo from './foo.js'; + /// import foo, { bar } from './foo.js'; + /// ``` + NoNamedDefault, + style, + pending // TODO: describe fix capabilities. Remove if no fix can be done, + // keep at 'pending' if you think one could be added but don't know how. + // Options are 'fix', 'fix_dangerous', 'suggestion', and 'conditional_fix_suggestion' +); + +impl Rule for NoNamedDefault { + fn run_once(&self, ctx: &LintContext) { + ctx.module_record().import_entries.iter().for_each(|entry| { + let ImportImportName::Name(import_name) = &entry.import_name else { + return; + }; + if import_name.name() == "default" && !entry.is_type { + ctx.diagnostic(no_named_default_diagnostic(entry.module_request.span())); + } + }); + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + r#"import bar from "./bar";"#, + r#"import bar, { foo } from "./bar";"#, + r#"import { type default as Foo } from "./bar";"#, + ]; + + let fail = vec![ + r#"import { default as bar } from "./bar";"#, + r#"import { foo, default as bar } from "./bar";"#, + r#"import { "default" as bar } from "./bar";"#, + ]; + + Tester::new(NoNamedDefault::NAME, NoNamedDefault::CATEGORY, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/import_no_named_default.snap b/crates/oxc_linter/src/snapshots/import_no_named_default.snap new file mode 100644 index 0000000000000..8d86115aced78 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/import_no_named_default.snap @@ -0,0 +1,24 @@ +--- +source: crates/oxc_linter/src/tester.rs +snapshot_kind: text +--- + ⚠ eslint-plugin-import(no-named-default): Replace default import with named import. + ╭─[no_named_default.tsx:1:32] + 1 │ import { default as bar } from "./bar"; + · ─────── + ╰──── + help: Forbid named default exports. + + ⚠ eslint-plugin-import(no-named-default): Replace default import with named import. + ╭─[no_named_default.tsx:1:37] + 1 │ import { foo, default as bar } from "./bar"; + · ─────── + ╰──── + help: Forbid named default exports. + + ⚠ eslint-plugin-import(no-named-default): Replace default import with named import. + ╭─[no_named_default.tsx:1:34] + 1 │ import { "default" as bar } from "./bar"; + · ─────── + ╰──── + help: Forbid named default exports. From c868d1f5cebfcf511a524ba5b9cddc6fd1f043ff Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 17 Dec 2024 10:25:47 +0800 Subject: [PATCH 2/2] u --- .../oxc_linter/src/rules/import/no_named_default.rs | 5 +---- .../src/snapshots/import_no_named_default.snap | 12 ++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/oxc_linter/src/rules/import/no_named_default.rs b/crates/oxc_linter/src/rules/import/no_named_default.rs index 287e3709b8313..94d3345d5fd92 100644 --- a/crates/oxc_linter/src/rules/import/no_named_default.rs +++ b/crates/oxc_linter/src/rules/import/no_named_default.rs @@ -36,9 +36,6 @@ declare_oxc_lint!( /// ``` NoNamedDefault, style, - pending // TODO: describe fix capabilities. Remove if no fix can be done, - // keep at 'pending' if you think one could be added but don't know how. - // Options are 'fix', 'fix_dangerous', 'suggestion', and 'conditional_fix_suggestion' ); impl Rule for NoNamedDefault { @@ -48,7 +45,7 @@ impl Rule for NoNamedDefault { return; }; if import_name.name() == "default" && !entry.is_type { - ctx.diagnostic(no_named_default_diagnostic(entry.module_request.span())); + ctx.diagnostic(no_named_default_diagnostic(import_name.span())); } }); } diff --git a/crates/oxc_linter/src/snapshots/import_no_named_default.snap b/crates/oxc_linter/src/snapshots/import_no_named_default.snap index 8d86115aced78..0722ba14c65c2 100644 --- a/crates/oxc_linter/src/snapshots/import_no_named_default.snap +++ b/crates/oxc_linter/src/snapshots/import_no_named_default.snap @@ -3,22 +3,22 @@ source: crates/oxc_linter/src/tester.rs snapshot_kind: text --- ⚠ eslint-plugin-import(no-named-default): Replace default import with named import. - ╭─[no_named_default.tsx:1:32] + ╭─[no_named_default.tsx:1:10] 1 │ import { default as bar } from "./bar"; - · ─────── + · ─────── ╰──── help: Forbid named default exports. ⚠ eslint-plugin-import(no-named-default): Replace default import with named import. - ╭─[no_named_default.tsx:1:37] + ╭─[no_named_default.tsx:1:15] 1 │ import { foo, default as bar } from "./bar"; - · ─────── + · ─────── ╰──── help: Forbid named default exports. ⚠ eslint-plugin-import(no-named-default): Replace default import with named import. - ╭─[no_named_default.tsx:1:34] + ╭─[no_named_default.tsx:1:10] 1 │ import { "default" as bar } from "./bar"; - · ─────── + · ───────── ╰──── help: Forbid named default exports.