Skip to content

Commit

Permalink
fix(linter): improve prefer_namespace_keyword rule (#4751)
Browse files Browse the repository at this point in the history
fix: #4651
This commit enhances the `prefer_namespace_keyword` rule in the
TypeScript linter: Add support for detecting and fixing nested module
declarations (e.g., module A.B {})

- Introduce helper functions `is_nest_module`, `is_valid_module`, and
`is_invalid_module` to improve code readability and maintainability
- Refactor the main `run` function to use these new helper functions
- Update test cases to cover nested module scenarios
- Improve error reporting for nested modules
  • Loading branch information
cblh authored Aug 9, 2024
1 parent c15c931 commit b22ed45
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 32 deletions.
66 changes: 48 additions & 18 deletions crates/oxc_linter/src/rules/typescript/prefer_namespace_keyword.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use oxc_ast::{
ast::{TSModuleDeclarationKind, TSModuleDeclarationName},
ast::{TSModuleDeclaration, TSModuleDeclarationKind, TSModuleDeclarationName},
AstKind,
};
use oxc_diagnostics::OxcDiagnostic;
Expand Down Expand Up @@ -34,13 +34,27 @@ declare_oxc_lint!(
fix
);

fn is_nest_module(node: &AstNode, ctx: &LintContext<'_>) -> bool {
ctx.nodes()
.parent_node(node.id())
.map_or(false, |parent_node| is_valid_module_node(parent_node))
}

fn is_valid_module_node(node: &AstNode) -> bool {
matches!(node.kind(), AstKind::TSModuleDeclaration(module) if is_valid_module(module))
}

fn is_valid_module(module: &TSModuleDeclaration) -> bool {
!module.id.is_string_literal()
&& matches!(module.id, TSModuleDeclarationName::Identifier(_))
&& module.kind == TSModuleDeclarationKind::Module
}

impl Rule for PreferNamespaceKeyword {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::TSModuleDeclaration(module) = node.kind() else { return };
if module.id.is_string_literal()
|| !matches!(module.id, TSModuleDeclarationName::Identifier(_))
|| module.kind != TSModuleDeclarationKind::Module
{

if !is_valid_module(module) || is_nest_module(node, ctx) {
return;
}

Expand Down Expand Up @@ -74,32 +88,48 @@ fn test() {

let fail = vec![
"module foo {}",
"module A.B {}",
"declare module foo {}",
"
declare module foo {
declare module bar {}
}
",
"declare global {
declare module foo {
declare module bar {}
}
",
"
declare global {
module foo {}
}
",
];

let fix = vec![
("module foo {}", "namespace foo {}", None),
("module A.B {}", "namespace A.B {}", None),
(
"
module A {
module B {}
}
",
"
namespace A {
namespace B {}
}
",
None,
),
("declare module foo {}", "declare namespace foo {}", None),
(
"
declare module foo {
declare module bar {}
}
",
declare module foo {
declare module bar {}
}
",
"
declare namespace foo {
declare namespace bar {}
}
",
declare namespace foo {
declare namespace bar {}
}
",
None,
),
];
Expand Down
35 changes: 21 additions & 14 deletions crates/oxc_linter/src/snapshots/prefer_namespace_keyword.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ source: crates/oxc_linter/src/tester.rs
╰────
help: Replace `module` with `namespace`.

typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
╭─[prefer_namespace_keyword.tsx:1:1]
1module A.B {}
· ─────────────
╰────
help: Replace `module` with `namespace`.

typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
╭─[prefer_namespace_keyword.tsx:1:1]
1declare module foo {}
Expand All @@ -16,29 +23,29 @@ source: crates/oxc_linter/src/tester.rs
help: Replace `module` with `namespace`.

typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
╭─[prefer_namespace_keyword.tsx:2:4]
╭─[prefer_namespace_keyword.tsx:2:9]
1
2 │ ╭─▶ declare module foo {
3 │ │ declare module bar {}
4 │ ╰─▶ }
5
2 │ ╭─▶ declare module foo {
3 │ │ declare module bar {}
4 │ ╰─▶ }
5
╰────
help: Replace `module` with `namespace`.

typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
╭─[prefer_namespace_keyword.tsx:3:6]
2 declare module foo {
3 declare module bar {}
· ─────────────────────
4 }
╭─[prefer_namespace_keyword.tsx:3:11]
2declare module foo {
3declare module bar {}
· ─────────────────────
4 │ }
╰────
help: Replace `module` with `namespace`.

typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
╭─[prefer_namespace_keyword.tsx:2:13]
1 declare global {
2module foo {}
╭─[prefer_namespace_keyword.tsx:3:13]
2 declare global {
3module foo {}
· ─────────────
3 │ }
4 │ }
╰────
help: Replace `module` with `namespace`.

0 comments on commit b22ed45

Please sign in to comment.