@flint.fyi/ts 0.14.3 → 0.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/lib/createTypeScriptFileFromProgram.js +5 -1
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/language.d.ts +1 -0
- package/lib/plugin.d.ts +61 -1
- package/lib/plugin.js +30 -0
- package/lib/rules/anyReturns.d.ts +6 -0
- package/lib/rules/anyReturns.js +187 -0
- package/lib/rules/anyReturns.test.d.ts +1 -0
- package/lib/rules/anyReturns.test.js +647 -0
- package/lib/rules/caseDuplicates.d.ts +6 -0
- package/lib/rules/caseDuplicates.js +49 -0
- package/lib/rules/caseDuplicates.test.d.ts +1 -0
- package/lib/rules/caseDuplicates.test.js +307 -0
- package/lib/rules/chainedAssignments.js +2 -1
- package/lib/rules/chainedAssignments.test.js +24 -0
- package/lib/rules/debuggerStatements.test.js +4 -4
- package/lib/rules/elseIfDuplicates.d.ts +6 -0
- package/lib/rules/elseIfDuplicates.js +53 -0
- package/lib/rules/elseIfDuplicates.test.d.ts +1 -0
- package/lib/rules/elseIfDuplicates.test.js +176 -0
- package/lib/rules/emptyBlocks.d.ts +6 -0
- package/lib/rules/emptyBlocks.js +66 -0
- package/lib/rules/emptyBlocks.test.d.ts +1 -0
- package/lib/rules/emptyBlocks.test.js +135 -0
- package/lib/rules/forDirections.d.ts +6 -0
- package/lib/rules/forDirections.js +124 -0
- package/lib/rules/forDirections.test.d.ts +1 -0
- package/lib/rules/forDirections.test.js +99 -0
- package/lib/rules/functionNewCalls.d.ts +6 -0
- package/lib/rules/functionNewCalls.js +60 -0
- package/lib/rules/functionNewCalls.test.d.ts +1 -0
- package/lib/rules/functionNewCalls.test.js +115 -0
- package/lib/rules/negativeZeroComparisons.js +4 -22
- package/lib/rules/nonOctalDecimalEscapes.d.ts +6 -0
- package/lib/rules/nonOctalDecimalEscapes.js +57 -0
- package/lib/rules/nonOctalDecimalEscapes.test.d.ts +1 -0
- package/lib/rules/nonOctalDecimalEscapes.test.js +69 -0
- package/lib/rules/numericLiteralParsing.d.ts +6 -0
- package/lib/rules/numericLiteralParsing.js +97 -0
- package/lib/rules/numericLiteralParsing.test.d.ts +1 -0
- package/lib/rules/numericLiteralParsing.test.js +99 -0
- package/lib/rules/octalNumbers.test.js +2 -2
- package/lib/rules/selfAssignments.d.ts +6 -0
- package/lib/rules/selfAssignments.js +44 -0
- package/lib/rules/selfAssignments.test.d.ts +1 -0
- package/lib/rules/selfAssignments.test.js +66 -0
- package/lib/rules/selfComparisons.d.ts +6 -0
- package/lib/rules/selfComparisons.js +41 -0
- package/lib/rules/selfComparisons.test.d.ts +1 -0
- package/lib/rules/selfComparisons.test.js +297 -0
- package/lib/rules/sequences.d.ts +6 -0
- package/lib/rules/sequences.js +34 -0
- package/lib/rules/sequences.test.d.ts +1 -0
- package/lib/rules/sequences.test.js +48 -0
- package/lib/rules/shadowedRestrictedNames.d.ts +6 -0
- package/lib/rules/shadowedRestrictedNames.js +95 -0
- package/lib/rules/shadowedRestrictedNames.test.d.ts +1 -0
- package/lib/rules/shadowedRestrictedNames.test.js +147 -0
- package/lib/rules/symbolDescriptions.test.js +4 -4
- package/lib/rules/typeofComparisons.d.ts +6 -0
- package/lib/rules/typeofComparisons.js +78 -0
- package/lib/rules/typeofComparisons.test.d.ts +1 -0
- package/lib/rules/typeofComparisons.test.js +85 -0
- package/lib/rules/unicodeBOMs.test.js +1 -0
- package/lib/rules/unnecessaryBlocks.d.ts +6 -0
- package/lib/rules/unnecessaryBlocks.js +75 -0
- package/lib/rules/unnecessaryBlocks.test.d.ts +1 -0
- package/lib/rules/unnecessaryBlocks.test.js +147 -0
- package/lib/rules/unnecessaryConcatenation.d.ts +6 -0
- package/lib/rules/unnecessaryConcatenation.js +38 -0
- package/lib/rules/unnecessaryConcatenation.test.d.ts +1 -0
- package/lib/rules/unnecessaryConcatenation.test.js +87 -0
- package/lib/rules/utils/discriminateAnyType.d.ts +12 -0
- package/lib/rules/utils/discriminateAnyType.js +41 -0
- package/lib/rules/utils/getThisExpression.d.ts +2 -0
- package/lib/rules/utils/getThisExpression.js +23 -0
- package/lib/rules/utils/isUnsafeAssignment.d.ts +13 -0
- package/lib/rules/utils/isUnsafeAssignment.js +76 -0
- package/lib/rules/utils/operators.d.ts +4 -0
- package/lib/rules/utils/operators.js +36 -0
- package/lib/rules/voidOperator.test.js +2 -2
- package/lib/utils/declarationIncludesGlobal.d.ts +2 -0
- package/lib/utils/declarationIncludesGlobal.js +5 -0
- package/lib/utils/declarationsIncludeGlobal.js +2 -5
- package/lib/utils/getDeclarationsIfGlobal.d.ts +2 -0
- package/lib/utils/getDeclarationsIfGlobal.js +7 -0
- package/lib/utils/hasSameTokens.d.ts +2 -0
- package/lib/utils/hasSameTokens.js +30 -0
- package/lib/utils/isGlobalDeclaration.js +2 -3
- package/lib/utils/isGlobalDeclarationOfName.d.ts +5 -0
- package/lib/utils/isGlobalDeclarationOfName.js +35 -0
- package/package.json +3 -3
- package/src/createTypeScriptFileFromProgram.ts +6 -1
- package/src/index.ts +3 -0
- package/src/language.ts +1 -0
- package/src/plugin.ts +30 -0
- package/src/rules/anyReturns.test.ts +649 -0
- package/src/rules/anyReturns.ts +263 -0
- package/src/rules/caseDuplicates.test.ts +308 -0
- package/src/rules/caseDuplicates.ts +57 -0
- package/src/rules/chainedAssignments.test.ts +24 -0
- package/src/rules/chainedAssignments.ts +4 -1
- package/src/rules/debuggerStatements.test.ts +4 -4
- package/src/rules/elseIfDuplicates.test.ts +177 -0
- package/src/rules/elseIfDuplicates.ts +69 -0
- package/src/rules/emptyBlocks.test.ts +136 -0
- package/src/rules/emptyBlocks.ts +73 -0
- package/src/rules/forDirections.test.ts +100 -0
- package/src/rules/forDirections.ts +163 -0
- package/src/rules/functionNewCalls.test.ts +116 -0
- package/src/rules/functionNewCalls.ts +75 -0
- package/src/rules/negativeZeroComparisons.ts +8 -27
- package/src/rules/nonOctalDecimalEscapes.test.ts +70 -0
- package/src/rules/nonOctalDecimalEscapes.ts +70 -0
- package/src/rules/numericLiteralParsing.test.ts +100 -0
- package/src/rules/numericLiteralParsing.ts +116 -0
- package/src/rules/octalNumbers.test.ts +2 -2
- package/src/rules/selfAssignments.test.ts +67 -0
- package/src/rules/selfAssignments.ts +50 -0
- package/src/rules/selfComparisons.test.ts +298 -0
- package/src/rules/selfComparisons.ts +45 -0
- package/src/rules/sequences.test.ts +49 -0
- package/src/rules/sequences.ts +37 -0
- package/src/rules/shadowedRestrictedNames.test.ts +148 -0
- package/src/rules/shadowedRestrictedNames.ts +105 -0
- package/src/rules/symbolDescriptions.test.ts +4 -4
- package/src/rules/typeofComparisons.test.ts +86 -0
- package/src/rules/typeofComparisons.ts +88 -0
- package/src/rules/unicodeBOMs.test.ts +1 -0
- package/src/rules/unnecessaryBlocks.test.ts +148 -0
- package/src/rules/unnecessaryBlocks.ts +89 -0
- package/src/rules/unnecessaryConcatenation.test.ts +88 -0
- package/src/rules/unnecessaryConcatenation.ts +44 -0
- package/src/rules/utils/discriminateAnyType.ts +66 -0
- package/src/rules/utils/getThisExpression.ts +24 -0
- package/src/rules/utils/isUnsafeAssignment.ts +113 -0
- package/src/rules/utils/operators.ts +39 -0
- package/src/rules/voidOperator.test.ts +2 -2
- package/src/utils/declarationIncludesGlobal.ts +9 -0
- package/src/utils/declarationsIncludeGlobal.ts +3 -7
- package/src/utils/getDeclarationsIfGlobal.ts +14 -0
- package/src/utils/hasSameTokens.ts +45 -0
- package/src/utils/isGlobalDeclaration.ts +3 -5
- package/src/utils/isGlobalDeclarationOfName.ts +56 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { ruleTester } from "./ruleTester.js";
|
|
2
|
+
import rule from "./selfComparisons.js";
|
|
3
|
+
ruleTester.describe(rule, {
|
|
4
|
+
invalid: [
|
|
5
|
+
{
|
|
6
|
+
code: `
|
|
7
|
+
if (value === value) {
|
|
8
|
+
console.log("always true");
|
|
9
|
+
}
|
|
10
|
+
`,
|
|
11
|
+
snapshot: `
|
|
12
|
+
if (value === value) {
|
|
13
|
+
~~~~~~~~~~~~~~~
|
|
14
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
15
|
+
console.log("always true");
|
|
16
|
+
}
|
|
17
|
+
`,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
code: `
|
|
21
|
+
if (value == value) {
|
|
22
|
+
console.log("always true");
|
|
23
|
+
}
|
|
24
|
+
`,
|
|
25
|
+
snapshot: `
|
|
26
|
+
if (value == value) {
|
|
27
|
+
~~~~~~~~~~~~~~
|
|
28
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
29
|
+
console.log("always true");
|
|
30
|
+
}
|
|
31
|
+
`,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
code: `
|
|
35
|
+
if (value !== value) {
|
|
36
|
+
console.log("always false");
|
|
37
|
+
}
|
|
38
|
+
`,
|
|
39
|
+
snapshot: `
|
|
40
|
+
if (value !== value) {
|
|
41
|
+
~~~~~~~~~~~~~~~
|
|
42
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
43
|
+
console.log("always false");
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
code: `
|
|
49
|
+
if (value != value) {
|
|
50
|
+
console.log("always false");
|
|
51
|
+
}
|
|
52
|
+
`,
|
|
53
|
+
snapshot: `
|
|
54
|
+
if (value != value) {
|
|
55
|
+
~~~~~~~~~~~~~~
|
|
56
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
57
|
+
console.log("always false");
|
|
58
|
+
}
|
|
59
|
+
`,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
code: `
|
|
63
|
+
if (value < value) {
|
|
64
|
+
console.log("always false");
|
|
65
|
+
}
|
|
66
|
+
`,
|
|
67
|
+
snapshot: `
|
|
68
|
+
if (value < value) {
|
|
69
|
+
~~~~~~~~~~~~~
|
|
70
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
71
|
+
console.log("always false");
|
|
72
|
+
}
|
|
73
|
+
`,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
code: `
|
|
77
|
+
if (value <= value) {
|
|
78
|
+
console.log("always true");
|
|
79
|
+
}
|
|
80
|
+
`,
|
|
81
|
+
snapshot: `
|
|
82
|
+
if (value <= value) {
|
|
83
|
+
~~~~~~~~~~~~~~
|
|
84
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
85
|
+
console.log("always true");
|
|
86
|
+
}
|
|
87
|
+
`,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
code: `
|
|
91
|
+
if (value > value) {
|
|
92
|
+
console.log("always false");
|
|
93
|
+
}
|
|
94
|
+
`,
|
|
95
|
+
snapshot: `
|
|
96
|
+
if (value > value) {
|
|
97
|
+
~~~~~~~~~~~~~
|
|
98
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
99
|
+
console.log("always false");
|
|
100
|
+
}
|
|
101
|
+
`,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
code: `
|
|
105
|
+
if (value >= value) {
|
|
106
|
+
console.log("always true");
|
|
107
|
+
}
|
|
108
|
+
`,
|
|
109
|
+
snapshot: `
|
|
110
|
+
if (value >= value) {
|
|
111
|
+
~~~~~~~~~~~~~~
|
|
112
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
113
|
+
console.log("always true");
|
|
114
|
+
}
|
|
115
|
+
`,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
code: `
|
|
119
|
+
const result = object.property === object.property;
|
|
120
|
+
`,
|
|
121
|
+
snapshot: `
|
|
122
|
+
const result = object.property === object.property;
|
|
123
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
124
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
125
|
+
`,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
code: `
|
|
129
|
+
const result = array[0] === array[0];
|
|
130
|
+
`,
|
|
131
|
+
snapshot: `
|
|
132
|
+
const result = array[0] === array[0];
|
|
133
|
+
~~~~~~~~~~~~~~~~~~~~~
|
|
134
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
135
|
+
`,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
code: `
|
|
139
|
+
if (calculate() === calculate()) {
|
|
140
|
+
console.log("functions");
|
|
141
|
+
}
|
|
142
|
+
`,
|
|
143
|
+
snapshot: `
|
|
144
|
+
if (calculate() === calculate()) {
|
|
145
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
146
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
147
|
+
console.log("functions");
|
|
148
|
+
}
|
|
149
|
+
`,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
code: `
|
|
153
|
+
if (value /* comment */ === value) {
|
|
154
|
+
console.log("with comment");
|
|
155
|
+
}
|
|
156
|
+
`,
|
|
157
|
+
snapshot: `
|
|
158
|
+
if (value /* comment */ === value) {
|
|
159
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
160
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
161
|
+
console.log("with comment");
|
|
162
|
+
}
|
|
163
|
+
`,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
code: `
|
|
167
|
+
if (object.property /* comment */ === object.property) {
|
|
168
|
+
console.log("with comment in property access");
|
|
169
|
+
}
|
|
170
|
+
`,
|
|
171
|
+
snapshot: `
|
|
172
|
+
if (object.property /* comment */ === object.property) {
|
|
173
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
174
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
175
|
+
console.log("with comment in property access");
|
|
176
|
+
}
|
|
177
|
+
`,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
code: `
|
|
181
|
+
if (array /* comment */ [0] === array[0]) {
|
|
182
|
+
console.log("with comment in array access");
|
|
183
|
+
}
|
|
184
|
+
`,
|
|
185
|
+
snapshot: `
|
|
186
|
+
if (array /* comment */ [0] === array[0]) {
|
|
187
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
188
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
189
|
+
console.log("with comment in array access");
|
|
190
|
+
}
|
|
191
|
+
`,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
code: `
|
|
195
|
+
if (value === value /* comment */) {
|
|
196
|
+
console.log("comment on right side");
|
|
197
|
+
}
|
|
198
|
+
`,
|
|
199
|
+
snapshot: `
|
|
200
|
+
if (value === value /* comment */) {
|
|
201
|
+
~~~~~~~~~~~~~~~
|
|
202
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
203
|
+
console.log("comment on right side");
|
|
204
|
+
}
|
|
205
|
+
`,
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
code: `
|
|
209
|
+
if (value /* left */ === value /* right */) {
|
|
210
|
+
console.log("comments on both sides");
|
|
211
|
+
}
|
|
212
|
+
`,
|
|
213
|
+
snapshot: `
|
|
214
|
+
if (value /* left */ === value /* right */) {
|
|
215
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
216
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
217
|
+
console.log("comments on both sides");
|
|
218
|
+
}
|
|
219
|
+
`,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
code: `
|
|
223
|
+
if (object.property === object /* comment */ .property) {
|
|
224
|
+
console.log("comment on right property access");
|
|
225
|
+
}
|
|
226
|
+
`,
|
|
227
|
+
snapshot: `
|
|
228
|
+
if (object.property === object /* comment */ .property) {
|
|
229
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
230
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
231
|
+
console.log("comment on right property access");
|
|
232
|
+
}
|
|
233
|
+
`,
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
code: `
|
|
237
|
+
if (array[0] === array /* comment */ [0]) {
|
|
238
|
+
console.log("comment on right array access");
|
|
239
|
+
}
|
|
240
|
+
`,
|
|
241
|
+
snapshot: `
|
|
242
|
+
if (array[0] === array /* comment */ [0]) {
|
|
243
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
244
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
245
|
+
console.log("comment on right array access");
|
|
246
|
+
}
|
|
247
|
+
`,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
code: `
|
|
251
|
+
if (/* before */ value === value /* after */) {
|
|
252
|
+
console.log("comments before and after");
|
|
253
|
+
}
|
|
254
|
+
`,
|
|
255
|
+
snapshot: `
|
|
256
|
+
if (/* before */ value === value /* after */) {
|
|
257
|
+
~~~~~~~~~~~~~~~
|
|
258
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
259
|
+
console.log("comments before and after");
|
|
260
|
+
}
|
|
261
|
+
`,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
code: `
|
|
265
|
+
const result = value /* a */ /* b */ === value /* c */ /* d */;
|
|
266
|
+
`,
|
|
267
|
+
snapshot: `
|
|
268
|
+
const result = value /* a */ /* b */ === value /* c */ /* d */;
|
|
269
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
270
|
+
Comparing a value to itself is unnecessary and likely indicates a logic error.
|
|
271
|
+
`,
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
valid: [
|
|
275
|
+
`if (value1 === value2) { console.log("different values"); }`,
|
|
276
|
+
`if (value === other) { console.log("different values"); }`,
|
|
277
|
+
`if (object.property === object.otherProperty) { console.log("different properties"); }`,
|
|
278
|
+
`if (array[0] === array[1]) { console.log("different elements"); }`,
|
|
279
|
+
`const result = value1 == value2;`,
|
|
280
|
+
`const result = value1 != value2;`,
|
|
281
|
+
`const result = value1 !== value2;`,
|
|
282
|
+
`const result = value1 < value2;`,
|
|
283
|
+
`const result = value1 <= value2;`,
|
|
284
|
+
`const result = value1 > value2;`,
|
|
285
|
+
`const result = value1 >= value2;`,
|
|
286
|
+
`if (Number.isNaN(value)) { console.log("checking for NaN correctly"); }`,
|
|
287
|
+
`if (value1 /* comment */ === value2) { console.log("different with comment on left"); }`,
|
|
288
|
+
`if (value1 === value2 /* comment */) { console.log("different with comment on right"); }`,
|
|
289
|
+
`if (value1 /* left */ === value2 /* right */) { console.log("different with comments on both"); }`,
|
|
290
|
+
`if (object /* comment */ .property === object.otherProperty) { console.log("different properties with comment"); }`,
|
|
291
|
+
`if (object.property === object /* comment */ .otherProperty) { console.log("different properties with comment on right"); }`,
|
|
292
|
+
`if (array /* comment */ [0] === array[1]) { console.log("different elements with comment on left"); }`,
|
|
293
|
+
`if (array[0] === array /* comment */ [1]) { console.log("different elements with comment on right"); }`,
|
|
294
|
+
`if (/* before */ value1 === value2 /* after */) { console.log("different with surrounding comments"); }`,
|
|
295
|
+
`const result = value1 /* a */ /* b */ === value2 /* c */ /* d */;`,
|
|
296
|
+
],
|
|
297
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare const _default: import("@flint.fyi/core").Rule<{
|
|
2
|
+
readonly description: "Reports using the comma operator in expressions.";
|
|
3
|
+
readonly id: "sequences";
|
|
4
|
+
readonly preset: "untyped";
|
|
5
|
+
}, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "noSequences", undefined>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
import { getTSNodeRange } from "../getTSNodeRange.js";
|
|
3
|
+
import { typescriptLanguage } from "../language.js";
|
|
4
|
+
export default typescriptLanguage.createRule({
|
|
5
|
+
about: {
|
|
6
|
+
description: "Reports using the comma operator in expressions.",
|
|
7
|
+
id: "sequences",
|
|
8
|
+
preset: "untyped",
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noSequences: {
|
|
12
|
+
primary: 'The "sequence" (comma) operator is often confusing and a sign of mistaken logic.',
|
|
13
|
+
secondary: [
|
|
14
|
+
"The comma operator can make code harder to read and may hide side effects.",
|
|
15
|
+
"Prefer separate expressions instead of using a single sequence.",
|
|
16
|
+
],
|
|
17
|
+
suggestions: ["Split the expression into separate statements."],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
setup(context) {
|
|
21
|
+
return {
|
|
22
|
+
visitors: {
|
|
23
|
+
BinaryExpression: (node) => {
|
|
24
|
+
if (node.operatorToken.kind === ts.SyntaxKind.CommaToken) {
|
|
25
|
+
context.report({
|
|
26
|
+
message: "noSequences",
|
|
27
|
+
range: getTSNodeRange(node.operatorToken, context.sourceFile),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ruleTester } from "./ruleTester.js";
|
|
2
|
+
import rule from "./sequences.js";
|
|
3
|
+
ruleTester.describe(rule, {
|
|
4
|
+
invalid: [
|
|
5
|
+
{
|
|
6
|
+
code: `
|
|
7
|
+
const a = (1, 2);
|
|
8
|
+
`,
|
|
9
|
+
snapshot: `
|
|
10
|
+
const a = (1, 2);
|
|
11
|
+
~
|
|
12
|
+
The "sequence" (comma) operator is often confusing and a sign of mistaken logic.
|
|
13
|
+
`,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
code: `
|
|
17
|
+
function f() {
|
|
18
|
+
return (g(), h());
|
|
19
|
+
}
|
|
20
|
+
`,
|
|
21
|
+
snapshot: `
|
|
22
|
+
function f() {
|
|
23
|
+
return (g(), h());
|
|
24
|
+
~
|
|
25
|
+
The "sequence" (comma) operator is often confusing and a sign of mistaken logic.
|
|
26
|
+
}
|
|
27
|
+
`,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
code: `
|
|
31
|
+
for ((a = 1, b = 2); ; ) {
|
|
32
|
+
}
|
|
33
|
+
`,
|
|
34
|
+
snapshot: `
|
|
35
|
+
for ((a = 1, b = 2); ; ) {
|
|
36
|
+
~
|
|
37
|
+
The "sequence" (comma) operator is often confusing and a sign of mistaken logic.
|
|
38
|
+
}
|
|
39
|
+
`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
valid: [
|
|
43
|
+
`const a = [1, 2];`,
|
|
44
|
+
`const a = (1 + 2);`,
|
|
45
|
+
`function f() { g(); h(); }`,
|
|
46
|
+
`for (let i = 0; i < 10; i += 1) {}`,
|
|
47
|
+
],
|
|
48
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare const _default: import("@flint.fyi/core").Rule<{
|
|
2
|
+
readonly description: "Reports variable declarations that shadow JavaScript's restricted names.";
|
|
3
|
+
readonly id: "shadowedRestrictedNames";
|
|
4
|
+
readonly preset: "untyped";
|
|
5
|
+
}, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "shadowedRestrictedName", undefined>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as ts from "typescript";
|
|
2
|
+
import { getTSNodeRange } from "../getTSNodeRange.js";
|
|
3
|
+
import { typescriptLanguage } from "../language.js";
|
|
4
|
+
const restrictedNames = new Set([
|
|
5
|
+
"arguments",
|
|
6
|
+
"eval",
|
|
7
|
+
"Infinity",
|
|
8
|
+
"NaN",
|
|
9
|
+
"undefined",
|
|
10
|
+
]);
|
|
11
|
+
export default typescriptLanguage.createRule({
|
|
12
|
+
about: {
|
|
13
|
+
description: "Reports variable declarations that shadow JavaScript's restricted names.",
|
|
14
|
+
id: "shadowedRestrictedNames",
|
|
15
|
+
preset: "untyped",
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
shadowedRestrictedName: {
|
|
19
|
+
primary: "This variable misleadingly shadows the global `{{ name }}`.",
|
|
20
|
+
secondary: [
|
|
21
|
+
"JavaScript has certain built-in global identifiers that are considered restricted because shadowing them can lead to confusing or erroneous code.",
|
|
22
|
+
"When you declare a variable with a restricted name, it shadows the global identifier and can cause unexpected behavior.",
|
|
23
|
+
],
|
|
24
|
+
suggestions: [
|
|
25
|
+
"Use a different variable name that doesn't shadow a restricted name.",
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
setup(context) {
|
|
30
|
+
function checkIdentifier(node) {
|
|
31
|
+
if (restrictedNames.has(node.text)) {
|
|
32
|
+
context.report({
|
|
33
|
+
data: {
|
|
34
|
+
name: node.text,
|
|
35
|
+
},
|
|
36
|
+
message: "shadowedRestrictedName",
|
|
37
|
+
range: getTSNodeRange(node, context.sourceFile),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function checkBindingName(name) {
|
|
42
|
+
if (ts.isIdentifier(name)) {
|
|
43
|
+
checkIdentifier(name);
|
|
44
|
+
}
|
|
45
|
+
else if (ts.isObjectBindingPattern(name) ||
|
|
46
|
+
ts.isArrayBindingPattern(name)) {
|
|
47
|
+
for (const element of name.elements) {
|
|
48
|
+
if (ts.isBindingElement(element)) {
|
|
49
|
+
checkBindingName(element.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function checkParameters(parameters) {
|
|
55
|
+
for (const parameter of parameters) {
|
|
56
|
+
checkBindingName(parameter.name);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
visitors: {
|
|
61
|
+
ArrowFunction: (node) => {
|
|
62
|
+
checkParameters(node.parameters);
|
|
63
|
+
},
|
|
64
|
+
ClassDeclaration: (node) => {
|
|
65
|
+
if (node.name) {
|
|
66
|
+
checkIdentifier(node.name);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
ClassExpression: (node) => {
|
|
70
|
+
if (node.name) {
|
|
71
|
+
checkIdentifier(node.name);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
FunctionDeclaration: (node) => {
|
|
75
|
+
if (node.name) {
|
|
76
|
+
checkIdentifier(node.name);
|
|
77
|
+
}
|
|
78
|
+
checkParameters(node.parameters);
|
|
79
|
+
},
|
|
80
|
+
FunctionExpression: (node) => {
|
|
81
|
+
if (node.name) {
|
|
82
|
+
checkIdentifier(node.name);
|
|
83
|
+
}
|
|
84
|
+
checkParameters(node.parameters);
|
|
85
|
+
},
|
|
86
|
+
MethodDeclaration: (node) => {
|
|
87
|
+
checkParameters(node.parameters);
|
|
88
|
+
},
|
|
89
|
+
VariableDeclaration: (node) => {
|
|
90
|
+
checkBindingName(node.name);
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ruleTester } from "./ruleTester.js";
|
|
2
|
+
import rule from "./shadowedRestrictedNames.js";
|
|
3
|
+
ruleTester.describe(rule, {
|
|
4
|
+
invalid: [
|
|
5
|
+
{
|
|
6
|
+
code: `
|
|
7
|
+
let undefined = 5;
|
|
8
|
+
`,
|
|
9
|
+
snapshot: `
|
|
10
|
+
let undefined = 5;
|
|
11
|
+
~~~~~~~~~
|
|
12
|
+
This variable misleadingly shadows the global \`undefined\`.
|
|
13
|
+
`,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
code: `
|
|
17
|
+
const NaN = 123;
|
|
18
|
+
`,
|
|
19
|
+
snapshot: `
|
|
20
|
+
const NaN = 123;
|
|
21
|
+
~~~
|
|
22
|
+
This variable misleadingly shadows the global \`NaN\`.
|
|
23
|
+
`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
code: `
|
|
27
|
+
var Infinity = 100;
|
|
28
|
+
`,
|
|
29
|
+
snapshot: `
|
|
30
|
+
var Infinity = 100;
|
|
31
|
+
~~~~~~~~
|
|
32
|
+
This variable misleadingly shadows the global \`Infinity\`.
|
|
33
|
+
`,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
code: `
|
|
37
|
+
function test(arguments) {
|
|
38
|
+
return arguments.length;
|
|
39
|
+
}
|
|
40
|
+
`,
|
|
41
|
+
snapshot: `
|
|
42
|
+
function test(arguments) {
|
|
43
|
+
~~~~~~~~~
|
|
44
|
+
This variable misleadingly shadows the global \`arguments\`.
|
|
45
|
+
return arguments.length;
|
|
46
|
+
}
|
|
47
|
+
`,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
code: `
|
|
51
|
+
function eval() {
|
|
52
|
+
return 42;
|
|
53
|
+
}
|
|
54
|
+
`,
|
|
55
|
+
snapshot: `
|
|
56
|
+
function eval() {
|
|
57
|
+
~~~~
|
|
58
|
+
This variable misleadingly shadows the global \`eval\`.
|
|
59
|
+
return 42;
|
|
60
|
+
}
|
|
61
|
+
`,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
code: `
|
|
65
|
+
const arrowFunc = (undefined) => undefined;
|
|
66
|
+
`,
|
|
67
|
+
snapshot: `
|
|
68
|
+
const arrowFunc = (undefined) => undefined;
|
|
69
|
+
~~~~~~~~~
|
|
70
|
+
This variable misleadingly shadows the global \`undefined\`.
|
|
71
|
+
`,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
code: `
|
|
75
|
+
class NaN {
|
|
76
|
+
constructor() {}
|
|
77
|
+
}
|
|
78
|
+
`,
|
|
79
|
+
snapshot: `
|
|
80
|
+
class NaN {
|
|
81
|
+
~~~
|
|
82
|
+
This variable misleadingly shadows the global \`NaN\`.
|
|
83
|
+
constructor() {}
|
|
84
|
+
}
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
code: `
|
|
89
|
+
const obj = {
|
|
90
|
+
method(eval) {
|
|
91
|
+
return eval;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
`,
|
|
95
|
+
snapshot: `
|
|
96
|
+
const obj = {
|
|
97
|
+
method(eval) {
|
|
98
|
+
~~~~
|
|
99
|
+
This variable misleadingly shadows the global \`eval\`.
|
|
100
|
+
return eval;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
`,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
code: `
|
|
107
|
+
function test() {
|
|
108
|
+
const { undefined } = obj;
|
|
109
|
+
}
|
|
110
|
+
`,
|
|
111
|
+
snapshot: `
|
|
112
|
+
function test() {
|
|
113
|
+
const { undefined } = obj;
|
|
114
|
+
~~~~~~~~~
|
|
115
|
+
This variable misleadingly shadows the global \`undefined\`.
|
|
116
|
+
}
|
|
117
|
+
`,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
code: `
|
|
121
|
+
function test() {
|
|
122
|
+
const [NaN] = array;
|
|
123
|
+
}
|
|
124
|
+
`,
|
|
125
|
+
snapshot: `
|
|
126
|
+
function test() {
|
|
127
|
+
const [NaN] = array;
|
|
128
|
+
~~~
|
|
129
|
+
This variable misleadingly shadows the global \`NaN\`.
|
|
130
|
+
}
|
|
131
|
+
`,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
valid: [
|
|
135
|
+
`let value = undefined;`,
|
|
136
|
+
`const result = NaN;`,
|
|
137
|
+
`const max = Infinity;`,
|
|
138
|
+
`function test() { return arguments; }`,
|
|
139
|
+
`const code = eval("1 + 1");`,
|
|
140
|
+
`let myValue = 5;`,
|
|
141
|
+
`function myFunction() {}`,
|
|
142
|
+
`class MyClass {}`,
|
|
143
|
+
`const obj = { undefined: 5 };`,
|
|
144
|
+
`const key = "undefined";`,
|
|
145
|
+
`obj.undefined = 5;`,
|
|
146
|
+
],
|
|
147
|
+
});
|
|
@@ -43,8 +43,8 @@ function createSymbol() {
|
|
|
43
43
|
snapshot: `
|
|
44
44
|
function createSymbol() {
|
|
45
45
|
return Symbol();
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
~~~~~~~~
|
|
47
|
+
Symbols without descriptions are more difficult to debug or reason about.
|
|
48
48
|
}
|
|
49
49
|
`,
|
|
50
50
|
},
|
|
@@ -57,8 +57,8 @@ const obj = {
|
|
|
57
57
|
snapshot: `
|
|
58
58
|
const obj = {
|
|
59
59
|
key: Symbol(),
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
~~~~~~~~
|
|
61
|
+
Symbols without descriptions are more difficult to debug or reason about.
|
|
62
62
|
};
|
|
63
63
|
`,
|
|
64
64
|
},
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare const _default: import("@flint.fyi/core").Rule<{
|
|
2
|
+
readonly description: "Reports typeof expressions that compare impossible string literals.";
|
|
3
|
+
readonly id: "typeofComparisons";
|
|
4
|
+
readonly preset: "untyped";
|
|
5
|
+
}, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "invalidValue", undefined>;
|
|
6
|
+
export default _default;
|