@cplieger/deadset-ts 8.0.0-dev.7 → 8.0.0-dev.9
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/bin/node-host.js +21 -3
- package/dist/src/analysis.js +94 -299
- package/dist/src/config.js +6 -83
- package/dist/src/configuration-files.js +2 -9
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/consumers.js +3 -30
- package/dist/src/contract/config.generated.js +544 -0
- package/dist/src/contract/contract.generated.js +20 -10
- package/dist/src/contract/report.generated.js +3 -2
- package/dist/src/conventions.js +3 -8
- package/dist/src/edges.js +36 -112
- package/dist/src/exempt-classes.js +0 -2
- package/dist/src/exempt.js +1 -1
- package/dist/src/failure.js +36 -0
- package/dist/src/findings/completion.js +5 -4
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/intra-function.js +1 -1
- package/dist/src/findings/non-code-artifacts.js +2 -2
- package/dist/src/findings/unused-declarations.js +1 -1
- package/dist/src/findings/visibility-narrowing.js +2 -2
- package/dist/src/findings-pass.js +1 -1
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +7 -0
- package/dist/src/injection-container.js +1 -1
- package/dist/src/json-document.js +194 -67
- package/dist/src/kinds.js +0 -7
- package/dist/src/load/classify.js +236 -0
- package/dist/src/load/diagnostics.js +79 -0
- package/dist/src/load/discover.js +230 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +22 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/plan.js +155 -0
- package/dist/src/{test-globals.js → load/test-globals.js} +51 -56
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +3 -3
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +37 -40
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +21 -59
- package/dist/src/{workspace-run.js → load/workspace-run.js} +4 -3
- package/dist/src/{workspace.js → load/workspace.js} +21 -17
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/print.js +10 -79
- package/dist/src/report-schema.js +3 -224
- package/dist/src/resolve.js +245 -715
- package/dist/src/run.js +59 -72
- package/dist/src/schema.js +320 -344
- package/dist/src/scope.js +37 -113
- package/dist/src/serialization-contract.js +1 -1
- package/dist/src/session.js +22 -28
- package/dist/src/source-files.js +1 -1
- package/dist/src/suppress-file.js +15 -17
- package/dist/src/suppress.js +3 -3
- package/dist/src/template-field.js +4 -4
- package/dist/src/type-errors.js +11 -216
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +100 -122
- package/dist/src/verbs/describe.js +5 -12
- package/dist/src/verbs/explain.js +3 -3
- package/dist/src/verbs/print-projects.js +2 -2
- package/dist/src/verbs/version.js +12 -2
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +95 -460
- package/src/config.ts +31 -298
- package/src/configuration-files.ts +8 -10
- package/src/configured-declarations.ts +18 -23
- package/src/consumers.ts +6 -57
- package/src/contract/config.generated.ts +798 -0
- package/src/contract/contract.generated.ts +20 -10
- package/src/contract/report.generated.ts +3 -2
- package/src/conventions.ts +6 -12
- package/src/edges.ts +39 -124
- package/src/exempt-classes.ts +0 -5
- package/src/exempt.ts +4 -4
- package/src/failure.ts +63 -0
- package/src/findings/completion.ts +5 -6
- package/src/findings/emitter.ts +2 -2
- package/src/findings/emitters.ts +1 -1
- package/src/findings/intra-function.ts +1 -1
- package/src/findings/non-code-artifacts.ts +4 -4
- package/src/findings/unused-declarations.ts +1 -1
- package/src/findings/visibility-narrowing.ts +2 -2
- package/src/findings-pass.ts +3 -3
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +8 -0
- package/src/host.ts +12 -5
- package/src/injection-container.ts +1 -1
- package/src/json-document.ts +236 -76
- package/src/kinds.ts +0 -8
- package/src/load/classify.ts +352 -0
- package/src/load/diagnostics.ts +141 -0
- package/src/load/discover.ts +378 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +188 -0
- package/src/load/load.ts +61 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/plan.ts +258 -0
- package/src/{test-globals.ts → load/test-globals.ts} +59 -65
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +4 -4
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +59 -53
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +31 -78
- package/src/{workspace-run.ts → load/workspace-run.ts} +14 -11
- package/src/{workspace.ts → load/workspace.ts} +28 -21
- package/src/outside-tests.ts +1 -1
- package/src/partial.ts +1 -1
- package/src/print.ts +11 -92
- package/src/report-schema.ts +3 -299
- package/src/resolve.ts +281 -1105
- package/src/run.ts +68 -80
- package/src/schema.ts +391 -389
- package/src/scope.ts +45 -131
- package/src/serialization-contract.ts +1 -1
- package/src/session.ts +52 -53
- package/src/source-files.ts +1 -1
- package/src/suppress-file.ts +15 -20
- package/src/suppress.ts +3 -3
- package/src/template-field.ts +10 -7
- package/src/type-errors.ts +18 -288
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +139 -157
- package/src/verbs/describe.ts +4 -11
- package/src/verbs/explain.ts +3 -7
- package/src/verbs/print-projects.ts +2 -2
- package/src/verbs/verb.ts +2 -2
- package/src/verbs/version.ts +13 -2
- package/dist/src/base-url.js +0 -18
- package/dist/src/discover.js +0 -374
- package/dist/src/setup-failure.js +0 -19
- package/dist/src/test-joins.js +0 -101
- package/src/base-url.ts +0 -24
- package/src/discover.ts +0 -548
- package/src/setup-failure.ts +0 -37
- package/src/test-joins.ts +0 -118
package/dist/src/discover.js
DELETED
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
import { DiagnosticCategory } from "@typescript/native/sync";
|
|
2
|
-
import { baseUrlPaths } from "./base-url.js";
|
|
3
|
-
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
4
|
-
import { SetupError } from "./setup-failure.js";
|
|
5
|
-
import { writtenPath } from "./workspace-programs.js";
|
|
6
|
-
import { filesBelow } from "./fs/tree.js";
|
|
7
|
-
import { LANGUAGE, message } from "./product.js";
|
|
8
|
-
import { LANGUAGE_ROWS } from "./contract/contract.generated.js";
|
|
9
|
-
import { globExpression } from "./text/glob.js";
|
|
10
|
-
const MARKERS = LANGUAGE_ROWS[LANGUAGE].markers.map(globExpression);
|
|
11
|
-
/** Whether one file name is a compiler configuration's: one of the language row's markers. */
|
|
12
|
-
export function isConfigFile(name) {
|
|
13
|
-
return MARKERS.some((marker) => marker.test(name));
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* A run that cannot read what it was asked to analyze. It ends the run with the
|
|
17
|
-
* failure code and no finding list: a configuration file the compiler cannot read,
|
|
18
|
-
* or a project carrying an error, leaves the analysis without the type information
|
|
19
|
-
* every answer rests on, and a partial answer is never printed as a complete one.
|
|
20
|
-
*/
|
|
21
|
-
export class DiscoveryError extends Error {
|
|
22
|
-
/** The diagnostics the compiler reported, in the order it reported them. */
|
|
23
|
-
diagnostics;
|
|
24
|
-
constructor(message, diagnostics) {
|
|
25
|
-
super(message);
|
|
26
|
-
this.name = "DiscoveryError";
|
|
27
|
-
this.diagnostics = diagnostics;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/** The category an error diagnostic carries, which the protocol sends as a number. */
|
|
31
|
-
const ERROR_CATEGORY = DiagnosticCategory.Error;
|
|
32
|
-
/** Whether one diagnostic is an error, which is what fails a run closed. */
|
|
33
|
-
function isError(diagnostic) {
|
|
34
|
-
return diagnostic.category === ERROR_CATEGORY;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* One diagnostic as a line naming its file, its line and column, its code and its
|
|
38
|
-
* message: `path:line:column: TScode: message`, the position left out where the
|
|
39
|
-
* diagnostic names none and the file where it names none. `display` spells the
|
|
40
|
-
* file's path; it answers the path itself where it is not given.
|
|
41
|
-
*/
|
|
42
|
-
export function renderDiagnostic(located, display = (path) => path) {
|
|
43
|
-
const { diagnostic, at } = located;
|
|
44
|
-
const message = `TS${String(diagnostic.code)}: ${diagnostic.text}`;
|
|
45
|
-
if (diagnostic.fileName === undefined) {
|
|
46
|
-
return message;
|
|
47
|
-
}
|
|
48
|
-
const where = display(diagnostic.fileName);
|
|
49
|
-
return at === undefined
|
|
50
|
-
? `${where}: ${message}`
|
|
51
|
-
: `${where}:${String(at.line)}:${String(at.column)}: ${message}`;
|
|
52
|
-
}
|
|
53
|
-
/** Each diagnostic with the line and column its offset falls on. */
|
|
54
|
-
function locatedIn(diagnostics, locate) {
|
|
55
|
-
return diagnostics.map((diagnostic) => ({
|
|
56
|
-
diagnostic,
|
|
57
|
-
at: diagnostic.fileName === undefined ? undefined : locate(diagnostic.fileName, diagnostic.pos),
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Every error a project's three diagnostic sets carry, in the order the compiler
|
|
62
|
-
* reported them: a configuration whose options do not parse, a file whose syntax
|
|
63
|
-
* does not, and a program that does not type-check. A resolved configuration
|
|
64
|
-
* carries no diagnostics of its own, so a configuration written with an unreadable
|
|
65
|
-
* option resolves and is refused here, once its project is open.
|
|
66
|
-
*/
|
|
67
|
-
export function diagnosticErrors(sets) {
|
|
68
|
-
return [...sets.configParsing, ...sets.syntactic, ...sets.semantic].filter(isError);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* The codes of a type library and a lib the configuration names that the compiler
|
|
72
|
-
* cannot find, which it reports while it gathers the program's files,
|
|
73
|
-
* https://github.com/microsoft/typescript-go/blob/89d5d5b2849a0db0957065889ca58536fa6d2e4a/internal/compiler/processingDiagnostic.go,
|
|
74
|
-
* and {@link MISSING_GLOBAL_TYPE}, which the checker reports.
|
|
75
|
-
*/
|
|
76
|
-
const UNFOUND_LIBRARY = new Set([2318, 2688, 2726, 2727]);
|
|
77
|
-
/**
|
|
78
|
-
* The code of a global type the checker finds in no library the program holds. The checker
|
|
79
|
-
* types every use of one against nothing and places no error in the file, so the analysis
|
|
80
|
-
* skips each file of such a project whole.
|
|
81
|
-
*/
|
|
82
|
-
export const MISSING_GLOBAL_TYPE = 2318;
|
|
83
|
-
/** The errors one open project carries, each located in the file it names. */
|
|
84
|
-
export function projectErrors(sets) {
|
|
85
|
-
// The compiler numbers its semantic messages from 2000 and its option messages from
|
|
86
|
-
// 5000. A file-less option error, a removed option or an output layout, leaves the
|
|
87
|
-
// program whole, and the compiler checks it all the same:
|
|
88
|
-
// https://github.com/microsoft/TypeScript/wiki/Coding-guidelines#diagnostic-message-codes
|
|
89
|
-
const semantic = sets.unplaced.filter((diagnostic) => isError(diagnostic) && diagnostic.code >= 2000 && diagnostic.code < 3000);
|
|
90
|
-
const unfound = semantic.filter(({ code }) => UNFOUND_LIBRARY.has(code));
|
|
91
|
-
const load = [
|
|
92
|
-
...sets.configParsing.filter(isError),
|
|
93
|
-
...semantic.filter(({ code }) => !UNFOUND_LIBRARY.has(code)),
|
|
94
|
-
];
|
|
95
|
-
return {
|
|
96
|
-
load: locatedIn(load, sets.locate),
|
|
97
|
-
check: load.length > 0 ? [] : locatedIn(diagnosticErrors(sets), sets.locate),
|
|
98
|
-
unfound: load.length > 0 ? [] : locatedIn(unfound, sets.locate),
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* The first line of one error about the target, every mention of the target root
|
|
103
|
-
* spelled relative to it: a path below the root loses the root and its separator, and
|
|
104
|
-
* the root itself is `.`.
|
|
105
|
-
*/
|
|
106
|
-
export function targetRelative(text, targetRoot) {
|
|
107
|
-
const root = targetRoot.endsWith("/") ? targetRoot.slice(0, -1) : targetRoot;
|
|
108
|
-
const [first = ""] = text.split(/\r?\n/u);
|
|
109
|
-
const spelled = first.split(`${root}/`).join("").split(root).join(".").trim();
|
|
110
|
-
return spelled === "" ? "the configuration could not be built" : spelled;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Whether one configuration is the analyzer's own guess: discovery derived it and the
|
|
114
|
-
* scope did not name it. A guess that does not load is dropped; any other ends the run.
|
|
115
|
-
*/
|
|
116
|
-
export function isGuess(discovery, configFile) {
|
|
117
|
-
return discovery.derived && !discovery.fromScope.includes(configFile);
|
|
118
|
-
}
|
|
119
|
-
/** The configuration files below `root`, by absolute path in ascending order. */
|
|
120
|
-
function configFilesUnder(host, root) {
|
|
121
|
-
return filesBelow(host, root, isConfigFile).map((path) => joinPath(root, path));
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* The configuration file the scope names for the target directly, where its path
|
|
125
|
-
* names one rather than a directory. A target naming a directory is reached by the
|
|
126
|
-
* walk over that directory instead. A consumer's projects are a consumer's, never the
|
|
127
|
-
* target's, so no consumer path is read here.
|
|
128
|
-
*/
|
|
129
|
-
function scopeConfigFiles(host, scope) {
|
|
130
|
-
return [scope.target.path]
|
|
131
|
-
.filter((path) => path.endsWith(".json"))
|
|
132
|
-
.map((path) => resolvePath(host.workingDirectory(), path));
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Every configuration file reached from `pending`, in the order discovery reads them:
|
|
136
|
-
* each once, each followed by the configurations it references that `follows` admits,
|
|
137
|
-
* transitively. A configuration the compiler cannot read ends the run naming it, unless
|
|
138
|
-
* `unreadable` is given, which is then told the configuration and why, and the walk
|
|
139
|
-
* goes on without it.
|
|
140
|
-
*/
|
|
141
|
-
function derivedFrom(engine, host, pending, follows, unreadable) {
|
|
142
|
-
const seen = new Set();
|
|
143
|
-
const found = [];
|
|
144
|
-
while (pending.length > 0) {
|
|
145
|
-
const configFile = pending.shift();
|
|
146
|
-
if (configFile === undefined) {
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
const path = resolvePath(host.workingDirectory(), configFile);
|
|
150
|
-
if (seen.has(path)) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
seen.add(path);
|
|
154
|
-
const read = readConfiguration(engine, path);
|
|
155
|
-
if ("reason" in read) {
|
|
156
|
-
if (unreadable === undefined) {
|
|
157
|
-
throw new DiscoveryError(`${path} cannot be read as a compiler configuration: ${read.reason}`, []);
|
|
158
|
-
}
|
|
159
|
-
unreadable(path, read.reason);
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
found.push(path);
|
|
163
|
-
pending.push(...read.references.filter(follows));
|
|
164
|
-
}
|
|
165
|
-
return found;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* The compiler configurations one consumer is loaded through: every one under its
|
|
169
|
-
* root that is not inside an ignored directory, and the configurations each of those
|
|
170
|
-
* references, transitively, in that order. A root that is absent, that is no
|
|
171
|
-
* directory, or that holds no configuration ends the run naming it, because a
|
|
172
|
-
* finding computed without a declared consumer would claim a reference set the run
|
|
173
|
-
* never read.
|
|
174
|
-
*/
|
|
175
|
-
export function consumerProjects(engine, host, root) {
|
|
176
|
-
const kind = host.kindOf(root);
|
|
177
|
-
if (kind === "absent") {
|
|
178
|
-
throw new SetupError([
|
|
179
|
-
{
|
|
180
|
-
setupClass: "missing-consumer",
|
|
181
|
-
detail: `the scope declares the consumer ${root}, and nothing is at that path: check the consumer out at ${root} and install its dependencies`,
|
|
182
|
-
},
|
|
183
|
-
]);
|
|
184
|
-
}
|
|
185
|
-
if (kind !== "directory") {
|
|
186
|
-
throw new DiscoveryError(`the consumer ${root} is not a directory`, []);
|
|
187
|
-
}
|
|
188
|
-
const found = derivedFrom(engine, host, [...configFilesUnder(host, root)], () => true);
|
|
189
|
-
if (found.length === 0) {
|
|
190
|
-
throw new DiscoveryError(`the consumer ${root} holds no compiler configuration, so none of its references can be read`, []);
|
|
191
|
-
}
|
|
192
|
-
return found;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* The name a derived project carries: its configuration file's path below the target
|
|
196
|
-
* root, or the absolute path of a file outside it.
|
|
197
|
-
*/
|
|
198
|
-
function derivedId(targetRoot, configFile) {
|
|
199
|
-
return relativePath(targetRoot, configFile) ?? configFile;
|
|
200
|
-
}
|
|
201
|
-
/** The configuration files one parsed configuration's `references` name. */
|
|
202
|
-
function referencesOf(parsed) {
|
|
203
|
-
// The parse answers a directory reference as the directory; the compiler reads a
|
|
204
|
-
// path not ending `.json` as its `tsconfig.json`:
|
|
205
|
-
// https://github.com/microsoft/typescript-go/blob/89d5d5b2849a0db0957065889ca58536fa6d2e4a/internal/core/projectreference.go#L18
|
|
206
|
-
return (parsed.projectReferences ?? []).map(({ path }) => path.endsWith(".json") ? path : joinPath(path, "tsconfig.json"));
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* The code of a configuration whose `extends` chain returns to a configuration it already
|
|
210
|
-
* passed. A snapshot that opens two configurations whose `extends` chains reach one such
|
|
211
|
-
* cycle panics (`OwnerCache.AddOwner: entry not found`, typescript 7.1.0-dev.20261014.1),
|
|
212
|
-
* so the analysis refuses one before any snapshot is asked to open it.
|
|
213
|
-
*/
|
|
214
|
-
const CIRCULAR_EXTENDS = 18000;
|
|
215
|
-
/**
|
|
216
|
-
* The configurations one configuration file's `references` name, or why it cannot be read:
|
|
217
|
-
* the compiler throws, or its parse reports the `extends` chain circular.
|
|
218
|
-
*/
|
|
219
|
-
function readConfiguration(engine, configFile) {
|
|
220
|
-
try {
|
|
221
|
-
const parsed = engine.parseConfigFile(configFile);
|
|
222
|
-
const circular = parsed.errors.find(({ code }) => code === CIRCULAR_EXTENDS);
|
|
223
|
-
// The compiler leaves the message's `{0}` unfilled:
|
|
224
|
-
// https://github.com/microsoft/TypeScript/pull/64755
|
|
225
|
-
return circular === undefined
|
|
226
|
-
? { references: referencesOf(parsed) }
|
|
227
|
-
: { reason: `TS${String(circular.code)}: ${circular.text.replace("{0}", () => configFile)}` };
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
return { reason: message(error) };
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* The references of one compiler configuration file, or ends the run naming it: a
|
|
235
|
-
* project opened from a configuration the compiler cannot read would be analyzed with
|
|
236
|
-
* no type information.
|
|
237
|
-
*/
|
|
238
|
-
function parseOrRefuse(engine, configFile, named) {
|
|
239
|
-
const read = readConfiguration(engine, configFile);
|
|
240
|
-
if ("reason" in read) {
|
|
241
|
-
throw new DiscoveryError(`${named} cannot be read as a compiler configuration: ${read.reason}`, []);
|
|
242
|
-
}
|
|
243
|
-
return read.references;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* The projects a build matrix declares, in its order, each entry a file below the target
|
|
247
|
-
* root: an entry naming an absent file, a directory or a file the compiler cannot read
|
|
248
|
-
* ends the run naming it, and one naming an earlier entry's file adds nothing. A
|
|
249
|
-
* reference below the root the matrix does not name ends the run naming both, because the
|
|
250
|
-
* compiler builds a referenced project's sources into the referencing program without
|
|
251
|
-
* reporting their diagnostics. A reference outside the root is an outside project.
|
|
252
|
-
*/
|
|
253
|
-
function declaredProjects(engine, host, targetRoot, entries) {
|
|
254
|
-
const seen = new Set();
|
|
255
|
-
const projects = [];
|
|
256
|
-
const references = new Map();
|
|
257
|
-
for (const entry of entries) {
|
|
258
|
-
const configFile = joinPath(targetRoot, entry.project);
|
|
259
|
-
const named = `the project ${JSON.stringify(entry.id)} (${configFile})`;
|
|
260
|
-
const kind = host.kindOf(configFile);
|
|
261
|
-
if (kind !== "file") {
|
|
262
|
-
throw new DiscoveryError(kind === "absent"
|
|
263
|
-
? `${named} does not exist`
|
|
264
|
-
: `${named} is a directory, and a project names its compiler configuration file`, []);
|
|
265
|
-
}
|
|
266
|
-
if (seen.has(configFile)) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
seen.add(configFile);
|
|
270
|
-
references.set(configFile, parseOrRefuse(engine, configFile, named));
|
|
271
|
-
projects.push({ id: entry.id, configFile });
|
|
272
|
-
}
|
|
273
|
-
for (const project of projects) {
|
|
274
|
-
const unnamed = references
|
|
275
|
-
.get(project.configFile)
|
|
276
|
-
?.find((path) => !seen.has(path) && relativePath(targetRoot, path) !== undefined);
|
|
277
|
-
if (unnamed !== undefined) {
|
|
278
|
-
throw new DiscoveryError(`the project ${JSON.stringify(project.id)} (${project.configFile}) references ` +
|
|
279
|
-
`${unnamed}, which the build matrix does not name. A referenced project is built ` +
|
|
280
|
-
"into the program that references it, so the matrix names it too", []);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
return {
|
|
284
|
-
projects,
|
|
285
|
-
derived: false,
|
|
286
|
-
notBuilt: [],
|
|
287
|
-
configFiles: projects.map((project) => project.configFile),
|
|
288
|
-
fromScope: [],
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* The projects a run derives where the matrix declares none, in discovery order: the
|
|
293
|
-
* paths the scope names, every compiler configuration under the target root outside an
|
|
294
|
-
* ignored directory, then each configuration below the root those reference,
|
|
295
|
-
* transitively, each once. A reference outside the root is an outside project, whose
|
|
296
|
-
* sources the compiler builds into the referencing program. A configuration the scope
|
|
297
|
-
* names ends the run where it cannot be read; one the walk found is dropped and named.
|
|
298
|
-
*/
|
|
299
|
-
function derivedProjects(engine, host, scope) {
|
|
300
|
-
const targetRoot = scope.target.path;
|
|
301
|
-
const fromScope = scopeConfigFiles(host, scope);
|
|
302
|
-
const notBuilt = [];
|
|
303
|
-
const rootDir = resolvePath(host.workingDirectory(), fromScope.length > 0 ? dirnamePath(targetRoot) : targetRoot);
|
|
304
|
-
const configFiles = derivedFrom(engine, host, [...fromScope, ...configFilesUnder(host, targetRoot)], (reference) => relativePath(rootDir, reference) !== undefined, (configFile, reason) => {
|
|
305
|
-
if (fromScope.includes(configFile)) {
|
|
306
|
-
throw new DiscoveryError(`${configFile} cannot be read as a compiler configuration: ${reason}`, []);
|
|
307
|
-
}
|
|
308
|
-
notBuilt.push({
|
|
309
|
-
id: derivedId(targetRoot, configFile),
|
|
310
|
-
configFile,
|
|
311
|
-
error: targetRelative(reason, resolvePath(host.workingDirectory(), targetRoot)),
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
const projects = configFiles.map((configFile) => ({
|
|
315
|
-
id: derivedId(targetRoot, configFile),
|
|
316
|
-
configFile,
|
|
317
|
-
}));
|
|
318
|
-
return { projects, derived: true, notBuilt, configFiles, fromScope };
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Every project one run analyzes.
|
|
322
|
-
*
|
|
323
|
-
* The project entries of the build matrix, where it holds any, are the projects:
|
|
324
|
-
* exactly those, in the order the matrix lists them, each named by its declared
|
|
325
|
-
* identifier, as {@link declaredProjects} reads them. A matrix holding no project
|
|
326
|
-
* entry, the empty one included, leaves discovery to derive the projects from the
|
|
327
|
-
* scope and the target tree. A platform entry names a configuration of another
|
|
328
|
-
* language and plays no part here.
|
|
329
|
-
*
|
|
330
|
-
* A configuration file the compiler cannot read is never analyzed. One the matrix or
|
|
331
|
-
* the scope names ends the run with the failure code; a guess is dropped and named in
|
|
332
|
-
* {@link Discovery.notBuilt}. What a configuration's own contents say is read once its
|
|
333
|
-
* project is open, by {@link diagnosticErrors}, because a resolution carries none.
|
|
334
|
-
*
|
|
335
|
-
* Nothing reads a build output: a project is the files its configuration names, so a
|
|
336
|
-
* package whose sources ship as TypeScript is analyzed as it stands.
|
|
337
|
-
*/
|
|
338
|
-
export function discoverProjects(engine, host, scope, configurations = []) {
|
|
339
|
-
const declared = configurations.filter((entry) => entry.shape === "project");
|
|
340
|
-
if (declared.length > 0) {
|
|
341
|
-
return declaredProjects(engine, host, scope.target.path, declared);
|
|
342
|
-
}
|
|
343
|
-
return derivedProjects(engine, host, scope);
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* How the snapshot reads each configuration of `configFiles` that sets `baseUrl` and
|
|
347
|
-
* `programs` does not already describe: a configuration only the snapshot holds, which
|
|
348
|
-
* extends it and states the `paths` {@link baseUrlPaths} gives, so its imports resolve as
|
|
349
|
-
* the compilers before version 7 resolve them. A configuration the compiler cannot read is
|
|
350
|
-
* left for its project to refuse.
|
|
351
|
-
*/
|
|
352
|
-
export function withBaseUrlPaths(engine, host, configFiles, programs) {
|
|
353
|
-
const found = new Map(programs);
|
|
354
|
-
for (const configFile of configFiles) {
|
|
355
|
-
if (found.has(configFile)) {
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
let paths;
|
|
359
|
-
try {
|
|
360
|
-
paths = baseUrlPaths(engine.parseConfigFile(configFile).options);
|
|
361
|
-
}
|
|
362
|
-
catch {
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
if (paths !== undefined) {
|
|
366
|
-
found.set(configFile, {
|
|
367
|
-
kind: "configuration",
|
|
368
|
-
file: writtenPath(host, configFile),
|
|
369
|
-
text: `${JSON.stringify({ extends: configFile, compilerOptions: { paths } }, null, 2)}\n`,
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return found;
|
|
374
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { SETUP_FAILURE_PREFIX } from "./contract/contract.generated.js";
|
|
2
|
-
/** The failure as the one line of the error stream that names it. */
|
|
3
|
-
export function setupLine(failure) {
|
|
4
|
-
return `${SETUP_FAILURE_PREFIX}${failure.setupClass}: ${failure.detail}`;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* A run that met a setup failure where none may be dropped: in a configuration the
|
|
8
|
-
* configuration document or the scope declares, in a declared consumer, or in every
|
|
9
|
-
* configuration discovery derived. It ends the run with the failure code and no finding
|
|
10
|
-
* list.
|
|
11
|
-
*/
|
|
12
|
-
export class SetupError extends Error {
|
|
13
|
-
failures;
|
|
14
|
-
constructor(failures) {
|
|
15
|
-
super(failures.map(setupLine).join("\n"));
|
|
16
|
-
this.name = "SetupError";
|
|
17
|
-
this.failures = failures;
|
|
18
|
-
}
|
|
19
|
-
}
|
package/dist/src/test-joins.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The test files a derived matrix holds although no configuration's file list names them.
|
|
3
|
-
* The test runner compiles such a file with the options of the nearest compiler
|
|
4
|
-
* configuration at or above it, so the file joins that configuration's program as a file
|
|
5
|
-
* its list names, unless a `package.json` below that configuration's directory makes the
|
|
6
|
-
* file another package's, which its own test runner compiles.
|
|
7
|
-
*/
|
|
8
|
-
import { sourcePaths } from "./file-facts.js";
|
|
9
|
-
import { ancestors, dirnamePath, joinPath } from "./paths.js";
|
|
10
|
-
import { writtenPath } from "./workspace-programs.js";
|
|
11
|
-
import { bytewise } from "./text/compare.js";
|
|
12
|
-
import { holdsManifest } from "./fs/manifest.js";
|
|
13
|
-
const PREFERRED = "/tsconfig.json";
|
|
14
|
-
/** The configurations of one directory in the order a file joins them: `tsconfig.json` first. */
|
|
15
|
-
function byPreference(a, b) {
|
|
16
|
-
const first = a.endsWith(PREFERRED) ? 0 : 1;
|
|
17
|
-
const second = b.endsWith(PREFERRED) ? 0 : 1;
|
|
18
|
-
return first - second || bytewise(a, b);
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Per configuration of `configFiles`, the absolute paths of the test files that join it:
|
|
22
|
-
* each file below `root` a pattern of `patterns` names, that no configuration's file list
|
|
23
|
-
* holds, joins the configuration nearest at or above its directory when no `package.json`
|
|
24
|
-
* sits between them. A configuration the compiler cannot read lists nothing and is joined
|
|
25
|
-
* by nothing.
|
|
26
|
-
*/
|
|
27
|
-
export function joinedTestFiles(engine, host, root, configFiles, patterns) {
|
|
28
|
-
const listed = new Set();
|
|
29
|
-
const byDir = new Map();
|
|
30
|
-
for (const configFile of configFiles) {
|
|
31
|
-
let fileNames;
|
|
32
|
-
try {
|
|
33
|
-
fileNames = engine.parseConfigFile(configFile).fileNames;
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
fileNames.forEach((name) => listed.add(name));
|
|
39
|
-
const dir = dirnamePath(configFile);
|
|
40
|
-
byDir.set(dir, [...(byDir.get(dir) ?? []), configFile].sort(byPreference));
|
|
41
|
-
}
|
|
42
|
-
const joins = new Map();
|
|
43
|
-
for (const path of sourcePaths(host, root)) {
|
|
44
|
-
const file = joinPath(root, path);
|
|
45
|
-
if (listed.has(file) || !patterns.some((pattern) => pattern.test(path))) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
for (const dir of ancestors(dirnamePath(file), root)) {
|
|
49
|
-
const [nearest] = byDir.get(dir) ?? [];
|
|
50
|
-
if (nearest !== undefined) {
|
|
51
|
-
joins.set(nearest, [...(joins.get(nearest) ?? []), file]);
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
if (holdsManifest(host, dir)) {
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return joins;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* How the snapshot reads each configuration a test file joins: the program `programs`
|
|
63
|
-
* describes with the files added to its root files, or a configuration only the snapshot
|
|
64
|
-
* holds that extends the one `programs` writes, or the configuration itself, and lists
|
|
65
|
-
* every file the configuration lists and the joined ones.
|
|
66
|
-
*/
|
|
67
|
-
export function withJoinedTests(engine, host, programs, joins) {
|
|
68
|
-
const found = new Map(programs);
|
|
69
|
-
for (const [configFile, files] of joins) {
|
|
70
|
-
const program = programs.get(configFile);
|
|
71
|
-
if (program?.kind === "program") {
|
|
72
|
-
found.set(configFile, {
|
|
73
|
-
kind: "program",
|
|
74
|
-
params: {
|
|
75
|
-
...program.params,
|
|
76
|
-
rootFiles: [...(program.params.rootFiles ?? []), ...files],
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
let listed;
|
|
82
|
-
try {
|
|
83
|
-
listed =
|
|
84
|
-
program?.kind === "configuration"
|
|
85
|
-
? engine.parseConfigJson(JSON.parse(program.text), program.file).fileNames
|
|
86
|
-
: engine.parseConfigFile(configFile).fileNames;
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
const value = program?.kind === "configuration"
|
|
92
|
-
? { ...JSON.parse(program.text), files: [...listed, ...files] }
|
|
93
|
-
: { extends: configFile, files: [...listed, ...files] };
|
|
94
|
-
found.set(configFile, {
|
|
95
|
-
kind: "configuration",
|
|
96
|
-
file: program?.kind === "configuration" ? program.file : writtenPath(host, configFile),
|
|
97
|
-
text: `${JSON.stringify({ ...value, include: [] }, null, 2)}\n`,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
return found;
|
|
101
|
-
}
|
package/src/base-url.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { resolvePath } from "./paths.ts";
|
|
2
|
-
import type { Engine } from "./session.ts";
|
|
3
|
-
|
|
4
|
-
type CompilerOptions = ReturnType<Engine["parseConfigFile"]>["options"];
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The `paths` one configuration's resolved options map under the compilers before version
|
|
8
|
-
* 7, each target absolute: a target is read against the effective `baseUrl`, and a specifier
|
|
9
|
-
* no other pattern maps is looked up below it. Undefined where no `baseUrl` is set, so the
|
|
10
|
-
* options' own `paths` stand. Version 7 reads no `baseUrl`:
|
|
11
|
-
* https://github.com/microsoft/TypeScript/issues/62207
|
|
12
|
-
*/
|
|
13
|
-
export function baseUrlPaths(options: CompilerOptions): Record<string, string[]> | undefined {
|
|
14
|
-
const baseUrl: unknown = Reflect.get(options, "baseUrl");
|
|
15
|
-
if (typeof baseUrl !== "string") {
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
return Object.fromEntries(
|
|
19
|
-
Object.entries({ "*": ["*"], ...options.paths }).map(([key, targets]) => [
|
|
20
|
-
key,
|
|
21
|
-
targets.map((target) => resolvePath(baseUrl, target)),
|
|
22
|
-
]),
|
|
23
|
-
);
|
|
24
|
-
}
|