eslint-plugin-ts-data-forge 0.2.0 → 0.3.0
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 +16 -14
- package/dist/plugin.d.mts +2 -0
- 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 +16 -1
- package/dist/rule-types.d.mts.map +1 -1
- package/dist/rules/import-utils.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-bounded-length-array.mjs +1 -1
- package/dist/rules/prefer-arr-is-bounded-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-fixed-length-array.mjs +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 +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 +1 -1
- package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-sum.mjs +2 -2
- package/dist/rules/prefer-arr-sum.mjs.map +1 -1
- package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-cast.d.mts +6 -0
- package/dist/rules/prefer-canonical-length-cast.d.mts.map +1 -0
- package/dist/rules/prefer-canonical-length-cast.mjs +155 -0
- package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -0
- package/dist/rules/prefer-canonical-length-guard.d.mts.map +1 -1
- package/dist/rules/prefer-canonical-length-guard.mjs +12 -8
- package/dist/rules/prefer-canonical-length-guard.mjs.map +1 -1
- package/dist/rules/prefer-range-for-loop.mjs +1 -1
- package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
- package/dist/rules/rules.d.mts +1 -0
- package/dist/rules/rules.d.mts.map +1 -1
- package/dist/rules/rules.mjs +2 -0
- package/dist/rules/rules.mjs.map +1 -1
- package/package.json +3 -3
- package/src/plugin.mts +1 -0
- package/src/rule-types.mts +17 -1
- package/src/rules/import-utils.mts +0 -1
- package/src/rules/prefer-arr-is-bounded-length-array.mts +1 -1
- package/src/rules/prefer-arr-is-bounded-length-array.test.mts +5 -5
- package/src/rules/prefer-arr-is-fixed-length-array.mts +1 -1
- package/src/rules/prefer-arr-is-fixed-length-array.test.mts +11 -11
- package/src/rules/prefer-arr-is-max-length-array.mts +1 -1
- package/src/rules/prefer-arr-is-max-length-array.test.mts +8 -8
- package/src/rules/prefer-arr-is-min-length-array.mts +1 -1
- package/src/rules/prefer-arr-is-min-length-array.test.mts +9 -9
- package/src/rules/prefer-arr-sum.mts +2 -2
- package/src/rules/prefer-canonical-array-slicing.mts +0 -2
- package/src/rules/prefer-canonical-length-cast.mts +290 -0
- package/src/rules/prefer-canonical-length-cast.test.mts +305 -0
- package/src/rules/prefer-canonical-length-guard.mts +40 -21
- package/src/rules/prefer-canonical-length-guard.test.mts +32 -32
- package/src/rules/prefer-range-for-loop.mts +1 -1
- package/src/rules/rules.mts +2 -0
|
@@ -52,28 +52,44 @@ const MESSAGES = {
|
|
|
52
52
|
} as const satisfies Record<MessageIds, string>;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Length guards whose bound makes them redundant with
|
|
56
|
-
*
|
|
55
|
+
* Length guards whose bound makes them redundant with a named degenerate
|
|
56
|
+
* guard, keyed by guard name.
|
|
57
57
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
58
|
+
* Every entry stays inside its own family rather than crossing the
|
|
59
|
+
* branded/structural divide:
|
|
60
60
|
*
|
|
61
|
-
* -
|
|
62
|
-
*
|
|
63
|
-
* -
|
|
64
|
-
* `readonly []` / `
|
|
65
|
-
*
|
|
66
|
-
*
|
|
61
|
+
* - the branded `*Array` guards go to `isEmpty` / `isNonEmpty`, which narrow to
|
|
62
|
+
* `FixedLengthArray<0, E> & Xs` / `MinLengthArray<1, E> & Xs`;
|
|
63
|
+
* - the structural `*Tuple` guards go to `isEmptyTuple` / `isNonEmptyTuple`,
|
|
64
|
+
* which narrow to `readonly []` / `MinLengthTuple<1, E>`.
|
|
65
|
+
*
|
|
66
|
+
* Most entries are then **type-identical** — `isFixedLengthArray(0, xs)` and
|
|
67
|
+
* `isMinLengthArray(1, xs)` produce exactly what `isEmpty` / `isNonEmpty`
|
|
68
|
+
* narrow to, and `FixedLengthTuple<0, E>`, `MaxLengthTuple<0, E>` and
|
|
69
|
+
* `BoundedLengthTuple<0, 0, E>` are all `readonly []`. Two *strengthen*:
|
|
70
|
+
* `MaxLengthArray<0, E>` and `BoundedLengthArray<0, 0, E>` do not include the
|
|
71
|
+
* `readonly []` structural part that `FixedLengthArray<0, E>` intersects on, so
|
|
72
|
+
* rewriting them to `isEmpty` adds it. That is sound for a guard — the narrowed
|
|
73
|
+
* type only flows outwards, and the stronger type is assignable everywhere the
|
|
74
|
+
* old one was — and it stays within the branded family.
|
|
75
|
+
*
|
|
76
|
+
* Sending a `*Tuple` guard to the branded `isEmpty` would also be sound, but it
|
|
77
|
+
* would silently change which family the value belongs to, which is why each
|
|
78
|
+
* family keeps its own lane.
|
|
67
79
|
*/
|
|
68
80
|
const GUARD_REWRITES = [
|
|
69
81
|
{ guard: 'isFixedLengthArray', bounds: [0], replacement: 'isEmpty' },
|
|
70
|
-
{ guard: 'isFixedLengthTuple', bounds: [0], replacement: 'isEmpty' },
|
|
71
|
-
{ guard: 'isMaxLengthTuple', bounds: [0], replacement: 'isEmpty' },
|
|
72
82
|
{ guard: 'isMaxLengthArray', bounds: [0], replacement: 'isEmpty' },
|
|
73
|
-
{ guard: 'isBoundedLengthTuple', bounds: [0, 0], replacement: 'isEmpty' },
|
|
74
83
|
{ guard: 'isBoundedLengthArray', bounds: [0, 0], replacement: 'isEmpty' },
|
|
75
84
|
{ guard: 'isMinLengthArray', bounds: [1], replacement: 'isNonEmpty' },
|
|
76
|
-
{ guard: '
|
|
85
|
+
{ guard: 'isFixedLengthTuple', bounds: [0], replacement: 'isEmptyTuple' },
|
|
86
|
+
{ guard: 'isMaxLengthTuple', bounds: [0], replacement: 'isEmptyTuple' },
|
|
87
|
+
{
|
|
88
|
+
guard: 'isBoundedLengthTuple',
|
|
89
|
+
bounds: [0, 0],
|
|
90
|
+
replacement: 'isEmptyTuple',
|
|
91
|
+
},
|
|
92
|
+
{ guard: 'isMinLengthTuple', bounds: [1], replacement: 'isNonEmptyTuple' },
|
|
77
93
|
] as const satisfies readonly Readonly<{
|
|
78
94
|
guard: string;
|
|
79
95
|
bounds: readonly number[];
|
|
@@ -88,7 +104,7 @@ export const preferCanonicalLengthGuard: TSESLint.RuleModule<
|
|
|
88
104
|
type: 'suggestion',
|
|
89
105
|
docs: {
|
|
90
106
|
description:
|
|
91
|
-
'Normalize array-length checks to their canonical `Arr` guard: `xs.length <op> n` becomes the matching `Arr.is*` guard, and degenerate
|
|
107
|
+
'Normalize array-length checks to their canonical `Arr` guard: `xs.length <op> n` becomes the matching `Arr.is*` guard, and a degenerate guard becomes the named one for its family (`Arr.isFixedLengthArray(0, xs)` → `Arr.isEmpty`, `Arr.isFixedLengthTuple(0, xs)` → `Arr.isEmptyTuple`).',
|
|
92
108
|
},
|
|
93
109
|
fixable: 'code',
|
|
94
110
|
schema: [],
|
|
@@ -125,7 +141,8 @@ export const preferCanonicalLengthGuard: TSESLint.RuleModule<
|
|
|
125
141
|
return;
|
|
126
142
|
}
|
|
127
143
|
|
|
128
|
-
|
|
144
|
+
// The array is the last argument; the bounds precede it.
|
|
145
|
+
const array = node.arguments[rewrite.bounds.length];
|
|
129
146
|
|
|
130
147
|
if (array === undefined) return;
|
|
131
148
|
|
|
@@ -137,7 +154,7 @@ export const preferCanonicalLengthGuard: TSESLint.RuleModule<
|
|
|
137
154
|
data: {
|
|
138
155
|
arrName: arrLocalName,
|
|
139
156
|
guard: guardName,
|
|
140
|
-
boundsText: [
|
|
157
|
+
boundsText: [...rewrite.bounds.map(String), '…'].join(', '),
|
|
141
158
|
replacement: rewrite.replacement,
|
|
142
159
|
},
|
|
143
160
|
fix: (fixer) =>
|
|
@@ -207,8 +224,11 @@ const getGuardName = (
|
|
|
207
224
|
};
|
|
208
225
|
|
|
209
226
|
/**
|
|
210
|
-
* Whether the call is `guard(
|
|
227
|
+
* Whether the call is `guard(...bounds, array)` with every bound written as the
|
|
211
228
|
* exact numeric literal the rewrite requires.
|
|
229
|
+
*
|
|
230
|
+
* The arity check also excludes the curried form (`guard(...bounds)`): the
|
|
231
|
+
* degenerate guards take only the array, so there is nothing to rewrite it to.
|
|
212
232
|
*/
|
|
213
233
|
const matchesBounds = (
|
|
214
234
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -224,8 +244,7 @@ const matchesBounds = (
|
|
|
224
244
|
return args.every(
|
|
225
245
|
(arg, index) =>
|
|
226
246
|
arg.type !== AST_NODE_TYPES.SpreadElement &&
|
|
227
|
-
(index ===
|
|
228
|
-
(arg.type === AST_NODE_TYPES.Literal &&
|
|
229
|
-
arg.value === bounds[index - 1])),
|
|
247
|
+
(index === bounds.length ||
|
|
248
|
+
(arg.type === AST_NODE_TYPES.Literal && arg.value === bounds[index])),
|
|
230
249
|
);
|
|
231
250
|
};
|
|
@@ -55,7 +55,7 @@ describe('prefer-canonical-length-guard (folded-in length comparisons)', () => {
|
|
|
55
55
|
errors: [{ messageId: 'useIsNonEmpty' }],
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
name: 'xs.length >= 2 becomes Arr.isMinLengthArray(
|
|
58
|
+
name: 'xs.length >= 2 becomes Arr.isMinLengthArray(2, xs)',
|
|
59
59
|
code: dedent`
|
|
60
60
|
const xs = [1, 2, 3];
|
|
61
61
|
const ok = xs.length >= 2;
|
|
@@ -63,12 +63,12 @@ describe('prefer-canonical-length-guard (folded-in length comparisons)', () => {
|
|
|
63
63
|
output: dedent`
|
|
64
64
|
import { Arr } from 'ts-data-forge';
|
|
65
65
|
const xs = [1, 2, 3];
|
|
66
|
-
const ok = Arr.isMinLengthArray(
|
|
66
|
+
const ok = Arr.isMinLengthArray(2, xs);
|
|
67
67
|
`,
|
|
68
68
|
errors: [{ messageId: 'useIsMinLengthArray' }],
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
name: 'xs.length === 3 becomes Arr.isFixedLengthArray(
|
|
71
|
+
name: 'xs.length === 3 becomes Arr.isFixedLengthArray(3, xs)',
|
|
72
72
|
code: dedent`
|
|
73
73
|
const xs = [1, 2, 3];
|
|
74
74
|
const ok = xs.length === 3;
|
|
@@ -76,7 +76,7 @@ describe('prefer-canonical-length-guard (folded-in length comparisons)', () => {
|
|
|
76
76
|
output: dedent`
|
|
77
77
|
import { Arr } from 'ts-data-forge';
|
|
78
78
|
const xs = [1, 2, 3];
|
|
79
|
-
const ok = Arr.isFixedLengthArray(
|
|
79
|
+
const ok = Arr.isFixedLengthArray(3, xs);
|
|
80
80
|
`,
|
|
81
81
|
errors: [{ messageId: 'useIsFixedLengthArray' }],
|
|
82
82
|
},
|
|
@@ -93,7 +93,7 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
93
93
|
import { Arr } from 'ts-data-forge';
|
|
94
94
|
|
|
95
95
|
declare const xs: readonly number[];
|
|
96
|
-
const ok = Arr.isFixedLengthTuple(
|
|
96
|
+
const ok = Arr.isFixedLengthTuple(2, xs);
|
|
97
97
|
`,
|
|
98
98
|
},
|
|
99
99
|
{
|
|
@@ -102,7 +102,7 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
102
102
|
import { Arr } from 'ts-data-forge';
|
|
103
103
|
|
|
104
104
|
declare const xs: readonly number[];
|
|
105
|
-
const ok = Arr.isMinLengthArray(
|
|
105
|
+
const ok = Arr.isMinLengthArray(2, xs);
|
|
106
106
|
`,
|
|
107
107
|
},
|
|
108
108
|
{
|
|
@@ -111,7 +111,7 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
111
111
|
import { Arr } from 'ts-data-forge';
|
|
112
112
|
|
|
113
113
|
declare const xs: readonly number[];
|
|
114
|
-
const ok = Arr.isBoundedLengthTuple(
|
|
114
|
+
const ok = Arr.isBoundedLengthTuple(0, 1, xs);
|
|
115
115
|
`,
|
|
116
116
|
},
|
|
117
117
|
{
|
|
@@ -121,7 +121,7 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
121
121
|
|
|
122
122
|
declare const xs: readonly number[];
|
|
123
123
|
const n = 0;
|
|
124
|
-
const ok = Arr.isFixedLengthTuple(
|
|
124
|
+
const ok = Arr.isFixedLengthTuple(n, xs);
|
|
125
125
|
`,
|
|
126
126
|
},
|
|
127
127
|
{
|
|
@@ -130,7 +130,7 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
130
130
|
import { Arr } from './my-helpers.mjs';
|
|
131
131
|
|
|
132
132
|
declare const xs: readonly number[];
|
|
133
|
-
const ok = Arr.isFixedLengthTuple(
|
|
133
|
+
const ok = Arr.isFixedLengthTuple(0, xs);
|
|
134
134
|
`,
|
|
135
135
|
},
|
|
136
136
|
{
|
|
@@ -154,12 +154,12 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
154
154
|
],
|
|
155
155
|
invalid: [
|
|
156
156
|
{
|
|
157
|
-
name: 'isFixedLengthArray(
|
|
157
|
+
name: 'isFixedLengthArray(0, xs) becomes isEmpty(xs)',
|
|
158
158
|
code: dedent`
|
|
159
159
|
import { Arr } from 'ts-data-forge';
|
|
160
160
|
|
|
161
161
|
declare const xs: readonly number[];
|
|
162
|
-
const ok = Arr.isFixedLengthArray(
|
|
162
|
+
const ok = Arr.isFixedLengthArray(0, xs);
|
|
163
163
|
`,
|
|
164
164
|
output: dedent`
|
|
165
165
|
import { Arr } from 'ts-data-forge';
|
|
@@ -170,76 +170,76 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
170
170
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
171
171
|
},
|
|
172
172
|
{
|
|
173
|
-
name: 'isMinLengthTuple(
|
|
173
|
+
name: 'isMinLengthTuple(1, xs) becomes isNonEmptyTuple(xs)',
|
|
174
174
|
code: dedent`
|
|
175
175
|
import { Arr } from 'ts-data-forge';
|
|
176
176
|
|
|
177
177
|
declare const xs: readonly number[];
|
|
178
|
-
const ok = Arr.isMinLengthTuple(
|
|
178
|
+
const ok = Arr.isMinLengthTuple(1, xs);
|
|
179
179
|
`,
|
|
180
180
|
output: dedent`
|
|
181
181
|
import { Arr } from 'ts-data-forge';
|
|
182
182
|
|
|
183
183
|
declare const xs: readonly number[];
|
|
184
|
-
const ok = Arr.
|
|
184
|
+
const ok = Arr.isNonEmptyTuple(xs);
|
|
185
185
|
`,
|
|
186
186
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
187
187
|
},
|
|
188
188
|
{
|
|
189
|
-
name: 'isFixedLengthTuple(
|
|
189
|
+
name: 'isFixedLengthTuple(0, xs) becomes isEmptyTuple(xs)',
|
|
190
190
|
code: dedent`
|
|
191
191
|
import { Arr } from 'ts-data-forge';
|
|
192
192
|
|
|
193
193
|
declare const xs: readonly number[];
|
|
194
|
-
const ok = Arr.isFixedLengthTuple(
|
|
194
|
+
const ok = Arr.isFixedLengthTuple(0, xs);
|
|
195
195
|
`,
|
|
196
196
|
output: dedent`
|
|
197
197
|
import { Arr } from 'ts-data-forge';
|
|
198
198
|
|
|
199
199
|
declare const xs: readonly number[];
|
|
200
|
-
const ok = Arr.
|
|
200
|
+
const ok = Arr.isEmptyTuple(xs);
|
|
201
201
|
`,
|
|
202
202
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
203
203
|
},
|
|
204
204
|
{
|
|
205
|
-
name: 'isMaxLengthTuple(
|
|
205
|
+
name: 'isMaxLengthTuple(0, xs) becomes isEmptyTuple(xs)',
|
|
206
206
|
code: dedent`
|
|
207
207
|
import { Arr } from 'ts-data-forge';
|
|
208
208
|
|
|
209
209
|
declare const xs: readonly number[];
|
|
210
|
-
const ok = Arr.isMaxLengthTuple(
|
|
210
|
+
const ok = Arr.isMaxLengthTuple(0, xs);
|
|
211
211
|
`,
|
|
212
212
|
output: dedent`
|
|
213
213
|
import { Arr } from 'ts-data-forge';
|
|
214
214
|
|
|
215
215
|
declare const xs: readonly number[];
|
|
216
|
-
const ok = Arr.
|
|
216
|
+
const ok = Arr.isEmptyTuple(xs);
|
|
217
217
|
`,
|
|
218
218
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
219
219
|
},
|
|
220
220
|
{
|
|
221
|
-
name: 'isBoundedLengthTuple(
|
|
221
|
+
name: 'isBoundedLengthTuple(0, 0, xs) becomes isEmptyTuple(xs)',
|
|
222
222
|
code: dedent`
|
|
223
223
|
import { Arr } from 'ts-data-forge';
|
|
224
224
|
|
|
225
225
|
declare const xs: readonly number[];
|
|
226
|
-
const ok = Arr.isBoundedLengthTuple(
|
|
226
|
+
const ok = Arr.isBoundedLengthTuple(0, 0, xs);
|
|
227
227
|
`,
|
|
228
228
|
output: dedent`
|
|
229
229
|
import { Arr } from 'ts-data-forge';
|
|
230
230
|
|
|
231
231
|
declare const xs: readonly number[];
|
|
232
|
-
const ok = Arr.
|
|
232
|
+
const ok = Arr.isEmptyTuple(xs);
|
|
233
233
|
`,
|
|
234
234
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
235
235
|
},
|
|
236
236
|
{
|
|
237
|
-
name: 'isMinLengthArray(
|
|
237
|
+
name: 'isMinLengthArray(1, xs) becomes isNonEmpty(xs)',
|
|
238
238
|
code: dedent`
|
|
239
239
|
import { Arr } from 'ts-data-forge';
|
|
240
240
|
|
|
241
241
|
declare const xs: readonly number[];
|
|
242
|
-
const ok = Arr.isMinLengthArray(
|
|
242
|
+
const ok = Arr.isMinLengthArray(1, xs);
|
|
243
243
|
`,
|
|
244
244
|
output: dedent`
|
|
245
245
|
import { Arr } from 'ts-data-forge';
|
|
@@ -255,13 +255,13 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
255
255
|
import { Arr } from 'ts-data-forge';
|
|
256
256
|
|
|
257
257
|
declare const obj: Readonly<{ items: readonly number[] }>;
|
|
258
|
-
const ok = Arr.isFixedLengthTuple(obj.items.filter((x) => x > 0)
|
|
258
|
+
const ok = Arr.isFixedLengthTuple(0, obj.items.filter((x) => x > 0));
|
|
259
259
|
`,
|
|
260
260
|
output: dedent`
|
|
261
261
|
import { Arr } from 'ts-data-forge';
|
|
262
262
|
|
|
263
263
|
declare const obj: Readonly<{ items: readonly number[] }>;
|
|
264
|
-
const ok = Arr.
|
|
264
|
+
const ok = Arr.isEmptyTuple(obj.items.filter((x) => x > 0));
|
|
265
265
|
`,
|
|
266
266
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
267
267
|
},
|
|
@@ -271,13 +271,13 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
271
271
|
import { Arr as A } from 'ts-data-forge';
|
|
272
272
|
|
|
273
273
|
declare const xs: readonly number[];
|
|
274
|
-
const ok = A.isFixedLengthTuple(
|
|
274
|
+
const ok = A.isFixedLengthTuple(0, xs);
|
|
275
275
|
`,
|
|
276
276
|
output: dedent`
|
|
277
277
|
import { Arr as A } from 'ts-data-forge';
|
|
278
278
|
|
|
279
279
|
declare const xs: readonly number[];
|
|
280
|
-
const ok = A.
|
|
280
|
+
const ok = A.isEmptyTuple(xs);
|
|
281
281
|
`,
|
|
282
282
|
errors: [{ messageId: 'useCanonicalGuard' }],
|
|
283
283
|
},
|
|
@@ -287,14 +287,14 @@ describe('prefer-canonical-length-guard', () => {
|
|
|
287
287
|
import { Arr } from 'ts-data-forge';
|
|
288
288
|
|
|
289
289
|
declare const xs: readonly number[];
|
|
290
|
-
const a = Arr.isFixedLengthTuple(
|
|
291
|
-
const b = Arr.isMinLengthArray(
|
|
290
|
+
const a = Arr.isFixedLengthTuple(0, xs);
|
|
291
|
+
const b = Arr.isMinLengthArray(1, xs);
|
|
292
292
|
`,
|
|
293
293
|
output: dedent`
|
|
294
294
|
import { Arr } from 'ts-data-forge';
|
|
295
295
|
|
|
296
296
|
declare const xs: readonly number[];
|
|
297
|
-
const a = Arr.
|
|
297
|
+
const a = Arr.isEmptyTuple(xs);
|
|
298
298
|
const b = Arr.isNonEmpty(xs);
|
|
299
299
|
`,
|
|
300
300
|
errors: [
|
|
@@ -50,7 +50,7 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
50
50
|
if (
|
|
51
51
|
node.init?.type !== AST_NODE_TYPES.VariableDeclaration ||
|
|
52
52
|
node.init.kind !== 'let' ||
|
|
53
|
-
!Arr.isFixedLengthTuple(node.init.declarations
|
|
53
|
+
!Arr.isFixedLengthTuple(1, node.init.declarations)
|
|
54
54
|
) {
|
|
55
55
|
return;
|
|
56
56
|
}
|
package/src/rules/rules.mts
CHANGED
|
@@ -4,6 +4,7 @@ import { preferArrIsArray } from './prefer-arr-is-array.mjs';
|
|
|
4
4
|
import { preferArrSum } from './prefer-arr-sum.mjs';
|
|
5
5
|
import { preferAsInt } from './prefer-as-int.mjs';
|
|
6
6
|
import { preferCanonicalArraySlicing } from './prefer-canonical-array-slicing.mjs';
|
|
7
|
+
import { preferCanonicalLengthCast } from './prefer-canonical-length-cast.mjs';
|
|
7
8
|
import { preferCanonicalLengthGuard } from './prefer-canonical-length-guard.mjs';
|
|
8
9
|
import { preferComparisonOverNullishGuard } from './prefer-comparison-over-nullish-guard.mjs';
|
|
9
10
|
import { preferIsNonNullObject } from './prefer-is-non-null-object.mjs';
|
|
@@ -15,6 +16,7 @@ import { preferRangeForLoop } from './prefer-range-for-loop.mjs';
|
|
|
15
16
|
export const tsDataForgeRules = {
|
|
16
17
|
'prefer-canonical-array-slicing': preferCanonicalArraySlicing,
|
|
17
18
|
'prefer-canonical-length-guard': preferCanonicalLengthGuard,
|
|
19
|
+
'prefer-canonical-length-cast': preferCanonicalLengthCast,
|
|
18
20
|
'prefer-arr-is-array': preferArrIsArray,
|
|
19
21
|
'prefer-arr-sum': preferArrSum,
|
|
20
22
|
'prefer-as-int': preferAsInt,
|