Skip to content

Commit b22ed45

Browse files
authored
fix(linter): improve prefer_namespace_keyword rule (#4751)
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
1 parent c15c931 commit b22ed45

2 files changed

Lines changed: 69 additions & 32 deletions

File tree

crates/oxc_linter/src/rules/typescript/prefer_namespace_keyword.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use oxc_ast::{
2-
ast::{TSModuleDeclarationKind, TSModuleDeclarationName},
2+
ast::{TSModuleDeclaration, TSModuleDeclarationKind, TSModuleDeclarationName},
33
AstKind,
44
};
55
use oxc_diagnostics::OxcDiagnostic;
@@ -34,13 +34,27 @@ declare_oxc_lint!(
3434
fix
3535
);
3636

37+
fn is_nest_module(node: &AstNode, ctx: &LintContext<'_>) -> bool {
38+
ctx.nodes()
39+
.parent_node(node.id())
40+
.map_or(false, |parent_node| is_valid_module_node(parent_node))
41+
}
42+
43+
fn is_valid_module_node(node: &AstNode) -> bool {
44+
matches!(node.kind(), AstKind::TSModuleDeclaration(module) if is_valid_module(module))
45+
}
46+
47+
fn is_valid_module(module: &TSModuleDeclaration) -> bool {
48+
!module.id.is_string_literal()
49+
&& matches!(module.id, TSModuleDeclarationName::Identifier(_))
50+
&& module.kind == TSModuleDeclarationKind::Module
51+
}
52+
3753
impl Rule for PreferNamespaceKeyword {
3854
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
3955
let AstKind::TSModuleDeclaration(module) = node.kind() else { return };
40-
if module.id.is_string_literal()
41-
|| !matches!(module.id, TSModuleDeclarationName::Identifier(_))
42-
|| module.kind != TSModuleDeclarationKind::Module
43-
{
56+
57+
if !is_valid_module(module) || is_nest_module(node, ctx) {
4458
return;
4559
}
4660

@@ -74,32 +88,48 @@ fn test() {
7488

7589
let fail = vec![
7690
"module foo {}",
91+
"module A.B {}",
7792
"declare module foo {}",
7893
"
79-
declare module foo {
80-
declare module bar {}
81-
}
82-
",
83-
"declare global {
94+
declare module foo {
95+
declare module bar {}
96+
}
97+
",
98+
"
99+
declare global {
84100
module foo {}
85101
}
86102
",
87103
];
88104

89105
let fix = vec![
90106
("module foo {}", "namespace foo {}", None),
107+
("module A.B {}", "namespace A.B {}", None),
108+
(
109+
"
110+
module A {
111+
module B {}
112+
}
113+
",
114+
"
115+
namespace A {
116+
namespace B {}
117+
}
118+
",
119+
None,
120+
),
91121
("declare module foo {}", "declare namespace foo {}", None),
92122
(
93123
"
94-
declare module foo {
95-
declare module bar {}
96-
}
97-
",
124+
declare module foo {
125+
declare module bar {}
126+
}
127+
",
98128
"
99-
declare namespace foo {
100-
declare namespace bar {}
101-
}
102-
",
129+
declare namespace foo {
130+
declare namespace bar {}
131+
}
132+
",
103133
None,
104134
),
105135
];

crates/oxc_linter/src/snapshots/prefer_namespace_keyword.snap

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ source: crates/oxc_linter/src/tester.rs
88
╰────
99
help: Replace `module` with `namespace`.
1010

11+
typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
12+
╭─[prefer_namespace_keyword.tsx:1:1]
13+
1module A.B {}
14+
· ─────────────
15+
╰────
16+
help: Replace `module` with `namespace`.
17+
1118
typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
1219
╭─[prefer_namespace_keyword.tsx:1:1]
1320
1declare module foo {}
@@ -16,29 +23,29 @@ source: crates/oxc_linter/src/tester.rs
1623
help: Replace `module` with `namespace`.
1724

1825
typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
19-
╭─[prefer_namespace_keyword.tsx:2:4]
26+
╭─[prefer_namespace_keyword.tsx:2:9]
2027
1
21-
2 │ ╭─▶ declare module foo {
22-
3 │ │ declare module bar {}
23-
4 │ ╰─▶ }
24-
5
28+
2 │ ╭─▶ declare module foo {
29+
3 │ │ declare module bar {}
30+
4 │ ╰─▶ }
31+
5
2532
╰────
2633
help: Replace `module` with `namespace`.
2734

2835
typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
29-
╭─[prefer_namespace_keyword.tsx:3:6]
30-
2 declare module foo {
31-
3 declare module bar {}
32-
· ─────────────────────
33-
4 }
36+
╭─[prefer_namespace_keyword.tsx:3:11]
37+
2declare module foo {
38+
3declare module bar {}
39+
· ─────────────────────
40+
4 │ }
3441
╰────
3542
help: Replace `module` with `namespace`.
3643

3744
typescript-eslint(prefer-namespace-keyword): Use 'namespace' instead of 'module' to declare custom TypeScript modules.
38-
╭─[prefer_namespace_keyword.tsx:2:13]
39-
1 declare global {
40-
2module foo {}
45+
╭─[prefer_namespace_keyword.tsx:3:13]
46+
2 declare global {
47+
3module foo {}
4148
· ─────────────
42-
3 │ }
49+
4 │ }
4350
╰────
4451
help: Replace `module` with `namespace`.

0 commit comments

Comments
 (0)