Skip to content
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]
1 │ module 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]
1 │ declare 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]
2 │ declare module foo {
3 │ declare 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 {
2 │ module foo {}
╭─[prefer_namespace_keyword.tsx:3:13]
2 │ declare global {
3 │ module foo {}
· ─────────────
3 │ }
4 │ }
╰────
help: Replace `module` with `namespace`.