@cplieger/deadset-ts 6.0.1 → 6.1.1-dev.1
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/configured-declarations.js +7 -5
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/convention-rows.js +67 -1
- package/dist/src/conventions.js +51 -9
- package/dist/src/edges.js +19 -16
- package/dist/src/findings/emitters.js +20 -23
- package/dist/src/inventory.js +6 -1
- package/dist/src/module-declarations.js +3 -3
- package/dist/src/outside-tests.js +5 -11
- package/dist/src/overrides.js +22 -10
- package/dist/src/ref.js +10 -2
- package/dist/src/version.js +1 -1
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/configured-declarations.ts +7 -5
- package/src/conformance-record.ts +2 -2
- package/src/convention-rows.ts +84 -1
- package/src/conventions.ts +77 -9
- package/src/edges.ts +20 -17
- package/src/findings/emitters.ts +28 -44
- package/src/inventory.ts +6 -1
- package/src/module-declarations.ts +3 -3
- package/src/outside-tests.ts +5 -11
- package/src/overrides.ts +26 -11
- package/src/ref.ts +18 -4
- package/src/version.ts +1 -1
|
@@ -143,8 +143,8 @@ function modulesNamed(project, specifiers) {
|
|
|
143
143
|
return modules;
|
|
144
144
|
}
|
|
145
145
|
/**
|
|
146
|
-
* The declaration each entry names in one project. A symbol entry names
|
|
147
|
-
* inventory
|
|
146
|
+
* The declaration each entry names in one project. A symbol entry names every
|
|
147
|
+
* declaration of the inventory whose reference it spells exactly; a module entry names the
|
|
148
148
|
* declaration its path reaches from the exports of the module its specifier resolves
|
|
149
149
|
* to; a global entry names the declaration its path reaches from the global scope.
|
|
150
150
|
* Every alias along a path is followed to the declaration it stands for.
|
|
@@ -153,12 +153,14 @@ export function resolveEntries(project, held, entries) {
|
|
|
153
153
|
if (entries.length === 0) {
|
|
154
154
|
return [];
|
|
155
155
|
}
|
|
156
|
-
const byRef = new Map(
|
|
156
|
+
const byRef = new Map();
|
|
157
|
+
for (const symbol of held.symbols) {
|
|
158
|
+
byRef.set(symbol.ref, [...(byRef.get(symbol.ref) ?? []), symbol.id]);
|
|
159
|
+
}
|
|
157
160
|
const modules = modulesNamed(project, new Set(entries.flatMap((entry) => (entry.shape === "module" ? [entry.module] : []))));
|
|
158
161
|
return entries.map((entry) => {
|
|
159
162
|
if (entry.shape === "symbol") {
|
|
160
|
-
|
|
161
|
-
return { entry, handles: new Set(), ids: new Set(id === undefined ? [] : [id]) };
|
|
163
|
+
return { entry, handles: new Set(), ids: new Set(byRef.get(entry.symbol) ?? []) };
|
|
162
164
|
}
|
|
163
165
|
const { components, static: isStatic } = componentsOf(entry.shape === "module" ? entry.name : entry.global);
|
|
164
166
|
const [first = "", ...rest] = components;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Regenerate it with `UPDATE_GOLDEN=1 npx vitest --run src/conformance.corpus.test.ts`.
|
|
3
3
|
export const RECORD = {
|
|
4
4
|
conformance: {
|
|
5
|
-
corpusVersion: "4.
|
|
5
|
+
corpusVersion: "4.1.0",
|
|
6
6
|
result: "pass",
|
|
7
|
-
digest: "sha256:
|
|
7
|
+
digest: "sha256:167f770cdff2776fa7ab28b7ff6121c4d7bdb01d83c5ba0057d9303281614008",
|
|
8
8
|
},
|
|
9
9
|
gaps: [],
|
|
10
10
|
};
|
|
@@ -31,6 +31,11 @@ const APP_DIRECTORY_ENTRIES = [
|
|
|
31
31
|
];
|
|
32
32
|
const SOLIDSTART_PLUGIN = { module: "@solidjs/start/config", export: "solidStart" };
|
|
33
33
|
const NUXT_CONFIG = [`nuxt.config.${ANY_MODULE}`];
|
|
34
|
+
const BABEL_CONFIG = [
|
|
35
|
+
"babel.config.{json,js,cjs,mjs,cts,mts,ts}",
|
|
36
|
+
".babelrc",
|
|
37
|
+
".babelrc.{json,js,cjs,mjs,cts}",
|
|
38
|
+
];
|
|
34
39
|
const STRYKER_CONFIG = "{stryker,.stryker}.{conf,config}.{json,js,mjs,cjs}";
|
|
35
40
|
const STRYKER_MODULE = "{stryker,.stryker}.{conf,config}.{js,mjs,cjs}";
|
|
36
41
|
const VITEST_CONFIG = `{vitest,vite}.config.${ANY_MODULE}`;
|
|
@@ -57,6 +62,19 @@ export const CONVENTION_ROWS = [
|
|
|
57
62
|
},
|
|
58
63
|
],
|
|
59
64
|
},
|
|
65
|
+
{
|
|
66
|
+
name: "babel",
|
|
67
|
+
package: "@babel/core",
|
|
68
|
+
range: ">=7.0.0 <9.0.0",
|
|
69
|
+
entries: [],
|
|
70
|
+
moves: [],
|
|
71
|
+
helpers: ["@babel/plugin-transform-runtime", "@babel/transform-runtime"].map((value) => ({
|
|
72
|
+
property: "plugins",
|
|
73
|
+
files: BABEL_CONFIG,
|
|
74
|
+
value,
|
|
75
|
+
package: "@babel/runtime",
|
|
76
|
+
})),
|
|
77
|
+
},
|
|
60
78
|
{
|
|
61
79
|
name: "eslint",
|
|
62
80
|
package: "eslint",
|
|
@@ -229,6 +247,21 @@ export const CONVENTION_ROWS = [
|
|
|
229
247
|
},
|
|
230
248
|
],
|
|
231
249
|
},
|
|
250
|
+
{
|
|
251
|
+
name: "rolldown",
|
|
252
|
+
package: "rolldown",
|
|
253
|
+
range: ">=1.0.0 <2.0.0",
|
|
254
|
+
entries: [],
|
|
255
|
+
moves: [],
|
|
256
|
+
helpers: [
|
|
257
|
+
{
|
|
258
|
+
property: "transform.helpers.mode",
|
|
259
|
+
files: [`rolldown.config.${ANY_MODULE}`],
|
|
260
|
+
value: "Runtime",
|
|
261
|
+
package: "@oxc-project/runtime",
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
232
265
|
{
|
|
233
266
|
name: "solidstart",
|
|
234
267
|
package: "@solidjs/start",
|
|
@@ -275,7 +308,10 @@ export const CONVENTION_ROWS = [
|
|
|
275
308
|
range: ">=7.0.0 <11.0.0",
|
|
276
309
|
entries: [STRYKER_MODULE],
|
|
277
310
|
moves: [],
|
|
278
|
-
selections: [
|
|
311
|
+
selections: [
|
|
312
|
+
{ property: "mutate", files: [STRYKER_CONFIG] },
|
|
313
|
+
{ property: "ignorePatterns", files: [STRYKER_CONFIG] },
|
|
314
|
+
],
|
|
279
315
|
shortNames: [
|
|
280
316
|
{
|
|
281
317
|
property: "testRunner",
|
|
@@ -406,6 +442,36 @@ export const CONVENTION_ROWS = [
|
|
|
406
442
|
},
|
|
407
443
|
],
|
|
408
444
|
},
|
|
445
|
+
{
|
|
446
|
+
name: "swc",
|
|
447
|
+
package: "@swc/core",
|
|
448
|
+
range: ">=1.0.0 <2.0.0",
|
|
449
|
+
entries: [],
|
|
450
|
+
moves: [],
|
|
451
|
+
helpers: [
|
|
452
|
+
{
|
|
453
|
+
property: "jsc.externalHelpers",
|
|
454
|
+
files: [".swcrc"],
|
|
455
|
+
value: true,
|
|
456
|
+
package: "@swc/helpers",
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: "vite",
|
|
462
|
+
package: "vite",
|
|
463
|
+
range: ">=8.0.0 <9.0.0",
|
|
464
|
+
entries: [],
|
|
465
|
+
moves: [],
|
|
466
|
+
helpers: [
|
|
467
|
+
{
|
|
468
|
+
property: "oxc.helpers.mode",
|
|
469
|
+
files: [VITE_CONFIG],
|
|
470
|
+
value: "Runtime",
|
|
471
|
+
package: "@oxc-project/runtime",
|
|
472
|
+
},
|
|
473
|
+
],
|
|
474
|
+
},
|
|
409
475
|
{
|
|
410
476
|
name: "vitest",
|
|
411
477
|
package: "vitest",
|
package/dist/src/conventions.js
CHANGED
|
@@ -13,6 +13,8 @@ import { globExpression } from "./glob.js";
|
|
|
13
13
|
import { dirnamePath, joinPath, normalizePath, relativePath, resolvePath } from "./paths.js";
|
|
14
14
|
import { satisfies } from "./version-range.js";
|
|
15
15
|
const JSON_EXTENSION = ".json";
|
|
16
|
+
/** A configuration file with no extension that its tool reads as a JSON document. */
|
|
17
|
+
const JSON_RC = /^\.[\w-]+rc$/u;
|
|
16
18
|
/** The sections an installed package is required by, so its absence fails the run. */
|
|
17
19
|
const REQUIRED_SECTIONS = ["dependencies", "devDependencies"];
|
|
18
20
|
const DEPENDENCY_SECTIONS = [
|
|
@@ -351,11 +353,10 @@ function readPath(object, keys, values, elements) {
|
|
|
351
353
|
return undefined;
|
|
352
354
|
}
|
|
353
355
|
/**
|
|
354
|
-
* Every
|
|
355
|
-
*
|
|
356
|
-
* array value, whatever else the path holds.
|
|
356
|
+
* Every value one file writes at one property's path inside the objects it is read from,
|
|
357
|
+
* as {@link readProperty} reads them, whatever else the path holds.
|
|
357
358
|
*/
|
|
358
|
-
function
|
|
359
|
+
function valuesAt(file, property, call) {
|
|
359
360
|
const declared = declaredValues(file);
|
|
360
361
|
const objects = call === undefined
|
|
361
362
|
? defaultExports(file).map((one) => objectOf(one, declared, true))
|
|
@@ -374,12 +375,9 @@ function stringsAt(file, property, call) {
|
|
|
374
375
|
if (rest.length > 0) {
|
|
375
376
|
visit(held, rest);
|
|
376
377
|
}
|
|
377
|
-
else
|
|
378
|
+
else {
|
|
378
379
|
found.push(held);
|
|
379
380
|
}
|
|
380
|
-
else if (isArrayLiteralExpression(held)) {
|
|
381
|
-
found.push(...held.elements.map(unwrapped).filter((one) => literalText(one) !== undefined));
|
|
382
|
-
}
|
|
383
381
|
}
|
|
384
382
|
};
|
|
385
383
|
for (const object of objects) {
|
|
@@ -389,6 +387,32 @@ function stringsAt(file, property, call) {
|
|
|
389
387
|
}
|
|
390
388
|
return found;
|
|
391
389
|
}
|
|
390
|
+
/** The string literals among values: each value itself, or each element of an array value. */
|
|
391
|
+
function stringsAt(file, property, call) {
|
|
392
|
+
return valuesAt(file, property, call).flatMap((held) => {
|
|
393
|
+
if (literalText(held) !== undefined) {
|
|
394
|
+
return [held];
|
|
395
|
+
}
|
|
396
|
+
return isArrayLiteralExpression(held)
|
|
397
|
+
? held.elements.map(unwrapped).filter((one) => literalText(one) !== undefined)
|
|
398
|
+
: [];
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
/** Whether one value holds a helper setting's value, as {@link HelperReading} states it. */
|
|
402
|
+
function holdsValue(held, value) {
|
|
403
|
+
if (value === true) {
|
|
404
|
+
return held.kind === SyntaxKind.TrueKeyword;
|
|
405
|
+
}
|
|
406
|
+
if (literalText(held) === value) {
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
return (isArrayLiteralExpression(held) &&
|
|
410
|
+
held.elements.some((element) => {
|
|
411
|
+
const one = unwrapped(element);
|
|
412
|
+
const first = isArrayLiteralExpression(one) ? one.elements[0] : one;
|
|
413
|
+
return first !== undefined && literalText(first) === value;
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
392
416
|
/** The strings an applied row's selection keys hold, added per configuration file to `into`. */
|
|
393
417
|
function selectedStrings(host, parse, dir, readings, into) {
|
|
394
418
|
for (const reading of readings) {
|
|
@@ -527,7 +551,11 @@ function readingFiles(host, parse, dir, files) {
|
|
|
527
551
|
catch {
|
|
528
552
|
continue;
|
|
529
553
|
}
|
|
530
|
-
found.push({
|
|
554
|
+
found.push({
|
|
555
|
+
name,
|
|
556
|
+
text,
|
|
557
|
+
file: parse(JSON_RC.test(name) ? `${path}${JSON_EXTENSION}` : path, text),
|
|
558
|
+
});
|
|
531
559
|
}
|
|
532
560
|
}
|
|
533
561
|
return found;
|
|
@@ -563,6 +591,17 @@ function shortNameUses(host, parse, dir, manifest, readings) {
|
|
|
563
591
|
}
|
|
564
592
|
return [...used].filter((name) => declared.has(name)).sort(compare);
|
|
565
593
|
}
|
|
594
|
+
/** The declared dependencies an applied row's helper settings use. */
|
|
595
|
+
function helperUses(host, parse, dir, manifest, readings) {
|
|
596
|
+
const declared = new Set(DEPENDENCY_SECTIONS.flatMap((section) => {
|
|
597
|
+
const held = isRecord(manifest) ? manifest[section] : undefined;
|
|
598
|
+
return isRecord(held) ? Object.keys(held) : [];
|
|
599
|
+
}));
|
|
600
|
+
return readings
|
|
601
|
+
.filter((reading) => declared.has(reading.package) &&
|
|
602
|
+
readingFiles(host, parse, dir, reading.files).some(({ file }) => valuesAt(file, reading.property, reading.call).some((held) => holdsValue(held, reading.value))))
|
|
603
|
+
.map((reading) => reading.package);
|
|
604
|
+
}
|
|
566
605
|
/** Two strings ordered bytewise. */
|
|
567
606
|
function compare(a, b) {
|
|
568
607
|
if (a === b) {
|
|
@@ -644,6 +683,9 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
|
|
|
644
683
|
for (const name of manifestKeyUses(declared, row.manifestKeys ?? [])) {
|
|
645
684
|
uses.add(name);
|
|
646
685
|
}
|
|
686
|
+
for (const name of helperUses(host, parse, manifest.dir, declared, row.helpers ?? [])) {
|
|
687
|
+
uses.add(name);
|
|
688
|
+
}
|
|
647
689
|
selectedStrings(host, parse, manifest.dir, row.selections ?? [], selected);
|
|
648
690
|
const excludes = [
|
|
649
691
|
...new Set((row.excludes ?? []).flatMap((one) => expand(one, resolved))),
|
package/dist/src/edges.js
CHANGED
|
@@ -154,9 +154,10 @@ function compare(a, b) {
|
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
156
|
* Evaluates every declared side of this language over the run's findings. A side naming a
|
|
157
|
-
* symbol the run enumerates nothing under is `absent`;
|
|
158
|
-
*
|
|
159
|
-
*
|
|
157
|
+
* symbol the run enumerates nothing under is `absent`; otherwise it is evaluated once per
|
|
158
|
+
* declaration its reference spells. A declaration the run holds a finding about is `dead`
|
|
159
|
+
* and carries that finding, pending until a merge reads the other side and reported
|
|
160
|
+
* nowhere else, a narrowing finding included; any other is `live`.
|
|
160
161
|
*/
|
|
161
162
|
export function evaluateEdges(findings, sides, symbols) {
|
|
162
163
|
if (sides.length === 0) {
|
|
@@ -164,8 +165,8 @@ export function evaluateEdges(findings, sides, symbols) {
|
|
|
164
165
|
}
|
|
165
166
|
const byRef = new Map();
|
|
166
167
|
for (const symbol of symbols) {
|
|
167
|
-
if (symbol.kind !== "file"
|
|
168
|
-
byRef.set(symbol.ref, symbol.id);
|
|
168
|
+
if (symbol.kind !== "file") {
|
|
169
|
+
byRef.set(symbol.ref, [...(byRef.get(symbol.ref) ?? []), symbol.id]);
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
const held = new Map();
|
|
@@ -175,18 +176,20 @@ export function evaluateEdges(findings, sides, symbols) {
|
|
|
175
176
|
}
|
|
176
177
|
});
|
|
177
178
|
const pending = new Set();
|
|
178
|
-
const evaluations = sides.
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
return { ...side, state: "absent" };
|
|
179
|
+
const evaluations = sides.flatMap((side) => {
|
|
180
|
+
const ids = byRef.get(side.symbol);
|
|
181
|
+
if (ids === undefined) {
|
|
182
|
+
return [{ ...side, state: "absent" }];
|
|
182
183
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
184
|
+
return ids.map((id) => {
|
|
185
|
+
const at = held.get(id);
|
|
186
|
+
const finding = at === undefined ? undefined : findings[at];
|
|
187
|
+
if (at === undefined || finding === undefined) {
|
|
188
|
+
return { ...side, state: "live" };
|
|
189
|
+
}
|
|
190
|
+
pending.add(at);
|
|
191
|
+
return { ...side, state: "dead", finding };
|
|
192
|
+
});
|
|
190
193
|
});
|
|
191
194
|
evaluations.sort((a, b) => compare(a.edge, b.edge) || compare(a.side, b.side));
|
|
192
195
|
return { findings: findings.filter((_finding, at) => !pending.has(at)), evaluations };
|
|
@@ -73,21 +73,13 @@ function dialsOver(input, found, suppressed, unmarked) {
|
|
|
73
73
|
* family's findings completed by one step, so every component number is minted once, the
|
|
74
74
|
* finding each record claims withheld, the rest withheld by the dials, so a root one family
|
|
75
75
|
* reports withholds what another reports in its component, and every declared edge
|
|
76
|
-
* evaluated over what remains, so a pending finding is in its evaluation alone.
|
|
77
|
-
* minimum confidence withheld is what the same decision at the lowest minimum adds.
|
|
76
|
+
* evaluated over what remains, so a pending finding is in its evaluation alone.
|
|
78
77
|
*/
|
|
79
78
|
export function decidedFindings(input, suppressed = { unmarked: input, records: [] }) {
|
|
80
79
|
const found = completedOver(input);
|
|
81
80
|
const unmarked = suppressed.records.length === 0 ? [] : completedOver(suppressed.unmarked, fallenMembers);
|
|
82
81
|
const would = [...unmarked, ...found];
|
|
83
|
-
|
|
84
|
-
const shown = input.config.analysis.minConfidence === "possible"
|
|
85
|
-
? decided
|
|
86
|
-
: dialledOver(atPossible(input), {
|
|
87
|
-
unmarked: atPossible(suppressed.unmarked),
|
|
88
|
-
records: suppressed.records,
|
|
89
|
-
}, found, unmarked);
|
|
90
|
-
return { ...decided, would, withheld: withheldOf(decided.findings, shown.findings) };
|
|
82
|
+
return { ...dialledOver(input, suppressed, found, unmarked), would };
|
|
91
83
|
}
|
|
92
84
|
/** The run's input with the minimum confidence at its lowest, which withholds nothing. */
|
|
93
85
|
function atPossible(input) {
|
|
@@ -107,32 +99,37 @@ function dialledOver(input, suppressed, found, unmarked) {
|
|
|
107
99
|
const ledger = ledgerOf(suppressed.records, would, dialsOver(input, found, suppressed, unmarked));
|
|
108
100
|
const unanswered = heldKeys(input);
|
|
109
101
|
const markup = markupKeys(input);
|
|
110
|
-
const
|
|
102
|
+
const candidates = found.filter((finding) => {
|
|
111
103
|
const key = declarationKey(finding.symbol.ref, finding.position.path);
|
|
112
104
|
return (!ledger.withheld(finding) &&
|
|
113
105
|
!unanswered.has(key) &&
|
|
114
106
|
!markup.has(key) &&
|
|
115
107
|
!insideSkipped(input.swept.skipped, finding.position));
|
|
116
|
-
})
|
|
108
|
+
});
|
|
109
|
+
const kept = reportable(input, candidates);
|
|
117
110
|
const evaluated = evaluateEdges(kept, input.boundary.edges, input.swept.matrix.union.symbols);
|
|
118
|
-
return {
|
|
111
|
+
return {
|
|
112
|
+
findings: evaluated.findings,
|
|
113
|
+
evaluations: evaluated.evaluations,
|
|
114
|
+
ledger,
|
|
115
|
+
withheld: withheldOf(input, candidates),
|
|
116
|
+
};
|
|
119
117
|
}
|
|
120
|
-
/**
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
/**
|
|
119
|
+
* The findings the dials withhold only because their confidence is below the minimum, each
|
|
120
|
+
* counted at the confidence this run gives it: the dials at the lowest minimum keep them.
|
|
121
|
+
*/
|
|
122
|
+
function withheldOf(input, candidates) {
|
|
123
|
+
const dials = dialsOf(input, candidates);
|
|
124
|
+
const lowest = dialsOf(atPossible(input), candidates);
|
|
123
125
|
const counts = { certain: 0, probable: 0, possible: 0 };
|
|
124
|
-
for (const finding of
|
|
125
|
-
if (!
|
|
126
|
+
for (const finding of candidates) {
|
|
127
|
+
if (dials.withholds(finding) && !lowest.withholds(finding)) {
|
|
126
128
|
counts[finding.confidence] += 1;
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
return counts;
|
|
130
132
|
}
|
|
131
|
-
/** A finding's identity across two decisions of one run: its position, code and subject. */
|
|
132
|
-
function findingKey(finding) {
|
|
133
|
-
const { path, line, column } = finding.position;
|
|
134
|
-
return JSON.stringify([path, line, column, finding.code, finding.symbol.ref]);
|
|
135
|
-
}
|
|
136
133
|
/** Every finding the run reports, each family's in table order. */
|
|
137
134
|
export function findingsOf(input) {
|
|
138
135
|
return decidedFindings(input).findings;
|
package/dist/src/inventory.js
CHANGED
|
@@ -787,7 +787,12 @@ function refOf(record, chain) {
|
|
|
787
787
|
return renderRef(record.module, { of: "module" });
|
|
788
788
|
}
|
|
789
789
|
if (record.kind === "export-alias") {
|
|
790
|
-
|
|
790
|
+
const block = record.parentChain.at(-1);
|
|
791
|
+
return renderRef(record.module, {
|
|
792
|
+
of: "alias",
|
|
793
|
+
name: record.component.text,
|
|
794
|
+
...(block === undefined ? {} : { block: block.text }),
|
|
795
|
+
});
|
|
791
796
|
}
|
|
792
797
|
return renderRef(record.module, {
|
|
793
798
|
of: "declaration",
|
|
@@ -9,7 +9,7 @@ import { isCallExpression, isExportDeclaration, isExternalModuleReference, isImp
|
|
|
9
9
|
import { nodeKey } from "./inventory.js";
|
|
10
10
|
import { renderPosition } from "./position.js";
|
|
11
11
|
import { UNANSWERED } from "./query.js";
|
|
12
|
-
import { nameComponent } from "./ref.js";
|
|
12
|
+
import { aliasFragment, nameComponent } from "./ref.js";
|
|
13
13
|
/** Whether a node is a specifier's text: a string literal or a template with no substitution. */
|
|
14
14
|
function literalText(node) {
|
|
15
15
|
return node !== undefined && (isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node));
|
|
@@ -78,7 +78,7 @@ function namesModule(specifier, name) {
|
|
|
78
78
|
* The module declarations of an inventory a specifier names by name or pattern, each with
|
|
79
79
|
* the members that hold the export names given.
|
|
80
80
|
*/
|
|
81
|
-
|
|
81
|
+
function namedBy(held) {
|
|
82
82
|
if (held.modules.size === 0) {
|
|
83
83
|
return () => [];
|
|
84
84
|
}
|
|
@@ -103,7 +103,7 @@ export function namedBy(held) {
|
|
|
103
103
|
const scope = ref.slice(0, ref.indexOf("#"));
|
|
104
104
|
const wanted = new Set(names.flatMap((one) => [
|
|
105
105
|
`${ref}.${nameComponent(one)}`,
|
|
106
|
-
`${scope}#${
|
|
106
|
+
`${scope}#${aliasFragment(one, name)}`,
|
|
107
107
|
]));
|
|
108
108
|
const members = (children.get(id) ?? []).filter((child) => wanted.has(child.ref));
|
|
109
109
|
return [{ id, members: members.map((child) => child.id) }];
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The test files no compiler configuration of a run holds. The runner executes them all
|
|
3
3
|
* the same, so each module one names is a test reference: the own file a relative
|
|
4
|
-
* specifier names, and the declarations that file exports under the names read from it
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* specifier names, and the declarations that file exports under the names read from it.
|
|
5
|
+
* No compiler run reads a module declaration for such a file, so its imports name none.
|
|
6
|
+
* Such a file is read without a program, so what its body references beyond the modules
|
|
7
|
+
* it names is not known.
|
|
8
8
|
*/
|
|
9
9
|
import { isCallExpression, isExportDeclaration, isImportDeclaration, isNamespaceExport, isNamespaceImport, isNoSubstitutionTemplateLiteral, isStringLiteral, SyntaxKind, } from "@typescript/native/unstable/ast";
|
|
10
10
|
import { RESOLVED_EXTENSIONS } from "./configuration-files.js";
|
|
11
11
|
import { emittedFrom } from "./emit-map.js";
|
|
12
|
-
import {
|
|
12
|
+
import { namesImported } from "./module-declarations.js";
|
|
13
13
|
import { dirnamePath, joinPath, normalizePath, queriedModulePath } from "./paths.js";
|
|
14
14
|
import { renderPosition } from "./position.js";
|
|
15
15
|
import { nameComponent } from "./ref.js";
|
|
@@ -102,7 +102,6 @@ export function outsideTestReferences(tests, held, targetRoot) {
|
|
|
102
102
|
exported.set(key, [...(exported.get(key) ?? []), symbol.id]);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
const declared = namedBy(held);
|
|
106
105
|
const found = [];
|
|
107
106
|
for (const { path, file } of tests) {
|
|
108
107
|
const from = `${path}#`;
|
|
@@ -112,11 +111,6 @@ export function outsideTestReferences(tests, held, targetRoot) {
|
|
|
112
111
|
const read = (to, use) => {
|
|
113
112
|
found.push({ from, to, position, use, resolution: "syntax", test: true, unheld: true });
|
|
114
113
|
};
|
|
115
|
-
for (const declaration of declared(named.text, named.names)) {
|
|
116
|
-
for (const to of [declaration.id, ...declaration.members]) {
|
|
117
|
-
read(to, "read");
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
114
|
const written = named.text.includes("?") ? queriedModulePath(named.text) : named.text;
|
|
121
115
|
if (written === undefined) {
|
|
122
116
|
continue;
|
package/dist/src/overrides.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The overrides of the target's class members. A call through the base class names the
|
|
3
3
|
* base's member and runs the override of whichever subclass the value is, so the base
|
|
4
|
-
* member's declaration references every override. A method
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* member's declaration references every override. A method, an accessor or a property,
|
|
5
|
+
* static or not, overriding a member of a class declared outside the target, at any depth
|
|
6
|
+
* of its `extends` chain, is used by outside code holding the instance or the class
|
|
7
|
+
* through that class, so its own class references it.
|
|
7
8
|
*/
|
|
8
9
|
import { isClassDeclaration, isClassExpression, isExpressionWithTypeArguments, isPropertyAccessExpression, isQualifiedName, SyntaxKind, } from "@typescript/native/unstable/ast";
|
|
9
10
|
import { memberComponent } from "./class-members.js";
|
|
10
11
|
import { nodeKey } from "./inventory.js";
|
|
11
12
|
import { SymbolFlags } from "@typescript/native/unstable/sync";
|
|
12
13
|
import { UNANSWERED } from "./query.js";
|
|
14
|
+
import { nameComponent } from "./ref.js";
|
|
13
15
|
/** The member kinds a subclass overrides. */
|
|
14
16
|
const OVERRIDABLE = new Set(["method", "class-member"]);
|
|
15
17
|
/** The node naming the class one `extends` entry names. */
|
|
@@ -40,7 +42,7 @@ function extending(project, held) {
|
|
|
40
42
|
}
|
|
41
43
|
/**
|
|
42
44
|
* The references each base class member makes to its overrides, for the classes of one
|
|
43
|
-
* project that extend another class of the target, and each class makes to its
|
|
45
|
+
* project that extend another class of the target, and each class makes to its members
|
|
44
46
|
* that override a member of a class declared outside the target. A member a nearer base
|
|
45
47
|
* already overrides is reached through that override. A private member is not
|
|
46
48
|
* overridden. Each reference is placed at the override and made by its file.
|
|
@@ -102,7 +104,7 @@ export function overrideReferences(project, held, chains, testFiles) {
|
|
|
102
104
|
const outsideNames = outsideMemberNames(project, bases, outsideBases);
|
|
103
105
|
for (const [classId, names] of outsideNames) {
|
|
104
106
|
for (const [component, member] of members.get(classId) ?? []) {
|
|
105
|
-
if (
|
|
107
|
+
if (names.has(component)) {
|
|
106
108
|
found.push({
|
|
107
109
|
from: classId,
|
|
108
110
|
to: member.id,
|
|
@@ -133,15 +135,20 @@ export function overrideReferences(project, held, chains, testFiles) {
|
|
|
133
135
|
}
|
|
134
136
|
/**
|
|
135
137
|
* Per class of the target with a class declared outside the target in its `extends`
|
|
136
|
-
* chain, the
|
|
138
|
+
* chain, the member components that outside class's instances and constructor carry, a
|
|
139
|
+
* static one spelled as a static member's component is.
|
|
137
140
|
*/
|
|
138
141
|
function outsideMemberNames(project, bases, outsideBases) {
|
|
139
142
|
const direct = new Map();
|
|
140
143
|
for (const [classId, base] of outsideBases) {
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
const instance = project.queries.declaredTypeOf(base);
|
|
145
|
+
const statics = project.queries.typeOfSymbol(base);
|
|
146
|
+
const components = [
|
|
147
|
+
...namesOf(project, instance === UNANSWERED ? undefined : instance).map(nameComponent),
|
|
148
|
+
...namesOf(project, statics === UNANSWERED ? undefined : statics).map((name) => `${nameComponent(name)}:static`),
|
|
149
|
+
];
|
|
150
|
+
if (components.length > 0) {
|
|
151
|
+
direct.set(classId, new Set(components));
|
|
145
152
|
}
|
|
146
153
|
}
|
|
147
154
|
const names = new Map();
|
|
@@ -163,3 +170,8 @@ function outsideMemberNames(project, bases, outsideBases) {
|
|
|
163
170
|
}
|
|
164
171
|
return names;
|
|
165
172
|
}
|
|
173
|
+
/** The names of a type's properties; none where the type or its properties are unanswered. */
|
|
174
|
+
function namesOf(project, type) {
|
|
175
|
+
const properties = type === undefined ? UNANSWERED : project.queries.propertiesOf(type);
|
|
176
|
+
return properties === UNANSWERED ? [] : properties.map((property) => property.name);
|
|
177
|
+
}
|
package/dist/src/ref.js
CHANGED
|
@@ -43,7 +43,7 @@ const MANIFEST_SCOPE = `${PREFIX}${TS_PACKAGE}/package\\.json`;
|
|
|
43
43
|
export const REF_EXPRESSIONS = [
|
|
44
44
|
`^${SCOPE}#$`,
|
|
45
45
|
`^${SCOPE}#${TS_HEAD}$`,
|
|
46
|
-
`^${SCOPE}
|
|
46
|
+
`^${SCOPE}#(?:${TS_QUOTED}\\.)?${TS_HEAD}:alias$`,
|
|
47
47
|
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})+$`,
|
|
48
48
|
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})+:static$`,
|
|
49
49
|
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})*(?::static)?<${TS_IDENT}>$`,
|
|
@@ -66,6 +66,9 @@ export function nameComponent(name) {
|
|
|
66
66
|
if (IDENTIFIER.test(name) || PRIVATE_NAME.test(name)) {
|
|
67
67
|
return name;
|
|
68
68
|
}
|
|
69
|
+
return quoted(name);
|
|
70
|
+
}
|
|
71
|
+
function quoted(name) {
|
|
69
72
|
const escaped = name
|
|
70
73
|
.replaceAll("\\", "\\\\")
|
|
71
74
|
.replaceAll("'", "\\'")
|
|
@@ -82,6 +85,11 @@ export function nameComponent(name) {
|
|
|
82
85
|
export function computedComponent(text) {
|
|
83
86
|
return `[${text.replaceAll(ASCII_WHITESPACE, "")}]`;
|
|
84
87
|
}
|
|
88
|
+
/** The fragment of an export alias, inside the `declare module` block named, if one is. */
|
|
89
|
+
export function aliasFragment(name, block) {
|
|
90
|
+
const head = block === undefined ? "" : `${quoted(block)}.`;
|
|
91
|
+
return `${head}${nameComponent(name)}:alias`;
|
|
92
|
+
}
|
|
85
93
|
function spell(component) {
|
|
86
94
|
return component.computed ? computedComponent(component.text) : nameComponent(component.text);
|
|
87
95
|
}
|
|
@@ -96,7 +104,7 @@ export function renderRef(module, fragment) {
|
|
|
96
104
|
case "module":
|
|
97
105
|
return `${scope}#`;
|
|
98
106
|
case "alias":
|
|
99
|
-
return `${scope}#${
|
|
107
|
+
return `${scope}#${aliasFragment(fragment.name, fragment.block)}`;
|
|
100
108
|
case "dependency":
|
|
101
109
|
return `${scope}#${fragment.name}:${fragment.section}`;
|
|
102
110
|
case "declaration": {
|
package/dist/src/version.js
CHANGED
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -207,8 +207,8 @@ function modulesNamed<Brand>(
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
210
|
-
* The declaration each entry names in one project. A symbol entry names
|
|
211
|
-
* inventory
|
|
210
|
+
* The declaration each entry names in one project. A symbol entry names every
|
|
211
|
+
* declaration of the inventory whose reference it spells exactly; a module entry names the
|
|
212
212
|
* declaration its path reaches from the exports of the module its specifier resolves
|
|
213
213
|
* to; a global entry names the declaration its path reaches from the global scope.
|
|
214
214
|
* Every alias along a path is followed to the declaration it stands for.
|
|
@@ -221,15 +221,17 @@ export function resolveEntries<Brand>(
|
|
|
221
221
|
if (entries.length === 0) {
|
|
222
222
|
return [];
|
|
223
223
|
}
|
|
224
|
-
const byRef = new Map
|
|
224
|
+
const byRef = new Map<string, string[]>();
|
|
225
|
+
for (const symbol of held.symbols) {
|
|
226
|
+
byRef.set(symbol.ref, [...(byRef.get(symbol.ref) ?? []), symbol.id]);
|
|
227
|
+
}
|
|
225
228
|
const modules = modulesNamed(
|
|
226
229
|
project,
|
|
227
230
|
new Set(entries.flatMap((entry) => (entry.shape === "module" ? [entry.module] : []))),
|
|
228
231
|
);
|
|
229
232
|
return entries.map((entry) => {
|
|
230
233
|
if (entry.shape === "symbol") {
|
|
231
|
-
|
|
232
|
-
return { entry, handles: new Set<string>(), ids: new Set(id === undefined ? [] : [id]) };
|
|
234
|
+
return { entry, handles: new Set<string>(), ids: new Set(byRef.get(entry.symbol) ?? []) };
|
|
233
235
|
}
|
|
234
236
|
const { components, static: isStatic } = componentsOf(
|
|
235
237
|
entry.shape === "module" ? entry.name : entry.global,
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Regenerate it with `UPDATE_GOLDEN=1 npx vitest --run src/conformance.corpus.test.ts`.
|
|
3
3
|
export const RECORD = {
|
|
4
4
|
conformance: {
|
|
5
|
-
corpusVersion: "4.
|
|
5
|
+
corpusVersion: "4.1.0",
|
|
6
6
|
result: "pass",
|
|
7
|
-
digest: "sha256:
|
|
7
|
+
digest: "sha256:167f770cdff2776fa7ab28b7ff6121c4d7bdb01d83c5ba0057d9303281614008",
|
|
8
8
|
},
|
|
9
9
|
gaps: [],
|
|
10
10
|
} as const;
|