Skip to content

Commit c9189ef

Browse files
sonar-nigel[bot]Vibe Botclaude
authored
JS-1114 Fix S3504 FP: skip TypeScript ambient 'declare var' declarations (#6224)
Co-authored-by: Vibe Bot <vibe-bot@sonarsource.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9abcffe commit c9189ef

6 files changed

Lines changed: 52 additions & 28 deletions

File tree

its/ruling/src/test/expected/jsts/TypeScript/typescript-S3504.json

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
20
1414
],
1515
"TypeScript:scripts/createBenchmark.ts": [
16-
7,
1716
9,
1817
10,
1918
11,
@@ -29,12 +28,8 @@
2928
115
3029
],
3130
"TypeScript:scripts/errorCheck.ts": [
32-
1,
3331
31
3432
],
35-
"TypeScript:scripts/importDefinitelyTypedTests/importDefinitelyTypedTests.ts": [
36-
10
37-
],
3833
"TypeScript:scripts/ior.ts": [
3934
24,
4035
25,
@@ -127,9 +122,6 @@
127122
"TypeScript:src/harness/harness.ts": [
128123
33,
129124
34,
130-
35,
131-
36,
132-
38,
133-
39
125+
36
134126
]
135127
}

its/ruling/src/test/expected/jsts/eigen/typescript-S3504.json

Lines changed: 0 additions & 9 deletions
This file was deleted.

its/ruling/src/test/expected/jsts/fireface/typescript-S3504.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

its/ruling/src/test/expected/jsts/rxjs/typescript-S3504.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,5 @@
22
"rxjs:src/testing/HotObservable.ts": [
33
40,
44
42
5-
],
6-
"rxjs:src/util/root.ts": [
7-
11
85
]
96
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// False positive scenario: TypeScript ambient declaration with 'declare var'
2+
// 'declare var' is a compile-time type annotation that describes an existing
3+
// external variable (like jQuery's $). It doesn't create a runtime variable
4+
// and cannot be changed to let/const.
5+
6+
// Example 1: External library type declaration (e.g., jQuery)
7+
declare var $: any;
8+
9+
// Example 2: Module globals from server-side rendering or global configuration
10+
declare var initConfig: { apiUrl: string; debug: boolean };
11+
declare var initPresets: string[];
12+
13+
// Example 3: Build-time injected variables (webpack/Vite)
14+
declare var __CORE_VERSION__: string;
15+
declare var __VERSION__: string;
16+
17+
// Example 4: React Refresh runtime globals
18+
declare var $RefreshHelpers$: any;
19+
declare var $RefreshReg$: any;
20+
declare var $RefreshSig$: any;
21+
22+
// Example 5: Complex object type with methods (Node.js process)
23+
declare var process: {
24+
argv: string[];
25+
env: Record<string, string>;
26+
exit(code?: number): void;
27+
};
28+
29+
// Example 6: Interface-like type declaration (browser XMLHttpRequest)
30+
declare var XMLHttpRequest: {
31+
new(): XMLHttpRequest;
32+
};
33+
34+
// Regular var declarations should still be flagged
35+
function bar() {
36+
var foo = 42; // Noncompliant [[qf1!]] {{Unexpected var, use let or const instead.}}
37+
//^^^^^^^
38+
// edit@qf1 {{ let foo = 42;}}
39+
40+
var x, y = 1; // Noncompliant [[qf2!]] {{Unexpected var, use let or const instead.}}
41+
//^^^^^
42+
// edit@qf2 {{ let x, y = 1;}}
43+
}

packages/jsts/src/rules/S3504/decorator.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,16 @@ export function decorate(rule: Rule.RuleModule): Rule.RuleModule {
2828
(context, reportDescriptor) => {
2929
if ('node' in reportDescriptor) {
3030
const { node, ...rest } = reportDescriptor;
31+
const varDecl = node as estree.VariableDeclaration & { declare?: boolean };
32+
33+
// Skip TypeScript ambient declarations (declare var)
34+
if (varDecl.declare) {
35+
return;
36+
}
37+
3138
const {
3239
declarations: [firstDecl, ..._],
33-
} = node as estree.VariableDeclaration;
40+
} = varDecl;
3441

3542
const varToken = context.sourceCode.getTokenBefore(firstDecl.id);
3643
const identifierEnd = firstDecl.id.loc!.end;

0 commit comments

Comments
 (0)