@cplieger/deadset-ts 8.0.0-dev.1 → 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 +181 -341
- package/dist/src/augmentations.js +106 -13
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/build-scripts.js +425 -0
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +2 -3
- package/dist/src/config.js +6 -82
- package/dist/src/configuration-files.js +28 -176
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/conformance-record.js +1 -1
- 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 +73 -3
- package/dist/src/conventions.js +36 -66
- package/dist/src/dependencies.js +103 -40
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +2 -8
- package/dist/src/entry-points.js +11 -27
- 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 +139 -72
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +5 -5
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +13 -10
- package/dist/src/findings/non-code-artifacts.js +7 -8
- 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 +41 -32
- package/dist/src/findings/visibility-narrowing.js +19 -16
- 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 +7 -4
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/graph.js +5 -3
- package/dist/src/html-entries.js +6 -33
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory.js +2 -21
- 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} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
- 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 +76 -4
- package/dist/src/mdx-entries.js +3 -26
- package/dist/src/outside-tests.js +1 -1
- 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 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +1 -0
- package/dist/src/ref.js +1 -0
- package/dist/src/references.js +48 -30
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -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 -729
- package/dist/src/roots.js +273 -87
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +595 -21
- package/dist/src/session.js +34 -29
- package/dist/src/source-files.js +1 -1
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +3 -2
- package/dist/src/suppress.js +33 -51
- package/dist/src/sweep.js +7 -9
- package/dist/src/symbol-keys.js +3 -5
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-support.js +8 -11
- 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 +11 -232
- 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 +166 -126
- package/dist/src/verbs/describe.js +9 -16
- package/dist/src/verbs/explain.js +10 -7
- 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 +62 -64
- package/jsr.json +1 -1
- package/package.json +4 -3
- package/src/analysis.ts +245 -502
- package/src/augmentations.ts +135 -17
- package/src/automatic-types.ts +11 -29
- package/src/build-scripts.ts +543 -0
- package/src/component-layer.ts +4 -2
- package/src/components.ts +2 -4
- package/src/config.ts +31 -302
- package/src/configuration-files.ts +34 -179
- package/src/configured-declarations.ts +18 -23
- package/src/conformance-record.ts +1 -1
- 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 +85 -3
- package/src/conventions.ts +46 -84
- package/src/dependencies.ts +118 -46
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +3 -9
- package/src/entry-points.ts +12 -38
- 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 +14 -9
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +181 -84
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +8 -9
- package/src/findings/emitters.ts +7 -7
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +13 -11
- package/src/findings/non-code-artifacts.ts +9 -11
- package/src/findings/reads-and-writes.ts +20 -16
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +45 -32
- package/src/findings/visibility-narrowing.ts +20 -17
- 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 +7 -4
- package/src/git-ignore.ts +50 -26
- package/src/graph.ts +5 -3
- package/src/host.ts +12 -5
- package/src/html-entries.ts +6 -33
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/injection-container.ts +1 -1
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory.ts +2 -20
- 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} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
- 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 +122 -4
- package/src/mdx-entries.ts +3 -26
- package/src/outside-tests.ts +1 -1
- package/src/partial.ts +3 -2
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +11 -0
- package/src/ref.ts +1 -0
- package/src/references.ts +52 -31
- package/src/report-schema.ts +68 -0
- package/src/report.ts +101 -224
- 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 -1114
- package/src/roots.ts +339 -104
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +763 -22
- package/src/session.ts +70 -54
- package/src/source-files.ts +1 -1
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +2 -2
- package/src/suppress.ts +43 -58
- package/src/sweep.ts +23 -9
- package/src/symbol-keys.ts +2 -5
- package/src/template-field.ts +15 -25
- package/src/test-support.ts +17 -13
- 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 +18 -288
- package/src/unseen-loads.ts +134 -0
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +224 -162
- package/src/verbs/describe.ts +14 -15
- package/src/verbs/explain.ts +10 -11
- 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 +74 -64
- package/dist/src/base-url.js +0 -18
- package/dist/src/discover.js +0 -468
- 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/base-url.ts +0 -24
- package/src/discover.ts +0 -653
- 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) {
|
|
@@ -271,13 +286,6 @@ export interface ProjectView<Brand> {
|
|
|
271
286
|
*/
|
|
272
287
|
export type ProjectVisitor<Result> = <Brand>(project: ProjectView<Brand>) => Result;
|
|
273
288
|
|
|
274
|
-
/** One project a session opened: its configuration and the files of its own program. */
|
|
275
|
-
export interface OpenedFiles {
|
|
276
|
-
readonly configFile: string;
|
|
277
|
-
/** The program's source files no default library and no external library holds. */
|
|
278
|
-
readonly fileNames: () => readonly string[];
|
|
279
|
-
}
|
|
280
|
-
|
|
281
289
|
/**
|
|
282
290
|
* The source files of one program that `own` admits, in the program's order, none of
|
|
283
291
|
* them one of the compiler's default libraries.
|
|
@@ -471,19 +479,30 @@ export function diagnosticsOf<Brand>(project: ProjectView<Brand>): ProjectDiagno
|
|
|
471
479
|
};
|
|
472
480
|
}
|
|
473
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
|
+
|
|
474
488
|
/** One run's result: what the visitor answered for each project, and what it cost. */
|
|
475
489
|
export interface SessionResult<Result> {
|
|
476
|
-
/** One answer per configuration
|
|
490
|
+
/** One answer per configuration, in the order named. */
|
|
477
491
|
readonly projects: readonly Result[];
|
|
478
|
-
/** The configurations the snapshot opened no project for, in the order named. */
|
|
479
|
-
readonly unopened: readonly string[];
|
|
480
492
|
readonly timing: TimingInfo;
|
|
481
|
-
/** Every question the checker could not answer, each once, in the order first asked. */
|
|
482
|
-
readonly unanswered: readonly UnansweredQuestion[];
|
|
483
493
|
}
|
|
484
494
|
|
|
485
|
-
/**
|
|
486
|
-
|
|
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
|
+
}
|
|
487
506
|
|
|
488
507
|
/**
|
|
489
508
|
* The projects one snapshot holds for the configurations named, by configuration file. A
|
|
@@ -512,22 +531,18 @@ function projectsOf(
|
|
|
512
531
|
}
|
|
513
532
|
|
|
514
533
|
/**
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
* `first` runs over every opened project before the first visit and `last` after the last,
|
|
520
|
-
* 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.
|
|
521
538
|
*/
|
|
522
|
-
export function
|
|
539
|
+
export function openSession<Result>(
|
|
523
540
|
engine: Engine,
|
|
524
541
|
configFiles: readonly string[],
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
first: (opened: readonly OpenedFiles[]) => void = () => undefined,
|
|
530
|
-
): SessionResult<Result> {
|
|
542
|
+
options: SessionOptions,
|
|
543
|
+
use: (opened: OpenedSession, unanswered: () => readonly UnansweredQuestion[]) => Result,
|
|
544
|
+
): Result {
|
|
545
|
+
const programs = options.programs ?? new Map<string, ProgramBuild>();
|
|
531
546
|
try {
|
|
532
547
|
const built: string[] = [];
|
|
533
548
|
const params: CreateSnapshotProgramParams[] = [];
|
|
@@ -552,32 +567,13 @@ export function runSession<Result>(
|
|
|
552
567
|
const opened = projectsOf(snapshot, built, written);
|
|
553
568
|
const log = new UnansweredLog();
|
|
554
569
|
const views: ProjectView<unknown>[] = [];
|
|
555
|
-
const missing: string[] = [];
|
|
556
570
|
for (const configFile of configFiles) {
|
|
557
571
|
const project = opened.get(configFile);
|
|
558
|
-
if (project
|
|
559
|
-
|
|
560
|
-
throw new DiscoveryError(`${configFile} opened no project`, []);
|
|
561
|
-
}
|
|
562
|
-
missing.push(configFile);
|
|
563
|
-
continue;
|
|
572
|
+
if (project !== undefined) {
|
|
573
|
+
views.push(viewOf(project, configFile, engine, log));
|
|
564
574
|
}
|
|
565
|
-
views.push(viewOf(project, configFile, engine, log));
|
|
566
575
|
}
|
|
567
|
-
|
|
568
|
-
views.map((view) => ({
|
|
569
|
-
configFile: view.configFile,
|
|
570
|
-
fileNames: () => view.ownSourceFiles().map((file) => file.fileName),
|
|
571
|
-
})),
|
|
572
|
-
);
|
|
573
|
-
const projects = views.map((view) => visit(view));
|
|
574
|
-
last();
|
|
575
|
-
return {
|
|
576
|
-
projects,
|
|
577
|
-
unopened: missing,
|
|
578
|
-
timing: engine.getTimingInfo(),
|
|
579
|
-
unanswered: log.questions,
|
|
580
|
-
};
|
|
576
|
+
return use({ views }, () => log.questions);
|
|
581
577
|
} finally {
|
|
582
578
|
snapshot.dispose();
|
|
583
579
|
}
|
|
@@ -585,3 +581,23 @@ export function runSession<Result>(
|
|
|
585
581
|
engine.close();
|
|
586
582
|
}
|
|
587
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,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { SourceFile } from "@typescript/native/ast";
|
|
8
|
-
import { commonDirectory, emittedFrom } from "./emit-map.ts";
|
|
8
|
+
import { commonDirectory, emittedFrom } from "./load/emit-map.ts";
|
|
9
9
|
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
|
|
10
10
|
import type { ProjectView } from "./session.ts";
|
|
11
11
|
|
package/src/suppress-file.ts
CHANGED
|
@@ -5,18 +5,17 @@
|
|
|
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,
|
|
22
21
|
isPartKind,
|
|
@@ -27,6 +26,7 @@ import {
|
|
|
27
26
|
type SuppressionRecord,
|
|
28
27
|
type Suppressions,
|
|
29
28
|
} from "./suppress.ts";
|
|
29
|
+
import { message } from "./product.ts";
|
|
30
30
|
|
|
31
31
|
/** The name and the location the grammar fixes for the ignore file. */
|
|
32
32
|
export const IGNORE_FILE = "deadset-ignore.json";
|
|
@@ -80,10 +80,6 @@ function documentSite(shape: Shape): Position {
|
|
|
80
80
|
return { path: shape.file, line: 0, column: 0 };
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
function isObject(value: unknown): value is Record<string, unknown> {
|
|
84
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
83
|
/** What one entry or row resolves to. */
|
|
88
84
|
interface Read {
|
|
89
85
|
readonly records: readonly SuppressionRecord[];
|
|
@@ -101,7 +97,7 @@ function readRecord(value: unknown, site: Position, byReference: ByReference, sh
|
|
|
101
97
|
const refuse = (text: string, want: string): never => {
|
|
102
98
|
throw new SuppressionError(shape.mechanism, siteText(site), text, want);
|
|
103
99
|
};
|
|
104
|
-
if (!
|
|
100
|
+
if (!isRecord(value)) {
|
|
105
101
|
return refuse(JSON.stringify(value), shape.recordWant);
|
|
106
102
|
}
|
|
107
103
|
for (const [key, held] of Object.entries(value)) {
|
|
@@ -148,10 +144,10 @@ function readRecord(value: unknown, site: Position, byReference: ByReference, sh
|
|
|
148
144
|
};
|
|
149
145
|
const refusals: Refusal[] = [];
|
|
150
146
|
if (blankReason(reason)) {
|
|
151
|
-
refusals.push({ ...written, reported:
|
|
147
|
+
refusals.push({ ...written, reported: CODE.suppressionWithoutReason });
|
|
152
148
|
}
|
|
153
149
|
if (written.path === "") {
|
|
154
|
-
refusals.push({ ...written, reported:
|
|
150
|
+
refusals.push({ ...written, reported: CODE.unscopedIgnoreEntry });
|
|
155
151
|
}
|
|
156
152
|
if (refusals.length > 0) {
|
|
157
153
|
return { records: [], refusals };
|
|
@@ -189,30 +185,26 @@ function readDocument(
|
|
|
189
185
|
symbols: readonly InventorySymbol[],
|
|
190
186
|
shape: Shape,
|
|
191
187
|
): Suppressions {
|
|
192
|
-
const
|
|
193
|
-
if (
|
|
188
|
+
const text = readTargetDocument(host, targetRoot, shape.file);
|
|
189
|
+
if (text === undefined) {
|
|
194
190
|
return { records: [], refusals: [] };
|
|
195
191
|
}
|
|
196
|
-
const text = host.readFile(file);
|
|
197
192
|
const malformed = (detail: string, site = documentSite(shape)): never => {
|
|
198
193
|
throw new SuppressionError(shape.mechanism, siteText(site), detail, shape.documentWant);
|
|
199
194
|
};
|
|
200
|
-
let
|
|
195
|
+
let document;
|
|
201
196
|
try {
|
|
202
|
-
|
|
197
|
+
document = readStrict(text, shape.array);
|
|
203
198
|
} catch (error: unknown) {
|
|
204
|
-
|
|
199
|
+
if (!(error instanceof StrictJSONError)) {
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
return malformed(error.message, positionAt(text, shape.file, error.offset));
|
|
205
203
|
}
|
|
206
|
-
|
|
204
|
+
const parsed = document.value;
|
|
205
|
+
if (!isRecord(parsed)) {
|
|
207
206
|
return malformed(shape.file);
|
|
208
207
|
}
|
|
209
|
-
const walk = walkDocument(text, shape.array);
|
|
210
|
-
if (walk.twice !== undefined) {
|
|
211
|
-
malformed(
|
|
212
|
-
`the member ${JSON.stringify(walk.twice.name)} is written twice, so neither value is chosen`,
|
|
213
|
-
positionAt(text, shape.file, walk.twice.offset),
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
208
|
for (const key of Object.keys(parsed)) {
|
|
217
209
|
if (key !== "description" && key !== shape.array) {
|
|
218
210
|
malformed(`the member ${JSON.stringify(key)} is not one the grammar declares`);
|
|
@@ -228,7 +220,7 @@ function readDocument(
|
|
|
228
220
|
const records: SuppressionRecord[] = [];
|
|
229
221
|
const refusals: Refusal[] = [];
|
|
230
222
|
(held as readonly unknown[]).forEach((value, index) => {
|
|
231
|
-
const offset =
|
|
223
|
+
const offset = document.starts.get(index);
|
|
232
224
|
const site = offset === undefined ? documentSite(shape) : positionAt(text, shape.file, offset);
|
|
233
225
|
const read = readRecord(value, site, byReference, shape);
|
|
234
226
|
records.push(...read.records);
|
|
@@ -329,9 +321,9 @@ export function otherSchemeRows(text: string, own: string = OWN_SCHEME): readonl
|
|
|
329
321
|
try {
|
|
330
322
|
parsed = JSON.parse(text);
|
|
331
323
|
} catch (error: unknown) {
|
|
332
|
-
return refuse(
|
|
324
|
+
return refuse(message(error));
|
|
333
325
|
}
|
|
334
|
-
const held =
|
|
326
|
+
const held = isRecord(parsed) ? parsed[BASELINE_SHAPE.array] : undefined;
|
|
335
327
|
if (!Array.isArray(held)) {
|
|
336
328
|
return refuse(BASELINE_SHAPE.documentWant);
|
|
337
329
|
}
|
|
@@ -339,7 +331,7 @@ export function otherSchemeRows(text: string, own: string = OWN_SCHEME): readonl
|
|
|
339
331
|
try {
|
|
340
332
|
readRecord(value, documentSite(BASELINE_SHAPE), new Map(), BASELINE_SHAPE);
|
|
341
333
|
} catch (error: unknown) {
|
|
342
|
-
return refuse(
|
|
334
|
+
return refuse(message(error));
|
|
343
335
|
}
|
|
344
336
|
// readRecord has checked every member is a string and the code and symbol are present.
|
|
345
337
|
const { code, symbol, path, reason } = value as Readonly<Record<string, string>>;
|
|
@@ -386,10 +378,9 @@ function* separatorsEscaped(pieces: Iterable<string>): Generator<string, void, u
|
|
|
386
378
|
* A baseline holding one row per finding, in the order given, which is the report's, and
|
|
387
379
|
* the other language's rows `kept`, Go's rows ahead of TypeScript's and each scheme's in
|
|
388
380
|
* the order given, so two analyzers writing one document in either order write the same
|
|
389
|
-
* bytes, in the form grammar/suppression.md fixes. Every
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
* 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.
|
|
393
384
|
*/
|
|
394
385
|
export function writeBaseline(
|
|
395
386
|
findings: readonly Recorded[],
|
package/src/suppress-inline.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
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,
|
|
@@ -18,7 +19,6 @@ import type { ProjectView } from "./session.ts";
|
|
|
18
19
|
import { signatureOf } from "./signatures.ts";
|
|
19
20
|
import {
|
|
20
21
|
isPartKind,
|
|
21
|
-
SUPPRESSION_WITHOUT_REASON,
|
|
22
22
|
SuppressionError,
|
|
23
23
|
siteText,
|
|
24
24
|
type Refusal,
|
|
@@ -354,7 +354,7 @@ export function inlineSuppressions(
|
|
|
354
354
|
case "no-reason":
|
|
355
355
|
for (const code of directive.codes) {
|
|
356
356
|
refusals.push({
|
|
357
|
-
reported:
|
|
357
|
+
reported: CODE.suppressionWithoutReason,
|
|
358
358
|
code,
|
|
359
359
|
symbol: "",
|
|
360
360
|
path: site.path,
|
package/src/suppress.ts
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* withholds every such finding anyway, and stale otherwise.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
type CODE,
|
|
12
|
+
KIND_ROWS,
|
|
13
|
+
SYMBOL_SUBJECTS,
|
|
14
|
+
type Subject,
|
|
15
|
+
} from "./contract/contract.generated.ts";
|
|
16
|
+
import { UsageError } from "./usage.ts";
|
|
11
17
|
import type { Finding } from "./finding.ts";
|
|
12
18
|
import { positionKey, type Position } from "./position.ts";
|
|
13
19
|
import { isRef } from "./ref.ts";
|
|
@@ -15,15 +21,6 @@ import { isRef } from "./ref.ts";
|
|
|
15
21
|
/** Which document a suppression is written in, spelled as a finding carries it. */
|
|
16
22
|
export type Mechanism = "inline" | "ignore" | "baseline";
|
|
17
23
|
|
|
18
|
-
/** The code a suppression that carries no reason is reported under. */
|
|
19
|
-
export const SUPPRESSION_WITHOUT_REASON = "DS1701";
|
|
20
|
-
|
|
21
|
-
/** The code an ignore entry or a baseline row that names no path is reported under. */
|
|
22
|
-
export const UNSCOPED_ENTRY = "DS1702";
|
|
23
|
-
|
|
24
|
-
/** The code a suppression that withholds nothing is reported under. */
|
|
25
|
-
export const STALE_SUPPRESSION = "DS1703";
|
|
26
|
-
|
|
27
24
|
/**
|
|
28
25
|
* One suppression record: one code bound to one site. A directive naming two codes is two
|
|
29
26
|
* records with one reason, and a directive above a line that declares two symbols is one
|
|
@@ -49,7 +46,7 @@ export interface SuppressionRecord {
|
|
|
49
46
|
* nothing, and its finding reports the suppression as written.
|
|
50
47
|
*/
|
|
51
48
|
export interface Refusal {
|
|
52
|
-
readonly reported: typeof
|
|
49
|
+
readonly reported: typeof CODE.suppressionWithoutReason | typeof CODE.unscopedIgnoreEntry;
|
|
53
50
|
readonly code: string;
|
|
54
51
|
/** The reference the entry names, empty for a directive. */
|
|
55
52
|
readonly symbol: string;
|
|
@@ -71,9 +68,9 @@ export interface Suppressions {
|
|
|
71
68
|
* instruction the analysis cannot carry out. It is a malformed input, so the command line
|
|
72
69
|
* answers it with the usage code.
|
|
73
70
|
*/
|
|
74
|
-
export class SuppressionError extends
|
|
71
|
+
export class SuppressionError extends UsageError {
|
|
75
72
|
constructor(mechanism: Mechanism, at: string, text: string, want: string) {
|
|
76
|
-
super(
|
|
73
|
+
super(`${mechanism} ${at}: ${text}: want ${want}`);
|
|
77
74
|
this.name = "SuppressionError";
|
|
78
75
|
}
|
|
79
76
|
}
|
|
@@ -115,6 +112,7 @@ export const GO_REF_EXPRESSIONS: readonly string[] = [
|
|
|
115
112
|
`^go://${GO_PATH}#${GO_IDENT}$`,
|
|
116
113
|
`^go://${GO_PATH}#${GO_IDENT}(?:\\.${GO_IDENT})+$`,
|
|
117
114
|
`^go://${GO_PATH}#${GO_IDENT}(?:\\.${GO_IDENT})?\\[${GO_IDENT}\\]$`,
|
|
115
|
+
`^go://${GO_PATH}#(?:${GO_IDENT}(?:\\.${GO_IDENT})?)?\\(${GO_IDENT}\\)$`,
|
|
118
116
|
`^go://${GO_PATH}#${GO_FILE}:file$`,
|
|
119
117
|
`^go://${GO_PATH}#${GO_PATH}(?:@${GO_VERSION})?:require$`,
|
|
120
118
|
`^go://${GO_PATH}#${GO_PATH}(?:@${GO_VERSION})?:replace$`,
|
|
@@ -157,48 +155,48 @@ export interface Ledger {
|
|
|
157
155
|
readonly withheld: (finding: Finding) => boolean;
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
]
|
|
158
|
+
/** The subject of the kind each live code names. */
|
|
159
|
+
const SUBJECT_OF_CODE: ReadonlyMap<string, Subject> = new Map(
|
|
160
|
+
KIND_ROWS.map((row): [string, Subject] => [row.code, row.subject]),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
/** The subject a finding about one symbol kind is about. */
|
|
164
|
+
function subjectOf(kind: string): Subject | undefined {
|
|
165
|
+
return Object.hasOwn(SYMBOL_SUBJECTS, kind)
|
|
166
|
+
? SYMBOL_SUBJECTS[kind as keyof typeof SYMBOL_SUBJECTS]
|
|
167
|
+
: undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Whether a subject is a row of a document rather than a declaration of the program. */
|
|
171
|
+
function rowOf(subject: Subject | undefined): boolean {
|
|
172
|
+
return subject === "file" || subject === "dependency" || subject === "record";
|
|
173
|
+
}
|
|
169
174
|
|
|
170
175
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* finding about one.
|
|
176
|
+
* Whether a finding's subject is a row of a document rather than a declaration. Apart
|
|
177
|
+
* from a dependency row, nothing withholds a finding about one.
|
|
174
178
|
*/
|
|
175
|
-
const ROW_SUBJECTS: ReadonlyMap<string, readonly string[]> = new Map([
|
|
176
|
-
["file", ["DS1501", "DS1502"]],
|
|
177
|
-
...DEPENDENCY_SUBJECTS,
|
|
178
|
-
["root", ["DS1704"]],
|
|
179
|
-
["configured-declaration", ["DS1706"]],
|
|
180
|
-
["suppression", ["DS1701", "DS1702", "DS1703"]],
|
|
181
|
-
["edge", ["DS1705"]],
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
/** Whether a finding's subject is a row of a document rather than a declaration. */
|
|
185
179
|
export function isRowSubject(kind: string): boolean {
|
|
186
|
-
return
|
|
180
|
+
return rowOf(subjectOf(kind));
|
|
187
181
|
}
|
|
188
182
|
|
|
189
183
|
/** Whether a code reports a row of a document. */
|
|
190
184
|
export function isRowCode(code: string): boolean {
|
|
191
|
-
return
|
|
185
|
+
return rowOf(SUBJECT_OF_CODE.get(code));
|
|
192
186
|
}
|
|
193
187
|
|
|
194
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* Whether a finding's subject is a dependency row. An ignore entry or a baseline row
|
|
190
|
+
* naming the row's reference and file withholds its finding and marks nothing, and an
|
|
191
|
+
* inline directive never binds one.
|
|
192
|
+
*/
|
|
195
193
|
export function isDependencySubject(kind: string): boolean {
|
|
196
|
-
return
|
|
194
|
+
return subjectOf(kind) === "dependency";
|
|
197
195
|
}
|
|
198
196
|
|
|
199
197
|
/** Whether a code reports a dependency row, which only an ignore entry or a baseline row names. */
|
|
200
198
|
export function isDependencyCode(code: string): boolean {
|
|
201
|
-
return
|
|
199
|
+
return SUBJECT_OF_CODE.get(code) === "dependency";
|
|
202
200
|
}
|
|
203
201
|
|
|
204
202
|
/** Whether a code reports a row of a document that no record of any mechanism can name. */
|
|
@@ -207,33 +205,20 @@ export function isUnsuppressibleCode(code: string): boolean {
|
|
|
207
205
|
}
|
|
208
206
|
|
|
209
207
|
/**
|
|
210
|
-
*
|
|
208
|
+
* Whether a finding's subject is a part of the declaration its reference names: a part
|
|
211
209
|
* has no reference of its own, so a finding about one names the declaration that holds
|
|
212
210
|
* it, and the part is decided inside that declaration whatever uses it.
|
|
213
211
|
*/
|
|
214
|
-
const PART_SUBJECTS: ReadonlySet<string> = new Set([
|
|
215
|
-
"parameter",
|
|
216
|
-
"receiver",
|
|
217
|
-
"result",
|
|
218
|
-
"statement",
|
|
219
|
-
"case",
|
|
220
|
-
"store",
|
|
221
|
-
]);
|
|
222
|
-
|
|
223
|
-
/** Whether a finding's subject is a part of the declaration its reference names. */
|
|
224
212
|
export function isPartSubject(kind: string): boolean {
|
|
225
|
-
return
|
|
213
|
+
return subjectOf(kind) === "part";
|
|
226
214
|
}
|
|
227
215
|
|
|
228
|
-
/** The prefix of the codes of the part kinds, the intra-function range. */
|
|
229
|
-
const PART_KIND_PREFIX = "DS18";
|
|
230
|
-
|
|
231
216
|
/**
|
|
232
217
|
* Whether a code is a part kind, whose record withholds its finding and marks nothing:
|
|
233
218
|
* the record says the part is wanted, not that the declaration holding it is.
|
|
234
219
|
*/
|
|
235
220
|
export function isPartKind(code: string): boolean {
|
|
236
|
-
return
|
|
221
|
+
return SUBJECT_OF_CODE.get(code) === "part";
|
|
237
222
|
}
|
|
238
223
|
|
|
239
224
|
/** One finding's identity: its code and the position of the thing it names. */
|
|
@@ -253,14 +238,14 @@ export function pairs(record: SuppressionRecord, finding: Finding): boolean {
|
|
|
253
238
|
if (record.code !== finding.code) {
|
|
254
239
|
return false;
|
|
255
240
|
}
|
|
256
|
-
if (
|
|
241
|
+
if (isDependencySubject(finding.symbol.kind)) {
|
|
257
242
|
return (
|
|
258
243
|
record.mechanism !== "inline" &&
|
|
259
244
|
record.symbol === finding.symbol.ref &&
|
|
260
245
|
record.path === finding.position.path
|
|
261
246
|
);
|
|
262
247
|
}
|
|
263
|
-
if (
|
|
248
|
+
if (isRowSubject(finding.symbol.kind)) {
|
|
264
249
|
return false;
|
|
265
250
|
}
|
|
266
251
|
if (record.bound !== "" && record.bound === positionKey(finding.position)) {
|
package/src/sweep.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface Exemption {
|
|
|
33
33
|
* The record holds only while one of them is called through its interface.
|
|
34
34
|
*/
|
|
35
35
|
readonly implementing?: Implementing;
|
|
36
|
+
/** Whether the record holds only where a write the mode counts stores into the declaration. */
|
|
37
|
+
readonly whileWritten?: true;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/** The interface methods one retained class member implements, and whether its body is empty. */
|
|
@@ -195,10 +197,14 @@ export function runnerCalls(symbol: InventorySymbol): boolean {
|
|
|
195
197
|
* That run's roots are the graph's own and, of each test file, its top level and every
|
|
196
198
|
* function it exports, which a test runner may call, and every export of a manual mock,
|
|
197
199
|
* which the runner reads; any other export of a test file, and test-support code, which
|
|
198
|
-
* runs where a test imports it, are judged as any file's are.
|
|
199
|
-
* `
|
|
200
|
+
* runs where a test imports it, are judged as any file's are. `held` seeds it as a mark
|
|
201
|
+
* seeds a sweep; with `namespaces` false a file read reaches none of the file's exports.
|
|
200
202
|
*/
|
|
201
|
-
export function reachedWithTheTests(
|
|
203
|
+
export function reachedWithTheTests(
|
|
204
|
+
graph: Graph,
|
|
205
|
+
held: readonly string[],
|
|
206
|
+
namespaces = true,
|
|
207
|
+
): readonly boolean[] {
|
|
202
208
|
const tests = graph.symbols.flatMap((symbol, at) => {
|
|
203
209
|
const exported = symbol.exported && graph.symbols[graph.parent[at] ?? OUTSIDE]?.kind === "file";
|
|
204
210
|
const called = exported && runnerCalls(symbol);
|
|
@@ -208,9 +214,12 @@ export function reachedWithTheTests(graph: Graph, held: readonly string[]): read
|
|
|
208
214
|
? [{ at, kind: "test-runner" as const }]
|
|
209
215
|
: [];
|
|
210
216
|
});
|
|
211
|
-
return reachable(
|
|
212
|
-
|
|
213
|
-
|
|
217
|
+
return reachable(
|
|
218
|
+
{ ...graph, rooted: [...graph.rooted, ...tests] },
|
|
219
|
+
flagged(graph, held),
|
|
220
|
+
{ production: false },
|
|
221
|
+
namespaces,
|
|
222
|
+
);
|
|
214
223
|
}
|
|
215
224
|
|
|
216
225
|
/**
|
|
@@ -240,7 +249,12 @@ function flagged(graph: Graph, ids: readonly string[]): boolean[] {
|
|
|
240
249
|
* included, while a root reaches through the references the mode counts. The held seed
|
|
241
250
|
* runs first, so what it reaches is expanded under the wider rule.
|
|
242
251
|
*/
|
|
243
|
-
function reachable(
|
|
252
|
+
function reachable(
|
|
253
|
+
graph: Graph,
|
|
254
|
+
held: readonly boolean[],
|
|
255
|
+
mode: Mode,
|
|
256
|
+
namespaces = true,
|
|
257
|
+
): readonly boolean[] {
|
|
244
258
|
const reached = graph.symbols.map(() => false);
|
|
245
259
|
const expanded = graph.symbols.map(() => false);
|
|
246
260
|
const queue: number[] = [];
|
|
@@ -269,7 +283,7 @@ function reachable(graph: Graph, held: readonly boolean[], mode: Mode): readonly
|
|
|
269
283
|
if (!holding && mode.production && edge.test) {
|
|
270
284
|
continue;
|
|
271
285
|
}
|
|
272
|
-
enter(edge.to, !edge.evaluation);
|
|
286
|
+
enter(edge.to, namespaces && !edge.evaluation);
|
|
273
287
|
}
|
|
274
288
|
}
|
|
275
289
|
};
|
|
@@ -285,7 +299,7 @@ function reachable(graph: Graph, held: readonly boolean[], mode: Mode): readonly
|
|
|
285
299
|
}
|
|
286
300
|
// A consumer's reference reaches what it names as one of the target's own does.
|
|
287
301
|
for (const edge of callsOf(graph, mode)) {
|
|
288
|
-
enter(edge.to, !edge.evaluation);
|
|
302
|
+
enter(edge.to, namespaces && !edge.evaluation);
|
|
289
303
|
}
|
|
290
304
|
walk(false);
|
|
291
305
|
return reached;
|