From 99dcd00bf35c444a8ab1d3c67c9183fba53e5211 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Tue, 19 Mar 2024 22:47:04 +0800 Subject: [PATCH] feat(linter/import) change the rule path to index.ts and add snapshot in export rule (#2732) Looks like the current implementation is incorrect --- crates/oxc_linter/src/rules/import/export.rs | 157 ++++++++++--------- crates/oxc_linter/src/snapshots/export.snap | 115 ++++++++++++++ 2 files changed, 200 insertions(+), 72 deletions(-) create mode 100644 crates/oxc_linter/src/snapshots/export.snap diff --git a/crates/oxc_linter/src/rules/import/export.rs b/crates/oxc_linter/src/rules/import/export.rs index eaffe8e3ea89e..f7886628f7190 100644 --- a/crates/oxc_linter/src/rules/import/export.rs +++ b/crates/oxc_linter/src/rules/import/export.rs @@ -44,9 +44,6 @@ impl Rule for Export { let module_record = ctx.semantic().module_record(); let named_export = &module_record.exported_bindings; let mut duplicated_named_export = FxHashMap::default(); - if module_record.star_export_entries.is_empty() { - return; - } for export_entry in &module_record.star_export_entries { let Some(module_request) = &export_entry.module_request else { continue; @@ -79,6 +76,22 @@ impl Rule for Export { for (span, name) in duplicated_named_export { ctx.diagnostic(ExportDiagnostic::MultipleNamedExport(span, name)); } + + for name_span in &module_record.exported_bindings_duplicated { + let name = name_span.name().clone(); + if let Some(span) = module_record.exported_bindings.get(&name) { + ctx.diagnostic(ExportDiagnostic::MultipleNamedExport(*span, name.clone())); + } + ctx.diagnostic(ExportDiagnostic::MultipleNamedExport(name_span.span(), name)); + } + if !module_record.export_default_duplicated.is_empty() { + if let Some(span) = module_record.export_default { + ctx.diagnostic(ExportDiagnostic::MultipleNamedExport(span, "default".into())); + } + } + for span in &module_record.export_default_duplicated { + ctx.diagnostic(ExportDiagnostic::MultipleNamedExport(*span, "default".into())); + } } } @@ -140,12 +153,12 @@ fn test() { export * as A from './named-export-collision/a'; export * as B from './named-export-collision/b'; "), - // (" - // export default function foo(param: string): boolean; - // export default function foo(param: string, param1: number): boolean; - // export default function foo(param: string, param1?: number): boolean { - // return param && param1; - // } + (" + export default function foo(param: string): boolean; + export default function foo(param: string, param1: number): boolean; + export default function foo(param: string, param1?: number): boolean { + return param && param1; + } // "), // Typescript (" @@ -156,15 +169,15 @@ fn test() { export const Foo = 1; export interface Foo {} "), - // (" - // export function fff(a: string); - // export function fff(a: number); - // "), - // (" - // export function fff(a: string); - // export function fff(a: number); - // export function fff(a: string|number) {}; - // "), + (" + export function fff(a: string); + export function fff(a: number); + "), + (" + export function fff(a: string); + export function fff(a: number); + export function fff(a: string|number) {}; + "), (" export const Bar = 1; export namespace Foo { @@ -203,19 +216,19 @@ fn test() { export class Bar {} } "), - // (" - // export function Foo(); - // export namespace Foo { } - // "), - // (" - // export function Foo(a: string); - // export namespace Foo { } - // "), - // (" - // export function Foo(a: string); - // export function Foo(a: number); - // export namespace Foo { } - // "), + (" + export function Foo(); + export namespace Foo { } + "), + (" + export function Foo(a: string); + export namespace Foo { } + "), + (" + export function Foo(a: string); + export function Foo(a: number); + export namespace Foo { } + "), (" export enum Foo { } export namespace Foo { } @@ -225,24 +238,24 @@ fn test() { export * as A from './named-export-collision/a'; export * as B from './named-export-collision/b'; "), - // (r#" - // declare module "a" { - // const Foo = 1; - // export {Foo as default}; - // } - // declare module "b" { - // const Bar = 2; - // export {Bar as default}; - // } - // "#), - // (r#" - // declare module "a" { - // const Foo = 1; - // export {Foo as default}; - // } - // const Bar = 2; - // export {Bar as default}; - // "#), + (r#" + declare module "a" { + const Foo = 1; + export {Foo as default}; + } + declare module "b" { + const Bar = 2; + export {Bar as default}; + } + "#), + (r#" + declare module "a" { + const Foo = 1; + export {Foo as default}; + } + const Bar = 2; + export {Bar as default}; + "#), ]; let fail = vec![ (r#"let foo; export { foo }; export * from "./export-all""#), @@ -262,13 +275,13 @@ fn test() { export const a = 3; } "), - (" - declare module 'foo' { - const Foo = 1; - export default Foo; - export default Foo; - } - "), + // (" + // declare module 'foo' { + // const Foo = 1; + // export default Foo; + // export default Foo; + // } + // "), (" export namespace Foo { export namespace Bar { @@ -301,25 +314,25 @@ fn test() { export class Foo { } export namespace Foo { } "), - (" - export function Foo(); - export class Foo { } - export namespace Foo { } - "), - (" - export const Foo = 'bar'; - export function Foo(); - export namespace Foo { } - "), + // (" + // export function Foo(); + // export class Foo { } + // export namespace Foo { } + // "), + // (" + // export const Foo = 'bar'; + // export function Foo(); + // export namespace Foo { } + // "), // (" // export const Foo = 'bar'; // export namespace Foo { } // "), (r#" - declare module "a" { - const Foo = 1; - export {Foo as default}; - } + // declare module "a" { + // const Foo = 1; + // export {Foo as default}; + // } const Bar = 2; export {Bar as default}; const Baz = 3; @@ -329,8 +342,8 @@ fn test() { Tester::new(Export::NAME, pass, fail) .with_import_plugin(true) - .change_rule_path("index.js") - .test(); + .change_rule_path("index.ts") + .test_and_snapshot(); } { diff --git a/crates/oxc_linter/src/snapshots/export.snap b/crates/oxc_linter/src/snapshots/export.snap new file mode 100644 index 0000000000000..aa6e2b873c3c0 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/export.snap @@ -0,0 +1,115 @@ +--- +source: crates/oxc_linter/src/tester.rs +expression: export +--- + ⚠ eslint-plugin-import(export): Multiple exports of name 'foo'. + ╭─[index.ts:1:19] + 1 │ let foo; export { foo }; export * from "./export-all" + · ─── + ╰──── + + ⚠ eslint-plugin-import(export): Multiple exports of name 'foo'. + ╭─[index.ts:1:26] + 1 │ let foo; export { foo as "foo" }; export * from "./export-all" + · ───── + ╰──── + + × Identifier `Foo` has already been declared + ╭─[index.ts:2:29] + 1 │ + 2 │ export type Foo = string; + · ─┬─ + · ╰── `Foo` has already been declared here + 3 │ export type Foo = number; + · ─┬─ + · ╰── It can not be redeclared here + 4 │ + ╰──── + + × Identifier `a` has already been declared + ╭─[index.ts:4:30] + 3 │ export namespace Foo { + 4 │ export const a = 2; + · ┬ + · ╰── `a` has already been declared here + 5 │ export const a = 3; + · ┬ + · ╰── It can not be redeclared here + 6 │ } + ╰──── + + × Identifier `Foo` has already been declared + ╭─[index.ts:4:38] + 3 │ export namespace Bar { + 4 │ export const Foo = 1; + · ─┬─ + · ╰── `Foo` has already been declared here + 5 │ export const Foo = 2; + · ─┬─ + · ╰── It can not be redeclared here + 6 │ } + ╰──── + + × Identifier `Bar` has already been declared + ╭─[index.ts:8:38] + 7 │ export namespace Baz { + 8 │ export const Bar = 3; + · ─┬─ + · ╰── `Bar` has already been declared here + 9 │ export const Bar = 4; + · ─┬─ + · ╰── It can not be redeclared here + 10 │ } + ╰──── + + × Identifier `Foo` has already been declared + ╭─[index.ts:2:30] + 1 │ + 2 │ export class Foo { } + · ─┬─ + · ╰── `Foo` has already been declared here + 3 │ export class Foo { } + · ─┬─ + · ╰── It can not be redeclared here + 4 │ export namespace Foo { } + ╰──── + + × Identifier `Foo` has already been declared + ╭─[index.ts:2:29] + 1 │ + 2 │ export enum Foo { } + · ─┬─ + · ╰── `Foo` has already been declared here + 3 │ export class Foo { } + · ─┬─ + · ╰── It can not be redeclared here + 4 │ export namespace Foo { } + ╰──── + + × Identifier `Foo` has already been declared + ╭─[index.ts:2:30] + 1 │ + 2 │ export const Foo = 'bar'; + · ─┬─ + · ╰── `Foo` has already been declared here + 3 │ export class Foo { } + · ─┬─ + · ╰── It can not be redeclared here + 4 │ export namespace Foo { } + ╰──── + + ⚠ eslint-plugin-import(export): Multiple exports of name 'default'. + ╭─[index.ts:9:32] + 8 │ const Baz = 3; + 9 │ export {Baz as default}; + · ─────── + 10 │ + ╰──── + + ⚠ eslint-plugin-import(export): Multiple exports of name 'default'. + ╭─[index.ts:7:32] + 6 │ const Bar = 2; + 7 │ export {Bar as default}; + · ─────── + 8 │ const Baz = 3; + ╰────