@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
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
* written for the runner, as one that imports it is.
|
|
8
8
|
*/
|
|
9
9
|
import { isAsExpression, isBinaryExpression, isCallExpression, isExportAssignment, isExpressionStatement, isIdentifier, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, SyntaxKind, } from "@typescript/native/ast";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { filesIn } from "
|
|
14
|
-
import { holdsManifest, INSTALLED_PACKAGES } from "
|
|
10
|
+
import { isRecord } from "../json-document.js";
|
|
11
|
+
import { ancestors, dirnamePath, joinPath } from "../paths.js";
|
|
12
|
+
import { UNANSWERED } from "../query.js";
|
|
13
|
+
import { filesIn } from "../fs/tree.js";
|
|
14
|
+
import { holdsManifest, INSTALLED_PACKAGES } from "../fs/manifest.js";
|
|
15
|
+
import { isTargetConfiguration } from "./discover.js";
|
|
15
16
|
/** The test runner whose configuration injects the globals, and the `types` entry declaring them. */
|
|
16
17
|
export const GLOBALS_RUNNER = "vitest";
|
|
17
18
|
const GLOBALS_TYPES = "vitest/globals";
|
|
@@ -117,67 +118,61 @@ function typesOf(value) {
|
|
|
117
118
|
return Array.isArray(value) && value.every((one) => typeof one === "string") ? value : undefined;
|
|
118
119
|
}
|
|
119
120
|
/**
|
|
120
|
-
*
|
|
121
|
-
* runner configuration injects
|
|
122
|
-
* `programs` reads it, else as itself, with the globals' declarations added to its `types`.
|
|
123
|
-
* A configuration the compiler cannot read is left for its project to refuse.
|
|
121
|
+
* The plans with the globals' declarations added to the `types` of each target configuration
|
|
122
|
+
* whose nearest manifest's runner configuration injects them and that can resolve them.
|
|
124
123
|
*/
|
|
125
|
-
export function
|
|
126
|
-
const found = new Map(programs);
|
|
124
|
+
export function testGlobals(host, parse, plans) {
|
|
127
125
|
const injects = new Map();
|
|
128
|
-
|
|
129
|
-
const dir = manifestDir(host, configFile);
|
|
130
|
-
if (
|
|
131
|
-
|
|
126
|
+
return plans.map((plan) => {
|
|
127
|
+
const dir = manifestDir(host, plan.configFile);
|
|
128
|
+
if (!isTargetConfiguration(plan) ||
|
|
129
|
+
dir === undefined ||
|
|
130
|
+
!globalsInstalled(host, plan.configFile)) {
|
|
131
|
+
return plan;
|
|
132
132
|
}
|
|
133
133
|
if (!injects.has(dir)) {
|
|
134
134
|
injects.set(dir, injectsGlobals(host, parse, dir));
|
|
135
135
|
}
|
|
136
|
+
const base = typesOf(plan.options.types) ?? [];
|
|
137
|
+
const { build } = plan;
|
|
136
138
|
if (injects.get(dir) !== true) {
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
compilerOptions: { ...held.params.compilerOptions, types: [...listed, GLOBALS_TYPES] },
|
|
139
|
+
return plan;
|
|
140
|
+
}
|
|
141
|
+
if (build.kind === "program") {
|
|
142
|
+
const listed = typesOf(build.params.compilerOptions.types) ?? base;
|
|
143
|
+
return listed.includes(GLOBALS_TYPES)
|
|
144
|
+
? plan
|
|
145
|
+
: {
|
|
146
|
+
...plan,
|
|
147
|
+
build: {
|
|
148
|
+
kind: "program",
|
|
149
|
+
params: {
|
|
150
|
+
...build.params,
|
|
151
|
+
compilerOptions: {
|
|
152
|
+
...build.params.compilerOptions,
|
|
153
|
+
types: [...listed, GLOBALS_TYPES],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
155
156
|
},
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
continue;
|
|
157
|
+
};
|
|
159
158
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
written = JSON.parse(held.text);
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const options = (written["compilerOptions"] ?? {});
|
|
159
|
+
const written = build.kind === "configuration" ? build.value : { extends: plan.configFile };
|
|
160
|
+
const held = written["compilerOptions"];
|
|
161
|
+
const options = isRecord(held) ? held : {};
|
|
170
162
|
const listed = typesOf(options["types"]) ?? base;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
163
|
+
return listed.includes(GLOBALS_TYPES)
|
|
164
|
+
? plan
|
|
165
|
+
: {
|
|
166
|
+
...plan,
|
|
167
|
+
build: {
|
|
168
|
+
kind: "configuration",
|
|
169
|
+
value: {
|
|
170
|
+
...written,
|
|
171
|
+
compilerOptions: { ...options, types: [...listed, GLOBALS_TYPES] },
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
});
|
|
181
176
|
}
|
|
182
177
|
/**
|
|
183
178
|
* Whether one file names a global the runner injects, which is how a file written for the
|
|
@@ -0,0 +1,82 @@
|
|
|
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 { bytewise } from "../text/compare.js";
|
|
11
|
+
import { holdsManifest } from "../fs/manifest.js";
|
|
12
|
+
const PREFERRED = "/tsconfig.json";
|
|
13
|
+
/** The configurations of one directory in the order a file joins them: `tsconfig.json` first. */
|
|
14
|
+
function byPreference(a, b) {
|
|
15
|
+
const first = a.endsWith(PREFERRED) ? 0 : 1;
|
|
16
|
+
const second = b.endsWith(PREFERRED) ? 0 : 1;
|
|
17
|
+
return first - second || bytewise(a, b);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Per configuration of `configurations`, the absolute paths of the test files that join it:
|
|
21
|
+
* each file below `root` a pattern of `patterns` names, that no configuration's file list
|
|
22
|
+
* holds, joins the configuration nearest at or above its directory when no `package.json`
|
|
23
|
+
* sits between them.
|
|
24
|
+
*/
|
|
25
|
+
export function joinedTestFiles(host, root, configurations, patterns) {
|
|
26
|
+
const listed = new Set();
|
|
27
|
+
const byDir = new Map();
|
|
28
|
+
for (const { configFile, parsed } of configurations) {
|
|
29
|
+
parsed.fileNames.forEach((name) => listed.add(name));
|
|
30
|
+
const dir = dirnamePath(configFile);
|
|
31
|
+
byDir.set(dir, [...(byDir.get(dir) ?? []), configFile].sort(byPreference));
|
|
32
|
+
}
|
|
33
|
+
const joins = new Map();
|
|
34
|
+
for (const path of sourcePaths(host, root)) {
|
|
35
|
+
const file = joinPath(root, path);
|
|
36
|
+
if (listed.has(file) || !patterns.some((pattern) => pattern.test(path))) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
for (const dir of ancestors(dirnamePath(file), root)) {
|
|
40
|
+
const [nearest] = byDir.get(dir) ?? [];
|
|
41
|
+
if (nearest !== undefined) {
|
|
42
|
+
joins.set(nearest, [...(joins.get(nearest) ?? []), file]);
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
if (holdsManifest(host, dir)) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return joins;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The plans with each joined test file added to the configuration it joins: to a described
|
|
54
|
+
* program's root files, or to the file list of a configuration only the snapshot holds, which
|
|
55
|
+
* lists every file the configuration lists and the joined ones.
|
|
56
|
+
*/
|
|
57
|
+
export function joinedTests(plans, joins) {
|
|
58
|
+
return plans.map((plan) => {
|
|
59
|
+
const files = joins.get(plan.configFile);
|
|
60
|
+
const { build } = plan;
|
|
61
|
+
if (files === undefined) {
|
|
62
|
+
return plan;
|
|
63
|
+
}
|
|
64
|
+
if (build.kind === "program") {
|
|
65
|
+
return {
|
|
66
|
+
...plan,
|
|
67
|
+
build: {
|
|
68
|
+
kind: "program",
|
|
69
|
+
params: { ...build.params, rootFiles: [...(build.params.rootFiles ?? []), ...files] },
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const written = build.kind === "configuration" ? build.value : { extends: plan.configFile };
|
|
74
|
+
return {
|
|
75
|
+
...plan,
|
|
76
|
+
build: {
|
|
77
|
+
kind: "configuration",
|
|
78
|
+
value: { ...written, files: [...plan.parsed.fileNames, ...files], include: [] },
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* workspace imports, so only its commands are entry points.
|
|
7
7
|
*/
|
|
8
8
|
import { emittedFrom } from "./emit-map.js";
|
|
9
|
-
import { readManifest } from "
|
|
10
|
-
import { joinPath, relativePath } from "
|
|
11
|
-
import { MANIFEST } from "
|
|
9
|
+
import { readManifest } from "../manifest.js";
|
|
10
|
+
import { joinPath, relativePath } from "../paths.js";
|
|
11
|
+
import { MANIFEST } from "../fs/manifest.js";
|
|
12
12
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
13
13
|
const SUBPATH_WILDCARD = "*";
|
|
14
14
|
/** The paths one written target stands for in its member's sources, itself included. */
|
|
@@ -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";
|