@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
package/src/session.ts
CHANGED
|
@@ -15,9 +15,7 @@ import type {
|
|
|
15
15
|
} from "@typescript/native/sync";
|
|
16
16
|
import type { Node, SourceFile } from "@typescript/native/ast";
|
|
17
17
|
import { componentLayer, mapperManifest } from "./component-layer.ts";
|
|
18
|
-
import { DiscoveryError } from "./discover.ts";
|
|
19
18
|
import type { Host, TemporaryDirectory } from "./host.ts";
|
|
20
|
-
import type { WorkspaceProgram } from "./workspace-programs.ts";
|
|
21
19
|
import { joinPath } from "./paths.ts";
|
|
22
20
|
import {
|
|
23
21
|
queriesOf,
|
|
@@ -26,6 +24,7 @@ import {
|
|
|
26
24
|
type Queries,
|
|
27
25
|
type UnansweredQuestion,
|
|
28
26
|
} from "./query.ts";
|
|
27
|
+
import { MANIFEST } from "./fs/manifest.ts";
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
30
|
* The compiler the analysis reads through: a client over a protocol to a separate
|
|
@@ -36,8 +35,8 @@ import {
|
|
|
36
35
|
export interface Engine {
|
|
37
36
|
/**
|
|
38
37
|
* Resolves one compiler configuration file, or throws with the reason it cannot
|
|
39
|
-
* be read. The result is spelled through the client's own signature: the type
|
|
40
|
-
*
|
|
38
|
+
* be read. The result is spelled through the client's own signature: the type the
|
|
39
|
+
* compiler package returns here is not one of its exported names.
|
|
41
40
|
*/
|
|
42
41
|
parseConfigFile(file: DocumentIdentifier): ReturnType<API["parseConfigFile"]>;
|
|
43
42
|
/** Resolves one configuration's JSON as if `configFile` held it, which no file need. */
|
|
@@ -82,6 +81,22 @@ export interface Engine {
|
|
|
82
81
|
close(): void;
|
|
83
82
|
}
|
|
84
83
|
|
|
84
|
+
/** The most questions one round trip carries. */
|
|
85
|
+
const BATCH = 2048;
|
|
86
|
+
|
|
87
|
+
/** Asks one question of every item, in round trips of at most {@link BATCH}, answers in order. */
|
|
88
|
+
export function batched<T, A>(
|
|
89
|
+
engine: Engine,
|
|
90
|
+
items: readonly T[],
|
|
91
|
+
question: (item: T) => APIRequestGenerator<A>,
|
|
92
|
+
): A[] {
|
|
93
|
+
const answers: A[] = [];
|
|
94
|
+
for (let at = 0; at < items.length; at += BATCH) {
|
|
95
|
+
answers.push(...engine.batch(items.slice(at, at + BATCH).map(question)));
|
|
96
|
+
}
|
|
97
|
+
return answers;
|
|
98
|
+
}
|
|
99
|
+
|
|
85
100
|
/** How a run opens its compiler client. */
|
|
86
101
|
export interface EngineOptions {
|
|
87
102
|
/** Collect per-request timing, which the calibration record reads. */
|
|
@@ -115,7 +130,7 @@ export function openEngine(options: EngineOptions): Engine {
|
|
|
115
130
|
if (components !== undefined && components.extensions.length > 0) {
|
|
116
131
|
const made = components.host.temporaryDirectory();
|
|
117
132
|
try {
|
|
118
|
-
components.host.writeDocument(joinPath(made.path,
|
|
133
|
+
components.host.writeDocument(joinPath(made.path, MANIFEST), [
|
|
119
134
|
mapperManifest(components.host.componentMapperCommand()),
|
|
120
135
|
]);
|
|
121
136
|
} catch (error: unknown) {
|
|
@@ -129,6 +144,7 @@ export function openEngine(options: EngineOptions): Engine {
|
|
|
129
144
|
...(mapper === undefined ? {} : { runExternalCode: true }),
|
|
130
145
|
});
|
|
131
146
|
let closed = false;
|
|
147
|
+
const parsed = new Map<string, { readonly text: string; readonly file: SourceFile }>();
|
|
132
148
|
return {
|
|
133
149
|
parseConfigFile: (file) => api.parseConfigFile(file),
|
|
134
150
|
parseConfigJson: (json, configFile) =>
|
|
@@ -160,8 +176,14 @@ export function openEngine(options: EngineOptions): Engine {
|
|
|
160
176
|
moduleResolutions: { fallback: "resolve", entries: [...entries] },
|
|
161
177
|
}),
|
|
162
178
|
parseSourceFile: (fileName, text) => {
|
|
179
|
+
// Every project of a run reads the same files outside its program, so one parse serves all.
|
|
180
|
+
const known = parsed.get(fileName);
|
|
181
|
+
if (known?.text === text) {
|
|
182
|
+
return known.file;
|
|
183
|
+
}
|
|
163
184
|
const retained = api.createSourceFile(fileName, text);
|
|
164
185
|
try {
|
|
186
|
+
parsed.set(fileName, { text, file: retained.sourceFile });
|
|
165
187
|
return retained.sourceFile;
|
|
166
188
|
} finally {
|
|
167
189
|
retained.dispose();
|
|
@@ -264,13 +286,6 @@ export interface ProjectView<Brand> {
|
|
|
264
286
|
*/
|
|
265
287
|
export type ProjectVisitor<Result> = <Brand>(project: ProjectView<Brand>) => Result;
|
|
266
288
|
|
|
267
|
-
/** One project a session opened: its configuration and the files of its own program. */
|
|
268
|
-
export interface OpenedFiles {
|
|
269
|
-
readonly configFile: string;
|
|
270
|
-
/** The program's source files no default library and no external library holds. */
|
|
271
|
-
readonly fileNames: () => readonly string[];
|
|
272
|
-
}
|
|
273
|
-
|
|
274
289
|
/**
|
|
275
290
|
* The source files of one program that `own` admits, in the program's order, none of
|
|
276
291
|
* them one of the compiler's default libraries.
|
|
@@ -464,19 +479,30 @@ export function diagnosticsOf<Brand>(project: ProjectView<Brand>): ProjectDiagno
|
|
|
464
479
|
};
|
|
465
480
|
}
|
|
466
481
|
|
|
482
|
+
/** How a snapshot builds one configuration other than by opening the project it names. */
|
|
483
|
+
export type ProgramBuild =
|
|
484
|
+
| { readonly kind: "program"; readonly params: CreateSnapshotProgramParams }
|
|
485
|
+
/** A configuration only the snapshot holds, at a path no file has. */
|
|
486
|
+
| { readonly kind: "configuration"; readonly file: string; readonly text: string };
|
|
487
|
+
|
|
467
488
|
/** One run's result: what the visitor answered for each project, and what it cost. */
|
|
468
489
|
export interface SessionResult<Result> {
|
|
469
|
-
/** One answer per configuration
|
|
490
|
+
/** One answer per configuration, in the order named. */
|
|
470
491
|
readonly projects: readonly Result[];
|
|
471
|
-
/** The configurations the snapshot opened no project for, in the order named. */
|
|
472
|
-
readonly unopened: readonly string[];
|
|
473
492
|
readonly timing: TimingInfo;
|
|
474
|
-
/** Every question the checker could not answer, each once, in the order first asked. */
|
|
475
|
-
readonly unanswered: readonly UnansweredQuestion[];
|
|
476
493
|
}
|
|
477
494
|
|
|
478
|
-
/**
|
|
479
|
-
|
|
495
|
+
/** One open snapshot's projects, valid only while the session that handed it out runs. */
|
|
496
|
+
export interface OpenedSession {
|
|
497
|
+
/** One view per configuration the snapshot opened a project for, in the order named. */
|
|
498
|
+
readonly views: readonly ProjectView<unknown>[];
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** How one session opens its configurations. */
|
|
502
|
+
export interface SessionOptions {
|
|
503
|
+
/** How the snapshot builds each configuration it does not open as its project. */
|
|
504
|
+
readonly programs?: ReadonlyMap<string, ProgramBuild> | undefined;
|
|
505
|
+
}
|
|
480
506
|
|
|
481
507
|
/**
|
|
482
508
|
* The projects one snapshot holds for the configurations named, by configuration file. A
|
|
@@ -505,22 +531,18 @@ function projectsOf(
|
|
|
505
531
|
}
|
|
506
532
|
|
|
507
533
|
/**
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
* `first` runs over every opened project before the first visit and `last` after the last,
|
|
513
|
-
* both while the client answers; the snapshot and the client are then released.
|
|
534
|
+
* Opens every project the compiler configurations name in one never updated snapshot of one
|
|
535
|
+
* client, and hands them to `use` while the client answers; the snapshot and the client are
|
|
536
|
+
* then released. A configuration `options.programs` describes is built as that program, or
|
|
537
|
+
* opened from the configuration it writes. One the snapshot holds nothing for has no view.
|
|
514
538
|
*/
|
|
515
|
-
export function
|
|
539
|
+
export function openSession<Result>(
|
|
516
540
|
engine: Engine,
|
|
517
541
|
configFiles: readonly string[],
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
first: (opened: readonly OpenedFiles[]) => void = () => undefined,
|
|
523
|
-
): SessionResult<Result> {
|
|
542
|
+
options: SessionOptions,
|
|
543
|
+
use: (opened: OpenedSession, unanswered: () => readonly UnansweredQuestion[]) => Result,
|
|
544
|
+
): Result {
|
|
545
|
+
const programs = options.programs ?? new Map<string, ProgramBuild>();
|
|
524
546
|
try {
|
|
525
547
|
const built: string[] = [];
|
|
526
548
|
const params: CreateSnapshotProgramParams[] = [];
|
|
@@ -545,32 +567,13 @@ export function runSession<Result>(
|
|
|
545
567
|
const opened = projectsOf(snapshot, built, written);
|
|
546
568
|
const log = new UnansweredLog();
|
|
547
569
|
const views: ProjectView<unknown>[] = [];
|
|
548
|
-
const missing: string[] = [];
|
|
549
570
|
for (const configFile of configFiles) {
|
|
550
571
|
const project = opened.get(configFile);
|
|
551
|
-
if (project
|
|
552
|
-
|
|
553
|
-
throw new DiscoveryError(`${configFile} opened no project`, []);
|
|
554
|
-
}
|
|
555
|
-
missing.push(configFile);
|
|
556
|
-
continue;
|
|
572
|
+
if (project !== undefined) {
|
|
573
|
+
views.push(viewOf(project, configFile, engine, log));
|
|
557
574
|
}
|
|
558
|
-
views.push(viewOf(project, configFile, engine, log));
|
|
559
575
|
}
|
|
560
|
-
|
|
561
|
-
views.map((view) => ({
|
|
562
|
-
configFile: view.configFile,
|
|
563
|
-
fileNames: () => view.ownSourceFiles().map((file) => file.fileName),
|
|
564
|
-
})),
|
|
565
|
-
);
|
|
566
|
-
const projects = views.map((view) => visit(view));
|
|
567
|
-
last();
|
|
568
|
-
return {
|
|
569
|
-
projects,
|
|
570
|
-
unopened: missing,
|
|
571
|
-
timing: engine.getTimingInfo(),
|
|
572
|
-
unanswered: log.questions,
|
|
573
|
-
};
|
|
576
|
+
return use({ views }, () => log.questions);
|
|
574
577
|
} finally {
|
|
575
578
|
snapshot.dispose();
|
|
576
579
|
}
|
|
@@ -578,3 +581,23 @@ export function runSession<Result>(
|
|
|
578
581
|
engine.close();
|
|
579
582
|
}
|
|
580
583
|
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Runs `visit` over the project {@link openSession} opens for each configuration, and answers
|
|
587
|
+
* in their order; a configuration the snapshot opens nothing for throws before any visit.
|
|
588
|
+
*/
|
|
589
|
+
export function runSession<Result>(
|
|
590
|
+
engine: Engine,
|
|
591
|
+
configFiles: readonly string[],
|
|
592
|
+
visit: ProjectVisitor<Result>,
|
|
593
|
+
): SessionResult<Result> {
|
|
594
|
+
return openSession(engine, configFiles, {}, (opened) => {
|
|
595
|
+
const unopened = configFiles.find(
|
|
596
|
+
(configFile) => !opened.views.some((view) => view.configFile === configFile),
|
|
597
|
+
);
|
|
598
|
+
if (unopened !== undefined) {
|
|
599
|
+
throw new Error(`${unopened} opened no project`);
|
|
600
|
+
}
|
|
601
|
+
return { projects: opened.views.map((view) => visit(view)), timing: engine.getTimingInfo() };
|
|
602
|
+
});
|
|
603
|
+
}
|
package/src/source-files.ts
CHANGED
|
@@ -5,13 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { SourceFile } from "@typescript/native/ast";
|
|
8
|
-
import { commonDirectory, emittedFrom } from "./emit-map.ts";
|
|
9
|
-
import { dirnamePath, relativePath, resolvePath } from "./paths.ts";
|
|
8
|
+
import { commonDirectory, emittedFrom } from "./load/emit-map.ts";
|
|
9
|
+
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
|
|
10
10
|
import type { ProjectView } from "./session.ts";
|
|
11
11
|
|
|
12
12
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
13
13
|
const SUBPATH_WILDCARD = "*";
|
|
14
14
|
|
|
15
|
+
/** The extension a source file's name drops when the project writes it out. */
|
|
16
|
+
const SOURCE_EXTENSION = /\.[cm]?[jt]sx?$/u;
|
|
17
|
+
|
|
18
|
+
/** The extensions the project may write a source file's output under. */
|
|
19
|
+
const OUTPUT_EXTENSIONS = [".js", ".mjs", ".cjs", ".jsx", ".d.ts", ".d.mts", ".d.cts"] as const;
|
|
20
|
+
|
|
15
21
|
/**
|
|
16
22
|
* Whether one path is what a subpath pattern stands for: the text before the
|
|
17
23
|
* wildcard, any run of characters including the solidus, then the text after it.
|
|
@@ -40,6 +46,47 @@ export interface SourceFiles {
|
|
|
40
46
|
named(path: string): readonly SourceFile[];
|
|
41
47
|
/** The directories the project writes its output below, absolute: its output and declaration directories. */
|
|
42
48
|
readonly outputDirs: readonly string[];
|
|
49
|
+
/** The output paths, absolute, the project writes one own file to, each of which {@link named} reads back to it. */
|
|
50
|
+
writtenAs(file: SourceFile): readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* The own files one absolute path names read as an output of the project written below
|
|
53
|
+
* `outputDir`: a manifest that ships from its build directory names its entries there.
|
|
54
|
+
*/
|
|
55
|
+
namedAsOutput(outputDir: string, path: string): readonly SourceFile[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The first own file of the paths given that the project holds, or none. */
|
|
59
|
+
function heldAt(
|
|
60
|
+
byName: ReadonlyMap<string, SourceFile>,
|
|
61
|
+
paths: readonly string[],
|
|
62
|
+
): readonly SourceFile[] {
|
|
63
|
+
for (const candidate of paths) {
|
|
64
|
+
const file = byName.get(candidate);
|
|
65
|
+
if (file !== undefined) {
|
|
66
|
+
return [file];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Where one project writes its output, and the directory it writes it from, absolute. */
|
|
73
|
+
function layoutOf<Brand>(
|
|
74
|
+
project: ProjectView<Brand>,
|
|
75
|
+
fileNames: readonly string[],
|
|
76
|
+
): {
|
|
77
|
+
readonly outDir: string | undefined;
|
|
78
|
+
readonly declarationDir: string | undefined;
|
|
79
|
+
readonly sourceDir: string;
|
|
80
|
+
} {
|
|
81
|
+
const options = project.program.getCompilerOptions();
|
|
82
|
+
const configDir = dirnamePath(project.configFile);
|
|
83
|
+
const at = (option: string | undefined): string | undefined =>
|
|
84
|
+
option === undefined ? undefined : resolvePath(configDir, option);
|
|
85
|
+
return {
|
|
86
|
+
outDir: at(options.outDir),
|
|
87
|
+
declarationDir: at(options.declarationDir),
|
|
88
|
+
sourceDir: at(options.rootDir) ?? commonDirectory(fileNames),
|
|
89
|
+
};
|
|
43
90
|
}
|
|
44
91
|
|
|
45
92
|
/**
|
|
@@ -62,14 +109,7 @@ export function sourceFilesOf<Brand>(project: ProjectView<Brand>, targetRoot: st
|
|
|
62
109
|
}
|
|
63
110
|
}
|
|
64
111
|
|
|
65
|
-
const
|
|
66
|
-
const configDir = dirnamePath(project.configFile);
|
|
67
|
-
const at = (option: string | undefined): string | undefined =>
|
|
68
|
-
option === undefined ? undefined : resolvePath(configDir, option);
|
|
69
|
-
const outDir = at(options.outDir);
|
|
70
|
-
const declarationDir = at(options.declarationDir);
|
|
71
|
-
const sourceDir = at(options.rootDir) ?? commonDirectory([...byName.keys()]);
|
|
72
|
-
|
|
112
|
+
const { outDir, declarationDir, sourceDir } = layoutOf(project, [...byName.keys()]);
|
|
73
113
|
const layout = { outDir, declarationDir, sourceDirs: [sourceDir] };
|
|
74
114
|
|
|
75
115
|
/** The source paths one written path may stand for, the path itself first. */
|
|
@@ -79,15 +119,25 @@ export function sourceFilesOf<Brand>(project: ProjectView<Brand>, targetRoot: st
|
|
|
79
119
|
byPath,
|
|
80
120
|
byName,
|
|
81
121
|
outputDirs: [...new Set([outDir, declarationDir])].filter((dir) => dir !== undefined),
|
|
122
|
+
writtenAs: (file) => {
|
|
123
|
+
const below = relativePath(sourceDir, file.fileName);
|
|
124
|
+
if (below === undefined) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const written = [outDir, declarationDir].flatMap((dir) =>
|
|
128
|
+
dir === undefined
|
|
129
|
+
? []
|
|
130
|
+
: OUTPUT_EXTENSIONS.map((extension) =>
|
|
131
|
+
joinPath(dir, below.replace(SOURCE_EXTENSION, extension)),
|
|
132
|
+
),
|
|
133
|
+
);
|
|
134
|
+
return [...new Set(written)].filter((path) => heldAt(byName, candidates(path))[0] === file);
|
|
135
|
+
},
|
|
136
|
+
namedAsOutput: (outputDir, path) =>
|
|
137
|
+
heldAt(byName, emittedFrom(path, { outDir: outputDir, sourceDirs: [sourceDir] })),
|
|
82
138
|
named: (path) => {
|
|
83
139
|
if (!path.includes(SUBPATH_WILDCARD)) {
|
|
84
|
-
|
|
85
|
-
const held = byName.get(candidate);
|
|
86
|
-
if (held !== undefined) {
|
|
87
|
-
return [held];
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return [];
|
|
140
|
+
return heldAt(byName, candidates(path));
|
|
91
141
|
}
|
|
92
142
|
const patterns = candidates(path).filter((candidate) => candidate.includes(SUBPATH_WILDCARD));
|
|
93
143
|
return [...byName.values()].filter((file) =>
|
package/src/suppress-file.ts
CHANGED
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
* ignore file by gaining a maintainer's reason.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { CODE } from "./contract/contract.generated.ts";
|
|
8
9
|
import type { Host } from "./host.ts";
|
|
9
10
|
import type { InventorySymbol } from "./inventory.ts";
|
|
11
|
+
import { readTargetDocument } from "./fs/document.ts";
|
|
10
12
|
import { jsonChunks } from "./json-chunks.ts";
|
|
11
|
-
import {
|
|
12
|
-
import { positionAt, walkDocument } from "./json-document.ts";
|
|
13
|
+
import { isRecord, positionAt, readStrict, StrictJSONError } from "./json-document.ts";
|
|
13
14
|
import type { Position } from "./position.ts";
|
|
14
15
|
import { declarationKey } from "./ref.ts";
|
|
15
16
|
import {
|
|
16
17
|
CODE_FORM,
|
|
17
|
-
SUPPRESSION_WITHOUT_REASON,
|
|
18
18
|
SuppressionError,
|
|
19
|
-
UNSCOPED_ENTRY,
|
|
20
19
|
blankReason,
|
|
21
20
|
isEntryPath,
|
|
21
|
+
isPartKind,
|
|
22
22
|
isSymbolRef,
|
|
23
23
|
siteText,
|
|
24
24
|
type Mechanism,
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type SuppressionRecord,
|
|
27
27
|
type Suppressions,
|
|
28
28
|
} from "./suppress.ts";
|
|
29
|
+
import { message } from "./product.ts";
|
|
29
30
|
|
|
30
31
|
/** The name and the location the grammar fixes for the ignore file. */
|
|
31
32
|
export const IGNORE_FILE = "deadset-ignore.json";
|
|
@@ -79,10 +80,6 @@ function documentSite(shape: Shape): Position {
|
|
|
79
80
|
return { path: shape.file, line: 0, column: 0 };
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
function isObject(value: unknown): value is Record<string, unknown> {
|
|
83
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
83
|
/** What one entry or row resolves to. */
|
|
87
84
|
interface Read {
|
|
88
85
|
readonly records: readonly SuppressionRecord[];
|
|
@@ -100,7 +97,7 @@ function readRecord(value: unknown, site: Position, byReference: ByReference, sh
|
|
|
100
97
|
const refuse = (text: string, want: string): never => {
|
|
101
98
|
throw new SuppressionError(shape.mechanism, siteText(site), text, want);
|
|
102
99
|
};
|
|
103
|
-
if (!
|
|
100
|
+
if (!isRecord(value)) {
|
|
104
101
|
return refuse(JSON.stringify(value), shape.recordWant);
|
|
105
102
|
}
|
|
106
103
|
for (const [key, held] of Object.entries(value)) {
|
|
@@ -147,21 +144,31 @@ function readRecord(value: unknown, site: Position, byReference: ByReference, sh
|
|
|
147
144
|
};
|
|
148
145
|
const refusals: Refusal[] = [];
|
|
149
146
|
if (blankReason(reason)) {
|
|
150
|
-
refusals.push({ ...written, reported:
|
|
147
|
+
refusals.push({ ...written, reported: CODE.suppressionWithoutReason });
|
|
151
148
|
}
|
|
152
149
|
if (written.path === "") {
|
|
153
|
-
refusals.push({ ...written, reported:
|
|
150
|
+
refusals.push({ ...written, reported: CODE.unscopedIgnoreEntry });
|
|
154
151
|
}
|
|
155
152
|
if (refusals.length > 0) {
|
|
156
153
|
return { records: [], refusals };
|
|
157
154
|
}
|
|
158
|
-
const named =
|
|
155
|
+
const named =
|
|
156
|
+
byReference.get(declarationKey(symbol, written.path)) ??
|
|
157
|
+
(isPartKind(code)
|
|
158
|
+
? byReference.get(declarationKey(parameterHolder(symbol), written.path))
|
|
159
|
+
: undefined) ??
|
|
160
|
+
[];
|
|
159
161
|
if (named.length === 0) {
|
|
160
162
|
return { records: [{ ...written, bound: "" }], refusals: [] };
|
|
161
163
|
}
|
|
162
164
|
return { records: named.map((one) => ({ ...written, bound: one.id })), refusals: [] };
|
|
163
165
|
}
|
|
164
166
|
|
|
167
|
+
/** The reference of the declaration a parameter's reference names it under, or `ref` itself. */
|
|
168
|
+
function parameterHolder(ref: string): string {
|
|
169
|
+
return ref.endsWith(")") ? ref.slice(0, ref.lastIndexOf("(")) : ref;
|
|
170
|
+
}
|
|
171
|
+
|
|
165
172
|
function byReferenceOf(symbols: readonly InventorySymbol[]): ByReference {
|
|
166
173
|
const byReference = new Map<string, InventorySymbol[]>();
|
|
167
174
|
for (const symbol of symbols) {
|
|
@@ -178,30 +185,26 @@ function readDocument(
|
|
|
178
185
|
symbols: readonly InventorySymbol[],
|
|
179
186
|
shape: Shape,
|
|
180
187
|
): Suppressions {
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
188
|
+
const text = readTargetDocument(host, targetRoot, shape.file);
|
|
189
|
+
if (text === undefined) {
|
|
183
190
|
return { records: [], refusals: [] };
|
|
184
191
|
}
|
|
185
|
-
const text = host.readFile(file);
|
|
186
192
|
const malformed = (detail: string, site = documentSite(shape)): never => {
|
|
187
193
|
throw new SuppressionError(shape.mechanism, siteText(site), detail, shape.documentWant);
|
|
188
194
|
};
|
|
189
|
-
let
|
|
195
|
+
let document;
|
|
190
196
|
try {
|
|
191
|
-
|
|
197
|
+
document = readStrict(text, shape.array);
|
|
192
198
|
} catch (error: unknown) {
|
|
193
|
-
|
|
199
|
+
if (!(error instanceof StrictJSONError)) {
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
return malformed(error.message, positionAt(text, shape.file, error.offset));
|
|
194
203
|
}
|
|
195
|
-
|
|
204
|
+
const parsed = document.value;
|
|
205
|
+
if (!isRecord(parsed)) {
|
|
196
206
|
return malformed(shape.file);
|
|
197
207
|
}
|
|
198
|
-
const walk = walkDocument(text, shape.array);
|
|
199
|
-
if (walk.twice !== undefined) {
|
|
200
|
-
malformed(
|
|
201
|
-
`the member ${JSON.stringify(walk.twice.name)} is written twice, so neither value is chosen`,
|
|
202
|
-
positionAt(text, shape.file, walk.twice.offset),
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
208
|
for (const key of Object.keys(parsed)) {
|
|
206
209
|
if (key !== "description" && key !== shape.array) {
|
|
207
210
|
malformed(`the member ${JSON.stringify(key)} is not one the grammar declares`);
|
|
@@ -217,7 +220,7 @@ function readDocument(
|
|
|
217
220
|
const records: SuppressionRecord[] = [];
|
|
218
221
|
const refusals: Refusal[] = [];
|
|
219
222
|
(held as readonly unknown[]).forEach((value, index) => {
|
|
220
|
-
const offset =
|
|
223
|
+
const offset = document.starts.get(index);
|
|
221
224
|
const site = offset === undefined ? documentSite(shape) : positionAt(text, shape.file, offset);
|
|
222
225
|
const read = readRecord(value, site, byReference, shape);
|
|
223
226
|
records.push(...read.records);
|
|
@@ -318,9 +321,9 @@ export function otherSchemeRows(text: string, own: string = OWN_SCHEME): readonl
|
|
|
318
321
|
try {
|
|
319
322
|
parsed = JSON.parse(text);
|
|
320
323
|
} catch (error: unknown) {
|
|
321
|
-
return refuse(
|
|
324
|
+
return refuse(message(error));
|
|
322
325
|
}
|
|
323
|
-
const held =
|
|
326
|
+
const held = isRecord(parsed) ? parsed[BASELINE_SHAPE.array] : undefined;
|
|
324
327
|
if (!Array.isArray(held)) {
|
|
325
328
|
return refuse(BASELINE_SHAPE.documentWant);
|
|
326
329
|
}
|
|
@@ -328,7 +331,7 @@ export function otherSchemeRows(text: string, own: string = OWN_SCHEME): readonl
|
|
|
328
331
|
try {
|
|
329
332
|
readRecord(value, documentSite(BASELINE_SHAPE), new Map(), BASELINE_SHAPE);
|
|
330
333
|
} catch (error: unknown) {
|
|
331
|
-
return refuse(
|
|
334
|
+
return refuse(message(error));
|
|
332
335
|
}
|
|
333
336
|
// readRecord has checked every member is a string and the code and symbol are present.
|
|
334
337
|
const { code, symbol, path, reason } = value as Readonly<Record<string, string>>;
|
|
@@ -375,10 +378,9 @@ function* separatorsEscaped(pieces: Iterable<string>): Generator<string, void, u
|
|
|
375
378
|
* A baseline holding one row per finding, in the order given, which is the report's, and
|
|
376
379
|
* the other language's rows `kept`, Go's rows ahead of TypeScript's and each scheme's in
|
|
377
380
|
* the order given, so two analyzers writing one document in either order write the same
|
|
378
|
-
* bytes, in the form grammar/suppression.md fixes. Every
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
* rather than written, because the grammar requires a reason on every row.
|
|
381
|
+
* bytes, in the form grammar/suppression.md fixes. Every row carries the provenance as
|
|
382
|
+
* its reason, so a finding missing a value a row needs, or an identity missing its name
|
|
383
|
+
* or version, is refused rather than written.
|
|
382
384
|
*/
|
|
383
385
|
export function writeBaseline(
|
|
384
386
|
findings: readonly Recorded[],
|
package/src/suppress-inline.ts
CHANGED
|
@@ -4,19 +4,21 @@
|
|
|
4
4
|
* below it, or on its own line where it trails a token there.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { CODE } from "./contract/contract.generated.ts";
|
|
7
8
|
import {
|
|
8
9
|
isConstructorDeclaration,
|
|
9
10
|
SyntaxKind,
|
|
10
11
|
type Node,
|
|
11
12
|
type SourceFile,
|
|
12
13
|
} from "@typescript/native/ast";
|
|
14
|
+
import { importBindings } from "./import-bindings.ts";
|
|
13
15
|
import { isParameterProperty, nodeKey, type Inventory } from "./inventory.ts";
|
|
14
16
|
import { byPosition, positionKey, renderPosition, type Position } from "./position.ts";
|
|
17
|
+
import { importRef } from "./ref.ts";
|
|
15
18
|
import type { ProjectView } from "./session.ts";
|
|
16
19
|
import { signatureOf } from "./signatures.ts";
|
|
17
20
|
import {
|
|
18
21
|
isPartKind,
|
|
19
|
-
SUPPRESSION_WITHOUT_REASON,
|
|
20
22
|
SuppressionError,
|
|
21
23
|
siteText,
|
|
22
24
|
type Refusal,
|
|
@@ -200,6 +202,7 @@ function declarationLines(
|
|
|
200
202
|
file: SourceFile,
|
|
201
203
|
held: Inventory,
|
|
202
204
|
symbols: ReadonlyMap<string, Declared>,
|
|
205
|
+
targetRoot: string,
|
|
203
206
|
): ReadonlyMap<number, readonly Binding[]> {
|
|
204
207
|
const below = new Map<number, Binding[]>();
|
|
205
208
|
const add = (offset: number, one: Binding): void => {
|
|
@@ -245,6 +248,20 @@ function declarationLines(
|
|
|
245
248
|
node.forEachChild(visit);
|
|
246
249
|
};
|
|
247
250
|
file.forEachChild(visit);
|
|
251
|
+
// An import binding is a subject of its own, bound on its line as a declaration is.
|
|
252
|
+
const fileId = held.declarations.get(nodeKey(file, file));
|
|
253
|
+
const moduleRef = held.symbols.find((symbol) => symbol.id === fileId)?.ref ?? "";
|
|
254
|
+
for (const name of moduleRef === "" ? [] : importBindings(file)) {
|
|
255
|
+
const position = renderPosition(file, targetRoot, name.getStart());
|
|
256
|
+
const one = { id: positionKey(position), ref: importRef(moduleRef, name.text), position };
|
|
257
|
+
let statement: Node = name;
|
|
258
|
+
while (statement.parent.kind !== SyntaxKind.SourceFile) {
|
|
259
|
+
statement = statement.parent;
|
|
260
|
+
}
|
|
261
|
+
for (const at of [statement.pos, name.getStart()]) {
|
|
262
|
+
add(at, { declared: one, part: one });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
248
265
|
return below;
|
|
249
266
|
}
|
|
250
267
|
|
|
@@ -285,7 +302,7 @@ export function inlineDirectives<Brand>(
|
|
|
285
302
|
if (comments.length === 0) {
|
|
286
303
|
continue;
|
|
287
304
|
}
|
|
288
|
-
const below = declarationLines(file, held, symbols);
|
|
305
|
+
const below = declarationLines(file, held, symbols, targetRoot);
|
|
289
306
|
for (const comment of comments) {
|
|
290
307
|
const site = renderPosition(file, targetRoot, comment.offset);
|
|
291
308
|
const target = trails(file, comment.offset) ? site.line : site.line + 1;
|
|
@@ -337,7 +354,7 @@ export function inlineSuppressions(
|
|
|
337
354
|
case "no-reason":
|
|
338
355
|
for (const code of directive.codes) {
|
|
339
356
|
refusals.push({
|
|
340
|
-
reported:
|
|
357
|
+
reported: CODE.suppressionWithoutReason,
|
|
341
358
|
code,
|
|
342
359
|
symbol: "",
|
|
343
360
|
path: site.path,
|