mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
implemented import/no-default-export (#2736)
Tests: https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/tests/src/rules/no-default-export.js Rule: https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/no-default-export.md --------- Co-authored-by: Boshen <boshenc@gmail.com>
This commit is contained in:
parent
9edda499aa
commit
26a8171b98
3 changed files with 143 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ mod import {
|
|||
pub mod namespace;
|
||||
pub mod no_amd;
|
||||
pub mod no_cycle;
|
||||
pub mod no_default_export;
|
||||
pub mod no_deprecated;
|
||||
pub mod no_duplicates;
|
||||
pub mod no_named_as_default;
|
||||
|
|
@ -582,6 +583,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
import::no_unresolved,
|
||||
import::no_unused_modules,
|
||||
import::no_duplicates,
|
||||
import::no_default_export,
|
||||
jsx_a11y::alt_text,
|
||||
jsx_a11y::anchor_has_content,
|
||||
jsx_a11y::anchor_is_valid,
|
||||
|
|
|
|||
101
crates/oxc_linter/src/rules/import/no_default_export.rs
Normal file
101
crates/oxc_linter/src/rules/import/no_default_export.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::Error,
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint-plugin-import(no-default-export): Prefer named exports")]
|
||||
#[diagnostic(severity(warning))]
|
||||
struct NoDefaultExportDiagnostic(#[label] Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoDefaultExport;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Forbid a module to have a default exports. This help your editor to provide better auto imports.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// ```javascript
|
||||
/// // bad1.js
|
||||
///
|
||||
/// // There is a default export.
|
||||
/// export const foo = 'foo';
|
||||
/// const bar = 'bar';
|
||||
/// export default 'bar';
|
||||
/// ```
|
||||
///
|
||||
/// ```javascript
|
||||
/// // bad2.js
|
||||
///
|
||||
/// // There is a default export.
|
||||
/// const foo = 'foo';
|
||||
/// export { foo as default }
|
||||
/// ```
|
||||
///
|
||||
NoDefaultExport,
|
||||
nursery
|
||||
);
|
||||
|
||||
impl Rule for NoDefaultExport {
|
||||
fn run_once(&self, ctx: &LintContext<'_>) {
|
||||
let module_record = ctx.semantic().module_record();
|
||||
write_diagnostic_optional(ctx, module_record.export_default);
|
||||
module_record.export_default_duplicated.iter().for_each(|it| write_diagnostic(ctx, *it));
|
||||
write_diagnostic_optional(ctx, module_record.exported_bindings.get("default").copied());
|
||||
}
|
||||
}
|
||||
|
||||
fn write_diagnostic(ctx: &LintContext<'_>, span: Span) {
|
||||
ctx.diagnostic(NoDefaultExportDiagnostic(span));
|
||||
}
|
||||
fn write_diagnostic_optional(ctx: &LintContext<'_>, span_option: Option<Span>) {
|
||||
if let Some(span) = span_option {
|
||||
write_diagnostic(ctx, span);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
"export const foo = 'foo'; export const bar = 'bar';",
|
||||
"export const foo = 'foo'; export function bar() {};",
|
||||
"export const foo = 'foo';",
|
||||
"const foo = 'foo'; export { foo };",
|
||||
"let foo, bar; export { foo, bar }",
|
||||
"export const { foo, bar } = item;",
|
||||
"export const { foo, bar: baz } = item;",
|
||||
"export const { foo: { bar, baz } } = item;",
|
||||
"let item; export const foo = item; export { item };",
|
||||
"export * from './foo';",
|
||||
"export const { foo } = { foo: 'bar' };",
|
||||
"export const { foo: { bar } } = { foo: { bar: 'baz' } };",
|
||||
"export { a, b } from 'foo.js'",
|
||||
"import * as foo from './foo';",
|
||||
"import foo from './foo';",
|
||||
"import {default as foo} from './foo';",
|
||||
"export type UserId = number;",
|
||||
];
|
||||
let fail = vec![
|
||||
"export default function bar() {};",
|
||||
"export const foo = 'foo';\nexport default bar;",
|
||||
"export default class Bar {};",
|
||||
"export default function() {};",
|
||||
"export default class {};",
|
||||
"let foo; export { foo as default }",
|
||||
// "export default from \"foo.js\"",
|
||||
];
|
||||
|
||||
Tester::new(NoDefaultExport::NAME, pass, fail)
|
||||
.with_import_plugin(true)
|
||||
.change_rule_path("index.ts")
|
||||
.test_and_snapshot();
|
||||
}
|
||||
40
crates/oxc_linter/src/snapshots/no_default_export.snap
Normal file
40
crates/oxc_linter/src/snapshots/no_default_export.snap
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: no_default_export
|
||||
---
|
||||
⚠ eslint-plugin-import(no-default-export): Prefer named exports
|
||||
╭─[index.ts:1:8]
|
||||
1 │ export default function bar() {};
|
||||
· ───────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-import(no-default-export): Prefer named exports
|
||||
╭─[index.ts:2:8]
|
||||
1 │ export const foo = 'foo';
|
||||
2 │ export default bar;
|
||||
· ───────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-import(no-default-export): Prefer named exports
|
||||
╭─[index.ts:1:8]
|
||||
1 │ export default class Bar {};
|
||||
· ───────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-import(no-default-export): Prefer named exports
|
||||
╭─[index.ts:1:8]
|
||||
1 │ export default function() {};
|
||||
· ───────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-import(no-default-export): Prefer named exports
|
||||
╭─[index.ts:1:8]
|
||||
1 │ export default class {};
|
||||
· ───────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-import(no-default-export): Prefer named exports
|
||||
╭─[index.ts:1:26]
|
||||
1 │ let foo; export { foo as default }
|
||||
· ───────
|
||||
╰────
|
||||
Loading…
Reference in a new issue