@cplieger/deadset-ts 8.0.0-dev.15 → 8.0.0-dev.16
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 +41 -37
- package/dist/src/commands/read.js +6 -7
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +3 -1
- package/dist/src/contract/config.generated.js +1 -1
- package/dist/src/contract/contract.generated.js +119 -2
- package/dist/src/dependencies.js +79 -48
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +20 -58
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
- package/dist/src/entries/conventions.js +739 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +3 -3
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +2 -2
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +669 -0
- package/dist/src/entries/test-runners.js +684 -0
- package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/findings/emitters.js +5 -8
- package/dist/src/findings/self-check.js +36 -20
- package/dist/src/findings-pass.js +5 -6
- package/dist/src/framework-lifecycle.js +1 -1
- package/dist/src/fs/manifest.js +15 -20
- package/dist/src/generated-file.js +172 -29
- package/dist/src/graph.js +2 -4
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/inventory/commonjs.js +62 -17
- package/dist/src/inventory/enumerate.js +2 -1
- package/dist/src/javascript-file.js +26 -11
- package/dist/src/load/classify.js +28 -9
- package/dist/src/load/diagnostics.js +8 -1
- package/dist/src/load/discover.js +15 -7
- package/dist/src/load/plan.js +2 -2
- package/dist/src/load/synthesize.js +5 -5
- package/dist/src/load/workspace-manifests.js +1 -1
- package/dist/src/matrix.js +6 -13
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/paths.js +16 -0
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +140 -0
- package/dist/src/references.js +202 -32
- package/dist/src/resolve.js +1 -1
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +4 -4
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
- package/dist/src/{manifest.js → roots/manifest.js} +4 -4
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +489 -0
- package/dist/src/roots/unseen-loads.js +208 -0
- package/dist/src/serialization-contract.js +1 -1
- package/dist/src/source-files.js +5 -9
- package/dist/src/suppress.js +30 -32
- package/dist/src/test-support.js +4 -2
- package/dist/src/verbs/analyze.js +13 -1
- package/dist/src/verbs/describe.js +5 -3
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/analysis.ts +75 -52
- package/src/automatic-types.ts +1 -1
- package/src/commands/read.ts +6 -8
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +4 -0
- package/src/contract/config.generated.ts +1 -1
- package/src/contract/contract.generated.ts +138 -2
- package/src/dependencies.ts +96 -49
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +23 -75
- package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
- package/src/{conventions.ts → entries/conventions.ts} +347 -522
- package/src/{html-entries.ts → entries/html-entries.ts} +5 -5
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +4 -4
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +857 -0
- package/src/entries/test-runners.ts +868 -0
- package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
- package/src/exempt.ts +3 -2
- package/src/extensions.ts +45 -0
- package/src/facts.ts +44 -0
- package/src/file-facts.ts +1 -1
- package/src/findings/emitters.ts +14 -10
- package/src/findings/self-check.ts +41 -22
- package/src/findings/visibility-narrowing.ts +1 -1
- package/src/findings-pass.ts +5 -12
- package/src/framework-lifecycle.ts +1 -1
- package/src/fs/manifest.ts +25 -21
- package/src/generated-file.ts +240 -36
- package/src/graph.ts +3 -5
- package/src/index.ts +1 -1
- package/src/injection-container.ts +1 -1
- package/src/inventory/commonjs.ts +102 -17
- package/src/inventory/enumerate.ts +2 -1
- package/src/javascript-file.ts +29 -12
- package/src/load/classify.ts +49 -13
- package/src/load/diagnostics.ts +11 -1
- package/src/load/discover.ts +27 -11
- package/src/load/plan.ts +11 -2
- package/src/load/synthesize.ts +6 -6
- package/src/load/test-globals.ts +1 -1
- package/src/load/workspace-manifests.ts +1 -1
- package/src/load/workspace-run.ts +1 -1
- package/src/matrix.ts +7 -14
- package/src/outside-tests.ts +1 -1
- package/src/paths.ts +18 -0
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +205 -0
- package/src/references.ts +281 -34
- package/src/report.ts +1 -1
- package/src/resolve.ts +1 -1
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +7 -7
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
- package/src/{manifest.ts → roots/manifest.ts} +5 -5
- package/src/roots/published-reach.ts +481 -0
- package/src/{roots.ts → roots/root-set.ts} +203 -630
- package/src/roots/unseen-loads.ts +307 -0
- package/src/serialization-contract.ts +1 -1
- package/src/source-files.ts +5 -10
- package/src/suppress.ts +48 -33
- package/src/test-support.ts +8 -3
- package/src/verbs/analyze.ts +17 -4
- package/src/verbs/describe.ts +5 -2
- package/src/verbs/explain.ts +1 -1
- package/dist/src/build-scripts.js +0 -418
- package/dist/src/conventions.js +0 -907
- package/dist/src/entry-points.js +0 -444
- package/dist/src/own-body.js +0 -28
- package/dist/src/roots.js +0 -865
- package/dist/src/unseen-loads.js +0 -189
- package/src/build-scripts.ts +0 -536
- package/src/entry-points.ts +0 -584
- package/src/own-body.ts +0 -42
- package/src/unseen-loads.ts +0 -282
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The platform's names read through a program's checker: its `require` and `URL`, as
|
|
3
|
+
* `platform-calls.ts` decides them, its worker constructors and `navigator`, and Node's
|
|
4
|
+
* `Worker`.
|
|
5
|
+
*/
|
|
6
|
+
import { isArrowFunction, isClassDeclaration, isClassExpression, isFunctionDeclaration, isFunctionExpression, isMethodDeclaration, isModuleDeclaration, isPropertyAssignment, isPropertyDeclaration, isSourceFile, isStringLiteralLikeNode, isVariableDeclaration, } from "@typescript/native/ast";
|
|
7
|
+
import { SymbolFlags } from "@typescript/native/sync";
|
|
8
|
+
import { UNANSWERED } from "./query.js";
|
|
9
|
+
import { boundExports, NAMESPACE } from "./entries/static-module.js";
|
|
10
|
+
import { isAmbient } from "./inventory.js";
|
|
11
|
+
import { callsPlatformBy, carriedNames } from "./platform-calls.js";
|
|
12
|
+
import { unwrapped } from "./unwrap.js";
|
|
13
|
+
/** The symbol one symbol names through its aliases, or the symbol itself where it is none. */
|
|
14
|
+
function dealiased(project, symbol, asked) {
|
|
15
|
+
if ((symbol.flags & SymbolFlags.Alias) === 0) {
|
|
16
|
+
return symbol;
|
|
17
|
+
}
|
|
18
|
+
asked();
|
|
19
|
+
return project.queries.aliased(symbol);
|
|
20
|
+
}
|
|
21
|
+
/** Each declaration of `symbol` in a file of the target, read in this project's program. */
|
|
22
|
+
function ownDeclarations(project, symbol) {
|
|
23
|
+
const own = project.ownPaths();
|
|
24
|
+
return symbol.declarations.flatMap((handle) => {
|
|
25
|
+
const node = own.has(handle.path) ? project.declarationAt(handle)?.node : undefined;
|
|
26
|
+
return node === undefined ? [] : [node];
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Whether one declaration writes a function or a class with a body (roots.23): a function
|
|
31
|
+
* or method declaration with a body, a class declaration, or a variable, a property or a
|
|
32
|
+
* class field whose initializer is a function, an arrow function or a class expression,
|
|
33
|
+
* under no `declare` modifier and in no declaration file.
|
|
34
|
+
*/
|
|
35
|
+
function writesBody(node) {
|
|
36
|
+
const value = (isVariableDeclaration(node) || isPropertyAssignment(node) || isPropertyDeclaration(node)) &&
|
|
37
|
+
node.initializer !== undefined
|
|
38
|
+
? unwrapped(node.initializer)
|
|
39
|
+
: node;
|
|
40
|
+
return ((isFunctionDeclaration(value) || isMethodDeclaration(value)
|
|
41
|
+
? value.body !== undefined
|
|
42
|
+
: isFunctionExpression(value) ||
|
|
43
|
+
isArrowFunction(value) ||
|
|
44
|
+
isClassDeclaration(value) ||
|
|
45
|
+
isClassExpression(value)) && !isAmbient(value.getSourceFile(), value));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* What the checker binds `symbol` to, one alias step at a time: every name a step of the
|
|
49
|
+
* chain carries it by, and the declarations of the target its last step reaches, which
|
|
50
|
+
* prove it the target's own where one {@link writesBody}. A chain that ends at no
|
|
51
|
+
* declaration, or that the checker leaves unanswered, reaches none.
|
|
52
|
+
*/
|
|
53
|
+
function boundBy(project, symbol, asked) {
|
|
54
|
+
if (typeof symbol !== "object") {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const names = new Set();
|
|
58
|
+
const stepped = new Set();
|
|
59
|
+
for (let at = symbol; at !== undefined && !stepped.has(at.id);) {
|
|
60
|
+
stepped.add(at.id);
|
|
61
|
+
names.add(at.name);
|
|
62
|
+
const own = ownDeclarations(project, at);
|
|
63
|
+
for (const node of own) {
|
|
64
|
+
carriedNames(node).forEach((one) => names.add(one));
|
|
65
|
+
}
|
|
66
|
+
if ((at.flags & SymbolFlags.Alias) === 0) {
|
|
67
|
+
return { names, own, provenOwn: own.some(writesBody) };
|
|
68
|
+
}
|
|
69
|
+
asked();
|
|
70
|
+
const next = project.aliasStepOf(at);
|
|
71
|
+
at = typeof next === "object" ? next : undefined;
|
|
72
|
+
}
|
|
73
|
+
return { names, own: [], provenOwn: false };
|
|
74
|
+
}
|
|
75
|
+
/** Each written name's binding, as this project's checker answers it. */
|
|
76
|
+
function checkerBinding(project, asked) {
|
|
77
|
+
return (written) => {
|
|
78
|
+
asked();
|
|
79
|
+
return boundBy(project, project.symbolsAt([project.handle(written)])[0], asked);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether a call or construction through `callee`, the batch's answer for which is `symbol`,
|
|
84
|
+
* is one of the platform's `require` or `URL` (roots.23, references-ts.1), as
|
|
85
|
+
* {@link callsPlatformBy} decides it over this project's checker, each request it puts
|
|
86
|
+
* counted by `asked`.
|
|
87
|
+
*/
|
|
88
|
+
export function callsPlatform(project, name, callee, symbol, asked) {
|
|
89
|
+
const others = checkerBinding(project, asked);
|
|
90
|
+
return callsPlatformBy(name, callee, (written) => written === callee ? boundBy(project, symbol, asked) : others(written));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Whether a worker's constructor or `navigator`, the batch's answer for which is `symbol`, is
|
|
94
|
+
* the platform's (references-ts.2): a name the checker leaves unanswered, or one whose symbol
|
|
95
|
+
* is no alias and has a declaration outside the target's files.
|
|
96
|
+
*/
|
|
97
|
+
export function isPlatformGlobal(project, symbol) {
|
|
98
|
+
if (symbol === UNANSWERED) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const own = project.ownPaths();
|
|
102
|
+
return (symbol !== undefined &&
|
|
103
|
+
(symbol.flags & SymbolFlags.Alias) === 0 &&
|
|
104
|
+
symbol.declarations.some((handle) => !own.has(handle.path)));
|
|
105
|
+
}
|
|
106
|
+
/** The module names Node's worker threads are imported by. */
|
|
107
|
+
const THREADS = new Set(["worker_threads", "node:worker_threads"]);
|
|
108
|
+
function namesThreads(node) {
|
|
109
|
+
return node !== undefined && isStringLiteralLikeNode(node) && THREADS.has(node.text);
|
|
110
|
+
}
|
|
111
|
+
/** Whether one declaration is written in the body of `declare module "worker_threads"`. */
|
|
112
|
+
function inThreadsModule(node) {
|
|
113
|
+
for (let at = node; !isSourceFile(at); at = at.parent) {
|
|
114
|
+
if (isModuleDeclaration(at) && namesThreads(at.name)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Whether a `Worker` constructor, the batch's answer for which is `symbol`, is Node's
|
|
122
|
+
* (references-ts.2): its symbol resolves to a declaration of `worker_threads`, or one of its
|
|
123
|
+
* own declarations binds the module's `Worker`, or `holder`, the namespace it is read
|
|
124
|
+
* through, binds the module, each binding read as {@link boundExports} reads one, which
|
|
125
|
+
* decides where the module has no declaration. Each request it puts is counted by `asked`.
|
|
126
|
+
*/
|
|
127
|
+
export function startsThread(project, symbol, holder, asked) {
|
|
128
|
+
const bindingOf = checkerBinding(project, asked);
|
|
129
|
+
const declared = (one, member) => typeof one === "object" &&
|
|
130
|
+
ownDeclarations(project, one).some((node) => boundExports(node, (specifier) => THREADS.has(specifier), bindingOf).includes(member));
|
|
131
|
+
if (declared(symbol, "Worker") || declared(holder, NAMESPACE)) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
const named = typeof symbol === "object" ? dealiased(project, symbol, asked) : undefined;
|
|
135
|
+
return (typeof named === "object" &&
|
|
136
|
+
named.declarations.some((handle) => {
|
|
137
|
+
const node = project.declarationAt(handle)?.node;
|
|
138
|
+
return node !== undefined && inThreadsModule(node);
|
|
139
|
+
}));
|
|
140
|
+
}
|
package/dist/src/references.js
CHANGED
|
@@ -3,7 +3,7 @@ import { parenthesesRemoved } from "./unwrap.js";
|
|
|
3
3
|
import { aliasChains } from "./alias-chain.js";
|
|
4
4
|
import { contextualUses } from "./contextual-uses.js";
|
|
5
5
|
import { destructuring, propertyReadsOf } from "./destructuring.js";
|
|
6
|
-
import { specifierCandidates } from "./configuration-files.js";
|
|
6
|
+
import { specifierCandidates } from "./entries/configuration-files.js";
|
|
7
7
|
import { namespaceUses } from "./namespace-objects.js";
|
|
8
8
|
import { isParameterProperty, nodeKey } from "./inventory.js";
|
|
9
9
|
import { ambientGlobalInterfaces, augmentationReferences } from "./augmentations.js";
|
|
@@ -13,13 +13,15 @@ import { keyofComparisonReferences } from "./keyof-comparisons.js";
|
|
|
13
13
|
import { unimplementedCalleeReads } from "./unimplemented-callees.js";
|
|
14
14
|
import { moduleDeclarationReferences } from "./module-declarations.js";
|
|
15
15
|
import { overrideReferences } from "./overrides.js";
|
|
16
|
-
import { dirnamePath, queriedModulePath, relativePath, resolvePath } from "./paths.js";
|
|
16
|
+
import { dirnamePath, queriedModulePath, relativePath, relativeURLPath, resolvePath, } from "./paths.js";
|
|
17
17
|
import { byPosition, isComponentFile, renderPosition } from "./position.js";
|
|
18
18
|
import { DEFAULT_BATCH_CAP, propertyTables, UNANSWERED } from "./query.js";
|
|
19
|
+
import { sourceFilesOf } from "./source-files.js";
|
|
19
20
|
import { typeParameterReads } from "./type-parameter-reads.js";
|
|
20
21
|
import { typeQueryAliases } from "./type-query-alias.js";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
22
|
+
import { callsPlatform, isPlatformGlobal, startsThread } from "./platform-symbols.js";
|
|
23
|
+
import { writtenName } from "./platform-calls.js";
|
|
24
|
+
import { computedLoadsOf, isLoadCall } from "./roots/unseen-loads.js";
|
|
23
25
|
import { computedKeyNames, iterationReferences, keyNameOf, keyedUses, } from "./symbol-keys.js";
|
|
24
26
|
import { handedOn, valuesOf } from "./value-flow.js";
|
|
25
27
|
import { bytewise } from "./text/compare.js";
|
|
@@ -185,25 +187,23 @@ function isImportMetaURL(node) {
|
|
|
185
187
|
}
|
|
186
188
|
/** The module URL one node builds, where it builds one. */
|
|
187
189
|
function moduleURLOf(node) {
|
|
188
|
-
const
|
|
190
|
+
const literal = (argument) => {
|
|
189
191
|
const at = argument === undefined ? undefined : parenthesesRemoved(argument);
|
|
190
|
-
return at
|
|
191
|
-
(isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at)) &&
|
|
192
|
-
/^\.\.?\//u.test(at.text)
|
|
193
|
-
? at.text
|
|
194
|
-
: undefined;
|
|
192
|
+
return isLiteralText(at) ? at.text : undefined;
|
|
195
193
|
};
|
|
196
|
-
|
|
194
|
+
const constructor = isNewExpression(node) ? writtenName(node.expression) : undefined;
|
|
195
|
+
if (isNewExpression(node) && constructor !== undefined) {
|
|
197
196
|
const [reference, base] = node.arguments ?? [];
|
|
198
|
-
const specifier =
|
|
197
|
+
const specifier = literal(reference);
|
|
199
198
|
return specifier !== undefined && base !== undefined && isImportMetaURL(base)
|
|
200
|
-
? { specifier, constructor
|
|
199
|
+
? { specifier, constructor, at: node }
|
|
201
200
|
: undefined;
|
|
202
201
|
}
|
|
203
202
|
if (isCallExpression(node)) {
|
|
204
203
|
const callee = parenthesesRemoved(node.expression);
|
|
205
|
-
const specifier =
|
|
204
|
+
const specifier = literal(node.arguments[0]);
|
|
206
205
|
if (specifier !== undefined &&
|
|
206
|
+
/^\.\.?\//u.test(specifier) &&
|
|
207
207
|
isPropertyAccessExpression(callee) &&
|
|
208
208
|
isMetaProperty(callee.expression) &&
|
|
209
209
|
callee.expression.keywordToken === SyntaxKind.ImportKeyword &&
|
|
@@ -213,6 +213,63 @@ function moduleURLOf(node) {
|
|
|
213
213
|
}
|
|
214
214
|
return undefined;
|
|
215
215
|
}
|
|
216
|
+
/** The constructors whose first argument addresses a worker. */
|
|
217
|
+
const WORKER_CONSTRUCTORS = new Set(["Worker", "SharedWorker"]);
|
|
218
|
+
/** Whether an options argument is an object literal whose `eval` member is written as anything but `false`. */
|
|
219
|
+
function evaluatesCode(options) {
|
|
220
|
+
const at = options === undefined ? undefined : parenthesesRemoved(options);
|
|
221
|
+
return (at !== undefined &&
|
|
222
|
+
isObjectLiteralExpression(at) &&
|
|
223
|
+
at.properties.some((property) => (isShorthandPropertyAssignment(property) &&
|
|
224
|
+
isIdentifier(property.name) &&
|
|
225
|
+
property.name.text === "eval") ||
|
|
226
|
+
(isPropertyAssignment(property) &&
|
|
227
|
+
(isIdentifier(property.name) || isStringLiteral(property.name)) &&
|
|
228
|
+
property.name.text === "eval" &&
|
|
229
|
+
parenthesesRemoved(property.initializer).kind !== SyntaxKind.FalseKeyword)));
|
|
230
|
+
}
|
|
231
|
+
/** The worker one node starts by a literal address, where it starts one. */
|
|
232
|
+
function workerOf(node) {
|
|
233
|
+
if (isNewExpression(node)) {
|
|
234
|
+
const constructor = writtenName(node.expression);
|
|
235
|
+
const [address, options] = node.arguments ?? [];
|
|
236
|
+
const literal = address === undefined ? undefined : parenthesesRemoved(address);
|
|
237
|
+
// A thread's constructor may be imported under another name, whose path is relative.
|
|
238
|
+
if (constructor === undefined ||
|
|
239
|
+
!isLiteralText(literal) ||
|
|
240
|
+
(!WORKER_CONSTRUCTORS.has(constructor.text) && !/^\.\.?\//u.test(literal.text))) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
const callee = parenthesesRemoved(node.expression);
|
|
244
|
+
const holder = isPropertyAccessExpression(callee)
|
|
245
|
+
? parenthesesRemoved(callee.expression)
|
|
246
|
+
: undefined;
|
|
247
|
+
return {
|
|
248
|
+
address: literal,
|
|
249
|
+
constructor,
|
|
250
|
+
holder: holder !== undefined && isIdentifier(holder) ? holder : undefined,
|
|
251
|
+
evaluated: evaluatesCode(options),
|
|
252
|
+
at: node,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (!isCallExpression(node)) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
const callee = parenthesesRemoved(node.expression);
|
|
259
|
+
const registry = isPropertyAccessExpression(callee) && callee.name.text === "register"
|
|
260
|
+
? parenthesesRemoved(callee.expression)
|
|
261
|
+
: undefined;
|
|
262
|
+
const navigator = registry !== undefined &&
|
|
263
|
+
isPropertyAccessExpression(registry) &&
|
|
264
|
+
registry.name.text === "serviceWorker"
|
|
265
|
+
? writtenName(registry.expression)
|
|
266
|
+
: undefined;
|
|
267
|
+
const [address] = node.arguments;
|
|
268
|
+
const literal = address === undefined ? undefined : parenthesesRemoved(address);
|
|
269
|
+
return navigator?.text === "navigator" && isLiteralText(literal)
|
|
270
|
+
? { address: literal, constructor: navigator, holder: undefined, evaluated: false, at: node }
|
|
271
|
+
: undefined;
|
|
272
|
+
}
|
|
216
273
|
/** The file of the target a relative specifier written in `file` names, by its source or output name. */
|
|
217
274
|
function fileNamed(file, specifier, fileIdByName) {
|
|
218
275
|
return specifierCandidates(dirnamePath(file.fileName), specifier)
|
|
@@ -226,10 +283,33 @@ function isLiteralText(node) {
|
|
|
226
283
|
/**
|
|
227
284
|
* The module specifier of the module one node evaluates, if it evaluates one: an import
|
|
228
285
|
* declaration, an import-equals declaration of an external module, an export
|
|
229
|
-
* declaration that names a module,
|
|
230
|
-
*
|
|
231
|
-
*
|
|
286
|
+
* declaration that names a module, an `import()` call whose argument is literal text, and
|
|
287
|
+
* a call that may be a `require()` of literal text: one written as the name `require`, or
|
|
288
|
+
* one of a relative specifier through another name. A type-only form evaluates nothing.
|
|
289
|
+
* An `import()` of a computed argument names no module this pass can know.
|
|
232
290
|
*/
|
|
291
|
+
function evaluationOf(node) {
|
|
292
|
+
if (isCallExpression(node) && node.expression.kind !== SyntaxKind.ImportKeyword) {
|
|
293
|
+
const [argument] = node.arguments;
|
|
294
|
+
const require = writtenName(node.expression);
|
|
295
|
+
if (require === undefined ||
|
|
296
|
+
!isLiteralText(argument) ||
|
|
297
|
+
(require.text !== "require" && !/^\.\.?\//u.test(argument.text))) {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
return { node: argument, require, whole: !discarded(node) };
|
|
301
|
+
}
|
|
302
|
+
const specifier = evaluatedBy(node);
|
|
303
|
+
return specifier === undefined ? undefined : { node: specifier };
|
|
304
|
+
}
|
|
305
|
+
/** Whether an expression's value is thrown away: it is a statement of its own, or `void`'s operand. */
|
|
306
|
+
function discarded(expression) {
|
|
307
|
+
let at = expression.parent;
|
|
308
|
+
while (isParenthesizedExpression(at)) {
|
|
309
|
+
at = at.parent;
|
|
310
|
+
}
|
|
311
|
+
return isExpressionStatement(at) || isVoidExpression(at);
|
|
312
|
+
}
|
|
233
313
|
function evaluatedBy(node) {
|
|
234
314
|
if (isImportDeclaration(node)) {
|
|
235
315
|
return node.importClause?.phaseModifier === SyntaxKind.TypeKeyword
|
|
@@ -338,6 +418,7 @@ function sitesOf(file, declarations, fileId, unread) {
|
|
|
338
418
|
const evaluations = [];
|
|
339
419
|
const wholes = [];
|
|
340
420
|
const urls = [];
|
|
421
|
+
const workers = [];
|
|
341
422
|
const loadCalls = [];
|
|
342
423
|
const decorated = [];
|
|
343
424
|
const parameterWrites = [];
|
|
@@ -414,14 +495,18 @@ function sitesOf(file, declarations, fileId, unread) {
|
|
|
414
495
|
reads.push({ ...read, from: enclosing });
|
|
415
496
|
}
|
|
416
497
|
links.push(...linksOf(file, node, declarations, enclosing));
|
|
417
|
-
const evaluated =
|
|
498
|
+
const evaluated = evaluationOf(node);
|
|
418
499
|
if (evaluated !== undefined) {
|
|
419
|
-
evaluations.push({
|
|
500
|
+
evaluations.push({ ...evaluated, from: enclosing });
|
|
420
501
|
}
|
|
421
502
|
const url = moduleURLOf(node);
|
|
422
503
|
if (url !== undefined) {
|
|
423
504
|
urls.push({ ...url, from: enclosing });
|
|
424
505
|
}
|
|
506
|
+
const worker = workerOf(node);
|
|
507
|
+
if (worker !== undefined) {
|
|
508
|
+
workers.push({ ...worker, from: enclosing });
|
|
509
|
+
}
|
|
425
510
|
if (isLoadCall(node)) {
|
|
426
511
|
loadCalls.push({ call: node, from: enclosing });
|
|
427
512
|
}
|
|
@@ -457,6 +542,7 @@ function sitesOf(file, declarations, fileId, unread) {
|
|
|
457
542
|
evaluations,
|
|
458
543
|
wholes,
|
|
459
544
|
urls,
|
|
545
|
+
workers,
|
|
460
546
|
loadCalls,
|
|
461
547
|
decorated,
|
|
462
548
|
parameterWrites,
|
|
@@ -643,6 +729,10 @@ export function references(project, held, targetRoot, options) {
|
|
|
643
729
|
let batched = 0;
|
|
644
730
|
let fileBatches = 0;
|
|
645
731
|
let residueFallbacks = 0;
|
|
732
|
+
let platformLookups = 0;
|
|
733
|
+
const asked = () => {
|
|
734
|
+
platformLookups += 1;
|
|
735
|
+
};
|
|
646
736
|
let shorthandLookups = 0;
|
|
647
737
|
const consumer = options.consumer;
|
|
648
738
|
const root = consumer?.root ?? targetRoot;
|
|
@@ -678,6 +768,8 @@ export function references(project, held, targetRoot, options) {
|
|
|
678
768
|
}
|
|
679
769
|
return moduleBodies.get(moduleId) ?? [];
|
|
680
770
|
};
|
|
771
|
+
let ownFiles;
|
|
772
|
+
const unseenLoads = [];
|
|
681
773
|
const exportsCache = new Map();
|
|
682
774
|
/**
|
|
683
775
|
* Every declaration one module exports, each re-export walked along its chain. A module
|
|
@@ -791,6 +883,7 @@ export function references(project, held, targetRoot, options) {
|
|
|
791
883
|
const loadable = walked
|
|
792
884
|
.filter((one) => fileIds.has(one.fileId))
|
|
793
885
|
.map(({ file, fileId }) => ({ file, fileId }));
|
|
886
|
+
const loadableById = new Map(loadable.map((one) => [one.fileId, one.file]));
|
|
794
887
|
const contextual = contextualUses(project, held, chains, walked.flatMap((one) => one.literals), walked.flatMap((one) => one.flows), cap, tables);
|
|
795
888
|
const writtenBy = new Map();
|
|
796
889
|
for (const write of contextual.writes) {
|
|
@@ -870,9 +963,9 @@ export function references(project, held, targetRoot, options) {
|
|
|
870
963
|
}
|
|
871
964
|
}
|
|
872
965
|
const keyNames = computedKeyNames(held.symbols);
|
|
873
|
-
for (const { file, fileId, uses, reads, links, evaluations, wholes, urls, loadCalls, decorated, parameterWrites, keyed, } of walked) {
|
|
966
|
+
for (const { file, fileId, uses, reads, links, evaluations, wholes, urls, workers, loadCalls, decorated, parameterWrites, keyed, } of walked) {
|
|
874
967
|
const test = testFile.get(file) === true;
|
|
875
|
-
const loads = computedLoadsOf(file, loadCalls, loadable);
|
|
968
|
+
const loads = computedLoadsOf(file, loadCalls, loadable, (fileName) => options.directories.bundlerRootOf(fileName));
|
|
876
969
|
// A component file's markup may use any binding its blocks declare at the top level.
|
|
877
970
|
const markup = isComponentFile(file);
|
|
878
971
|
const bindings = markup ? importBindings(file) : [];
|
|
@@ -909,9 +1002,15 @@ export function references(project, held, targetRoot, options) {
|
|
|
909
1002
|
...new Set([
|
|
910
1003
|
...uses.filter((site) => site.shorthand === undefined).map((site) => site.node),
|
|
911
1004
|
...links.map((link) => link.node),
|
|
912
|
-
...evaluations.
|
|
1005
|
+
...evaluations.flatMap((evaluation) => evaluation.require === undefined
|
|
1006
|
+
? [evaluation.node]
|
|
1007
|
+
: [
|
|
1008
|
+
evaluation.require,
|
|
1009
|
+
...(evaluation.require.text === "require" ? [evaluation.node] : []),
|
|
1010
|
+
]),
|
|
913
1011
|
...wholes.map((whole) => whole.specifier),
|
|
914
1012
|
...urls.flatMap((url) => url.constructor ?? []),
|
|
1013
|
+
...workers.flatMap((worker) => worker.holder === undefined ? [worker.constructor] : [worker.constructor, worker.holder]),
|
|
915
1014
|
...bindings.map((binding) => binding.node),
|
|
916
1015
|
...loads.flatMap((load) => [
|
|
917
1016
|
...(load.require === undefined ? [] : [load.require]),
|
|
@@ -952,9 +1051,11 @@ export function references(project, held, targetRoot, options) {
|
|
|
952
1051
|
});
|
|
953
1052
|
}
|
|
954
1053
|
}
|
|
1054
|
+
const loading = evaluations.filter((one) => one.require === undefined ||
|
|
1055
|
+
callsPlatform(project, "require", one.require, answered.get(one.require), asked));
|
|
955
1056
|
// A script declares no module, so the checker names nothing for a specifier of one;
|
|
956
1057
|
// the compiler's module resolution still names its file.
|
|
957
|
-
const unnamed =
|
|
1058
|
+
const unnamed = loading.flatMap(({ node }) => answered.get(node) === undefined &&
|
|
958
1059
|
isStringLiteralLikeNode(node) &&
|
|
959
1060
|
queriedFile(file, node, fileIdByName) === undefined
|
|
960
1061
|
? [node]
|
|
@@ -964,7 +1065,8 @@ export function references(project, held, targetRoot, options) {
|
|
|
964
1065
|
const name = resolved[at];
|
|
965
1066
|
return [node, name === undefined ? undefined : fileIdByName.get(name)];
|
|
966
1067
|
}));
|
|
967
|
-
|
|
1068
|
+
const wholeReads = [];
|
|
1069
|
+
for (const evaluation of loading) {
|
|
968
1070
|
const queried = queriedFile(file, evaluation.node, fileIdByName);
|
|
969
1071
|
if (queried !== undefined) {
|
|
970
1072
|
found.push({
|
|
@@ -977,7 +1079,18 @@ export function references(project, held, targetRoot, options) {
|
|
|
977
1079
|
});
|
|
978
1080
|
}
|
|
979
1081
|
const module = answered.get(evaluation.node);
|
|
980
|
-
|
|
1082
|
+
// Node's require resolves a relative specifier the program records no resolution for,
|
|
1083
|
+
// as in a TypeScript file, by its own extension search.
|
|
1084
|
+
const script = scripts.get(evaluation.node) ??
|
|
1085
|
+
(evaluation.require !== undefined &&
|
|
1086
|
+
module === undefined &&
|
|
1087
|
+
isLiteralText(evaluation.node) &&
|
|
1088
|
+
/^\.\.?\//u.test(evaluation.node.text)
|
|
1089
|
+
? fileNamed(file, evaluation.node.text, fileIdByName)
|
|
1090
|
+
: undefined);
|
|
1091
|
+
if (script !== undefined && evaluation.whole === true && module === undefined) {
|
|
1092
|
+
wholeReads.push({ evaluation, fileId: script });
|
|
1093
|
+
}
|
|
981
1094
|
if (script !== undefined) {
|
|
982
1095
|
found.push({
|
|
983
1096
|
from: evaluation.from,
|
|
@@ -1007,12 +1120,34 @@ export function references(project, held, targetRoot, options) {
|
|
|
1007
1120
|
}
|
|
1008
1121
|
}
|
|
1009
1122
|
}
|
|
1123
|
+
// A required file the checker names no module for is read whole where the call's value
|
|
1124
|
+
// is used: the value is the file's exports object, which this pass does not follow.
|
|
1125
|
+
const required = wholeReads.flatMap((one) => {
|
|
1126
|
+
const loaded = loadableById.get(one.fileId);
|
|
1127
|
+
return loaded === undefined ? [] : [{ ...one, loaded }];
|
|
1128
|
+
});
|
|
1129
|
+
const modules = project.symbolsAt(required.map((one) => project.handle(one.loaded)), cap);
|
|
1130
|
+
required.forEach(({ evaluation }, at) => {
|
|
1131
|
+
const module = modules[at];
|
|
1132
|
+
const position = renderPosition(file, root, evaluation.node.getStart());
|
|
1133
|
+
for (const target of module === undefined ? [] : exportsRead(module)) {
|
|
1134
|
+
found.push({
|
|
1135
|
+
from: evaluation.from,
|
|
1136
|
+
to: target.id,
|
|
1137
|
+
position,
|
|
1138
|
+
use: "read",
|
|
1139
|
+
resolution: target.guessed ? "by-name" : "batch",
|
|
1140
|
+
test,
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1010
1144
|
for (const url of urls) {
|
|
1011
|
-
|
|
1012
|
-
|
|
1145
|
+
if (url.constructor !== undefined &&
|
|
1146
|
+
!callsPlatform(project, "URL", url.constructor, answered.get(url.constructor), asked)) {
|
|
1013
1147
|
continue;
|
|
1014
1148
|
}
|
|
1015
|
-
const
|
|
1149
|
+
const path = relativeURLPath(dirnamePath(file.fileName), url.specifier);
|
|
1150
|
+
const loaded = path === undefined ? undefined : fileNamed(file, path, fileIdByName);
|
|
1016
1151
|
if (loaded !== undefined) {
|
|
1017
1152
|
found.push({
|
|
1018
1153
|
from: url.from,
|
|
@@ -1024,15 +1159,48 @@ export function references(project, held, targetRoot, options) {
|
|
|
1024
1159
|
});
|
|
1025
1160
|
}
|
|
1026
1161
|
}
|
|
1162
|
+
for (const worker of workers) {
|
|
1163
|
+
const symbol = answered.get(worker.constructor);
|
|
1164
|
+
const text = worker.address.text;
|
|
1165
|
+
let path;
|
|
1166
|
+
if (startsThread(project, symbol, worker.holder && answered.get(worker.holder), asked)) {
|
|
1167
|
+
path =
|
|
1168
|
+
worker.evaluated || !/^\.\.?\//u.test(text)
|
|
1169
|
+
? undefined
|
|
1170
|
+
: resolvePath(options.directories.workingDirectoryOf(file.fileName), text);
|
|
1171
|
+
}
|
|
1172
|
+
else if ((WORKER_CONSTRUCTORS.has(worker.constructor.text) ||
|
|
1173
|
+
worker.constructor.text === "navigator") &&
|
|
1174
|
+
isPlatformGlobal(project, symbol)) {
|
|
1175
|
+
path = relativeURLPath(dirnamePath(file.fileName), text);
|
|
1176
|
+
}
|
|
1177
|
+
ownFiles ??= sourceFilesOf(project, targetRoot);
|
|
1178
|
+
for (const started of path === undefined ? [] : ownFiles.named(path)) {
|
|
1179
|
+
const to = declaredAt(started);
|
|
1180
|
+
if (to !== undefined && fileIds.has(to)) {
|
|
1181
|
+
found.push({
|
|
1182
|
+
from: worker.from,
|
|
1183
|
+
to,
|
|
1184
|
+
position: renderPosition(file, root, worker.at.getStart()),
|
|
1185
|
+
use: "evaluation",
|
|
1186
|
+
resolution: "syntax",
|
|
1187
|
+
test,
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1027
1192
|
// A computed load imports each file it loads where the call is written, reading what
|
|
1028
|
-
// the file exports unless it reads the file as text or a URL;
|
|
1029
|
-
// `require
|
|
1193
|
+
// the file exports unless it reads the file as text or a URL; callsPlatform owns which
|
|
1194
|
+
// call is a `require`.
|
|
1030
1195
|
for (const load of loads) {
|
|
1031
|
-
|
|
1032
|
-
|
|
1196
|
+
if (load.require !== undefined &&
|
|
1197
|
+
!callsPlatform(project, "require", load.require, answered.get(load.require), asked)) {
|
|
1033
1198
|
continue;
|
|
1034
1199
|
}
|
|
1035
1200
|
const position = renderPosition(file, root, load.call.getStart());
|
|
1201
|
+
if (!load.resolved && !test && consumer === undefined && !file.isDeclarationFile) {
|
|
1202
|
+
unseenLoads.push(position);
|
|
1203
|
+
}
|
|
1036
1204
|
for (const loaded of load.files) {
|
|
1037
1205
|
found.push({
|
|
1038
1206
|
from: load.eager ? fileId : load.from,
|
|
@@ -1248,12 +1416,14 @@ export function references(project, held, targetRoot, options) {
|
|
|
1248
1416
|
? found
|
|
1249
1417
|
: found.map((reference) => ({ ...reference, consumer: consumer.id })),
|
|
1250
1418
|
testFilePaths: tests.sort(bytewise),
|
|
1419
|
+
unseenLoads,
|
|
1251
1420
|
cost: {
|
|
1252
1421
|
batched,
|
|
1253
1422
|
fileBatches,
|
|
1254
1423
|
residueFallbacks,
|
|
1255
1424
|
shorthandLookups,
|
|
1256
1425
|
aliasSteps: chains.steps,
|
|
1426
|
+
platformLookups,
|
|
1257
1427
|
patternBatches: destructured.cost.patternBatches,
|
|
1258
1428
|
patternLookups: destructured.cost.patternLookups,
|
|
1259
1429
|
contextualBatches: contextual.batches,
|
package/dist/src/resolve.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SETTINGS } from "./contract/config.generated.js";
|
|
2
2
|
import { FAMILY_KEY_LENGTH } from "./contract/contract.generated.js";
|
|
3
3
|
import {} from "./config.js";
|
|
4
|
-
import { CONVENTION_ROWS } from "./convention-rows.js";
|
|
4
|
+
import { CONVENTION_ROWS } from "./entries/convention-rows.js";
|
|
5
5
|
import { refuseOverBound } from "./fs/document.js";
|
|
6
6
|
import { dotted, isRecord, locatedFault, placeIn, pointerOf, readStrict, StrictJSONError, } from "./json-document.js";
|
|
7
7
|
import { FIXED_SEVERITY_CODES } from "./kinds.js";
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { isCallExpression, isExportDeclaration, isExternalModuleReference, isImportDeclaration, isImportEqualsDeclaration, isNoSubstitutionTemplateLiteral, isStringLiteral, SyntaxKind, } from "@typescript/native/ast";
|
|
8
8
|
import { SymbolFlags } from "@typescript/native/sync";
|
|
9
|
-
import { resolvedTargets } from "
|
|
10
|
-
import { declaredComponent } from "
|
|
11
|
-
import { must, Unanswerable } from "
|
|
12
|
-
import { nameComponent } from "
|
|
9
|
+
import { resolvedTargets } from "../calls.js";
|
|
10
|
+
import { declaredComponent } from "../inventory.js";
|
|
11
|
+
import { must, Unanswerable } from "../query.js";
|
|
12
|
+
import { nameComponent } from "../ref.js";
|
|
13
13
|
/** The meanings a name of the global scope is looked up under: any of them. */
|
|
14
14
|
const ANY_MEANING = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace;
|
|
15
15
|
/** The suffix that marks a static member at the end of a path. */
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Every entry-point convention this analyzer declines, each with
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Every row carries a reason, because the list is read where the rows are shown
|
|
8
|
-
* one at a time: beside a finding, or in a report's declared gaps.
|
|
2
|
+
* Every entry-point convention this analyzer declines, each with its tool and why. A file only
|
|
3
|
+
* a declined convention enters is reported as never imported, so a project relying on one names
|
|
4
|
+
* the file in `ts.entry_files` or `roots.patterns`, and this list tells it to. Every row carries
|
|
5
|
+
* a reason, since rows are shown one at a time, beside a finding or in a report's declared gaps.
|
|
9
6
|
*/
|
|
10
|
-
import { bytewise } from "
|
|
7
|
+
import { bytewise } from "../text/compare.js";
|
|
11
8
|
/** What is declined for a tool whose own conventions are entered only through its configuration files. */
|
|
12
9
|
const EVERY_CONVENTION = "every file it loads by its own convention beyond its configuration files";
|
|
13
10
|
/** Why a tool whose own conventions are not read declines them. */
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* shell running its command or one of its scripts. {@link readManifest} reads one
|
|
5
5
|
* directory's manifest, {@link packageEntries} those of the packages below the target root.
|
|
6
6
|
*/
|
|
7
|
-
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "
|
|
8
|
-
import { isRecord } from "
|
|
9
|
-
import { MANIFEST, manifestAt, readJSON } from "
|
|
10
|
-
import { pathsNamed, readCommands } from "
|
|
7
|
+
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "../paths.js";
|
|
8
|
+
import { isRecord } from "../json-document.js";
|
|
9
|
+
import { MANIFEST, manifestAt, readJSON } from "../fs/manifest.js";
|
|
10
|
+
import { pathsNamed, readCommands } from "../commands/read.js";
|
|
11
11
|
/** The three members that name an entry point beside `exports` and `bin`. */
|
|
12
12
|
const LEGACY_MEMBERS = ["main", "module", "types"];
|
|
13
13
|
/**
|