eslint-plugin-ts-data-forge 0.10.6 → 0.10.7
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/README.md +3 -3
- package/dist/plugin.d.mts +2 -2
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +1 -0
- package/dist/plugin.mjs.map +1 -1
- package/dist/rule-types.d.mts +5 -5
- package/dist/rules/ast-utils.d.mts +3 -4
- package/dist/rules/ast-utils.d.mts.map +1 -1
- package/dist/rules/ast-utils.mjs +0 -1
- package/dist/rules/ast-utils.mjs.map +1 -1
- package/dist/rules/import-binding.d.mts +6 -6
- package/dist/rules/no-unnecessary-type-guard.mjs.map +1 -1
- package/dist/rules/prefer-arr-generate.d.mts +2 -2
- package/dist/rules/prefer-arr-generate.d.mts.map +1 -1
- package/dist/rules/prefer-arr-generate.mjs +17 -5
- package/dist/rules/prefer-arr-generate.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-fixed-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-max-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-scan.mjs.map +1 -1
- package/dist/rules/prefer-arr-sum.mjs.map +1 -1
- package/dist/rules/prefer-arr-uniq.mjs.map +1 -1
- package/dist/rules/prefer-canonical-array-slicing.d.mts.map +1 -1
- package/dist/rules/prefer-canonical-array-slicing.mjs +0 -1
- package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -1
- package/dist/rules/prefer-num-safe-parse-float.d.mts +1 -1
- package/dist/rules/prefer-num-safe-parse-float.d.mts.map +1 -1
- package/dist/rules/prefer-num-safe-parse-int.d.mts +1 -1
- package/dist/rules/prefer-num-safe-parse-int.d.mts.map +1 -1
- package/dist/rules/prefer-pipe-map-nullable.d.mts +2 -2
- package/dist/rules/prefer-pipe-map-nullable.mjs.map +1 -1
- package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
- package/dist/rules/rules.d.mts +2 -2
- package/package.json +6 -6
- package/src/plugin.mts +4 -3
- package/src/rule-types.mts +5 -5
- package/src/rules/ast-utils.mts +3 -4
- package/src/rules/import-binding.mts +6 -6
- package/src/rules/no-unnecessary-type-guard.mts +4 -4
- package/src/rules/prefer-arr-generate.mts +45 -27
- package/src/rules/prefer-arr-generate.test.mts +229 -0
- package/src/rules/prefer-arr-is-fixed-length-array.mts +2 -2
- package/src/rules/prefer-arr-is-max-length-array.mts +2 -2
- package/src/rules/prefer-arr-is-min-length-array.mts +2 -2
- package/src/rules/prefer-arr-scan.mts +8 -8
- package/src/rules/prefer-arr-sum.mts +3 -3
- package/src/rules/prefer-arr-uniq.mts +2 -2
- package/src/rules/prefer-canonical-array-slicing.mts +17 -18
- package/src/rules/prefer-canonical-length-cast.mts +11 -11
- package/src/rules/prefer-canonical-length-guard.mts +2 -2
- package/src/rules/prefer-num-safe-parse-float.test.mts +255 -94
- package/src/rules/prefer-num-safe-parse-int.test.mts +212 -76
- package/src/rules/prefer-pipe-map-nullable.mts +11 -11
- package/src/rules/prefer-range-for-loop.mts +6 -6
- package/src/rules/prefer-range-for-loop.test.mts +2 -2
|
@@ -28,7 +28,7 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
28
28
|
`,
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
|
-
name: 'ignores number arguments (
|
|
31
|
+
name: 'ignores number arguments (the rewrite would be unsafe)',
|
|
32
32
|
code: dedent`
|
|
33
33
|
const x = 42;
|
|
34
34
|
const n = parseInt(x, 10);
|
|
@@ -50,18 +50,76 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
50
50
|
},
|
|
51
51
|
],
|
|
52
52
|
invalid: [
|
|
53
|
+
{
|
|
54
|
+
name: 'offers no suggestion when `Result` is bound to another module',
|
|
55
|
+
code: dedent`
|
|
56
|
+
import { Result } from 'other-lib';
|
|
57
|
+
|
|
58
|
+
declare const s: string;
|
|
59
|
+
const n = parseInt(s);
|
|
60
|
+
export const r = Result;
|
|
61
|
+
`,
|
|
62
|
+
errors: [{ messageId: 'useSafeParseInt', suggestions: [] }],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
// The replacement reads these strings differently ('1e3' is 1000, not
|
|
66
|
+
// 1; '12px' is NaN, not 12), so it is offered, never applied by
|
|
67
|
+
// --fix
|
|
68
|
+
name: 'a string the replacement parses differently is a suggestion, not a fix',
|
|
69
|
+
code: dedent`
|
|
70
|
+
const a = parseInt('1e3');
|
|
71
|
+
const b = parseInt('12px', 10);
|
|
72
|
+
`,
|
|
73
|
+
errors: [
|
|
74
|
+
{
|
|
75
|
+
messageId: 'useSafeParseInt',
|
|
76
|
+
suggestions: [
|
|
77
|
+
{
|
|
78
|
+
messageId: 'replaceWithSafeParse',
|
|
79
|
+
output: dedent`
|
|
80
|
+
import { Num, Result } from 'ts-data-forge';
|
|
81
|
+
const a = Result.unwrapOkOr(Num.safeParseInt('1e3'), Number.NaN);
|
|
82
|
+
const b = parseInt('12px', 10);
|
|
83
|
+
`,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
messageId: 'useSafeParseInt',
|
|
89
|
+
suggestions: [
|
|
90
|
+
{
|
|
91
|
+
messageId: 'replaceWithSafeParse',
|
|
92
|
+
output: dedent`
|
|
93
|
+
import { Num, Result } from 'ts-data-forge';
|
|
94
|
+
const a = parseInt('1e3');
|
|
95
|
+
const b = Result.unwrapOkOr(Num.safeParseInt('12px'), Number.NaN);
|
|
96
|
+
`,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
53
102
|
{
|
|
54
103
|
name: 'replaces parseInt(s, 10) and imports Num + Result',
|
|
55
104
|
code: dedent`
|
|
56
105
|
const s = "123";
|
|
57
106
|
const n = parseInt(s, 10);
|
|
58
107
|
`,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
108
|
+
errors: [
|
|
109
|
+
{
|
|
110
|
+
messageId: 'useSafeParseInt',
|
|
111
|
+
suggestions: [
|
|
112
|
+
{
|
|
113
|
+
messageId: 'replaceWithSafeParse',
|
|
114
|
+
output: dedent`
|
|
115
|
+
import { Num, Result } from 'ts-data-forge';
|
|
116
|
+
const s = "123";
|
|
117
|
+
const n = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
118
|
+
`,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
],
|
|
65
123
|
},
|
|
66
124
|
{
|
|
67
125
|
name: 'replaces parseInt(s) without radix',
|
|
@@ -69,12 +127,21 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
69
127
|
const s = "123";
|
|
70
128
|
const n = parseInt(s);
|
|
71
129
|
`,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
130
|
+
errors: [
|
|
131
|
+
{
|
|
132
|
+
messageId: 'useSafeParseInt',
|
|
133
|
+
suggestions: [
|
|
134
|
+
{
|
|
135
|
+
messageId: 'replaceWithSafeParse',
|
|
136
|
+
output: dedent`
|
|
137
|
+
import { Num, Result } from 'ts-data-forge';
|
|
138
|
+
const s = "123";
|
|
139
|
+
const n = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
140
|
+
`,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
78
145
|
},
|
|
79
146
|
{
|
|
80
147
|
name: 'replaces Number.parseInt(s, 10)',
|
|
@@ -82,12 +149,21 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
82
149
|
const s = "123";
|
|
83
150
|
const n = Number.parseInt(s, 10);
|
|
84
151
|
`,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
152
|
+
errors: [
|
|
153
|
+
{
|
|
154
|
+
messageId: 'useSafeParseInt',
|
|
155
|
+
suggestions: [
|
|
156
|
+
{
|
|
157
|
+
messageId: 'replaceWithSafeParse',
|
|
158
|
+
output: dedent`
|
|
159
|
+
import { Num, Result } from 'ts-data-forge';
|
|
160
|
+
const s = "123";
|
|
161
|
+
const n = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
162
|
+
`,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
91
167
|
},
|
|
92
168
|
{
|
|
93
169
|
name: 'adds only the missing Result import when Num is present',
|
|
@@ -97,13 +173,22 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
97
173
|
const s = "123";
|
|
98
174
|
const n = parseInt(s, 10);
|
|
99
175
|
`,
|
|
100
|
-
|
|
101
|
-
|
|
176
|
+
errors: [
|
|
177
|
+
{
|
|
178
|
+
messageId: 'useSafeParseInt',
|
|
179
|
+
suggestions: [
|
|
180
|
+
{
|
|
181
|
+
messageId: 'replaceWithSafeParse',
|
|
182
|
+
output: dedent`
|
|
183
|
+
import { Num, Result } from 'ts-data-forge';
|
|
102
184
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
185
|
+
const s = "123";
|
|
186
|
+
const n = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
187
|
+
`,
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
],
|
|
107
192
|
},
|
|
108
193
|
{
|
|
109
194
|
name: 'wraps in parentheses in an operator context',
|
|
@@ -111,12 +196,21 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
111
196
|
const s = "123";
|
|
112
197
|
const ok = parseInt(s, 10) > 5;
|
|
113
198
|
`,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
199
|
+
errors: [
|
|
200
|
+
{
|
|
201
|
+
messageId: 'useSafeParseInt',
|
|
202
|
+
suggestions: [
|
|
203
|
+
{
|
|
204
|
+
messageId: 'replaceWithSafeParse',
|
|
205
|
+
output: dedent`
|
|
206
|
+
import { Num, Result } from 'ts-data-forge';
|
|
207
|
+
const s = "123";
|
|
208
|
+
const ok = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN) > 5;
|
|
209
|
+
`,
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
],
|
|
120
214
|
},
|
|
121
215
|
{
|
|
122
216
|
name: 'preserves a complex string argument expression',
|
|
@@ -124,12 +218,21 @@ describe('prefer-num-safe-parse-int', () => {
|
|
|
124
218
|
const get = (k: string): string => k;
|
|
125
219
|
const n = parseInt(get("x").trim(), 10);
|
|
126
220
|
`,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
221
|
+
errors: [
|
|
222
|
+
{
|
|
223
|
+
messageId: 'useSafeParseInt',
|
|
224
|
+
suggestions: [
|
|
225
|
+
{
|
|
226
|
+
messageId: 'replaceWithSafeParse',
|
|
227
|
+
output: dedent`
|
|
228
|
+
import { Num, Result } from 'ts-data-forge';
|
|
229
|
+
const get = (k: string): string => k;
|
|
230
|
+
const n = Result.unwrapOkOr(Num.safeParseInt(get("x").trim()), Number.NaN);
|
|
231
|
+
`,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
},
|
|
235
|
+
],
|
|
133
236
|
},
|
|
134
237
|
],
|
|
135
238
|
});
|
|
@@ -161,23 +264,35 @@ describe('prefer-num-safe-parse-int through type wrappers', () => {
|
|
|
161
264
|
const a = parseInt(s, 10 as const);
|
|
162
265
|
const b = Number.parseInt(s!, 10 satisfies number);
|
|
163
266
|
`,
|
|
164
|
-
output: [
|
|
165
|
-
dedent`
|
|
166
|
-
import { Num, Result } from 'ts-data-forge';
|
|
167
|
-
declare const s: string;
|
|
168
|
-
const a = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
169
|
-
const b = Number.parseInt(s!, 10 satisfies number);
|
|
170
|
-
`,
|
|
171
|
-
dedent`
|
|
172
|
-
import { Num, Result } from 'ts-data-forge';
|
|
173
|
-
declare const s: string;
|
|
174
|
-
const a = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
175
|
-
const b = Result.unwrapOkOr(Num.safeParseInt(s!), Number.NaN);
|
|
176
|
-
`,
|
|
177
|
-
],
|
|
178
267
|
errors: [
|
|
179
|
-
{
|
|
180
|
-
|
|
268
|
+
{
|
|
269
|
+
messageId: 'useSafeParseInt',
|
|
270
|
+
suggestions: [
|
|
271
|
+
{
|
|
272
|
+
messageId: 'replaceWithSafeParse',
|
|
273
|
+
output: dedent`
|
|
274
|
+
import { Num, Result } from 'ts-data-forge';
|
|
275
|
+
declare const s: string;
|
|
276
|
+
const a = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
277
|
+
const b = Number.parseInt(s!, 10 satisfies number);
|
|
278
|
+
`,
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
messageId: 'useSafeParseInt',
|
|
284
|
+
suggestions: [
|
|
285
|
+
{
|
|
286
|
+
messageId: 'replaceWithSafeParse',
|
|
287
|
+
output: dedent`
|
|
288
|
+
import { Num, Result } from 'ts-data-forge';
|
|
289
|
+
declare const s: string;
|
|
290
|
+
const a = parseInt(s, 10 as const);
|
|
291
|
+
const b = Result.unwrapOkOr(Num.safeParseInt(s!), Number.NaN);
|
|
292
|
+
`,
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
},
|
|
181
296
|
],
|
|
182
297
|
},
|
|
183
298
|
{
|
|
@@ -187,23 +302,35 @@ describe('prefer-num-safe-parse-int through type wrappers', () => {
|
|
|
187
302
|
const a = (parseInt as typeof parseInt)(s);
|
|
188
303
|
const b = (Number as NumberConstructor)!.parseInt(s, 10);
|
|
189
304
|
`,
|
|
190
|
-
output: [
|
|
191
|
-
dedent`
|
|
192
|
-
import { Num, Result } from 'ts-data-forge';
|
|
193
|
-
declare const s: string;
|
|
194
|
-
const a = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
195
|
-
const b = (Number as NumberConstructor)!.parseInt(s, 10);
|
|
196
|
-
`,
|
|
197
|
-
dedent`
|
|
198
|
-
import { Num, Result } from 'ts-data-forge';
|
|
199
|
-
declare const s: string;
|
|
200
|
-
const a = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
201
|
-
const b = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
202
|
-
`,
|
|
203
|
-
],
|
|
204
305
|
errors: [
|
|
205
|
-
{
|
|
206
|
-
|
|
306
|
+
{
|
|
307
|
+
messageId: 'useSafeParseInt',
|
|
308
|
+
suggestions: [
|
|
309
|
+
{
|
|
310
|
+
messageId: 'replaceWithSafeParse',
|
|
311
|
+
output: dedent`
|
|
312
|
+
import { Num, Result } from 'ts-data-forge';
|
|
313
|
+
declare const s: string;
|
|
314
|
+
const a = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
315
|
+
const b = (Number as NumberConstructor)!.parseInt(s, 10);
|
|
316
|
+
`,
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
messageId: 'useSafeParseInt',
|
|
322
|
+
suggestions: [
|
|
323
|
+
{
|
|
324
|
+
messageId: 'replaceWithSafeParse',
|
|
325
|
+
output: dedent`
|
|
326
|
+
import { Num, Result } from 'ts-data-forge';
|
|
327
|
+
declare const s: string;
|
|
328
|
+
const a = (parseInt as typeof parseInt)(s);
|
|
329
|
+
const b = Result.unwrapOkOr(Num.safeParseInt(s), Number.NaN);
|
|
330
|
+
`,
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
},
|
|
207
334
|
],
|
|
208
335
|
},
|
|
209
336
|
],
|
|
@@ -221,13 +348,22 @@ describe('prefer-num-safe-parse-int with parenthesized operands', () => {
|
|
|
221
348
|
declare const log: () => void;
|
|
222
349
|
const a = parseInt((log(), s), 10);
|
|
223
350
|
`,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
351
|
+
errors: [
|
|
352
|
+
{
|
|
353
|
+
messageId: 'useSafeParseInt',
|
|
354
|
+
suggestions: [
|
|
355
|
+
{
|
|
356
|
+
messageId: 'replaceWithSafeParse',
|
|
357
|
+
output: dedent`
|
|
358
|
+
import { Num, Result } from 'ts-data-forge';
|
|
359
|
+
declare const s: string;
|
|
360
|
+
declare const log: () => void;
|
|
361
|
+
const a = Result.unwrapOkOr(Num.safeParseInt((log(), s)), Number.NaN);
|
|
362
|
+
`,
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
},
|
|
366
|
+
],
|
|
231
367
|
},
|
|
232
368
|
],
|
|
233
369
|
});
|
|
@@ -34,8 +34,8 @@ type MessageIds = 'useMapNullable' | 'suggestMapNullable';
|
|
|
34
34
|
* first infers `'a'` and the second `string`, and `(v) => [v, 1]` becomes
|
|
35
35
|
* `number[]` instead of `readonly [number, 1]`. The fix is therefore applied
|
|
36
36
|
* automatically only when the function's return type is not inferred, or is
|
|
37
|
-
* inferred with nothing such a widening could change; otherwise, and whenever
|
|
38
|
-
*
|
|
37
|
+
* inferred with nothing such a widening could change; otherwise, and whenever a
|
|
38
|
+
* comment or a type wrapper around `mapNullable` would be dropped, it is
|
|
39
39
|
* offered as a suggestion.
|
|
40
40
|
*/
|
|
41
41
|
export const preferPipeMapNullable: TSESLint.RuleModule<MessageIds, Options> = {
|
|
@@ -81,8 +81,8 @@ export const preferPipeMapNullable: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
81
81
|
const esTreeNodeToTSNodeMap = services?.esTreeNodeToTSNodeMap;
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* Whether `callee` calls the export `name` of the module `resolve`
|
|
85
|
-
*
|
|
84
|
+
* Whether `callee` calls the export `name` of the module `resolve` reads,
|
|
85
|
+
* rather than a local binding that shadows the import.
|
|
86
86
|
*/
|
|
87
87
|
const calls = (
|
|
88
88
|
resolve: ReturnType<typeof buildCalleeResolver>,
|
|
@@ -170,9 +170,9 @@ export const preferPipeMapNullable: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
// The `B | undefined` that `mapNullable(fn)` returns, with `B` as the
|
|
173
|
-
// `const` type parameter inferred it. The function's own return type
|
|
174
|
-
//
|
|
175
|
-
//
|
|
173
|
+
// `const` type parameter inferred it. The function's own return type is
|
|
174
|
+
// no guide: for `(v) => ({ kind: 'n', v })` it is already widened to
|
|
175
|
+
// `{ kind: string; v: number }`, while `B` keeps `'n'`.
|
|
176
176
|
const signatures = checker
|
|
177
177
|
.getTypeAtLocation(esTreeNodeToTSNodeMap.get(mapNullableCall))
|
|
178
178
|
.getCallSignatures();
|
|
@@ -313,11 +313,11 @@ const MAX_DEPTH = 4;
|
|
|
313
313
|
|
|
314
314
|
/**
|
|
315
315
|
* Whether `type`, inferred for a `const` type parameter, has a part a plain
|
|
316
|
-
* type parameter would infer differently: a literal (`'a'` against `string`)
|
|
317
|
-
*
|
|
316
|
+
* type parameter would infer differently: a literal (`'a'` against `string`) or
|
|
317
|
+
* a tuple (`readonly [number, 1]` against `number[]`), at the top level or
|
|
318
318
|
* inside an array, a generic type's arguments or an object literal's
|
|
319
|
-
* properties. Conservative: a declared literal type, which neither widens,
|
|
320
|
-
*
|
|
319
|
+
* properties. Conservative: a declared literal type, which neither widens, also
|
|
320
|
+
* counts.
|
|
321
321
|
*/
|
|
322
322
|
const hasConstInferredPart = (
|
|
323
323
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -33,8 +33,8 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Whether `node` is the same value on every iteration: a literal, or a
|
|
36
|
-
* variable that is never reassigned anywhere (not only in the loop, since
|
|
37
|
-
*
|
|
36
|
+
* variable that is never reassigned anywhere (not only in the loop, since a
|
|
37
|
+
* function the loop calls could reassign it). The loop reads its end and
|
|
38
38
|
* its step on every iteration, and `range` reads them once.
|
|
39
39
|
*/
|
|
40
40
|
const isStableBound = (
|
|
@@ -103,8 +103,8 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// Check test: i < end. The loop variable and the step are read
|
|
107
|
-
//
|
|
106
|
+
// Check test: i < end. The loop variable and the step are read through
|
|
107
|
+
// type wrappers: `(i satisfies number) < n` tests `i`, and
|
|
108
108
|
// `i += 0 as number` still steps by 0.
|
|
109
109
|
if (
|
|
110
110
|
node.test?.type !== AST_NODE_TYPES.BinaryExpression ||
|
|
@@ -166,8 +166,8 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
166
166
|
}
|
|
167
167
|
} else if (isNegatedLiteral(stepValue)) {
|
|
168
168
|
// `i += -1` under `i < end` never gets there, and `range` with a
|
|
169
|
-
// negative step yields nothing: no fix that type-checks would
|
|
170
|
-
//
|
|
169
|
+
// negative step yields nothing: no fix that type-checks would keep
|
|
170
|
+
// that.
|
|
171
171
|
return;
|
|
172
172
|
} else {
|
|
173
173
|
// Variable step like i += step. Its type is left to the type
|
|
@@ -309,8 +309,8 @@ describe('prefer-range-for-loop where the rewrite would change behavior', () =>
|
|
|
309
309
|
errors: [{ messageId: 'useRangeForLoop' }],
|
|
310
310
|
},
|
|
311
311
|
{
|
|
312
|
-
// The type checker judges it: a `number` step makes the fixed call
|
|
313
|
-
//
|
|
312
|
+
// The type checker judges it: a `number` step makes the fixed call fail
|
|
313
|
+
// to type-check.
|
|
314
314
|
name: 'a variable step is fixed without asking its type',
|
|
315
315
|
code: dedent`
|
|
316
316
|
declare const n: number;
|