@cplieger/deadset-ts 8.0.0-dev.16 → 8.0.0-dev.17
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/alias-chain.js +0 -5
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +58 -22
- package/dist/src/augmentations.js +23 -24
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +25 -8
- package/dist/src/commands/tools.js +5 -9
- package/dist/src/component-files.js +3 -2
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +6 -9
- package/dist/src/contextual-uses.js +1 -17
- package/dist/src/contract/config.generated.js +4 -1
- package/dist/src/contract/report.generated.js +6 -2
- package/dist/src/dependencies.js +25 -29
- package/dist/src/destructuring.js +1 -19
- package/dist/src/element-access.js +179 -164
- package/dist/src/entries/build-scripts.js +2 -2
- package/dist/src/entries/configuration-files.js +3 -7
- package/dist/src/entries/conventions.js +2 -2
- package/dist/src/entries/html-entries.js +7 -10
- package/dist/src/entries/mdx-entries.js +2 -2
- package/dist/src/entries/static-module.js +2 -1
- package/dist/src/facts.js +4 -4
- package/dist/src/findings/completion.js +40 -4
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +2 -2
- package/dist/src/framework-lifecycle.js +41 -14
- package/dist/src/graph.js +12 -4
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/interface-satisfaction.js +1 -1
- package/dist/src/keyof-comparisons.js +124 -103
- package/dist/src/load/expected-module.js +2 -2
- package/dist/src/load/specifiers.js +2 -4
- package/dist/src/load/synthesize.js +5 -0
- package/dist/src/load/workspace-resolution.js +2 -2
- package/dist/src/matrix.js +6 -4
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/paths.js +46 -7
- package/dist/src/platform-calls.js +2 -2
- package/dist/src/platform-symbols.js +13 -19
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +151 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +110 -1285
- package/dist/src/roots/configured-declarations.js +3 -0
- package/dist/src/roots/root-set.js +1 -1
- package/dist/src/roots/unseen-loads.js +38 -10
- package/dist/src/serialization-contract.js +8 -3
- package/dist/src/stores.js +4 -2
- package/dist/src/sweep.js +25 -13
- package/dist/src/symbol-keys.js +89 -83
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +2 -11
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/verbs/analyze.js +3 -3
- package/dist/src/verbs/explain.js +50 -28
- package/dist/src/verbs/print-retained.js +2 -2
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/alias-chain.ts +0 -7
- package/src/amd.ts +130 -0
- package/src/analysis.ts +86 -23
- package/src/augmentations.ts +41 -27
- package/src/bindings.ts +460 -0
- package/src/calls.ts +25 -7
- package/src/commands/tools.ts +5 -11
- package/src/component-files.ts +4 -2
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +8 -11
- package/src/contextual-uses.ts +2 -22
- package/src/contract/config.generated.ts +4 -1
- package/src/contract/report.generated.ts +6 -2
- package/src/dependencies.ts +27 -28
- package/src/destructuring.ts +1 -31
- package/src/element-access.ts +188 -182
- package/src/entries/build-scripts.ts +2 -2
- package/src/entries/configuration-files.ts +11 -8
- package/src/entries/conventions.ts +2 -1
- package/src/entries/html-entries.ts +15 -14
- package/src/entries/mdx-entries.ts +2 -2
- package/src/entries/static-module.ts +2 -1
- package/src/facts.ts +5 -3
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +43 -4
- package/src/findings/emitter.ts +1 -1
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
- package/src/framework-lifecycle.ts +42 -14
- package/src/graph.ts +24 -6
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/indexed-access.ts +570 -527
- package/src/interface-satisfaction.ts +1 -1
- package/src/keyof-comparisons.ts +131 -116
- package/src/load/expected-module.ts +8 -2
- package/src/load/specifiers.ts +8 -5
- package/src/load/synthesize.ts +6 -0
- package/src/load/workspace-resolution.ts +9 -2
- package/src/matrix.ts +6 -3
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/paths.ts +54 -8
- package/src/platform-calls.ts +3 -3
- package/src/platform-symbols.ts +11 -27
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +213 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +168 -1733
- package/src/report.ts +1 -1
- package/src/roots/configured-declarations.ts +3 -0
- package/src/roots/root-set.ts +1 -1
- package/src/roots/unseen-loads.ts +49 -11
- package/src/serialization-contract.ts +8 -3
- package/src/stores.ts +13 -2
- package/src/sweep.ts +37 -14
- package/src/symbol-keys.ts +102 -102
- package/src/tests/file-class.ts +118 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +9 -20
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/verbs/analyze.ts +3 -2
- package/src/verbs/explain.ts +74 -31
- package/src/verbs/print-retained.ts +2 -2
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
* call's value is what the read reads, whatever member of the constraint the name resolves
|
|
6
6
|
* to. A class's members a constraint requires are interface satisfaction's.
|
|
7
7
|
*/
|
|
8
|
-
import { isBinaryExpression, isCallExpression, isIdentifier, isNewExpression, isPropertyAccessExpression, isTypeParameterDeclaration, SyntaxKind, } from "@typescript/native/ast";
|
|
8
|
+
import { isBinaryExpression, isCallExpression, isIdentifier, isNewExpression, isPropertyAccessExpression, isSourceFile, isTypeParameterDeclaration, SyntaxKind, } from "@typescript/native/ast";
|
|
9
9
|
import { SymbolFlags } from "@typescript/native/sync";
|
|
10
|
-
import {
|
|
11
|
-
import { renderPosition } from "./position.js";
|
|
12
|
-
import { isAnswered } from "./query.js";
|
|
10
|
+
import { isAnswered, UNANSWERED } from "./query.js";
|
|
13
11
|
/** How deep a parameter's type is matched against the type a call passes: `readonly T[]` is one level. */
|
|
14
12
|
const MATCH_DEPTH = 3;
|
|
15
13
|
/** The name a call reaches one generic by: its own, or that of what holds it. */
|
|
@@ -26,147 +24,188 @@ function assignedTo(access) {
|
|
|
26
24
|
parent.operatorToken.kind === SyntaxKind.EqualsToken &&
|
|
27
25
|
parent.left === access);
|
|
28
26
|
}
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export function typeParameterReads(project, held, chains, root, testFiles) {
|
|
35
|
-
const queries = project.queries;
|
|
36
|
-
const reads = [];
|
|
37
|
-
const calls = [];
|
|
38
|
-
for (const file of project.ownSourceFiles()) {
|
|
39
|
-
const fileId = held.declarations.get(nodeKey(file, file));
|
|
40
|
-
if (fileId === undefined) {
|
|
41
|
-
continue;
|
|
27
|
+
/** Whether one node is written inside a declaration that declares type parameters, itself included. */
|
|
28
|
+
function inGeneric(node) {
|
|
29
|
+
for (let at = node; !isSourceFile(at); at = at.parent) {
|
|
30
|
+
if (at.typeParameters !== undefined) {
|
|
31
|
+
return true;
|
|
42
32
|
}
|
|
43
|
-
const visit = (node, from, generic) => {
|
|
44
|
-
const holder = held.declarations.get(nodeKey(file, node)) ?? from;
|
|
45
|
-
const inside = generic ||
|
|
46
|
-
node.typeParameters !== undefined;
|
|
47
|
-
if (inside &&
|
|
48
|
-
isPropertyAccessExpression(node) &&
|
|
49
|
-
isIdentifier(node.name) &&
|
|
50
|
-
!assignedTo(node)) {
|
|
51
|
-
reads.push({ file, from: holder, access: node });
|
|
52
|
-
}
|
|
53
|
-
if (isCallExpression(node) || isNewExpression(node)) {
|
|
54
|
-
calls.push(node);
|
|
55
|
-
}
|
|
56
|
-
node.forEachChild((child) => {
|
|
57
|
-
visit(child, holder, inside);
|
|
58
|
-
});
|
|
59
|
-
};
|
|
60
|
-
file.forEachChild((child) => {
|
|
61
|
-
visit(child, fileId, false);
|
|
62
|
-
});
|
|
63
33
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (generic !== undefined) {
|
|
83
|
-
byGeneric.set(generic, [...(byGeneric.get(generic) ?? []), { read, parameter: type }]);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
if (byGeneric.size === 0) {
|
|
87
|
-
return [];
|
|
88
|
-
}
|
|
89
|
-
/** The types `instantiated` holds where `declared` holds `parameter`, matched part for part. */
|
|
90
|
-
const passedFor = (parameter, declared, instantiated, depth) => {
|
|
91
|
-
if (declared.id === parameter.id) {
|
|
92
|
-
return [instantiated];
|
|
93
|
-
}
|
|
94
|
-
if (depth >= MATCH_DEPTH) {
|
|
95
|
-
return [];
|
|
96
|
-
}
|
|
97
|
-
const a = queries.typeArguments(declared);
|
|
98
|
-
const b = queries.typeArguments(instantiated);
|
|
99
|
-
if (!isAnswered(a) || !isAnswered(b) || a.length !== b.length) {
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
return a.flatMap((one, at) => {
|
|
103
|
-
const other = b[at];
|
|
104
|
-
return other === undefined ? [] : passedFor(parameter, one, other, depth + 1);
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
// Only a call spelling a generic's name is resolved: one request each.
|
|
108
|
-
const spelled = new Set([...byGeneric.keys()].flatMap((generic) => nameOf(generic) ?? []));
|
|
109
|
-
const found = new Map();
|
|
110
|
-
for (const call of calls) {
|
|
111
|
-
const callee = call.expression;
|
|
112
|
-
const written = isIdentifier(callee)
|
|
113
|
-
? callee.text
|
|
114
|
-
: isPropertyAccessExpression(callee) && isIdentifier(callee.name)
|
|
115
|
-
? callee.name.text
|
|
116
|
-
: undefined;
|
|
117
|
-
if (written === undefined || !spelled.has(written)) {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
const resolved = queries.resolvedSignature(call);
|
|
121
|
-
if (resolved === undefined || !isAnswered(resolved) || resolved.declaration === undefined) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
const generic = project.declarationAt(resolved.declaration)?.node;
|
|
125
|
-
const pending = generic === undefined ? undefined : byGeneric.get(generic);
|
|
126
|
-
const declared = pending === undefined ? undefined : queries.genericOf(resolved);
|
|
127
|
-
if (pending === undefined || declared === undefined || !isAnswered(declared)) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
const count = (generic?.parameters ?? []).length;
|
|
131
|
-
for (const { read, parameter } of pending) {
|
|
132
|
-
const passed = [];
|
|
133
|
-
for (let at = 0; at < count; at += 1) {
|
|
134
|
-
const own = queries.parameterType(declared, at);
|
|
135
|
-
const given = queries.typeAtPosition(resolved, at);
|
|
136
|
-
if (own !== undefined && isAnswered(own) && isAnswered(given)) {
|
|
137
|
-
passed.push(...passedFor(parameter, own, given, 0));
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The reads the reads through type-parameter-typed values of a side's files make of the
|
|
38
|
+
* members of the types its calls pass, each made by the declaration holding the read. A
|
|
39
|
+
* question the checker leaves unanswered holds every member the read's name spells.
|
|
40
|
+
*/
|
|
41
|
+
export const typeParameterReads = {
|
|
42
|
+
start() {
|
|
43
|
+
const reads = [];
|
|
44
|
+
const calls = [];
|
|
45
|
+
return {
|
|
46
|
+
visit(node, { file, from }) {
|
|
47
|
+
if (isPropertyAccessExpression(node) &&
|
|
48
|
+
isIdentifier(node.name) &&
|
|
49
|
+
!assignedTo(node) &&
|
|
50
|
+
inGeneric(node)) {
|
|
51
|
+
reads.push({ file, from, access: node });
|
|
138
52
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
53
|
+
if (isCallExpression(node) || isNewExpression(node)) {
|
|
54
|
+
calls.push(node);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
reads({ project, chains }) {
|
|
58
|
+
const out = [];
|
|
59
|
+
if (reads.length === 0) {
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
const queries = project.queries;
|
|
63
|
+
const hold = (read) => {
|
|
64
|
+
out.push({ kind: "held", from: read.from, names: [read.access.name.text] });
|
|
65
|
+
};
|
|
66
|
+
// The reads whose receiver the checker types as a type parameter, by the generic declaring it.
|
|
67
|
+
const receivers = queries.typesAt(reads.map((read) => read.access.expression));
|
|
68
|
+
const byGeneric = new Map();
|
|
69
|
+
reads.forEach((read, at) => {
|
|
70
|
+
const type = receivers[at];
|
|
71
|
+
if (type === UNANSWERED) {
|
|
72
|
+
hold(read);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (type?.isTypeParameter() !== true) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const symbol = queries.symbolOfType(type);
|
|
79
|
+
if (symbol === UNANSWERED) {
|
|
80
|
+
hold(read);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const declaration = symbol === undefined
|
|
84
|
+
? undefined
|
|
85
|
+
: symbol.declarations
|
|
86
|
+
.map((handle) => project.declarationAt(handle)?.node)
|
|
87
|
+
.find((node) => node !== undefined && isTypeParameterDeclaration(node));
|
|
88
|
+
const generic = declaration?.parent;
|
|
89
|
+
if (generic !== undefined) {
|
|
90
|
+
byGeneric.set(generic, [...(byGeneric.get(generic) ?? []), { read, parameter: type }]);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (byGeneric.size === 0) {
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
/** The types `instantiated` holds where `declared` holds `parameter`, matched part for part. */
|
|
97
|
+
const passedFor = (read, parameter, declared, instantiated, depth) => {
|
|
98
|
+
if (declared.id === parameter.id) {
|
|
99
|
+
return [instantiated];
|
|
100
|
+
}
|
|
101
|
+
if (depth >= MATCH_DEPTH) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const a = queries.typeArguments(declared);
|
|
105
|
+
const b = queries.typeArguments(instantiated);
|
|
106
|
+
if (!isAnswered(a) || !isAnswered(b)) {
|
|
107
|
+
hold(read);
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
if (a.length !== b.length) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
return a.flatMap((one, at) => {
|
|
114
|
+
const other = b[at];
|
|
115
|
+
return other === undefined ? [] : passedFor(read, parameter, one, other, depth + 1);
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
// Only a call spelling a generic's name is resolved: one request each.
|
|
119
|
+
const bySpelling = new Map();
|
|
120
|
+
for (const [generic, pending] of byGeneric) {
|
|
121
|
+
const name = nameOf(generic);
|
|
122
|
+
if (name !== undefined) {
|
|
123
|
+
bySpelling.set(name, [
|
|
124
|
+
...(bySpelling.get(name) ?? []),
|
|
125
|
+
...pending.map((one) => one.read),
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const found = new Map();
|
|
130
|
+
for (const call of calls) {
|
|
131
|
+
const callee = call.expression;
|
|
132
|
+
const written = isIdentifier(callee)
|
|
133
|
+
? callee.text
|
|
134
|
+
: isPropertyAccessExpression(callee) && isIdentifier(callee.name)
|
|
135
|
+
? callee.name.text
|
|
136
|
+
: undefined;
|
|
137
|
+
const spelledBy = written === undefined ? undefined : bySpelling.get(written);
|
|
138
|
+
if (spelledBy === undefined) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const resolved = queries.resolvedSignature(call);
|
|
142
|
+
if (resolved === UNANSWERED) {
|
|
143
|
+
spelledBy.forEach(hold);
|
|
149
144
|
continue;
|
|
150
145
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
if (resolved?.declaration === undefined) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const generic = project.declarationAt(resolved.declaration)?.node;
|
|
150
|
+
const pending = generic === undefined ? undefined : byGeneric.get(generic);
|
|
151
|
+
const declared = pending === undefined ? undefined : queries.genericOf(resolved);
|
|
152
|
+
if (declared === UNANSWERED) {
|
|
153
|
+
pending?.forEach((one) => {
|
|
154
|
+
hold(one.read);
|
|
155
|
+
});
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (pending === undefined || declared === undefined) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const count = (generic?.parameters ?? []).length;
|
|
162
|
+
for (const { read, parameter } of pending) {
|
|
163
|
+
const passed = [];
|
|
164
|
+
for (let at = 0; at < count; at += 1) {
|
|
165
|
+
const own = queries.parameterType(declared, at);
|
|
166
|
+
const given = queries.typeAtPosition(resolved, at);
|
|
167
|
+
if (own === UNANSWERED || given === UNANSWERED) {
|
|
168
|
+
hold(read);
|
|
169
|
+
}
|
|
170
|
+
else if (own !== undefined) {
|
|
171
|
+
passed.push(...passedFor(read, parameter, own, given, 0));
|
|
172
|
+
}
|
|
155
173
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
174
|
+
const name = read.access.name.text;
|
|
175
|
+
for (const type of passed) {
|
|
176
|
+
const parts = type.isUnionType() ? queries.constituents(type) : [type];
|
|
177
|
+
for (const part of isAnswered(parts) ? parts : [type]) {
|
|
178
|
+
const owner = queries.symbolOfType(part);
|
|
179
|
+
const properties = queries.propertiesOf(part);
|
|
180
|
+
if (owner === UNANSWERED || properties === UNANSWERED) {
|
|
181
|
+
hold(read);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (owner === undefined || (owner.flags & SymbolFlags.Class) !== 0) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
for (const property of properties) {
|
|
188
|
+
if (property.name !== name) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
for (const to of chains.declarationsOf(property)) {
|
|
192
|
+
found.set(`${read.from}\u0000${to}\u0000${String(read.access.name.pos)}`, {
|
|
193
|
+
kind: "named",
|
|
194
|
+
from: read.from,
|
|
195
|
+
to,
|
|
196
|
+
file: read.file,
|
|
197
|
+
at: read.access.name,
|
|
198
|
+
use: "read",
|
|
199
|
+
via: "batch",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
165
204
|
}
|
|
166
205
|
}
|
|
167
206
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
207
|
+
return [...out, ...found.values()];
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
};
|