@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
|
@@ -7,24 +7,20 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { ModuleKind, ModuleResolutionKind } from "@typescript/native/sync";
|
|
9
9
|
import { isStringLiteralLikeNode } from "@typescript/native/ast";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { PRODUCT } from "./product.js";
|
|
10
|
+
import { dirnamePath, resolvePath } from "../paths.js";
|
|
11
|
+
import { bytewise } from "../text/compare.js";
|
|
12
|
+
import { PRODUCT } from "../product.js";
|
|
14
13
|
/** The most questions one round trip carries. */
|
|
15
14
|
const BATCH = 2048;
|
|
16
15
|
/**
|
|
17
|
-
* The options a configuration's program is built with:
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* the compiler refuses under such a layout.
|
|
16
|
+
* The options a configuration's program is built with: the plan's, less the ones that lay
|
|
17
|
+
* out an emitted program's inputs and outputs. The analysis emits nothing, and a member's
|
|
18
|
+
* source is outside the importer's root directory by construction, which the compiler
|
|
19
|
+
* refuses under such a layout.
|
|
22
20
|
*/
|
|
23
|
-
function analysisOptions(
|
|
24
|
-
const { composite, rootDir: _rootDir, outDir: _outDir, declarationDir: _declarationDir, tsBuildInfoFile: _tsBuildInfoFile, ...kept } =
|
|
25
|
-
|
|
26
|
-
const options = paths === undefined ? kept : { ...kept, paths };
|
|
27
|
-
return composite === true ? { ...options, declaration: true } : options;
|
|
21
|
+
function analysisOptions(options) {
|
|
22
|
+
const { composite, rootDir: _rootDir, outDir: _outDir, declarationDir: _declarationDir, tsBuildInfoFile: _tsBuildInfoFile, ...kept } = options;
|
|
23
|
+
return composite === true ? { ...kept, declaration: true } : kept;
|
|
28
24
|
}
|
|
29
25
|
/** The conditions an `exports` lookup under one configuration and one resolution mode reads. */
|
|
30
26
|
function conditionsOf(parsed, mode) {
|
|
@@ -75,11 +71,12 @@ function configurationOf(engine, host, reading) {
|
|
|
75
71
|
if (reason !== undefined) {
|
|
76
72
|
return { kind: "unread", reason };
|
|
77
73
|
}
|
|
78
|
-
const { options
|
|
74
|
+
const { options } = reading;
|
|
75
|
+
const references = reading.parsed.projectReferences ?? [];
|
|
79
76
|
const raw = options["pathsBasePath"];
|
|
80
77
|
const base = typeof raw === "string" ? raw : dirnamePath(reading.configFile);
|
|
81
78
|
const paths = {};
|
|
82
|
-
for (const [key, targets] of Object.entries(
|
|
79
|
+
for (const [key, targets] of Object.entries(options.paths ?? {})) {
|
|
83
80
|
paths[key] = targets.map((target) => resolvePath(base, target));
|
|
84
81
|
}
|
|
85
82
|
for (const entry of reading.entries) {
|
|
@@ -126,11 +123,11 @@ function configurationOf(engine, host, reading) {
|
|
|
126
123
|
};
|
|
127
124
|
}
|
|
128
125
|
}
|
|
129
|
-
return { kind: "configuration",
|
|
126
|
+
return { kind: "configuration", value };
|
|
130
127
|
}
|
|
131
128
|
/** The program one configuration is built as, under the answers it holds so far. */
|
|
132
129
|
function programOf(engine, reading) {
|
|
133
|
-
const compilerOptions = analysisOptions(reading.
|
|
130
|
+
const compilerOptions = analysisOptions(reading.options);
|
|
134
131
|
const references = reading.parsed.projectReferences ?? [];
|
|
135
132
|
const resolver = engine.createModuleResolver(compilerOptions, reading.entries);
|
|
136
133
|
return {
|
|
@@ -217,6 +214,17 @@ function scan(engine, program, reading, resolver) {
|
|
|
217
214
|
});
|
|
218
215
|
return added;
|
|
219
216
|
}
|
|
217
|
+
function configurationText(value) {
|
|
218
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
219
|
+
}
|
|
220
|
+
/** One configuration value as the snapshot holds it, beside the configuration it stands for. */
|
|
221
|
+
export function writtenConfiguration(host, configFile, value) {
|
|
222
|
+
return {
|
|
223
|
+
kind: "configuration",
|
|
224
|
+
file: writtenPath(host, configFile),
|
|
225
|
+
text: configurationText(value),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
220
228
|
/**
|
|
221
229
|
* Answers the member imports of every reading `build` describes, round by round, all
|
|
222
230
|
* the readings still adding answers built in one snapshot per round. A reading `build`
|
|
@@ -258,27 +266,14 @@ function readRounds(engine, readings, resolver, build) {
|
|
|
258
266
|
* the rounds go on over each reading's configuration, which reads them, for the imports
|
|
259
267
|
* only they make.
|
|
260
268
|
*/
|
|
261
|
-
export function workspacePrograms(engine, host,
|
|
262
|
-
const readings =
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return [];
|
|
270
|
-
}
|
|
271
|
-
return [
|
|
272
|
-
{
|
|
273
|
-
configFile,
|
|
274
|
-
parsed,
|
|
275
|
-
entries: [],
|
|
276
|
-
seen: new Set(),
|
|
277
|
-
bound: new Map(),
|
|
278
|
-
unresolved: [],
|
|
279
|
-
},
|
|
280
|
-
];
|
|
281
|
-
});
|
|
269
|
+
export function workspacePrograms(engine, host, configurations, resolver) {
|
|
270
|
+
const readings = configurations.map((configuration) => ({
|
|
271
|
+
...configuration,
|
|
272
|
+
entries: [],
|
|
273
|
+
seen: new Set(),
|
|
274
|
+
bound: new Map(),
|
|
275
|
+
unresolved: [],
|
|
276
|
+
}));
|
|
282
277
|
readRounds(engine, readings, resolver, (reading) => ({
|
|
283
278
|
kind: "program",
|
|
284
279
|
...programOf(engine, reading),
|
|
@@ -286,7 +281,9 @@ export function workspacePrograms(engine, host, configFiles, resolver) {
|
|
|
286
281
|
if (engine.readsComponents) {
|
|
287
282
|
readRounds(engine, readings, resolver, (reading) => {
|
|
288
283
|
const one = configurationOf(engine, host, reading);
|
|
289
|
-
return one.kind === "configuration"
|
|
284
|
+
return one.kind === "configuration"
|
|
285
|
+
? writtenConfiguration(host, reading.configFile, one.value)
|
|
286
|
+
: undefined;
|
|
290
287
|
});
|
|
291
288
|
}
|
|
292
289
|
const programs = new Map();
|
|
@@ -6,37 +6,17 @@
|
|
|
6
6
|
* the package neither compiles nor writes is read as installed, and the rest is unresolved.
|
|
7
7
|
*/
|
|
8
8
|
import { emittedFrom } from "./emit-map.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
9
|
+
import { packageOfSpecifier } from "../dependencies.js";
|
|
10
|
+
import { gitIgnored } from "../git-ignore.js";
|
|
11
|
+
import { ancestors, dirnamePath, joinPath, relativePath, resolvePath } from "../paths.js";
|
|
12
|
+
import { satisfies } from "../version-range.js";
|
|
13
|
+
import { isRecord } from "../json-document.js";
|
|
14
|
+
import { MANIFEST } from "../fs/manifest.js";
|
|
15
|
+
import { dependencySpecifiers, installedPackage, manifestsAbove, } from "./module-lookup.js";
|
|
14
16
|
/** The manifest members that name an entry point for the subpath `.` without `exports`. */
|
|
15
17
|
const LEGACY_MEMBERS = ["types", "typings", "module", "main"];
|
|
16
|
-
/** The dependency members a manifest declares other packages under. */
|
|
17
|
-
const DEPENDENCY_MEMBERS = [
|
|
18
|
-
"dependencies",
|
|
19
|
-
"devDependencies",
|
|
20
|
-
"peerDependencies",
|
|
21
|
-
"optionalDependencies",
|
|
22
|
-
];
|
|
23
18
|
const SOURCE = /(?<!\.d)\.(?:[mc]?ts|tsx)$/u;
|
|
24
19
|
const OUTPUT = /(?:\.d\.[mc]?ts|\.[mc]?js|\.jsx)$/u;
|
|
25
|
-
/** The package name a bare specifier names, or `undefined` for any other specifier. */
|
|
26
|
-
export function packageNameOf(specifier) {
|
|
27
|
-
if (specifier === "" ||
|
|
28
|
-
specifier.startsWith(".") ||
|
|
29
|
-
specifier.startsWith("#") ||
|
|
30
|
-
isAbsolutePath(specifier) ||
|
|
31
|
-
specifier.includes(":")) {
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
const [first, second] = specifier.split("/");
|
|
35
|
-
if (specifier.startsWith("@")) {
|
|
36
|
-
return second === undefined || second === "" ? undefined : `${first ?? ""}/${second}`;
|
|
37
|
-
}
|
|
38
|
-
return first;
|
|
39
|
-
}
|
|
40
20
|
function inside(dir, path) {
|
|
41
21
|
return relativePath(dir, path) !== undefined;
|
|
42
22
|
}
|
|
@@ -139,46 +119,32 @@ function dependsOn(specifier, member, fromDir) {
|
|
|
139
119
|
/** The member imports of one workspace, read from the members' sources. */
|
|
140
120
|
export function workspaceResolver(host, workspace) {
|
|
141
121
|
const links = new Map();
|
|
142
|
-
/** The directory `
|
|
122
|
+
/** The directory the package `name` installed for one directory is, links followed. */
|
|
143
123
|
const linkedFrom = (name, dir) => {
|
|
144
124
|
const key = `${name}\u0000${dir}`;
|
|
145
|
-
if (links.has(key)) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const candidate = joinPath(dir, INSTALLED_PACKAGES, name);
|
|
149
|
-
let found;
|
|
150
|
-
if (host.kindOf(candidate) === "absent") {
|
|
151
|
-
const up = dirnamePath(dir);
|
|
152
|
-
found = up === dir ? undefined : linkedFrom(name, up);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
125
|
+
if (!links.has(key)) {
|
|
126
|
+
const installed = installedPackage(host, dir, name);
|
|
127
|
+
let found;
|
|
155
128
|
try {
|
|
156
|
-
found = host.realPath(
|
|
129
|
+
found = installed === undefined ? undefined : host.realPath(installed);
|
|
157
130
|
}
|
|
158
131
|
catch {
|
|
159
132
|
found = undefined;
|
|
160
133
|
}
|
|
134
|
+
links.set(key, found);
|
|
161
135
|
}
|
|
162
|
-
links.
|
|
163
|
-
return found;
|
|
136
|
+
return links.get(key);
|
|
164
137
|
};
|
|
165
138
|
const root = workspace.members[0]?.dir;
|
|
166
139
|
const ignored = root === undefined ? () => false : gitIgnored(host, root);
|
|
167
140
|
const manifests = new Map();
|
|
168
141
|
/** The nearest manifest at or above one directory, up to the workspace's root. */
|
|
169
142
|
const nearestManifest = (dir) => {
|
|
170
|
-
if (manifests.has(dir)) {
|
|
171
|
-
|
|
143
|
+
if (!manifests.has(dir)) {
|
|
144
|
+
const [nearest] = manifestsAbove(host, dir, root ?? dir);
|
|
145
|
+
manifests.set(dir, nearest);
|
|
172
146
|
}
|
|
173
|
-
|
|
174
|
-
const up = dirnamePath(dir);
|
|
175
|
-
const found = manifest !== undefined
|
|
176
|
-
? { dir, manifest }
|
|
177
|
-
: up === dir || root === undefined || !inside(root, up)
|
|
178
|
-
? undefined
|
|
179
|
-
: nearestManifest(up);
|
|
180
|
-
manifests.set(dir, found);
|
|
181
|
-
return found;
|
|
147
|
+
return manifests.get(dir);
|
|
182
148
|
};
|
|
183
149
|
const linkOf = (candidates, fromDir) => {
|
|
184
150
|
const name = candidates[0]?.name ?? "";
|
|
@@ -194,11 +160,7 @@ export function workspaceResolver(host, workspace) {
|
|
|
194
160
|
// A package below the root that no workspace lists depends on a member as a member does.
|
|
195
161
|
const owner = scope ?? nearestManifest(fromDir);
|
|
196
162
|
const manifest = owner?.manifest;
|
|
197
|
-
const declared =
|
|
198
|
-
const held = manifest?.[field];
|
|
199
|
-
const specifier = isRecord(held) ? held[name] : undefined;
|
|
200
|
-
return typeof specifier === "string" ? [specifier] : [];
|
|
201
|
-
});
|
|
163
|
+
const declared = (manifest === undefined ? [] : dependencySpecifiers(manifest, name)).filter((specifier) => typeof specifier === "string");
|
|
202
164
|
const matched = candidates.filter((member) => declared.some((specifier) => dependsOn(specifier, member, owner?.dir ?? fromDir)));
|
|
203
165
|
const [one, two] = matched;
|
|
204
166
|
if (one === undefined) {
|
|
@@ -284,11 +246,11 @@ export function workspaceResolver(host, workspace) {
|
|
|
284
246
|
workspace,
|
|
285
247
|
sourceOf,
|
|
286
248
|
names: (specifier) => {
|
|
287
|
-
const name =
|
|
249
|
+
const name = packageOfSpecifier(specifier);
|
|
288
250
|
return name !== undefined && workspace.named.has(name);
|
|
289
251
|
},
|
|
290
252
|
resolve(specifier, fromDir, conditions, answered) {
|
|
291
|
-
const name =
|
|
253
|
+
const name = packageOfSpecifier(specifier);
|
|
292
254
|
const candidates = name === undefined ? undefined : workspace.named.get(name);
|
|
293
255
|
if (name === undefined || candidates === undefined) {
|
|
294
256
|
return { kind: "default" };
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* the files each configuration holds only for their references, and the entry points
|
|
5
5
|
* the members' manifests name. A target in no workspace reads none of it.
|
|
6
6
|
*/
|
|
7
|
-
import { relativePath } from "
|
|
7
|
+
import { relativePath } from "../paths.js";
|
|
8
8
|
import { findWorkspace, referenceOnlyIn } from "./workspace.js";
|
|
9
9
|
import { memberEntries, targetManifestIn } from "./workspace-manifests.js";
|
|
10
10
|
import { workspacePrograms, } from "./workspace-programs.js";
|
|
@@ -42,16 +42,17 @@ function unbuildableReason(reading, referenceOnly, targetRoot) {
|
|
|
42
42
|
* The workspace the target at `targetRoot` sits in, read for the configurations named,
|
|
43
43
|
* or `undefined` where the target sits in none.
|
|
44
44
|
*/
|
|
45
|
-
export function workspaceRun(engine, host, targetRoot,
|
|
45
|
+
export function workspaceRun(engine, host, targetRoot, configurations, manifest) {
|
|
46
46
|
const workspace = findWorkspace(host, targetRoot, (configFile) => layoutOf(engine, configFile));
|
|
47
47
|
if (workspace === undefined) {
|
|
48
48
|
return undefined;
|
|
49
49
|
}
|
|
50
50
|
const resolver = workspaceResolver(host, workspace);
|
|
51
|
-
const read = workspacePrograms(engine, host,
|
|
51
|
+
const read = workspacePrograms(engine, host, configurations, resolver);
|
|
52
52
|
const readings = new Map(read.readings.map((reading) => [reading.configFile, reading]));
|
|
53
53
|
const referenceOnly = (configFile, compiled = []) => referenceOnlyIn(workspace, new Set([...(readings.get(configFile)?.fileNames ?? []), ...compiled]));
|
|
54
54
|
return {
|
|
55
|
+
workspace,
|
|
55
56
|
programs: read.programs,
|
|
56
57
|
componentsUnread: read.readings.flatMap(({ configFile, componentsUnread }) => componentsUnread === undefined ? [] : [{ configFile, reason: componentsUnread }]),
|
|
57
58
|
unbuildable: (configFile) => {
|
|
@@ -1,20 +1,19 @@
|
|
|
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
|
-
import {
|
|
7
|
+
import { isConfigFile } from "./discover.js";
|
|
8
|
+
import { failureExit } from "../failure.js";
|
|
10
9
|
import { commonDirectory } from "./emit-map.js";
|
|
11
|
-
import { ancestors, dirnamePath, joinPath, relativePath } from "
|
|
12
|
-
import { bytewise } from "
|
|
13
|
-
import { isRecord } from "
|
|
14
|
-
import { directoriesIn, filesIn, repositoryOf } from "
|
|
15
|
-
import { holdsManifest, inInstalledPackages, INSTALLED_PACKAGES, MANIFEST, manifestAt, } from "
|
|
16
|
-
import { braceExpanded, pathMatches, segmentMatches } from "
|
|
17
|
-
import { yamlKey } from "
|
|
10
|
+
import { ancestors, dirnamePath, joinPath, relativePath } from "../paths.js";
|
|
11
|
+
import { bytewise } from "../text/compare.js";
|
|
12
|
+
import { isRecord } from "../json-document.js";
|
|
13
|
+
import { directoriesIn, filesIn, repositoryOf } from "../fs/tree.js";
|
|
14
|
+
import { holdsManifest, inInstalledPackages, INSTALLED_PACKAGES, MANIFEST, manifestAt, } from "../fs/manifest.js";
|
|
15
|
+
import { braceExpanded, pathMatches, segmentMatches } from "../text/glob.js";
|
|
16
|
+
import { yamlKey } from "../text/yaml.js";
|
|
18
17
|
const PNPM_WORKSPACE = "pnpm-workspace.yaml";
|
|
19
18
|
/** The patterns one directory declares a workspace with, or `undefined` where it declares none. */
|
|
20
19
|
function declarationAt(host, dir) {
|
|
@@ -27,7 +26,7 @@ function declarationAt(host, dir) {
|
|
|
27
26
|
const listed = read.kind === "value" ? read.value : undefined;
|
|
28
27
|
if (!Array.isArray(listed) || !listed.every((entry) => typeof entry === "string")) {
|
|
29
28
|
const reason = read.kind === "refused" ? read.reason : "packages is not a sequence of strings";
|
|
30
|
-
throw
|
|
29
|
+
throw failureExit("no-program", `${pnpm}: ${reason}; the workspace's packages are read from a sequence of strings: correct the declaration`);
|
|
31
30
|
}
|
|
32
31
|
return { file: pnpm, patterns: listed };
|
|
33
32
|
}
|
|
@@ -38,7 +37,7 @@ function declarationAt(host, dir) {
|
|
|
38
37
|
const declared = manifest["workspaces"];
|
|
39
38
|
const list = isRecord(declared) ? declared["packages"] : declared;
|
|
40
39
|
if (!Array.isArray(list) || !list.every((entry) => typeof entry === "string")) {
|
|
41
|
-
throw
|
|
40
|
+
throw failureExit("no-program", `${joinPath(dir, MANIFEST)}: workspaces is neither an array of strings nor an object whose packages is one: correct the declaration`);
|
|
42
41
|
}
|
|
43
42
|
return { file: joinPath(dir, MANIFEST), patterns: list };
|
|
44
43
|
}
|
|
@@ -201,9 +200,10 @@ function nearestDeclaration(host, targetRoot) {
|
|
|
201
200
|
* from the target root up to its repository root declares one with a member beside
|
|
202
201
|
* its root, or the nearest one does not name the highest package below it, at or
|
|
203
202
|
* above the target root, among its members. `parse` reads one compiler configuration,
|
|
204
|
-
* or answers `undefined` where it does not read.
|
|
203
|
+
* or answers `undefined` where it does not read. `known`, a workspace already read, is the
|
|
204
|
+
* answer where the nearest declaration is its own, so its members are not listed again.
|
|
205
205
|
*/
|
|
206
|
-
export function findWorkspace(host, targetRoot, parse) {
|
|
206
|
+
export function findWorkspace(host, targetRoot, parse, known) {
|
|
207
207
|
const declared = nearestDeclaration(host, targetRoot);
|
|
208
208
|
if (declared === undefined) {
|
|
209
209
|
return undefined;
|
|
@@ -212,6 +212,9 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
212
212
|
!namesDirectory(declared.root, declared.patterns, declared.highestPackage)) {
|
|
213
213
|
return undefined;
|
|
214
214
|
}
|
|
215
|
+
if (known?.root === declared.root) {
|
|
216
|
+
return known;
|
|
217
|
+
}
|
|
215
218
|
const members = [];
|
|
216
219
|
for (const dir of memberDirectories(host, declared.root, declared.patterns)) {
|
|
217
220
|
const manifest = manifestAt(host, dir);
|
|
@@ -249,6 +252,7 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
249
252
|
return found;
|
|
250
253
|
};
|
|
251
254
|
return {
|
|
255
|
+
root: declared.root,
|
|
252
256
|
members,
|
|
253
257
|
named,
|
|
254
258
|
memberOf: (path) => {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { isCallExpression, isExportDeclaration, isImportDeclaration, isNamespaceExport, isNamespaceImport, isNoSubstitutionTemplateLiteral, isStringLiteral, SyntaxKind, } from "@typescript/native/ast";
|
|
10
10
|
import { RESOLVED_EXTENSIONS } from "./configuration-files.js";
|
|
11
|
-
import { emittedFrom } from "./emit-map.js";
|
|
11
|
+
import { emittedFrom } from "./load/emit-map.js";
|
|
12
12
|
import { namesImported } from "./module-declarations.js";
|
|
13
13
|
import { dirnamePath, joinPath, normalizePath, queriedModulePath } from "./paths.js";
|
|
14
14
|
import { renderPosition } from "./position.js";
|
package/dist/src/run.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CONFIG_MAX_BYTES, SETTINGS } from "./contract/config.generated.js";
|
|
2
2
|
import { EXIT_FAILURE, EXIT_USAGE } from "./contract/contract.generated.js";
|
|
3
3
|
import { REPOSITORY_DOCUMENT } from "./config.js";
|
|
4
|
-
import {
|
|
5
|
-
import { readTargetDocument, TargetDocumentError } from "./fs/document.js";
|
|
4
|
+
import { readTargetDocument } from "./fs/document.js";
|
|
6
5
|
import { joinPath, resolvePath } from "./paths.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { renderDiagnostic } from "./load/diagnostics.js";
|
|
7
|
+
import { FailureExit, failureLines, productFault } from "./failure.js";
|
|
8
|
+
import { readScope, scopeForDir } from "./scope.js";
|
|
9
9
|
import { UsageError } from "./usage.js";
|
|
10
10
|
import { openEngine } from "./session.js";
|
|
11
11
|
import { printConfigVerb } from "./verbs/print-config.js";
|
|
@@ -106,13 +106,8 @@ function documentAt(host, label) {
|
|
|
106
106
|
function repositoryAt(host, target) {
|
|
107
107
|
const label = joinPath(target, REPOSITORY_DOCUMENT);
|
|
108
108
|
const root = resolvePath(host.workingDirectory(), target);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return text === undefined ? undefined : { text, label };
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
throw error instanceof TargetDocumentError ? new UsageError(error.message) : error;
|
|
115
|
-
}
|
|
109
|
+
const text = readTargetDocument(host, root, REPOSITORY_DOCUMENT, label, (named, reason) => new UsageError(`${named}: ${reason}`));
|
|
110
|
+
return text === undefined ? undefined : { text, label };
|
|
116
111
|
}
|
|
117
112
|
/**
|
|
118
113
|
* The configuration sources one invocation carries: the repository configuration at
|
|
@@ -202,29 +197,28 @@ function invoke(verb, own, args, streams, openClient) {
|
|
|
202
197
|
return refuse(error, streams.err);
|
|
203
198
|
}
|
|
204
199
|
}
|
|
205
|
-
/**
|
|
200
|
+
/**
|
|
201
|
+
* Turns one refusal into the exit code the Contract's table gives it. An error no class names
|
|
202
|
+
* is a fault of this analyzer, printed with its stack for the maintainers it asks the user to
|
|
203
|
+
* report it to.
|
|
204
|
+
*/
|
|
206
205
|
function refuse(error, err) {
|
|
207
206
|
if (error instanceof UsageError) {
|
|
208
207
|
diagnose(err, error.message);
|
|
209
208
|
err.write(USAGE);
|
|
210
209
|
return EXIT_USAGE;
|
|
211
210
|
}
|
|
212
|
-
if (error instanceof
|
|
213
|
-
|
|
214
|
-
err.write(`${
|
|
211
|
+
if (!(error instanceof FailureExit)) {
|
|
212
|
+
if (error instanceof Error && error.stack !== undefined) {
|
|
213
|
+
err.write(`${error.stack}\n`);
|
|
215
214
|
}
|
|
216
|
-
|
|
217
|
-
return EXIT_FAILURE;
|
|
215
|
+
return refuse(productFault(`meets an error none of its classes names: ${message(error)}`), err);
|
|
218
216
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
err.write(`${setupLine(failure)}\n`);
|
|
222
|
-
}
|
|
223
|
-
return EXIT_FAILURE;
|
|
217
|
+
for (const diagnostic of error.diagnostics) {
|
|
218
|
+
err.write(`${renderDiagnostic(diagnostic)}\n`);
|
|
224
219
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return EXIT_FAILURE;
|
|
220
|
+
for (const line of failureLines(error.failures)) {
|
|
221
|
+
err.write(`${line}\n`);
|
|
228
222
|
}
|
|
229
|
-
|
|
223
|
+
return EXIT_FAILURE;
|
|
230
224
|
}
|
package/dist/src/scope.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SCOPE_SCHEMA } from "./contract/config.generated.js";
|
|
2
2
|
import { dotted, locatedFault, placeIn, readStrict, StrictJSONError } from "./json-document.js";
|
|
3
3
|
import { dirnamePath, isAbsolutePath, joinPath, resolvePath } from "./paths.js";
|
|
4
|
+
import { MARKERS } from "./load/discover.js";
|
|
5
|
+
import { failureExit } from "./failure.js";
|
|
4
6
|
import { message } from "./product.js";
|
|
5
7
|
import { firstRefusal } from "./schema.js";
|
|
6
8
|
import { UsageError } from "./usage.js";
|
|
@@ -14,23 +16,13 @@ const MAX_DOCUMENT_LENGTH = 1 << 20;
|
|
|
14
16
|
* so a document past the bound is past it within these.
|
|
15
17
|
*/
|
|
16
18
|
const MAX_DOCUMENT_BYTES = 3 * (MAX_DOCUMENT_LENGTH + 1);
|
|
17
|
-
/**
|
|
18
|
-
* A scope that cannot be read as one. It ends the run with the failure code: the run
|
|
19
|
-
* could not learn what to analyze, so it produced no answer.
|
|
20
|
-
*/
|
|
21
|
-
export class ScopeError extends Error {
|
|
22
|
-
constructor(message) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.name = "ScopeError";
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
19
|
function refusal(file, place, reason) {
|
|
28
|
-
return new
|
|
20
|
+
return new UsageError(`scope: ${file}: ${place === "" ? "" : `${place}: `}${reason}`);
|
|
29
21
|
}
|
|
30
22
|
/**
|
|
31
23
|
* Decodes the scope document at `file`, held to the Contract's scope schema, a relative
|
|
32
|
-
* path resolved against the document's own directory. A document that cannot be read is
|
|
33
|
-
* a usage error,
|
|
24
|
+
* path resolved against the document's own directory. A document that cannot be read or is
|
|
25
|
+
* refused is a usage error, as any document the invocation names. `workspace` is read by Go consumers
|
|
34
26
|
* alone: a TypeScript project resolves the target through its own compiler configuration.
|
|
35
27
|
*/
|
|
36
28
|
export function readScope(host, file) {
|
|
@@ -43,7 +35,7 @@ export function readScope(host, file) {
|
|
|
43
35
|
throw new UsageError(`scope: ${file}: ${message(error)}`);
|
|
44
36
|
}
|
|
45
37
|
if (text.length > MAX_DOCUMENT_LENGTH) {
|
|
46
|
-
throw new
|
|
38
|
+
throw new UsageError(`scope: ${file} is longer than ${String(MAX_DOCUMENT_LENGTH)} characters`);
|
|
47
39
|
}
|
|
48
40
|
let value;
|
|
49
41
|
try {
|
|
@@ -67,15 +59,15 @@ export function readScope(host, file) {
|
|
|
67
59
|
});
|
|
68
60
|
return { target: moduleOf(declared.target), consumers: (declared.consumers ?? []).map(moduleOf) };
|
|
69
61
|
}
|
|
70
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* The single-package scope one directory is, when no scope document is given. A target that is
|
|
64
|
+
* no directory holds no program.
|
|
65
|
+
*/
|
|
71
66
|
export function scopeForDir(host, dir) {
|
|
72
67
|
const path = resolvePath(host.workingDirectory(), dir);
|
|
73
68
|
const kind = host.kindOf(path);
|
|
74
|
-
if (kind === "absent") {
|
|
75
|
-
throw new ScopeError(`scope: ${path} does not exist`);
|
|
76
|
-
}
|
|
77
69
|
if (kind !== "directory") {
|
|
78
|
-
throw
|
|
70
|
+
throw failureExit("no-program", `the target ${path} ${kind === "absent" ? "does not exist" : "is not a directory"}, so it holds no compiler configuration, no file named ${MARKERS.join(", ")}: name the directory that holds one`);
|
|
79
71
|
}
|
|
80
72
|
return { target: { id: "", path }, consumers: [] };
|
|
81
73
|
}
|
package/dist/src/session.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { API, SymbolFlags } from "@typescript/native/sync";
|
|
2
2
|
import { componentLayer, mapperManifest } from "./component-layer.js";
|
|
3
|
-
import { DiscoveryError } from "./discover.js";
|
|
4
3
|
import { joinPath } from "./paths.js";
|
|
5
4
|
import { queriesOf, UnansweredLog, } from "./query.js";
|
|
6
5
|
import { MANIFEST } from "./fs/manifest.js";
|
|
@@ -253,14 +252,13 @@ function projectsOf(snapshot, built, written) {
|
|
|
253
252
|
return opened;
|
|
254
253
|
}
|
|
255
254
|
/**
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* `first` runs over every opened project before the first visit and `last` after the last,
|
|
261
|
-
* both while the client answers; the snapshot and the client are then released.
|
|
255
|
+
* Opens every project the compiler configurations name in one never updated snapshot of one
|
|
256
|
+
* client, and hands them to `use` while the client answers; the snapshot and the client are
|
|
257
|
+
* then released. A configuration `options.programs` describes is built as that program, or
|
|
258
|
+
* opened from the configuration it writes. One the snapshot holds nothing for has no view.
|
|
262
259
|
*/
|
|
263
|
-
export function
|
|
260
|
+
export function openSession(engine, configFiles, options, use) {
|
|
261
|
+
const programs = options.programs ?? new Map();
|
|
264
262
|
try {
|
|
265
263
|
const built = [];
|
|
266
264
|
const params = [];
|
|
@@ -282,30 +280,13 @@ export function runSession(engine, configFiles, visit, unopened = "refuse", prog
|
|
|
282
280
|
const opened = projectsOf(snapshot, built, written);
|
|
283
281
|
const log = new UnansweredLog();
|
|
284
282
|
const views = [];
|
|
285
|
-
const missing = [];
|
|
286
283
|
for (const configFile of configFiles) {
|
|
287
284
|
const project = opened.get(configFile);
|
|
288
|
-
if (project
|
|
289
|
-
|
|
290
|
-
throw new DiscoveryError(`${configFile} opened no project`, []);
|
|
291
|
-
}
|
|
292
|
-
missing.push(configFile);
|
|
293
|
-
continue;
|
|
285
|
+
if (project !== undefined) {
|
|
286
|
+
views.push(viewOf(project, configFile, engine, log));
|
|
294
287
|
}
|
|
295
|
-
views.push(viewOf(project, configFile, engine, log));
|
|
296
288
|
}
|
|
297
|
-
|
|
298
|
-
configFile: view.configFile,
|
|
299
|
-
fileNames: () => view.ownSourceFiles().map((file) => file.fileName),
|
|
300
|
-
})));
|
|
301
|
-
const projects = views.map((view) => visit(view));
|
|
302
|
-
last();
|
|
303
|
-
return {
|
|
304
|
-
projects,
|
|
305
|
-
unopened: missing,
|
|
306
|
-
timing: engine.getTimingInfo(),
|
|
307
|
-
unanswered: log.questions,
|
|
308
|
-
};
|
|
289
|
+
return use({ views }, () => log.questions);
|
|
309
290
|
}
|
|
310
291
|
finally {
|
|
311
292
|
snapshot.dispose();
|
|
@@ -315,3 +296,16 @@ export function runSession(engine, configFiles, visit, unopened = "refuse", prog
|
|
|
315
296
|
engine.close();
|
|
316
297
|
}
|
|
317
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Runs `visit` over the project {@link openSession} opens for each configuration, and answers
|
|
301
|
+
* in their order; a configuration the snapshot opens nothing for throws before any visit.
|
|
302
|
+
*/
|
|
303
|
+
export function runSession(engine, configFiles, visit) {
|
|
304
|
+
return openSession(engine, configFiles, {}, (opened) => {
|
|
305
|
+
const unopened = configFiles.find((configFile) => !opened.views.some((view) => view.configFile === configFile));
|
|
306
|
+
if (unopened !== undefined) {
|
|
307
|
+
throw new Error(`${unopened} opened no project`);
|
|
308
|
+
}
|
|
309
|
+
return { projects: opened.views.map((view) => visit(view)), timing: engine.getTimingInfo() };
|
|
310
|
+
});
|
|
311
|
+
}
|
package/dist/src/source-files.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* in a document or a string names one: as the file itself, or as a file the
|
|
4
4
|
* compiler emits from it.
|
|
5
5
|
*/
|
|
6
|
-
import { commonDirectory, emittedFrom } from "./emit-map.js";
|
|
6
|
+
import { commonDirectory, emittedFrom } from "./load/emit-map.js";
|
|
7
7
|
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
8
8
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
9
9
|
const SUBPATH_WILDCARD = "*";
|