@cplieger/deadset-ts 2.3.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -16
- package/dist/src/alias-chain.js +96 -0
- package/dist/src/analysis.js +50 -16
- package/dist/src/components.js +289 -0
- package/dist/src/discover.js +98 -24
- package/dist/src/graph.js +120 -0
- package/dist/src/index.js +0 -2
- package/dist/src/matrix.js +138 -0
- package/dist/src/print.js +3 -6
- package/dist/src/references.js +162 -79
- package/dist/src/resolve.js +82 -20
- package/dist/src/roots.js +14 -37
- package/dist/src/run.js +11 -7
- package/dist/src/schema.js +1 -1
- package/dist/src/session.js +16 -5
- package/dist/src/sweep.js +152 -0
- package/dist/src/version.js +1 -1
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/alias-chain.ts +135 -0
- package/src/analysis.ts +85 -24
- package/src/components.ts +372 -0
- package/src/config.ts +23 -2
- package/src/discover.ts +144 -29
- package/src/graph.ts +187 -0
- package/src/index.ts +0 -20
- package/src/matrix.ts +212 -0
- package/src/print.ts +5 -6
- package/src/references.ts +235 -93
- package/src/resolve.ts +117 -24
- package/src/roots.ts +15 -46
- package/src/run.ts +11 -7
- package/src/schema.ts +5 -2
- package/src/session.ts +18 -5
- package/src/sweep.ts +224 -0
- package/src/version.ts +1 -1
package/dist/src/discover.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DiagnosticCategory } from "@typescript/native/unstable/sync";
|
|
2
|
-
import { dirnamePath, isAbsolutePath, joinPath, resolvePath } from "./paths.js";
|
|
2
|
+
import { dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
3
3
|
/** Directory names discovery does not descend into. */
|
|
4
4
|
const IGNORED_DIRECTORIES = new Set(["node_modules", ".git"]);
|
|
5
5
|
/** A compiler configuration file discovery recognises under a root. */
|
|
@@ -128,24 +128,77 @@ function scopeConfigFiles(host, scope) {
|
|
|
128
128
|
.map((path) => resolvePath(host.workingDirectory(), path));
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
131
|
+
* The name a derived project carries: its configuration file's path below the target
|
|
132
|
+
* root, or the absolute path of a file outside it.
|
|
133
|
+
*/
|
|
134
|
+
function derivedId(targetRoot, configFile) {
|
|
135
|
+
return relativePath(targetRoot, configFile) ?? configFile;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Resolves one compiler configuration file, or ends the run naming it: a project
|
|
139
|
+
* opened from a configuration the compiler cannot read would be analyzed with no
|
|
140
|
+
* type information.
|
|
141
|
+
*/
|
|
142
|
+
function parseOrRefuse(engine, configFile, named) {
|
|
143
|
+
try {
|
|
144
|
+
engine.parseConfigFile(configFile);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
throw new DiscoveryError(`${named} cannot be read as a compiler configuration: ` +
|
|
148
|
+
(error instanceof Error ? error.message : String(error)), []);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The projects a build matrix declares, in the order it lists them. Each entry
|
|
153
|
+
* names a file below the target root, and an entry naming a file that is absent,
|
|
154
|
+
* that is a directory, or that the compiler cannot read ends the run naming it.
|
|
141
155
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
156
|
+
* A declared project's `references` are not followed, because the entries are the
|
|
157
|
+
* matrix, and a reference to a configuration the matrix does not name ends the run
|
|
158
|
+
* naming both: the compiler builds a referenced project's sources into the program
|
|
159
|
+
* that references it without reporting their diagnostics, so the project the matrix
|
|
160
|
+
* left out would be analyzed with its errors unread. An entry naming a file an
|
|
161
|
+
* earlier entry named adds nothing, so the earlier identifier stands.
|
|
162
|
+
*/
|
|
163
|
+
function declaredProjects(engine, host, targetRoot, entries) {
|
|
164
|
+
const seen = new Set();
|
|
165
|
+
const projects = [];
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
const configFile = joinPath(targetRoot, entry.project);
|
|
168
|
+
const named = `the project ${JSON.stringify(entry.id)} (${configFile})`;
|
|
169
|
+
const kind = host.kindOf(configFile);
|
|
170
|
+
if (kind !== "file") {
|
|
171
|
+
throw new DiscoveryError(kind === "absent"
|
|
172
|
+
? `${named} does not exist`
|
|
173
|
+
: `${named} is a directory, and a project names its compiler configuration file`, []);
|
|
174
|
+
}
|
|
175
|
+
if (seen.has(configFile)) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
seen.add(configFile);
|
|
179
|
+
parseOrRefuse(engine, configFile, named);
|
|
180
|
+
projects.push({ id: entry.id, configFile });
|
|
181
|
+
}
|
|
182
|
+
for (const project of projects) {
|
|
183
|
+
const unnamed = referencesOf(host, project.configFile).find((path) => !seen.has(path));
|
|
184
|
+
if (unnamed !== undefined) {
|
|
185
|
+
throw new DiscoveryError(`the project ${JSON.stringify(project.id)} (${project.configFile}) references ` +
|
|
186
|
+
`${unnamed}, which the build matrix does not name; a referenced project is built ` +
|
|
187
|
+
"into the program that references it, so the matrix names it too", []);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return { projects, configFiles: projects.map((project) => project.configFile), fromScope: [] };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The projects a run derives where the matrix declares none, in the order discovery
|
|
194
|
+
* reads them: the paths the scope names, then every compiler configuration under
|
|
195
|
+
* the target root that is not inside an ignored directory, then the configurations
|
|
196
|
+
* each of those references, transitively. Each configuration appears once.
|
|
144
197
|
*/
|
|
145
|
-
|
|
198
|
+
function derivedProjects(engine, host, scope) {
|
|
146
199
|
const fromScope = scopeConfigFiles(host, scope);
|
|
147
200
|
const seen = new Set();
|
|
148
|
-
const
|
|
201
|
+
const projects = [];
|
|
149
202
|
const pending = [...fromScope, ...configFilesUnder(host, scope.target.path)];
|
|
150
203
|
while (pending.length > 0) {
|
|
151
204
|
const configFile = pending.shift();
|
|
@@ -157,15 +210,36 @@ export function discoverProjects(engine, host, scope) {
|
|
|
157
210
|
continue;
|
|
158
211
|
}
|
|
159
212
|
seen.add(path);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
catch (error) {
|
|
164
|
-
throw new DiscoveryError(`${path} cannot be read as a compiler configuration: ` +
|
|
165
|
-
(error instanceof Error ? error.message : String(error)), []);
|
|
166
|
-
}
|
|
167
|
-
configFiles.push(path);
|
|
213
|
+
parseOrRefuse(engine, path, path);
|
|
214
|
+
projects.push({ id: derivedId(scope.target.path, path), configFile: path });
|
|
168
215
|
pending.push(...referencesOf(host, path));
|
|
169
216
|
}
|
|
170
|
-
return { configFiles, fromScope };
|
|
217
|
+
return { projects, configFiles: projects.map((project) => project.configFile), fromScope };
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Every project one run analyzes.
|
|
221
|
+
*
|
|
222
|
+
* The project entries of the build matrix, where it holds any, are the projects:
|
|
223
|
+
* exactly those, in the order the matrix lists them, each named by its declared
|
|
224
|
+
* identifier, as {@link declaredProjects} reads them. A matrix holding no project
|
|
225
|
+
* entry, the empty one included, leaves discovery to derive the projects from the
|
|
226
|
+
* scope and the target tree. A platform entry names a configuration of another
|
|
227
|
+
* language and plays no part here.
|
|
228
|
+
*
|
|
229
|
+
* A configuration file the compiler cannot read ends the run with the failure code,
|
|
230
|
+
* so a project that would have been analyzed with no type information is never
|
|
231
|
+
* analyzed at all, whether the matrix declared it or discovery derived it. What a
|
|
232
|
+
* configuration's own contents say is refused once its project is open, by
|
|
233
|
+
* {@link diagnosticErrors} over the three sets a program reports, because a
|
|
234
|
+
* resolution carries no diagnostics.
|
|
235
|
+
*
|
|
236
|
+
* Nothing reads a build output: a project is the files its configuration names, so a
|
|
237
|
+
* package whose sources ship as TypeScript is analyzed as it stands.
|
|
238
|
+
*/
|
|
239
|
+
export function discoverProjects(engine, host, scope, configurations = []) {
|
|
240
|
+
const declared = configurations.filter((entry) => entry.shape === "project");
|
|
241
|
+
if (declared.length > 0) {
|
|
242
|
+
return declaredProjects(engine, host, scope.target.path, declared);
|
|
243
|
+
}
|
|
244
|
+
return derivedProjects(engine, host, scope);
|
|
171
245
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One project's declarations, the references between them and the roots that seed
|
|
3
|
+
* reachability, indexed for the sweep. The graph reads no file and asks the compiler
|
|
4
|
+
* nothing, so a sweep over it is a function of the values it was built from, and the
|
|
5
|
+
* inventory's order is the order every set a sweep answers reads in.
|
|
6
|
+
*/
|
|
7
|
+
/** The position of a declaration the inventory does not hold. */
|
|
8
|
+
export const OUTSIDE = -1;
|
|
9
|
+
/**
|
|
10
|
+
* Whether the sweep judges a declaration of each kind. A file is not judged by either
|
|
11
|
+
* relation: whether a file is built and whether anything imports it are the subjects of
|
|
12
|
+
* the file kinds, which read the program rather than ask whether anything references the
|
|
13
|
+
* file. The Contract's finding schema names the kinds that carry no liveness relation,
|
|
14
|
+
* and a test holds this table to that list.
|
|
15
|
+
*/
|
|
16
|
+
const SWEPT = {
|
|
17
|
+
file: false,
|
|
18
|
+
function: true,
|
|
19
|
+
class: true,
|
|
20
|
+
interface: true,
|
|
21
|
+
type: true,
|
|
22
|
+
enum: true,
|
|
23
|
+
namespace: true,
|
|
24
|
+
variable: true,
|
|
25
|
+
"export-alias": true,
|
|
26
|
+
method: true,
|
|
27
|
+
"class-member": true,
|
|
28
|
+
"interface-method": true,
|
|
29
|
+
"type-member": true,
|
|
30
|
+
"enum-member": true,
|
|
31
|
+
"type-parameter": true,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Whether a root of each kind names a caller, which holds it live under both relations: a
|
|
35
|
+
* tool reads the configuration it loads, a runtime runs a test file, a setup file and a
|
|
36
|
+
* worker, and a configured root asserts a caller. The other kinds only suppose a consumer
|
|
37
|
+
* that imports what a manifest entry, a binary or an entry file exports, or names a
|
|
38
|
+
* library's published API, so such a root is live under reachability alone.
|
|
39
|
+
*/
|
|
40
|
+
const NAMES_A_CALLER = {
|
|
41
|
+
"entry-file": false,
|
|
42
|
+
"manifest-entry": false,
|
|
43
|
+
"manifest-binary": false,
|
|
44
|
+
"published-api": false,
|
|
45
|
+
configured: true,
|
|
46
|
+
pattern: true,
|
|
47
|
+
"test-runner": true,
|
|
48
|
+
"lint-configuration": true,
|
|
49
|
+
"mutation-testing": true,
|
|
50
|
+
"browser-tests": true,
|
|
51
|
+
worker: true,
|
|
52
|
+
};
|
|
53
|
+
/** Whether the sweep judges a declaration of one kind. */
|
|
54
|
+
export function swept(kind) {
|
|
55
|
+
return SWEPT[kind];
|
|
56
|
+
}
|
|
57
|
+
/** Whether a root of one kind names a caller rather than supposing one. */
|
|
58
|
+
export function namesACaller(kind) {
|
|
59
|
+
return NAMES_A_CALLER[kind];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Indexes one project's inventory, references and roots. `testFiles` are the paths the
|
|
63
|
+
* reference pass classified as test files, so a declaration one holds is a test
|
|
64
|
+
* declaration. A reference to a declaration the inventory does not hold is dropped; one
|
|
65
|
+
* from such a declaration still counts toward its target, because reference counting
|
|
66
|
+
* asks whether any declaration names the target. A root naming nothing is dropped.
|
|
67
|
+
*/
|
|
68
|
+
export function graphOf(symbols, references, roots, testFiles) {
|
|
69
|
+
const index = new Map(symbols.map((symbol, at) => [symbol.id, at]));
|
|
70
|
+
const at = (id) => index.get(id) ?? OUTSIDE;
|
|
71
|
+
const tests = new Set(testFiles);
|
|
72
|
+
const out = symbols.map(() => []);
|
|
73
|
+
const made = symbols.map(() => ({ production: 0, test: 0 }));
|
|
74
|
+
for (const reference of references) {
|
|
75
|
+
const to = at(reference.to);
|
|
76
|
+
if (to === OUTSIDE) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const counts = made[to];
|
|
80
|
+
if (counts !== undefined) {
|
|
81
|
+
if (reference.test) {
|
|
82
|
+
counts.test += 1;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
counts.production += 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
out[at(reference.from)]?.push({
|
|
89
|
+
to,
|
|
90
|
+
test: reference.test,
|
|
91
|
+
evaluation: reference.use === "evaluation",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const parent = symbols.map((symbol) => at(symbol.parent));
|
|
95
|
+
const exportsOf = symbols.map(() => []);
|
|
96
|
+
symbols.forEach((symbol, position) => {
|
|
97
|
+
const container = parent[position] ?? OUTSIDE;
|
|
98
|
+
if (symbol.exported && symbols[container]?.kind === "file") {
|
|
99
|
+
exportsOf[container]?.push(position);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
const rooted = [];
|
|
103
|
+
for (const root of roots) {
|
|
104
|
+
const position = at(root.id);
|
|
105
|
+
if (position !== OUTSIDE) {
|
|
106
|
+
rooted.push({ at: position, kind: root.kind });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
symbols,
|
|
111
|
+
out,
|
|
112
|
+
made,
|
|
113
|
+
parent,
|
|
114
|
+
test: symbols.map((symbol) => tests.has(symbol.position.path)),
|
|
115
|
+
subject: symbols.map((symbol) => swept(symbol.kind)),
|
|
116
|
+
exportsOf,
|
|
117
|
+
rooted,
|
|
118
|
+
at,
|
|
119
|
+
};
|
|
120
|
+
}
|
package/dist/src/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export { run, SETTING_OPTIONS } from "./run.js";
|
|
2
2
|
export { DECLINED_CONVENTIONS } from "./entry-point-gaps.js";
|
|
3
|
-
export { inventory, nodeKey, } from "./inventory.js";
|
|
4
|
-
export { DEFAULT_BATCH_CAP, references, } from "./references.js";
|
|
5
3
|
export { byPosition, positionKey, PositionError, renderPosition, } from "./position.js";
|
|
6
4
|
export { computedComponent, isRef, nameComponent, REF_EXPRESSIONS, renderRef, } from "./ref.js";
|
|
7
5
|
export { CONTRACT_VERSION } from "./version.js";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One run's projects as one matrix: every declaration any project holds, keyed by its
|
|
3
|
+
* position and carrying the configurations that hold it, swept once per configuration
|
|
4
|
+
* and intersected, with the dead components computed once over every configuration.
|
|
5
|
+
*/
|
|
6
|
+
import { componentsOf } from "./components.js";
|
|
7
|
+
import { graphOf } from "./graph.js";
|
|
8
|
+
import { byPosition } from "./position.js";
|
|
9
|
+
import { sweep } from "./sweep.js";
|
|
10
|
+
/** Two strings ordered bytewise. */
|
|
11
|
+
function compare(a, b) {
|
|
12
|
+
if (a === b) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
return a < b ? -1 : 1;
|
|
16
|
+
}
|
|
17
|
+
/** What makes one reference one reference, whichever configuration made it. */
|
|
18
|
+
function referenceKey(reference) {
|
|
19
|
+
const { path, line, column } = reference.position;
|
|
20
|
+
return [reference.from, reference.to, path, String(line), String(column), reference.use].join("\u0000");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Indexes what the passes answered for each configuration of one run, in the run's order.
|
|
24
|
+
*
|
|
25
|
+
* A declaration is keyed across configurations by its identifier, which is its rendered
|
|
26
|
+
* position and so is the same in every configuration that compiles its file; the fields
|
|
27
|
+
* of the first configuration that holds it are the ones kept. A declaration one
|
|
28
|
+
* configuration alone holds is in the union with that one configuration, so it is
|
|
29
|
+
* judged where it exists rather than skipped.
|
|
30
|
+
*
|
|
31
|
+
* One reference written at one position of a file several configurations compile is seen
|
|
32
|
+
* once per configuration and is one reference, so the union holds it once; two references
|
|
33
|
+
* one configuration makes at one position are two.
|
|
34
|
+
*/
|
|
35
|
+
export function matrixOf(per) {
|
|
36
|
+
const symbols = [];
|
|
37
|
+
const holders = new Map();
|
|
38
|
+
const references = [];
|
|
39
|
+
const firstSeen = new Map();
|
|
40
|
+
per.forEach((one, index) => {
|
|
41
|
+
for (const symbol of one.symbols) {
|
|
42
|
+
const held = holders.get(symbol.id);
|
|
43
|
+
if (held === undefined) {
|
|
44
|
+
holders.set(symbol.id, [one.configuration]);
|
|
45
|
+
symbols.push(symbol);
|
|
46
|
+
}
|
|
47
|
+
else if (!held.includes(one.configuration)) {
|
|
48
|
+
held.push(one.configuration);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const reference of one.references) {
|
|
52
|
+
const key = referenceKey(reference);
|
|
53
|
+
const seen = firstSeen.get(key);
|
|
54
|
+
if (seen === undefined) {
|
|
55
|
+
firstSeen.set(key, index);
|
|
56
|
+
}
|
|
57
|
+
else if (seen !== index) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
references.push(reference);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
symbols.sort((a, b) => byPosition(a.position, b.position) || compare(a.ref, b.ref));
|
|
64
|
+
return {
|
|
65
|
+
configurations: per.map((one) => one.configuration),
|
|
66
|
+
graphs: per.map((one) => graphOf(one.symbols, one.references, one.roots, one.testFiles)),
|
|
67
|
+
union: graphOf(symbols, references, per.flatMap((one) => one.roots), [...new Set(per.flatMap((one) => one.testFiles))]),
|
|
68
|
+
heldIn: symbols.map((symbol) => holders.get(symbol.id) ?? []),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Answers which declarations of the run are dead in every configuration that holds them.
|
|
73
|
+
*
|
|
74
|
+
* Liveness is a question about one configuration, because a file another configuration
|
|
75
|
+
* does not compile makes no reference there and a root it does not hold seeds nothing
|
|
76
|
+
* there, so each configuration is swept on its own graph under the run's input. A
|
|
77
|
+
* declaration is a candidate when every configuration holding it judged it one: a
|
|
78
|
+
* reference under one configuration is a reference, so what one project uses is never
|
|
79
|
+
* reported, and a configuration that does not hold a declaration says nothing about it.
|
|
80
|
+
* The candidate's relation is reference counting where every configuration found it so,
|
|
81
|
+
* and reachability otherwise; its counts are the union's, one per reference.
|
|
82
|
+
*
|
|
83
|
+
* The components are computed once, over the union and the intersected dead set, so one
|
|
84
|
+
* dead component is one entry of the run with one identifier.
|
|
85
|
+
*/
|
|
86
|
+
export function sweepMatrix(matrix, input) {
|
|
87
|
+
const per = matrix.graphs.map((graph) => sweep(graph, input));
|
|
88
|
+
const byConfiguration = new Map(matrix.configurations.map((configuration, index) => [
|
|
89
|
+
configuration,
|
|
90
|
+
new Map((per[index]?.candidates ?? []).map((candidate) => [candidate.id, candidate])),
|
|
91
|
+
]));
|
|
92
|
+
const union = matrix.union;
|
|
93
|
+
const dead = union.symbols.map(() => false);
|
|
94
|
+
const testOfDeadCode = union.symbols.map(() => false);
|
|
95
|
+
const candidates = [];
|
|
96
|
+
union.symbols.forEach((symbol, at) => {
|
|
97
|
+
const held = matrix.heldIn[at] ?? [];
|
|
98
|
+
const found = held.map((configuration) => byConfiguration.get(configuration)?.get(symbol.id));
|
|
99
|
+
if (held.length === 0 || found.some((candidate) => candidate === undefined)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const all = found.filter((candidate) => candidate !== undefined);
|
|
103
|
+
const admitted = all.every((candidate) => candidate.testOfDeadCode);
|
|
104
|
+
dead[at] = true;
|
|
105
|
+
testOfDeadCode[at] = admitted;
|
|
106
|
+
candidates.push({
|
|
107
|
+
id: symbol.id,
|
|
108
|
+
productionRefs: union.made[at]?.production ?? 0,
|
|
109
|
+
testRefs: union.made[at]?.test ?? 0,
|
|
110
|
+
relation: all.every((candidate) => candidate.relation === "reference-counting")
|
|
111
|
+
? "reference-counting"
|
|
112
|
+
: "reachability",
|
|
113
|
+
testOfDeadCode: admitted,
|
|
114
|
+
configurations: held,
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
return {
|
|
118
|
+
liveUnder: liveAnywhere(union.symbols, per),
|
|
119
|
+
candidates,
|
|
120
|
+
components: componentsOf(union, dead, testOfDeadCode),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** The relations in the order a declaration's entry lists them. */
|
|
124
|
+
const RELATIONS = ["reference-counting", "reachability"];
|
|
125
|
+
/**
|
|
126
|
+
* Per declaration, in site order, every relation that holds it live in at least one
|
|
127
|
+
* configuration.
|
|
128
|
+
*/
|
|
129
|
+
function liveAnywhere(symbols, per) {
|
|
130
|
+
const live = new Map();
|
|
131
|
+
for (const symbol of symbols) {
|
|
132
|
+
const relations = RELATIONS.filter((relation) => per.some((liveness) => (liveness.liveUnder.get(symbol.id) ?? []).includes(relation)));
|
|
133
|
+
if (relations.length > 0) {
|
|
134
|
+
live.set(symbol.id, relations);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return live;
|
|
138
|
+
}
|
package/dist/src/print.js
CHANGED
|
@@ -19,12 +19,9 @@ export function printConfig(config, provenance) {
|
|
|
19
19
|
min_confidence: config.analysis.minConfidence,
|
|
20
20
|
generated_files: config.analysis.generatedFiles,
|
|
21
21
|
consumer_tests: config.analysis.consumerTests,
|
|
22
|
-
configurations: config.analysis.configurations.map((entry) =>
|
|
23
|
-
id: entry.id,
|
|
24
|
-
os: entry.os,
|
|
25
|
-
arch: entry.arch,
|
|
26
|
-
tags: entry.tags,
|
|
27
|
-
})),
|
|
22
|
+
configurations: config.analysis.configurations.map((entry) => entry.shape === "project"
|
|
23
|
+
? { id: entry.id, project: entry.project }
|
|
24
|
+
: { id: entry.id, os: entry.os, arch: entry.arch, tags: entry.tags }),
|
|
28
25
|
matrix: { complete: config.analysis.matrixComplete },
|
|
29
26
|
template_dirs: config.analysis.templateDirs,
|
|
30
27
|
template_delimiters: {
|