@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
|
@@ -1,47 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The workspace a target sits in: the packages `pnpm-workspace.yaml` or a manifest's
|
|
3
|
-
* `workspaces` declares in the nearest directory at or above the target root, up to
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* member is the workspace root or a directory the patterns name that holds a named
|
|
7
|
-
* manifest, never one below `node_modules`.
|
|
3
|
+
* `workspaces` declares in the nearest directory at or above the target root, up to its
|
|
4
|
+
* repository root, where its patterns name the package the target is in, each with the
|
|
5
|
+
* compiler configurations in its directory.
|
|
8
6
|
*/
|
|
9
|
-
import {
|
|
7
|
+
import { configFilesIn } from "./discover.js";
|
|
8
|
+
import { failureExit } from "../failure.js";
|
|
10
9
|
import { commonDirectory } from "./emit-map.js";
|
|
11
|
-
import { dirnamePath, joinPath, relativePath } from "
|
|
12
|
-
import {
|
|
13
|
-
|
|
10
|
+
import { ancestors, dirnamePath, joinPath, relativePath } from "../paths.js";
|
|
11
|
+
import { bytewise } from "../text/compare.js";
|
|
12
|
+
import { isRecord } from "../json-document.js";
|
|
13
|
+
import { directoriesIn, repositoryOf } from "../fs/tree.js";
|
|
14
|
+
import { holdsManifest, inInstalledPackages, INSTALLED_PACKAGES, MANIFEST, manifestAt, } from "../fs/manifest.js";
|
|
15
|
+
import { braceExpanded, pathMatches, segmentMatches } from "../text/glob.js";
|
|
16
|
+
import { yamlKey } from "../text/yaml.js";
|
|
14
17
|
const PNPM_WORKSPACE = "pnpm-workspace.yaml";
|
|
15
|
-
const CONFIG_FILE = /^tsconfig.*\.json$/u;
|
|
16
|
-
function isRecord(value) {
|
|
17
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18
|
-
}
|
|
19
|
-
/** One manifest, decoded, or `undefined` where there is none to read. */
|
|
20
|
-
function manifestAt(host, dir) {
|
|
21
|
-
let text;
|
|
22
|
-
try {
|
|
23
|
-
text = host.readFile(joinPath(dir, MANIFEST));
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const value = JSON.parse(text);
|
|
30
|
-
return isRecord(value) ? value : undefined;
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
18
|
/** The patterns one directory declares a workspace with, or `undefined` where it declares none. */
|
|
37
19
|
function declarationAt(host, dir) {
|
|
38
20
|
const pnpm = joinPath(dir, PNPM_WORKSPACE);
|
|
39
21
|
if (host.kindOf(pnpm) === "file") {
|
|
40
|
-
const read =
|
|
41
|
-
if (read.kind === "
|
|
42
|
-
|
|
22
|
+
const read = yamlKey(host.readFile(pnpm), "packages");
|
|
23
|
+
if (read.kind === "absent") {
|
|
24
|
+
return { file: pnpm, patterns: [] };
|
|
43
25
|
}
|
|
44
|
-
|
|
26
|
+
const listed = read.kind === "value" ? read.value : undefined;
|
|
27
|
+
if (!Array.isArray(listed) || !listed.every((entry) => typeof entry === "string")) {
|
|
28
|
+
const reason = read.kind === "refused" ? read.reason : "packages is not a sequence of strings";
|
|
29
|
+
throw failureExit("no-program", `${pnpm}: ${reason}; the workspace's packages are read from a sequence of strings: correct the declaration`);
|
|
30
|
+
}
|
|
31
|
+
return { file: pnpm, patterns: listed };
|
|
45
32
|
}
|
|
46
33
|
const manifest = manifestAt(host, dir);
|
|
47
34
|
if (manifest === undefined || !Object.hasOwn(manifest, "workspaces")) {
|
|
@@ -50,7 +37,7 @@ function declarationAt(host, dir) {
|
|
|
50
37
|
const declared = manifest["workspaces"];
|
|
51
38
|
const list = isRecord(declared) ? declared["packages"] : declared;
|
|
52
39
|
if (!Array.isArray(list) || !list.every((entry) => typeof entry === "string")) {
|
|
53
|
-
throw
|
|
40
|
+
throw failureExit("no-program", `${joinPath(dir, MANIFEST)}: workspaces is neither an array of strings nor an object whose packages is one: correct the declaration`);
|
|
54
41
|
}
|
|
55
42
|
return { file: joinPath(dir, MANIFEST), patterns: list };
|
|
56
43
|
}
|
|
@@ -62,20 +49,6 @@ function declaresWorkspace(host, dir) {
|
|
|
62
49
|
const manifest = manifestAt(host, dir);
|
|
63
50
|
return manifest !== undefined && Object.hasOwn(manifest, "workspaces");
|
|
64
51
|
}
|
|
65
|
-
/** A pattern with every brace list expanded into its alternatives. */
|
|
66
|
-
function braceExpanded(pattern) {
|
|
67
|
-
const open = pattern.indexOf("{");
|
|
68
|
-
const close = open < 0 ? -1 : pattern.indexOf("}", open);
|
|
69
|
-
if (close < 0) {
|
|
70
|
-
return [pattern];
|
|
71
|
-
}
|
|
72
|
-
const before = pattern.slice(0, open);
|
|
73
|
-
const after = pattern.slice(close + 1);
|
|
74
|
-
return pattern
|
|
75
|
-
.slice(open + 1, close)
|
|
76
|
-
.split(",")
|
|
77
|
-
.flatMap((member) => braceExpanded(before + member + after));
|
|
78
|
-
}
|
|
79
52
|
/**
|
|
80
53
|
* The segments of one pattern below the workspace root, `.` and empty segments
|
|
81
54
|
* dropped and `..` taken back, or `undefined` where it leaves the root.
|
|
@@ -96,52 +69,6 @@ function segmentsOf(pattern) {
|
|
|
96
69
|
}
|
|
97
70
|
return segments;
|
|
98
71
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Whether one directory name matches one pattern segment: `*` stands for any run of
|
|
101
|
-
* characters and `?` for one, and neither matches a leading dot.
|
|
102
|
-
*/
|
|
103
|
-
function segmentMatches(segment, name) {
|
|
104
|
-
if (name.startsWith(".") && !segment.startsWith(".")) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
const source = Array.from(segment)
|
|
108
|
-
.map((character) => {
|
|
109
|
-
if (character === "*") {
|
|
110
|
-
return ".*";
|
|
111
|
-
}
|
|
112
|
-
if (character === "?") {
|
|
113
|
-
return ".";
|
|
114
|
-
}
|
|
115
|
-
return character.replaceAll(/[.+^${}()|[\]\\/]/gu, (c) => `\\${c}`);
|
|
116
|
-
})
|
|
117
|
-
.join("");
|
|
118
|
-
return new RegExp(`^${source}$`, "u").test(name);
|
|
119
|
-
}
|
|
120
|
-
/** Whether one path's segments match one pattern's, `**` standing for any run of segments. */
|
|
121
|
-
function pathMatches(pattern, path) {
|
|
122
|
-
const [head, ...rest] = pattern;
|
|
123
|
-
if (head === undefined) {
|
|
124
|
-
return path.length === 0;
|
|
125
|
-
}
|
|
126
|
-
if (head === "**") {
|
|
127
|
-
return (pathMatches(rest, path) ||
|
|
128
|
-
(path.length > 0 && !(path[0] ?? "").startsWith(".") && pathMatches(pattern, path.slice(1))));
|
|
129
|
-
}
|
|
130
|
-
const [name, ...below] = path;
|
|
131
|
-
return name !== undefined && segmentMatches(head, name) && pathMatches(rest, below);
|
|
132
|
-
}
|
|
133
|
-
function subdirectories(host, dir) {
|
|
134
|
-
try {
|
|
135
|
-
return host
|
|
136
|
-
.readDirectory(dir)
|
|
137
|
-
.filter((entry) => entry.directory && entry.name !== "node_modules" && entry.name !== ".git")
|
|
138
|
-
.map((entry) => entry.name)
|
|
139
|
-
.sort();
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
return [];
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
72
|
/**
|
|
146
73
|
* Every directory below `dir` one pattern names. `**` does not descend into a
|
|
147
74
|
* directory that declares a workspace of its own, whose packages are that
|
|
@@ -155,7 +82,7 @@ function expand(host, dir, pattern, into) {
|
|
|
155
82
|
}
|
|
156
83
|
if (head === "**") {
|
|
157
84
|
expand(host, dir, rest, into);
|
|
158
|
-
for (const name of
|
|
85
|
+
for (const name of directoriesIn(host, dir)) {
|
|
159
86
|
if (name.startsWith(".")) {
|
|
160
87
|
continue;
|
|
161
88
|
}
|
|
@@ -166,12 +93,12 @@ function expand(host, dir, pattern, into) {
|
|
|
166
93
|
}
|
|
167
94
|
if (!head.includes("*") && !head.includes("?")) {
|
|
168
95
|
const child = joinPath(dir, head);
|
|
169
|
-
if (head !==
|
|
96
|
+
if (head !== INSTALLED_PACKAGES && host.kindOf(child) === "directory") {
|
|
170
97
|
expand(host, child, rest, into);
|
|
171
98
|
}
|
|
172
99
|
return;
|
|
173
100
|
}
|
|
174
|
-
for (const name of
|
|
101
|
+
for (const name of directoriesIn(host, dir)) {
|
|
175
102
|
if (segmentMatches(head, name)) {
|
|
176
103
|
expand(host, joinPath(dir, name), rest, into);
|
|
177
104
|
}
|
|
@@ -208,10 +135,10 @@ function namesDirectory(root, patterns, dir) {
|
|
|
208
135
|
if (below === undefined) {
|
|
209
136
|
return false;
|
|
210
137
|
}
|
|
211
|
-
|
|
212
|
-
if (path.includes("node_modules")) {
|
|
138
|
+
if (inInstalledPackages(below)) {
|
|
213
139
|
return false;
|
|
214
140
|
}
|
|
141
|
+
const path = below.split("/");
|
|
215
142
|
let named = false;
|
|
216
143
|
for (const written of patterns) {
|
|
217
144
|
const negated = written.startsWith("!");
|
|
@@ -238,18 +165,7 @@ function layoutOf(configFile, parsed) {
|
|
|
238
165
|
return { outDir: parsed.outDir, declarationDir: parsed.declarationDir, sourceDirs };
|
|
239
166
|
}
|
|
240
167
|
function configurationsOf(host, dir, parse) {
|
|
241
|
-
|
|
242
|
-
try {
|
|
243
|
-
names = host
|
|
244
|
-
.readDirectory(dir)
|
|
245
|
-
.filter((entry) => !entry.directory && CONFIG_FILE.test(entry.name))
|
|
246
|
-
.map((entry) => entry.name)
|
|
247
|
-
.sort();
|
|
248
|
-
}
|
|
249
|
-
catch {
|
|
250
|
-
return [];
|
|
251
|
-
}
|
|
252
|
-
return names.flatMap((name) => {
|
|
168
|
+
return configFilesIn(host, dir).flatMap((name) => {
|
|
253
169
|
const configFile = joinPath(dir, name);
|
|
254
170
|
const parsed = parse(configFile);
|
|
255
171
|
return parsed === undefined
|
|
@@ -267,31 +183,27 @@ function configurationsOf(host, dir, parse) {
|
|
|
267
183
|
* highest directory below it, at or above the target root, that holds a manifest.
|
|
268
184
|
*/
|
|
269
185
|
function nearestDeclaration(host, targetRoot) {
|
|
270
|
-
let dir = targetRoot;
|
|
271
186
|
let highestPackage;
|
|
272
|
-
for (
|
|
187
|
+
for (const dir of ancestors(targetRoot, repositoryOf(host, targetRoot)?.root)) {
|
|
273
188
|
const declared = declarationAt(host, dir);
|
|
274
189
|
if (declared !== undefined) {
|
|
275
190
|
return { root: dir, ...declared, highestPackage };
|
|
276
191
|
}
|
|
277
|
-
if (host
|
|
192
|
+
if (holdsManifest(host, dir)) {
|
|
278
193
|
highestPackage = dir;
|
|
279
194
|
}
|
|
280
|
-
const up = dirnamePath(dir);
|
|
281
|
-
if (up === dir || host.kindOf(joinPath(dir, ".git")) !== "absent") {
|
|
282
|
-
return undefined;
|
|
283
|
-
}
|
|
284
|
-
dir = up;
|
|
285
195
|
}
|
|
196
|
+
return undefined;
|
|
286
197
|
}
|
|
287
198
|
/**
|
|
288
199
|
* The workspace the target sits in, or `undefined` where none holds it: no directory
|
|
289
200
|
* from the target root up to its repository root declares one with a member beside
|
|
290
201
|
* its root, or the nearest one does not name the highest package below it, at or
|
|
291
202
|
* above the target root, among its members. `parse` reads one compiler configuration,
|
|
292
|
-
* or answers `undefined` where it does not read.
|
|
203
|
+
* or answers `undefined` where it does not read. `known`, a workspace already read, is the
|
|
204
|
+
* answer where the nearest declaration is its own, so its members are not listed again.
|
|
293
205
|
*/
|
|
294
|
-
export function findWorkspace(host, targetRoot, parse) {
|
|
206
|
+
export function findWorkspace(host, targetRoot, parse, known) {
|
|
295
207
|
const declared = nearestDeclaration(host, targetRoot);
|
|
296
208
|
if (declared === undefined) {
|
|
297
209
|
return undefined;
|
|
@@ -300,6 +212,9 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
300
212
|
!namesDirectory(declared.root, declared.patterns, declared.highestPackage)) {
|
|
301
213
|
return undefined;
|
|
302
214
|
}
|
|
215
|
+
if (known?.root === declared.root) {
|
|
216
|
+
return known;
|
|
217
|
+
}
|
|
303
218
|
const members = [];
|
|
304
219
|
for (const dir of memberDirectories(host, declared.root, declared.patterns)) {
|
|
305
220
|
const manifest = manifestAt(host, dir);
|
|
@@ -320,7 +235,10 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
320
235
|
if (members.length < 2) {
|
|
321
236
|
return undefined;
|
|
322
237
|
}
|
|
323
|
-
members.sort((a, b) => a.dir === declared.root ? -1 : b.dir === declared.root ? 1 : a.dir
|
|
238
|
+
members.sort((a, b) => a.dir === declared.root ? -1 : b.dir === declared.root ? 1 : bytewise(a.dir, b.dir));
|
|
239
|
+
return assembled(host, declared.root, members);
|
|
240
|
+
}
|
|
241
|
+
function assembled(host, root, members) {
|
|
324
242
|
const named = new Map();
|
|
325
243
|
for (const member of members) {
|
|
326
244
|
named.set(member.name, [...(named.get(member.name) ?? []), member]);
|
|
@@ -332,11 +250,12 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
332
250
|
return scopes.get(dir);
|
|
333
251
|
}
|
|
334
252
|
const up = dirnamePath(dir);
|
|
335
|
-
const found = host
|
|
253
|
+
const found = holdsManifest(host, dir) ? dir : up === dir ? undefined : scopeOf(up);
|
|
336
254
|
scopes.set(dir, found);
|
|
337
255
|
return found;
|
|
338
256
|
};
|
|
339
257
|
return {
|
|
258
|
+
root,
|
|
340
259
|
members,
|
|
341
260
|
named,
|
|
342
261
|
memberOf: (path) => {
|
|
@@ -345,6 +264,25 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
345
264
|
},
|
|
346
265
|
};
|
|
347
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* The workspace with the programs the run forms put first among each member's configurations,
|
|
269
|
+
* by the member's directory: a formed program has no file on disk to list, so its file list
|
|
270
|
+
* is what makes a member's JavaScript its source.
|
|
271
|
+
*/
|
|
272
|
+
export function withFormed(host, workspace, formed) {
|
|
273
|
+
return assembled(host, workspace.root, workspace.members.map((member) => {
|
|
274
|
+
const own = formed.get(member.dir) ?? [];
|
|
275
|
+
return own.length === 0
|
|
276
|
+
? member
|
|
277
|
+
: {
|
|
278
|
+
...member,
|
|
279
|
+
configurations: [
|
|
280
|
+
...own.map((layout) => ({ fileNames: new Set(layout.fileNames) })),
|
|
281
|
+
...member.configurations,
|
|
282
|
+
],
|
|
283
|
+
};
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
348
286
|
/**
|
|
349
287
|
* Whether one configuration holds one file only for the references it makes: the file
|
|
350
288
|
* belongs to a workspace package, the root included, and the configuration does not
|
package/dist/src/manifest.js
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* directory's manifest, {@link packageEntries} those of the packages below the target root.
|
|
6
6
|
*/
|
|
7
7
|
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
8
|
+
import { isRecord } from "./json-document.js";
|
|
9
|
+
import { MANIFEST, manifestAt, readJSON } from "./fs/manifest.js";
|
|
10
|
+
import { scriptTokens } from "./text/shell.js";
|
|
8
11
|
/** The manifest's own name. */
|
|
9
|
-
const MANIFEST = "package.json";
|
|
10
12
|
/** The three members that name an entry point beside `exports` and `bin`. */
|
|
11
13
|
const LEGACY_MEMBERS = ["main", "module", "types"];
|
|
12
|
-
function isRecord(value) {
|
|
13
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
-
}
|
|
15
14
|
/**
|
|
16
15
|
* Whether one member's value names a file of this package rather than another
|
|
17
16
|
* package or a URL. A target written with no leading dot is a path too, which is
|
|
@@ -23,31 +22,32 @@ function isTarget(value, requireDot) {
|
|
|
23
22
|
}
|
|
24
23
|
return !requireDot || value.startsWith("./");
|
|
25
24
|
}
|
|
26
|
-
/** Where a script's command line splits into tokens: white space and the shell's operators. */
|
|
27
|
-
const SCRIPT_SEPARATORS = /\s+|&&|\|\||;|\|/u;
|
|
28
|
-
/** A token written inside one pair of quotes. */
|
|
29
|
-
const QUOTED = /^(["'])(.*)\1$/su;
|
|
30
|
-
/**
|
|
31
|
-
* Every token one script's command line holds, each with one pair of enclosing quotes
|
|
32
|
-
* removed. A token holding a wildcard is a pattern rather than a path, and names no
|
|
33
|
-
* entry point.
|
|
34
|
-
*/
|
|
35
|
-
export function scriptTokens(command) {
|
|
36
|
-
return command
|
|
37
|
-
.split(SCRIPT_SEPARATORS)
|
|
38
|
-
.map((token) => token.replace(QUOTED, "$2"))
|
|
39
|
-
.filter((token) => token !== "" && !token.includes("*"));
|
|
40
|
-
}
|
|
41
25
|
/** One member's spelling below another: `exports` then `exports["."]`. */
|
|
42
26
|
function below(member, key) {
|
|
43
27
|
return `${member}[${JSON.stringify(key)}]`;
|
|
44
28
|
}
|
|
45
29
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
|
|
30
|
+
* The command strings one manifest runs, each at the member it is written under: each of its
|
|
31
|
+
* `scripts`, and the `exec` command of nodemon's configuration, in the manifest's `nodemonConfig`
|
|
32
|
+
* or the `nodemon.json` beside it, which nodemon runs the watched script with:
|
|
33
|
+
* https://github.com/remy/nodemon#config-files
|
|
34
|
+
*/
|
|
35
|
+
export function manifestCommands(host, dir, manifest) {
|
|
36
|
+
const scripts = manifest["scripts"];
|
|
37
|
+
const nodemon = {
|
|
38
|
+
nodemonConfig: manifest["nodemonConfig"],
|
|
39
|
+
"nodemon.json": readJSON(host, joinPath(dir, "nodemon.json")),
|
|
40
|
+
};
|
|
41
|
+
const written = [
|
|
42
|
+
...Object.entries(isRecord(scripts) ? scripts : {}).map(([name, value]) => [below("scripts", name), value]),
|
|
43
|
+
...Object.entries(nodemon).map(([member, config]) => [below(member, "exec"), isRecord(config) ? config["exec"] : undefined]),
|
|
44
|
+
];
|
|
45
|
+
return written.flatMap(([member, command]) => typeof command === "string" ? [{ member, command }] : []);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Every target one `exports` value carries, at the member each is written under. Every level of
|
|
49
|
+
* strings, subpath or condition objects and alternative arrays is walked, because each condition
|
|
50
|
+
* names its own entry file; a `null` blocks a subpath, and a key's meaning is never read.
|
|
51
51
|
*/
|
|
52
52
|
function exportTargets(value, member, found) {
|
|
53
53
|
if (typeof value === "string") {
|
|
@@ -69,28 +69,6 @@ function exportTargets(value, member, found) {
|
|
|
69
69
|
exportTargets(held, below(member, key), found);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
/** The manifest at the target root, decoded, or undefined where there is none to read. */
|
|
73
|
-
function manifestOf(host, targetRoot) {
|
|
74
|
-
let text;
|
|
75
|
-
try {
|
|
76
|
-
text = host.readFile(joinPath(targetRoot, MANIFEST));
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
let value;
|
|
82
|
-
try {
|
|
83
|
-
value = JSON.parse(text);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// A manifest this program cannot read names no entry point, which is the same
|
|
87
|
-
// answer as an absent one. What a manifest's contents say is not refused here:
|
|
88
|
-
// the package manager owns that refusal, and an analysis of a tree it rejects
|
|
89
|
-
// is not the run's subject.
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
return isRecord(value) ? value : undefined;
|
|
93
|
-
}
|
|
94
72
|
/**
|
|
95
73
|
* What the manifest in `targetRoot` declares about where its package is entered.
|
|
96
74
|
*
|
|
@@ -99,7 +77,7 @@ function manifestOf(host, targetRoot) {
|
|
|
99
77
|
* it and there is one such configuration per project, while there is one manifest.
|
|
100
78
|
*/
|
|
101
79
|
export function readManifest(host, targetRoot) {
|
|
102
|
-
const manifest =
|
|
80
|
+
const manifest = manifestAt(host, targetRoot);
|
|
103
81
|
if (manifest === undefined) {
|
|
104
82
|
return { entries: [], declaresExports: false };
|
|
105
83
|
}
|
|
@@ -110,6 +88,24 @@ export function readManifest(host, targetRoot) {
|
|
|
110
88
|
found.push({ member, path: value, role: "import", published: true });
|
|
111
89
|
}
|
|
112
90
|
}
|
|
91
|
+
// A `browser` string replaces `main` in a browser bundle, and an object replaces each
|
|
92
|
+
// module it maps with the file it names: https://github.com/defunctzombie/package-browser-field-spec
|
|
93
|
+
const browser = manifest["browser"];
|
|
94
|
+
if (typeof browser === "string" && isTarget(browser, false)) {
|
|
95
|
+
found.push({ member: "browser", path: browser, role: "import", published: true });
|
|
96
|
+
}
|
|
97
|
+
else if (isRecord(browser)) {
|
|
98
|
+
for (const [replaced, value] of Object.entries(browser)) {
|
|
99
|
+
if (typeof value === "string" && isTarget(value, true)) {
|
|
100
|
+
found.push({
|
|
101
|
+
member: below("browser", replaced),
|
|
102
|
+
path: value,
|
|
103
|
+
role: "import",
|
|
104
|
+
published: true,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
113
109
|
const bin = manifest["bin"];
|
|
114
110
|
if (typeof bin === "string" && isTarget(bin, false)) {
|
|
115
111
|
found.push({ member: "bin", path: bin, role: "run", published: false });
|
|
@@ -128,16 +124,15 @@ export function readManifest(host, targetRoot) {
|
|
|
128
124
|
if (typeof command !== "string") {
|
|
129
125
|
continue;
|
|
130
126
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
path: token,
|
|
135
|
-
role: "script",
|
|
136
|
-
published: false,
|
|
137
|
-
});
|
|
127
|
+
const member = below("scripts", name);
|
|
128
|
+
for (const path of new Set(scriptTokens(command))) {
|
|
129
|
+
found.push({ member, path, role: "script", published: false });
|
|
138
130
|
}
|
|
139
131
|
}
|
|
140
132
|
}
|
|
133
|
+
for (const { member, command } of manifestCommands(host, targetRoot, manifest)) {
|
|
134
|
+
found.push({ member, path: ".", role: "script", published: false, command });
|
|
135
|
+
}
|
|
141
136
|
return {
|
|
142
137
|
entries: found.map((entry) => ({
|
|
143
138
|
...entry,
|
package/dist/src/matrix.js
CHANGED
|
@@ -70,11 +70,13 @@ export function matrixOf(per) {
|
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
symbols.sort((a, b) => byPosition(a.position, b.position));
|
|
73
|
+
const testUsed = new Set(per.flatMap((one) => one.testUsedFiles ?? []));
|
|
73
74
|
return {
|
|
74
75
|
configurations: per.map((one) => one.configuration),
|
|
75
76
|
graphs: per.map((one) => graphOf(one.symbols, one.references, one.roots, one.testFiles, one.supportFiles, one.ambient)),
|
|
76
77
|
union: graphOf(symbols, references, per.flatMap((one) => one.roots), [...new Set(per.flatMap((one) => one.testFiles))], [...new Set(per.flatMap((one) => one.supportFiles ?? []))], new Set(per.flatMap((one) => [...(one.ambient ?? [])]))),
|
|
77
78
|
heldIn: symbols.map((symbol) => holders.get(symbol.id) ?? []),
|
|
79
|
+
testUsed: symbols.map((symbol) => testUsed.has(symbol.position.path)),
|
|
78
80
|
dependents,
|
|
79
81
|
};
|
|
80
82
|
}
|
|
@@ -101,18 +103,24 @@ export function sweepMatrix(matrix, input) {
|
|
|
101
103
|
]));
|
|
102
104
|
const union = matrix.union;
|
|
103
105
|
const heldBy = union.symbols.map(() => undefined);
|
|
104
|
-
const
|
|
106
|
+
const held = [
|
|
105
107
|
...input.marked,
|
|
106
108
|
...(input.exempt ?? []).map((record) => record.id),
|
|
107
109
|
...(input.unanswered ?? []),
|
|
108
|
-
]
|
|
109
|
-
const
|
|
110
|
+
];
|
|
111
|
+
const testReached = reachedWithTheTests(union, held);
|
|
112
|
+
// A test uses what it names: a file a test reads through a star re-export or a
|
|
113
|
+
// namespace keeps the exports nothing names at their own class.
|
|
114
|
+
const testNamed = reachedWithTheTests(union, held, false);
|
|
115
|
+
const everywhere = union.symbols.map((symbol, at) => {
|
|
110
116
|
const held = matrix.heldIn[at] ?? [];
|
|
111
117
|
const found = held.map((configuration) => byConfiguration.get(configuration)?.get(symbol.id));
|
|
112
118
|
return held.length === 0 || found.some((candidate) => candidate === undefined)
|
|
113
119
|
? undefined
|
|
114
120
|
: found.filter((candidate) => candidate !== undefined);
|
|
115
121
|
});
|
|
122
|
+
const compiled = compiledReferences(matrix, new Set(union.symbols.flatMap((symbol, at) => (everywhere[at] === undefined ? [] : [symbol.id]))), input.mode);
|
|
123
|
+
const judged = everywhere.map((found, at) => compiled.has(union.symbols[at]?.id ?? "") ? undefined : found);
|
|
116
124
|
// A configuration that does not hold a test's subject's caller finds the subject dead,
|
|
117
125
|
// so a test is of dead code only where every production subject it names is dead in
|
|
118
126
|
// every configuration that holds it.
|
|
@@ -121,6 +129,9 @@ export function sweepMatrix(matrix, input) {
|
|
|
121
129
|
union.ambient[edge.to] === true ||
|
|
122
130
|
union.subject[edge.to] !== true ||
|
|
123
131
|
judged[edge.to] !== undefined);
|
|
132
|
+
const admittedAt = (at) => judged[at]?.every((candidate) => candidate.testOfDeadCode) === true && subjectsDead(at);
|
|
133
|
+
const kept = keptByTests(union, testReached, admittedAt);
|
|
134
|
+
const testUsed = testUsedReach(union, union.symbols.map((_symbol, at) => matrix.testUsed[at] === true && testNamed[at] === true), judged.map((one) => one !== undefined));
|
|
124
135
|
const candidates = [];
|
|
125
136
|
union.symbols.forEach((symbol, at) => {
|
|
126
137
|
const all = judged[at];
|
|
@@ -128,7 +139,7 @@ export function sweepMatrix(matrix, input) {
|
|
|
128
139
|
return;
|
|
129
140
|
}
|
|
130
141
|
const held = matrix.heldIn[at] ?? [];
|
|
131
|
-
const admitted =
|
|
142
|
+
const admitted = admittedAt(at);
|
|
132
143
|
const testRefs = union.made[at]?.test ?? 0;
|
|
133
144
|
const heldByTests = heldBy[union.parent[at] ?? OUTSIDE] ??
|
|
134
145
|
(union.support[at] === true && testRefs > 0 && !admitted ? symbol.id : undefined);
|
|
@@ -148,6 +159,8 @@ export function sweepMatrix(matrix, input) {
|
|
|
148
159
|
configurations: held,
|
|
149
160
|
heldByTests,
|
|
150
161
|
unreferencedTest: unreferenced,
|
|
162
|
+
testUsed: testUsed[at] === true,
|
|
163
|
+
keptByTests: kept[at] === true,
|
|
151
164
|
});
|
|
152
165
|
});
|
|
153
166
|
const liveUnder = liveAnywhere(union.symbols, per);
|
|
@@ -157,6 +170,65 @@ export function sweepMatrix(matrix, input) {
|
|
|
157
170
|
components: deadComponents(matrix, { liveUnder, candidates }, new Set()),
|
|
158
171
|
};
|
|
159
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Every declaration of `dead`, those dead in every configuration that holds them, that a
|
|
175
|
+
* configuration's graph references from a judged declaration outside `dead` or already
|
|
176
|
+
* kept, until none joins: deleting one would break that configuration's compile. A
|
|
177
|
+
* production run counts no reference a test file made.
|
|
178
|
+
*/
|
|
179
|
+
function compiledReferences(matrix, dead, mode) {
|
|
180
|
+
const kept = new Set();
|
|
181
|
+
for (let changed = true; changed;) {
|
|
182
|
+
changed = false;
|
|
183
|
+
for (const graph of matrix.graphs) {
|
|
184
|
+
graph.out.forEach((edges, from) => {
|
|
185
|
+
const id = graph.symbols[from]?.id ?? "";
|
|
186
|
+
if (graph.subject[from] !== true || (dead.has(id) && !kept.has(id))) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
for (const edge of edges) {
|
|
190
|
+
const to = graph.symbols[edge.to]?.id ?? "";
|
|
191
|
+
if ((!mode.production || !edge.test) && dead.has(to) && !kept.has(to)) {
|
|
192
|
+
kept.add(to);
|
|
193
|
+
changed = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return kept;
|
|
200
|
+
}
|
|
201
|
+
/** Per declaration of the union, whether one of `seeds` is it or reaches it through `dead` declarations. */
|
|
202
|
+
function testUsedReach(union, seeds, dead) {
|
|
203
|
+
// A file is no candidate, and its top level is what reaches what it alone calls.
|
|
204
|
+
const reached = seeds.map((seed, at) => seed && dead[at] === true);
|
|
205
|
+
const queue = seeds.flatMap((one, at) => (one ? [at] : []));
|
|
206
|
+
for (let at = queue.pop(); at !== undefined; at = queue.pop()) {
|
|
207
|
+
for (const edge of union.out[at] ?? []) {
|
|
208
|
+
if (dead[edge.to] === true && reached[edge.to] !== true) {
|
|
209
|
+
reached[edge.to] = true;
|
|
210
|
+
queue.push(edge.to);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return reached;
|
|
215
|
+
}
|
|
216
|
+
/** Per declaration of the union, whether test code `reached` holds and `admitted` rejects references it. */
|
|
217
|
+
function keptByTests(union, reached, admitted) {
|
|
218
|
+
const kept = union.symbols.map(() => false);
|
|
219
|
+
union.out.forEach((edges, from) => {
|
|
220
|
+
const testCode = union.test[from] === true || union.support[from] === true;
|
|
221
|
+
if (!testCode || reached[from] !== true || admitted(from)) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
for (const edge of edges) {
|
|
225
|
+
if (edge.test) {
|
|
226
|
+
kept[edge.to] = true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
return kept;
|
|
231
|
+
}
|
|
160
232
|
/**
|
|
161
233
|
* The dead components of one sweep over the union, with the file declarations at `files`
|
|
162
234
|
* dead as well: a file that is deleted whole takes the declarations it holds and every
|
package/dist/src/mdx-entries.js
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { resolveRelativeSpecifier } from "./configuration-files.js";
|
|
7
7
|
import { dirnamePath, joinPath, resolvePath } from "./paths.js";
|
|
8
|
-
|
|
9
|
-
const SKIPPED = new Set(["node_modules", ".git"]);
|
|
8
|
+
import { filesBelow } from "./fs/tree.js";
|
|
10
9
|
/** The extensions of a document whose imports an MDX compiler reads. */
|
|
11
10
|
const DOCUMENT = /\.mdx?$/u;
|
|
12
11
|
/** A fence line, its marker run and what follows it captured. */
|
|
@@ -100,29 +99,6 @@ function clauseNames(clause) {
|
|
|
100
99
|
}
|
|
101
100
|
return names;
|
|
102
101
|
}
|
|
103
|
-
/** Every document below `dir`, outside every skipped directory, by absolute path. */
|
|
104
|
-
function documents(host, dir) {
|
|
105
|
-
let entries;
|
|
106
|
-
try {
|
|
107
|
-
entries = host.readDirectory(dir);
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
return [];
|
|
111
|
-
}
|
|
112
|
-
const found = [];
|
|
113
|
-
for (const entry of entries) {
|
|
114
|
-
const path = joinPath(dir, entry.name);
|
|
115
|
-
if (entry.directory) {
|
|
116
|
-
if (!SKIPPED.has(entry.name)) {
|
|
117
|
-
found.push(...documents(host, path));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else if (DOCUMENT.test(entry.name)) {
|
|
121
|
-
found.push(path);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return found.sort();
|
|
125
|
-
}
|
|
126
102
|
/** The relative specifiers one document's import lines name, its fenced code blocks skipped. */
|
|
127
103
|
function importedBy(text) {
|
|
128
104
|
const found = [];
|
|
@@ -165,7 +141,8 @@ function documentImports(host, root) {
|
|
|
165
141
|
if (known !== undefined) {
|
|
166
142
|
return known;
|
|
167
143
|
}
|
|
168
|
-
const found =
|
|
144
|
+
const found = filesBelow(host, root, (name) => DOCUMENT.test(name)).flatMap((below) => {
|
|
145
|
+
const path = joinPath(root, below);
|
|
169
146
|
try {
|
|
170
147
|
return [{ path, imports: importedBy(host.readFile(path)) }];
|
|
171
148
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { isCallExpression, isExportDeclaration, isImportDeclaration, isNamespaceExport, isNamespaceImport, isNoSubstitutionTemplateLiteral, isStringLiteral, SyntaxKind, } from "@typescript/native/ast";
|
|
10
10
|
import { RESOLVED_EXTENSIONS } from "./configuration-files.js";
|
|
11
|
-
import { emittedFrom } from "./emit-map.js";
|
|
11
|
+
import { emittedFrom } from "./load/emit-map.js";
|
|
12
12
|
import { namesImported } from "./module-declarations.js";
|
|
13
13
|
import { dirnamePath, joinPath, normalizePath, queriedModulePath } from "./paths.js";
|
|
14
14
|
import { renderPosition } from "./position.js";
|
package/dist/src/partial.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { relativePath } from "./paths.js";
|
|
2
|
+
import { bytewise } from "./text/compare.js";
|
|
2
3
|
/** A count with its noun, so a line reads for one as well as for several. */
|
|
3
4
|
function counted(n, one, many) {
|
|
4
5
|
return `${String(n)} ${n === 1 ? one : many}`;
|
|
@@ -10,7 +11,7 @@ function counted(n, one, many) {
|
|
|
10
11
|
*/
|
|
11
12
|
export function partialNotes(partial) {
|
|
12
13
|
const notes = [...partial.notBuilt]
|
|
13
|
-
.sort((a, b) => (a.id
|
|
14
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
14
15
|
.map((one) => `the derived configuration ${one.id} was not built and is not analyzed: ${one.error}`);
|
|
15
16
|
if (partial.unanswered.length > 0) {
|
|
16
17
|
const byProject = new Map();
|