@cplieger/deadset-ts 7.0.0-dev.2 → 7.0.0-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/alias-chain.js +2 -2
- package/dist/src/analysis.js +89 -44
- package/dist/src/augmentations.js +14 -12
- package/dist/src/calls.js +2 -2
- package/dist/src/class-members.js +1 -1
- package/dist/src/components.js +62 -20
- package/dist/src/configuration-files.js +6 -6
- package/dist/src/configured-declarations.js +2 -2
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/contextual-uses.js +71 -14
- package/dist/src/convention-rows.js +6 -2
- package/dist/src/conventions.js +4 -2
- package/dist/src/dependencies.js +81 -27
- package/dist/src/deprecation.js +1 -1
- package/dist/src/destructuring.js +2 -2
- package/dist/src/discover.js +1 -1
- package/dist/src/element-access.js +341 -0
- package/dist/src/entry-points.js +2 -2
- package/dist/src/enum-group.js +2 -2
- package/dist/src/erased-stores.js +317 -0
- package/dist/src/findings/completion.js +46 -15
- package/dist/src/findings/dependencies-and-module-machinery.js +1 -1
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/self-check.js +17 -4
- package/dist/src/findings-pass.js +6 -5
- package/dist/src/framework-lifecycle.js +1 -1
- package/dist/src/html-entries.js +1 -1
- package/dist/src/implementations.js +2 -2
- package/dist/src/in-operands.js +30 -0
- package/dist/src/indexed-access.js +264 -125
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.js +2 -2
- package/dist/src/intra-function-parts.js +26 -12
- package/dist/src/inventory.js +26 -1
- package/dist/src/keyof-comparisons.js +170 -0
- package/dist/src/kinds.js +17 -7
- package/dist/src/manifest.js +6 -16
- package/dist/src/matrix.js +20 -2
- package/dist/src/member-names.js +1 -1
- package/dist/src/module-declarations.js +1 -1
- package/dist/src/namespace-objects.js +1 -1
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/overrides.js +2 -2
- package/dist/src/query.js +4 -1
- package/dist/src/references.js +13 -2
- package/dist/src/reflective-lookup.js +2 -2
- package/dist/src/report.js +1 -1
- package/dist/src/reporters/sarif.js +4 -0
- package/dist/src/roots.js +1 -1
- package/dist/src/serialization-contract.js +45 -16
- package/dist/src/session.js +15 -8
- package/dist/src/signatures.js +1 -1
- package/dist/src/stores.js +1 -1
- package/dist/src/suppress-file.js +58 -6
- package/dist/src/suppress-inline.js +14 -5
- package/dist/src/suppress.js +54 -24
- package/dist/src/symbol-keys.js +1 -1
- package/dist/src/type-errors.js +1 -1
- package/dist/src/type-query-alias.js +1 -1
- package/dist/src/unimplemented-callees.js +312 -0
- package/dist/src/value-flow.js +1 -1
- package/dist/src/value-reach.js +8 -8
- package/dist/src/verbs/analyze.js +11 -9
- package/dist/src/workspace-programs.js +2 -2
- package/jsr.json +1 -1
- package/package.json +3 -3
- package/src/alias-chain.ts +2 -2
- package/src/analysis.ts +135 -52
- package/src/augmentations.ts +14 -11
- package/src/calls.ts +2 -2
- package/src/class-members.ts +2 -2
- package/src/component-layer.ts +1 -1
- package/src/components.ts +103 -21
- package/src/configuration-files.ts +6 -5
- package/src/configured-declarations.ts +2 -6
- package/src/conformance-record.ts +1 -1
- package/src/contextual-uses.ts +82 -18
- package/src/convention-rows.ts +6 -2
- package/src/conventions.ts +11 -2
- package/src/decorator.ts +1 -1
- package/src/dependencies.ts +108 -31
- package/src/deprecation.ts +1 -1
- package/src/destructuring.ts +2 -2
- package/src/discover.ts +2 -2
- package/src/element-access.ts +446 -0
- package/src/entry-points.ts +2 -2
- package/src/enum-group.ts +2 -2
- package/src/erased-stores.ts +413 -0
- package/src/file-facts.ts +3 -1
- package/src/findings/completion.ts +54 -20
- package/src/findings/dependencies-and-module-machinery.ts +1 -1
- package/src/findings/emitters.ts +1 -1
- package/src/findings/self-check.ts +18 -4
- package/src/findings-pass.ts +12 -5
- package/src/framework-lifecycle.ts +2 -2
- package/src/html-entries.ts +1 -1
- package/src/implementations.ts +2 -2
- package/src/in-operands.ts +45 -0
- package/src/indexed-access.ts +304 -146
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.ts +2 -2
- package/src/intra-function-parts.ts +42 -17
- package/src/inventory.ts +34 -2
- package/src/keyof-comparisons.ts +211 -0
- package/src/kinds.ts +20 -7
- package/src/manifest.ts +6 -21
- package/src/matrix.ts +34 -2
- package/src/member-names.ts +1 -1
- package/src/module-declarations.ts +1 -1
- package/src/namespace-objects.ts +1 -1
- package/src/outside-tests.ts +1 -1
- package/src/overrides.ts +2 -2
- package/src/position.ts +1 -1
- package/src/query.ts +12 -2
- package/src/references.ts +25 -3
- package/src/reflective-lookup.ts +2 -2
- package/src/report.ts +3 -1
- package/src/reporters/sarif.ts +4 -0
- package/src/roots.ts +2 -2
- package/src/serialization-contract.ts +55 -16
- package/src/session.ts +39 -32
- package/src/signatures.ts +1 -1
- package/src/source-files.ts +1 -1
- package/src/stores.ts +1 -1
- package/src/suppress-file.ts +68 -5
- package/src/suppress-inline.ts +15 -5
- package/src/suppress.ts +63 -28
- package/src/symbol-keys.ts +2 -2
- package/src/type-errors.ts +2 -2
- package/src/type-query-alias.ts +1 -1
- package/src/unimplemented-callees.ts +411 -0
- package/src/value-flow.ts +1 -1
- package/src/value-reach.ts +12 -8
- package/src/verbs/analyze.ts +15 -9
- package/src/workflow-steps.ts +1 -1
- package/src/workspace-programs.ts +4 -4
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* the parameters and results of functions and constructors too; a class instance there is
|
|
7
7
|
* the interface-satisfaction class's evidence instead.
|
|
8
8
|
*/
|
|
9
|
-
import { isComputedPropertyName, isGetAccessorDeclaration, isIdentifier, isMethodDeclaration, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isPropertyAssignment, isSetAccessorDeclaration, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteral, } from "@typescript/native/
|
|
10
|
-
import { SignatureKind
|
|
9
|
+
import { isClassDeclaration, isClassExpression, isComputedPropertyName, isGetAccessorDeclaration, isIdentifier, isMethodDeclaration, isMethodSignatureDeclaration, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isPropertyAssignment, isSetAccessorDeclaration, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteral, } from "@typescript/native/ast";
|
|
10
|
+
import { SignatureKind } from "@typescript/native/sync";
|
|
11
11
|
import { isAnswered } from "./query.js";
|
|
12
12
|
/** The member kinds a contextual type writes and reads: data members and the members of object types. */
|
|
13
13
|
const MEMBER_KINDS = new Set(["type-member", "class-member"]);
|
|
@@ -36,6 +36,20 @@ function propertyName(property) {
|
|
|
36
36
|
}
|
|
37
37
|
return undefined;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether an object spread copies a member a declaration declares: a method, a method
|
|
41
|
+
* signature and a class's accessor are no own data property of the value, while an
|
|
42
|
+
* accessor of an interface or a type literal describes one. It is decided on the
|
|
43
|
+
* declaration, because a mapped type over a class keeps the class's declarations on
|
|
44
|
+
* plain property symbols.
|
|
45
|
+
*/
|
|
46
|
+
function copiedBySpread(node) {
|
|
47
|
+
if (isMethodDeclaration(node) || isMethodSignatureDeclaration(node)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return !((isGetAccessorDeclaration(node) || isSetAccessorDeclaration(node)) &&
|
|
51
|
+
(isClassDeclaration(node.parent) || isClassExpression(node.parent)));
|
|
52
|
+
}
|
|
39
53
|
/**
|
|
40
54
|
* The contextual uses of one project's literals and values, asked in batches: one
|
|
41
55
|
* contextual type per literal and per value whose type carries a member of the target,
|
|
@@ -85,9 +99,12 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
85
99
|
ids: chains
|
|
86
100
|
.declarationsOf(property)
|
|
87
101
|
.filter((id) => MEMBER_KINDS.has(kinds.get(id) ?? "file")),
|
|
102
|
+
methods: chains
|
|
103
|
+
.declarationsOf(property)
|
|
104
|
+
.filter((id) => kinds.get(id) === "interface-method"),
|
|
88
105
|
handles: new Set(property.declarations.map((handle) => `${handle.path}#${String(handle.index)}`)),
|
|
89
106
|
own: property.declarations.some((handle) => ownPaths.has(handle.path)),
|
|
90
|
-
|
|
107
|
+
declarations: property.declarations.filter((handle) => ownPaths.has(handle.path)),
|
|
91
108
|
});
|
|
92
109
|
}
|
|
93
110
|
tables.set(type.id, table);
|
|
@@ -137,7 +154,10 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
137
154
|
batches += batchesOf(carried.length);
|
|
138
155
|
const types = queries.typesAt(carried.map((flow) => flow.value), cap);
|
|
139
156
|
/** The members a position may read structurally: those of object types, not of classes. */
|
|
140
|
-
const readable = (member) =>
|
|
157
|
+
const readable = (member) => [
|
|
158
|
+
...member.ids.filter((id) => kinds.get(id) === "type-member"),
|
|
159
|
+
...member.methods,
|
|
160
|
+
];
|
|
141
161
|
const carries = (part) => [...membersOf(part).values()].some((member) => readable(member).length > 0);
|
|
142
162
|
/** Whether an object type has members and declares none of them in the target. */
|
|
143
163
|
const outside = (part) => {
|
|
@@ -161,6 +181,19 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
161
181
|
elements.set(type.id, element);
|
|
162
182
|
return element;
|
|
163
183
|
};
|
|
184
|
+
const argumentsOf = new Map();
|
|
185
|
+
/** The type arguments of an instantiation of a generic type, read once per type. */
|
|
186
|
+
const typeArgumentsOf = (type) => {
|
|
187
|
+
const known = argumentsOf.get(type.id);
|
|
188
|
+
if (known !== undefined) {
|
|
189
|
+
return known;
|
|
190
|
+
}
|
|
191
|
+
lookups += type.isTypeReference() ? 1 : 0;
|
|
192
|
+
const held = queries.typeArguments(type);
|
|
193
|
+
const found = isAnswered(held) ? held : [];
|
|
194
|
+
argumentsOf.set(type.id, found);
|
|
195
|
+
return found;
|
|
196
|
+
};
|
|
164
197
|
const calls = new Map();
|
|
165
198
|
/**
|
|
166
199
|
* The parameter and return types of a type's one call signature, or of its one construct
|
|
@@ -195,10 +228,11 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
195
228
|
};
|
|
196
229
|
/**
|
|
197
230
|
* Each object type a value of `source` is checked as against the object types of
|
|
198
|
-
* `target`: the value's own, and through array elements
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
231
|
+
* `target`: the value's own, and through array elements, a function's parameters,
|
|
232
|
+
* checked the other way, and result, and the type arguments two instantiations share
|
|
233
|
+
* by place, an array among them, as an array reaches `Iterable<T>`.
|
|
234
|
+
* A source that is one of the target's own object types matches it as it stands. Each
|
|
235
|
+
* pair is compared once, which ends the walk over a recursive type.
|
|
202
236
|
*/
|
|
203
237
|
const compared = (source, target, into, seen) => {
|
|
204
238
|
const key = `${String(source?.id)}>${String(target?.id)}`;
|
|
@@ -220,9 +254,20 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
220
254
|
}
|
|
221
255
|
const element = elementOf(one);
|
|
222
256
|
const called = element === undefined ? callOf(one) : undefined;
|
|
257
|
+
const sourceArguments = typeArgumentsOf(one);
|
|
223
258
|
for (const part of targets) {
|
|
259
|
+
const partElement = elementOf(part);
|
|
260
|
+
if (element !== undefined && partElement !== undefined) {
|
|
261
|
+
compared(element, partElement, into, seen);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const targetArguments = typeArgumentsOf(part);
|
|
265
|
+
// A defaulted trailing parameter, as `Iterable<T, TReturn, TNext>` has, leaves
|
|
266
|
+
// the places two instantiations share comparable.
|
|
267
|
+
sourceArguments.slice(0, targetArguments.length).forEach((argument, index) => {
|
|
268
|
+
compared(argument, targetArguments[index], into, seen);
|
|
269
|
+
});
|
|
224
270
|
if (element !== undefined) {
|
|
225
|
-
compared(element, elementOf(part), into, seen);
|
|
226
271
|
continue;
|
|
227
272
|
}
|
|
228
273
|
const other = called === undefined ? undefined : callOf(part);
|
|
@@ -253,7 +298,7 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
253
298
|
if (element !== undefined) {
|
|
254
299
|
return mayCarry(element, seen);
|
|
255
300
|
}
|
|
256
|
-
return callOf(part) !== undefined;
|
|
301
|
+
return callOf(part) !== undefined || typeArgumentsOf(part).some((one) => mayCarry(one, seen));
|
|
257
302
|
});
|
|
258
303
|
};
|
|
259
304
|
const sourced = carried.flatMap((flow, index) => {
|
|
@@ -302,6 +347,19 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
302
347
|
reads.push({ at: flow.value, from: flow.from, ids: [...ids] });
|
|
303
348
|
}
|
|
304
349
|
});
|
|
350
|
+
const copies = new Map();
|
|
351
|
+
/** Whether a spread copies the member: where any declaration of it declares data. */
|
|
352
|
+
const copied = (member) => {
|
|
353
|
+
let known = copies.get(member);
|
|
354
|
+
if (known === undefined) {
|
|
355
|
+
known = member.declarations.some((handle) => {
|
|
356
|
+
const node = project.declarationAt(handle)?.node;
|
|
357
|
+
return node === undefined || copiedBySpread(node);
|
|
358
|
+
});
|
|
359
|
+
copies.set(member, known);
|
|
360
|
+
}
|
|
361
|
+
return known;
|
|
362
|
+
};
|
|
305
363
|
const spreads = literals.flatMap(({ literal, from }) => literal.properties.flatMap((property) => isSpreadAssignment(property) ? [{ value: property.expression, from }] : []));
|
|
306
364
|
batches += batchesOf(spreads.length);
|
|
307
365
|
const spreadTypes = queries.typesAt(spreads.map((one) => one.value), cap);
|
|
@@ -310,11 +368,10 @@ export function contextualUses(project, held, chains, literals, flows, cap, prop
|
|
|
310
368
|
if (type === undefined || !isAnswered(type)) {
|
|
311
369
|
return;
|
|
312
370
|
}
|
|
313
|
-
// A spread gets every own enumerable property, an overwritten key's getter included
|
|
314
|
-
//
|
|
315
|
-
// the class's methods (never data members), and a private name, which is no property
|
|
371
|
+
// A spread gets every own enumerable property, an overwritten key's getter included,
|
|
372
|
+
// and no private name, which is no property
|
|
316
373
|
// (https://tc39.es/ecma262/#sec-copydataproperties).
|
|
317
|
-
const own = (member, id) => !privateNames.has(id) &&
|
|
374
|
+
const own = (member, id) => !privateNames.has(id) && copied(member);
|
|
318
375
|
const ids = [
|
|
319
376
|
...new Set(partsOf(type).flatMap((part) => [...membersOf(part).values()].flatMap((member) => member.ids.filter((id) => own(member, id))))),
|
|
320
377
|
];
|
|
@@ -41,7 +41,8 @@ const STRYKER_MODULE = "{stryker,.stryker}.{conf,config}.{js,mjs,cjs}";
|
|
|
41
41
|
const VITEST_CONFIG = `{vitest,vite}.config.${ANY_MODULE}`;
|
|
42
42
|
/**
|
|
43
43
|
* The properties Vitest takes its project root from, `test.root` before Vite's `root`; it
|
|
44
|
-
* resolves `setupFiles` against that root
|
|
44
|
+
* resolves `setupFiles` and `globalSetup` against that root
|
|
45
|
+
* (https://vitest.dev/config/setupfiles, https://vitest.dev/config/globalsetup).
|
|
45
46
|
*/
|
|
46
47
|
const VITEST_ROOTS = ["test.root", "root"];
|
|
47
48
|
/** The entry files of an Angular CLI project, at the workspace root or below `projects`. */
|
|
@@ -540,6 +541,9 @@ export const CONVENTION_ROWS = [
|
|
|
540
541
|
{ property: "test.coverage.include", files: [VITEST_CONFIG] },
|
|
541
542
|
{ property: "test.coverage.exclude", files: [VITEST_CONFIG] },
|
|
542
543
|
],
|
|
543
|
-
testFiles: [
|
|
544
|
+
testFiles: [
|
|
545
|
+
{ property: "test.setupFiles", files: [VITEST_CONFIG], roots: VITEST_ROOTS },
|
|
546
|
+
{ property: "test.globalSetup", files: [VITEST_CONFIG], roots: VITEST_ROOTS },
|
|
547
|
+
],
|
|
544
548
|
},
|
|
545
549
|
];
|
package/dist/src/conventions.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* directory a configuration property moves read from the property's literal value.
|
|
6
6
|
* No configuration file is run.
|
|
7
7
|
*/
|
|
8
|
-
import { isArrayLiteralExpression, isAsExpression, isBinaryExpression, isCallExpression, isClassDeclaration, isComputedPropertyName, isExportAssignment, isExportDeclaration, isExpressionStatement, isFunctionDeclaration, isIdentifier, isImportDeclaration, isNamedExports, isNamespaceImport, isNoSubstitutionTemplateLiteral, isNonNullExpression, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteral, isVariableStatement, SyntaxKind, } from "@typescript/native/
|
|
8
|
+
import { isArrayLiteralExpression, isAsExpression, isBinaryExpression, isCallExpression, isClassDeclaration, isComputedPropertyName, isExportAssignment, isExportDeclaration, isExpressionStatement, isFunctionDeclaration, isIdentifier, isImportDeclaration, isNamedExports, isNamespaceImport, isNoSubstitutionTemplateLiteral, isNonNullExpression, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteral, isVariableStatement, SyntaxKind, } from "@typescript/native/ast";
|
|
9
9
|
import { lineOf } from "./component-files.js";
|
|
10
10
|
import { CONVENTION_ROWS, } from "./convention-rows.js";
|
|
11
11
|
import { documentStrings } from "./configuration-files.js";
|
|
@@ -707,7 +707,9 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
|
|
|
707
707
|
}
|
|
708
708
|
const version = versions.get(row.package);
|
|
709
709
|
if (version === undefined) {
|
|
710
|
-
if (missing.has(row.package) ||
|
|
710
|
+
if (missing.has(row.package) ||
|
|
711
|
+
manifest.nested === true ||
|
|
712
|
+
!declares(declared, row.package, REQUIRED_SECTIONS)) {
|
|
711
713
|
continue;
|
|
712
714
|
}
|
|
713
715
|
missing.add(row.package);
|
package/dist/src/dependencies.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* file a tool loads needs each dependency its strings spell. A package one dependency pulls in for
|
|
7
7
|
* itself is that dependency's need, not the target's.
|
|
8
8
|
*/
|
|
9
|
-
import { isCallExpression, isExportDeclaration, isExternalModuleReference, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isMetaProperty, isNamespaceExport, isPropertyAccessExpression, isShorthandPropertyAssignment, isStringLiteral, isNoSubstitutionTemplateLiteral, SyntaxKind, } from "@typescript/native/
|
|
9
|
+
import { isCallExpression, isExportDeclaration, isExternalModuleReference, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isMetaProperty, isNamespaceExport, isPropertyAccessExpression, isShorthandPropertyAssignment, isStringLiteral, isNoSubstitutionTemplateLiteral, SyntaxKind, } from "@typescript/native/ast";
|
|
10
10
|
import { configurationFiles, declaredIn as declaredBeside, dependenciesNamed, moduleStrings, } from "./configuration-files.js";
|
|
11
11
|
import { nodeKey, packageScope } from "./inventory.js";
|
|
12
12
|
import { scriptTokens } from "./manifest.js";
|
|
@@ -29,11 +29,13 @@ const PROJECT_OWNER = "";
|
|
|
29
29
|
/** What a configuration's own reading needs: packages no deletion of a declaration removes. */
|
|
30
30
|
export function configurationNeeds(packages) {
|
|
31
31
|
return {
|
|
32
|
-
packages: new Set(packages),
|
|
33
32
|
uses: new Map([[PROJECT_OWNER, new Set(packages)]]),
|
|
33
|
+
at: new Map([[ANYWHERE, new Set(packages)]]),
|
|
34
34
|
unanswered: [],
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
/** The key of {@link ProjectNeeds.at} for a use no file of the target governs. */
|
|
38
|
+
const ANYWHERE = "";
|
|
37
39
|
function isRecord(value) {
|
|
38
40
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
41
|
}
|
|
@@ -207,9 +209,10 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
|
|
|
207
209
|
}
|
|
208
210
|
const packages = configurationPackages(host, project.configFile, project.program.getCompilerOptions(), programPackages);
|
|
209
211
|
const uses = new Map();
|
|
210
|
-
const
|
|
212
|
+
const at = new Map();
|
|
213
|
+
const use = (owners, named, path) => {
|
|
211
214
|
for (const one of named) {
|
|
212
|
-
|
|
215
|
+
at.set(path, (at.get(path) ?? new Set()).add(one));
|
|
213
216
|
for (const owner of owners) {
|
|
214
217
|
let set = uses.get(owner);
|
|
215
218
|
if (set === undefined) {
|
|
@@ -220,10 +223,13 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
|
|
|
220
223
|
}
|
|
221
224
|
}
|
|
222
225
|
};
|
|
223
|
-
use([PROJECT_OWNER], packages);
|
|
226
|
+
use([PROJECT_OWNER], packages, project.configFile);
|
|
224
227
|
const unanswered = [];
|
|
225
228
|
for (const file of project.ownSourceFiles()) {
|
|
226
|
-
|
|
229
|
+
const inFile = (owners, named) => {
|
|
230
|
+
use(owners, named, file.fileName);
|
|
231
|
+
};
|
|
232
|
+
if (fileNeeds(project, held, file, programPackages, inFile)) {
|
|
227
233
|
unanswered.push(file.fileName);
|
|
228
234
|
}
|
|
229
235
|
}
|
|
@@ -241,14 +247,14 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
|
|
|
241
247
|
for (const { file } of configuration.modules) {
|
|
242
248
|
const names = declaredAt(file.fileName);
|
|
243
249
|
for (const { node, text } of moduleStrings(file)) {
|
|
244
|
-
use(ownersOf(file, held, node), dependenciesNamed(text, names));
|
|
250
|
+
use(ownersOf(file, held, node), dependenciesNamed(text, names), file.fileName);
|
|
245
251
|
}
|
|
246
252
|
}
|
|
247
253
|
for (const { strings, manifestDirs } of configuration.documents) {
|
|
248
254
|
for (const manifestDir of manifestDirs) {
|
|
249
255
|
const names = declaredAt(joinPath(manifestDir, "package.json"));
|
|
250
256
|
for (const text of strings) {
|
|
251
|
-
use([PROJECT_OWNER], dependenciesNamed(text, names));
|
|
257
|
+
use([PROJECT_OWNER], dependenciesNamed(text, names), joinPath(manifestDir, MANIFEST));
|
|
252
258
|
}
|
|
253
259
|
}
|
|
254
260
|
}
|
|
@@ -256,11 +262,11 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
|
|
|
256
262
|
for (const manifestDir of manifestDirs) {
|
|
257
263
|
const names = declaredAt(joinPath(manifestDir, "package.json"));
|
|
258
264
|
for (const { text } of moduleStrings(file)) {
|
|
259
|
-
use([PROJECT_OWNER], dependenciesNamed(text, names));
|
|
265
|
+
use([PROJECT_OWNER], dependenciesNamed(text, names), joinPath(manifestDir, MANIFEST));
|
|
260
266
|
}
|
|
261
267
|
}
|
|
262
268
|
}
|
|
263
|
-
return {
|
|
269
|
+
return { uses, at, unanswered };
|
|
264
270
|
}
|
|
265
271
|
/** The declarations of the inventory a use written at one node belongs to. */
|
|
266
272
|
function ownersOf(file, held, node) {
|
|
@@ -496,8 +502,10 @@ function installedOf(host, root, name) {
|
|
|
496
502
|
const read = readJSON(host, joinPath(dir, MODULES_DIR, name, MANIFEST));
|
|
497
503
|
if (read !== undefined && isRecord(read.value)) {
|
|
498
504
|
const bin = read.value["bin"];
|
|
505
|
+
const peers = read.value["peerDependencies"];
|
|
499
506
|
// A string `bin` names one command, the package's name without its scope.
|
|
500
507
|
return {
|
|
508
|
+
peers: isRecord(peers) ? Object.keys(peers) : [],
|
|
501
509
|
commands: typeof bin === "string"
|
|
502
510
|
? bin === ""
|
|
503
511
|
? []
|
|
@@ -558,20 +566,49 @@ function scriptTokensOf(manifest) {
|
|
|
558
566
|
function isInside(path, dir) {
|
|
559
567
|
return dir === "" || path.startsWith(`${dir}/`);
|
|
560
568
|
}
|
|
569
|
+
/** The directory below the target root a declared dependency's manifest is in, `""` being the root. */
|
|
570
|
+
function manifestDir(dependency) {
|
|
571
|
+
const dir = dirnamePath(dependency.position.path);
|
|
572
|
+
return dir === "." ? "" : dir;
|
|
573
|
+
}
|
|
561
574
|
/**
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
* nothing.
|
|
575
|
+
* Adds to `needed` each declared dependency that the installed manifest of a needed or
|
|
576
|
+
* run declared dependency names as a peer, until no further one joins: the declaration of
|
|
577
|
+
* that name in the needing dependency's manifest or in a manifest above it, where the
|
|
578
|
+
* installed peer is resolved from. `peers` holds each declaration's installed peers by
|
|
579
|
+
* {@link declarationKey}.
|
|
568
580
|
*/
|
|
569
|
-
|
|
581
|
+
function addNeededPeers(declared, peers, needed, ran) {
|
|
582
|
+
const pending = declared.filter((dependency) => needed.has(declarationKey(dependency)) || ran.has(declarationKey(dependency)));
|
|
583
|
+
for (let next = pending.pop(); next !== undefined; next = pending.pop()) {
|
|
584
|
+
const below = manifestDir(next);
|
|
585
|
+
for (const peer of peers.get(declarationKey(next)) ?? []) {
|
|
586
|
+
for (const dependency of declared) {
|
|
587
|
+
const key = declarationKey(dependency);
|
|
588
|
+
if (dependency.name === peer &&
|
|
589
|
+
!needed.has(key) &&
|
|
590
|
+
(below === manifestDir(dependency) || isInside(below, manifestDir(dependency)))) {
|
|
591
|
+
needed.add(key);
|
|
592
|
+
pending.push(dependency);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* The run's dependency evidence over the target's manifest and those of `members` and
|
|
600
|
+
* `nested` packages below the root: each declared dependency's position, what the projects,
|
|
601
|
+
* scripts and workflow steps need, and each deletion candidate's last uses. A member in
|
|
602
|
+
* `unbuilt` holds source only in configurations the run could not build. An unreadable
|
|
603
|
+
* manifest declares nothing, nor does a nested package's uninstalled dependency, because
|
|
604
|
+
* no run requires a nested package to be installed.
|
|
605
|
+
*/
|
|
606
|
+
export function dependenciesOf(host, targetRoot, perProject, candidates, members = [], unbuiltMembers = [], nested = []) {
|
|
570
607
|
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
571
608
|
const scopeOf = packageScope(host, targetRoot);
|
|
572
609
|
const manifests = new Map([[root, MANIFEST]]);
|
|
573
610
|
const unbuilt = new Set();
|
|
574
|
-
for (const dir of [...members, ...unbuiltMembers]) {
|
|
611
|
+
for (const dir of [...members, ...unbuiltMembers, ...nested]) {
|
|
575
612
|
const below = relativePath(root, dir);
|
|
576
613
|
if (below !== undefined && !manifests.has(dir)) {
|
|
577
614
|
manifests.set(dir, `${below}/${MANIFEST}`);
|
|
@@ -586,6 +623,8 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
|
|
|
586
623
|
const workflow = new Set(workflowTokens(host, targetRoot));
|
|
587
624
|
const declared = [];
|
|
588
625
|
const ran = new Set();
|
|
626
|
+
const peers = new Map();
|
|
627
|
+
const uninstalledHere = new Set(nested);
|
|
589
628
|
for (const [dir, path] of manifests) {
|
|
590
629
|
const read = readJSON(host, joinPath(dir, MANIFEST));
|
|
591
630
|
if (read === undefined || !isRecord(read.value)) {
|
|
@@ -593,12 +632,16 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
|
|
|
593
632
|
}
|
|
594
633
|
const tokens = scriptTokensOf(read.value);
|
|
595
634
|
for (const dependency of declaredIn(read.text, read.value, path, scopeOf(path))) {
|
|
596
|
-
declared.push(dependency);
|
|
597
635
|
const found = installedOf(host, dir, dependency.name);
|
|
636
|
+
if (found === undefined && uninstalledHere.has(dir)) {
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
declared.push(dependency);
|
|
598
640
|
if (found === undefined) {
|
|
599
641
|
continue;
|
|
600
642
|
}
|
|
601
|
-
|
|
643
|
+
peers.set(declarationKey(dependency), found.peers);
|
|
644
|
+
const runs = (command) => tokens.has(command) || workflow.has(command);
|
|
602
645
|
if (found.commands.some(runs)) {
|
|
603
646
|
ran.add(declarationKey(dependency));
|
|
604
647
|
}
|
|
@@ -607,25 +650,36 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
|
|
|
607
650
|
// A declaration several projects compile is one user, and a use any project makes is
|
|
608
651
|
// a use, so the uses are merged by declaration before anything is counted.
|
|
609
652
|
const needed = new Set();
|
|
653
|
+
const byName = new Map();
|
|
654
|
+
for (const dependency of declared) {
|
|
655
|
+
byName.set(dependency.name, [...(byName.get(dependency.name) ?? []), dependency]);
|
|
656
|
+
}
|
|
610
657
|
const uses = new Map();
|
|
611
658
|
for (const project of perProject) {
|
|
612
659
|
// A specifier the checker left unanswered may resolve to any dependency a manifest at
|
|
613
660
|
// or above its file declares, and what the configuration needs is never deleted.
|
|
614
661
|
const unanswered = project.unanswered.flatMap((file) => relativePath(root, file) ?? []);
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
return unanswered.some((file) => isInside(file, dir === "." ? "" : dir));
|
|
619
|
-
})
|
|
620
|
-
.map((dependency) => dependency.name);
|
|
662
|
+
const unknownDeclared = declared.filter((dependency) => unanswered.some((file) => isInside(file, manifestDir(dependency))));
|
|
663
|
+
unknownDeclared.forEach((dependency) => needed.add(declarationKey(dependency)));
|
|
664
|
+
const unknown = unknownDeclared.map((dependency) => dependency.name);
|
|
621
665
|
const held = unknown.length === 0 ? [] : [[PROJECT_OWNER, new Set(unknown)]];
|
|
622
666
|
for (const [id, used] of [...project.uses, ...held]) {
|
|
623
667
|
const merged = uses.get(id) ?? new Set();
|
|
624
668
|
used.forEach((one) => merged.add(one));
|
|
625
669
|
uses.set(id, merged);
|
|
626
670
|
}
|
|
627
|
-
[
|
|
671
|
+
for (const [path, named] of project.at) {
|
|
672
|
+
const below = path === ANYWHERE ? undefined : relativePath(root, path);
|
|
673
|
+
for (const one of named) {
|
|
674
|
+
for (const dependency of byName.get(one) ?? []) {
|
|
675
|
+
if (below === undefined || isInside(below, manifestDir(dependency))) {
|
|
676
|
+
needed.add(declarationKey(dependency));
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
628
681
|
}
|
|
682
|
+
addNeededPeers(declared, peers, needed, ran);
|
|
629
683
|
const users = new Map();
|
|
630
684
|
for (const used of uses.values()) {
|
|
631
685
|
used.forEach((one) => users.set(one, (users.get(one) ?? 0) + 1));
|
package/dist/src/deprecation.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* declares, and the checker attaches it to the first name alone, so the later names read
|
|
7
7
|
* the list's own tags from the tree.
|
|
8
8
|
*/
|
|
9
|
-
import { isVariableStatement, SyntaxKind } from "@typescript/native/
|
|
9
|
+
import { isVariableStatement, SyntaxKind } from "@typescript/native/ast";
|
|
10
10
|
import { nodeKey } from "./inventory.js";
|
|
11
11
|
import { isAnswered, UNANSWERED } from "./query.js";
|
|
12
12
|
/** The tag the TypeScript tools recognize as marking a declaration deprecated. */
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* to a local of the same name, renames it, gives it a default or nests a pattern under
|
|
6
6
|
* it. A rest element names no property: what it copies is read where the copy is.
|
|
7
7
|
*/
|
|
8
|
-
import { isArrayLiteralExpression, isBinaryExpression, isForOfStatement, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isParameterDeclaration, isParenthesizedExpression, isPropertyAssignment, isShorthandPropertyAssignment, isStringLiteral, SyntaxKind, } from "@typescript/native/
|
|
9
|
-
import { TypeFlags } from "@typescript/native/
|
|
8
|
+
import { isArrayLiteralExpression, isBinaryExpression, isForOfStatement, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isParameterDeclaration, isParenthesizedExpression, isPropertyAssignment, isShorthandPropertyAssignment, isStringLiteral, SyntaxKind, } from "@typescript/native/ast";
|
|
9
|
+
import { TypeFlags } from "@typescript/native/sync";
|
|
10
10
|
import { isAnswered, propertyTables, UNANSWERED, } from "./query.js";
|
|
11
11
|
/** The text a property name spells, or `undefined` for a computed name. */
|
|
12
12
|
function nameText(node) {
|
package/dist/src/discover.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DiagnosticCategory } from "@typescript/native/
|
|
1
|
+
import { DiagnosticCategory } from "@typescript/native/sync";
|
|
2
2
|
import { dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
3
3
|
import { SetupError } from "./setup-failure.js";
|
|
4
4
|
/** Directory names discovery does not descend into. */
|