eslint-plugin-ts-type-forge 0.8.0 → 0.8.1
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/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/plugin.mjs +34 -31
- package/dist/plugin.mjs.map +1 -1
- package/dist/rule-types.mjs +2 -1
- package/dist/rule-types.mjs.map +1 -1
- package/dist/rules/ast-utils.mjs +224 -103
- package/dist/rules/ast-utils.mjs.map +1 -1
- package/dist/rules/constants.mjs +14 -11
- package/dist/rules/constants.mjs.map +1 -1
- package/dist/rules/import-style.mjs +31 -26
- package/dist/rules/import-style.mjs.map +1 -1
- package/dist/rules/import-utils.mjs +49 -29
- package/dist/rules/import-utils.mjs.map +1 -1
- package/dist/rules/index.mjs +2 -2
- package/dist/rules/index.mjs.map +1 -1
- package/dist/rules/no-side-effect-import.mjs +48 -34
- package/dist/rules/no-side-effect-import.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-constrained-tuple.mjs +93 -73
- package/dist/rules/prefer-canonical-length-constrained-tuple.mjs.map +1 -1
- package/dist/rules/prefer-canonical-mutable-record.mjs +88 -75
- package/dist/rules/prefer-canonical-mutable-record.mjs.map +1 -1
- package/dist/rules/prefer-readonly-or-mutable-record.mjs +41 -45
- package/dist/rules/prefer-readonly-or-mutable-record.mjs.map +1 -1
- package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs +48 -46
- package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs.map +1 -1
- package/dist/rules/rewrite-rule-utils.mjs +31 -28
- package/dist/rules/rewrite-rule-utils.mjs.map +1 -1
- package/dist/rules/rules.mjs +7 -10
- package/dist/rules/rules.mjs.map +1 -1
- package/dist/rules/std-type-rule-utils.mjs +47 -30
- package/dist/rules/std-type-rule-utils.mjs.map +1 -1
- package/dist/types.mjs +2 -2
- package/dist/types.mjs.map +1 -1
- package/package.json +6 -7
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { eslintPluginTsTypeForge } from './plugin.mjs';
|
|
2
|
-
export { tsTypeForgeRules } from './rules/
|
|
3
|
-
//# sourceMappingURL=index.mjs.map
|
|
2
|
+
export { tsTypeForgeRules } from './rules/index.mjs';
|
|
3
|
+
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAKvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
|
-
import { tsTypeForgeRules } from './rules/
|
|
1
|
+
import { tsTypeForgeRules } from './rules/index.mjs';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
2
7
|
|
|
3
8
|
const recommendedRules = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
'ts-type-forge/no-side-effect-import': 'error',
|
|
10
|
+
'ts-type-forge/prefer-canonical-length-constrained-tuple': 'error',
|
|
11
|
+
'ts-type-forge/prefer-canonical-mutable-record': 'error',
|
|
12
|
+
'ts-type-forge/prefer-readonly-or-mutable-record': 'error',
|
|
13
|
+
'ts-type-forge/prefer-strict-or-relaxed-utility-type': 'error',
|
|
9
14
|
};
|
|
10
15
|
const recommendedConfig = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
const eslintPluginTsTypeForge = {
|
|
26
|
-
meta: {
|
|
27
|
-
name: "eslint-plugin-ts-type-forge"
|
|
28
|
-
},
|
|
29
|
-
rules: tsTypeForgeRules,
|
|
30
|
-
configs: {
|
|
31
|
-
/** Enables every rule of this plugin at `error`. */
|
|
32
|
-
recommended: recommendedConfig
|
|
33
|
-
}
|
|
16
|
+
name: 'ts-type-forge/recommended',
|
|
17
|
+
plugins: {
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
get 'ts-type-forge'() {
|
|
25
|
+
return eslintPluginTsTypeForge;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
rules: recommendedRules,
|
|
34
29
|
};
|
|
30
|
+
export const eslintPluginTsTypeForge = {
|
|
31
|
+
meta: {
|
|
32
|
+
name: 'eslint-plugin-ts-type-forge',
|
|
33
|
+
},
|
|
34
|
+
rules: tsTypeForgeRules,
|
|
35
|
+
configs: {
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
recommended: recommendedConfig,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=plugin.mjs.map
|
package/dist/plugin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","
|
|
1
|
+
{"version":3,"file":"plugin.mjs","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG;IACvB,qCAAqC,EAAE,OAAO;IAC9C,yDAAyD,EAAE,OAAO;IAClE,+CAA+C,EAAE,OAAO;IACxD,iDAAiD,EAAE,OAAO;IAC1D,qDAAqD,EAAE,OAAO;CAG/D,CAAC;AAEF,MAAM,iBAAiB,GAAG;IACxB,IAAI,EAAE,2BAA2B;IACjC,OAAO,EAAE;QACP,uEAAuE;QACvE,yEAAyE;QACzE,wEAAwE;QACxE,mDAAmD;QACnD,0EAA0E;QAC1E,wDAAwD;QACxD,IAAI,eAAe;YACjB,OAAO,uBAAuB,CAAC;QACjC,CAAC;KACF;IACD,KAAK,EAAE,gBAAgB;CACY,CAAC;AAEtC,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,IAAI,EAAE;QACJ,IAAI,EAAE,6BAA6B;KACpC;IACD,KAAK,EAAE,gBAAgB;IACvB,OAAO,EAAE;QACP,oDAAoD;QACpD,WAAW,EAAE,iBAAiB;KAC/B;CAC8B,CAAC"}
|
package/dist/rule-types.mjs
CHANGED
package/dist/rule-types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-types.mjs","
|
|
1
|
+
{"version":3,"file":"rule-types.mjs","sourceRoot":"","sources":["../src/rule-types.mts"],"names":[],"mappings":"AAAA,oBAAoB"}
|
package/dist/rules/ast-utils.mjs
CHANGED
|
@@ -1,123 +1,244 @@
|
|
|
1
|
-
import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils';
|
|
2
|
-
import { Arr,
|
|
1
|
+
import { AST_NODE_TYPES, ASTUtils, } from '@typescript-eslint/utils';
|
|
2
|
+
import { Arr, hasKey, isNonNullObject, isRecord } from 'ts-data-forge';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export const isLocallyBound = (sourceCode, node, name) => {
|
|
15
|
+
const variable = ASTUtils.findVariable(sourceCode.getScope(node), name);
|
|
16
|
+
return variable !== null && Arr.isNonEmpty(variable.defs);
|
|
7
17
|
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
export const analyzeUniformTuple = (tuple, sourceCode) => {
|
|
39
|
+
if (isInConditionalTypeExtendsClause(tuple))
|
|
40
|
+
return undefined;
|
|
41
|
+
const { parent } = tuple;
|
|
42
|
+
const isReadonly = parent.type === AST_NODE_TYPES.TSTypeOperator &&
|
|
43
|
+
parent.operator === 'readonly';
|
|
44
|
+
const elements = tuple.elementTypes;
|
|
45
|
+
const last = elements.at(-1);
|
|
46
|
+
const hasRest = last?.type === AST_NODE_TYPES.TSRestType;
|
|
47
|
+
const leading = hasRest ? Arr.butLast(elements) : elements;
|
|
48
|
+
if (Arr.isEmpty(leading) ||
|
|
49
|
+
leading.some((element) => element.type === AST_NODE_TYPES.TSRestType ||
|
|
50
|
+
element.type === AST_NODE_TYPES.TSOptionalType ||
|
|
51
|
+
element.type === AST_NODE_TYPES.TSNamedTupleMember)) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const restElementType = last !== undefined && hasRest
|
|
55
|
+
? getArrayElementType(last.typeAnnotation)
|
|
56
|
+
: undefined;
|
|
57
|
+
if (hasRest && restElementType === undefined)
|
|
58
|
+
return undefined;
|
|
59
|
+
const [head] = leading;
|
|
60
|
+
if (head === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
const elementText = sourceCode.getText(head);
|
|
63
|
+
const expected = normalizeWhitespace(elementText);
|
|
64
|
+
const others = [
|
|
65
|
+
...Arr.tail(leading),
|
|
66
|
+
...(restElementType === undefined ? [] : [restElementType]),
|
|
67
|
+
];
|
|
68
|
+
if (others.some((element) => normalizeWhitespace(sourceCode.getText(element)) !== expected)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return definesRecursiveTypeAlias(tuple, sourceCode)
|
|
72
|
+
? undefined
|
|
73
|
+
: {
|
|
74
|
+
node: isReadonly ? parent : tuple,
|
|
75
|
+
isReadonly,
|
|
76
|
+
elementText,
|
|
77
|
+
fixedCount: leading.length,
|
|
78
|
+
hasRest,
|
|
79
|
+
};
|
|
43
80
|
};
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
44
92
|
const isInConditionalTypeExtendsClause = (node) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
93
|
+
|
|
94
|
+
if (node.type === AST_NODE_TYPES.Program)
|
|
95
|
+
return false;
|
|
96
|
+
const { parent } = node;
|
|
97
|
+
return ((parent.type === AST_NODE_TYPES.TSConditionalType &&
|
|
98
|
+
parent.extendsType === node) ||
|
|
99
|
+
isInConditionalTypeExtendsClause(parent));
|
|
48
100
|
};
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
49
140
|
const definesRecursiveTypeAlias = (tuple, sourceCode) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(element) => Array.from(referencedTypeNames(element, sourceCode))
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
141
|
+
const alias = enclosingTypeAlias(tuple);
|
|
142
|
+
if (alias === undefined)
|
|
143
|
+
return false;
|
|
144
|
+
const references = aliasReferenceGraph(programOf(alias), sourceCode);
|
|
145
|
+
const mut_seen = new Set();
|
|
146
|
+
const mut_queue = tuple.elementTypes.flatMap((element) => Array.from(referencedTypeNames(element, sourceCode)));
|
|
147
|
+
while (true) {
|
|
148
|
+
const next = mut_queue.pop();
|
|
149
|
+
if (next === undefined)
|
|
150
|
+
return false;
|
|
151
|
+
if (next === alias.id.name)
|
|
152
|
+
return true;
|
|
153
|
+
if (mut_seen.has(next))
|
|
154
|
+
continue;
|
|
155
|
+
mut_seen.add(next);
|
|
156
|
+
const referenced = references.get(next);
|
|
157
|
+
if (referenced !== undefined) {
|
|
158
|
+
mut_queue.push(...referenced);
|
|
159
|
+
}
|
|
66
160
|
}
|
|
67
|
-
}
|
|
68
161
|
};
|
|
162
|
+
|
|
69
163
|
const enclosingTypeAlias = (node) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
164
|
+
if (node.type === AST_NODE_TYPES.TSTypeAliasDeclaration)
|
|
165
|
+
return node;
|
|
166
|
+
if (node.type === AST_NODE_TYPES.Program)
|
|
167
|
+
return undefined;
|
|
168
|
+
return enclosingTypeAlias(node.parent);
|
|
73
169
|
};
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
74
177
|
const aliasReferenceGraph = (program, sourceCode) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
aliasReferenceGraphCache.set(program, mut_graph);
|
|
87
|
-
return mut_graph;
|
|
178
|
+
const cached = aliasReferenceGraphCache.get(program);
|
|
179
|
+
if (cached !== undefined)
|
|
180
|
+
return cached;
|
|
181
|
+
const mut_graph = new Map();
|
|
182
|
+
walk(program, sourceCode, (visited) => {
|
|
183
|
+
if (visited.type === AST_NODE_TYPES.TSTypeAliasDeclaration) {
|
|
184
|
+
mut_graph.set(visited.id.name, referencedTypeNames(visited.typeAnnotation, sourceCode));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
aliasReferenceGraphCache.set(program, mut_graph);
|
|
188
|
+
return mut_graph;
|
|
88
189
|
};
|
|
89
|
-
const aliasReferenceGraphCache =
|
|
190
|
+
const aliasReferenceGraphCache = new WeakMap();
|
|
90
191
|
const programOf = (node) => node.type === AST_NODE_TYPES.Program ? node : programOf(node.parent);
|
|
192
|
+
|
|
91
193
|
const referencedTypeNames = (node, sourceCode) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
194
|
+
const mut_names = new Set();
|
|
195
|
+
walk(node, sourceCode, (visited) => {
|
|
196
|
+
if (visited.type === AST_NODE_TYPES.TSTypeReference &&
|
|
197
|
+
visited.typeName.type === AST_NODE_TYPES.Identifier) {
|
|
198
|
+
mut_names.add(visited.typeName.name);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return mut_names;
|
|
99
202
|
};
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
100
212
|
const walk = (node, sourceCode, visit) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
213
|
+
visit(node);
|
|
214
|
+
if (!isRecord(node))
|
|
215
|
+
return;
|
|
216
|
+
const keys = sourceCode.visitorKeys[node.type] ??
|
|
217
|
+
Object.keys(node).filter((key) => key !== 'parent');
|
|
218
|
+
for (const key of keys) {
|
|
219
|
+
const value = hasKey(node, key) ? node[key] : undefined;
|
|
220
|
+
if (Arr.isArray(value)) {
|
|
221
|
+
for (const element of value) {
|
|
222
|
+
if (isNode(element))
|
|
223
|
+
walk(element, sourceCode, visit);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (isNode(value)) {
|
|
227
|
+
walk(value, sourceCode, visit);
|
|
228
|
+
}
|
|
112
229
|
}
|
|
113
|
-
}
|
|
114
230
|
};
|
|
115
|
-
const isNode = (value) => isNonNullObject(value) &&
|
|
231
|
+
const isNode = (value) => isNonNullObject(value) &&
|
|
232
|
+
typeof value.type === 'string';
|
|
233
|
+
|
|
116
234
|
const getArrayElementType = (node) => {
|
|
117
|
-
|
|
118
|
-
|
|
235
|
+
if (node.type === AST_NODE_TYPES.TSArrayType)
|
|
236
|
+
return node.elementType;
|
|
237
|
+
return node.type === AST_NODE_TYPES.TSTypeOperator &&
|
|
238
|
+
node.operator === 'readonly' &&
|
|
239
|
+
node.typeAnnotation?.type === AST_NODE_TYPES.TSArrayType
|
|
240
|
+
? node.typeAnnotation.elementType
|
|
241
|
+
: undefined;
|
|
119
242
|
};
|
|
120
|
-
const normalizeWhitespace = (text) => text.replaceAll(/\s+/gu,
|
|
121
|
-
|
|
122
|
-
export { analyzeUniformTuple, isLocallyBound };
|
|
123
|
-
//# sourceMappingURL=ast-utils.mjs.map
|
|
243
|
+
const normalizeWhitespace = (text) => text.replaceAll(/\s+/gu, ' ').trim();
|
|
244
|
+
//# sourceMappingURL=ast-utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-utils.mjs","sources":["../../src/rules/ast-utils.mts"],"sourcesContent":["import {\n AST_NODE_TYPES,\n ASTUtils,\n type TSESLint,\n type TSESTree,\n} from '@typescript-eslint/utils';\nimport { Arr, hasKey, isNonNullObject, isRecord } from 'ts-data-forge';\n\n/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */\n\n/**\n * Whether `name` resolves to a declaration in this file (a type alias, an\n * interface, a class, an import, …) rather than to the ambient standard-library\n * type of the same name.\n *\n * The `defs` check is what separates the two: ESLint materializes an *implicit*\n * global variable for every unresolved reference, so `findVariable` also\n * succeeds for `Exclude` in a file that never declares it. Only a variable with\n * at least one definition was actually written down somewhere in this file.\n */\nexport const isLocallyBound = (\n sourceCode: TSESLint.SourceCode,\n node: TSESTree.Node,\n name: string,\n): boolean => {\n const variable = ASTUtils.findVariable(sourceCode.getScope(node), name);\n\n return variable !== null && Arr.isNonEmpty(variable.defs);\n};\n\nexport type UniformTupleShape = Readonly<{\n /** The node an autofix must replace: the tuple, or the `readonly` operator. */\n node: TSESTree.Node;\n isReadonly: boolean;\n /** Source text of the (single, shared) element type. */\n elementText: string;\n /** Number of leading fixed-position elements. */\n fixedCount: number;\n /** Whether a trailing `...V[]` rest element is present. */\n hasRest: boolean;\n}>;\n\n/**\n * Recognizes a tuple whose every position has the *same* element type — the\n * hand-rolled spelling of ts-type-forge's length-constrained tuple family:\n *\n * | shape | meaning |\n * | :------------------- | :------------------------- |\n * | `[V, ..., V]` | `FixedLengthTuple<N, V>` |\n * | `[V, ..., V, ...V[]]`| `MinLengthTuple<N, V>` |\n *\n * Returns `undefined` for anything else. Deliberately narrow:\n *\n * - Element types are compared by normalized source text, so heterogeneous\n * tuples are never matched.\n * - Optional (`[V?]`) and labelled (`[head: V]`) members are skipped, since\n * rewriting them would drop information.\n * - A tuple that is only a rest element (`[...V[]]`) is not a length\n * constraint at all.\n * - A tuple inside the `extends` clause of a conditional type is a match\n * pattern, not a type (see {@link isInConditionalTypeExtendsClause}).\n */\nexport const analyzeUniformTuple = (\n tuple: TSESTree.TSTupleType,\n sourceCode: TSESLint.SourceCode,\n): UniformTupleShape | undefined => {\n if (isInConditionalTypeExtendsClause(tuple)) return undefined;\n\n const { parent } = tuple;\n\n const isReadonly =\n parent.type === AST_NODE_TYPES.TSTypeOperator &&\n parent.operator === 'readonly';\n\n const elements = tuple.elementTypes;\n\n const last = elements.at(-1);\n\n const hasRest = last?.type === AST_NODE_TYPES.TSRestType;\n\n const leading = hasRest ? Arr.butLast(elements) : elements;\n\n if (\n Arr.isEmpty(leading) ||\n leading.some(\n (element) =>\n element.type === AST_NODE_TYPES.TSRestType ||\n element.type === AST_NODE_TYPES.TSOptionalType ||\n element.type === AST_NODE_TYPES.TSNamedTupleMember,\n )\n ) {\n return undefined;\n }\n\n const restElementType =\n last !== undefined && hasRest\n ? getArrayElementType(last.typeAnnotation)\n : undefined;\n\n if (hasRest && restElementType === undefined) return undefined;\n\n const [head] = leading;\n\n if (head === undefined) return undefined;\n\n const elementText = sourceCode.getText(head);\n\n const expected = normalizeWhitespace(elementText);\n\n const others = [\n ...Arr.tail(leading),\n ...(restElementType === undefined ? [] : [restElementType]),\n ];\n\n if (\n others.some(\n (element) =>\n normalizeWhitespace(sourceCode.getText(element)) !== expected,\n )\n ) {\n return undefined;\n }\n\n return definesRecursiveTypeAlias(tuple, sourceCode)\n ? undefined\n : {\n node: isReadonly ? parent : tuple,\n isReadonly,\n elementText,\n fixedCount: leading.length,\n hasRest,\n };\n};\n\n/**\n * Whether `node` sits inside the `extends` clause of a conditional type, where\n * a tuple is a *match pattern* rather than a type.\n *\n * `[A, B] extends [true, true]` matches element-wise even while `A` and `B` are\n * still generic. The canonical spellings resolve through a mapped type\n * (`MutableFixedLengthTuple<N, V>` is `Mutable<FixedLengthTuple<N, V>>`), and\n * against one of those the checker defers the whole conditional instead —\n * yielding `boolean` where the tuple pattern yielded `true` or `false`, which\n * silently widens everything downstream. So those positions are left alone.\n */\nconst isInConditionalTypeExtendsClause = (node: TSESTree.Node): boolean => {\n // The root has no parent, so it terminates the walk.\n if (node.type === AST_NODE_TYPES.Program) return false;\n\n const { parent } = node;\n\n return (\n (parent.type === AST_NODE_TYPES.TSConditionalType &&\n parent.extendsType === node) ||\n isInConditionalTypeExtendsClause(parent)\n );\n};\n\n/**\n * Whether the tuple spells out an alias that its own element type leads back\n * to.\n *\n * A tuple literal is how TypeScript's cycle-breaking works: `type T = readonly\n * [T, T]` resolves, because the element positions are deferred. Rewriting it to\n * `FixedLengthTuple<2, T>` routes the same cycle through a mapped type, which\n * the checker will not compute — `T` becomes an error type, and every use of it\n * silently reads as `any`. `tsc` reports the alias once; the typed linter then\n * reports each use, which is how this was found.\n *\n * The cycle is often indirect. `LambdaApplication = readonly [LambdaTerm,\n * LambdaTerm]` looks fine on its own, and only recurses because `LambdaTerm` is\n * a union that includes `LambdaApplication`. So this follows references through\n * the other aliases in the file rather than looking for the enclosing name in\n * the element text.\n *\n * **Any cycle counts, which leaves some rewritable tuples alone.** Not every\n * cycle actually breaks: TypeScript resolves an object type, an array, a tuple\n * and a function type without resolving what is inside them, so `type Pair =\n * FixedLengthTuple<2, Foo>` alongside `type Foo = { p: Pair }` compiles, and so\n * does `type Tree = { kids: FixedLengthTuple<2, Tree> }`. Skipping those\n * constructs while following references was tried and does not hold up — the\n * deferral is undone by anything that asks for the structure, and that can sit\n * anywhere in the file:\n *\n * ```ts\n * type Pair = readonly [Foo, Foo]; // rewriting this breaks Pair and Foo\n * type Foo = Wrapper[number]; // …because of the indexed access here\n * type Wrapper = readonly Pair[];\n * ```\n *\n * Deciding it properly means knowing every use of every alias, which no\n * syntactic rule can do — so a cycle of any shape suppresses the rewrite. The\n * cost is a tuple left spelled out; the alternative is an autofix that turns a\n * type into `any`.\n *\n * A cycle closed through an `import` is not visible here and is not detected.\n */\nconst definesRecursiveTypeAlias = (\n tuple: TSESTree.TSTupleType,\n sourceCode: TSESLint.SourceCode,\n): boolean => {\n const alias = enclosingTypeAlias(tuple);\n\n if (alias === undefined) return false;\n\n const references = aliasReferenceGraph(programOf(alias), sourceCode);\n\n const mut_seen = new Set<string>();\n\n const mut_queue: string[] = tuple.elementTypes.flatMap((element) =>\n Array.from(referencedTypeNames(element, sourceCode)),\n );\n\n while (true) {\n const next = mut_queue.pop();\n\n if (next === undefined) return false;\n\n if (next === alias.id.name) return true;\n\n if (mut_seen.has(next)) continue;\n\n mut_seen.add(next);\n\n const referenced = references.get(next);\n\n if (referenced !== undefined) {\n mut_queue.push(...referenced);\n }\n }\n};\n\n/** The `type X = …` declaration `node` sits in, if any. */\nconst enclosingTypeAlias = (\n node: TSESTree.Node,\n): TSESTree.TSTypeAliasDeclaration | undefined => {\n if (node.type === AST_NODE_TYPES.TSTypeAliasDeclaration) return node;\n\n if (node.type === AST_NODE_TYPES.Program) return undefined;\n\n return enclosingTypeAlias(node.parent);\n};\n\n/**\n * Which other type names each `type X = …` in the file refers to, keyed by `X`.\n *\n * Built once per file and cached on the `Program` node: the search below runs\n * per candidate tuple, and rebuilding this for each of them made the rule cost\n * `O(tuples × file size)` — a full second on the largest generated files here.\n */\nconst aliasReferenceGraph = (\n program: TSESTree.Program,\n sourceCode: TSESLint.SourceCode,\n): ReadonlyMap<string, ReadonlySet<string>> => {\n const cached = aliasReferenceGraphCache.get(program);\n\n if (cached !== undefined) return cached;\n\n const mut_graph = new Map<string, ReadonlySet<string>>();\n\n walk(program, sourceCode, (visited) => {\n if (visited.type === AST_NODE_TYPES.TSTypeAliasDeclaration) {\n mut_graph.set(\n visited.id.name,\n referencedTypeNames(visited.typeAnnotation, sourceCode),\n );\n }\n });\n\n aliasReferenceGraphCache.set(program, mut_graph);\n\n return mut_graph;\n};\n\nconst aliasReferenceGraphCache = new WeakMap<\n TSESTree.Program,\n ReadonlyMap<string, ReadonlySet<string>>\n>();\n\nconst programOf = (node: TSESTree.Node): TSESTree.Program =>\n node.type === AST_NODE_TYPES.Program ? node : programOf(node.parent);\n\n/** The names every `X` / `X<…>` reference in the subtree points at. */\nconst referencedTypeNames = (\n node: TSESTree.Node,\n sourceCode: TSESLint.SourceCode,\n): ReadonlySet<string> => {\n const mut_names = new Set<string>();\n\n walk(node, sourceCode, (visited) => {\n if (\n visited.type === AST_NODE_TYPES.TSTypeReference &&\n visited.typeName.type === AST_NODE_TYPES.Identifier\n ) {\n mut_names.add(visited.typeName.name);\n }\n });\n\n return mut_names;\n};\n\n/**\n * Visits `node` and its descendants.\n *\n * Children are found through the parser's visitor keys, so only the properties\n * that actually hold one are read. Reading every own property instead works\n * too, and is the fallback for a parser that declares no keys for a node type,\n * but it allocates an entry pair per property and walks `loc` / `range` as\n * well — on the generated rule-type files that alone was most of the cost.\n */\nconst walk = (\n node: TSESTree.Node,\n sourceCode: TSESLint.SourceCode,\n visit: (visited: TSESTree.Node) => void,\n): void => {\n visit(node);\n\n if (!isRecord(node)) return;\n\n const keys =\n sourceCode.visitorKeys[node.type] ??\n Object.keys(node).filter((key) => key !== 'parent');\n\n for (const key of keys) {\n const value: unknown = hasKey(node, key) ? node[key] : undefined;\n\n if (Arr.isArray(value)) {\n for (const element of value) {\n if (isNode(element)) walk(element, sourceCode, visit);\n }\n } else if (isNode(value)) {\n walk(value, sourceCode, visit);\n }\n }\n};\n\nconst isNode = (value: unknown): value is TSESTree.Node =>\n isNonNullObject(value) &&\n typeof (value as Readonly<{ type?: unknown }>).type === 'string';\n\n/** Unwraps `V[]` and `readonly V[]` to `V`. */\nconst getArrayElementType = (\n node: TSESTree.TypeNode,\n): TSESTree.TypeNode | undefined => {\n if (node.type === AST_NODE_TYPES.TSArrayType) return node.elementType;\n\n return node.type === AST_NODE_TYPES.TSTypeOperator &&\n node.operator === 'readonly' &&\n node.typeAnnotation?.type === AST_NODE_TYPES.TSArrayType\n ? node.typeAnnotation.elementType\n : undefined;\n};\n\nconst normalizeWhitespace = (text: string): string =>\n text.replaceAll(/\\s+/gu, ' ').trim();\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ast-utils.mjs","sourceRoot":"","sources":["../../src/rules/ast-utils.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,QAAQ,GAGT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvE,uEAAuE;AAEvE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,UAA+B,EAC/B,IAAmB,EACnB,IAAY,EACH,EAAE;IACX,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAExE,OAAO,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5D,CAAC,CAAC;AAcF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,KAA2B,EAC3B,UAA+B,EACA,EAAE;IACjC,IAAI,gCAAgC,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE9D,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAEzB,MAAM,UAAU,GACd,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,cAAc;QAC7C,MAAM,CAAC,QAAQ,KAAK,UAAU,CAAC;IAEjC,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,CAAC;IAEpC,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7B,MAAM,OAAO,GAAG,IAAI,EAAE,IAAI,KAAK,cAAc,CAAC,UAAU,CAAC;IAEzD,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE3D,IACE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;QACpB,OAAO,CAAC,IAAI,CACV,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;YAC1C,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,cAAc;YAC9C,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,kBAAkB,CACrD,EACD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,eAAe,GACnB,IAAI,KAAK,SAAS,IAAI,OAAO;QAC3B,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,cAAc,CAAC;QAC1C,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,OAAO,IAAI,eAAe,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE/D,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IAEvB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEzC,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAElD,MAAM,MAAM,GAAG;QACb,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QACpB,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;KAC5D,CAAC;IAEF,IACE,MAAM,CAAC,IAAI,CACT,CAAC,OAAO,EAAE,EAAE,CACV,mBAAmB,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,QAAQ,CAChE,EACD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,yBAAyB,CAAC,KAAK,EAAE,UAAU,CAAC;QACjD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC;YACE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;YACjC,UAAU;YACV,WAAW;YACX,UAAU,EAAE,OAAO,CAAC,MAAM;YAC1B,OAAO;SACR,CAAC;AACR,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,gCAAgC,GAAG,CAAC,IAAmB,EAAW,EAAE;IACxE,qDAAqD;IACrD,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAEvD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAExB,OAAO,CACL,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,iBAAiB;QAC/C,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC;QAC9B,gCAAgC,CAAC,MAAM,CAAC,CACzC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,yBAAyB,GAAG,CAChC,KAA2B,EAC3B,UAA+B,EACtB,EAAE;IACX,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAExC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,UAAU,GAAG,mBAAmB,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC;IAErE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,MAAM,SAAS,GAAa,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CACjE,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CACrD,CAAC;IAEF,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAErC,IAAI,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAExC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAEjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEnB,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAExC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,2DAA2D;AAC3D,MAAM,kBAAkB,GAAG,CACzB,IAAmB,EAC0B,EAAE;IAC/C,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,sBAAsB;QAAE,OAAO,IAAI,CAAC;IAErE,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAE3D,OAAO,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,CAC1B,OAAyB,EACzB,UAA+B,EACW,EAAE;IAC5C,MAAM,MAAM,GAAG,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAErD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExC,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAC;IAEzD,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE;QACpC,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,sBAAsB,EAAE,CAAC;YAC3D,SAAS,CAAC,GAAG,CACX,OAAO,CAAC,EAAE,CAAC,IAAI,EACf,mBAAmB,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,CACxD,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,wBAAwB,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEjD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,IAAI,OAAO,EAGzC,CAAC;AAEJ,MAAM,SAAS,GAAG,CAAC,IAAmB,EAAoB,EAAE,CAC1D,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAEvE,uEAAuE;AACvE,MAAM,mBAAmB,GAAG,CAC1B,IAAmB,EACnB,UAA+B,EACV,EAAE;IACvB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE;QACjC,IACE,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe;YAC/C,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU,EACnD,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,IAAI,GAAG,CACX,IAAmB,EACnB,UAA+B,EAC/B,KAAuC,EACjC,EAAE;IACR,KAAK,CAAC,IAAI,CAAC,CAAC;IAEZ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO;IAE5B,MAAM,IAAI,GACR,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC;IAEtD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAY,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjE,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;gBAC5B,IAAI,MAAM,CAAC,OAAO,CAAC;oBAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,KAAc,EAA0B,EAAE,CACxD,eAAe,CAAC,KAAK,CAAC;IACtB,OAAQ,KAAsC,CAAC,IAAI,KAAK,QAAQ,CAAC;AAEnE,+CAA+C;AAC/C,MAAM,mBAAmB,GAAG,CAC1B,IAAuB,EACQ,EAAE;IACjC,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC,WAAW,CAAC;IAEtE,OAAO,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,cAAc;QAChD,IAAI,CAAC,QAAQ,KAAK,UAAU;QAC5B,IAAI,CAAC,cAAc,EAAE,IAAI,KAAK,cAAc,CAAC,WAAW;QACxD,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW;QACjC,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,IAAY,EAAU,EAAE,CACnD,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC"}
|
package/dist/rules/constants.mjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
const TS_TYPE_FORGE_MODULE =
|
|
2
|
-
const NON_EMPTY_TUPLE_TYPE_NAME =
|
|
3
|
-
const MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME =
|
|
4
|
-
const MIN_LENGTH_TUPLE_TYPE_NAME =
|
|
5
|
-
const MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME =
|
|
6
|
-
const FIXED_LENGTH_TUPLE_TYPE_NAME =
|
|
7
|
-
const MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
export const TS_TYPE_FORGE_MODULE = 'ts-type-forge';
|
|
2
|
+
export const NON_EMPTY_TUPLE_TYPE_NAME = 'NonEmptyTuple';
|
|
3
|
+
export const MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME = 'MutableNonEmptyTuple';
|
|
4
|
+
export const MIN_LENGTH_TUPLE_TYPE_NAME = 'MinLengthTuple';
|
|
5
|
+
export const MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME = 'MutableMinLengthTuple';
|
|
6
|
+
export const FIXED_LENGTH_TUPLE_TYPE_NAME = 'FixedLengthTuple';
|
|
7
|
+
export const MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME = 'MutableFixedLengthTuple';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_MAX_TUPLE_LENGTH = 10;
|
|
14
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.mjs","sources":["../../src/rules/constants.mts"],"
|
|
1
|
+
{"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../src/rules/constants.mts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAEpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC;AAEzD,MAAM,CAAC,MAAM,iCAAiC,GAAG,sBAAsB,CAAC;AAExE,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAE3D,MAAM,CAAC,MAAM,kCAAkC,GAAG,uBAAuB,CAAC;AAE1E,MAAM,CAAC,MAAM,4BAA4B,GAAG,kBAAkB,CAAC;AAE/D,MAAM,CAAC,MAAM,oCAAoC,GAAG,yBAAyB,CAAC;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC"}
|
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
import { TS_TYPE_FORGE_MODULE } from './constants.mjs';
|
|
2
|
-
import { getImportedLocalName, getTsTypeForgeImports, hasConflictingDeclaration } from './import-utils.mjs';
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
].join(" ")
|
|
16
|
-
};
|
|
17
|
-
const resolveTypeName = (program, canonicalName, importStyle) => {
|
|
18
|
-
const importedLocalName = getImportedLocalName(
|
|
19
|
-
getTsTypeForgeImports(program),
|
|
20
|
-
canonicalName
|
|
21
|
-
);
|
|
22
|
-
if (importedLocalName !== void 0) {
|
|
23
|
-
return { localName: importedLocalName, needsImport: false };
|
|
24
|
-
}
|
|
25
|
-
return hasConflictingDeclaration(program, canonicalName) ? void 0 : { localName: canonicalName, needsImport: importStyle === "named" };
|
|
2
|
+
import { getImportedLocalName, getTsTypeForgeImports, hasConflictingDeclaration, } from './import-utils.mjs';
|
|
3
|
+
export const DEFAULT_IMPORT_STYLE = 'named';
|
|
4
|
+
export const IMPORT_STYLE_SCHEMA_PROPERTY = {
|
|
5
|
+
type: 'string',
|
|
6
|
+
enum: ['global', 'named'],
|
|
7
|
+
description: [
|
|
8
|
+
'How the ts-type-forge type is brought into scope.',
|
|
9
|
+
"'named' (default) makes the autofix add the corresponding",
|
|
10
|
+
`\`import { type … } from '${TS_TYPE_FORGE_MODULE}';\``,
|
|
11
|
+
"when the name is not imported yet; 'global' assumes the",
|
|
12
|
+
'ambient globals of `ts-type-forge/global` and never touches',
|
|
13
|
+
'imports.',
|
|
14
|
+
].join(' '),
|
|
26
15
|
};
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export const resolveTypeName = (program, canonicalName, importStyle) => {
|
|
26
|
+
const importedLocalName = getImportedLocalName(getTsTypeForgeImports(program), canonicalName);
|
|
27
|
+
if (importedLocalName !== undefined) {
|
|
28
|
+
return { localName: importedLocalName, needsImport: false };
|
|
29
|
+
}
|
|
30
|
+
return hasConflictingDeclaration(program, canonicalName)
|
|
31
|
+
? undefined
|
|
32
|
+
: { localName: canonicalName, needsImport: importStyle === 'named' };
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=import-style.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-style.mjs","sources":["../../src/rules/import-style.mts"],"
|
|
1
|
+
{"version":3,"file":"import-style.mjs","sourceRoot":"","sources":["../../src/rules/import-style.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAY5B,MAAM,CAAC,MAAM,oBAAoB,GAAgB,OAAO,CAAC;AAEzD,MAAM,CAAC,MAAM,4BAA4B,GAAe;IACtD,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE;QACX,mDAAmD;QACnD,2DAA2D;QAC3D,6BAA6B,oBAAoB,MAAM;QACvD,yDAAyD;QACzD,6DAA6D;QAC7D,UAAU;KACX,CAAC,IAAI,CAAC,GAAG,CAAC;CACZ,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,OAAyB,EACzB,aAAqB,EACrB,WAAwB,EAC2C,EAAE;IACrE,MAAM,iBAAiB,GAAG,oBAAoB,CAC5C,qBAAqB,CAAC,OAAO,CAAC,EAC9B,aAAa,CACd,CAAC;IAEF,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAC9D,CAAC;IAED,OAAO,yBAAyB,CAAC,OAAO,EAAE,aAAa,CAAC;QACtD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,KAAK,OAAO,EAAE,CAAC;AACzE,CAAC,CAAC"}
|