@cplieger/deadset-ts 8.0.0-dev.8 → 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/src/analysis.js +84 -288
- package/dist/src/configuration-files.js +2 -9
- package/dist/src/consumers.js +1 -28
- package/dist/src/contract/contract.generated.js +20 -10
- package/dist/src/conventions.js +3 -8
- package/dist/src/failure.js +36 -0
- package/dist/src/fs/document.js +21 -28
- package/dist/src/fs/manifest.js +7 -0
- 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/run.js +20 -26
- package/dist/src/scope.js +11 -19
- package/dist/src/session.js +22 -28
- package/dist/src/source-files.js +1 -1
- package/dist/src/type-errors.js +11 -216
- package/dist/src/verbs/analyze.js +90 -109
- package/dist/src/verbs/describe.js +5 -12
- package/dist/src/verbs/version.js +12 -2
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +68 -437
- package/src/configuration-files.ts +8 -10
- package/src/consumers.ts +2 -53
- package/src/contract/contract.generated.ts +20 -10
- package/src/conventions.ts +6 -12
- package/src/failure.ts +63 -0
- package/src/fs/document.ts +23 -27
- package/src/fs/manifest.ts +8 -0
- 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/run.ts +26 -25
- package/src/scope.ts +15 -21
- package/src/session.ts +52 -53
- package/src/source-files.ts +1 -1
- package/src/type-errors.ts +18 -288
- package/src/verbs/analyze.ts +129 -136
- package/src/verbs/describe.ts +4 -11
- 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
|
@@ -16,13 +16,14 @@ import type {
|
|
|
16
16
|
} from "@typescript/native/sync";
|
|
17
17
|
import { isStringLiteralLikeNode } from "@typescript/native/ast";
|
|
18
18
|
import type { StringLiteralLikeNode } from "@typescript/native/ast";
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
22
|
-
import type { Engine } from "./session.ts";
|
|
19
|
+
import type { Host } from "../host.ts";
|
|
20
|
+
import { dirnamePath, resolvePath } from "../paths.ts";
|
|
21
|
+
import type { Engine, ProgramBuild } from "../session.ts";
|
|
23
22
|
import type { WorkspaceResolver } from "./workspace-resolution.ts";
|
|
24
|
-
import { bytewise } from "
|
|
25
|
-
import { PRODUCT } from "
|
|
23
|
+
import { bytewise } from "../text/compare.ts";
|
|
24
|
+
import { PRODUCT } from "../product.ts";
|
|
25
|
+
import type { Parsed } from "./discover.ts";
|
|
26
|
+
import type { Build, CompilerOptions } from "./plan.ts";
|
|
26
27
|
|
|
27
28
|
/** One member import no member source answers for. */
|
|
28
29
|
interface UnresolvedImport {
|
|
@@ -45,32 +46,33 @@ export interface MemberReading {
|
|
|
45
46
|
readonly componentsUnread: string | undefined;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
| { readonly kind: "program"; readonly params: CreateSnapshotProgramParams }
|
|
51
|
-
/** A configuration only the snapshot holds, at a path no file has. */
|
|
52
|
-
| { readonly kind: "configuration"; readonly file: string; readonly text: string };
|
|
49
|
+
/** One configuration as a written configuration or a described program. */
|
|
50
|
+
type Written = Exclude<Build, { readonly kind: "project" }>;
|
|
53
51
|
|
|
54
52
|
/** The programs one run builds instead of opening projects, with what reading them did. */
|
|
55
53
|
interface WorkspacePrograms {
|
|
56
54
|
/** Per configuration that imports a member, how the snapshot reads it. */
|
|
57
|
-
readonly programs: ReadonlyMap<string,
|
|
55
|
+
readonly programs: ReadonlyMap<string, Written>;
|
|
58
56
|
readonly readings: readonly MemberReading[];
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
/** One configuration the rounds read: its parse and the options the plan builds it with. */
|
|
60
|
+
export interface PlannedConfiguration {
|
|
61
|
+
readonly configFile: string;
|
|
62
|
+
readonly parsed: Parsed;
|
|
63
|
+
readonly options: CompilerOptions;
|
|
64
|
+
}
|
|
62
65
|
|
|
63
66
|
/** The most questions one round trip carries. */
|
|
64
67
|
const BATCH = 2048;
|
|
65
68
|
|
|
66
69
|
/**
|
|
67
|
-
* The options a configuration's program is built with:
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* the compiler refuses under such a layout.
|
|
70
|
+
* The options a configuration's program is built with: the plan's, less the ones that lay
|
|
71
|
+
* out an emitted program's inputs and outputs. The analysis emits nothing, and a member's
|
|
72
|
+
* source is outside the importer's root directory by construction, which the compiler
|
|
73
|
+
* refuses under such a layout.
|
|
72
74
|
*/
|
|
73
|
-
function analysisOptions(
|
|
75
|
+
function analysisOptions(options: CompilerOptions): CreateSnapshotProgramParams["compilerOptions"] {
|
|
74
76
|
const {
|
|
75
77
|
composite,
|
|
76
78
|
rootDir: _rootDir,
|
|
@@ -78,10 +80,8 @@ function analysisOptions(parsed: Parsed): CreateSnapshotProgramParams["compilerO
|
|
|
78
80
|
declarationDir: _declarationDir,
|
|
79
81
|
tsBuildInfoFile: _tsBuildInfoFile,
|
|
80
82
|
...kept
|
|
81
|
-
} =
|
|
82
|
-
|
|
83
|
-
const options = paths === undefined ? kept : { ...kept, paths };
|
|
84
|
-
return composite === true ? { ...options, declaration: true } : options;
|
|
83
|
+
} = options;
|
|
84
|
+
return composite === true ? { ...kept, declaration: true } : kept;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/** The conditions an `exports` lookup under one configuration and one resolution mode reads. */
|
|
@@ -103,9 +103,7 @@ function resolutionMode(kind: ModuleKind): ResolutionMode | undefined {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
/** One configuration's state across the rounds. */
|
|
106
|
-
interface Reading {
|
|
107
|
-
readonly configFile: string;
|
|
108
|
-
readonly parsed: Parsed;
|
|
106
|
+
interface Reading extends PlannedConfiguration {
|
|
109
107
|
readonly entries: ModuleResolutionEntry[];
|
|
110
108
|
readonly seen: Set<string>;
|
|
111
109
|
/** Per member specifier, every file an import of it is read as. */
|
|
@@ -149,16 +147,17 @@ function configurationOf(
|
|
|
149
147
|
engine: Engine,
|
|
150
148
|
host: Host,
|
|
151
149
|
reading: Reading,
|
|
152
|
-
):
|
|
150
|
+
): Written | { readonly kind: "unread"; readonly reason: string } {
|
|
153
151
|
const reason = unstatable(reading);
|
|
154
152
|
if (reason !== undefined) {
|
|
155
153
|
return { kind: "unread", reason };
|
|
156
154
|
}
|
|
157
|
-
const { options
|
|
155
|
+
const { options } = reading;
|
|
156
|
+
const references = reading.parsed.projectReferences ?? [];
|
|
158
157
|
const raw: unknown = (options as Record<string, unknown>)["pathsBasePath"];
|
|
159
158
|
const base = typeof raw === "string" ? raw : dirnamePath(reading.configFile);
|
|
160
159
|
const paths: Record<string, string[]> = {};
|
|
161
|
-
for (const [key, targets] of Object.entries(
|
|
160
|
+
for (const [key, targets] of Object.entries(options.paths ?? {})) {
|
|
162
161
|
paths[key] = targets.map((target) => resolvePath(base, target));
|
|
163
162
|
}
|
|
164
163
|
for (const entry of reading.entries) {
|
|
@@ -204,7 +203,7 @@ function configurationOf(
|
|
|
204
203
|
};
|
|
205
204
|
}
|
|
206
205
|
}
|
|
207
|
-
return { kind: "configuration",
|
|
206
|
+
return { kind: "configuration", value };
|
|
208
207
|
}
|
|
209
208
|
|
|
210
209
|
/** The program one configuration is built as, under the answers it holds so far. */
|
|
@@ -212,7 +211,7 @@ function programOf(
|
|
|
212
211
|
engine: Engine,
|
|
213
212
|
reading: Reading,
|
|
214
213
|
): { readonly params: CreateSnapshotProgramParams; readonly resolver: ModuleResolver } {
|
|
215
|
-
const compilerOptions = analysisOptions(reading.
|
|
214
|
+
const compilerOptions = analysisOptions(reading.options);
|
|
216
215
|
const references = reading.parsed.projectReferences ?? [];
|
|
217
216
|
const resolver = engine.createModuleResolver(compilerOptions, reading.entries);
|
|
218
217
|
return {
|
|
@@ -338,6 +337,23 @@ type Built =
|
|
|
338
337
|
}
|
|
339
338
|
| { readonly kind: "configuration"; readonly file: string; readonly text: string };
|
|
340
339
|
|
|
340
|
+
function configurationText(value: Readonly<Record<string, unknown>>): string {
|
|
341
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** One configuration value as the snapshot holds it, beside the configuration it stands for. */
|
|
345
|
+
export function writtenConfiguration(
|
|
346
|
+
host: Host,
|
|
347
|
+
configFile: string,
|
|
348
|
+
value: Readonly<Record<string, unknown>>,
|
|
349
|
+
): Extract<ProgramBuild, { readonly kind: "configuration" }> {
|
|
350
|
+
return {
|
|
351
|
+
kind: "configuration",
|
|
352
|
+
file: writtenPath(host, configFile),
|
|
353
|
+
text: configurationText(value),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
341
357
|
/**
|
|
342
358
|
* Answers the member imports of every reading `build` describes, round by round, all
|
|
343
359
|
* the readings still adding answers built in one snapshot per round. A reading `build`
|
|
@@ -393,28 +409,16 @@ function readRounds(
|
|
|
393
409
|
export function workspacePrograms(
|
|
394
410
|
engine: Engine,
|
|
395
411
|
host: Host,
|
|
396
|
-
|
|
412
|
+
configurations: readonly PlannedConfiguration[],
|
|
397
413
|
resolver: WorkspaceResolver,
|
|
398
414
|
): WorkspacePrograms {
|
|
399
|
-
const readings: Reading[] =
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
return [
|
|
408
|
-
{
|
|
409
|
-
configFile,
|
|
410
|
-
parsed,
|
|
411
|
-
entries: [],
|
|
412
|
-
seen: new Set<string>(),
|
|
413
|
-
bound: new Map<string, Set<string>>(),
|
|
414
|
-
unresolved: [],
|
|
415
|
-
},
|
|
416
|
-
];
|
|
417
|
-
});
|
|
415
|
+
const readings: Reading[] = configurations.map((configuration) => ({
|
|
416
|
+
...configuration,
|
|
417
|
+
entries: [],
|
|
418
|
+
seen: new Set<string>(),
|
|
419
|
+
bound: new Map<string, Set<string>>(),
|
|
420
|
+
unresolved: [],
|
|
421
|
+
}));
|
|
418
422
|
readRounds(engine, readings, resolver, (reading) => ({
|
|
419
423
|
kind: "program",
|
|
420
424
|
...programOf(engine, reading),
|
|
@@ -422,10 +426,12 @@ export function workspacePrograms(
|
|
|
422
426
|
if (engine.readsComponents) {
|
|
423
427
|
readRounds(engine, readings, resolver, (reading) => {
|
|
424
428
|
const one = configurationOf(engine, host, reading);
|
|
425
|
-
return one.kind === "configuration"
|
|
429
|
+
return one.kind === "configuration"
|
|
430
|
+
? writtenConfiguration(host, reading.configFile, one.value)
|
|
431
|
+
: undefined;
|
|
426
432
|
});
|
|
427
433
|
}
|
|
428
|
-
const programs = new Map<string,
|
|
434
|
+
const programs = new Map<string, Written>();
|
|
429
435
|
const unread = new Map<string, string>();
|
|
430
436
|
for (const reading of readings) {
|
|
431
437
|
if (reading.entries.length === 0) {
|
|
@@ -7,20 +7,20 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { emittedFrom } from "./emit-map.ts";
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
isAbsolutePath,
|
|
16
|
-
joinPath,
|
|
17
|
-
relativePath,
|
|
18
|
-
resolvePath,
|
|
19
|
-
} from "./paths.ts";
|
|
20
|
-
import { satisfies } from "./version-range.ts";
|
|
10
|
+
import { packageOfSpecifier } from "../dependencies.ts";
|
|
11
|
+
import { gitIgnored } from "../git-ignore.ts";
|
|
12
|
+
import type { Host } from "../host.ts";
|
|
13
|
+
import { ancestors, dirnamePath, joinPath, relativePath, resolvePath } from "../paths.ts";
|
|
14
|
+
import { satisfies } from "../version-range.ts";
|
|
21
15
|
import type { Workspace, WorkspaceMember } from "./workspace.ts";
|
|
22
|
-
import { isRecord } from "
|
|
23
|
-
import {
|
|
16
|
+
import { isRecord } from "../json-document.ts";
|
|
17
|
+
import { MANIFEST } from "../fs/manifest.ts";
|
|
18
|
+
import {
|
|
19
|
+
dependencySpecifiers,
|
|
20
|
+
installedPackage,
|
|
21
|
+
manifestsAbove,
|
|
22
|
+
type ManifestAt,
|
|
23
|
+
} from "./module-lookup.ts";
|
|
24
24
|
|
|
25
25
|
/** What the compiler's own resolution answered for one import. */
|
|
26
26
|
export interface DefaultResolution {
|
|
@@ -45,35 +45,9 @@ export type MemberResolution =
|
|
|
45
45
|
/** The manifest members that name an entry point for the subpath `.` without `exports`. */
|
|
46
46
|
const LEGACY_MEMBERS = ["types", "typings", "module", "main"] as const;
|
|
47
47
|
|
|
48
|
-
/** The dependency members a manifest declares other packages under. */
|
|
49
|
-
const DEPENDENCY_MEMBERS = [
|
|
50
|
-
"dependencies",
|
|
51
|
-
"devDependencies",
|
|
52
|
-
"peerDependencies",
|
|
53
|
-
"optionalDependencies",
|
|
54
|
-
] as const;
|
|
55
|
-
|
|
56
48
|
const SOURCE = /(?<!\.d)\.(?:[mc]?ts|tsx)$/u;
|
|
57
49
|
const OUTPUT = /(?:\.d\.[mc]?ts|\.[mc]?js|\.jsx)$/u;
|
|
58
50
|
|
|
59
|
-
/** The package name a bare specifier names, or `undefined` for any other specifier. */
|
|
60
|
-
export function packageNameOf(specifier: string): string | undefined {
|
|
61
|
-
if (
|
|
62
|
-
specifier === "" ||
|
|
63
|
-
specifier.startsWith(".") ||
|
|
64
|
-
specifier.startsWith("#") ||
|
|
65
|
-
isAbsolutePath(specifier) ||
|
|
66
|
-
specifier.includes(":")
|
|
67
|
-
) {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
const [first, second] = specifier.split("/");
|
|
71
|
-
if (specifier.startsWith("@")) {
|
|
72
|
-
return second === undefined || second === "" ? undefined : `${first ?? ""}/${second}`;
|
|
73
|
-
}
|
|
74
|
-
return first;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
51
|
function inside(dir: string, path: string): boolean {
|
|
78
52
|
return relativePath(dir, path) !== undefined;
|
|
79
53
|
}
|
|
@@ -215,51 +189,32 @@ type Linked =
|
|
|
215
189
|
/** The member imports of one workspace, read from the members' sources. */
|
|
216
190
|
export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceResolver {
|
|
217
191
|
const links = new Map<string, string | undefined>();
|
|
218
|
-
/** The directory `
|
|
192
|
+
/** The directory the package `name` installed for one directory is, links followed. */
|
|
219
193
|
const linkedFrom = (name: string, dir: string): string | undefined => {
|
|
220
194
|
const key = `${name}\u0000${dir}`;
|
|
221
|
-
if (links.has(key)) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const candidate = joinPath(dir, INSTALLED_PACKAGES, name);
|
|
225
|
-
let found: string | undefined;
|
|
226
|
-
if (host.kindOf(candidate) === "absent") {
|
|
227
|
-
const up = dirnamePath(dir);
|
|
228
|
-
found = up === dir ? undefined : linkedFrom(name, up);
|
|
229
|
-
} else {
|
|
195
|
+
if (!links.has(key)) {
|
|
196
|
+
const installed = installedPackage(host, dir, name);
|
|
197
|
+
let found: string | undefined;
|
|
230
198
|
try {
|
|
231
|
-
found = host.realPath(
|
|
199
|
+
found = installed === undefined ? undefined : host.realPath(installed);
|
|
232
200
|
} catch {
|
|
233
201
|
found = undefined;
|
|
234
202
|
}
|
|
203
|
+
links.set(key, found);
|
|
235
204
|
}
|
|
236
|
-
links.
|
|
237
|
-
return found;
|
|
205
|
+
return links.get(key);
|
|
238
206
|
};
|
|
239
207
|
|
|
240
208
|
const root = workspace.members[0]?.dir;
|
|
241
209
|
const ignored = root === undefined ? () => false : gitIgnored(host, root);
|
|
242
|
-
const manifests = new Map<
|
|
243
|
-
string,
|
|
244
|
-
{ dir: string; manifest: Record<string, unknown> } | undefined
|
|
245
|
-
>();
|
|
210
|
+
const manifests = new Map<string, ManifestAt | undefined>();
|
|
246
211
|
/** The nearest manifest at or above one directory, up to the workspace's root. */
|
|
247
|
-
const nearestManifest = (
|
|
248
|
-
dir
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return manifests.get(dir);
|
|
212
|
+
const nearestManifest = (dir: string): ManifestAt | undefined => {
|
|
213
|
+
if (!manifests.has(dir)) {
|
|
214
|
+
const [nearest] = manifestsAbove(host, dir, root ?? dir);
|
|
215
|
+
manifests.set(dir, nearest);
|
|
252
216
|
}
|
|
253
|
-
|
|
254
|
-
const up = dirnamePath(dir);
|
|
255
|
-
const found =
|
|
256
|
-
manifest !== undefined
|
|
257
|
-
? { dir, manifest }
|
|
258
|
-
: up === dir || root === undefined || !inside(root, up)
|
|
259
|
-
? undefined
|
|
260
|
-
: nearestManifest(up);
|
|
261
|
-
manifests.set(dir, found);
|
|
262
|
-
return found;
|
|
217
|
+
return manifests.get(dir);
|
|
263
218
|
};
|
|
264
219
|
|
|
265
220
|
const linkOf = (candidates: readonly WorkspaceMember[], fromDir: string): Linked => {
|
|
@@ -276,11 +231,9 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
276
231
|
// A package below the root that no workspace lists depends on a member as a member does.
|
|
277
232
|
const owner = scope ?? nearestManifest(fromDir);
|
|
278
233
|
const manifest = owner?.manifest;
|
|
279
|
-
const declared =
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return typeof specifier === "string" ? [specifier] : [];
|
|
283
|
-
});
|
|
234
|
+
const declared = (manifest === undefined ? [] : dependencySpecifiers(manifest, name)).filter(
|
|
235
|
+
(specifier) => typeof specifier === "string",
|
|
236
|
+
);
|
|
284
237
|
const matched = candidates.filter((member) =>
|
|
285
238
|
declared.some((specifier) => dependsOn(specifier, member, owner?.dir ?? fromDir)),
|
|
286
239
|
);
|
|
@@ -383,11 +336,11 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
383
336
|
workspace,
|
|
384
337
|
sourceOf,
|
|
385
338
|
names: (specifier) => {
|
|
386
|
-
const name =
|
|
339
|
+
const name = packageOfSpecifier(specifier);
|
|
387
340
|
return name !== undefined && workspace.named.has(name);
|
|
388
341
|
},
|
|
389
342
|
resolve(specifier, fromDir, conditions, answered) {
|
|
390
|
-
const name =
|
|
343
|
+
const name = packageOfSpecifier(specifier);
|
|
391
344
|
const candidates = name === undefined ? undefined : workspace.named.get(name);
|
|
392
345
|
if (name === undefined || candidates === undefined) {
|
|
393
346
|
return { kind: "default" };
|
|
@@ -5,24 +5,26 @@
|
|
|
5
5
|
* the members' manifests name. A target in no workspace reads none of it.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
9
|
-
import type {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import type {
|
|
13
|
-
import {
|
|
8
|
+
import type { Host } from "../host.ts";
|
|
9
|
+
import type { Manifest, ManifestEntry } from "../manifest.ts";
|
|
10
|
+
import { relativePath } from "../paths.ts";
|
|
11
|
+
import type { Engine } from "../session.ts";
|
|
12
|
+
import type { LocatedDiagnostic } from "./diagnostics.ts";
|
|
13
|
+
import type { Build } from "./plan.ts";
|
|
14
|
+
import { findWorkspace, referenceOnlyIn, type ParsedLayout, type Workspace } from "./workspace.ts";
|
|
14
15
|
import { memberEntries, targetManifestIn } from "./workspace-manifests.ts";
|
|
15
16
|
import {
|
|
16
17
|
workspacePrograms,
|
|
17
18
|
type MemberReading,
|
|
18
|
-
type
|
|
19
|
+
type PlannedConfiguration,
|
|
19
20
|
} from "./workspace-programs.ts";
|
|
20
21
|
import { workspaceResolver } from "./workspace-resolution.ts";
|
|
21
22
|
|
|
22
23
|
/** One run's workspace. */
|
|
23
|
-
interface WorkspaceRun {
|
|
24
|
+
export interface WorkspaceRun {
|
|
25
|
+
readonly workspace: Workspace;
|
|
24
26
|
/** Per configuration that imports a member, how the snapshot reads it. */
|
|
25
|
-
readonly programs: ReadonlyMap<string,
|
|
27
|
+
readonly programs: ReadonlyMap<string, Exclude<Build, { readonly kind: "project" }>>;
|
|
26
28
|
/**
|
|
27
29
|
* Per configuration whose component files the run cannot read, the reason, in the
|
|
28
30
|
* order the configurations are named.
|
|
@@ -96,7 +98,7 @@ export function workspaceRun(
|
|
|
96
98
|
engine: Engine,
|
|
97
99
|
host: Host,
|
|
98
100
|
targetRoot: string,
|
|
99
|
-
|
|
101
|
+
configurations: readonly PlannedConfiguration[],
|
|
100
102
|
manifest: Manifest,
|
|
101
103
|
): WorkspaceRun | undefined {
|
|
102
104
|
const workspace = findWorkspace(host, targetRoot, (configFile) => layoutOf(engine, configFile));
|
|
@@ -104,7 +106,7 @@ export function workspaceRun(
|
|
|
104
106
|
return undefined;
|
|
105
107
|
}
|
|
106
108
|
const resolver = workspaceResolver(host, workspace);
|
|
107
|
-
const read = workspacePrograms(engine, host,
|
|
109
|
+
const read = workspacePrograms(engine, host, configurations, resolver);
|
|
108
110
|
const readings = new Map(read.readings.map((reading) => [reading.configFile, reading]));
|
|
109
111
|
const referenceOnly = (
|
|
110
112
|
configFile: string,
|
|
@@ -115,6 +117,7 @@ export function workspaceRun(
|
|
|
115
117
|
new Set([...(readings.get(configFile)?.fileNames ?? []), ...compiled]),
|
|
116
118
|
);
|
|
117
119
|
return {
|
|
120
|
+
workspace,
|
|
118
121
|
programs: read.programs,
|
|
119
122
|
componentsUnread: read.readings.flatMap(({ configFile, componentsUnread }) =>
|
|
120
123
|
componentsUnread === undefined ? [] : [{ configFile, reason: componentsUnread }],
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The workspace a target sits in: the packages `pnpm-workspace.yaml` or a manifest's
|
|
3
|
-
* `workspaces` declares in the nearest directory at or above the target root, up to
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* member is the workspace root or a directory the patterns name that holds a named
|
|
7
|
-
* manifest, never one below `node_modules`.
|
|
3
|
+
* `workspaces` declares in the nearest directory at or above the target root, up to its
|
|
4
|
+
* repository root, where its patterns name the package the target is in, each with the
|
|
5
|
+
* compiler configurations in its directory.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
|
-
import {
|
|
8
|
+
import { isConfigFile } from "./discover.ts";
|
|
9
|
+
import { failureExit } from "../failure.ts";
|
|
11
10
|
import type { EmitLayout } from "./emit-map.ts";
|
|
12
11
|
import { commonDirectory } from "./emit-map.ts";
|
|
13
|
-
import type { Host } from "
|
|
14
|
-
import { ancestors, dirnamePath, joinPath, relativePath } from "
|
|
15
|
-
import { bytewise } from "
|
|
16
|
-
import { isRecord } from "
|
|
17
|
-
import { directoriesIn, filesIn, repositoryOf } from "
|
|
12
|
+
import type { Host } from "../host.ts";
|
|
13
|
+
import { ancestors, dirnamePath, joinPath, relativePath } from "../paths.ts";
|
|
14
|
+
import { bytewise } from "../text/compare.ts";
|
|
15
|
+
import { isRecord } from "../json-document.ts";
|
|
16
|
+
import { directoriesIn, filesIn, repositoryOf } from "../fs/tree.ts";
|
|
18
17
|
import {
|
|
19
18
|
holdsManifest,
|
|
20
19
|
inInstalledPackages,
|
|
21
20
|
INSTALLED_PACKAGES,
|
|
22
21
|
MANIFEST,
|
|
23
22
|
manifestAt,
|
|
24
|
-
} from "
|
|
25
|
-
import { braceExpanded, pathMatches, segmentMatches } from "
|
|
26
|
-
import { yamlKey } from "
|
|
23
|
+
} from "../fs/manifest.ts";
|
|
24
|
+
import { braceExpanded, pathMatches, segmentMatches } from "../text/glob.ts";
|
|
25
|
+
import { yamlKey } from "../text/yaml.ts";
|
|
27
26
|
|
|
28
27
|
/** What one compiler configuration of a member says about where it reads and writes. */
|
|
29
28
|
export interface ParsedLayout {
|
|
@@ -56,6 +55,8 @@ export interface WorkspaceMember {
|
|
|
56
55
|
|
|
57
56
|
/** The workspace one target sits in. */
|
|
58
57
|
export interface Workspace {
|
|
58
|
+
/** The directory that declares the workspace, absolute. */
|
|
59
|
+
readonly root: string;
|
|
59
60
|
/** Every member, the root first, then by directory. */
|
|
60
61
|
readonly members: readonly WorkspaceMember[];
|
|
61
62
|
/** The members one package name names; two members may share a name. */
|
|
@@ -84,9 +85,9 @@ function declarationAt(
|
|
|
84
85
|
if (!Array.isArray(listed) || !listed.every((entry) => typeof entry === "string")) {
|
|
85
86
|
const reason =
|
|
86
87
|
read.kind === "refused" ? read.reason : "packages is not a sequence of strings";
|
|
87
|
-
throw
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
throw failureExit(
|
|
89
|
+
"no-program",
|
|
90
|
+
`${pnpm}: ${reason}; the workspace's packages are read from a sequence of strings: correct the declaration`,
|
|
90
91
|
);
|
|
91
92
|
}
|
|
92
93
|
return { file: pnpm, patterns: listed };
|
|
@@ -98,9 +99,9 @@ function declarationAt(
|
|
|
98
99
|
const declared = manifest["workspaces"];
|
|
99
100
|
const list = isRecord(declared) ? declared["packages"] : declared;
|
|
100
101
|
if (!Array.isArray(list) || !list.every((entry) => typeof entry === "string")) {
|
|
101
|
-
throw
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
throw failureExit(
|
|
103
|
+
"no-program",
|
|
104
|
+
`${joinPath(dir, MANIFEST)}: workspaces is neither an array of strings nor an object whose packages is one: correct the declaration`,
|
|
104
105
|
);
|
|
105
106
|
}
|
|
106
107
|
return { file: joinPath(dir, MANIFEST), patterns: list };
|
|
@@ -291,12 +292,14 @@ function nearestDeclaration(
|
|
|
291
292
|
* from the target root up to its repository root declares one with a member beside
|
|
292
293
|
* its root, or the nearest one does not name the highest package below it, at or
|
|
293
294
|
* above the target root, among its members. `parse` reads one compiler configuration,
|
|
294
|
-
* or answers `undefined` where it does not read.
|
|
295
|
+
* or answers `undefined` where it does not read. `known`, a workspace already read, is the
|
|
296
|
+
* answer where the nearest declaration is its own, so its members are not listed again.
|
|
295
297
|
*/
|
|
296
298
|
export function findWorkspace(
|
|
297
299
|
host: Host,
|
|
298
300
|
targetRoot: string,
|
|
299
301
|
parse: (configFile: string) => ParsedLayout | undefined,
|
|
302
|
+
known?: Workspace,
|
|
300
303
|
): Workspace | undefined {
|
|
301
304
|
const declared = nearestDeclaration(host, targetRoot);
|
|
302
305
|
if (declared === undefined) {
|
|
@@ -308,6 +311,9 @@ export function findWorkspace(
|
|
|
308
311
|
) {
|
|
309
312
|
return undefined;
|
|
310
313
|
}
|
|
314
|
+
if (known?.root === declared.root) {
|
|
315
|
+
return known;
|
|
316
|
+
}
|
|
311
317
|
const members: WorkspaceMember[] = [];
|
|
312
318
|
for (const dir of memberDirectories(host, declared.root, declared.patterns)) {
|
|
313
319
|
const manifest = manifestAt(host, dir);
|
|
@@ -347,6 +353,7 @@ export function findWorkspace(
|
|
|
347
353
|
return found;
|
|
348
354
|
};
|
|
349
355
|
return {
|
|
356
|
+
root: declared.root,
|
|
350
357
|
members,
|
|
351
358
|
named,
|
|
352
359
|
memberOf: (path) => {
|
package/src/outside-tests.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
type SourceFile,
|
|
21
21
|
} from "@typescript/native/ast";
|
|
22
22
|
import { RESOLVED_EXTENSIONS, type ParseFile } from "./configuration-files.ts";
|
|
23
|
-
import { emittedFrom } from "./emit-map.ts";
|
|
23
|
+
import { emittedFrom } from "./load/emit-map.ts";
|
|
24
24
|
import type { Host } from "./host.ts";
|
|
25
25
|
import type { Inventory } from "./inventory.ts";
|
|
26
26
|
import { namesImported } from "./module-declarations.ts";
|
package/src/partial.ts
CHANGED
package/src/run.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CONFIG_MAX_BYTES, SETTINGS } from "./contract/config.generated.ts";
|
|
2
2
|
import { EXIT_FAILURE, EXIT_USAGE } from "./contract/contract.generated.ts";
|
|
3
3
|
import { REPOSITORY_DOCUMENT, type Document, type Inputs } from "./config.ts";
|
|
4
|
-
import {
|
|
5
|
-
import { readTargetDocument, TargetDocumentError } from "./fs/document.ts";
|
|
4
|
+
import { readTargetDocument } from "./fs/document.ts";
|
|
6
5
|
import type { Host } from "./host.ts";
|
|
7
6
|
import { joinPath, resolvePath } from "./paths.ts";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { renderDiagnostic } from "./load/diagnostics.ts";
|
|
8
|
+
import { FailureExit, failureLines, productFault } from "./failure.ts";
|
|
9
|
+
import { readScope, scopeForDir, type Scope } from "./scope.ts";
|
|
10
10
|
import { UsageError } from "./usage.ts";
|
|
11
11
|
import { openEngine, type Engine, type EngineOptions } from "./session.ts";
|
|
12
12
|
import { printConfigVerb } from "./verbs/print-config.ts";
|
|
@@ -135,12 +135,14 @@ function documentAt(host: Host, label: string): Document {
|
|
|
135
135
|
function repositoryAt(host: Host, target: string): Document | undefined {
|
|
136
136
|
const label = joinPath(target, REPOSITORY_DOCUMENT);
|
|
137
137
|
const root = resolvePath(host.workingDirectory(), target);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
const text = readTargetDocument(
|
|
139
|
+
host,
|
|
140
|
+
root,
|
|
141
|
+
REPOSITORY_DOCUMENT,
|
|
142
|
+
label,
|
|
143
|
+
(named, reason) => new UsageError(`${named}: ${reason}`),
|
|
144
|
+
);
|
|
145
|
+
return text === undefined ? undefined : { text, label };
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
/**
|
|
@@ -253,29 +255,28 @@ function invoke(
|
|
|
253
255
|
}
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
/**
|
|
258
|
+
/**
|
|
259
|
+
* Turns one refusal into the exit code the Contract's table gives it. An error no class names
|
|
260
|
+
* is a fault of this analyzer, printed with its stack for the maintainers it asks the user to
|
|
261
|
+
* report it to.
|
|
262
|
+
*/
|
|
257
263
|
function refuse(error: unknown, err: Writer): number {
|
|
258
264
|
if (error instanceof UsageError) {
|
|
259
265
|
diagnose(err, error.message);
|
|
260
266
|
err.write(USAGE);
|
|
261
267
|
return EXIT_USAGE;
|
|
262
268
|
}
|
|
263
|
-
if (error instanceof
|
|
264
|
-
|
|
265
|
-
err.write(`${
|
|
269
|
+
if (!(error instanceof FailureExit)) {
|
|
270
|
+
if (error instanceof Error && error.stack !== undefined) {
|
|
271
|
+
err.write(`${error.stack}\n`);
|
|
266
272
|
}
|
|
267
|
-
|
|
268
|
-
return EXIT_FAILURE;
|
|
273
|
+
return refuse(productFault(`meets an error none of its classes names: ${message(error)}`), err);
|
|
269
274
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
err.write(`${setupLine(failure)}\n`);
|
|
273
|
-
}
|
|
274
|
-
return EXIT_FAILURE;
|
|
275
|
+
for (const diagnostic of error.diagnostics) {
|
|
276
|
+
err.write(`${renderDiagnostic(diagnostic)}\n`);
|
|
275
277
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
return EXIT_FAILURE;
|
|
278
|
+
for (const line of failureLines(error.failures)) {
|
|
279
|
+
err.write(`${line}\n`);
|
|
279
280
|
}
|
|
280
|
-
|
|
281
|
+
return EXIT_FAILURE;
|
|
281
282
|
}
|