Skip to content

Commit

Permalink
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 0 deletions.
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ mod typescript {
pub mod no_this_alias;
pub mod no_unnecessary_type_constraint;
pub mod no_unsafe_declaration_merging;
pub mod no_useless_empty_export;
pub mod no_var_requires;
pub mod prefer_as_const;
pub mod prefer_enum_initializers;
Expand Down Expand Up @@ -522,6 +523,7 @@ oxc_macros::declare_all_lint_rules! {
typescript::no_this_alias,
typescript::no_unnecessary_type_constraint,
typescript::no_unsafe_declaration_merging,
typescript::no_useless_empty_export,
typescript::no_var_requires,
typescript::prefer_as_const,
typescript::prefer_for_of,
Expand Down
129 changes: 129 additions & 0 deletions crates/oxc_linter/src/rules/typescript/no_useless_empty_export.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{context::LintContext, rule::Rule, AstNode};

fn no_useless_empty_export_diagnostic(span0: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(
"typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file",
)
.with_help("Empty export does nothing and can be removed.")
.with_labels([span0.into()])
}

#[derive(Debug, Default, Clone)]
pub struct NoUselessEmptyExport;

declare_oxc_lint!(
/// ### What it does
///
/// Disallow empty exports that don't change anything in a module file.
///
/// ### Example
///
/// ### Bad
/// ```javascript
/// export const value = 'Hello, world!';
/// export {};
/// ```
///
/// ### Good
/// ```javascript
/// export const value = 'Hello, world!';
/// ```
///
NoUselessEmptyExport,
correctness
);

impl Rule for NoUselessEmptyExport {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::ExportNamedDeclaration(decl) = node.kind() else { return };
if decl.declaration.is_some() || !decl.specifiers.is_empty() {
return;
}
let module_record = ctx.semantic().module_record();
if module_record.exported_bindings.is_empty()
&& module_record.local_export_entries.is_empty()
&& module_record.indirect_export_entries.is_empty()
&& module_record.star_export_entries.is_empty()
&& module_record.export_default.is_none()
{
return;
}
ctx.diagnostic_with_fix(no_useless_empty_export_diagnostic(decl.span), |fixer| {
fixer.delete(&decl.span)
});
}
}

#[test]
fn test() {
use crate::tester::Tester;

let pass = vec![
"declare module '_'",
"import {} from '_';",
"import * as _ from '_';",
"export = {};",
"export = 3;",
"export const _ = {};",
"
const _ = {};
export default _;
",
"
export * from '_';
export = {};
",
"export {};",
];

let fail = vec![
"
export const _ = {};
export {};
",
"
export * from '_';
export {};
",
"
export {};
export * from '_';
",
"
const _ = {};
export default _;
export {};
",
"
export {};
const _ = {};
export default _;
",
"
const _ = {};
export { _ };
export {};
",
// "
// import _ = require('_');
// export {};
// ",
];

let fix = vec![
("export const _ = {};export {};", "export const _ = {};"),
("export * from '_';export {};", "export * from '_';"),
("export {};export * from '_';", "export * from '_';"),
("const _ = {};export default _;export {};", "const _ = {};export default _;"),
("export {};const _ = {};export default _;", "const _ = {};export default _;"),
("const _ = {};export { _ };export {};", "const _ = {};export { _ };"),
// ("import _ = require('_');export {};", "import _ = require('_');"),
];

Tester::new(NoUselessEmptyExport::NAME, pass, fail).expect_fix(fix).test_and_snapshot();
}
57 changes: 57 additions & 0 deletions crates/oxc_linter/src/snapshots/no_useless_empty_export.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
source: crates/oxc_linter/src/tester.rs
expression: no_useless_empty_export
---
typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file
╭─[no_useless_empty_export.tsx:3:13]
2export const _ = {};
3export {};
· ──────────
4
╰────
help: Empty export does nothing and can be removed.

typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file
╭─[no_useless_empty_export.tsx:3:13]
2export * from '_';
3export {};
· ──────────
4
╰────
help: Empty export does nothing and can be removed.

typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file
╭─[no_useless_empty_export.tsx:2:13]
1
2export {};
· ──────────
3export * from '_';
╰────
help: Empty export does nothing and can be removed.

typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file
╭─[no_useless_empty_export.tsx:4:13]
3export default _;
4export {};
· ──────────
5
╰────
help: Empty export does nothing and can be removed.

typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file
╭─[no_useless_empty_export.tsx:2:13]
1
2export {};
· ──────────
3const _ = {};
╰────
help: Empty export does nothing and can be removed.

typescript-eslint(no-useless-empty-export): Disallow empty exports that don't change anything in a module file
╭─[no_useless_empty_export.tsx:4:13]
3export { _ };
4export {};
· ──────────
5
╰────
help: Empty export does nothing and can be removed.

0 comments on commit 21d3425

Please sign in to comment.