@cplieger/deadset-ts 8.0.0-dev.15 → 8.0.0-dev.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/alias-chain.js +0 -5
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +94 -54
- package/dist/src/augmentations.js +23 -24
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +25 -8
- package/dist/src/commands/read.js +6 -7
- 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 +9 -10
- package/dist/src/contextual-uses.js +1 -17
- package/dist/src/contract/config.generated.js +5 -2
- package/dist/src/contract/contract.generated.js +119 -2
- package/dist/src/contract/report.generated.js +6 -2
- package/dist/src/dependencies.js +98 -71
- package/dist/src/destructuring.js +1 -19
- package/dist/src/element-access.js +179 -164
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +22 -64
- 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} +9 -12
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +3 -3
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -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/completion.js +40 -4
- package/dist/src/findings/emitters.js +5 -8
- 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/self-check.js +36 -20
- package/dist/src/findings-pass.js +5 -6
- package/dist/src/framework-lifecycle.js +42 -15
- package/dist/src/fs/manifest.js +15 -20
- package/dist/src/generated-file.js +172 -29
- package/dist/src/graph.js +14 -8
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index.js +1 -1
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.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/keyof-comparisons.js +124 -103
- 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/expected-module.js +2 -2
- package/dist/src/load/plan.js +2 -2
- package/dist/src/load/specifiers.js +2 -4
- package/dist/src/load/synthesize.js +10 -5
- package/dist/src/load/workspace-manifests.js +1 -1
- package/dist/src/load/workspace-resolution.js +2 -2
- package/dist/src/matrix.js +12 -17
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/paths.js +56 -1
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -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 +151 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +111 -1116
- package/dist/src/resolve.js +1 -1
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +7 -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 +236 -0
- package/dist/src/serialization-contract.js +9 -4
- package/dist/src/source-files.js +5 -9
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress.js +30 -32
- package/dist/src/sweep.js +25 -13
- package/dist/src/symbol-keys.js +89 -83
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/verbs/analyze.js +15 -3
- package/dist/src/verbs/describe.js +5 -3
- package/dist/src/verbs/explain.js +50 -28
- package/dist/src/verbs/print-retained.js +2 -2
- package/jsr.json +1 -1
- package/package.json +3 -3
- package/src/alias-chain.ts +0 -7
- package/src/amd.ts +130 -0
- package/src/analysis.ts +156 -70
- package/src/augmentations.ts +41 -27
- package/src/automatic-types.ts +1 -1
- package/src/bindings.ts +460 -0
- package/src/calls.ts +25 -7
- package/src/commands/read.ts +6 -8
- 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 +12 -11
- package/src/contextual-uses.ts +2 -22
- package/src/contract/config.generated.ts +5 -2
- package/src/contract/contract.generated.ts +138 -2
- package/src/contract/report.generated.ts +6 -2
- package/src/dependencies.ts +117 -71
- package/src/destructuring.ts +1 -31
- package/src/element-access.ts +188 -182
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +33 -82
- package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
- package/src/{conventions.ts → entries/conventions.ts} +349 -523
- package/src/{html-entries.ts → entries/html-entries.ts} +19 -18
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +5 -5
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -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 +46 -0
- package/src/file-facts.ts +1 -1
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +43 -4
- package/src/findings/emitter.ts +1 -1
- package/src/findings/emitters.ts +14 -10
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
- 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 +43 -15
- package/src/fs/manifest.ts +25 -21
- package/src/generated-file.ts +240 -36
- package/src/graph.ts +27 -11
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index.ts +1 -1
- package/src/indexed-access.ts +570 -527
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.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/keyof-comparisons.ts +131 -116
- package/src/load/classify.ts +49 -13
- package/src/load/diagnostics.ts +11 -1
- package/src/load/discover.ts +27 -11
- package/src/load/expected-module.ts +8 -2
- package/src/load/plan.ts +11 -2
- package/src/load/specifiers.ts +8 -5
- package/src/load/synthesize.ts +12 -6
- package/src/load/test-globals.ts +1 -1
- package/src/load/workspace-manifests.ts +1 -1
- package/src/load/workspace-resolution.ts +9 -2
- package/src/load/workspace-run.ts +1 -1
- package/src/matrix.ts +13 -17
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/paths.ts +65 -1
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +213 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +174 -1492
- package/src/report.ts +2 -2
- package/src/resolve.ts +1 -1
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +10 -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 +345 -0
- package/src/serialization-contract.ts +9 -4
- package/src/source-files.ts +5 -10
- package/src/stores.ts +13 -2
- package/src/suppress.ts +48 -33
- package/src/sweep.ts +37 -14
- package/src/symbol-keys.ts +102 -102
- package/src/tests/file-class.ts +118 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/verbs/analyze.ts +19 -5
- package/src/verbs/describe.ts +5 -2
- package/src/verbs/explain.ts +75 -32
- package/src/verbs/print-retained.ts +2 -2
- 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
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { EXIT_CLEAN, EXIT_USAGE } from "../contract/contract.generated.js";
|
|
2
|
-
import { runAnalysis } from "../analysis.js";
|
|
2
|
+
import { productionMode, runAnalysis } from "../analysis.js";
|
|
3
3
|
import { listing } from "../components.js";
|
|
4
4
|
import { OUTSIDE, swept as judged } from "../graph.js";
|
|
5
5
|
import { referenceKey } from "../matrix.js";
|
|
6
6
|
import { partialNotes } from "../partial.js";
|
|
7
7
|
import { resolvePath } from "../paths.js";
|
|
8
8
|
import { positionKey } from "../position.js";
|
|
9
|
+
import { madeByTestCode, withheldBy } from "../tests/file-class.js";
|
|
9
10
|
import { resolve } from "../resolve.js";
|
|
10
11
|
import {} from "./verb.js";
|
|
11
12
|
import { UsageError } from "../usage.js";
|
|
@@ -107,24 +108,32 @@ function rootsOf(configured) {
|
|
|
107
108
|
});
|
|
108
109
|
}
|
|
109
110
|
/**
|
|
110
|
-
* The shortest path from a root
|
|
111
|
-
* from every root at once in the order the run names them,
|
|
112
|
-
*
|
|
111
|
+
* The shortest path from a root, a loaded consumer or a test file no project holds to one
|
|
112
|
+
* declaration, walked breadth first from every root at once in the order the run names them,
|
|
113
|
+
* a reference of a consumer or of such a file being the first hop of a path of its own, as
|
|
114
|
+
* the sweep seeds them, and following the references the sweep follows: a
|
|
113
115
|
* reference that reads a module reaches what the module exports, and an evaluation or a root
|
|
114
116
|
* reaches the module alone. Under `production` no reference a test file made is followed,
|
|
115
117
|
* which is the set the report's sweep counts.
|
|
116
118
|
*/
|
|
117
|
-
function shortestPath(analysis, to,
|
|
119
|
+
function shortestPath(analysis, to, mode, support) {
|
|
118
120
|
const graph = analysis.swept.matrix.union;
|
|
119
121
|
const out = new Map();
|
|
120
122
|
const consumed = [];
|
|
121
123
|
for (const reference of referencesOf(analysis.configured)) {
|
|
122
|
-
if (
|
|
124
|
+
if (withheldBy(mode, reference, support)) {
|
|
123
125
|
continue;
|
|
124
126
|
}
|
|
125
127
|
const { consumer } = reference;
|
|
126
128
|
if (consumer !== undefined) {
|
|
127
|
-
consumed.push({
|
|
129
|
+
consumed.push({ reference, origin: { k: "consumer", consumer } });
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (reference.unheld === true) {
|
|
133
|
+
consumed.push({
|
|
134
|
+
reference,
|
|
135
|
+
origin: { k: "unheld", file: reference.from.replace(/#$/u, "") },
|
|
136
|
+
});
|
|
128
137
|
continue;
|
|
129
138
|
}
|
|
130
139
|
const held = out.get(reference.from);
|
|
@@ -161,13 +170,12 @@ function shortestPath(analysis, to, production) {
|
|
|
161
170
|
for (const root of rootsOf(analysis.configured)) {
|
|
162
171
|
enter({ at: root.id, hop: undefined, previous: -1, origin: { k: "root", root } });
|
|
163
172
|
}
|
|
164
|
-
// A
|
|
165
|
-
// hops do.
|
|
173
|
+
// A consumed reference is one hop long, so it joins the walk where the roots' first hops do.
|
|
166
174
|
const firstHops = steps.length;
|
|
167
175
|
for (let head = 0;; head += 1) {
|
|
168
176
|
if (head === firstHops) {
|
|
169
|
-
for (const reference of consumed) {
|
|
170
|
-
follow(reference, -1,
|
|
177
|
+
for (const { reference, origin } of consumed) {
|
|
178
|
+
follow(reference, -1, origin);
|
|
171
179
|
}
|
|
172
180
|
}
|
|
173
181
|
const step = steps[head];
|
|
@@ -187,15 +195,27 @@ function shortestPath(analysis, to, production) {
|
|
|
187
195
|
}
|
|
188
196
|
return undefined;
|
|
189
197
|
}
|
|
198
|
+
/** Where a path starts, as a line names it. */
|
|
199
|
+
function originText(origin) {
|
|
200
|
+
switch (origin.k) {
|
|
201
|
+
case "root":
|
|
202
|
+
return `root ${origin.root.kind} ${origin.root.id}`;
|
|
203
|
+
case "consumer":
|
|
204
|
+
return `consumer ${origin.consumer}`;
|
|
205
|
+
case "unheld":
|
|
206
|
+
return `test file no project holds ${origin.file}`;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
190
209
|
/** What made a reference: a declaration of the target, or a loaded consumer. */
|
|
191
210
|
function madeBy(reference) {
|
|
192
211
|
return reference.consumer === undefined ? reference.from : `consumer ${reference.consumer}`;
|
|
193
212
|
}
|
|
194
|
-
|
|
195
|
-
|
|
213
|
+
/** One reference of an answer, marked where test code made it, a test-support file's included. */
|
|
214
|
+
function referenceLine(reference, tail, support) {
|
|
215
|
+
return ` reference: ${positionKey(reference.position)}\t${reference.use}\t${tail}${madeByTestCode(reference, support) ? "\tfrom a test file" : ""}\n`;
|
|
196
216
|
}
|
|
197
217
|
/** Why a declaration no finding names and no exemption held back is live, or how it fell. */
|
|
198
|
-
function liveness(analysis, subject, cascade) {
|
|
218
|
+
function liveness(analysis, subject, cascade, mode) {
|
|
199
219
|
const { sweep } = analysis.swept;
|
|
200
220
|
const candidate = sweep.candidates.find((one) => one.id === subject.id);
|
|
201
221
|
if (candidate === undefined && !judged(subject.kind)) {
|
|
@@ -206,12 +226,14 @@ function liveness(analysis, subject, cascade) {
|
|
|
206
226
|
for (const root of rootsOf(analysis.configured).filter((one) => one.id === subject.id)) {
|
|
207
227
|
text += ` root: ${root.kind}${root.source === "" ? "" : `\tnamed by ${root.source}`}\n`;
|
|
208
228
|
}
|
|
209
|
-
const
|
|
229
|
+
const support = new Set(analysis.configured.flatMap((one) => one.supportFiles ?? []));
|
|
230
|
+
const found = shortestPath(analysis, subject.id, mode, support) ??
|
|
231
|
+
shortestPath(analysis, subject.id, { production: false }, support);
|
|
210
232
|
if (found !== undefined && found.path.length > 0) {
|
|
211
233
|
const { origin } = found;
|
|
212
|
-
text += ` reached from: ${origin
|
|
234
|
+
text += ` reached from: ${originText(origin)}\n`;
|
|
213
235
|
for (const hop of found.path) {
|
|
214
|
-
text += referenceLine(hop.reference, `${madeBy(hop.reference)} -> ${hop.reference.to}
|
|
236
|
+
text += referenceLine(hop.reference, `${madeBy(hop.reference)} -> ${hop.reference.to}`, support);
|
|
215
237
|
if (hop.k === "export") {
|
|
216
238
|
text += ` export: ${hop.reference.to} -> ${hop.to}\n`;
|
|
217
239
|
}
|
|
@@ -219,10 +241,11 @@ function liveness(analysis, subject, cascade) {
|
|
|
219
241
|
}
|
|
220
242
|
else if (found === undefined) {
|
|
221
243
|
const references = referencesOf(analysis.configured).filter((one) => one.to === subject.id);
|
|
222
|
-
text +=
|
|
244
|
+
text +=
|
|
245
|
+
" unreachable: no path of references reaches it from a root, a loaded consumer or a test file no project holds\n";
|
|
223
246
|
text += ` references: ${String(references.length)}\n`;
|
|
224
247
|
for (const reference of references) {
|
|
225
|
-
text += referenceLine(reference, `from ${madeBy(reference)}
|
|
248
|
+
text += referenceLine(reference, `from ${madeBy(reference)}`, support);
|
|
226
249
|
}
|
|
227
250
|
}
|
|
228
251
|
if (candidate !== undefined) {
|
|
@@ -271,7 +294,7 @@ function namedElsewhere(findings, subject) {
|
|
|
271
294
|
.join("");
|
|
272
295
|
}
|
|
273
296
|
/** The one explanation that applies to a declaration, built whole before it is written. */
|
|
274
|
-
function explanation(analysis, subject, cascade) {
|
|
297
|
+
function explanation(analysis, subject, cascade, mode) {
|
|
275
298
|
const graph = analysis.swept.matrix.union;
|
|
276
299
|
const at = graph.at(subject.id);
|
|
277
300
|
let text = `symbol: ${subject.ref}\n`;
|
|
@@ -294,7 +317,7 @@ function explanation(analysis, subject, cascade) {
|
|
|
294
317
|
"answer: held\n held by: a question the checker did not answer, which could have kept it live, so no finding names it\n";
|
|
295
318
|
}
|
|
296
319
|
else {
|
|
297
|
-
text += liveness(analysis, subject, cascade);
|
|
320
|
+
text += liveness(analysis, subject, cascade, mode);
|
|
298
321
|
}
|
|
299
322
|
return text + namedElsewhere(analysis.result.findings, subject);
|
|
300
323
|
}
|
|
@@ -302,17 +325,16 @@ function explanation(analysis, subject, cascade) {
|
|
|
302
325
|
* Explains one symbol from the analysis the report is built from: why a reported symbol is
|
|
303
326
|
* reported, which exemption classes held a retained one back, that an unanswered question held
|
|
304
327
|
* a held one, and for any other declaration the relations that hold it live and the shortest
|
|
305
|
-
* path from a root
|
|
306
|
-
* request naming no one declaration exits with the usage
|
|
307
|
-
* matches it. Where the analysis was partial, the error stream says so.
|
|
328
|
+
* path from a root, a loaded consumer or a test file no project holds, or the references it
|
|
329
|
+
* has where no path reaches it. A request naming no one declaration exits with the usage
|
|
330
|
+
* code and names what partially matches it. Where the analysis was partial, the error stream says so.
|
|
308
331
|
*/
|
|
309
332
|
export const explainVerb = ({ out, err, host, inputs, scope, openClient, option }) => {
|
|
310
333
|
const named = namedSymbol(option);
|
|
311
334
|
const { config, provenance } = resolve(inputs());
|
|
312
335
|
const scoped = scope();
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
});
|
|
336
|
+
const mode = productionMode(config);
|
|
337
|
+
const analysis = runAnalysis(openClient(config), host, scoped, config, provenance, mode);
|
|
316
338
|
const { subject, candidates } = subjectOf(analysis.swept.matrix.union.symbols, named);
|
|
317
339
|
const notes = partialNotes({
|
|
318
340
|
notBuilt: analysis.run.notBuilt,
|
|
@@ -329,7 +351,7 @@ export const explainVerb = ({ out, err, host, inputs, scope, openClient, option
|
|
|
329
351
|
}
|
|
330
352
|
}
|
|
331
353
|
else {
|
|
332
|
-
out.write(explanation(analysis, subject, config.reporters.cascade));
|
|
354
|
+
out.write(explanation(analysis, subject, config.reporters.cascade, mode));
|
|
333
355
|
}
|
|
334
356
|
for (const note of notes) {
|
|
335
357
|
diagnose(err, note);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EXIT_CLEAN } from "../contract/contract.generated.js";
|
|
2
|
-
import { runSweep } from "../analysis.js";
|
|
2
|
+
import { productionMode, runSweep } from "../analysis.js";
|
|
3
3
|
import { retainedLines } from "../exempt.js";
|
|
4
4
|
import { partialNotes } from "../partial.js";
|
|
5
5
|
import { resolvePath } from "../paths.js";
|
|
@@ -18,7 +18,7 @@ export const printRetainedVerb = ({ out, err, host, inputs, scope, openClient })
|
|
|
18
18
|
const scoped = scope();
|
|
19
19
|
const swept = runSweep(openClient(config), host, scoped, config, {
|
|
20
20
|
marked: [],
|
|
21
|
-
mode:
|
|
21
|
+
mode: productionMode(config),
|
|
22
22
|
});
|
|
23
23
|
for (const line of retainedLines(swept.matrix.union.symbols, swept.retained)) {
|
|
24
24
|
out.write(`${line}\n`);
|
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/deadset-ts",
|
|
3
|
-
"version": "8.0.0-dev.
|
|
3
|
+
"version": "8.0.0-dev.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Deterministic dead-code analysis for TypeScript, class and type members included",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"lint:fix": "eslint . --fix && prettier --write ."
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@typescript/native": "npm:typescript@7.1.0-dev.
|
|
35
|
+
"@typescript/native": "npm:typescript@7.1.0-dev.20261103.1"
|
|
36
36
|
},
|
|
37
37
|
"overrides": {
|
|
38
38
|
"qs": "^6.15.2"
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"prettier": "3.9.10",
|
|
49
49
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
50
50
|
"typescript-eslint": "8.72.1",
|
|
51
|
-
"vitest": "5.0
|
|
51
|
+
"vitest": "5.1.0"
|
|
52
52
|
},
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public"
|
package/src/alias-chain.ts
CHANGED
|
@@ -49,8 +49,6 @@ export interface AliasChains {
|
|
|
49
49
|
* link is declared.
|
|
50
50
|
*/
|
|
51
51
|
nextDeclared(symbol: TSSymbol): readonly ChainTarget[];
|
|
52
|
-
/** How many steps the compiler was asked for: one per alias, whatever the chains it heads. */
|
|
53
|
-
readonly steps: number;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
/**
|
|
@@ -65,7 +63,6 @@ export function aliasChains<Brand>(project: ProjectView<Brand>, held: Inventory)
|
|
|
65
63
|
const ownFiles = project.ownPaths();
|
|
66
64
|
const steps = new Map<number, Answer<TSSymbol | undefined>>();
|
|
67
65
|
const chains = new Map<number, readonly ChainTarget[]>();
|
|
68
|
-
let asked = 0;
|
|
69
66
|
|
|
70
67
|
const declarationsOf = (symbol: TSSymbol): string[] => {
|
|
71
68
|
const ids: string[] = [];
|
|
@@ -102,7 +99,6 @@ export function aliasChains<Brand>(project: ProjectView<Brand>, held: Inventory)
|
|
|
102
99
|
return steps.get(symbol.id);
|
|
103
100
|
}
|
|
104
101
|
const next = project.aliasStepOf(symbol);
|
|
105
|
-
asked += 1;
|
|
106
102
|
steps.set(symbol.id, next);
|
|
107
103
|
return next;
|
|
108
104
|
};
|
|
@@ -197,8 +193,5 @@ export function aliasChains<Brand>(project: ProjectView<Brand>, held: Inventory)
|
|
|
197
193
|
declarationsOf,
|
|
198
194
|
chainOf,
|
|
199
195
|
nextDeclared,
|
|
200
|
-
get steps() {
|
|
201
|
-
return asked;
|
|
202
|
-
},
|
|
203
196
|
};
|
|
204
197
|
}
|
package/src/amd.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AMD's module forms (references-ts.37), read from the syntax because the binder declares
|
|
3
|
+
* none of them: `define([<ids>], factory)`, `define("<name>", [<ids>], factory)` and
|
|
4
|
+
* `require([<ids>], callback)` (https://github.com/amdjs/amdjs-api/blob/master/AMD.md).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
isArrayLiteralExpression,
|
|
9
|
+
isArrowFunction,
|
|
10
|
+
isFunctionExpression,
|
|
11
|
+
isCallExpression,
|
|
12
|
+
isIdentifier,
|
|
13
|
+
isNoSubstitutionTemplateLiteral,
|
|
14
|
+
isStringLiteral,
|
|
15
|
+
type Identifier,
|
|
16
|
+
type Node,
|
|
17
|
+
type StringLiteralLikeNode,
|
|
18
|
+
} from "@typescript/native/ast";
|
|
19
|
+
import { hasURLScheme, isAbsolutePath, resolvePath, startsRelativePath } from "./paths.ts";
|
|
20
|
+
import { parenthesesRemoved } from "./unwrap.ts";
|
|
21
|
+
|
|
22
|
+
/** The platform function an AMD call is written as. */
|
|
23
|
+
type AmdPlatform = "define" | "require";
|
|
24
|
+
|
|
25
|
+
/** One AMD call's dependency list. */
|
|
26
|
+
export interface AmdLoad {
|
|
27
|
+
/** The name the call is written with; {@link callsPlatform} owns whether it is AMD's. */
|
|
28
|
+
readonly callee: Identifier;
|
|
29
|
+
/** Each dependency id written as literal text, AMD's own `require`, `exports` and `module` left out. */
|
|
30
|
+
readonly ids: readonly AmdDependency[];
|
|
31
|
+
/** Whether the list, or an element of it, is computed, so the call may load any module. */
|
|
32
|
+
readonly computed: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** One dependency id of an AMD call. */
|
|
36
|
+
interface AmdDependency {
|
|
37
|
+
readonly id: StringLiteralLikeNode;
|
|
38
|
+
/**
|
|
39
|
+
* Whether the factory may receive the module's value: it declares a parameter at the id's
|
|
40
|
+
* place, a rest parameter included, or it is written as anything but a function.
|
|
41
|
+
*/
|
|
42
|
+
readonly received: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The ids AMD binds to the factory's CommonJS parameters, which load no module. */
|
|
46
|
+
const FREE_VARIABLES: ReadonlySet<string> = new Set(["require", "exports", "module"]);
|
|
47
|
+
|
|
48
|
+
/** The platform function `callee` is written as. */
|
|
49
|
+
export function amdPlatform(callee: Identifier): AmdPlatform {
|
|
50
|
+
return callee.text === "define" ? "define" : "require";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The dependency list one call writes, where it is a call of a bare `define` or `require` in
|
|
55
|
+
* one of AMD's forms. A `define` with no list, of a factory or a value alone, loads nothing;
|
|
56
|
+
* a `require` whose first argument is no array literal is CommonJS's.
|
|
57
|
+
*/
|
|
58
|
+
export function amdLoadOf(node: Node): AmdLoad | undefined {
|
|
59
|
+
if (!isCallExpression(node)) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const callee = parenthesesRemoved(node.expression);
|
|
63
|
+
if (!isIdentifier(callee) || (callee.text !== "define" && callee.text !== "require")) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const written = node.arguments.map((one) => parenthesesRemoved(one));
|
|
67
|
+
const [first] = written;
|
|
68
|
+
if (first === undefined) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const define = callee.text === "define";
|
|
72
|
+
const named = define && isLiteralText(first);
|
|
73
|
+
const list = written[named ? 1 : 0];
|
|
74
|
+
if (list !== undefined && isArrayLiteralExpression(list)) {
|
|
75
|
+
const elements = list.elements.map((one) => parenthesesRemoved(one));
|
|
76
|
+
const factory = written[named ? 2 : 1];
|
|
77
|
+
const ids = elements.flatMap((one, at) =>
|
|
78
|
+
isLiteralText(one) && !FREE_VARIABLES.has(one.text)
|
|
79
|
+
? [{ id: one, received: receives(factory, at) }]
|
|
80
|
+
: [],
|
|
81
|
+
);
|
|
82
|
+
return { callee, ids, computed: elements.some((one) => !isLiteralText(one)) };
|
|
83
|
+
}
|
|
84
|
+
if (!define) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
// A factory after the list's place makes what stands there a list, here a computed one.
|
|
88
|
+
return { callee, ids: [], computed: written.length > (named ? 2 : 1) };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isLiteralText(node: Node): node is StringLiteralLikeNode {
|
|
92
|
+
return isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Whether a factory may receive the dependency at place `at` of its list. */
|
|
96
|
+
function receives(factory: Node | undefined, at: number): boolean {
|
|
97
|
+
if (factory === undefined) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (!isFunctionExpression(factory) && !isArrowFunction(factory)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
const { parameters } = factory;
|
|
104
|
+
return at < parameters.length || parameters.some((one) => one.dotDotDotToken !== undefined);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The path a dependency id names against the calling file's directory: a relative module id,
|
|
109
|
+
* `./` or `../` with no `.js` ending, with `.js` appended. RequireJS reads any other id
|
|
110
|
+
* through its configuration or as a URL against the page, which the analysis does not know.
|
|
111
|
+
*/
|
|
112
|
+
export function amdPath(dir: string, id: string): string | undefined {
|
|
113
|
+
return startsRelativePath(id) && !id.endsWith(".js") ? resolvePath(dir, `${id}.js`) : undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Whether one call may load a file the analysis cannot name: a computed list, or an id that
|
|
118
|
+
* RequireJS reads as a URL, one ending in `.js`, starting with `/` or carrying a scheme. Any
|
|
119
|
+
* other id {@link amdPath} reads no path from is a package's.
|
|
120
|
+
*/
|
|
121
|
+
export function amdUnresolved(load: AmdLoad): boolean {
|
|
122
|
+
return (
|
|
123
|
+
load.computed ||
|
|
124
|
+
load.ids.some(
|
|
125
|
+
({ id }) =>
|
|
126
|
+
amdPath("/", id.text) === undefined &&
|
|
127
|
+
(id.text.endsWith(".js") || isAbsolutePath(id.text) || hasURLScheme(id.text)),
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
}
|