eslint-plugin-ts-data-forge 0.8.5 → 0.8.6
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/dist/rules/ast-utils.d.mts +0 -32
- package/dist/rules/ast-utils.d.mts.map +1 -1
- package/dist/rules/ast-utils.mjs +4 -56
- package/dist/rules/ast-utils.mjs.map +1 -1
- 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-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 +11 -18
- 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 +10 -6
- 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 +5 -5
- 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 +5 -5
- 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 +8 -8
- package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
- package/package.json +5 -4
- package/src/rules/ast-utils.mts +8 -82
- package/src/rules/no-unnecessary-type-guard.mts +14 -10
- 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-fixed-length-array.mts +17 -11
- package/src/rules/prefer-arr-is-max-length-array.mts +17 -11
- package/src/rules/prefer-arr-is-min-length-array.mts +17 -11
- 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 +24 -28
- package/src/rules/prefer-as-int.mts +19 -12
- package/src/rules/prefer-canonical-array-slicing.mts +22 -12
- 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 +11 -7
- package/src/rules/prefer-is-record-and-has-key.mts +14 -10
- 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 +16 -11
- 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,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 [
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AST_NODE_TYPES,
|
|
3
|
+
ASTUtils,
|
|
3
4
|
type TSESLint,
|
|
4
5
|
type TSESTree,
|
|
5
6
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import { Arr } from 'ts-data-forge';
|
|
7
|
-
import * as ts from 'typescript';
|
|
8
|
-
import { skipTypeWrappers, typeWrapperLayers } from './ast-utils.mjs';
|
|
9
7
|
import {
|
|
10
|
-
|
|
8
|
+
buildNamedImportFix,
|
|
9
|
+
getArgumentText,
|
|
10
|
+
getImportDeclarations,
|
|
11
11
|
getImportedLocalName,
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
skipTypeWrappers,
|
|
13
|
+
typeWrapperLayers,
|
|
14
|
+
} from 'eslint-rule-forge';
|
|
15
|
+
import { Arr } from 'ts-data-forge';
|
|
16
|
+
import * as ts from 'typescript';
|
|
17
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
14
18
|
|
|
15
19
|
type Options = readonly [];
|
|
16
20
|
|
|
@@ -47,7 +51,10 @@ export const preferArrUniq: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
47
51
|
|
|
48
52
|
const program = sourceCode.ast;
|
|
49
53
|
|
|
50
|
-
const
|
|
54
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
55
|
+
program,
|
|
56
|
+
TS_DATA_FORGE_MODULE,
|
|
57
|
+
);
|
|
51
58
|
|
|
52
59
|
const services = sourceCode.parserServices;
|
|
53
60
|
|
|
@@ -150,7 +157,7 @@ export const preferArrUniq: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
150
157
|
check(node, element.argument);
|
|
151
158
|
},
|
|
152
159
|
'Program:exit': () => {
|
|
153
|
-
const arrLocalName = getImportedLocalName(
|
|
160
|
+
const arrLocalName = getImportedLocalName(tsDataForgeImports, 'Arr');
|
|
154
161
|
|
|
155
162
|
const arrName = arrLocalName ?? 'Arr';
|
|
156
163
|
|
|
@@ -162,16 +169,18 @@ export const preferArrUniq: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
162
169
|
for (const match of mut_matches) {
|
|
163
170
|
const arrayText = sourceCode.getText(match.arrayExpression);
|
|
164
171
|
|
|
165
|
-
const argumentText =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
172
|
+
const argumentText = getArgumentText(
|
|
173
|
+
sourceCode,
|
|
174
|
+
match.arrayExpression,
|
|
175
|
+
);
|
|
169
176
|
|
|
170
177
|
const buildFix =
|
|
171
178
|
(withImport: boolean): TSESLint.ReportFixFunction =>
|
|
172
179
|
(fixer) => [
|
|
173
180
|
...(withImport && arrLocalName === undefined
|
|
174
|
-
?
|
|
181
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
182
|
+
'Arr',
|
|
183
|
+
])
|
|
175
184
|
: []),
|
|
176
185
|
fixer.replaceText(match.node, `${arrName}.uniq(${argumentText})`),
|
|
177
186
|
];
|
|
@@ -254,23 +263,10 @@ const isGlobal = (
|
|
|
254
263
|
node: TSESTree.Node,
|
|
255
264
|
name: string,
|
|
256
265
|
): boolean => {
|
|
257
|
-
const variable = findVariable(sourceCode.getScope(node), name);
|
|
266
|
+
const variable = ASTUtils.findVariable(sourceCode.getScope(node), name);
|
|
258
267
|
|
|
259
268
|
// Globals from the TypeScript lib are implicit variables with no definition.
|
|
260
|
-
return variable ===
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const findVariable = (
|
|
264
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
265
|
-
scope: TSESLint.Scope.Scope,
|
|
266
|
-
name: string,
|
|
267
|
-
): TSESLint.Scope.Variable | undefined => {
|
|
268
|
-
const variable = scope.set.get(name);
|
|
269
|
-
|
|
270
|
-
return (
|
|
271
|
-
variable ??
|
|
272
|
-
(scope.upper === null ? undefined : findVariable(scope.upper, name))
|
|
273
|
-
);
|
|
269
|
+
return variable === null || variable.defs.length === 0;
|
|
274
270
|
};
|
|
275
271
|
|
|
276
272
|
/**
|
|
@@ -3,14 +3,15 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import type { DeepReadonly } from 'ts-type-forge';
|
|
7
|
-
import { toArgumentText } from './ast-utils.mjs';
|
|
8
|
-
import { brandedNumberTypeNameToFunctionName } from './branded-number-types.mjs';
|
|
9
6
|
import {
|
|
10
|
-
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getArgumentText,
|
|
9
|
+
getImportDeclarations,
|
|
11
10
|
getNamedImports,
|
|
12
|
-
|
|
13
|
-
} from '
|
|
11
|
+
} from 'eslint-rule-forge';
|
|
12
|
+
import type { DeepReadonly } from 'ts-type-forge';
|
|
13
|
+
import { brandedNumberTypeNameToFunctionName } from './branded-number-types.mjs';
|
|
14
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
14
15
|
|
|
15
16
|
type Options = readonly [];
|
|
16
17
|
|
|
@@ -36,7 +37,10 @@ export const preferAsInt: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
36
37
|
|
|
37
38
|
const program = sourceCode.ast;
|
|
38
39
|
|
|
39
|
-
const
|
|
40
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
41
|
+
program,
|
|
42
|
+
TS_DATA_FORGE_MODULE,
|
|
43
|
+
);
|
|
40
44
|
|
|
41
45
|
const mut_nodesToFix: {
|
|
42
46
|
node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion;
|
|
@@ -66,7 +70,7 @@ export const preferAsInt: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
66
70
|
TSAsExpression: collect,
|
|
67
71
|
TSTypeAssertion: collect,
|
|
68
72
|
'Program:exit': () => {
|
|
69
|
-
const namedImports = getNamedImports(
|
|
73
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
70
74
|
|
|
71
75
|
// Group nodes by function name to handle imports efficiently
|
|
72
76
|
const functionNameToNodes = Map.groupBy(
|
|
@@ -87,14 +91,17 @@ export const preferAsInt: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
87
91
|
functionName,
|
|
88
92
|
},
|
|
89
93
|
fix: (fixer) => {
|
|
90
|
-
const replacement = `${functionName}(${
|
|
94
|
+
const replacement = `${functionName}(${getArgumentText(sourceCode, node.expression)})`;
|
|
91
95
|
|
|
92
96
|
// Add import only for the first node of this function and only if not already imported
|
|
93
97
|
const importFixes =
|
|
94
98
|
index === 0 && !hasImport
|
|
95
|
-
?
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
? buildNamedImportFix(
|
|
100
|
+
fixer,
|
|
101
|
+
program,
|
|
102
|
+
TS_DATA_FORGE_MODULE,
|
|
103
|
+
[functionName],
|
|
104
|
+
)
|
|
98
105
|
: [];
|
|
99
106
|
|
|
100
107
|
return [...importFixes, fixer.replaceText(node, replacement)];
|
|
@@ -4,14 +4,16 @@ import {
|
|
|
4
4
|
type TSESLint,
|
|
5
5
|
type TSESTree,
|
|
6
6
|
} from '@typescript-eslint/utils';
|
|
7
|
-
import type { ReadonlyRecord } from 'ts-type-forge';
|
|
8
|
-
import * as ts from 'typescript';
|
|
9
|
-
import { skipTypeWrappers, typeWrapperLayers } from './ast-utils.mjs';
|
|
10
7
|
import {
|
|
11
|
-
|
|
8
|
+
buildNamedImportFix,
|
|
9
|
+
getImportDeclarations,
|
|
12
10
|
getImportedLocalName,
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
skipTypeWrappers,
|
|
12
|
+
typeWrapperLayers,
|
|
13
|
+
} from 'eslint-rule-forge';
|
|
14
|
+
import type { ReadonlyRecord } from 'ts-type-forge';
|
|
15
|
+
import * as ts from 'typescript';
|
|
16
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
15
17
|
|
|
16
18
|
/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
|
|
17
19
|
|
|
@@ -188,7 +190,10 @@ export const preferCanonicalArraySlicing: TSESLint.RuleModule<
|
|
|
188
190
|
|
|
189
191
|
const program = sourceCode.ast;
|
|
190
192
|
|
|
191
|
-
const
|
|
193
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
194
|
+
program,
|
|
195
|
+
TS_DATA_FORGE_MODULE,
|
|
196
|
+
);
|
|
192
197
|
|
|
193
198
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
194
199
|
|
|
@@ -199,11 +204,14 @@ export const preferCanonicalArraySlicing: TSESLint.RuleModule<
|
|
|
199
204
|
* (possibly aliased), a namespace import member, or the canonical `Arr`
|
|
200
205
|
* (added by the import fix when nothing is imported yet).
|
|
201
206
|
*/
|
|
202
|
-
const arrLocalName = getImportedLocalName(
|
|
207
|
+
const arrLocalName = getImportedLocalName(tsDataForgeImports, 'Arr');
|
|
203
208
|
|
|
204
|
-
const namespaceLocalName =
|
|
205
|
-
(
|
|
206
|
-
|
|
209
|
+
const namespaceLocalName = tsDataForgeImports
|
|
210
|
+
.flatMap((declaration) => declaration.specifiers)
|
|
211
|
+
.find(
|
|
212
|
+
(specifier) =>
|
|
213
|
+
specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier,
|
|
214
|
+
)?.local.name;
|
|
207
215
|
|
|
208
216
|
const arrRef =
|
|
209
217
|
arrLocalName ??
|
|
@@ -837,7 +845,9 @@ export const preferCanonicalArraySlicing: TSESLint.RuleModule<
|
|
|
837
845
|
fix: (fixer) => {
|
|
838
846
|
const importFixes =
|
|
839
847
|
index === 0 && needsArrImport
|
|
840
|
-
?
|
|
848
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
849
|
+
'Arr',
|
|
850
|
+
])
|
|
841
851
|
: [];
|
|
842
852
|
|
|
843
853
|
return [
|
|
@@ -4,8 +4,12 @@ import {
|
|
|
4
4
|
type TSESLint,
|
|
5
5
|
type TSESTree,
|
|
6
6
|
} from '@typescript-eslint/utils';
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
getImportDeclarations,
|
|
9
|
+
getImportedLocalName,
|
|
10
|
+
skipTypeWrappers,
|
|
11
|
+
} from 'eslint-rule-forge';
|
|
12
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
9
13
|
|
|
10
14
|
type Options = readonly [];
|
|
11
15
|
|
|
@@ -143,7 +147,7 @@ export const preferCanonicalLengthCast: TSESLint.RuleModule<
|
|
|
143
147
|
const sourceCode = context.sourceCode;
|
|
144
148
|
|
|
145
149
|
const arrLocalName = getImportedLocalName(
|
|
146
|
-
|
|
150
|
+
getImportDeclarations(sourceCode.ast, TS_DATA_FORGE_MODULE),
|
|
147
151
|
'Arr',
|
|
148
152
|
);
|
|
149
153
|
|
|
@@ -3,9 +3,14 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
+
import {
|
|
7
|
+
getArgumentText,
|
|
8
|
+
getImportDeclarations,
|
|
9
|
+
getImportedLocalName,
|
|
10
|
+
skipTypeWrappers,
|
|
11
|
+
} from 'eslint-rule-forge';
|
|
6
12
|
import type { MutableRecord, ReadonlyRecord } from 'ts-type-forge';
|
|
7
|
-
import {
|
|
8
|
-
import { getImportedLocalName, getTsDataForgeImport } from './import-utils.mjs';
|
|
13
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
9
14
|
import { preferArrIsBoundedLengthArray } from './prefer-arr-is-bounded-length-array.mjs';
|
|
10
15
|
import { preferArrIsFixedLengthArray } from './prefer-arr-is-fixed-length-array.mjs';
|
|
11
16
|
import { preferArrIsMaxLengthArray } from './prefer-arr-is-max-length-array.mjs';
|
|
@@ -117,7 +122,7 @@ export const preferCanonicalLengthGuard: TSESLint.RuleModule<
|
|
|
117
122
|
const sourceCode = context.sourceCode;
|
|
118
123
|
|
|
119
124
|
const arrLocalName = getImportedLocalName(
|
|
120
|
-
|
|
125
|
+
getImportDeclarations(sourceCode.ast, TS_DATA_FORGE_MODULE),
|
|
121
126
|
'Arr',
|
|
122
127
|
);
|
|
123
128
|
|
|
@@ -154,7 +159,7 @@ export const preferCanonicalLengthGuard: TSESLint.RuleModule<
|
|
|
154
159
|
return;
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
const arrayText =
|
|
162
|
+
const arrayText = getArgumentText(sourceCode, array);
|
|
158
163
|
|
|
159
164
|
context.report({
|
|
160
165
|
node,
|
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
+
import { buildCalleeResolver, getImportDeclarations } from 'eslint-rule-forge';
|
|
6
7
|
import type { DeepReadonly, ReadonlyRecord } from 'ts-type-forge';
|
|
7
|
-
import {
|
|
8
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
8
9
|
|
|
9
10
|
type Options = readonly [];
|
|
10
11
|
|
|
@@ -121,7 +122,7 @@ export const preferComparisonOverNullishGuard: TSESLint.RuleModule<
|
|
|
121
122
|
const sourceCode = context.sourceCode;
|
|
122
123
|
|
|
123
124
|
const resolveGuard = buildCalleeResolver(
|
|
124
|
-
|
|
125
|
+
getImportDeclarations(sourceCode.ast, TS_DATA_FORGE_MODULE),
|
|
125
126
|
);
|
|
126
127
|
|
|
127
128
|
return {
|
|
@@ -49,6 +49,22 @@ describe('prefer-comparison-over-nullish-guard', () => {
|
|
|
49
49
|
},
|
|
50
50
|
],
|
|
51
51
|
invalid: [
|
|
52
|
+
{
|
|
53
|
+
name: 'the guard imported by a second ts-data-forge declaration',
|
|
54
|
+
code: dedent`
|
|
55
|
+
import type { Optional } from 'ts-data-forge';
|
|
56
|
+
import { isUndefined } from 'ts-data-forge';
|
|
57
|
+
declare const x: string | undefined;
|
|
58
|
+
const y = isUndefined(x);
|
|
59
|
+
`,
|
|
60
|
+
output: dedent`
|
|
61
|
+
import type { Optional } from 'ts-data-forge';
|
|
62
|
+
import { isUndefined } from 'ts-data-forge';
|
|
63
|
+
declare const x: string | undefined;
|
|
64
|
+
const y = x === undefined;
|
|
65
|
+
`,
|
|
66
|
+
errors: [{ messageId: 'preferComparison' }],
|
|
67
|
+
},
|
|
52
68
|
{
|
|
53
69
|
name: 'isNotUndefined with explicit argument',
|
|
54
70
|
code: dedent`
|
|
@@ -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 preferIsNonNullObject: 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: {
|
|
40
44
|
node: TSESTree.LogicalExpression;
|
|
@@ -54,7 +58,7 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
54
58
|
'Program:exit': () => {
|
|
55
59
|
// Check if isNonNullObject is already imported
|
|
56
60
|
const hasIsNonNullObjectImport =
|
|
57
|
-
getNamedImports(
|
|
61
|
+
getNamedImports(tsDataForgeImports).includes('isNonNullObject');
|
|
58
62
|
|
|
59
63
|
// Note: We add import only for the first node to avoid conflicts when
|
|
60
64
|
// multiple fixes try to insert at the same position. This means if the
|
|
@@ -73,7 +77,7 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
73
77
|
// Add import only for the first node and only if not already imported
|
|
74
78
|
const importFixes =
|
|
75
79
|
index === 0 && !hasIsNonNullObjectImport
|
|
76
|
-
?
|
|
80
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
77
81
|
'isNonNullObject',
|
|
78
82
|
])
|
|
79
83
|
: [];
|
|
@@ -3,14 +3,15 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import { Arr } from 'ts-data-forge';
|
|
7
|
-
import * as ts from 'typescript';
|
|
8
|
-
import { typeWrapperLayers } from './ast-utils.mjs';
|
|
9
6
|
import {
|
|
10
|
-
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getImportDeclarations,
|
|
11
9
|
getNamedImports,
|
|
12
|
-
|
|
13
|
-
} from '
|
|
10
|
+
typeWrapperLayers,
|
|
11
|
+
} from 'eslint-rule-forge';
|
|
12
|
+
import { Arr } from 'ts-data-forge';
|
|
13
|
+
import * as ts from 'typescript';
|
|
14
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
14
15
|
|
|
15
16
|
type Options = readonly [];
|
|
16
17
|
|
|
@@ -39,7 +40,10 @@ export const preferIsRecordAndHasKey: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
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 = sourceCode.parserServices;
|
|
45
49
|
|
|
@@ -141,7 +145,7 @@ export const preferIsRecordAndHasKey: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
141
145
|
},
|
|
142
146
|
|
|
143
147
|
'Program:exit': () => {
|
|
144
|
-
const namedImports = getNamedImports(
|
|
148
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
145
149
|
|
|
146
150
|
const rewrites = mut_nodesToFix.map((entry) => ({
|
|
147
151
|
...entry,
|
|
@@ -186,10 +190,10 @@ export const preferIsRecordAndHasKey: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
186
190
|
// otherwise and only one of them would survive a pass.
|
|
187
191
|
const importFixes =
|
|
188
192
|
index === 0 && importsToAdd.length > 0
|
|
189
|
-
?
|
|
193
|
+
? buildNamedImportFix(
|
|
190
194
|
fixer,
|
|
191
195
|
program,
|
|
192
|
-
|
|
196
|
+
TS_DATA_FORGE_MODULE,
|
|
193
197
|
importsToAdd,
|
|
194
198
|
)
|
|
195
199
|
: [];
|
|
@@ -3,13 +3,15 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import * as ts from 'typescript';
|
|
7
|
-
import { toArgumentText, typeWrapperLayers } from './ast-utils.mjs';
|
|
8
6
|
import {
|
|
9
|
-
|
|
7
|
+
buildNamedImportFix,
|
|
8
|
+
getArgumentText,
|
|
9
|
+
getImportDeclarations,
|
|
10
10
|
getNamedImports,
|
|
11
|
-
|
|
12
|
-
} from '
|
|
11
|
+
typeWrapperLayers,
|
|
12
|
+
} from 'eslint-rule-forge';
|
|
13
|
+
import * as ts from 'typescript';
|
|
14
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
13
15
|
|
|
14
16
|
type Options = readonly [];
|
|
15
17
|
|
|
@@ -62,7 +64,10 @@ export const preferNumSafeParseFloat: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
62
64
|
|
|
63
65
|
const program = sourceCode.ast;
|
|
64
66
|
|
|
65
|
-
const
|
|
67
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
68
|
+
program,
|
|
69
|
+
TS_DATA_FORGE_MODULE,
|
|
70
|
+
);
|
|
66
71
|
|
|
67
72
|
const services = context.sourceCode.parserServices;
|
|
68
73
|
|
|
@@ -145,7 +150,7 @@ export const preferNumSafeParseFloat: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
145
150
|
mut_nodesToFix.push({ node, argExpression: firstArg });
|
|
146
151
|
},
|
|
147
152
|
'Program:exit': () => {
|
|
148
|
-
const namedImports = getNamedImports(
|
|
153
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
149
154
|
|
|
150
155
|
const missingImports = (['Num', 'Result'] as const).filter(
|
|
151
156
|
(name) => !namedImports.includes(name),
|
|
@@ -155,7 +160,7 @@ export const preferNumSafeParseFloat: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
155
160
|
index,
|
|
156
161
|
{ node, argExpression },
|
|
157
162
|
] of mut_nodesToFix.entries()) {
|
|
158
|
-
const argText =
|
|
163
|
+
const argText = getArgumentText(sourceCode, argExpression);
|
|
159
164
|
|
|
160
165
|
const originalText = sourceCode.getText(node);
|
|
161
166
|
|
|
@@ -171,10 +176,10 @@ export const preferNumSafeParseFloat: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
171
176
|
|
|
172
177
|
const importFixes =
|
|
173
178
|
index === 0 && missingImports.length > 0
|
|
174
|
-
?
|
|
179
|
+
? buildNamedImportFix(
|
|
175
180
|
fixer,
|
|
176
181
|
program,
|
|
177
|
-
|
|
182
|
+
TS_DATA_FORGE_MODULE,
|
|
178
183
|
missingImports,
|
|
179
184
|
)
|
|
180
185
|
: [];
|