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
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AST_NODE_TYPES,
|
|
3
|
-
type TSESLint,
|
|
4
|
-
type TSESTree,
|
|
5
|
-
} from '@typescript-eslint/utils';
|
|
6
|
-
import type { DeepReadonly } from 'ts-type-forge';
|
|
7
|
-
import { isTypeWrapper } from './ast-utils.mjs';
|
|
8
|
-
import { TS_DATA_FORGE_MODULE } from './constants.mjs';
|
|
9
|
-
|
|
10
|
-
/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
|
|
11
|
-
|
|
12
|
-
export const getTsDataForgeImport = (
|
|
13
|
-
program: TSESTree.Program,
|
|
14
|
-
): TSESTree.ImportDeclaration | undefined =>
|
|
15
|
-
program.body.find(
|
|
16
|
-
(node): node is TSESTree.ImportDeclaration =>
|
|
17
|
-
node.type === AST_NODE_TYPES.ImportDeclaration &&
|
|
18
|
-
node.source.value === TS_DATA_FORGE_MODULE,
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
export const getNamedImports = (
|
|
22
|
-
node: DeepReadonly<TSESTree.ImportDeclaration> | undefined,
|
|
23
|
-
): readonly string[] => {
|
|
24
|
-
if (node === undefined) {
|
|
25
|
-
return [];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return node.specifiers.flatMap((specifier) =>
|
|
29
|
-
specifier.type === AST_NODE_TYPES.ImportSpecifier
|
|
30
|
-
? (() => {
|
|
31
|
-
const importedName =
|
|
32
|
-
specifier.imported.type === AST_NODE_TYPES.Identifier
|
|
33
|
-
? specifier.imported.name
|
|
34
|
-
: specifier.imported.value;
|
|
35
|
-
|
|
36
|
-
return typeof importedName === 'string' ? [importedName] : [];
|
|
37
|
-
})()
|
|
38
|
-
: [],
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Returns the in-scope local name a given canonical export is imported as
|
|
44
|
-
* (handling aliases such as `import { isX as y }` → `'y'`), or `undefined` when
|
|
45
|
-
* it is not imported. Used so autofixes reference the binding that actually
|
|
46
|
-
* exists rather than the canonical name.
|
|
47
|
-
*/
|
|
48
|
-
export const getImportedLocalName = (
|
|
49
|
-
node: DeepReadonly<TSESTree.ImportDeclaration> | undefined,
|
|
50
|
-
importedName: string,
|
|
51
|
-
): string | undefined =>
|
|
52
|
-
node?.specifiers.find(
|
|
53
|
-
(specifier) =>
|
|
54
|
-
specifier.type === AST_NODE_TYPES.ImportSpecifier &&
|
|
55
|
-
(specifier.imported.type === AST_NODE_TYPES.Identifier
|
|
56
|
-
? specifier.imported.name
|
|
57
|
-
: specifier.imported.value) === importedName,
|
|
58
|
-
)?.local.name;
|
|
59
|
-
|
|
60
|
-
type ResolvedCallee = Readonly<{
|
|
61
|
-
/** The canonical (imported) ts-data-forge name, regardless of local alias. */
|
|
62
|
-
canonicalName: string;
|
|
63
|
-
/** The identifier node to rewrite when replacing the callee name. */
|
|
64
|
-
propertyNode: TSESTree.Node;
|
|
65
|
-
/** Whether the call was made through a namespace import (`tf.isX(...)`). */
|
|
66
|
-
isNamespace: boolean;
|
|
67
|
-
}>;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Builds a resolver that maps a call expression's callee to the canonical
|
|
71
|
-
* ts-data-forge function it refers to. Handles named imports (including aliases
|
|
72
|
-
* such as `import { isX as y }`) and namespace imports (`import * as tf` →
|
|
73
|
-
* `tf.isX(...)`). Returns `undefined` for any callee that does not reference the
|
|
74
|
-
* given ts-data-forge import.
|
|
75
|
-
*/
|
|
76
|
-
export const buildCalleeResolver = (
|
|
77
|
-
importDecl: TSESTree.ImportDeclaration | undefined,
|
|
78
|
-
): ((
|
|
79
|
-
callee: DeepReadonly<TSESTree.Expression>,
|
|
80
|
-
) => ResolvedCallee | undefined) => {
|
|
81
|
-
const specifiers = importDecl?.specifiers ?? [];
|
|
82
|
-
|
|
83
|
-
const namespaceName = specifiers.find(
|
|
84
|
-
(specifier) => specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier,
|
|
85
|
-
)?.local.name;
|
|
86
|
-
|
|
87
|
-
const localToCanonical = new Map<string, string>(
|
|
88
|
-
specifiers.flatMap((specifier) => {
|
|
89
|
-
if (specifier.type !== AST_NODE_TYPES.ImportSpecifier) {
|
|
90
|
-
return [];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const importedName =
|
|
94
|
-
specifier.imported.type === AST_NODE_TYPES.Identifier
|
|
95
|
-
? specifier.imported.name
|
|
96
|
-
: specifier.imported.value;
|
|
97
|
-
|
|
98
|
-
return typeof importedName === 'string'
|
|
99
|
-
? [[specifier.local.name, importedName] as const]
|
|
100
|
-
: [];
|
|
101
|
-
}),
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
// `(isNull as (u: unknown) => boolean)(x)` and `(tf as typeof tf).isNull(x)`
|
|
105
|
-
// still call `isNull`: both the callee and a namespace object are read
|
|
106
|
-
// through type wrappers.
|
|
107
|
-
const resolve = (
|
|
108
|
-
callee: DeepReadonly<TSESTree.Expression>,
|
|
109
|
-
): ResolvedCallee | undefined => {
|
|
110
|
-
if (isTypeWrapper(callee)) {
|
|
111
|
-
return resolve(callee.expression);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (callee.type === AST_NODE_TYPES.Identifier) {
|
|
115
|
-
const canonicalName = localToCanonical.get(callee.name);
|
|
116
|
-
|
|
117
|
-
return canonicalName === undefined
|
|
118
|
-
? undefined
|
|
119
|
-
: {
|
|
120
|
-
canonicalName,
|
|
121
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
122
|
-
propertyNode: callee as TSESTree.Node,
|
|
123
|
-
isNamespace: false,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
namespaceName === undefined ||
|
|
129
|
-
callee.type !== AST_NODE_TYPES.MemberExpression ||
|
|
130
|
-
callee.computed ||
|
|
131
|
-
callee.property.type !== AST_NODE_TYPES.Identifier
|
|
132
|
-
) {
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const object = skipReadonlyTypeWrappers(callee.object);
|
|
137
|
-
|
|
138
|
-
return object.type === AST_NODE_TYPES.Identifier &&
|
|
139
|
-
object.name === namespaceName
|
|
140
|
-
? {
|
|
141
|
-
canonicalName: callee.property.name,
|
|
142
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
143
|
-
propertyNode: callee.property as TSESTree.Node,
|
|
144
|
-
isNamespace: true,
|
|
145
|
-
}
|
|
146
|
-
: undefined;
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
return resolve;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const skipReadonlyTypeWrappers = (
|
|
153
|
-
node: DeepReadonly<TSESTree.Expression>,
|
|
154
|
-
): DeepReadonly<TSESTree.Expression> =>
|
|
155
|
-
isTypeWrapper(node) ? skipReadonlyTypeWrappers(node.expression) : node;
|
|
156
|
-
|
|
157
|
-
export const buildImportFixes = (
|
|
158
|
-
fixer: TSESLint.RuleFixer,
|
|
159
|
-
program: TSESTree.Program,
|
|
160
|
-
_tsDataForgeImport: TSESTree.ImportDeclaration | undefined,
|
|
161
|
-
requiredNames: readonly string[],
|
|
162
|
-
): readonly TSESLint.RuleFix[] => {
|
|
163
|
-
const specifierText = requiredNames.join(', ');
|
|
164
|
-
|
|
165
|
-
const importStatement =
|
|
166
|
-
`import { ${specifierText} } from '${TS_DATA_FORGE_MODULE}';` as const;
|
|
167
|
-
|
|
168
|
-
const newLine = '\n';
|
|
169
|
-
|
|
170
|
-
const insertionText = `${importStatement}${newLine}` as const;
|
|
171
|
-
|
|
172
|
-
// Always insert at the beginning of the file
|
|
173
|
-
// (organize-imports will handle merging/deduplication)
|
|
174
|
-
return [fixer.insertTextBefore(program, insertionText)];
|
|
175
|
-
};
|