eslint-plugin-ts-data-forge 0.8.5 → 0.9.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 +20 -19
- 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/rule-types.mjs.map +1 -1
- package/dist/rules/ast-utils.d.mts +21 -34
- package/dist/rules/ast-utils.d.mts.map +1 -1
- package/dist/rules/ast-utils.mjs +53 -58
- package/dist/rules/ast-utils.mjs.map +1 -1
- package/dist/rules/constants.d.mts +2 -0
- package/dist/rules/constants.d.mts.map +1 -1
- package/dist/rules/constants.mjs +9 -0
- package/dist/rules/constants.mjs.map +1 -1
- package/dist/rules/mutable-result.d.mts +10 -0
- package/dist/rules/mutable-result.d.mts.map +1 -0
- package/dist/rules/mutable-result.mjs +145 -0
- package/dist/rules/mutable-result.mjs.map +1 -0
- package/dist/rules/no-unnecessary-type-guard.d.mts.map +1 -1
- package/dist/rules/no-unnecessary-type-guard.mjs +6 -6
- package/dist/rules/no-unnecessary-type-guard.mjs.map +1 -1
- package/dist/rules/prefer-arr-generate.d.mts +57 -0
- package/dist/rules/prefer-arr-generate.d.mts.map +1 -0
- package/dist/rules/prefer-arr-generate.mjs +588 -0
- package/dist/rules/prefer-arr-generate.mjs.map +1 -0
- package/dist/rules/prefer-arr-is-array.d.mts.map +1 -1
- package/dist/rules/prefer-arr-is-array.mjs +7 -5
- package/dist/rules/prefer-arr-is-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-bounded-length-array.d.mts.map +1 -1
- package/dist/rules/prefer-arr-is-bounded-length-array.mjs +9 -6
- package/dist/rules/prefer-arr-is-bounded-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-fixed-length-array.d.mts.map +1 -1
- package/dist/rules/prefer-arr-is-fixed-length-array.mjs +9 -6
- package/dist/rules/prefer-arr-is-fixed-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-max-length-array.d.mts.map +1 -1
- package/dist/rules/prefer-arr-is-max-length-array.mjs +9 -6
- package/dist/rules/prefer-arr-is-max-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-min-length-array.d.mts.map +1 -1
- package/dist/rules/prefer-arr-is-min-length-array.mjs +9 -6
- package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
- package/dist/rules/prefer-arr-is-non-empty.d.mts.map +1 -1
- package/dist/rules/prefer-arr-is-non-empty.mjs +9 -6
- package/dist/rules/prefer-arr-is-non-empty.mjs.map +1 -1
- package/dist/rules/prefer-arr-scan.d.mts.map +1 -1
- package/dist/rules/prefer-arr-scan.mjs +8 -11
- package/dist/rules/prefer-arr-scan.mjs.map +1 -1
- package/dist/rules/prefer-arr-sum.d.mts.map +1 -1
- package/dist/rules/prefer-arr-sum.mjs +8 -6
- package/dist/rules/prefer-arr-sum.mjs.map +1 -1
- package/dist/rules/prefer-arr-uniq.d.mts.map +1 -1
- package/dist/rules/prefer-arr-uniq.mjs +12 -166
- package/dist/rules/prefer-arr-uniq.mjs.map +1 -1
- package/dist/rules/prefer-as-int.d.mts.map +1 -1
- package/dist/rules/prefer-as-int.mjs +6 -8
- package/dist/rules/prefer-as-int.mjs.map +1 -1
- package/dist/rules/prefer-canonical-array-slicing.d.mts.map +1 -1
- package/dist/rules/prefer-canonical-array-slicing.mjs +57 -34
- package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-cast.d.mts.map +1 -1
- package/dist/rules/prefer-canonical-length-cast.mjs +3 -3
- package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-guard.d.mts.map +1 -1
- package/dist/rules/prefer-canonical-length-guard.mjs +4 -4
- package/dist/rules/prefer-canonical-length-guard.mjs.map +1 -1
- package/dist/rules/prefer-comparison-over-nullish-guard.d.mts.map +1 -1
- package/dist/rules/prefer-comparison-over-nullish-guard.mjs +3 -2
- package/dist/rules/prefer-comparison-over-nullish-guard.mjs.map +1 -1
- package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
- package/dist/rules/prefer-is-non-null-object.mjs +113 -43
- package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
- package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
- package/dist/rules/prefer-is-record-and-has-key.mjs +105 -48
- package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
- package/dist/rules/prefer-num-safe-parse-float.d.mts.map +1 -1
- package/dist/rules/prefer-num-safe-parse-float.mjs +6 -6
- package/dist/rules/prefer-num-safe-parse-float.mjs.map +1 -1
- package/dist/rules/prefer-num-safe-parse-int.d.mts.map +1 -1
- package/dist/rules/prefer-num-safe-parse-int.mjs +6 -6
- package/dist/rules/prefer-num-safe-parse-int.mjs.map +1 -1
- package/dist/rules/prefer-obj-over-entries-round-trip.d.mts.map +1 -1
- package/dist/rules/prefer-obj-over-entries-round-trip.mjs +9 -12
- package/dist/rules/prefer-obj-over-entries-round-trip.mjs.map +1 -1
- package/dist/rules/prefer-range-for-loop.d.mts.map +1 -1
- package/dist/rules/prefer-range-for-loop.mjs +104 -23
- 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 +11 -10
- package/src/plugin.mts +1 -0
- package/src/rule-types.mts +17 -1
- package/src/rules/ast-utils.mts +73 -80
- package/src/rules/constants.mts +12 -0
- package/src/rules/mutable-result.mts +204 -0
- package/src/rules/no-unnecessary-type-guard.mts +14 -10
- package/src/rules/prefer-arr-generate.mts +918 -0
- package/src/rules/prefer-arr-generate.test.mts +967 -0
- package/src/rules/prefer-arr-is-array.mts +14 -7
- package/src/rules/prefer-arr-is-array.test.mts +14 -0
- package/src/rules/prefer-arr-is-bounded-length-array.mts +16 -10
- package/src/rules/prefer-arr-is-bounded-length-array.test.mts +19 -0
- package/src/rules/prefer-arr-is-fixed-length-array.mts +17 -11
- package/src/rules/prefer-arr-is-max-length-array.mts +17 -11
- package/src/rules/prefer-arr-is-max-length-array.test.mts +8 -0
- package/src/rules/prefer-arr-is-min-length-array.mts +17 -11
- package/src/rules/prefer-arr-is-min-length-array.test.mts +8 -0
- package/src/rules/prefer-arr-is-non-empty.mts +16 -13
- package/src/rules/prefer-arr-scan.mts +24 -19
- package/src/rules/prefer-arr-sum.mts +18 -14
- package/src/rules/prefer-arr-uniq.mts +25 -234
- package/src/rules/prefer-as-int.mts +19 -12
- package/src/rules/prefer-canonical-array-slicing.mts +79 -52
- package/src/rules/prefer-canonical-array-slicing.test.mts +55 -0
- package/src/rules/prefer-canonical-length-cast.mts +7 -3
- package/src/rules/prefer-canonical-length-guard.mts +9 -4
- package/src/rules/prefer-comparison-over-nullish-guard.mts +3 -2
- package/src/rules/prefer-comparison-over-nullish-guard.test.mts +16 -0
- package/src/rules/prefer-is-non-null-object.mts +171 -64
- package/src/rules/prefer-is-non-null-object.test.mts +138 -0
- package/src/rules/prefer-is-record-and-has-key.mts +159 -74
- package/src/rules/prefer-is-record-and-has-key.test.mts +118 -23
- package/src/rules/prefer-num-safe-parse-float.mts +15 -10
- package/src/rules/prefer-num-safe-parse-int.mts +15 -13
- package/src/rules/prefer-obj-over-entries-round-trip.mts +19 -22
- package/src/rules/prefer-range-for-loop.mts +157 -31
- package/src/rules/prefer-range-for-loop.test.mts +127 -5
- package/src/rules/rules.mts +2 -0
- package/dist/rules/import-utils.d.mts +0 -30
- package/dist/rules/import-utils.d.mts.map +0 -1
- package/dist/rules/import-utils.mjs +0 -98
- package/dist/rules/import-utils.mjs.map +0 -1
- package/src/rules/import-utils.mts +0 -175
|
@@ -3,12 +3,13 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import { skipTypeWrappers } from './ast-utils.mjs';
|
|
7
6
|
import {
|
|
8
|
-
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getImportDeclarations,
|
|
9
9
|
getNamedImports,
|
|
10
|
-
|
|
11
|
-
} from '
|
|
10
|
+
skipTypeWrappers,
|
|
11
|
+
} from 'eslint-rule-forge';
|
|
12
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
12
13
|
|
|
13
14
|
type Options = readonly [];
|
|
14
15
|
|
|
@@ -34,7 +35,10 @@ export const preferArrIsArray: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
34
35
|
|
|
35
36
|
const program = sourceCode.ast;
|
|
36
37
|
|
|
37
|
-
const
|
|
38
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
39
|
+
program,
|
|
40
|
+
TS_DATA_FORGE_MODULE,
|
|
41
|
+
);
|
|
38
42
|
|
|
39
43
|
const mut_nodesToFix: TSESTree.CallExpression[] = [];
|
|
40
44
|
|
|
@@ -48,7 +52,8 @@ export const preferArrIsArray: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
48
52
|
},
|
|
49
53
|
'Program:exit': () => {
|
|
50
54
|
// Check if Arr is already imported
|
|
51
|
-
const hasArrImport =
|
|
55
|
+
const hasArrImport =
|
|
56
|
+
getNamedImports(tsDataForgeImports).includes('Arr');
|
|
52
57
|
|
|
53
58
|
// Note: We add import only for the first node to avoid conflicts when
|
|
54
59
|
// multiple fixes try to insert at the same position. This means if the
|
|
@@ -70,7 +75,9 @@ export const preferArrIsArray: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
70
75
|
// Add import only for the first node and only if not already imported
|
|
71
76
|
const importFixes =
|
|
72
77
|
index === 0 && !hasArrImport
|
|
73
|
-
?
|
|
78
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
79
|
+
'Arr',
|
|
80
|
+
])
|
|
74
81
|
: [];
|
|
75
82
|
|
|
76
83
|
return [...importFixes, fixer.replaceText(callee, 'Arr.isArray')];
|
|
@@ -33,6 +33,20 @@ ruleTester.run('prefer-arr-is-array', preferArrIsArray, {
|
|
|
33
33
|
`,
|
|
34
34
|
errors: [{ messageId: 'useArrIsArray' }],
|
|
35
35
|
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Arr imported by a second ts-data-forge declaration is not imported again',
|
|
38
|
+
code: dedent`
|
|
39
|
+
import type { Optional } from 'ts-data-forge';
|
|
40
|
+
import { Arr } from 'ts-data-forge';
|
|
41
|
+
const result = Array.isArray(value);
|
|
42
|
+
`,
|
|
43
|
+
output: dedent`
|
|
44
|
+
import type { Optional } from 'ts-data-forge';
|
|
45
|
+
import { Arr } from 'ts-data-forge';
|
|
46
|
+
const result = Arr.isArray(value);
|
|
47
|
+
`,
|
|
48
|
+
errors: [{ messageId: 'useArrIsArray' }],
|
|
49
|
+
},
|
|
36
50
|
{
|
|
37
51
|
name: 'Replace Array.isArray with Arr.isArray when Arr is already imported',
|
|
38
52
|
code: dedent`
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import {
|
|
3
|
+
buildNamedImportFix,
|
|
4
|
+
getArgumentText,
|
|
5
|
+
getImportDeclarations,
|
|
6
|
+
getNamedImports,
|
|
7
|
+
} from 'eslint-rule-forge';
|
|
2
8
|
import {
|
|
3
9
|
isArrayOrTupleExpression,
|
|
4
10
|
isSameArrayText,
|
|
5
11
|
parseLengthComparison,
|
|
6
|
-
toArgumentText,
|
|
7
12
|
} from './ast-utils.mjs';
|
|
8
|
-
import {
|
|
9
|
-
buildImportFixes,
|
|
10
|
-
getNamedImports,
|
|
11
|
-
getTsDataForgeImport,
|
|
12
|
-
} from './import-utils.mjs';
|
|
13
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
13
14
|
|
|
14
15
|
type Options = readonly [];
|
|
15
16
|
|
|
@@ -38,7 +39,10 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
|
|
|
38
39
|
|
|
39
40
|
const program = sourceCode.ast;
|
|
40
41
|
|
|
41
|
-
const
|
|
42
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
43
|
+
program,
|
|
44
|
+
TS_DATA_FORGE_MODULE,
|
|
45
|
+
);
|
|
42
46
|
|
|
43
47
|
const services = context.sourceCode.parserServices;
|
|
44
48
|
|
|
@@ -95,7 +99,7 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
|
|
|
95
99
|
});
|
|
96
100
|
},
|
|
97
101
|
'Program:exit': () => {
|
|
98
|
-
const namedImports = getNamedImports(
|
|
102
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
99
103
|
|
|
100
104
|
const hasArrImport = namedImports.includes('Arr');
|
|
101
105
|
|
|
@@ -103,7 +107,7 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
|
|
|
103
107
|
index,
|
|
104
108
|
{ node, arrayExpression, minExpression, maxExpression },
|
|
105
109
|
] of mut_nodesToFix.entries()) {
|
|
106
|
-
const arrayText =
|
|
110
|
+
const arrayText = getArgumentText(sourceCode, arrayExpression);
|
|
107
111
|
|
|
108
112
|
const minText = sourceCode.getText(minExpression);
|
|
109
113
|
|
|
@@ -125,7 +129,9 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
|
|
|
125
129
|
|
|
126
130
|
const importFixes =
|
|
127
131
|
index === 0 && !hasArrImport
|
|
128
|
-
?
|
|
132
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
133
|
+
'Arr',
|
|
134
|
+
])
|
|
129
135
|
: [];
|
|
130
136
|
|
|
131
137
|
return [...importFixes, fixer.replaceText(node, replacement)];
|
|
@@ -188,6 +188,25 @@ describe('prefer-arr-is-bounded-length-array through type wrappers', () => {
|
|
|
188
188
|
{ messageId: 'useIsBoundedLengthArray' },
|
|
189
189
|
],
|
|
190
190
|
},
|
|
191
|
+
{
|
|
192
|
+
name: 'either comparison wrapped as a whole',
|
|
193
|
+
code: dedent`
|
|
194
|
+
import { Arr } from 'ts-data-forge';
|
|
195
|
+
declare const xs: readonly number[];
|
|
196
|
+
const a = (xs.length >= 1 satisfies boolean) && xs.length <= 3;
|
|
197
|
+
const b = xs.length >= 1 && (xs.length <= 3 as boolean);
|
|
198
|
+
`,
|
|
199
|
+
output: dedent`
|
|
200
|
+
import { Arr } from 'ts-data-forge';
|
|
201
|
+
declare const xs: readonly number[];
|
|
202
|
+
const a = Arr.isBoundedLengthArray(1, 3, xs);
|
|
203
|
+
const b = Arr.isBoundedLengthArray(1, 3, xs);
|
|
204
|
+
`,
|
|
205
|
+
errors: [
|
|
206
|
+
{ messageId: 'useIsBoundedLengthArray' },
|
|
207
|
+
{ messageId: 'useIsBoundedLengthArray' },
|
|
208
|
+
],
|
|
209
|
+
},
|
|
191
210
|
],
|
|
192
211
|
},
|
|
193
212
|
);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import {
|
|
3
|
+
buildNamedImportFix,
|
|
4
|
+
getArgumentText,
|
|
5
|
+
getImportDeclarations,
|
|
6
|
+
getNamedImports,
|
|
7
|
+
skipTypeWrappers,
|
|
8
|
+
} from 'eslint-rule-forge';
|
|
2
9
|
import {
|
|
3
10
|
asLengthAccess,
|
|
4
11
|
isArrayOrTupleExpression,
|
|
5
12
|
isIntegerLiteralOrConstant,
|
|
6
|
-
skipTypeWrappers,
|
|
7
|
-
toArgumentText,
|
|
8
13
|
} from './ast-utils.mjs';
|
|
9
|
-
import {
|
|
10
|
-
buildImportFixes,
|
|
11
|
-
getNamedImports,
|
|
12
|
-
getTsDataForgeImport,
|
|
13
|
-
} from './import-utils.mjs';
|
|
14
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
14
15
|
|
|
15
16
|
type Options = readonly [];
|
|
16
17
|
|
|
@@ -39,7 +40,10 @@ export const preferArrIsFixedLengthArray: TSESLint.RuleModule<
|
|
|
39
40
|
|
|
40
41
|
const program = sourceCode.ast;
|
|
41
42
|
|
|
42
|
-
const
|
|
43
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
44
|
+
program,
|
|
45
|
+
TS_DATA_FORGE_MODULE,
|
|
46
|
+
);
|
|
43
47
|
|
|
44
48
|
const services = context.sourceCode.parserServices;
|
|
45
49
|
|
|
@@ -94,7 +98,7 @@ export const preferArrIsFixedLengthArray: TSESLint.RuleModule<
|
|
|
94
98
|
});
|
|
95
99
|
},
|
|
96
100
|
'Program:exit': () => {
|
|
97
|
-
const namedImports = getNamedImports(
|
|
101
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
98
102
|
|
|
99
103
|
const hasArrImport = namedImports.includes('Arr');
|
|
100
104
|
|
|
@@ -102,7 +106,7 @@ export const preferArrIsFixedLengthArray: TSESLint.RuleModule<
|
|
|
102
106
|
index,
|
|
103
107
|
{ node, arrayExpression, lengthExpression, isNegated },
|
|
104
108
|
] of mut_nodesToFix.entries()) {
|
|
105
|
-
const arrayText =
|
|
109
|
+
const arrayText = getArgumentText(sourceCode, arrayExpression);
|
|
106
110
|
|
|
107
111
|
const lengthText = sourceCode.getText(lengthExpression);
|
|
108
112
|
|
|
@@ -123,7 +127,9 @@ export const preferArrIsFixedLengthArray: TSESLint.RuleModule<
|
|
|
123
127
|
|
|
124
128
|
const importFixes =
|
|
125
129
|
index === 0 && !hasArrImport
|
|
126
|
-
?
|
|
130
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
131
|
+
'Arr',
|
|
132
|
+
])
|
|
127
133
|
: [];
|
|
128
134
|
|
|
129
135
|
return [...importFixes, fixer.replaceText(node, replacement)];
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import {
|
|
3
|
+
buildNamedImportFix,
|
|
4
|
+
getArgumentText,
|
|
5
|
+
getImportDeclarations,
|
|
6
|
+
getNamedImports,
|
|
7
|
+
skipTypeWrappers,
|
|
8
|
+
} from 'eslint-rule-forge';
|
|
2
9
|
import {
|
|
3
10
|
asLengthAccess,
|
|
4
11
|
isArrayOrTupleExpression,
|
|
5
12
|
isIntegerLiteralOrConstant,
|
|
6
13
|
isPartOfBoundedLengthCheck,
|
|
7
|
-
skipTypeWrappers,
|
|
8
|
-
toArgumentText,
|
|
9
14
|
} from './ast-utils.mjs';
|
|
10
|
-
import {
|
|
11
|
-
buildImportFixes,
|
|
12
|
-
getNamedImports,
|
|
13
|
-
getTsDataForgeImport,
|
|
14
|
-
} from './import-utils.mjs';
|
|
15
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
15
16
|
|
|
16
17
|
type Options = readonly [];
|
|
17
18
|
|
|
@@ -40,7 +41,10 @@ export const preferArrIsMaxLengthArray: TSESLint.RuleModule<
|
|
|
40
41
|
|
|
41
42
|
const program = sourceCode.ast;
|
|
42
43
|
|
|
43
|
-
const
|
|
44
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
45
|
+
program,
|
|
46
|
+
TS_DATA_FORGE_MODULE,
|
|
47
|
+
);
|
|
44
48
|
|
|
45
49
|
const services = context.sourceCode.parserServices;
|
|
46
50
|
|
|
@@ -99,7 +103,7 @@ export const preferArrIsMaxLengthArray: TSESLint.RuleModule<
|
|
|
99
103
|
});
|
|
100
104
|
},
|
|
101
105
|
'Program:exit': () => {
|
|
102
|
-
const namedImports = getNamedImports(
|
|
106
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
103
107
|
|
|
104
108
|
const hasArrImport = namedImports.includes('Arr');
|
|
105
109
|
|
|
@@ -107,7 +111,7 @@ export const preferArrIsMaxLengthArray: TSESLint.RuleModule<
|
|
|
107
111
|
index,
|
|
108
112
|
{ node, arrayExpression, lengthExpression },
|
|
109
113
|
] of mut_nodesToFix.entries()) {
|
|
110
|
-
const arrayText =
|
|
114
|
+
const arrayText = getArgumentText(sourceCode, arrayExpression);
|
|
111
115
|
|
|
112
116
|
const lengthText = sourceCode.getText(lengthExpression);
|
|
113
117
|
|
|
@@ -126,7 +130,9 @@ export const preferArrIsMaxLengthArray: TSESLint.RuleModule<
|
|
|
126
130
|
|
|
127
131
|
const importFixes =
|
|
128
132
|
index === 0 && !hasArrImport
|
|
129
|
-
?
|
|
133
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
134
|
+
'Arr',
|
|
135
|
+
])
|
|
130
136
|
: [];
|
|
131
137
|
|
|
132
138
|
return [...importFixes, fixer.replaceText(node, replacement)];
|
|
@@ -205,6 +205,14 @@ describe('prefer-arr-is-max-length-array through type wrappers', () => {
|
|
|
205
205
|
const ok = xs!.length >= 1 && xs.length <= 3;
|
|
206
206
|
`,
|
|
207
207
|
},
|
|
208
|
+
{
|
|
209
|
+
name: 'one half of a bounded pair, either half wrapped as a whole',
|
|
210
|
+
code: dedent`
|
|
211
|
+
declare const xs: readonly number[];
|
|
212
|
+
const a = (xs.length >= 1 satisfies boolean) && xs.length <= 3;
|
|
213
|
+
const b = xs.length >= 1 && (xs.length <= 3 as boolean);
|
|
214
|
+
`,
|
|
215
|
+
},
|
|
208
216
|
],
|
|
209
217
|
invalid: [
|
|
210
218
|
{
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import {
|
|
3
|
+
buildNamedImportFix,
|
|
4
|
+
getArgumentText,
|
|
5
|
+
getImportDeclarations,
|
|
6
|
+
getNamedImports,
|
|
7
|
+
skipTypeWrappers,
|
|
8
|
+
} from 'eslint-rule-forge';
|
|
2
9
|
import {
|
|
3
10
|
asLengthAccess,
|
|
4
11
|
isArrayOrTupleExpression,
|
|
5
12
|
isIntegerLiteralOrConstant,
|
|
6
13
|
isPartOfBoundedLengthCheck,
|
|
7
|
-
skipTypeWrappers,
|
|
8
|
-
toArgumentText,
|
|
9
14
|
} from './ast-utils.mjs';
|
|
10
|
-
import {
|
|
11
|
-
buildImportFixes,
|
|
12
|
-
getNamedImports,
|
|
13
|
-
getTsDataForgeImport,
|
|
14
|
-
} from './import-utils.mjs';
|
|
15
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
15
16
|
|
|
16
17
|
type Options = readonly [];
|
|
17
18
|
|
|
@@ -40,7 +41,10 @@ export const preferArrIsMinLengthArray: TSESLint.RuleModule<
|
|
|
40
41
|
|
|
41
42
|
const program = sourceCode.ast;
|
|
42
43
|
|
|
43
|
-
const
|
|
44
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
45
|
+
program,
|
|
46
|
+
TS_DATA_FORGE_MODULE,
|
|
47
|
+
);
|
|
44
48
|
|
|
45
49
|
const services = context.sourceCode.parserServices;
|
|
46
50
|
|
|
@@ -99,7 +103,7 @@ export const preferArrIsMinLengthArray: TSESLint.RuleModule<
|
|
|
99
103
|
});
|
|
100
104
|
},
|
|
101
105
|
'Program:exit': () => {
|
|
102
|
-
const namedImports = getNamedImports(
|
|
106
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
103
107
|
|
|
104
108
|
const hasArrImport = namedImports.includes('Arr');
|
|
105
109
|
|
|
@@ -107,7 +111,7 @@ export const preferArrIsMinLengthArray: TSESLint.RuleModule<
|
|
|
107
111
|
index,
|
|
108
112
|
{ node, arrayExpression, lengthExpression },
|
|
109
113
|
] of mut_nodesToFix.entries()) {
|
|
110
|
-
const arrayText =
|
|
114
|
+
const arrayText = getArgumentText(sourceCode, arrayExpression);
|
|
111
115
|
|
|
112
116
|
const lengthText = sourceCode.getText(lengthExpression);
|
|
113
117
|
|
|
@@ -126,7 +130,9 @@ export const preferArrIsMinLengthArray: TSESLint.RuleModule<
|
|
|
126
130
|
|
|
127
131
|
const importFixes =
|
|
128
132
|
index === 0 && !hasArrImport
|
|
129
|
-
?
|
|
133
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
134
|
+
'Arr',
|
|
135
|
+
])
|
|
130
136
|
: [];
|
|
131
137
|
|
|
132
138
|
return [...importFixes, fixer.replaceText(node, replacement)];
|
|
@@ -219,6 +219,14 @@ describe('prefer-arr-is-min-length-array through type wrappers', () => {
|
|
|
219
219
|
const ok = xs.length >= 1 && (xs as readonly number[]).length <= 3;
|
|
220
220
|
`,
|
|
221
221
|
},
|
|
222
|
+
{
|
|
223
|
+
name: 'one half of a bounded pair, either half wrapped as a whole',
|
|
224
|
+
code: dedent`
|
|
225
|
+
declare const xs: readonly number[];
|
|
226
|
+
const a = (xs.length >= 1 satisfies boolean) && xs.length <= 3;
|
|
227
|
+
const b = xs.length >= 1 && (xs.length <= 3 as boolean);
|
|
228
|
+
`,
|
|
229
|
+
},
|
|
222
230
|
],
|
|
223
231
|
invalid: [
|
|
224
232
|
{
|
|
@@ -4,16 +4,14 @@ import {
|
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
toArgumentText,
|
|
11
|
-
} from './ast-utils.mjs';
|
|
12
|
-
import {
|
|
13
|
-
buildImportFixes,
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getArgumentText,
|
|
9
|
+
getImportDeclarations,
|
|
14
10
|
getNamedImports,
|
|
15
|
-
|
|
16
|
-
} from '
|
|
11
|
+
skipTypeWrappers,
|
|
12
|
+
} from 'eslint-rule-forge';
|
|
13
|
+
import { asLengthAccess, isArrayOrTupleExpression } from './ast-utils.mjs';
|
|
14
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
17
15
|
|
|
18
16
|
type Options = readonly [];
|
|
19
17
|
|
|
@@ -39,7 +37,10 @@ export const preferArrIsNonEmpty: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
39
37
|
|
|
40
38
|
const program = sourceCode.ast;
|
|
41
39
|
|
|
42
|
-
const
|
|
40
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
41
|
+
program,
|
|
42
|
+
TS_DATA_FORGE_MODULE,
|
|
43
|
+
);
|
|
43
44
|
|
|
44
45
|
const services = context.sourceCode.parserServices;
|
|
45
46
|
|
|
@@ -88,7 +89,7 @@ export const preferArrIsNonEmpty: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
88
89
|
});
|
|
89
90
|
},
|
|
90
91
|
'Program:exit': () => {
|
|
91
|
-
const namedImports = getNamedImports(
|
|
92
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
92
93
|
|
|
93
94
|
const hasArrImport = namedImports.includes('Arr');
|
|
94
95
|
|
|
@@ -96,7 +97,7 @@ export const preferArrIsNonEmpty: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
96
97
|
index,
|
|
97
98
|
{ node, arrayExpression },
|
|
98
99
|
] of mut_nodesToFix.entries()) {
|
|
99
|
-
const arrayText =
|
|
100
|
+
const arrayText = getArgumentText(sourceCode, arrayExpression);
|
|
100
101
|
|
|
101
102
|
const originalText = sourceCode.getText(node);
|
|
102
103
|
|
|
@@ -112,7 +113,9 @@ export const preferArrIsNonEmpty: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
112
113
|
|
|
113
114
|
const importFixes =
|
|
114
115
|
index === 0 && !hasArrImport
|
|
115
|
-
?
|
|
116
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
117
|
+
'Arr',
|
|
118
|
+
])
|
|
116
119
|
: [];
|
|
117
120
|
|
|
118
121
|
return [...importFixes, fixer.replaceText(node, replacement)];
|
|
@@ -3,19 +3,18 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import { Arr } from 'ts-data-forge';
|
|
7
|
-
import type { FixedLengthTuple } from 'ts-type-forge';
|
|
8
|
-
import * as ts from 'typescript';
|
|
9
6
|
import {
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getArgumentText,
|
|
9
|
+
getImportDeclarations,
|
|
10
|
+
getNamedImports,
|
|
10
11
|
skipTypeWrappers,
|
|
11
|
-
toArgumentText,
|
|
12
12
|
typeWrapperLayers,
|
|
13
|
-
} from '
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from './import-utils.mjs';
|
|
13
|
+
} from 'eslint-rule-forge';
|
|
14
|
+
import { Arr } from 'ts-data-forge';
|
|
15
|
+
import type { FixedLengthTuple } from 'ts-type-forge';
|
|
16
|
+
import * as ts from 'typescript';
|
|
17
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
19
18
|
|
|
20
19
|
type Options = readonly [];
|
|
21
20
|
|
|
@@ -179,7 +178,10 @@ export const preferArrScan: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
179
178
|
|
|
180
179
|
const program = sourceCode.ast;
|
|
181
180
|
|
|
182
|
-
const
|
|
181
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
182
|
+
program,
|
|
183
|
+
TS_DATA_FORGE_MODULE,
|
|
184
|
+
);
|
|
183
185
|
|
|
184
186
|
const services = sourceCode.parserServices;
|
|
185
187
|
|
|
@@ -343,10 +345,9 @@ export const preferArrScan: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
343
345
|
mut_lastReads,
|
|
344
346
|
);
|
|
345
347
|
|
|
346
|
-
const arrayText =
|
|
347
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
348
|
+
const arrayText = getArgumentText(
|
|
349
|
+
sourceCode, // eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
348
350
|
(call.callee as TSESTree.MemberExpression).object,
|
|
349
|
-
sourceCode,
|
|
350
351
|
);
|
|
351
352
|
|
|
352
353
|
// A node's text never includes the parentheses the source put around it:
|
|
@@ -358,7 +359,7 @@ export const preferArrScan: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
358
359
|
? `(${elementText})`
|
|
359
360
|
: elementText;
|
|
360
361
|
|
|
361
|
-
return `Arr.scan(${arrayText}, (${parameterText}) => ${bodyText}, ${
|
|
362
|
+
return `Arr.scan(${arrayText}, (${parameterText}) => ${bodyText}, ${getArgumentText(sourceCode, seed)})`;
|
|
362
363
|
};
|
|
363
364
|
|
|
364
365
|
/**
|
|
@@ -493,7 +494,8 @@ export const preferArrScan: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
493
494
|
// been seen by the time its `map` is judged, whichever order the traversal
|
|
494
495
|
// reached them in.
|
|
495
496
|
'Program:exit': () => {
|
|
496
|
-
const hasArrImport =
|
|
497
|
+
const hasArrImport =
|
|
498
|
+
getNamedImports(tsDataForgeImports).includes('Arr');
|
|
497
499
|
|
|
498
500
|
// The import is inserted once per pass: two fixes writing the same
|
|
499
501
|
// insertion point would otherwise produce it twice.
|
|
@@ -514,9 +516,12 @@ export const preferArrScan: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
514
516
|
? undefined
|
|
515
517
|
: (fixer) => [
|
|
516
518
|
...(call === mut_importNeededBy
|
|
517
|
-
?
|
|
518
|
-
|
|
519
|
-
|
|
519
|
+
? buildNamedImportFix(
|
|
520
|
+
fixer,
|
|
521
|
+
program,
|
|
522
|
+
TS_DATA_FORGE_MODULE,
|
|
523
|
+
['Arr'],
|
|
524
|
+
)
|
|
520
525
|
: []),
|
|
521
526
|
fixer.replaceText(call, replacement),
|
|
522
527
|
],
|
|
@@ -3,18 +3,17 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import { Arr, pipe } from 'ts-data-forge';
|
|
7
|
-
import type { TypeReference } from 'typescript';
|
|
8
6
|
import {
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getArgumentText,
|
|
9
|
+
getImportDeclarations,
|
|
10
|
+
getNamedImports,
|
|
9
11
|
skipTypeWrappers,
|
|
10
|
-
toArgumentText,
|
|
11
12
|
typeWrapperLayers,
|
|
12
|
-
} from '
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
getTsDataForgeImport,
|
|
17
|
-
} from './import-utils.mjs';
|
|
13
|
+
} from 'eslint-rule-forge';
|
|
14
|
+
import { Arr, pipe } from 'ts-data-forge';
|
|
15
|
+
import type { TypeReference } from 'typescript';
|
|
16
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
18
17
|
|
|
19
18
|
type Options = readonly [];
|
|
20
19
|
|
|
@@ -41,7 +40,10 @@ export const preferArrSum: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
41
40
|
|
|
42
41
|
const program = sourceCode.ast;
|
|
43
42
|
|
|
44
|
-
const
|
|
43
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
44
|
+
program,
|
|
45
|
+
TS_DATA_FORGE_MODULE,
|
|
46
|
+
);
|
|
45
47
|
|
|
46
48
|
const services = context.sourceCode.parserServices;
|
|
47
49
|
|
|
@@ -264,14 +266,14 @@ export const preferArrSum: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
264
266
|
}
|
|
265
267
|
},
|
|
266
268
|
'Program:exit': () => {
|
|
267
|
-
const namedImports = getNamedImports(
|
|
269
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
268
270
|
|
|
269
271
|
const hasArrImport = namedImports.includes('Arr');
|
|
270
272
|
|
|
271
273
|
for (const [index, nodeInfo] of mut_nodesToFix.entries()) {
|
|
272
|
-
const arrayText =
|
|
273
|
-
nodeInfo.arrayExpression,
|
|
274
|
+
const arrayText = getArgumentText(
|
|
274
275
|
sourceCode,
|
|
276
|
+
nodeInfo.arrayExpression,
|
|
275
277
|
);
|
|
276
278
|
|
|
277
279
|
context.report({
|
|
@@ -289,7 +291,9 @@ export const preferArrSum: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
289
291
|
|
|
290
292
|
const importFixes =
|
|
291
293
|
index === 0 && !hasArrImport
|
|
292
|
-
?
|
|
294
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
295
|
+
'Arr',
|
|
296
|
+
])
|
|
293
297
|
: [];
|
|
294
298
|
|
|
295
299
|
return [
|