@@ -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]
223240fn 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 ( ) ;
0 commit comments