@cplieger/deadset-ts 8.0.0-dev.16 → 8.0.0-dev.18
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 +82 -91
- package/dist/src/augmentations.js +24 -25
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +279 -43
- 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/contract.generated.js +2 -2
- 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/exempt.js +0 -26
- package/dist/src/exposure.js +400 -0
- package/dist/src/facts.js +4 -4
- package/dist/src/findings/completion.js +44 -21
- package/dist/src/findings/emitters.js +22 -33
- 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/findings/intra-function.js +3 -3
- package/dist/src/findings/reads-and-writes.js +71 -15
- package/dist/src/findings/unused-declarations.js +2 -22
- package/dist/src/findings/visibility-narrowing.js +14 -20
- package/dist/src/framework-lifecycle.js +41 -14
- 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/inventory.js +18 -0
- package/dist/src/keyof-comparisons.js +124 -103
- package/dist/src/{components.js → liveness/components.js} +1 -1
- package/dist/src/{graph.js → liveness/graph.js} +45 -20
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- 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/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/query.js +46 -0
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +237 -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/published-reach.js +4 -4
- 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/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 +75 -132
- package/dist/src/verbs/print-retained.js +3 -3
- 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 +125 -128
- package/src/augmentations.ts +42 -28
- package/src/bindings.ts +460 -0
- package/src/calls.ts +338 -46
- 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/contract.generated.ts +2 -2
- 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/exempt.ts +31 -46
- package/src/exposure.ts +492 -0
- package/src/facts.ts +5 -3
- package/src/finding.ts +1 -1
- package/src/findings/boundary.ts +9 -0
- package/src/findings/completion.ts +48 -23
- package/src/findings/emitter.ts +1 -1
- package/src/findings/emitters.ts +23 -41
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
- package/src/findings/interfaces.ts +3 -3
- package/src/findings/intra-function.ts +3 -3
- package/src/findings/reads-and-writes.ts +99 -26
- package/src/findings/unused-declarations.ts +4 -28
- package/src/findings/visibility-narrowing.ts +25 -26
- package/src/framework-lifecycle.ts +42 -14
- 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 +2 -2
- package/src/inventory.ts +19 -0
- package/src/keyof-comparisons.ts +131 -116
- package/src/{components.ts → liveness/components.ts} +3 -3
- package/src/{graph.ts → liveness/graph.ts} +93 -27
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- 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/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/query.ts +81 -0
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +314 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +175 -1733
- package/src/report.ts +1 -1
- package/src/roots/configured-declarations.ts +3 -0
- package/src/roots/published-reach.ts +9 -4
- 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 +15 -3
- package/src/symbol-keys.ts +102 -102
- package/src/tests/file-class.ts +135 -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 +83 -158
- package/src/verbs/print-retained.ts +3 -3
- package/dist/src/matrix.js +0 -273
- package/dist/src/sweep.js +0 -222
- package/src/matrix.ts +0 -463
- package/src/sweep.ts +0 -361
package/dist/src/dependencies.js
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
* itself is that dependency's need, not the target's.
|
|
8
8
|
*/
|
|
9
9
|
import { isArrayLiteralExpression, isCallExpression, isExportDeclaration, isExpressionStatement, isExternalModuleReference, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isMetaProperty, isNamespaceExport, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isShorthandPropertyAssignment, isStringLiteral, isNoSubstitutionTemplateLiteral, SyntaxKind, } from "@typescript/native/ast";
|
|
10
|
+
import { amdLoadOf, amdPlatform } from "./amd.js";
|
|
10
11
|
import { automaticTypes } from "./automatic-types.js";
|
|
11
12
|
import { declaredIn as declaredBeside, dependenciesNamed, moduleStrings, outsideChain, } from "./entries/configuration-files.js";
|
|
13
|
+
import { declarationBindings } from "./import-bindings.js";
|
|
12
14
|
import { nodeKey } from "./inventory.js";
|
|
13
15
|
import { packageScope } from "./load/package-scope.js";
|
|
14
|
-
import { ancestors,
|
|
16
|
+
import { ancestors, cannotStartPackageName, dirnamePath, joinPath, relativePath, resolvePath, } from "./paths.js";
|
|
15
17
|
import { UNANSWERED } from "./query.js";
|
|
16
18
|
import { sourceFilesOf } from "./source-files.js";
|
|
17
19
|
import { manifestCommands, nodemonTexts } from "./roots/manifest.js";
|
|
@@ -153,7 +155,7 @@ function configurationPackages(host, configFile, options, programPackages, parse
|
|
|
153
155
|
}
|
|
154
156
|
seen.add(file);
|
|
155
157
|
for (const entry of extendsOf(host, file, parse)) {
|
|
156
|
-
if (
|
|
158
|
+
if (cannotStartPackageName(entry)) {
|
|
157
159
|
const local = resolvePath(dirnamePath(file), entry);
|
|
158
160
|
pending.push(local.endsWith(".json") ? local : `${local}.json`);
|
|
159
161
|
}
|
|
@@ -178,27 +180,9 @@ function importOf(specifier) {
|
|
|
178
180
|
}
|
|
179
181
|
/** The local names one import declaration binds. */
|
|
180
182
|
function bindingsOf(node) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (isImportEqualsDeclaration(node)) {
|
|
185
|
-
return [node.name];
|
|
186
|
-
}
|
|
187
|
-
if (!isImportDeclaration(node) || node.importClause === undefined) {
|
|
188
|
-
return [];
|
|
189
|
-
}
|
|
190
|
-
const clause = node.importClause;
|
|
191
|
-
const names = clause.name === undefined ? [] : [clause.name];
|
|
192
|
-
const bindings = clause.namedBindings;
|
|
193
|
-
if (bindings !== undefined) {
|
|
194
|
-
if (bindings.kind === SyntaxKind.NamespaceImport) {
|
|
195
|
-
names.push(bindings.name);
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
names.push(...bindings.elements.map((element) => element.name));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return names;
|
|
183
|
+
return node !== undefined && (isImportDeclaration(node) || isImportEqualsDeclaration(node))
|
|
184
|
+
? declarationBindings(node).map((binding) => binding.name)
|
|
185
|
+
: [];
|
|
202
186
|
}
|
|
203
187
|
/**
|
|
204
188
|
* Every package one project needs, and which declaration each use is written in.
|
|
@@ -428,6 +412,7 @@ function fileNeeds(project, held, file, { programPackages, automatic }, use) {
|
|
|
428
412
|
}
|
|
429
413
|
const loads = runtimeLoads(file);
|
|
430
414
|
const callees = loads.flatMap((load) => load.callees);
|
|
415
|
+
const amdCallees = new Set(loads.flatMap((load) => (load.amd ? load.callees : [])));
|
|
431
416
|
const asked = [
|
|
432
417
|
...specifiers,
|
|
433
418
|
...bindings.map(({ node }) => node),
|
|
@@ -517,10 +502,11 @@ function fileNeeds(project, held, file, { programPackages, automatic }, use) {
|
|
|
517
502
|
unansweredCallees.add(callee);
|
|
518
503
|
return;
|
|
519
504
|
}
|
|
520
|
-
// The decision reads the callee's symbol and its
|
|
521
|
-
const
|
|
505
|
+
// The decision reads the callee's symbol, its written name and its platform name, and nothing else.
|
|
506
|
+
const platform = amdCallees.has(callee) ? amdPlatform(callee) : "require";
|
|
507
|
+
const key = symbol === undefined ? undefined : `${symbol.id}\u0000${platform}\u0000${callee.text}`;
|
|
522
508
|
const answer = (key === undefined ? undefined : decided.get(key)) ??
|
|
523
|
-
callsPlatform(project,
|
|
509
|
+
callsPlatform(project, platform, callee, symbol);
|
|
524
510
|
if (key !== undefined) {
|
|
525
511
|
decided.set(key, answer);
|
|
526
512
|
}
|
|
@@ -543,12 +529,22 @@ function fileNeeds(project, held, file, { programPackages, automatic }, use) {
|
|
|
543
529
|
* argument is literal text naming a package: a `require()` call, which the compiler lists among
|
|
544
530
|
* a file's imports only in a JavaScript file and only through the bare name; a `.resolve` of
|
|
545
531
|
* another name, which needs it where that name is a `require`; and `import.meta.resolve` or
|
|
546
|
-
* a `.resolve` of the name `require`, whatever it names, a use where it stands
|
|
532
|
+
* a `.resolve` of the name `require`, whatever it names, a use where it stands; and each id of
|
|
533
|
+
* an AMD dependency list (references-ts.37), which needs it where the call is AMD's.
|
|
547
534
|
*/
|
|
548
535
|
function runtimeLoads(file) {
|
|
549
536
|
const found = [];
|
|
550
537
|
const visit = (node) => {
|
|
551
|
-
|
|
538
|
+
const amd = amdLoadOf(node);
|
|
539
|
+
if (amd !== undefined) {
|
|
540
|
+
for (const { id } of amd.ids) {
|
|
541
|
+
const named = packageOfSpecifier(id.text);
|
|
542
|
+
if (named !== undefined) {
|
|
543
|
+
found.push({ specifier: id, named, callees: [amd.callee], amd: true });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
else if (isCallExpression(node)) {
|
|
552
548
|
const [argument] = node.arguments;
|
|
553
549
|
if (argument !== undefined && isLiteralText(argument)) {
|
|
554
550
|
const named = packageOfSpecifier(argument.text);
|
|
@@ -566,7 +562,7 @@ function runtimeLoads(file) {
|
|
|
566
562
|
receiver === undefined ? undefined : writtenName(receiver),
|
|
567
563
|
].filter((one) => one !== undefined);
|
|
568
564
|
if (named !== undefined && (stands || callees.length > 0)) {
|
|
569
|
-
found.push({ specifier: argument, named, callees });
|
|
565
|
+
found.push({ specifier: argument, named, callees, amd: false });
|
|
570
566
|
}
|
|
571
567
|
}
|
|
572
568
|
}
|
|
@@ -156,8 +156,6 @@ function sourceOf(target) {
|
|
|
156
156
|
export function destructuring(project, cap, properties = propertyTables(project.queries)) {
|
|
157
157
|
const queries = project.queries;
|
|
158
158
|
const tables = new Map();
|
|
159
|
-
let patternBatches = 0;
|
|
160
|
-
let patternLookups = 0;
|
|
161
159
|
const tableOf = (type) => {
|
|
162
160
|
const known = tables.get(type.id);
|
|
163
161
|
if (known !== undefined) {
|
|
@@ -166,7 +164,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
166
164
|
let table = new Map();
|
|
167
165
|
if ((type.flags & TypeFlags.AnyOrUnknown) === 0) {
|
|
168
166
|
const read = properties.of(type);
|
|
169
|
-
patternLookups += read.asked ? 1 : 0;
|
|
170
167
|
table = isAnswered(read.properties)
|
|
171
168
|
? new Map(read.properties.map((property) => [property.name, property]))
|
|
172
169
|
: UNANSWERED;
|
|
@@ -178,7 +175,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
178
175
|
if ((type.flags & TypeFlags.Union) === 0) {
|
|
179
176
|
return type;
|
|
180
177
|
}
|
|
181
|
-
patternLookups += 1;
|
|
182
178
|
return queries.nonNullable(type);
|
|
183
179
|
};
|
|
184
180
|
/**
|
|
@@ -193,11 +189,9 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
193
189
|
if (index === undefined) {
|
|
194
190
|
return undefined;
|
|
195
191
|
}
|
|
196
|
-
patternLookups += 1;
|
|
197
192
|
const elements = queries.typeArguments(type);
|
|
198
193
|
return isAnswered(elements) ? elements[index] : UNANSWERED;
|
|
199
194
|
}
|
|
200
|
-
patternLookups += 1;
|
|
201
195
|
const array = queries.isArray(type);
|
|
202
196
|
if (!isAnswered(array)) {
|
|
203
197
|
return UNANSWERED;
|
|
@@ -205,7 +199,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
205
199
|
if (!array) {
|
|
206
200
|
return undefined;
|
|
207
201
|
}
|
|
208
|
-
patternLookups += 1;
|
|
209
202
|
const elements = queries.typeArguments(type);
|
|
210
203
|
return isAnswered(elements) ? elements[0] : UNANSWERED;
|
|
211
204
|
};
|
|
@@ -222,14 +215,12 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
222
215
|
if (more.length > 0) {
|
|
223
216
|
return UNANSWERED;
|
|
224
217
|
}
|
|
225
|
-
patternLookups += 1;
|
|
226
218
|
return queries.typeOfSymbol(property);
|
|
227
219
|
};
|
|
228
220
|
const resultOf = (callee) => {
|
|
229
221
|
if (callee === undefined || callee === UNANSWERED) {
|
|
230
222
|
return callee;
|
|
231
223
|
}
|
|
232
|
-
patternLookups += 1;
|
|
233
224
|
const signatures = queries.signaturesOf(callee, SignatureKind.Call);
|
|
234
225
|
if (!isAnswered(signatures)) {
|
|
235
226
|
return UNANSWERED;
|
|
@@ -238,7 +229,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
238
229
|
if (signature === undefined) {
|
|
239
230
|
return undefined;
|
|
240
231
|
}
|
|
241
|
-
patternLookups += 1;
|
|
242
232
|
return queries.returnTypeOf(signature);
|
|
243
233
|
};
|
|
244
234
|
const iterations = new Map();
|
|
@@ -266,7 +256,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
266
256
|
if (result !== undefined && result !== UNANSWERED) {
|
|
267
257
|
let parts = [result];
|
|
268
258
|
if (result.isUnionType()) {
|
|
269
|
-
patternLookups += 1;
|
|
270
259
|
parts = queries.constituents(result);
|
|
271
260
|
}
|
|
272
261
|
const values = isAnswered(parts)
|
|
@@ -296,7 +285,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
296
285
|
if (property === undefined) {
|
|
297
286
|
return undefined;
|
|
298
287
|
}
|
|
299
|
-
patternLookups += 1;
|
|
300
288
|
return queries.typeOfSymbol(property);
|
|
301
289
|
}
|
|
302
290
|
return elementOf(defined, next.index);
|
|
@@ -317,7 +305,6 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
317
305
|
}
|
|
318
306
|
}
|
|
319
307
|
const asked = [...asking];
|
|
320
|
-
patternBatches += Math.ceil(asked.length / cap);
|
|
321
308
|
const answered = new Map();
|
|
322
309
|
queries.typesAt(asked, cap).forEach((type, index) => {
|
|
323
310
|
const node = asked[index];
|
|
@@ -347,10 +334,5 @@ export function destructuring(project, cap, properties = propertyTables(project.
|
|
|
347
334
|
return isAnswered(table) ? table.get(read.name) : UNANSWERED;
|
|
348
335
|
});
|
|
349
336
|
};
|
|
350
|
-
return {
|
|
351
|
-
resolve,
|
|
352
|
-
get cost() {
|
|
353
|
-
return { patternBatches, patternLookups };
|
|
354
|
-
},
|
|
355
|
-
};
|
|
337
|
+
return { resolve };
|
|
356
338
|
}
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* target holds, the members are read at each call, by the type of the argument it passes.
|
|
6
6
|
*/
|
|
7
7
|
import { isArrayLiteralExpression, isArrowFunction, isBinaryExpression, isCallExpression, isElementAccessExpression, isForInStatement, isForOfStatement, isFunctionDeclaration, isFunctionExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isSpreadElement, isStringLiteral, isVariableDeclaration, isVariableDeclarationList, isVariableStatement, NodeFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
8
|
-
import { nodeKey } from "./inventory.js";
|
|
9
|
-
import { renderPosition } from "./position.js";
|
|
10
8
|
import { UNANSWERED } from "./query.js";
|
|
11
9
|
import { parenthesesRemoved } from "./unwrap.js";
|
|
12
10
|
/** The assignment operators that read their target before they write it. */
|
|
@@ -153,174 +151,191 @@ function assigns(body, name) {
|
|
|
153
151
|
return found;
|
|
154
152
|
}
|
|
155
153
|
/**
|
|
156
|
-
* The
|
|
157
|
-
*
|
|
154
|
+
* The reads the element accesses of a side's files make of the members their index's literal
|
|
155
|
+
* type names, each made by the declaration holding the access or the call. A type the checker
|
|
156
|
+
* leaves unanswered holds what its answer could have read.
|
|
158
157
|
*/
|
|
159
|
-
export
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (isCallExpression(node)) {
|
|
175
|
-
calls.set(node, { file, from: holder });
|
|
176
|
-
}
|
|
177
|
-
if (isIdentifier(node)) {
|
|
178
|
-
names.push(node);
|
|
179
|
-
}
|
|
180
|
-
node.forEachChild((child) => {
|
|
181
|
-
visit(child, holder);
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
file.forEachChild((child) => {
|
|
185
|
-
visit(child, fileId);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
if (candidates.length === 0) {
|
|
189
|
-
return [];
|
|
190
|
-
}
|
|
191
|
-
// A parameter index is decided at the calls only where the function is a callable every
|
|
192
|
-
// use of which is a call, so the symbols of the parameters and of every name are read.
|
|
193
|
-
const parameterOf = new Map();
|
|
194
|
-
const byCallable = new Map();
|
|
195
|
-
for (const candidate of candidates) {
|
|
196
|
-
const index = parenthesesRemoved(candidate.access.argumentExpression);
|
|
197
|
-
const fn = isIdentifier(index) ? enclosingFunction(candidate.access) : undefined;
|
|
198
|
-
const callable = fn === undefined ? undefined : callableOf(fn);
|
|
199
|
-
if (callable === undefined || !isIdentifier(index)) {
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
const at = callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === index.text);
|
|
203
|
-
if (at < 0 || assigns(callable.body, index.text)) {
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
parameterOf.set(candidate, { callable, at });
|
|
207
|
-
byCallable.set(callable.name, [...(byCallable.get(callable.name) ?? []), candidate]);
|
|
208
|
-
}
|
|
209
|
-
const callableNames = [...byCallable.keys()];
|
|
210
|
-
const spelled = new Set(callableNames.map((name) => name.text));
|
|
211
|
-
const sameName = names.filter((name) => spelled.has(name.text));
|
|
212
|
-
const symbols = queries.symbolsAt([...callableNames, ...sameName]);
|
|
213
|
-
const symbolOf = new Map();
|
|
214
|
-
[...callableNames, ...sameName].forEach((node, at) => {
|
|
215
|
-
const symbol = symbols[at];
|
|
216
|
-
if (symbol !== UNANSWERED && symbol !== undefined) {
|
|
217
|
-
symbolOf.set(node, symbol);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
const callsOf = new Map();
|
|
221
|
-
for (const name of callableNames) {
|
|
222
|
-
const symbol = symbolOf.get(name);
|
|
223
|
-
let found = symbol === undefined ? undefined : [];
|
|
224
|
-
for (const use of sameName) {
|
|
225
|
-
if (found === undefined) {
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
if (use === name || symbolOf.get(use) !== symbol) {
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
const parent = use.parent;
|
|
232
|
-
found =
|
|
233
|
-
isCallExpression(parent) && parent.expression === use ? [...found, parent] : undefined;
|
|
234
|
-
}
|
|
235
|
-
callsOf.set(name, found);
|
|
236
|
-
}
|
|
237
|
-
const lookups = [];
|
|
238
|
-
for (const candidate of candidates) {
|
|
239
|
-
const deferred = parameterOf.get(candidate);
|
|
240
|
-
const sites = deferred === undefined ? undefined : callsOf.get(deferred.callable.name);
|
|
241
|
-
if (deferred === undefined || sites === undefined) {
|
|
242
|
-
lookups.push({
|
|
243
|
-
file: candidate.file,
|
|
244
|
-
from: candidate.from,
|
|
245
|
-
at: candidate.access.argumentExpression,
|
|
246
|
-
object: candidate.access.expression,
|
|
247
|
-
index: candidate.access.argumentExpression,
|
|
248
|
-
use: candidate.use,
|
|
249
|
-
});
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
// An object that is a parameter too is read as the argument each call passes there.
|
|
253
|
-
const object = parenthesesRemoved(candidate.access.expression);
|
|
254
|
-
const objectAt = isIdentifier(object)
|
|
255
|
-
? deferred.callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === object.text)
|
|
256
|
-
: -1;
|
|
257
|
-
for (const call of sites) {
|
|
258
|
-
const parameter = deferred.callable.parameters[deferred.at];
|
|
259
|
-
const index = call.arguments[deferred.at] ?? parameter?.initializer;
|
|
260
|
-
const site = calls.get(call);
|
|
261
|
-
if (index === undefined || site === undefined) {
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
lookups.push({
|
|
265
|
-
file: site.file,
|
|
266
|
-
from: site.from,
|
|
267
|
-
at: call,
|
|
268
|
-
object: (objectAt < 0 ? undefined : call.arguments[objectAt]) ?? candidate.access.expression,
|
|
269
|
-
index,
|
|
270
|
-
use: candidate.use,
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
const nodes = lookups.flatMap((one) => [one.index, one.object]);
|
|
275
|
-
const types = queries.typesAt(nodes);
|
|
276
|
-
const typeOf = (node, at) => {
|
|
277
|
-
const type = types[at];
|
|
278
|
-
return nodes[at] === node && type !== UNANSWERED ? type : undefined;
|
|
279
|
-
};
|
|
280
|
-
// A type parameter's body serves every instantiation, so it reads what its constraint admits.
|
|
281
|
-
const keysOf = (type) => {
|
|
282
|
-
if (!type.isTypeParameter()) {
|
|
283
|
-
return type;
|
|
284
|
-
}
|
|
285
|
-
const constraint = queries.constraintOf(type);
|
|
286
|
-
return constraint === UNANSWERED || constraint === undefined ? type : constraint;
|
|
287
|
-
};
|
|
288
|
-
const partsOf = (type) => {
|
|
289
|
-
const parts = queries.constituents(type);
|
|
290
|
-
return parts === UNANSWERED ? [type] : parts;
|
|
291
|
-
};
|
|
292
|
-
const found = [];
|
|
293
|
-
lookups.forEach((lookup, at) => {
|
|
294
|
-
const indexType = typeOf(lookup.index, 2 * at);
|
|
295
|
-
const objectType = typeOf(lookup.object, 2 * at + 1);
|
|
296
|
-
const literals = indexType === undefined ? undefined : literalNames(partsOf(keysOf(indexType)));
|
|
297
|
-
if (objectType === undefined || literals === undefined) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
const position = renderPosition(lookup.file, root, lookup.at.getStart());
|
|
301
|
-
for (const part of partsOf(objectType)) {
|
|
302
|
-
const properties = queries.propertiesOf(part);
|
|
303
|
-
for (const property of properties === UNANSWERED ? [] : properties) {
|
|
304
|
-
if (!literals.has(property.escapedName)) {
|
|
305
|
-
continue;
|
|
158
|
+
export const elementAccess = {
|
|
159
|
+
start() {
|
|
160
|
+
const candidates = [];
|
|
161
|
+
const calls = new Map();
|
|
162
|
+
const names = [];
|
|
163
|
+
return {
|
|
164
|
+
visit(node, { file, from }) {
|
|
165
|
+
if (isElementAccessExpression(node) && !isLiteralIndex(node.argumentExpression)) {
|
|
166
|
+
candidates.push({ file, from, access: node, use: useOf(node) });
|
|
167
|
+
}
|
|
168
|
+
if (isCallExpression(node)) {
|
|
169
|
+
calls.set(node, { file, from });
|
|
170
|
+
}
|
|
171
|
+
if (isIdentifier(node)) {
|
|
172
|
+
names.push(node);
|
|
306
173
|
}
|
|
307
|
-
|
|
308
|
-
|
|
174
|
+
},
|
|
175
|
+
reads({ project, chains }) {
|
|
176
|
+
const found = [];
|
|
177
|
+
if (candidates.length === 0) {
|
|
178
|
+
return found;
|
|
179
|
+
}
|
|
180
|
+
const queries = project.queries;
|
|
181
|
+
// A parameter index is decided at the calls only where the function is a callable every
|
|
182
|
+
// use of which is a call, so the symbols of the parameters and of every name are read.
|
|
183
|
+
const parameterOf = new Map();
|
|
184
|
+
const byCallable = new Map();
|
|
185
|
+
for (const candidate of candidates) {
|
|
186
|
+
const index = parenthesesRemoved(candidate.access.argumentExpression);
|
|
187
|
+
const fn = isIdentifier(index) ? enclosingFunction(candidate.access) : undefined;
|
|
188
|
+
const callable = fn === undefined ? undefined : callableOf(fn);
|
|
189
|
+
if (callable === undefined || !isIdentifier(index)) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const at = callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === index.text);
|
|
193
|
+
if (at < 0 || assigns(callable.body, index.text)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
parameterOf.set(candidate, { callable, at });
|
|
197
|
+
byCallable.set(callable.name, [...(byCallable.get(callable.name) ?? []), candidate]);
|
|
198
|
+
}
|
|
199
|
+
const callableNames = [...byCallable.keys()];
|
|
200
|
+
const spelled = new Set(callableNames.map((name) => name.text));
|
|
201
|
+
const sameName = names.filter((name) => spelled.has(name.text));
|
|
202
|
+
const asked = [...callableNames, ...sameName];
|
|
203
|
+
const symbols = queries.symbolsAt(asked);
|
|
204
|
+
const symbolOf = new Map();
|
|
205
|
+
asked.forEach((node, at) => {
|
|
206
|
+
const symbol = symbols[at];
|
|
207
|
+
if (symbol !== undefined) {
|
|
208
|
+
symbolOf.set(node, symbol);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const callsOf = new Map();
|
|
212
|
+
for (const name of callableNames) {
|
|
213
|
+
const symbol = symbolOf.get(name);
|
|
214
|
+
let sites = symbol === undefined || symbol === UNANSWERED ? undefined : [];
|
|
215
|
+
for (const use of sameName) {
|
|
216
|
+
if (sites === undefined) {
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
const other = symbolOf.get(use);
|
|
220
|
+
if (use === name || (other !== symbol && other !== UNANSWERED)) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// A use the checker could not resolve may be the function's, read where it is not called.
|
|
224
|
+
const parent = use.parent;
|
|
225
|
+
sites =
|
|
226
|
+
other !== UNANSWERED && isCallExpression(parent) && parent.expression === use
|
|
227
|
+
? [...sites, parent]
|
|
228
|
+
: undefined;
|
|
229
|
+
}
|
|
230
|
+
callsOf.set(name, sites);
|
|
231
|
+
}
|
|
232
|
+
const lookups = [];
|
|
233
|
+
for (const candidate of candidates) {
|
|
234
|
+
const deferred = parameterOf.get(candidate);
|
|
235
|
+
const sites = deferred === undefined ? undefined : callsOf.get(deferred.callable.name);
|
|
236
|
+
if (deferred === undefined || sites === undefined) {
|
|
237
|
+
lookups.push({
|
|
238
|
+
file: candidate.file,
|
|
239
|
+
from: candidate.from,
|
|
240
|
+
at: candidate.access.argumentExpression,
|
|
241
|
+
object: candidate.access.expression,
|
|
242
|
+
index: candidate.access.argumentExpression,
|
|
243
|
+
use: candidate.use,
|
|
244
|
+
});
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// An object that is a parameter too is read as the argument each call passes there.
|
|
248
|
+
const object = parenthesesRemoved(candidate.access.expression);
|
|
249
|
+
const objectAt = isIdentifier(object)
|
|
250
|
+
? deferred.callable.parameters.findIndex((parameter) => isIdentifier(parameter.name) && parameter.name.text === object.text)
|
|
251
|
+
: -1;
|
|
252
|
+
for (const call of sites) {
|
|
253
|
+
const parameter = deferred.callable.parameters[deferred.at];
|
|
254
|
+
const index = call.arguments[deferred.at] ?? parameter?.initializer;
|
|
255
|
+
const site = calls.get(call);
|
|
256
|
+
if (index === undefined || site === undefined) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
lookups.push({
|
|
260
|
+
file: site.file,
|
|
261
|
+
from: site.from,
|
|
262
|
+
at: call,
|
|
263
|
+
object: (objectAt < 0 ? undefined : call.arguments[objectAt]) ??
|
|
264
|
+
candidate.access.expression,
|
|
265
|
+
index,
|
|
266
|
+
use: candidate.use,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const nodes = lookups.flatMap((one) => [one.index, one.object]);
|
|
271
|
+
const types = queries.typesAt(nodes);
|
|
272
|
+
// A type parameter's body serves every instantiation, so it reads what its constraint admits.
|
|
273
|
+
const keysOf = (type) => {
|
|
274
|
+
if (!type.isTypeParameter()) {
|
|
275
|
+
return type;
|
|
276
|
+
}
|
|
277
|
+
const constraint = queries.constraintOf(type);
|
|
278
|
+
return constraint === UNANSWERED || constraint === undefined ? type : constraint;
|
|
279
|
+
};
|
|
280
|
+
const partsOf = (type) => {
|
|
281
|
+
const parts = queries.constituents(type);
|
|
282
|
+
return parts === UNANSWERED ? [type] : parts;
|
|
283
|
+
};
|
|
284
|
+
lookups.forEach((lookup, at) => {
|
|
285
|
+
const indexType = types[2 * at];
|
|
286
|
+
const objectType = types[2 * at + 1];
|
|
287
|
+
const literals = indexType === undefined || indexType === UNANSWERED
|
|
288
|
+
? undefined
|
|
289
|
+
: literalNames(partsOf(keysOf(indexType)));
|
|
290
|
+
if (indexType === UNANSWERED || objectType === UNANSWERED) {
|
|
309
291
|
found.push({
|
|
292
|
+
kind: "held",
|
|
310
293
|
from: lookup.from,
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
294
|
+
...(literals === undefined ? {} : { names: [...literals] }),
|
|
295
|
+
...(objectType === UNANSWERED || objectType === undefined
|
|
296
|
+
? literals === undefined
|
|
297
|
+
? { members: true }
|
|
298
|
+
: {}
|
|
299
|
+
: { types: partsOf(objectType) }),
|
|
316
300
|
});
|
|
301
|
+
return;
|
|
317
302
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
303
|
+
if (objectType === undefined || literals === undefined) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
for (const part of partsOf(objectType)) {
|
|
307
|
+
const properties = queries.propertiesOf(part);
|
|
308
|
+
if (properties === UNANSWERED) {
|
|
309
|
+
found.push({ kind: "held", from: lookup.from, names: [...literals] });
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
for (const property of properties) {
|
|
313
|
+
if (!literals.has(property.escapedName)) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
for (const to of chains.declarationsOf(property)) {
|
|
317
|
+
for (const use of lookup.use === "both"
|
|
318
|
+
? ["read", "write"]
|
|
319
|
+
: [lookup.use]) {
|
|
320
|
+
found.push({
|
|
321
|
+
kind: "named",
|
|
322
|
+
from: lookup.from,
|
|
323
|
+
to,
|
|
324
|
+
file: lookup.file,
|
|
325
|
+
at: lookup.at,
|
|
326
|
+
use,
|
|
327
|
+
via: "keyed",
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
return found;
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
},
|
|
338
|
+
};
|
|
324
339
|
/** The names a union of literal types spells, or none where a constituent is no string or number literal. */
|
|
325
340
|
function literalNames(parts) {
|
|
326
341
|
const names = new Set();
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { isArrowFunction, isCallExpression, isConstructorDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isIdentifier, isMethodDeclaration, isNewExpression, isSetAccessorDeclaration, isVariableDeclaration, } from "@typescript/native/ast";
|
|
8
8
|
import { declarationOf, membersNamed, staticModule } from "./static-module.js";
|
|
9
9
|
import { filesNamedBy } from "./configuration-files.js";
|
|
10
|
-
import { ancestors, dirnamePath, relativePath, resolvePath } from "../paths.js";
|
|
10
|
+
import { ancestors, dirnamePath, isExplicitPath, relativePath, resolvePath } from "../paths.js";
|
|
11
11
|
import { bytewise } from "../text/compare.js";
|
|
12
12
|
import { unwrapped } from "../unwrap.js";
|
|
13
13
|
import { holdsManifest, inInstalledPackages, manifestAt } from "../fs/manifest.js";
|
|
@@ -43,7 +43,7 @@ function lastMember(object, key) {
|
|
|
43
43
|
function pathOf(value, dir, scriptDir) {
|
|
44
44
|
if (value.kind === "text") {
|
|
45
45
|
const { text } = value;
|
|
46
|
-
const request = !
|
|
46
|
+
const request = !isExplicitPath(text);
|
|
47
47
|
return { path: resolvePath(dir, text), text, request };
|
|
48
48
|
}
|
|
49
49
|
if (value.kind === "directory") {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { isNoSubstitutionTemplateLiteral, isStringLiteral, } from "@typescript/native/ast";
|
|
10
10
|
import { relativeSpecifiers } from "./static-module.js";
|
|
11
|
-
import { ancestors, dirnamePath, joinPath, relativePath, resolvePath } from "../paths.js";
|
|
11
|
+
import { ancestors, dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath, startsRelativePath, } from "../paths.js";
|
|
12
12
|
import { bytewise } from "../text/compare.js";
|
|
13
13
|
import { isRecord } from "../json-document.js";
|
|
14
14
|
import { filesIn } from "../fs/tree.js";
|
|
@@ -32,8 +32,6 @@ const MODULE_FORMS = [
|
|
|
32
32
|
];
|
|
33
33
|
/** A JSON configuration file's name. */
|
|
34
34
|
const DOCUMENT_NAME = /^(?:[\w-]+(?:\.[\w-]+)?\.config\.json|\.[\w-]+rc(?:\.json)?)$/u;
|
|
35
|
-
/** The prefixes a string names a file with, relative to the file that writes it. */
|
|
36
|
-
const RELATIVE_PREFIXES = ["./", "../"];
|
|
37
35
|
/** The JavaScript extensions a relative specifier from a configuration file stands for TypeScript under. */
|
|
38
36
|
const COUNTERPARTS = [
|
|
39
37
|
[".js", [".ts", ".tsx"]],
|
|
@@ -185,9 +183,7 @@ export function configurationFiles(host, targetRoot, files, parse) {
|
|
|
185
183
|
}
|
|
186
184
|
document.manifestDirs.push(next.manifestDir);
|
|
187
185
|
for (const text of document.strings) {
|
|
188
|
-
const path =
|
|
189
|
-
? resolvePath(dirnamePath(next.path), text)
|
|
190
|
-
: undefined;
|
|
186
|
+
const path = startsRelativePath(text) ? resolvePath(dirnamePath(next.path), text) : undefined;
|
|
191
187
|
if (path?.endsWith(".json") === true &&
|
|
192
188
|
isProjectPath(root, path) &&
|
|
193
189
|
host.kindOf(path) === "file") {
|
|
@@ -311,7 +307,7 @@ export function dependenciesNamed(text, declared) {
|
|
|
311
307
|
* none.
|
|
312
308
|
*/
|
|
313
309
|
export function filesNamedBy(files, dir, text) {
|
|
314
|
-
if (text === "" || text
|
|
310
|
+
if (text === "" || isAbsolutePath(text) || /[*?[{]/u.test(text)) {
|
|
315
311
|
return [];
|
|
316
312
|
}
|
|
317
313
|
const path = resolvePath(dir, text);
|
|
@@ -11,7 +11,7 @@ import { documentStrings } from "./configuration-files.js";
|
|
|
11
11
|
import { readCommands } from "../commands/read.js";
|
|
12
12
|
import { nodeTestGlobs, } from "./test-runners.js";
|
|
13
13
|
import { documentModule, membersNamed, staticModule, textsOf, valuesAt, } from "./static-module.js";
|
|
14
|
-
import { ancestors, dirnamePath, joinPath, normalizePath, relativePath, resolvePath, } from "../paths.js";
|
|
14
|
+
import { ancestors, cannotStartPackageName, dirnamePath, joinPath, normalizePath, relativePath, resolvePath, } from "../paths.js";
|
|
15
15
|
import { satisfies } from "../version-range.js";
|
|
16
16
|
import { bytewise } from "../text/compare.js";
|
|
17
17
|
import { isRecord } from "../json-document.js";
|
|
@@ -425,7 +425,7 @@ function prefixedPackage(value, reading) {
|
|
|
425
425
|
const { prefix, marker } = reading;
|
|
426
426
|
let name;
|
|
427
427
|
if (marker === undefined) {
|
|
428
|
-
if (value.includes(":") ||
|
|
428
|
+
if (value.includes(":") || cannotStartPackageName(value)) {
|
|
429
429
|
return undefined;
|
|
430
430
|
}
|
|
431
431
|
const parts = value.split("/");
|