Skip to content

Commit 55ee962

Browse files
hamirmahalcamc314
andauthored
fix(linter/vars-on-top): false positive with typescript declare block (#14952)
Fixes #14951 --------- Co-authored-by: Cameron Clark <cameron.clark@hey.com>
1 parent 2de9f39 commit 55ee962

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

crates/oxc_linter/src/rules/eslint/vars_on_top.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ impl Rule for VarsOnTop {
9999
if declaration.kind != VariableDeclarationKind::Var {
100100
return;
101101
}
102+
103+
// Skip TypeScript ambient declarations (declare global, declare module, etc.)
104+
if is_in_ambient_typescript_context(node, ctx) {
105+
return;
106+
}
107+
102108
let parent = ctx.nodes().parent_node(node.id());
103109

104110
match parent.kind() {
@@ -219,6 +225,17 @@ fn check_var_on_top_in_function_scope(
219225
false
220226
}
221227

228+
fn is_in_ambient_typescript_context(node: &AstNode, ctx: &LintContext) -> bool {
229+
ctx.nodes().ancestors(node.id()).any(|ancestor| {
230+
if let AstKind::TSModuleDeclaration(module) = ancestor.kind() {
231+
// Ambient if it has the `declare` keyword or is a `declare global` block
232+
module.declare || module.kind.is_global()
233+
} else {
234+
false
235+
}
236+
})
237+
}
238+
222239
#[test]
223240
fn test() {
224241
use crate::tester::Tester;
@@ -387,6 +404,15 @@ fn test() {
387404
let x;
388405
}
389406
}", // { "ecmaVersion": 2022 }
407+
"declare global {
408+
var __CUSTOM_FLAG__: boolean | undefined;
409+
}",
410+
"declare module 'foo' {
411+
var x: string;
412+
}",
413+
"declare namespace MyNamespace {
414+
var y: number;
415+
}",
390416
];
391417

392418
let fail = vec![
@@ -532,6 +558,7 @@ fn test() {
532558
var x;
533559
}
534560
}", // { "ecmaVersion": 2022 }
561+
"namespace MyNamespace { const y: number = 123; var z: string; }",
535562
];
536563

537564
Tester::new(VarsOnTop::NAME, VarsOnTop::PLUGIN, pass, fail).test_and_snapshot();

crates/oxc_linter/src/snapshots/eslint_vars_on_top.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,10 @@ source: crates/oxc_linter/src/tester.rs
229229
5 │ }
230230
╰────
231231
help: Consider moving this to the top of the functions scope or using let or const to declare this variable.
232+
233+
eslint(vars-on-top): All 'var' declarations must be at the top of the function scope.
234+
╭─[vars_on_top.tsx:1:48]
235+
1 │ namespace MyNamespace { const y: number = 123; var z: string; }
236+
· ──────────────
237+
╰────
238+
help: Consider moving this to the top of the functions scope or using let or const to declare this variable.

0 commit comments

Comments
 (0)