@cplieger/deadset-ts 7.2.0-dev.4 → 8.0.0-dev.2
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/src/analysis.js +108 -10
- package/dist/src/augmentations.js +62 -18
- package/dist/src/automatic-types.js +189 -0
- package/dist/src/base-url.js +18 -0
- package/dist/src/components.js +7 -6
- package/dist/src/config.js +1 -0
- package/dist/src/configuration-files.js +50 -12
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/convention-rows.js +98 -0
- package/dist/src/conventions.js +101 -5
- package/dist/src/decorator.js +21 -18
- package/dist/src/dependencies.js +183 -28
- package/dist/src/discover.js +132 -11
- package/dist/src/entry-point-gaps.js +7 -10
- package/dist/src/entry-points.js +112 -11
- package/dist/src/findings/completion.js +172 -40
- package/dist/src/findings/dependencies-and-module-machinery.js +71 -25
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/intra-function.js +44 -13
- package/dist/src/findings/non-code-artifacts.js +66 -33
- package/dist/src/findings/unused-declarations.js +30 -5
- package/dist/src/findings/visibility-narrowing.js +29 -5
- package/dist/src/generated-file.js +11 -0
- package/dist/src/git-ignore.js +86 -0
- package/dist/src/graph.js +4 -1
- package/dist/src/import-bindings.js +97 -0
- package/dist/src/indexed-access.js +130 -28
- package/dist/src/interface-satisfaction.js +30 -12
- package/dist/src/intra-function-parts.js +297 -45
- package/dist/src/inventory.js +52 -8
- package/dist/src/kinds.js +13 -13
- package/dist/src/matrix.js +57 -10
- package/dist/src/mdx-entries.js +197 -0
- package/dist/src/module-declarations.js +9 -13
- package/dist/src/overrides.js +41 -10
- package/dist/src/print.js +1 -0
- package/dist/src/ref.js +10 -0
- package/dist/src/references.js +38 -4
- package/dist/src/report.js +4 -2
- package/dist/src/resolve.js +2 -0
- package/dist/src/roots.js +110 -38
- package/dist/src/schema.js +1 -0
- package/dist/src/serialization-contract.js +54 -8
- package/dist/src/session.js +7 -0
- package/dist/src/source-files.js +39 -14
- package/dist/src/suppress-file.js +10 -2
- package/dist/src/suppress-inline.js +18 -2
- package/dist/src/suppress.js +8 -5
- package/dist/src/sweep.js +27 -10
- package/dist/src/symbol-keys.js +103 -2
- package/dist/src/test-support.js +119 -18
- package/dist/src/type-errors.js +34 -7
- package/dist/src/type-parameter-reads.js +172 -0
- package/dist/src/verbs/analyze.js +16 -0
- package/dist/src/verbs/explain.js +4 -2
- package/dist/src/version.js +1 -1
- package/dist/src/workflow-steps.js +119 -22
- package/dist/src/workspace-programs.js +7 -3
- package/dist/src/workspace-resolution.js +53 -10
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/analysis.ts +146 -11
- package/src/augmentations.ts +76 -22
- package/src/automatic-types.ts +246 -0
- package/src/base-url.ts +24 -0
- package/src/components.ts +7 -6
- package/src/config.ts +3 -0
- package/src/configuration-files.ts +66 -12
- package/src/conformance-record.ts +2 -2
- package/src/convention-rows.ts +128 -0
- package/src/conventions.ts +121 -7
- package/src/decorator.ts +28 -18
- package/src/dependencies.ts +247 -41
- package/src/discover.ts +156 -13
- package/src/entry-point-gaps.ts +8 -11
- package/src/entry-points.ts +133 -11
- package/src/finding.ts +15 -0
- package/src/findings/completion.ts +222 -46
- package/src/findings/dependencies-and-module-machinery.ts +90 -28
- package/src/findings/emitters.ts +1 -1
- package/src/findings/intra-function.ts +56 -14
- package/src/findings/non-code-artifacts.ts +81 -41
- package/src/findings/unused-declarations.ts +36 -5
- package/src/findings/visibility-narrowing.ts +40 -5
- package/src/generated-file.ts +16 -0
- package/src/git-ignore.ts +98 -0
- package/src/graph.ts +6 -0
- package/src/host.ts +5 -9
- package/src/import-bindings.ts +128 -0
- package/src/indexed-access.ts +152 -30
- package/src/interface-satisfaction.ts +33 -13
- package/src/intra-function-parts.ts +394 -59
- package/src/inventory.ts +71 -7
- package/src/kinds.ts +13 -13
- package/src/matrix.ts +104 -15
- package/src/mdx-entries.ts +241 -0
- package/src/module-declarations.ts +11 -13
- package/src/overrides.ts +51 -12
- package/src/print.ts +1 -0
- package/src/ref.ts +12 -0
- package/src/references.ts +48 -3
- package/src/report.ts +16 -3
- package/src/resolve.ts +3 -0
- package/src/roots.ts +163 -45
- package/src/schema.ts +1 -0
- package/src/serialization-contract.ts +55 -4
- package/src/session.ts +7 -0
- package/src/source-files.ts +66 -16
- package/src/suppress-file.ts +12 -1
- package/src/suppress-inline.ts +18 -1
- package/src/suppress.ts +10 -5
- package/src/sweep.ts +32 -11
- package/src/symbol-keys.ts +129 -2
- package/src/test-support.ts +155 -18
- package/src/type-errors.ts +38 -6
- package/src/type-parameter-reads.ts +227 -0
- package/src/verbs/analyze.ts +22 -0
- package/src/verbs/explain.ts +5 -2
- package/src/version.ts +1 -1
- package/src/workflow-steps.ts +127 -22
- package/src/workspace-programs.ts +7 -3
- package/src/workspace-resolution.ts +62 -10
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* that parameter, and a call of a method of a generic receiver fixes the receiver's by its
|
|
5
5
|
* type arguments. The type query of a type-query alias is no reference.
|
|
6
6
|
*/
|
|
7
|
-
import { isArrowFunction, isBindingElement, isCallExpression, isClassDeclaration, isClassExpression, isFunctionDeclaration, isFunctionExpression, isFunctionTypeNode, isIdentifier, isIndexedAccessTypeNode, isInterfaceDeclaration, isLiteralTypeNode, isMappedTypeNode, isMethodDeclaration, isMethodSignatureDeclaration, isNewExpression, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectBindingPattern, isParenthesizedTypeNode, isPropertyAccessExpression, isPropertySignatureDeclaration, isStringLiteral, isTypeAliasDeclaration, isTypeOperatorNode, isTypeReferenceNode, isUnionTypeNode, isVariableDeclaration, SyntaxKind, } from "@typescript/native/ast";
|
|
7
|
+
import { isArrowFunction, isBindingElement, isCallExpression, isClassDeclaration, isClassExpression, isConstructorDeclaration, isConstructorTypeNode, isFunctionDeclaration, isFunctionExpression, isFunctionTypeNode, isIdentifier, isIndexedAccessTypeNode, isInterfaceDeclaration, isLiteralTypeNode, isMappedTypeNode, isMethodDeclaration, isMethodSignatureDeclaration, isNewExpression, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectBindingPattern, isParenthesizedTypeNode, isPropertyAccessExpression, isPropertyAssignment, isPropertySignatureDeclaration, isStringLiteral, isTypeAliasDeclaration, isTypeOperatorNode, isTypeReferenceNode, isUnionTypeNode, isVariableDeclaration, SyntaxKind, } from "@typescript/native/ast";
|
|
8
8
|
import { SignatureKind, SymbolFlags, } from "@typescript/native/sync";
|
|
9
9
|
import { nodeKey } from "./inventory.js";
|
|
10
10
|
import { renderPosition } from "./position.js";
|
|
@@ -17,12 +17,25 @@ function isGeneric(node) {
|
|
|
17
17
|
isArrowFunction(node) ||
|
|
18
18
|
isFunctionExpression(node) ||
|
|
19
19
|
isFunctionTypeNode(node) ||
|
|
20
|
+
isConstructorTypeNode(node) ||
|
|
20
21
|
isTypeAliasDeclaration(node) ||
|
|
21
22
|
isInterfaceDeclaration(node) ||
|
|
22
23
|
isClassDeclaration(node) ||
|
|
23
24
|
isClassExpression(node)) &&
|
|
24
25
|
node.typeParameters !== undefined);
|
|
25
26
|
}
|
|
27
|
+
/** Whether a function declares no type parameter and a parameter whose type holds `keyof`. */
|
|
28
|
+
function takesKeyof(node) {
|
|
29
|
+
if (!(isFunctionDeclaration(node) ||
|
|
30
|
+
isMethodDeclaration(node) ||
|
|
31
|
+
isMethodSignatureDeclaration(node) ||
|
|
32
|
+
isArrowFunction(node) ||
|
|
33
|
+
isFunctionExpression(node)) ||
|
|
34
|
+
node.typeParameters !== undefined) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return node.parameters.some((parameter) => parameter.type !== undefined && keyofOperands(parameter.type).length > 0);
|
|
38
|
+
}
|
|
26
39
|
/** Whether one generic is a receiver's: a class or an interface whose methods it parameterizes. */
|
|
27
40
|
function isReceiver(node) {
|
|
28
41
|
return isInterfaceDeclaration(node) || isClassDeclaration(node) || isClassExpression(node);
|
|
@@ -57,8 +70,8 @@ function unwrappedType(node) {
|
|
|
57
70
|
function literalNames(index) {
|
|
58
71
|
const node = unwrappedType(index);
|
|
59
72
|
if (isUnionTypeNode(node)) {
|
|
60
|
-
const names = node.types.
|
|
61
|
-
return names.
|
|
73
|
+
const names = node.types.flatMap((one) => literalNames(one) ?? []);
|
|
74
|
+
return names.length > 0 ? names : undefined;
|
|
62
75
|
}
|
|
63
76
|
if (!isLiteralTypeNode(node)) {
|
|
64
77
|
return undefined;
|
|
@@ -69,7 +82,7 @@ function literalNames(index) {
|
|
|
69
82
|
}
|
|
70
83
|
return isNumericLiteral(literal) ? [String(Number(literal.text))] : undefined;
|
|
71
84
|
}
|
|
72
|
-
/** The
|
|
85
|
+
/** The names the literal constituents of a type carry: a key the type names is one the access requires. */
|
|
73
86
|
function literalTypeNames(type, parts) {
|
|
74
87
|
const names = [];
|
|
75
88
|
for (const part of parts(type)) {
|
|
@@ -79,9 +92,6 @@ function literalTypeNames(type, parts) {
|
|
|
79
92
|
else if (part.isNumberLiteralType()) {
|
|
80
93
|
names.push(String(part.value));
|
|
81
94
|
}
|
|
82
|
-
else {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
95
|
}
|
|
86
96
|
return names;
|
|
87
97
|
}
|
|
@@ -140,16 +150,21 @@ function calledName(generic) {
|
|
|
140
150
|
}
|
|
141
151
|
const parent = generic.parent;
|
|
142
152
|
return parent !== undefined &&
|
|
143
|
-
(isVariableDeclaration(parent) ||
|
|
153
|
+
(isVariableDeclaration(parent) ||
|
|
154
|
+
isPropertySignatureDeclaration(parent) ||
|
|
155
|
+
isPropertyAssignment(parent)) &&
|
|
144
156
|
isIdentifier(parent.name)
|
|
145
157
|
? parent.name.text
|
|
146
158
|
: undefined;
|
|
147
159
|
}
|
|
148
160
|
/** The generic a declaration a symbol names is: the function a variable is initialized with included. */
|
|
149
161
|
function genericOf(node) {
|
|
150
|
-
if (isGeneric(node) || isReceiverMember(node)) {
|
|
162
|
+
if (isGeneric(node) || isReceiverMember(node) || takesKeyof(node)) {
|
|
151
163
|
return node;
|
|
152
164
|
}
|
|
165
|
+
if (isConstructorDeclaration(node) && isGeneric(node.parent)) {
|
|
166
|
+
return node.parent;
|
|
167
|
+
}
|
|
153
168
|
if (isPropertySignatureDeclaration(node)) {
|
|
154
169
|
// The typings mark the annotation present; a signature written without one has none.
|
|
155
170
|
const declared = node.type;
|
|
@@ -238,6 +253,8 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
238
253
|
const carried = new Map();
|
|
239
254
|
const names = new Set();
|
|
240
255
|
const sites = [];
|
|
256
|
+
/** Accesses indexed by a type parameter whose constraint is no `keyof`: it requires each key it names. */
|
|
257
|
+
const constrained = [];
|
|
241
258
|
/** Calls passing an argument, which a generic declared outside the own files may fix. */
|
|
242
259
|
const argumentCalls = [];
|
|
243
260
|
const carry = (generic, one) => {
|
|
@@ -263,14 +280,23 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
263
280
|
const own = held.declarations.get(nodeKey(file, node));
|
|
264
281
|
const holder = own ?? from;
|
|
265
282
|
const inside = isGeneric(node) ? [...enclosing, node] : enclosing;
|
|
266
|
-
if (isGeneric(node)) {
|
|
283
|
+
if (isGeneric(node) || takesKeyof(node)) {
|
|
267
284
|
carriedIn(node).forEach((one) => carry(node, one));
|
|
268
285
|
}
|
|
269
286
|
if (isIndexedAccessTypeNode(node) && !aliasTypes.has(node)) {
|
|
270
287
|
const literal = literalNames(node.indexType);
|
|
288
|
+
const parameter = literal === undefined ? namedParameter(node.indexType, inside) : undefined;
|
|
289
|
+
const constraint = parameter === undefined
|
|
290
|
+
? undefined
|
|
291
|
+
: parameter.generic.typeParameters?.[parameter.index]?.constraint;
|
|
271
292
|
if (literal !== undefined) {
|
|
272
293
|
accesses.push({ file, from: holder, at: node, object: node.objectType, index: literal });
|
|
273
294
|
}
|
|
295
|
+
else if (constraint !== undefined &&
|
|
296
|
+
keyofOperands(constraint).length === 0 &&
|
|
297
|
+
namedParameter(node.objectType, inside) === undefined) {
|
|
298
|
+
constrained.push({ file, from: holder, at: node, object: node.objectType, constraint });
|
|
299
|
+
}
|
|
274
300
|
}
|
|
275
301
|
if (isTypeReferenceNode(node) &&
|
|
276
302
|
node.typeArguments !== undefined &&
|
|
@@ -287,7 +313,7 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
287
313
|
if (name !== undefined) {
|
|
288
314
|
const site = { file, from: holder, node, name, enclosing: inside };
|
|
289
315
|
sites.push(site);
|
|
290
|
-
if (
|
|
316
|
+
if (argumentsOf(node).length > 0) {
|
|
291
317
|
argumentCalls.push(site);
|
|
292
318
|
}
|
|
293
319
|
}
|
|
@@ -300,6 +326,35 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
300
326
|
visit(child, fileId, []);
|
|
301
327
|
});
|
|
302
328
|
}
|
|
329
|
+
/** The literal keys one constraint names, through the type aliases it references. */
|
|
330
|
+
const requiredNames = (node, seen) => {
|
|
331
|
+
const type = unwrappedType(node);
|
|
332
|
+
if (isUnionTypeNode(type)) {
|
|
333
|
+
return type.types.flatMap((one) => requiredNames(one, seen));
|
|
334
|
+
}
|
|
335
|
+
if (!isTypeReferenceNode(type) || type.typeArguments !== undefined) {
|
|
336
|
+
return literalNames(type) ?? [];
|
|
337
|
+
}
|
|
338
|
+
const [symbol] = queries.symbolsAt([type.typeName]);
|
|
339
|
+
if (symbol === UNANSWERED || symbol === undefined) {
|
|
340
|
+
return [];
|
|
341
|
+
}
|
|
342
|
+
return symbol.declarations.flatMap((handle) => {
|
|
343
|
+
const declared = project.declarationAt(handle)?.node;
|
|
344
|
+
return declared !== undefined &&
|
|
345
|
+
isTypeAliasDeclaration(declared) &&
|
|
346
|
+
declared.typeParameters === undefined &&
|
|
347
|
+
!seen.has(declared)
|
|
348
|
+
? requiredNames(declared.type, new Set([...seen, declared]))
|
|
349
|
+
: [];
|
|
350
|
+
});
|
|
351
|
+
};
|
|
352
|
+
for (const { constraint, ...access } of constrained) {
|
|
353
|
+
const index = requiredNames(constraint, new Set());
|
|
354
|
+
if (index.length > 0) {
|
|
355
|
+
accesses.push({ ...access, index });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
303
358
|
function partsOf(type) {
|
|
304
359
|
const parts = queries.constituents(type);
|
|
305
360
|
return parts === UNANSWERED ? [type] : parts;
|
|
@@ -322,11 +377,13 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
322
377
|
* variable holding the callee is initialized with.
|
|
323
378
|
*/
|
|
324
379
|
const receiverTypeOf = (callee) => {
|
|
380
|
+
let operand;
|
|
325
381
|
if (isPropertyAccessExpression(callee)) {
|
|
326
382
|
const type = queries.typeAt(callee.expression);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
383
|
+
operand = type === UNANSWERED ? undefined : type;
|
|
384
|
+
const args = operand === undefined ? [] : queries.typeArguments(operand);
|
|
385
|
+
if (operand !== undefined && args !== UNANSWERED && args.length > 0) {
|
|
386
|
+
return operand;
|
|
330
387
|
}
|
|
331
388
|
}
|
|
332
389
|
const name = isPropertyAccessExpression(callee) ? callee.name : callee;
|
|
@@ -335,7 +392,7 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
335
392
|
? named
|
|
336
393
|
: queries.aliased(named);
|
|
337
394
|
if (symbol === UNANSWERED || symbol === undefined) {
|
|
338
|
-
return
|
|
395
|
+
return operand;
|
|
339
396
|
}
|
|
340
397
|
for (const handle of symbol.declarations) {
|
|
341
398
|
const node = project.declarationAt(handle)?.node;
|
|
@@ -355,7 +412,40 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
355
412
|
return type;
|
|
356
413
|
}
|
|
357
414
|
}
|
|
358
|
-
return
|
|
415
|
+
return operand;
|
|
416
|
+
};
|
|
417
|
+
/**
|
|
418
|
+
* The instantiation of `owner` a receiver's type is, or the first one among the base
|
|
419
|
+
* types it extends, breadth first: a subclass fixes its base's type parameters, and
|
|
420
|
+
* `this` stands for its class.
|
|
421
|
+
*/
|
|
422
|
+
const instantiationOf = (type, owner) => {
|
|
423
|
+
const seen = new Set();
|
|
424
|
+
for (let queue = [type]; queue.length > 0;) {
|
|
425
|
+
const next = [];
|
|
426
|
+
for (const at of queue) {
|
|
427
|
+
if (seen.has(at.id)) {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
seen.add(at.id);
|
|
431
|
+
const target = at.isTypeReference() ? queries.targetOf(at) : at;
|
|
432
|
+
const symbol = target === UNANSWERED ? undefined : queries.symbolOfType(target);
|
|
433
|
+
const declares = symbol !== undefined &&
|
|
434
|
+
symbol !== UNANSWERED &&
|
|
435
|
+
symbol.declarations.some((handle) => project.declarationAt(handle)?.node === owner);
|
|
436
|
+
if (declares) {
|
|
437
|
+
return at;
|
|
438
|
+
}
|
|
439
|
+
const constraint = at.isTypeParameter() ? queries.constraintOf(at) : undefined;
|
|
440
|
+
const bases = at.isTypeParameter() ? [] : queries.baseTypes(at);
|
|
441
|
+
next.push(...(bases === UNANSWERED ? [] : bases));
|
|
442
|
+
if (constraint !== undefined && constraint !== UNANSWERED) {
|
|
443
|
+
next.push(constraint);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
queue = next;
|
|
447
|
+
}
|
|
448
|
+
return type;
|
|
359
449
|
};
|
|
360
450
|
/** What one site fixes for one side of a carried access. */
|
|
361
451
|
const fixedAt = (site, side, generic) => {
|
|
@@ -365,7 +455,9 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
365
455
|
const { node } = site;
|
|
366
456
|
if (side.kind === "receiver") {
|
|
367
457
|
const callee = isCallExpression(node) ? node.expression : undefined;
|
|
368
|
-
const
|
|
458
|
+
const owner = receiverOf(generic);
|
|
459
|
+
const typed = callee === undefined ? undefined : receiverTypeOf(callee);
|
|
460
|
+
const receiver = typed === undefined || owner === undefined ? typed : instantiationOf(typed, owner);
|
|
369
461
|
if (receiver === undefined) {
|
|
370
462
|
return undefined;
|
|
371
463
|
}
|
|
@@ -389,7 +481,7 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
389
481
|
if (isTypeReferenceNode(node)) {
|
|
390
482
|
return undefined;
|
|
391
483
|
}
|
|
392
|
-
const at = (generic
|
|
484
|
+
const at = parametersOf(generic).findIndex((parameter) => {
|
|
393
485
|
const type = parameter.type === undefined ? undefined : unwrappedType(parameter.type);
|
|
394
486
|
return (type !== undefined &&
|
|
395
487
|
isTypeReferenceNode(type) &&
|
|
@@ -482,9 +574,7 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
482
574
|
// by its type parameters and its receiver's. Only a call passing an argument the compiler
|
|
483
575
|
// types as a literal can fix an index, so only such a call's signature is resolved.
|
|
484
576
|
const outside = argumentCalls.filter((site) => !resolvedGenerics.has(site));
|
|
485
|
-
const argumentNodes = argumentCalls.flatMap((site) =>
|
|
486
|
-
...site.node.arguments,
|
|
487
|
-
]);
|
|
577
|
+
const argumentNodes = argumentCalls.flatMap((site) => argumentsOf(site.node));
|
|
488
578
|
const argumentTypes = queries.typesAt(argumentNodes);
|
|
489
579
|
const literalArgument = new Set();
|
|
490
580
|
argumentTypes.forEach((type, at) => {
|
|
@@ -492,13 +582,13 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
492
582
|
if (node !== undefined &&
|
|
493
583
|
type !== UNANSWERED &&
|
|
494
584
|
type !== undefined &&
|
|
495
|
-
|
|
585
|
+
literalTypeNames(type, partsOf).length > 0) {
|
|
496
586
|
literalArgument.add(node);
|
|
497
587
|
}
|
|
498
588
|
});
|
|
499
589
|
const own = project.ownPaths();
|
|
500
590
|
for (const site of outside) {
|
|
501
|
-
if (!site.node.
|
|
591
|
+
if (!argumentsOf(site.node).some((one) => literalArgument.has(one))) {
|
|
502
592
|
continue;
|
|
503
593
|
}
|
|
504
594
|
const resolved = queries.resolvedSignature(site.node);
|
|
@@ -516,7 +606,7 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
516
606
|
}
|
|
517
607
|
}
|
|
518
608
|
for (const site of argumentCalls) {
|
|
519
|
-
if (site.node.
|
|
609
|
+
if (argumentsOf(site.node).some((one) => literalArgument.has(one))) {
|
|
520
610
|
accesses.push(...instantiatedAccesses(site));
|
|
521
611
|
}
|
|
522
612
|
}
|
|
@@ -536,7 +626,7 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
536
626
|
generic === undefined) {
|
|
537
627
|
return [];
|
|
538
628
|
}
|
|
539
|
-
const count = site.node.
|
|
629
|
+
const count = argumentsOf(site.node).length;
|
|
540
630
|
const parameters = [];
|
|
541
631
|
for (let at = 0; at < count; at += 1) {
|
|
542
632
|
const type = queries.parameterType(generic, at);
|
|
@@ -573,13 +663,13 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
573
663
|
}
|
|
574
664
|
const names = access.index.isTypeParameter()
|
|
575
665
|
? parameters.flatMap((parameter, at) => {
|
|
576
|
-
if (parameter.id
|
|
666
|
+
if (!partsOf(parameter).some((part) => part.id === access.index.id)) {
|
|
577
667
|
return [];
|
|
578
668
|
}
|
|
579
669
|
const passed = queries.typeAtPosition(resolved, at);
|
|
580
|
-
return passed === UNANSWERED ? [] :
|
|
670
|
+
return passed === UNANSWERED ? [] : literalTypeNames(passed, partsOf);
|
|
581
671
|
})
|
|
582
|
-
:
|
|
672
|
+
: literalTypeNames(access.index, partsOf);
|
|
583
673
|
if (names.length > 0) {
|
|
584
674
|
found.push({
|
|
585
675
|
file: site.file,
|
|
@@ -643,6 +733,18 @@ export function indexedAccessReferences(project, held, chains, root, testFiles)
|
|
|
643
733
|
}
|
|
644
734
|
return found;
|
|
645
735
|
}
|
|
736
|
+
/** The arguments a call or a `new` expression passes, none for a type reference. */
|
|
737
|
+
function argumentsOf(node) {
|
|
738
|
+
return isTypeReferenceNode(node) ? [] : (node.arguments ?? []);
|
|
739
|
+
}
|
|
740
|
+
/** The parameters a site's arguments bind: a class's are its constructor's. */
|
|
741
|
+
function parametersOf(generic) {
|
|
742
|
+
if (isClassDeclaration(generic) || isClassExpression(generic)) {
|
|
743
|
+
const constructor = generic.members.find(isConstructorDeclaration);
|
|
744
|
+
return constructor?.parameters ?? [];
|
|
745
|
+
}
|
|
746
|
+
return generic.parameters ?? [];
|
|
747
|
+
}
|
|
646
748
|
/** What makes two carried accesses one: the kind and position of each side, or its written node. */
|
|
647
749
|
function sideKey(one) {
|
|
648
750
|
const key = (side) => side.kind === "written" ? ["written", side.node.pos, side.node.end] : [side.kind, side.index];
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The interface-satisfaction class: a member is held back when a value of its class
|
|
3
|
-
* reaches a position
|
|
4
|
-
* `implements` entry, a typed initializer, an assignment, an
|
|
5
|
-
* element, an object property or an `as` or `satisfies`
|
|
6
|
-
*
|
|
7
|
-
* lookup has no batch form, so it is asked only of a value
|
|
3
|
+
* reaches a position typed as an interface, or an object type a type alias names, that
|
|
4
|
+
* requires the member: an `implements` entry, a typed initializer, an assignment, an
|
|
5
|
+
* argument, a return, an array element, an object property or an `as` or `satisfies`
|
|
6
|
+
* operand. `this` is a value of its class; a type parameter reaches its constraint. The
|
|
7
|
+
* contextual lookup has no batch form, so it is asked only of a value of a target class.
|
|
8
8
|
*/
|
|
9
|
-
import { isCallExpression, isClassDeclaration, isClassExpression, isClassStaticBlockDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isHeritageClause, isMethodDeclaration, isNewExpression, isObjectLiteralExpression, isSetAccessorDeclaration, ModifierFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
9
|
+
import { isCallExpression, isClassDeclaration, isClassExpression, isClassStaticBlockDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isHeritageClause, isMethodDeclaration, isNewExpression, isObjectLiteralExpression, isSetAccessorDeclaration, isTypeLiteralNode, ModifierFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
10
10
|
import { SymbolFlags } from "@typescript/native/sync";
|
|
11
11
|
import { aliasChains } from "./alias-chain.js";
|
|
12
12
|
import { emptyImplementation } from "./implementations.js";
|
|
@@ -14,6 +14,10 @@ import { nodeKey } from "./inventory.js";
|
|
|
14
14
|
import { renderPosition } from "./position.js";
|
|
15
15
|
import { must } from "./query.js";
|
|
16
16
|
import { handedOn, valuesOf } from "./value-flow.js";
|
|
17
|
+
/** Whether a type alias names one type: the client's type object carries the alias it was written through. */
|
|
18
|
+
function aliased(type) {
|
|
19
|
+
return type.aliasSymbol !== undefined;
|
|
20
|
+
}
|
|
17
21
|
/** Whether one node declares a static member, whose `this` is the class itself. */
|
|
18
22
|
function isStatic(node) {
|
|
19
23
|
const flags = node.modifierFlags ?? 0;
|
|
@@ -146,19 +150,33 @@ export function interfaceSatisfaction(input) {
|
|
|
146
150
|
return generic === undefined ? [] : [{ owner: generic, type: part }];
|
|
147
151
|
});
|
|
148
152
|
const interfaceNames = new Map();
|
|
149
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* The interface types one position's type is or holds, each with the interface's name:
|
|
155
|
+
* an interface, or an object type literal a type alias names, directly or as a
|
|
156
|
+
* constituent of an intersection the alias names.
|
|
157
|
+
*/
|
|
150
158
|
const interfacesOf = (type) => partsOf(type).flatMap((part) => {
|
|
151
159
|
if (part.isTypeParameter()) {
|
|
152
160
|
const constraint = must(queries.constraintOf(part));
|
|
153
161
|
return constraint === undefined ? [] : interfacesOf(constraint);
|
|
154
162
|
}
|
|
155
|
-
|
|
163
|
+
const named = aliased(part) ? part : aliased(type) ? type : undefined;
|
|
164
|
+
const key = `${String(part.id)}:${String(named?.id ?? "")}`;
|
|
165
|
+
if (!interfaceNames.has(key)) {
|
|
156
166
|
const symbol = part.isObjectType() ? must(queries.symbolOfType(part)) : undefined;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
const flags = symbol?.flags ?? 0;
|
|
168
|
+
interfaceNames.set(key, (flags & SymbolFlags.Interface) !== 0
|
|
169
|
+
? symbol?.name
|
|
170
|
+
: (flags & SymbolFlags.TypeLiteral) !== 0 &&
|
|
171
|
+
named !== undefined &&
|
|
172
|
+
symbol?.declarations.some((handle) => {
|
|
173
|
+
const node = project.declarationAt(handle)?.node;
|
|
174
|
+
return node !== undefined && isTypeLiteralNode(node);
|
|
175
|
+
}) === true
|
|
176
|
+
? must(queries.typeToString(named))
|
|
177
|
+
: undefined);
|
|
160
178
|
}
|
|
161
|
-
const name = interfaceNames.get(
|
|
179
|
+
const name = interfaceNames.get(key);
|
|
162
180
|
return name === undefined ? [] : [{ type: part, name }];
|
|
163
181
|
});
|
|
164
182
|
/**
|