@cplieger/deadset-ts 7.2.0-dev.4 → 8.0.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/analysis.js +245 -309
- package/dist/src/augmentations.js +124 -18
- package/dist/src/automatic-types.js +170 -0
- package/dist/src/build-scripts.js +425 -0
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +9 -9
- package/dist/src/config.js +6 -81
- package/dist/src/configuration-files.js +78 -188
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/consumers.js +3 -30
- package/dist/src/contextual-uses.js +56 -9
- package/dist/src/contract/config.generated.js +558 -0
- package/dist/src/contract/contract.generated.js +1244 -0
- package/dist/src/contract/report.generated.js +862 -0
- package/dist/src/convention-rows.js +146 -1
- package/dist/src/conventions.js +136 -70
- package/dist/src/decorator.js +21 -18
- package/dist/src/dependencies.js +280 -62
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +9 -18
- package/dist/src/entry-points.js +106 -21
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -40
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +225 -63
- package/dist/src/findings/dependencies-and-module-machinery.js +72 -27
- package/dist/src/findings/emitters.js +6 -6
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +53 -19
- package/dist/src/findings/non-code-artifacts.js +71 -39
- package/dist/src/findings/reads-and-writes.js +16 -13
- package/dist/src/findings/self-check.js +10 -12
- package/dist/src/findings/unused-declarations.js +57 -28
- package/dist/src/findings/visibility-narrowing.js +40 -18
- package/dist/src/findings-pass.js +8 -15
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +72 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/generated-file.js +18 -4
- package/dist/src/git-ignore.js +99 -0
- package/dist/src/graph.js +9 -4
- package/dist/src/html-entries.js +6 -33
- package/dist/src/import-bindings.js +97 -0
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/indexed-access.js +130 -28
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.js +30 -12
- package/dist/src/intra-function-parts.js +341 -69
- package/dist/src/inventory.js +54 -29
- package/dist/src/javascript-file.js +33 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +3 -366
- package/dist/src/load/classify.js +270 -0
- package/dist/src/load/diagnostics.js +80 -0
- package/dist/src/load/discover.js +277 -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 +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +115 -0
- package/dist/src/load/synthesize.js +140 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +88 -61
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +60 -59
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/manifest.js +49 -54
- package/dist/src/matrix.js +94 -13
- package/dist/src/mdx-entries.js +174 -0
- package/dist/src/module-declarations.js +9 -13
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/overrides.js +41 -10
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +26 -15
- package/dist/src/position.js +2 -1
- package/dist/src/print.js +11 -78
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +1 -0
- package/dist/src/ref.js +11 -0
- package/dist/src/references.js +52 -31
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +59 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +245 -727
- package/dist/src/roots.js +374 -116
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -342
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +649 -29
- package/dist/src/session.js +41 -29
- package/dist/src/source-files.js +40 -15
- package/dist/src/suppress-file.js +34 -29
- package/dist/src/suppress-inline.js +21 -4
- package/dist/src/suppress.js +40 -56
- package/dist/src/sweep.js +32 -17
- package/dist/src/symbol-keys.js +105 -6
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-support.js +119 -18
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +54 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/text/yaml.js +393 -0
- package/dist/src/type-errors.js +27 -221
- package/dist/src/type-parameter-reads.js +172 -0
- package/dist/src/unseen-loads.js +100 -0
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +181 -125
- package/dist/src/verbs/describe.js +9 -16
- package/dist/src/verbs/explain.js +14 -9
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +4 -2
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/dist/src/workflow-steps.js +128 -33
- package/jsr.json +1 -1
- package/package.json +5 -4
- package/src/analysis.ts +333 -457
- package/src/augmentations.ts +152 -23
- package/src/automatic-types.ts +228 -0
- package/src/build-scripts.ts +543 -0
- package/src/component-layer.ts +4 -2
- package/src/components.ts +9 -10
- package/src/config.ts +31 -299
- package/src/configuration-files.ts +100 -191
- package/src/configured-declarations.ts +18 -23
- package/src/conformance-record.ts +2 -2
- package/src/consumers.ts +6 -57
- package/src/contextual-uses.ts +64 -12
- package/src/contract/config.generated.ts +818 -0
- package/src/contract/contract.generated.ts +1308 -0
- package/src/contract/report.generated.ts +1237 -0
- package/src/convention-rows.ts +186 -1
- package/src/conventions.ts +166 -90
- package/src/decorator.ts +28 -18
- package/src/dependencies.ts +356 -78
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +11 -20
- package/src/entry-points.ts +124 -28
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +36 -50
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +9 -24
- package/src/finding.ts +24 -9
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +297 -77
- package/src/findings/dependencies-and-module-machinery.ts +90 -31
- package/src/findings/emitter.ts +8 -9
- package/src/findings/emitters.ts +8 -8
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +64 -20
- package/src/findings/non-code-artifacts.ts +88 -50
- package/src/findings/reads-and-writes.ts +20 -16
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +65 -28
- package/src/findings/visibility-narrowing.ts +51 -19
- package/src/findings-pass.ts +10 -19
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +92 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +23 -4
- package/src/git-ignore.ts +122 -0
- package/src/graph.ts +11 -3
- package/src/host.ts +17 -14
- package/src/html-entries.ts +6 -33
- package/src/import-bindings.ts +128 -0
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/indexed-access.ts +152 -30
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.ts +33 -13
- package/src/intra-function-parts.ts +449 -85
- package/src/inventory.ts +73 -27
- package/src/javascript-file.ts +37 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +5 -413
- package/src/load/classify.ts +397 -0
- package/src/load/diagnostics.ts +144 -0
- package/src/load/discover.ts +455 -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 +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/plan.ts +504 -0
- package/src/load/specifiers.ts +168 -0
- package/src/load/synthesize.ts +211 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +127 -80
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +73 -64
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/manifest.ts +81 -75
- package/src/matrix.ts +154 -18
- package/src/mdx-entries.ts +218 -0
- package/src/module-declarations.ts +11 -13
- package/src/outside-tests.ts +1 -1
- package/src/overrides.ts +51 -12
- package/src/partial.ts +3 -2
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -91
- package/src/product.ts +18 -0
- package/src/query.ts +11 -0
- package/src/ref.ts +13 -0
- package/src/references.ts +62 -32
- package/src/report-schema.ts +68 -0
- package/src/report.ts +105 -215
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +283 -1111
- package/src/roots.ts +490 -137
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -387
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +818 -26
- package/src/session.ts +77 -54
- package/src/source-files.ts +67 -17
- package/src/suppress-file.ts +36 -34
- package/src/suppress-inline.ts +20 -3
- package/src/suppress.ts +52 -63
- package/src/sweep.ts +53 -18
- package/src/symbol-keys.ts +131 -7
- package/src/template-field.ts +15 -25
- package/src/test-support.ts +155 -18
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.inputs.json +1522 -0
- package/src/text/named-files.ts +68 -0
- package/src/text/shell.ts +161 -0
- package/src/text/yaml.ts +423 -0
- package/src/type-errors.ts +35 -273
- package/src/type-parameter-reads.ts +227 -0
- package/src/unseen-loads.ts +134 -0
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +245 -161
- package/src/verbs/describe.ts +14 -15
- package/src/verbs/explain.ts +15 -13
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +4 -2
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/src/workflow-steps.ts +149 -34
- package/dist/src/discover.js +0 -347
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/src/discover.ts +0 -510
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
- package/src/setup-failure.ts +0 -39
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which file an import of a workspace package's name is read from
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* the package
|
|
7
|
-
* import nothing answers for is unresolved.
|
|
2
|
+
* Which file an import of a workspace package's name is read from: the package
|
|
3
|
+
* `node_modules` links the importer to or, with no link, the one its manifest depends on.
|
|
4
|
+
* A source file the compiler reaches stands; any other file reads back to its source or to
|
|
5
|
+
* a manifest target that is source, an ignored file to the source its path mirrors, a file
|
|
6
|
+
* the package neither compiles nor writes is read as installed, and the rest is unresolved.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import { emittedFrom } from "./emit-map.ts";
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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";
|
|
14
15
|
import type { Workspace, WorkspaceMember } from "./workspace.ts";
|
|
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";
|
|
15
24
|
|
|
16
25
|
/** What the compiler's own resolution answered for one import. */
|
|
17
26
|
export interface DefaultResolution {
|
|
@@ -36,39 +45,9 @@ export type MemberResolution =
|
|
|
36
45
|
/** The manifest members that name an entry point for the subpath `.` without `exports`. */
|
|
37
46
|
const LEGACY_MEMBERS = ["types", "typings", "module", "main"] as const;
|
|
38
47
|
|
|
39
|
-
/** The dependency members a manifest declares other packages under. */
|
|
40
|
-
const DEPENDENCY_MEMBERS = [
|
|
41
|
-
"dependencies",
|
|
42
|
-
"devDependencies",
|
|
43
|
-
"peerDependencies",
|
|
44
|
-
"optionalDependencies",
|
|
45
|
-
] as const;
|
|
46
|
-
|
|
47
48
|
const SOURCE = /(?<!\.d)\.(?:[mc]?ts|tsx)$/u;
|
|
48
49
|
const OUTPUT = /(?:\.d\.[mc]?ts|\.[mc]?js|\.jsx)$/u;
|
|
49
50
|
|
|
50
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
51
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** The package name a bare specifier names, or `undefined` for any other specifier. */
|
|
55
|
-
export function packageNameOf(specifier: string): string | undefined {
|
|
56
|
-
if (
|
|
57
|
-
specifier === "" ||
|
|
58
|
-
specifier.startsWith(".") ||
|
|
59
|
-
specifier.startsWith("#") ||
|
|
60
|
-
isAbsolutePath(specifier) ||
|
|
61
|
-
specifier.includes(":")
|
|
62
|
-
) {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
const [first, second] = specifier.split("/");
|
|
66
|
-
if (specifier.startsWith("@")) {
|
|
67
|
-
return second === undefined || second === "" ? undefined : `${first ?? ""}/${second}`;
|
|
68
|
-
}
|
|
69
|
-
return first;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
51
|
function inside(dir: string, path: string): boolean {
|
|
73
52
|
return relativePath(dir, path) !== undefined;
|
|
74
53
|
}
|
|
@@ -210,26 +189,32 @@ type Linked =
|
|
|
210
189
|
/** The member imports of one workspace, read from the members' sources. */
|
|
211
190
|
export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceResolver {
|
|
212
191
|
const links = new Map<string, string | undefined>();
|
|
213
|
-
/** The directory `
|
|
192
|
+
/** The directory the package `name` installed for one directory is, links followed. */
|
|
214
193
|
const linkedFrom = (name: string, dir: string): string | undefined => {
|
|
215
194
|
const key = `${name}\u0000${dir}`;
|
|
216
|
-
if (links.has(key)) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const candidate = joinPath(dir, "node_modules", name);
|
|
220
|
-
let found: string | undefined;
|
|
221
|
-
if (host.kindOf(candidate) === "absent") {
|
|
222
|
-
const up = dirnamePath(dir);
|
|
223
|
-
found = up === dir ? undefined : linkedFrom(name, up);
|
|
224
|
-
} else {
|
|
195
|
+
if (!links.has(key)) {
|
|
196
|
+
const installed = installedPackage(host, dir, name);
|
|
197
|
+
let found: string | undefined;
|
|
225
198
|
try {
|
|
226
|
-
found = host.realPath(
|
|
199
|
+
found = installed === undefined ? undefined : host.realPath(installed);
|
|
227
200
|
} catch {
|
|
228
201
|
found = undefined;
|
|
229
202
|
}
|
|
203
|
+
links.set(key, found);
|
|
204
|
+
}
|
|
205
|
+
return links.get(key);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const root = workspace.members[0]?.dir;
|
|
209
|
+
const ignored = root === undefined ? () => false : gitIgnored(host, root);
|
|
210
|
+
const manifests = new Map<string, ManifestAt | undefined>();
|
|
211
|
+
/** The nearest manifest at or above one directory, up to the workspace's root. */
|
|
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);
|
|
230
216
|
}
|
|
231
|
-
|
|
232
|
-
return found;
|
|
217
|
+
return manifests.get(dir);
|
|
233
218
|
};
|
|
234
219
|
|
|
235
220
|
const linkOf = (candidates: readonly WorkspaceMember[], fromDir: string): Linked => {
|
|
@@ -239,18 +224,18 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
239
224
|
const member = candidates.find((one) => one.dir === linked);
|
|
240
225
|
return member === undefined ? { kind: "none" } : { kind: "member", member };
|
|
241
226
|
}
|
|
242
|
-
const scope = workspace.memberOf(joinPath(fromDir,
|
|
227
|
+
const scope = workspace.memberOf(joinPath(fromDir, MANIFEST));
|
|
243
228
|
if (scope?.name === name) {
|
|
244
229
|
return { kind: "member", member: scope };
|
|
245
230
|
}
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
231
|
+
// A package below the root that no workspace lists depends on a member as a member does.
|
|
232
|
+
const owner = scope ?? nearestManifest(fromDir);
|
|
233
|
+
const manifest = owner?.manifest;
|
|
234
|
+
const declared = (manifest === undefined ? [] : dependencySpecifiers(manifest, name)).filter(
|
|
235
|
+
(specifier) => typeof specifier === "string",
|
|
236
|
+
);
|
|
252
237
|
const matched = candidates.filter((member) =>
|
|
253
|
-
declared.some((specifier) => dependsOn(specifier, member,
|
|
238
|
+
declared.some((specifier) => dependsOn(specifier, member, owner?.dir ?? fromDir)),
|
|
254
239
|
);
|
|
255
240
|
const [one, two] = matched;
|
|
256
241
|
if (one === undefined) {
|
|
@@ -265,6 +250,25 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
265
250
|
const compiled = (member: WorkspaceMember, path: string): boolean =>
|
|
266
251
|
member.configurations.some((configuration) => configuration.fileNames.has(path));
|
|
267
252
|
|
|
253
|
+
/**
|
|
254
|
+
* The member's source an ignored output path mirrors: the path below one of its
|
|
255
|
+
* directories, the deepest first, read below the member's own directory as an output
|
|
256
|
+
* directory's tree mirrors its root directory's, which a build leaves in an ignored
|
|
257
|
+
* directory however its configuration writes it.
|
|
258
|
+
*/
|
|
259
|
+
const mirrored = (member: WorkspaceMember, path: string): string | undefined => {
|
|
260
|
+
for (const dir of ancestors(dirnamePath(path), member.dir).filter((at) => at !== member.dir)) {
|
|
261
|
+
const found = emittedFrom(path, { outDir: dir, sourceDirs: [member.dir] }).find(
|
|
262
|
+
(candidate) =>
|
|
263
|
+
SOURCE.test(candidate) && !ignored(candidate) && host.kindOf(candidate) === "file",
|
|
264
|
+
);
|
|
265
|
+
if (found !== undefined) {
|
|
266
|
+
return found;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return undefined;
|
|
270
|
+
};
|
|
271
|
+
|
|
268
272
|
/**
|
|
269
273
|
* The member's source one of its paths is, or is compiled from: a TypeScript source
|
|
270
274
|
* file, the source an output path maps back to, or a file one of the member's
|
|
@@ -286,6 +290,9 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
286
290
|
if (found !== undefined) {
|
|
287
291
|
return found;
|
|
288
292
|
}
|
|
293
|
+
if (ignored(path)) {
|
|
294
|
+
return mirrored(member, path);
|
|
295
|
+
}
|
|
289
296
|
return compiled(member, path) && host.kindOf(path) === "file" ? path : undefined;
|
|
290
297
|
};
|
|
291
298
|
|
|
@@ -329,11 +336,11 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
329
336
|
workspace,
|
|
330
337
|
sourceOf,
|
|
331
338
|
names: (specifier) => {
|
|
332
|
-
const name =
|
|
339
|
+
const name = packageOfSpecifier(specifier);
|
|
333
340
|
return name !== undefined && workspace.named.has(name);
|
|
334
341
|
},
|
|
335
342
|
resolve(specifier, fromDir, conditions, answered) {
|
|
336
|
-
const name =
|
|
343
|
+
const name = packageOfSpecifier(specifier);
|
|
337
344
|
const candidates = name === undefined ? undefined : workspace.named.get(name);
|
|
338
345
|
if (name === undefined || candidates === undefined) {
|
|
339
346
|
return { kind: "default" };
|
|
@@ -352,10 +359,12 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
352
359
|
}
|
|
353
360
|
const { member } = linked;
|
|
354
361
|
// A member no compiler configuration builds is read as the package manager
|
|
355
|
-
// installed it, wherever the compiler's resolution found it
|
|
362
|
+
// installed it, wherever the compiler's resolution found it, unless what it found is
|
|
363
|
+
// a file the tree ignores, which no install wrote.
|
|
356
364
|
if (
|
|
357
365
|
answered !== undefined &&
|
|
358
|
-
(member.configurations.length === 0
|
|
366
|
+
((member.configurations.length === 0 && !ignored(answered.resolvedFileName)) ||
|
|
367
|
+
!inside(member.dir, answered.resolvedFileName))
|
|
359
368
|
) {
|
|
360
369
|
return { kind: "default" };
|
|
361
370
|
}
|
|
@@ -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 { 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.
|
|
@@ -50,11 +52,10 @@ interface WorkspaceRun {
|
|
|
50
52
|
readonly manifest: Manifest;
|
|
51
53
|
/** The entry points the other members' manifests name. */
|
|
52
54
|
readonly entries: readonly ManifestEntry[];
|
|
53
|
-
/** The directory of every member, the target's included, in the workspace's order. */
|
|
54
|
-
readonly memberDirs: readonly string[];
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
/** What one member's configuration file says of its layout, or `undefined` where it does not parse. */
|
|
58
|
+
export function layoutOf(engine: Engine, configFile: string): ParsedLayout | undefined {
|
|
58
59
|
try {
|
|
59
60
|
const parsed = engine.parseConfigFile(configFile);
|
|
60
61
|
return {
|
|
@@ -96,15 +97,16 @@ export function workspaceRun(
|
|
|
96
97
|
engine: Engine,
|
|
97
98
|
host: Host,
|
|
98
99
|
targetRoot: string,
|
|
99
|
-
|
|
100
|
+
configurations: readonly PlannedConfiguration[],
|
|
100
101
|
manifest: Manifest,
|
|
102
|
+
workspace: Workspace | undefined,
|
|
101
103
|
): WorkspaceRun | undefined {
|
|
102
|
-
const workspace = findWorkspace(host, targetRoot, (configFile) => layoutOf(engine, configFile));
|
|
103
104
|
if (workspace === undefined) {
|
|
104
105
|
return undefined;
|
|
105
106
|
}
|
|
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 }],
|
|
@@ -132,7 +135,6 @@ export function workspaceRun(
|
|
|
132
135
|
: !fromExternalLibrary,
|
|
133
136
|
manifest: targetManifestIn(resolver, targetRoot, manifest),
|
|
134
137
|
entries: memberEntries(host, resolver, targetRoot),
|
|
135
|
-
memberDirs: workspace.members.map((member) => member.dir),
|
|
136
138
|
};
|
|
137
139
|
}
|
|
138
140
|
|
|
@@ -1,18 +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 { configFilesIn } 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 { dirnamePath, joinPath, relativePath } from "
|
|
15
|
-
import {
|
|
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, repositoryOf } from "../fs/tree.ts";
|
|
17
|
+
import {
|
|
18
|
+
holdsManifest,
|
|
19
|
+
inInstalledPackages,
|
|
20
|
+
INSTALLED_PACKAGES,
|
|
21
|
+
MANIFEST,
|
|
22
|
+
manifestAt,
|
|
23
|
+
} from "../fs/manifest.ts";
|
|
24
|
+
import { braceExpanded, pathMatches, segmentMatches } from "../text/glob.ts";
|
|
25
|
+
import { yamlKey } from "../text/yaml.ts";
|
|
16
26
|
|
|
17
27
|
/** What one compiler configuration of a member says about where it reads and writes. */
|
|
18
28
|
export interface ParsedLayout {
|
|
@@ -39,12 +49,17 @@ export interface WorkspaceMember {
|
|
|
39
49
|
/** Whether the manifest forbids publishing it, so nothing outside the workspace imports it. */
|
|
40
50
|
readonly private: boolean;
|
|
41
51
|
readonly manifest: Readonly<Record<string, unknown>>;
|
|
42
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* The programs the run forms in its directory, then every configuration file directly in
|
|
54
|
+
* it a derived matrix opens that parses, by file name.
|
|
55
|
+
*/
|
|
43
56
|
readonly configurations: readonly MemberConfiguration[];
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
/** The workspace one target sits in. */
|
|
47
60
|
export interface Workspace {
|
|
61
|
+
/** The directory that declares the workspace, absolute. */
|
|
62
|
+
readonly root: string;
|
|
48
63
|
/** Every member, the root first, then by directory. */
|
|
49
64
|
readonly members: readonly WorkspaceMember[];
|
|
50
65
|
/** The members one package name names; two members may share a name. */
|
|
@@ -56,29 +71,7 @@ export interface Workspace {
|
|
|
56
71
|
memberOf(path: string): WorkspaceMember | undefined;
|
|
57
72
|
}
|
|
58
73
|
|
|
59
|
-
const MANIFEST = "package.json";
|
|
60
74
|
const PNPM_WORKSPACE = "pnpm-workspace.yaml";
|
|
61
|
-
const CONFIG_FILE = /^tsconfig.*\.json$/u;
|
|
62
|
-
|
|
63
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
64
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** One manifest, decoded, or `undefined` where there is none to read. */
|
|
68
|
-
function manifestAt(host: Host, dir: string): Record<string, unknown> | undefined {
|
|
69
|
-
let text: string;
|
|
70
|
-
try {
|
|
71
|
-
text = host.readFile(joinPath(dir, MANIFEST));
|
|
72
|
-
} catch {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
try {
|
|
76
|
-
const value: unknown = JSON.parse(text);
|
|
77
|
-
return isRecord(value) ? value : undefined;
|
|
78
|
-
} catch {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
75
|
|
|
83
76
|
/** The patterns one directory declares a workspace with, or `undefined` where it declares none. */
|
|
84
77
|
function declarationAt(
|
|
@@ -87,14 +80,20 @@ function declarationAt(
|
|
|
87
80
|
): { readonly file: string; readonly patterns: readonly string[] } | undefined {
|
|
88
81
|
const pnpm = joinPath(dir, PNPM_WORKSPACE);
|
|
89
82
|
if (host.kindOf(pnpm) === "file") {
|
|
90
|
-
const read =
|
|
91
|
-
if (read.kind === "
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
const read = yamlKey(host.readFile(pnpm), "packages");
|
|
84
|
+
if (read.kind === "absent") {
|
|
85
|
+
return { file: pnpm, patterns: [] };
|
|
86
|
+
}
|
|
87
|
+
const listed = read.kind === "value" ? read.value : undefined;
|
|
88
|
+
if (!Array.isArray(listed) || !listed.every((entry) => typeof entry === "string")) {
|
|
89
|
+
const reason =
|
|
90
|
+
read.kind === "refused" ? read.reason : "packages is not a sequence of strings";
|
|
91
|
+
throw failureExit(
|
|
92
|
+
"no-program",
|
|
93
|
+
`${pnpm}: ${reason}; the workspace's packages are read from a sequence of strings: correct the declaration`,
|
|
95
94
|
);
|
|
96
95
|
}
|
|
97
|
-
return { file: pnpm, patterns:
|
|
96
|
+
return { file: pnpm, patterns: listed };
|
|
98
97
|
}
|
|
99
98
|
const manifest = manifestAt(host, dir);
|
|
100
99
|
if (manifest === undefined || !Object.hasOwn(manifest, "workspaces")) {
|
|
@@ -103,9 +102,9 @@ function declarationAt(
|
|
|
103
102
|
const declared = manifest["workspaces"];
|
|
104
103
|
const list = isRecord(declared) ? declared["packages"] : declared;
|
|
105
104
|
if (!Array.isArray(list) || !list.every((entry) => typeof entry === "string")) {
|
|
106
|
-
throw
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
throw failureExit(
|
|
106
|
+
"no-program",
|
|
107
|
+
`${joinPath(dir, MANIFEST)}: workspaces is neither an array of strings nor an object whose packages is one: correct the declaration`,
|
|
109
108
|
);
|
|
110
109
|
}
|
|
111
110
|
return { file: joinPath(dir, MANIFEST), patterns: list };
|
|
@@ -120,21 +119,6 @@ function declaresWorkspace(host: Host, dir: string): boolean {
|
|
|
120
119
|
return manifest !== undefined && Object.hasOwn(manifest, "workspaces");
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
/** A pattern with every brace list expanded into its alternatives. */
|
|
124
|
-
function braceExpanded(pattern: string): readonly string[] {
|
|
125
|
-
const open = pattern.indexOf("{");
|
|
126
|
-
const close = open < 0 ? -1 : pattern.indexOf("}", open);
|
|
127
|
-
if (close < 0) {
|
|
128
|
-
return [pattern];
|
|
129
|
-
}
|
|
130
|
-
const before = pattern.slice(0, open);
|
|
131
|
-
const after = pattern.slice(close + 1);
|
|
132
|
-
return pattern
|
|
133
|
-
.slice(open + 1, close)
|
|
134
|
-
.split(",")
|
|
135
|
-
.flatMap((member) => braceExpanded(before + member + after));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
122
|
/**
|
|
139
123
|
* The segments of one pattern below the workspace root, `.` and empty segments
|
|
140
124
|
* dropped and `..` taken back, or `undefined` where it leaves the root.
|
|
@@ -156,56 +140,6 @@ function segmentsOf(pattern: string): readonly string[] | undefined {
|
|
|
156
140
|
return segments;
|
|
157
141
|
}
|
|
158
142
|
|
|
159
|
-
/**
|
|
160
|
-
* Whether one directory name matches one pattern segment: `*` stands for any run of
|
|
161
|
-
* characters and `?` for one, and neither matches a leading dot.
|
|
162
|
-
*/
|
|
163
|
-
function segmentMatches(segment: string, name: string): boolean {
|
|
164
|
-
if (name.startsWith(".") && !segment.startsWith(".")) {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
const source = Array.from(segment)
|
|
168
|
-
.map((character) => {
|
|
169
|
-
if (character === "*") {
|
|
170
|
-
return ".*";
|
|
171
|
-
}
|
|
172
|
-
if (character === "?") {
|
|
173
|
-
return ".";
|
|
174
|
-
}
|
|
175
|
-
return character.replaceAll(/[.+^${}()|[\]\\/]/gu, (c) => `\\${c}`);
|
|
176
|
-
})
|
|
177
|
-
.join("");
|
|
178
|
-
return new RegExp(`^${source}$`, "u").test(name);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/** Whether one path's segments match one pattern's, `**` standing for any run of segments. */
|
|
182
|
-
function pathMatches(pattern: readonly string[], path: readonly string[]): boolean {
|
|
183
|
-
const [head, ...rest] = pattern;
|
|
184
|
-
if (head === undefined) {
|
|
185
|
-
return path.length === 0;
|
|
186
|
-
}
|
|
187
|
-
if (head === "**") {
|
|
188
|
-
return (
|
|
189
|
-
pathMatches(rest, path) ||
|
|
190
|
-
(path.length > 0 && !(path[0] ?? "").startsWith(".") && pathMatches(pattern, path.slice(1)))
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
const [name, ...below] = path;
|
|
194
|
-
return name !== undefined && segmentMatches(head, name) && pathMatches(rest, below);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function subdirectories(host: Host, dir: string): readonly string[] {
|
|
198
|
-
try {
|
|
199
|
-
return host
|
|
200
|
-
.readDirectory(dir)
|
|
201
|
-
.filter((entry) => entry.directory && entry.name !== "node_modules" && entry.name !== ".git")
|
|
202
|
-
.map((entry) => entry.name)
|
|
203
|
-
.sort();
|
|
204
|
-
} catch {
|
|
205
|
-
return [];
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
143
|
/**
|
|
210
144
|
* Every directory below `dir` one pattern names. `**` does not descend into a
|
|
211
145
|
* directory that declares a workspace of its own, whose packages are that
|
|
@@ -219,7 +153,7 @@ function expand(host: Host, dir: string, pattern: readonly string[], into: Set<s
|
|
|
219
153
|
}
|
|
220
154
|
if (head === "**") {
|
|
221
155
|
expand(host, dir, rest, into);
|
|
222
|
-
for (const name of
|
|
156
|
+
for (const name of directoriesIn(host, dir)) {
|
|
223
157
|
if (name.startsWith(".")) {
|
|
224
158
|
continue;
|
|
225
159
|
}
|
|
@@ -230,12 +164,12 @@ function expand(host: Host, dir: string, pattern: readonly string[], into: Set<s
|
|
|
230
164
|
}
|
|
231
165
|
if (!head.includes("*") && !head.includes("?")) {
|
|
232
166
|
const child = joinPath(dir, head);
|
|
233
|
-
if (head !==
|
|
167
|
+
if (head !== INSTALLED_PACKAGES && host.kindOf(child) === "directory") {
|
|
234
168
|
expand(host, child, rest, into);
|
|
235
169
|
}
|
|
236
170
|
return;
|
|
237
171
|
}
|
|
238
|
-
for (const name of
|
|
172
|
+
for (const name of directoriesIn(host, dir)) {
|
|
239
173
|
if (segmentMatches(head, name)) {
|
|
240
174
|
expand(host, joinPath(dir, name), rest, into);
|
|
241
175
|
}
|
|
@@ -277,10 +211,10 @@ function namesDirectory(root: string, patterns: readonly string[], dir: string):
|
|
|
277
211
|
if (below === undefined) {
|
|
278
212
|
return false;
|
|
279
213
|
}
|
|
280
|
-
|
|
281
|
-
if (path.includes("node_modules")) {
|
|
214
|
+
if (inInstalledPackages(below)) {
|
|
282
215
|
return false;
|
|
283
216
|
}
|
|
217
|
+
const path = below.split("/");
|
|
284
218
|
let named = false;
|
|
285
219
|
for (const written of patterns) {
|
|
286
220
|
const negated = written.startsWith("!");
|
|
@@ -314,17 +248,7 @@ function configurationsOf(
|
|
|
314
248
|
dir: string,
|
|
315
249
|
parse: (configFile: string) => ParsedLayout | undefined,
|
|
316
250
|
): readonly MemberConfiguration[] {
|
|
317
|
-
|
|
318
|
-
try {
|
|
319
|
-
names = host
|
|
320
|
-
.readDirectory(dir)
|
|
321
|
-
.filter((entry) => !entry.directory && CONFIG_FILE.test(entry.name))
|
|
322
|
-
.map((entry) => entry.name)
|
|
323
|
-
.sort();
|
|
324
|
-
} catch {
|
|
325
|
-
return [];
|
|
326
|
-
}
|
|
327
|
-
return names.flatMap((name) => {
|
|
251
|
+
return configFilesIn(host, dir).flatMap((name) => {
|
|
328
252
|
const configFile = joinPath(dir, name);
|
|
329
253
|
const parsed = parse(configFile);
|
|
330
254
|
return parsed === undefined
|
|
@@ -353,22 +277,17 @@ function nearestDeclaration(
|
|
|
353
277
|
readonly highestPackage: string | undefined;
|
|
354
278
|
}
|
|
355
279
|
| undefined {
|
|
356
|
-
let dir = targetRoot;
|
|
357
280
|
let highestPackage: string | undefined;
|
|
358
|
-
for (
|
|
281
|
+
for (const dir of ancestors(targetRoot, repositoryOf(host, targetRoot)?.root)) {
|
|
359
282
|
const declared = declarationAt(host, dir);
|
|
360
283
|
if (declared !== undefined) {
|
|
361
284
|
return { root: dir, ...declared, highestPackage };
|
|
362
285
|
}
|
|
363
|
-
if (host
|
|
286
|
+
if (holdsManifest(host, dir)) {
|
|
364
287
|
highestPackage = dir;
|
|
365
288
|
}
|
|
366
|
-
const up = dirnamePath(dir);
|
|
367
|
-
if (up === dir || host.kindOf(joinPath(dir, ".git")) !== "absent") {
|
|
368
|
-
return undefined;
|
|
369
|
-
}
|
|
370
|
-
dir = up;
|
|
371
289
|
}
|
|
290
|
+
return undefined;
|
|
372
291
|
}
|
|
373
292
|
|
|
374
293
|
/**
|
|
@@ -376,12 +295,14 @@ function nearestDeclaration(
|
|
|
376
295
|
* from the target root up to its repository root declares one with a member beside
|
|
377
296
|
* its root, or the nearest one does not name the highest package below it, at or
|
|
378
297
|
* above the target root, among its members. `parse` reads one compiler configuration,
|
|
379
|
-
* or answers `undefined` where it does not read.
|
|
298
|
+
* or answers `undefined` where it does not read. `known`, a workspace already read, is the
|
|
299
|
+
* answer where the nearest declaration is its own, so its members are not listed again.
|
|
380
300
|
*/
|
|
381
301
|
export function findWorkspace(
|
|
382
302
|
host: Host,
|
|
383
303
|
targetRoot: string,
|
|
384
304
|
parse: (configFile: string) => ParsedLayout | undefined,
|
|
305
|
+
known?: Workspace,
|
|
385
306
|
): Workspace | undefined {
|
|
386
307
|
const declared = nearestDeclaration(host, targetRoot);
|
|
387
308
|
if (declared === undefined) {
|
|
@@ -393,6 +314,9 @@ export function findWorkspace(
|
|
|
393
314
|
) {
|
|
394
315
|
return undefined;
|
|
395
316
|
}
|
|
317
|
+
if (known?.root === declared.root) {
|
|
318
|
+
return known;
|
|
319
|
+
}
|
|
396
320
|
const members: WorkspaceMember[] = [];
|
|
397
321
|
for (const dir of memberDirectories(host, declared.root, declared.patterns)) {
|
|
398
322
|
const manifest = manifestAt(host, dir);
|
|
@@ -414,8 +338,12 @@ export function findWorkspace(
|
|
|
414
338
|
return undefined;
|
|
415
339
|
}
|
|
416
340
|
members.sort((a, b) =>
|
|
417
|
-
a.dir === declared.root ? -1 : b.dir === declared.root ? 1 : a.dir
|
|
341
|
+
a.dir === declared.root ? -1 : b.dir === declared.root ? 1 : bytewise(a.dir, b.dir),
|
|
418
342
|
);
|
|
343
|
+
return assembled(host, declared.root, members);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function assembled(host: Host, root: string, members: readonly WorkspaceMember[]): Workspace {
|
|
419
347
|
const named = new Map<string, WorkspaceMember[]>();
|
|
420
348
|
for (const member of members) {
|
|
421
349
|
named.set(member.name, [...(named.get(member.name) ?? []), member]);
|
|
@@ -427,12 +355,12 @@ export function findWorkspace(
|
|
|
427
355
|
return scopes.get(dir);
|
|
428
356
|
}
|
|
429
357
|
const up = dirnamePath(dir);
|
|
430
|
-
const found =
|
|
431
|
-
host.kindOf(joinPath(dir, MANIFEST)) === "file" ? dir : up === dir ? undefined : scopeOf(up);
|
|
358
|
+
const found = holdsManifest(host, dir) ? dir : up === dir ? undefined : scopeOf(up);
|
|
432
359
|
scopes.set(dir, found);
|
|
433
360
|
return found;
|
|
434
361
|
};
|
|
435
362
|
return {
|
|
363
|
+
root,
|
|
436
364
|
members,
|
|
437
365
|
named,
|
|
438
366
|
memberOf: (path) => {
|
|
@@ -442,6 +370,34 @@ export function findWorkspace(
|
|
|
442
370
|
};
|
|
443
371
|
}
|
|
444
372
|
|
|
373
|
+
/**
|
|
374
|
+
* The workspace with the programs the run forms put first among each member's configurations,
|
|
375
|
+
* by the member's directory: a formed program has no file on disk to list, so its file list
|
|
376
|
+
* is what makes a member's JavaScript its source.
|
|
377
|
+
*/
|
|
378
|
+
export function withFormed(
|
|
379
|
+
host: Host,
|
|
380
|
+
workspace: Workspace,
|
|
381
|
+
formed: ReadonlyMap<string, readonly ParsedLayout[]>,
|
|
382
|
+
): Workspace {
|
|
383
|
+
return assembled(
|
|
384
|
+
host,
|
|
385
|
+
workspace.root,
|
|
386
|
+
workspace.members.map((member) => {
|
|
387
|
+
const own = formed.get(member.dir) ?? [];
|
|
388
|
+
return own.length === 0
|
|
389
|
+
? member
|
|
390
|
+
: {
|
|
391
|
+
...member,
|
|
392
|
+
configurations: [
|
|
393
|
+
...own.map((layout) => ({ fileNames: new Set(layout.fileNames) })),
|
|
394
|
+
...member.configurations,
|
|
395
|
+
],
|
|
396
|
+
};
|
|
397
|
+
}),
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
445
401
|
/**
|
|
446
402
|
* Whether one configuration holds one file only for the references it makes: the file
|
|
447
403
|
* belongs to a workspace package, the root included, and the configuration does not
|