eslint-plugin-ts-data-forge 0.8.4 → 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 +10 -9
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
|
|
2
|
+
import { buildNamedImportFix, getArgumentText, getImportDeclarations, getNamedImports, skipTypeWrappers, } from 'eslint-rule-forge';
|
|
2
3
|
import { Arr } from 'ts-data-forge';
|
|
3
|
-
import {
|
|
4
|
-
import { buildImportFixes, getNamedImports, getTsDataForgeImport, } from './import-utils.mjs';
|
|
4
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
5
5
|
export const preferRangeForLoop = {
|
|
6
6
|
meta: {
|
|
7
7
|
type: 'suggestion',
|
|
@@ -17,7 +17,7 @@ export const preferRangeForLoop = {
|
|
|
17
17
|
create: (context) => {
|
|
18
18
|
const sourceCode = context.sourceCode;
|
|
19
19
|
const program = sourceCode.ast;
|
|
20
|
-
const
|
|
20
|
+
const tsDataForgeImports = getImportDeclarations(program, TS_DATA_FORGE_MODULE);
|
|
21
21
|
const mut_nodesToFix = [];
|
|
22
22
|
return {
|
|
23
23
|
ForStatement: (node) => {
|
|
@@ -81,14 +81,14 @@ export const preferRangeForLoop = {
|
|
|
81
81
|
}
|
|
82
82
|
else {
|
|
83
83
|
|
|
84
|
-
mut_step =
|
|
84
|
+
mut_step = getArgumentText(sourceCode, node.update.right);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
else {
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
const beginText =
|
|
91
|
-
const endText =
|
|
90
|
+
const beginText = getArgumentText(sourceCode, beginExpr);
|
|
91
|
+
const endText = getArgumentText(sourceCode, endExpr);
|
|
92
92
|
mut_nodesToFix.push({
|
|
93
93
|
node,
|
|
94
94
|
varName,
|
|
@@ -98,7 +98,7 @@ export const preferRangeForLoop = {
|
|
|
98
98
|
});
|
|
99
99
|
},
|
|
100
100
|
'Program:exit': () => {
|
|
101
|
-
const namedImports = getNamedImports(
|
|
101
|
+
const namedImports = getNamedImports(tsDataForgeImports);
|
|
102
102
|
const hasRangeImport = namedImports.includes('range');
|
|
103
103
|
for (const [index, { node, varName, begin, end, step },] of mut_nodesToFix.entries()) {
|
|
104
104
|
context.report({
|
|
@@ -116,7 +116,7 @@ export const preferRangeForLoop = {
|
|
|
116
116
|
: `${begin}, ${end}, ${step}`;
|
|
117
117
|
const replacement = `for (const ${varName} of range(${rangeArgs})) ${bodyText}`;
|
|
118
118
|
const importFixes = index === 0 && !hasRangeImport
|
|
119
|
-
?
|
|
119
|
+
? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
120
120
|
'range',
|
|
121
121
|
])
|
|
122
122
|
: [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-range-for-loop.mjs","sourceRoot":"","sources":["../../src/rules/prefer-range-for-loop.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"prefer-range-for-loop.mjs","sourceRoot":"","sources":["../../src/rules/prefer-range-for-loop.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-ts-data-forge",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "ESLint rules that steer code toward ts-data-forge idioms.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,17 +34,18 @@
|
|
|
34
34
|
"LICENSE"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@typescript-eslint/utils": "^8.71.
|
|
37
|
+
"@typescript-eslint/utils": "^8.71.1",
|
|
38
|
+
"eslint-rule-forge": "^0.1.0",
|
|
38
39
|
"ts-data-forge": "14.7.1",
|
|
39
40
|
"ts-type-forge": "~9.2.2"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"@typescript-eslint/parser": "8.71.
|
|
43
|
-
"@typescript-eslint/rule-tester": "8.71.
|
|
43
|
+
"@typescript-eslint/parser": "8.71.1",
|
|
44
|
+
"@typescript-eslint/rule-tester": "8.71.1",
|
|
44
45
|
"dedent": "1.7.2",
|
|
45
|
-
"eslint-config-typed": "5.17.
|
|
46
|
-
"eslint-plugin-ts-fortress": "1.3.
|
|
47
|
-
"eslint-plugin-ts-type-forge": "0.8.
|
|
46
|
+
"eslint-config-typed": "5.17.4",
|
|
47
|
+
"eslint-plugin-ts-fortress": "1.3.3",
|
|
48
|
+
"eslint-plugin-ts-type-forge": "0.8.8",
|
|
48
49
|
"prettier": "3.9.9",
|
|
49
50
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
50
51
|
"prettier-plugin-packagejson": "3.0.2",
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
"build": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/build.mts",
|
|
67
68
|
"check:dist:branded-number-types": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/check-branded-number-types.mts",
|
|
68
69
|
"check:ext": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/check-ext.mts",
|
|
69
|
-
"check:lint": "eslint .",
|
|
70
|
+
"check:lint": "oxlint . && eslint .",
|
|
70
71
|
"check:test": "pnpm run z:vitest run",
|
|
71
72
|
"check:test:cov": "pnpm run z:vitest run --coverage",
|
|
72
73
|
"check:types": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
"fix:fmt": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-uncommitted.mts --cwd .",
|
|
75
76
|
"fix:fmt:diff": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-diff-from.mts origin/main --cwd .",
|
|
76
77
|
"fix:fmt:full": "pnpm run z:prettier .",
|
|
77
|
-
"fix:lint": "eslint . --fix",
|
|
78
|
+
"fix:lint": "oxlint . --fix && eslint . --fix",
|
|
78
79
|
"fmt": "pnpm run fix:fmt",
|
|
79
80
|
"gen": "run-s gen:rule-types gen:readme",
|
|
80
81
|
"gen:readme": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/embed-examples.mts",
|
package/src/rules/ast-utils.mts
CHANGED
|
@@ -1,82 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AST_NODE_TYPES,
|
|
3
|
+
ASTUtils,
|
|
3
4
|
type TSESLint,
|
|
4
5
|
type TSESTree,
|
|
5
6
|
} from '@typescript-eslint/utils';
|
|
7
|
+
import {
|
|
8
|
+
isTypeWrapper,
|
|
9
|
+
skipTypeWrappers,
|
|
10
|
+
typeWrapperLayers,
|
|
11
|
+
} from 'eslint-rule-forge';
|
|
6
12
|
import type { DeepReadonly } from 'ts-type-forge';
|
|
7
13
|
|
|
8
|
-
/**
|
|
9
|
-
* `node` with every `as`, `satisfies`, `!` and `<T>` around it taken off: the
|
|
10
|
-
* expression whose value it is. A wrapper changes no value, so a rule judges
|
|
11
|
-
* syntax on this — `xs.length > (0 as number)` compares with the literal `0`
|
|
12
|
-
* — and writes its fix from the original node so the wrapper is kept. A type
|
|
13
|
-
* is another matter: see {@link typeWrapperLayers}. See
|
|
14
|
-
* `docs/writing-lint-rules.md` at the repository root. A copy of
|
|
15
|
-
* `eslint-config-typed`'s `type-wrapper-utils.mts`, since this package is
|
|
16
|
-
* published on its own.
|
|
17
|
-
*/
|
|
18
|
-
export const skipTypeWrappers = <N extends TSESTree.Node>(
|
|
19
|
-
node: N,
|
|
20
|
-
): N | TSESTree.Expression =>
|
|
21
|
-
isTypeWrapper(node) ? skipTypeWrappers(node.expression) : node;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* `node` and every expression inside the type wrappers around it, outermost
|
|
25
|
-
* first: `x as A as B` gives `x as A as B`, `x as A` and `x`.
|
|
26
|
-
*
|
|
27
|
-
* A conclusion a rule draws from a type — that a guard always holds, that a
|
|
28
|
-
* value is an array, that `?? 0` is dead — has to hold for the type of every
|
|
29
|
-
* layer. An assertion therefore only ever makes a rule more cautious: one
|
|
30
|
-
* that widens (`x as string | null`) is the author saying the value may be
|
|
31
|
-
* `null`, and is respected; one that narrows (`x!`, `v as string` on an
|
|
32
|
-
* `unknown`) is a claim the checker cannot verify, and the value's own type
|
|
33
|
-
* still decides.
|
|
34
|
-
*/
|
|
35
|
-
export const typeWrapperLayers = <N extends TSESTree.Node>(
|
|
36
|
-
node: N,
|
|
37
|
-
): readonly (N | TSESTree.Expression)[] =>
|
|
38
|
-
isTypeWrapper(node)
|
|
39
|
-
? ([node, ...typeWrapperLayers(node.expression)] as const)
|
|
40
|
-
: ([node] as const);
|
|
41
|
-
|
|
42
|
-
export const isTypeWrapper = (
|
|
43
|
-
node: DeepReadonly<TSESTree.Node>,
|
|
44
|
-
): node is TypeWrapper => TYPE_WRAPPERS.has(node.type);
|
|
45
|
-
|
|
46
|
-
export type TypeWrapper =
|
|
47
|
-
| TSESTree.TSAsExpression
|
|
48
|
-
| TSESTree.TSNonNullExpression
|
|
49
|
-
| TSESTree.TSSatisfiesExpression
|
|
50
|
-
| TSESTree.TSTypeAssertion;
|
|
51
|
-
|
|
52
|
-
const TYPE_WRAPPERS: ReadonlySet<AST_NODE_TYPES> = new Set([
|
|
53
|
-
AST_NODE_TYPES.TSAsExpression,
|
|
54
|
-
AST_NODE_TYPES.TSNonNullExpression,
|
|
55
|
-
AST_NODE_TYPES.TSSatisfiesExpression,
|
|
56
|
-
AST_NODE_TYPES.TSTypeAssertion,
|
|
57
|
-
]);
|
|
58
|
-
|
|
59
14
|
const isIntegerLiteral = (node: DeepReadonly<TSESTree.Expression>): boolean =>
|
|
60
15
|
node.type === AST_NODE_TYPES.Literal &&
|
|
61
16
|
typeof node.value === 'number' &&
|
|
62
17
|
Number.isInteger(node.value);
|
|
63
18
|
|
|
64
|
-
/**
|
|
65
|
-
* The source text of `node` for an argument position. A node's text never
|
|
66
|
-
* includes the parentheses the source wrote around it, so a comma (sequence)
|
|
67
|
-
* expression gets them back rather than spilling into the next argument.
|
|
68
|
-
*/
|
|
69
|
-
export const toArgumentText = (
|
|
70
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
71
|
-
node: TSESTree.Node,
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
73
|
-
sourceCode: TSESLint.SourceCode,
|
|
74
|
-
): string => {
|
|
75
|
-
const text = sourceCode.getText(node);
|
|
76
|
-
|
|
77
|
-
return node.type === AST_NODE_TYPES.SequenceExpression ? `(${text})` : text;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
19
|
/**
|
|
81
20
|
* Whether `node` is an array or a tuple at every layer of type wrappers (see
|
|
82
21
|
* {@link typeWrapperLayers}): a cast does not make a string an array, and the
|
|
@@ -135,9 +74,9 @@ export const isIntegerLiteralOrConstant = (
|
|
|
135
74
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
136
75
|
const scope = sourceCode.getScope(node as TSESTree.Node);
|
|
137
76
|
|
|
138
|
-
const variable = findVariable(scope, node.name);
|
|
77
|
+
const variable = ASTUtils.findVariable(scope, node.name);
|
|
139
78
|
|
|
140
|
-
if (variable ===
|
|
79
|
+
if (variable === null) {
|
|
141
80
|
return false;
|
|
142
81
|
}
|
|
143
82
|
|
|
@@ -309,16 +248,3 @@ const isVariableDefinition = (
|
|
|
309
248
|
def: TSESLint.Scope.Definition,
|
|
310
249
|
): def is TSESLint.Scope.Definition & VariableDefinition =>
|
|
311
250
|
(def.type as string) === 'Variable';
|
|
312
|
-
|
|
313
|
-
const findVariable = (
|
|
314
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
315
|
-
scope: TSESLint.Scope.Scope,
|
|
316
|
-
name: string,
|
|
317
|
-
): TSESLint.Scope.Variable | undefined => {
|
|
318
|
-
const variable = scope.set.get(name);
|
|
319
|
-
|
|
320
|
-
return (
|
|
321
|
-
variable ??
|
|
322
|
-
(scope.upper === null ? undefined : findVariable(scope.upper, name))
|
|
323
|
-
);
|
|
324
|
-
};
|
|
@@ -4,15 +4,16 @@ import {
|
|
|
4
4
|
type TSESLint,
|
|
5
5
|
type TSESTree,
|
|
6
6
|
} from '@typescript-eslint/utils';
|
|
7
|
-
import type { DeepReadonly, ReadonlyRecord } from 'ts-type-forge';
|
|
8
|
-
import * as ts from 'typescript';
|
|
9
|
-
import { typeWrapperLayers } from './ast-utils.mjs';
|
|
10
7
|
import {
|
|
11
8
|
buildCalleeResolver,
|
|
12
|
-
|
|
9
|
+
buildNamedImportFix,
|
|
10
|
+
getImportDeclarations,
|
|
13
11
|
getImportedLocalName,
|
|
14
|
-
|
|
15
|
-
} from '
|
|
12
|
+
typeWrapperLayers,
|
|
13
|
+
} from 'eslint-rule-forge';
|
|
14
|
+
import type { DeepReadonly, ReadonlyRecord } from 'ts-type-forge';
|
|
15
|
+
import * as ts from 'typescript';
|
|
16
|
+
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
16
17
|
|
|
17
18
|
type Options = readonly [
|
|
18
19
|
Readonly<{
|
|
@@ -169,9 +170,12 @@ export const noUnnecessaryTypeGuard: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
169
170
|
|
|
170
171
|
const ignored = new Set(options?.ignore);
|
|
171
172
|
|
|
172
|
-
const
|
|
173
|
+
const tsDataForgeImports = getImportDeclarations(
|
|
174
|
+
program,
|
|
175
|
+
TS_DATA_FORGE_MODULE,
|
|
176
|
+
);
|
|
173
177
|
|
|
174
|
-
const resolveGuard = buildCalleeResolver(
|
|
178
|
+
const resolveGuard = buildCalleeResolver(tsDataForgeImports);
|
|
175
179
|
|
|
176
180
|
const buildReplaceFix =
|
|
177
181
|
(
|
|
@@ -191,7 +195,7 @@ export const noUnnecessaryTypeGuard: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
191
195
|
// alias), rename to its in-scope local name. Otherwise add a new
|
|
192
196
|
// import and rename to the canonical name.
|
|
193
197
|
const localName = getImportedLocalName(
|
|
194
|
-
|
|
198
|
+
tsDataForgeImports,
|
|
195
199
|
replacement,
|
|
196
200
|
);
|
|
197
201
|
|
|
@@ -200,7 +204,7 @@ export const noUnnecessaryTypeGuard: TSESLint.RuleModule<MessageIds, Options> =
|
|
|
200
204
|
}
|
|
201
205
|
|
|
202
206
|
return [
|
|
203
|
-
...
|
|
207
|
+
...buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
|
|
204
208
|
replacement,
|
|
205
209
|
]),
|
|
206
210
|
fixer.replaceText(propertyNode, replacement),
|
|
@@ -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)];
|
|
@@ -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)];
|
|
@@ -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)];
|