@cplieger/deadset-ts 8.0.0-dev.7 → 8.0.0-dev.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/node-host.js +21 -3
- package/dist/src/analysis.js +94 -299
- package/dist/src/config.js +6 -83
- package/dist/src/configuration-files.js +2 -9
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/consumers.js +3 -30
- package/dist/src/contract/config.generated.js +544 -0
- package/dist/src/contract/contract.generated.js +20 -10
- package/dist/src/contract/report.generated.js +3 -2
- package/dist/src/conventions.js +3 -8
- package/dist/src/edges.js +36 -112
- package/dist/src/exempt-classes.js +0 -2
- package/dist/src/exempt.js +1 -1
- package/dist/src/failure.js +36 -0
- package/dist/src/findings/completion.js +5 -4
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/intra-function.js +1 -1
- package/dist/src/findings/non-code-artifacts.js +2 -2
- package/dist/src/findings/unused-declarations.js +1 -1
- package/dist/src/findings/visibility-narrowing.js +2 -2
- package/dist/src/findings-pass.js +1 -1
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +7 -0
- package/dist/src/injection-container.js +1 -1
- package/dist/src/json-document.js +194 -67
- package/dist/src/kinds.js +0 -7
- package/dist/src/load/classify.js +236 -0
- package/dist/src/load/diagnostics.js +79 -0
- package/dist/src/load/discover.js +230 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +22 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/plan.js +155 -0
- package/dist/src/{test-globals.js → load/test-globals.js} +51 -56
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +3 -3
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +37 -40
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +21 -59
- package/dist/src/{workspace-run.js → load/workspace-run.js} +4 -3
- package/dist/src/{workspace.js → load/workspace.js} +21 -17
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/print.js +10 -79
- package/dist/src/report-schema.js +3 -224
- package/dist/src/resolve.js +245 -715
- package/dist/src/run.js +59 -72
- package/dist/src/schema.js +320 -344
- package/dist/src/scope.js +37 -113
- package/dist/src/serialization-contract.js +1 -1
- package/dist/src/session.js +22 -28
- package/dist/src/source-files.js +1 -1
- package/dist/src/suppress-file.js +15 -17
- package/dist/src/suppress.js +3 -3
- package/dist/src/template-field.js +4 -4
- package/dist/src/type-errors.js +11 -216
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +100 -122
- package/dist/src/verbs/describe.js +5 -12
- package/dist/src/verbs/explain.js +3 -3
- package/dist/src/verbs/print-projects.js +2 -2
- package/dist/src/verbs/version.js +12 -2
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +95 -460
- package/src/config.ts +31 -298
- package/src/configuration-files.ts +8 -10
- package/src/configured-declarations.ts +18 -23
- package/src/consumers.ts +6 -57
- package/src/contract/config.generated.ts +798 -0
- package/src/contract/contract.generated.ts +20 -10
- package/src/contract/report.generated.ts +3 -2
- package/src/conventions.ts +6 -12
- package/src/edges.ts +39 -124
- package/src/exempt-classes.ts +0 -5
- package/src/exempt.ts +4 -4
- package/src/failure.ts +63 -0
- package/src/findings/completion.ts +5 -6
- package/src/findings/emitter.ts +2 -2
- package/src/findings/emitters.ts +1 -1
- package/src/findings/intra-function.ts +1 -1
- package/src/findings/non-code-artifacts.ts +4 -4
- package/src/findings/unused-declarations.ts +1 -1
- package/src/findings/visibility-narrowing.ts +2 -2
- package/src/findings-pass.ts +3 -3
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +8 -0
- package/src/host.ts +12 -5
- package/src/injection-container.ts +1 -1
- package/src/json-document.ts +236 -76
- package/src/kinds.ts +0 -8
- package/src/load/classify.ts +352 -0
- package/src/load/diagnostics.ts +141 -0
- package/src/load/discover.ts +378 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +188 -0
- package/src/load/load.ts +61 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/plan.ts +258 -0
- package/src/{test-globals.ts → load/test-globals.ts} +59 -65
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +4 -4
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +59 -53
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +31 -78
- package/src/{workspace-run.ts → load/workspace-run.ts} +14 -11
- package/src/{workspace.ts → load/workspace.ts} +28 -21
- package/src/outside-tests.ts +1 -1
- package/src/partial.ts +1 -1
- package/src/print.ts +11 -92
- package/src/report-schema.ts +3 -299
- package/src/resolve.ts +281 -1105
- package/src/run.ts +68 -80
- package/src/schema.ts +391 -389
- package/src/scope.ts +45 -131
- package/src/serialization-contract.ts +1 -1
- package/src/session.ts +52 -53
- package/src/source-files.ts +1 -1
- package/src/suppress-file.ts +15 -20
- package/src/suppress.ts +3 -3
- package/src/template-field.ts +10 -7
- package/src/type-errors.ts +18 -288
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +139 -157
- package/src/verbs/describe.ts +4 -11
- package/src/verbs/explain.ts +3 -7
- package/src/verbs/print-projects.ts +2 -2
- package/src/verbs/verb.ts +2 -2
- package/src/verbs/version.ts +13 -2
- package/dist/src/base-url.js +0 -18
- package/dist/src/discover.js +0 -374
- package/dist/src/setup-failure.js +0 -19
- package/dist/src/test-joins.js +0 -101
- package/src/base-url.ts +0 -24
- package/src/discover.ts +0 -548
- package/src/setup-failure.ts +0 -37
- package/src/test-joins.ts +0 -118
package/src/load/plan.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import type { CreateSnapshotProgramParams } from "@typescript/native/sync";
|
|
2
|
+
import type { PartialConfig } from "../config.ts";
|
|
3
|
+
import { readConventions, type ConventionManifest, type Conventions } from "../conventions.ts";
|
|
4
|
+
import { holdsManifest, inInstalledPackages, MANIFEST } from "../fs/manifest.ts";
|
|
5
|
+
import type { Host } from "../host.ts";
|
|
6
|
+
import { packageEntries, readManifest, type Manifest, type ManifestEntry } from "../manifest.ts";
|
|
7
|
+
import { ancestors, dirnamePath, normalizePath, relativePath, resolvePath } from "../paths.ts";
|
|
8
|
+
import type { Scope } from "../scope.ts";
|
|
9
|
+
import type { Engine, ProgramBuild } from "../session.ts";
|
|
10
|
+
import { bytewise } from "../text/compare.ts";
|
|
11
|
+
import { globExpression } from "../text/glob.ts";
|
|
12
|
+
import {
|
|
13
|
+
discoverProjects,
|
|
14
|
+
isTargetConfiguration,
|
|
15
|
+
type Configuration,
|
|
16
|
+
type Discovery,
|
|
17
|
+
type LoadedConsumer,
|
|
18
|
+
type Parsed,
|
|
19
|
+
} from "./discover.ts";
|
|
20
|
+
import { FailureExit } from "../failure.ts";
|
|
21
|
+
import { joinedTestFiles, joinedTests } from "./test-joins.ts";
|
|
22
|
+
import { testGlobals } from "./test-globals.ts";
|
|
23
|
+
import { findWorkspace, type Workspace } from "./workspace.ts";
|
|
24
|
+
import { writtenConfiguration } from "./workspace-programs.ts";
|
|
25
|
+
import { workspaceRun, type WorkspaceRun } from "./workspace-run.ts";
|
|
26
|
+
|
|
27
|
+
export type CompilerOptions = Parsed["options"];
|
|
28
|
+
|
|
29
|
+
/** How the snapshot builds one configuration. */
|
|
30
|
+
export type Build =
|
|
31
|
+
/** The project the compiler opens for the configuration as it stands. */
|
|
32
|
+
| { readonly kind: "project" }
|
|
33
|
+
| { readonly kind: "program"; readonly params: CreateSnapshotProgramParams }
|
|
34
|
+
/** A configuration only the snapshot holds, which extends the one it stands for. */
|
|
35
|
+
| { readonly kind: "configuration"; readonly value: Readonly<Record<string, unknown>> };
|
|
36
|
+
|
|
37
|
+
/** One configuration of the run and how the snapshot builds it. */
|
|
38
|
+
export interface ProgramPlan extends Configuration {
|
|
39
|
+
/** The options the program is built with, the parse's own with `paths` read as {@link baseUrlPaths} states. */
|
|
40
|
+
readonly options: CompilerOptions;
|
|
41
|
+
readonly build: Build;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The manifests the run reads, each once, and what they decide before any project opens. */
|
|
45
|
+
interface PackageSet {
|
|
46
|
+
/** The target's own manifest, its targets read back to source where the target is a member. */
|
|
47
|
+
readonly manifest: Manifest;
|
|
48
|
+
/** The directory of every workspace member, absolute, in the workspace's order. */
|
|
49
|
+
readonly members: readonly string[];
|
|
50
|
+
/** The directory of every nested package, absolute, in path order. */
|
|
51
|
+
readonly nested: readonly string[];
|
|
52
|
+
/** The entry points the other members' and the nested packages' manifests name. */
|
|
53
|
+
readonly entries: readonly ManifestEntry[];
|
|
54
|
+
/** The directories of the members whose manifest is not private. */
|
|
55
|
+
readonly published: ReadonlySet<string>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The workspace one consumer sits in, or the fault of a declaration that cannot be read,
|
|
60
|
+
* which ends the run only where an import's membership depends on it.
|
|
61
|
+
*/
|
|
62
|
+
export type ConsumerWorkspace =
|
|
63
|
+
{ readonly workspace: Workspace | undefined } | { readonly fault: string };
|
|
64
|
+
|
|
65
|
+
/** What a run opens and how it builds each program, decided before the snapshot. */
|
|
66
|
+
export interface RunPlan {
|
|
67
|
+
readonly discovery: Discovery;
|
|
68
|
+
readonly plans: readonly ProgramPlan[];
|
|
69
|
+
readonly packages: PackageSet;
|
|
70
|
+
/** The convention rows applied per package of {@link PackageSet}. */
|
|
71
|
+
readonly conventions: Conventions;
|
|
72
|
+
readonly workspace: WorkspaceRun | undefined;
|
|
73
|
+
/** The workspace each consumer sits in, by its directory, read from its own root. */
|
|
74
|
+
readonly consumerWorkspaces: ReadonlyMap<string, ConsumerWorkspace>;
|
|
75
|
+
/** The target root, absolute. */
|
|
76
|
+
readonly root: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The `paths` one configuration's resolved options map under the compilers before version
|
|
81
|
+
* 7, each target absolute: a target is read against the effective `baseUrl`, and a specifier
|
|
82
|
+
* no other pattern maps is looked up below it. Undefined where no `baseUrl` is set, so the
|
|
83
|
+
* options' own `paths` stand. Version 7 reads no `baseUrl`:
|
|
84
|
+
* https://github.com/microsoft/TypeScript/issues/62207
|
|
85
|
+
*/
|
|
86
|
+
export function baseUrlPaths(options: CompilerOptions): Record<string, string[]> | undefined {
|
|
87
|
+
const baseUrl: unknown = Reflect.get(options, "baseUrl");
|
|
88
|
+
if (typeof baseUrl !== "string") {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
return Object.fromEntries(
|
|
92
|
+
Object.entries({ "*": ["*"], ...options.paths }).map(([key, targets]) => [
|
|
93
|
+
key,
|
|
94
|
+
targets.map((target) => resolvePath(baseUrl, target)),
|
|
95
|
+
]),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** One configuration, read through the `paths` its `baseUrl` gives. */
|
|
100
|
+
function planned(configuration: Configuration): ProgramPlan {
|
|
101
|
+
const { options } = configuration.parsed;
|
|
102
|
+
const paths = baseUrlPaths(options);
|
|
103
|
+
return {
|
|
104
|
+
...configuration,
|
|
105
|
+
options: paths === undefined ? options : { ...options, paths },
|
|
106
|
+
build:
|
|
107
|
+
paths === undefined
|
|
108
|
+
? { kind: "project" }
|
|
109
|
+
: {
|
|
110
|
+
kind: "configuration",
|
|
111
|
+
value: { extends: configuration.configFile, compilerOptions: { paths } },
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The nested packages of a run: each directory below the target root, in no `node_modules`
|
|
118
|
+
* directory and none of `known`, that holds a `package.json` and lies at or above one of
|
|
119
|
+
* `files`, in path order.
|
|
120
|
+
*/
|
|
121
|
+
function nestedPackageDirs(
|
|
122
|
+
host: Host,
|
|
123
|
+
targetRoot: string,
|
|
124
|
+
files: Iterable<string>,
|
|
125
|
+
known: ReadonlySet<string>,
|
|
126
|
+
): readonly string[] {
|
|
127
|
+
const seen = new Set<string>();
|
|
128
|
+
const found: string[] = [];
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
for (const dir of ancestors(dirnamePath(file), targetRoot)) {
|
|
131
|
+
if (seen.has(dir) || relativePath(targetRoot, dir) === undefined) {
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
seen.add(dir);
|
|
135
|
+
const below = relativePath(targetRoot, dir) ?? "";
|
|
136
|
+
if (!inInstalledPackages(below) && !known.has(dir) && holdsManifest(host, dir)) {
|
|
137
|
+
found.push(dir);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return found.sort(bytewise);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** The manifests conventions are applied from: the target's, then each member's and nested package's. */
|
|
145
|
+
function conventionManifests(
|
|
146
|
+
host: Host,
|
|
147
|
+
root: string,
|
|
148
|
+
packages: PackageSet,
|
|
149
|
+
): readonly ConventionManifest[] {
|
|
150
|
+
const found = new Map<string, ConventionManifest>();
|
|
151
|
+
if (holdsManifest(host, root)) {
|
|
152
|
+
found.set(root, { dir: root, path: MANIFEST });
|
|
153
|
+
}
|
|
154
|
+
for (const [dirs, nested] of [
|
|
155
|
+
[packages.members, false],
|
|
156
|
+
[packages.nested, true],
|
|
157
|
+
] as const) {
|
|
158
|
+
for (const dir of dirs) {
|
|
159
|
+
const below = relativePath(root, dir);
|
|
160
|
+
if (below !== undefined && !found.has(dir)) {
|
|
161
|
+
found.set(dir, { dir, path: `${below}/${MANIFEST}`, nested });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return [...found.values()];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** The workspace one consumer sits in, read from its own root, the target's reused. */
|
|
169
|
+
function consumerWorkspace(
|
|
170
|
+
host: Host,
|
|
171
|
+
consumer: LoadedConsumer,
|
|
172
|
+
target: Workspace | undefined,
|
|
173
|
+
): ConsumerWorkspace {
|
|
174
|
+
try {
|
|
175
|
+
return { workspace: findWorkspace(host, consumer.path, () => undefined, target) };
|
|
176
|
+
} catch (error: unknown) {
|
|
177
|
+
if (!(error instanceof FailureExit)) {
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
return { fault: error.failures[0].detail };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The plan of one run: the configurations discovery names, each built through the steps in
|
|
186
|
+
* order (the `baseUrl` paths, the workspace members read from source, the test runner's
|
|
187
|
+
* globals, the joined test files of a derived matrix), the package set and the convention
|
|
188
|
+
* rows applied per package. A nested package is one at or above a file a target
|
|
189
|
+
* configuration lists or a test file that joins it.
|
|
190
|
+
*/
|
|
191
|
+
export function planRun(engine: Engine, host: Host, scope: Scope, config: PartialConfig): RunPlan {
|
|
192
|
+
const discovery = discoverProjects(engine, host, scope, config.analysis.configurations);
|
|
193
|
+
const root = resolvePath(host.workingDirectory(), scope.target.path);
|
|
194
|
+
const parse = (fileName: string, text: string) => engine.parseSourceFile(fileName, text);
|
|
195
|
+
let plans: readonly ProgramPlan[] = discovery.configurations.map(planned);
|
|
196
|
+
const targets = plans.filter(isTargetConfiguration);
|
|
197
|
+
const manifest = readManifest(host, scope.target.path);
|
|
198
|
+
const workspace = workspaceRun(engine, host, root, targets, manifest);
|
|
199
|
+
const consumerWorkspaces = new Map(
|
|
200
|
+
discovery.consumers.map((consumer) => [
|
|
201
|
+
consumer.path,
|
|
202
|
+
consumerWorkspace(host, consumer, workspace?.workspace),
|
|
203
|
+
]),
|
|
204
|
+
);
|
|
205
|
+
plans = plans.map((plan) => {
|
|
206
|
+
const build = workspace?.programs.get(plan.configFile);
|
|
207
|
+
return build === undefined ? plan : { ...plan, build };
|
|
208
|
+
});
|
|
209
|
+
plans = testGlobals(host, parse, plans);
|
|
210
|
+
const joins =
|
|
211
|
+
discovery.mode === "derived"
|
|
212
|
+
? joinedTestFiles(host, root, targets, config.ts.test_files.map(globExpression))
|
|
213
|
+
: new Map<string, readonly string[]>();
|
|
214
|
+
plans = joinedTests(plans, joins);
|
|
215
|
+
const members = workspace?.memberDirs ?? [];
|
|
216
|
+
const nested = nestedPackageDirs(
|
|
217
|
+
host,
|
|
218
|
+
normalizePath(root),
|
|
219
|
+
targets.flatMap((plan) => [
|
|
220
|
+
plan.configFile,
|
|
221
|
+
...plan.parsed.fileNames,
|
|
222
|
+
...(joins.get(plan.configFile) ?? []),
|
|
223
|
+
]),
|
|
224
|
+
new Set(members),
|
|
225
|
+
);
|
|
226
|
+
const packages: PackageSet = {
|
|
227
|
+
manifest: workspace?.manifest ?? manifest,
|
|
228
|
+
members,
|
|
229
|
+
nested,
|
|
230
|
+
entries: [...(workspace?.entries ?? []), ...packageEntries(host, normalizePath(root), nested)],
|
|
231
|
+
published: new Set(
|
|
232
|
+
(workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir),
|
|
233
|
+
),
|
|
234
|
+
};
|
|
235
|
+
const conventions = readConventions(
|
|
236
|
+
host,
|
|
237
|
+
parse,
|
|
238
|
+
conventionManifests(host, root, packages),
|
|
239
|
+
config.ts.disabled_conventions,
|
|
240
|
+
);
|
|
241
|
+
return { discovery, plans, packages, conventions, workspace, consumerWorkspaces, root };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** How the snapshot builds each planned configuration other than by opening its project. */
|
|
245
|
+
export function programBuilds(
|
|
246
|
+
host: Host,
|
|
247
|
+
plans: readonly ProgramPlan[],
|
|
248
|
+
): ReadonlyMap<string, ProgramBuild> {
|
|
249
|
+
const builds = new Map<string, ProgramBuild>();
|
|
250
|
+
for (const { configFile, build } of plans) {
|
|
251
|
+
if (build.kind === "program") {
|
|
252
|
+
builds.set(configFile, build);
|
|
253
|
+
} else if (build.kind === "configuration") {
|
|
254
|
+
builds.set(configFile, writtenConfiguration(host, configFile, build.value));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return builds;
|
|
258
|
+
}
|
|
@@ -23,14 +23,16 @@ import {
|
|
|
23
23
|
type Node,
|
|
24
24
|
type SourceFile,
|
|
25
25
|
} from "@typescript/native/ast";
|
|
26
|
-
import type { ParseFile } from "
|
|
27
|
-
import type { Host } from "
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import
|
|
31
|
-
import {
|
|
32
|
-
import { filesIn } from "
|
|
33
|
-
import { holdsManifest, INSTALLED_PACKAGES } from "
|
|
26
|
+
import type { ParseFile } from "../configuration-files.ts";
|
|
27
|
+
import type { Host } from "../host.ts";
|
|
28
|
+
import { isRecord } from "../json-document.ts";
|
|
29
|
+
import { ancestors, dirnamePath, joinPath } from "../paths.ts";
|
|
30
|
+
import { UNANSWERED } from "../query.ts";
|
|
31
|
+
import type { ProjectView } from "../session.ts";
|
|
32
|
+
import { filesIn } from "../fs/tree.ts";
|
|
33
|
+
import { holdsManifest, INSTALLED_PACKAGES } from "../fs/manifest.ts";
|
|
34
|
+
import { isTargetConfiguration } from "./discover.ts";
|
|
35
|
+
import type { ProgramPlan } from "./plan.ts";
|
|
34
36
|
|
|
35
37
|
/** The test runner whose configuration injects the globals, and the `types` entry declaring them. */
|
|
36
38
|
export const GLOBALS_RUNNER = "vitest";
|
|
@@ -150,75 +152,67 @@ function typesOf(value: unknown): readonly string[] | undefined {
|
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
/**
|
|
153
|
-
*
|
|
154
|
-
* runner configuration injects
|
|
155
|
-
* `programs` reads it, else as itself, with the globals' declarations added to its `types`.
|
|
156
|
-
* A configuration the compiler cannot read is left for its project to refuse.
|
|
155
|
+
* The plans with the globals' declarations added to the `types` of each target configuration
|
|
156
|
+
* whose nearest manifest's runner configuration injects them and that can resolve them.
|
|
157
157
|
*/
|
|
158
|
-
export function
|
|
159
|
-
engine: Engine,
|
|
158
|
+
export function testGlobals(
|
|
160
159
|
host: Host,
|
|
161
160
|
parse: ParseFile,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
): ReadonlyMap<string, WorkspaceProgram> {
|
|
165
|
-
const found = new Map(programs);
|
|
161
|
+
plans: readonly ProgramPlan[],
|
|
162
|
+
): readonly ProgramPlan[] {
|
|
166
163
|
const injects = new Map<string, boolean>();
|
|
167
|
-
|
|
168
|
-
const dir = manifestDir(host, configFile);
|
|
169
|
-
if (
|
|
170
|
-
|
|
164
|
+
return plans.map((plan): ProgramPlan => {
|
|
165
|
+
const dir = manifestDir(host, plan.configFile);
|
|
166
|
+
if (
|
|
167
|
+
!isTargetConfiguration(plan) ||
|
|
168
|
+
dir === undefined ||
|
|
169
|
+
!globalsInstalled(host, plan.configFile)
|
|
170
|
+
) {
|
|
171
|
+
return plan;
|
|
171
172
|
}
|
|
172
173
|
if (!injects.has(dir)) {
|
|
173
174
|
injects.set(dir, injectsGlobals(host, parse, dir));
|
|
174
175
|
}
|
|
176
|
+
const base = typesOf(plan.options.types) ?? [];
|
|
177
|
+
const { build } = plan;
|
|
175
178
|
if (injects.get(dir) !== true) {
|
|
176
|
-
|
|
179
|
+
return plan;
|
|
177
180
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
continue;
|
|
181
|
+
if (build.kind === "program") {
|
|
182
|
+
const listed = typesOf(build.params.compilerOptions.types) ?? base;
|
|
183
|
+
return listed.includes(GLOBALS_TYPES)
|
|
184
|
+
? plan
|
|
185
|
+
: {
|
|
186
|
+
...plan,
|
|
187
|
+
build: {
|
|
188
|
+
kind: "program",
|
|
189
|
+
params: {
|
|
190
|
+
...build.params,
|
|
191
|
+
compilerOptions: {
|
|
192
|
+
...build.params.compilerOptions,
|
|
193
|
+
types: [...listed, GLOBALS_TYPES],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
};
|
|
197
198
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
written = JSON.parse(held.text) as Record<string, unknown>;
|
|
202
|
-
} catch {
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
const options = (written["compilerOptions"] ?? {}) as Record<string, unknown>;
|
|
199
|
+
const written = build.kind === "configuration" ? build.value : { extends: plan.configFile };
|
|
200
|
+
const held = written["compilerOptions"];
|
|
201
|
+
const options = isRecord(held) ? held : {};
|
|
207
202
|
const listed = typesOf(options["types"]) ?? base;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
return found;
|
|
203
|
+
return listed.includes(GLOBALS_TYPES)
|
|
204
|
+
? plan
|
|
205
|
+
: {
|
|
206
|
+
...plan,
|
|
207
|
+
build: {
|
|
208
|
+
kind: "configuration",
|
|
209
|
+
value: {
|
|
210
|
+
...written,
|
|
211
|
+
compilerOptions: { ...options, types: [...listed, GLOBALS_TYPES] },
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
});
|
|
222
216
|
}
|
|
223
217
|
|
|
224
218
|
/**
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
|
|
9
|
+
import { sourcePaths } from "../file-facts.ts";
|
|
10
|
+
import type { Host } from "../host.ts";
|
|
11
|
+
import { ancestors, dirnamePath, joinPath } from "../paths.ts";
|
|
12
|
+
import { bytewise } from "../text/compare.ts";
|
|
13
|
+
import { holdsManifest } from "../fs/manifest.ts";
|
|
14
|
+
import type { Configuration } from "./discover.ts";
|
|
15
|
+
import type { ProgramPlan } from "./plan.ts";
|
|
16
|
+
|
|
17
|
+
const PREFERRED = "/tsconfig.json";
|
|
18
|
+
|
|
19
|
+
/** The configurations of one directory in the order a file joins them: `tsconfig.json` first. */
|
|
20
|
+
function byPreference(a: string, b: string): number {
|
|
21
|
+
const first = a.endsWith(PREFERRED) ? 0 : 1;
|
|
22
|
+
const second = b.endsWith(PREFERRED) ? 0 : 1;
|
|
23
|
+
return first - second || bytewise(a, b);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Per configuration of `configurations`, the absolute paths of the test files that join it:
|
|
28
|
+
* each file below `root` a pattern of `patterns` names, that no configuration's file list
|
|
29
|
+
* holds, joins the configuration nearest at or above its directory when no `package.json`
|
|
30
|
+
* sits between them.
|
|
31
|
+
*/
|
|
32
|
+
export function joinedTestFiles(
|
|
33
|
+
host: Host,
|
|
34
|
+
root: string,
|
|
35
|
+
configurations: readonly Configuration[],
|
|
36
|
+
patterns: readonly RegExp[],
|
|
37
|
+
): ReadonlyMap<string, readonly string[]> {
|
|
38
|
+
const listed = new Set<string>();
|
|
39
|
+
const byDir = new Map<string, string[]>();
|
|
40
|
+
for (const { configFile, parsed } of configurations) {
|
|
41
|
+
parsed.fileNames.forEach((name) => listed.add(name));
|
|
42
|
+
const dir = dirnamePath(configFile);
|
|
43
|
+
byDir.set(dir, [...(byDir.get(dir) ?? []), configFile].sort(byPreference));
|
|
44
|
+
}
|
|
45
|
+
const joins = new Map<string, string[]>();
|
|
46
|
+
for (const path of sourcePaths(host, root)) {
|
|
47
|
+
const file = joinPath(root, path);
|
|
48
|
+
if (listed.has(file) || !patterns.some((pattern) => pattern.test(path))) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
for (const dir of ancestors(dirnamePath(file), root)) {
|
|
52
|
+
const [nearest] = byDir.get(dir) ?? [];
|
|
53
|
+
if (nearest !== undefined) {
|
|
54
|
+
joins.set(nearest, [...(joins.get(nearest) ?? []), file]);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
if (holdsManifest(host, dir)) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return joins;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The plans with each joined test file added to the configuration it joins: to a described
|
|
67
|
+
* program's root files, or to the file list of a configuration only the snapshot holds, which
|
|
68
|
+
* lists every file the configuration lists and the joined ones.
|
|
69
|
+
*/
|
|
70
|
+
export function joinedTests(
|
|
71
|
+
plans: readonly ProgramPlan[],
|
|
72
|
+
joins: ReadonlyMap<string, readonly string[]>,
|
|
73
|
+
): readonly ProgramPlan[] {
|
|
74
|
+
return plans.map((plan): ProgramPlan => {
|
|
75
|
+
const files = joins.get(plan.configFile);
|
|
76
|
+
const { build } = plan;
|
|
77
|
+
if (files === undefined) {
|
|
78
|
+
return plan;
|
|
79
|
+
}
|
|
80
|
+
if (build.kind === "program") {
|
|
81
|
+
return {
|
|
82
|
+
...plan,
|
|
83
|
+
build: {
|
|
84
|
+
kind: "program",
|
|
85
|
+
params: { ...build.params, rootFiles: [...(build.params.rootFiles ?? []), ...files] },
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const written = build.kind === "configuration" ? build.value : { extends: plan.configFile };
|
|
90
|
+
return {
|
|
91
|
+
...plan,
|
|
92
|
+
build: {
|
|
93
|
+
kind: "configuration",
|
|
94
|
+
value: { ...written, files: [...plan.parsed.fileNames, ...files], include: [] },
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { emittedFrom } from "./emit-map.ts";
|
|
10
|
-
import type { Host } from "
|
|
11
|
-
import { readManifest, type Manifest, type ManifestEntry } from "
|
|
12
|
-
import { joinPath, relativePath } from "
|
|
10
|
+
import type { Host } from "../host.ts";
|
|
11
|
+
import { readManifest, type Manifest, type ManifestEntry } from "../manifest.ts";
|
|
12
|
+
import { joinPath, relativePath } from "../paths.ts";
|
|
13
13
|
import type { WorkspaceMember } from "./workspace.ts";
|
|
14
14
|
import type { WorkspaceResolver } from "./workspace-resolution.ts";
|
|
15
|
-
import { MANIFEST } from "
|
|
15
|
+
import { MANIFEST } from "../fs/manifest.ts";
|
|
16
16
|
|
|
17
17
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
18
18
|
const SUBPATH_WILDCARD = "*";
|