@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
|
@@ -8,18 +8,30 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
isCallExpression,
|
|
11
12
|
isExportDeclaration,
|
|
13
|
+
isIdentifier,
|
|
12
14
|
isImportDeclaration,
|
|
13
15
|
isNoSubstitutionTemplateLiteral,
|
|
14
16
|
isStringLiteral,
|
|
17
|
+
SyntaxKind,
|
|
15
18
|
type Node,
|
|
16
19
|
type SourceFile,
|
|
17
20
|
} from "@typescript/native/ast";
|
|
18
21
|
import type { Host } from "./host.ts";
|
|
19
|
-
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
|
|
22
|
+
import { ancestors, dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
|
|
20
23
|
import type { SourceFiles } from "./source-files.ts";
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
import { bytewise } from "./text/compare.ts";
|
|
25
|
+
import { isRecord } from "./json-document.ts";
|
|
26
|
+
import { filesIn } from "./fs/tree.ts";
|
|
27
|
+
import {
|
|
28
|
+
DEPENDENCY_SECTIONS,
|
|
29
|
+
holdsManifest,
|
|
30
|
+
inInstalledPackages,
|
|
31
|
+
manifestAt,
|
|
32
|
+
readJSON,
|
|
33
|
+
} from "./fs/manifest.ts";
|
|
34
|
+
import { shellWords } from "./text/shell.ts";
|
|
23
35
|
|
|
24
36
|
/** A configuration module's name, each form with the spelling a root reports it by. */
|
|
25
37
|
const MODULE_FORMS: readonly { readonly name: RegExp; readonly form: string }[] = [
|
|
@@ -34,14 +46,6 @@ const MODULE_FORMS: readonly { readonly name: RegExp; readonly form: string }[]
|
|
|
34
46
|
/** A JSON configuration file's name. */
|
|
35
47
|
const DOCUMENT_NAME = /^(?:[\w-]+(?:\.[\w-]+)?\.config\.json|\.[\w-]+rc(?:\.json)?)$/u;
|
|
36
48
|
|
|
37
|
-
/** The manifest members a dependency is declared in. */
|
|
38
|
-
const DEPENDENCY_MEMBERS = [
|
|
39
|
-
"dependencies",
|
|
40
|
-
"devDependencies",
|
|
41
|
-
"peerDependencies",
|
|
42
|
-
"optionalDependencies",
|
|
43
|
-
] as const;
|
|
44
|
-
|
|
45
49
|
/** The prefixes a string names a file with, relative to the file that writes it. */
|
|
46
50
|
const RELATIVE_PREFIXES = ["./", "../"] as const;
|
|
47
51
|
|
|
@@ -69,9 +73,6 @@ export const RESOLVED_EXTENSIONS = [
|
|
|
69
73
|
".cjs",
|
|
70
74
|
] as const;
|
|
71
75
|
|
|
72
|
-
/** The directory a package manager installs packages into, whose files are no project's own. */
|
|
73
|
-
const MODULES_DIR = "node_modules";
|
|
74
|
-
|
|
75
76
|
/** The file's name, the last segment of its path. */
|
|
76
77
|
function basename(path: string): string {
|
|
77
78
|
return path.slice(path.lastIndexOf("/") + 1);
|
|
@@ -79,11 +80,8 @@ function basename(path: string): string {
|
|
|
79
80
|
|
|
80
81
|
/** Whether one path is the project's own: below the target root and in no `node_modules`. */
|
|
81
82
|
function isProjectPath(root: string, path: string): boolean {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
86
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
83
|
+
const below = relativePath(root, path);
|
|
84
|
+
return below !== undefined && !inInstalledPackages(below);
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
/** The form one file name is as a configuration module, or undefined where it is none. */
|
|
@@ -110,7 +108,7 @@ interface ConfigurationDocument {
|
|
|
110
108
|
export type ParseFile = (fileName: string, text: string) => SourceFile;
|
|
111
109
|
|
|
112
110
|
/** One file no program holds that a configuration module outside the program leads to. */
|
|
113
|
-
interface OutsideModule {
|
|
111
|
+
export interface OutsideModule {
|
|
114
112
|
/** The file, parsed alone. */
|
|
115
113
|
readonly file: SourceFile;
|
|
116
114
|
/** The directories of the manifests of the configuration files the file was reached from. */
|
|
@@ -123,120 +121,13 @@ const CONFIG_FLAGS: ReadonlySet<string> = new Set(["--config", "-c"]);
|
|
|
123
121
|
/** The extensions of a module a configuration flag may name. */
|
|
124
122
|
const MODULE_EXTENSIONS = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"] as const;
|
|
125
123
|
|
|
126
|
-
/** The characters that end a word outside quotes and separate nothing: blanks. */
|
|
127
|
-
// Stryker disable next-line Regex: its \v to \V mutant is no valid escape under the u flag, so the whole module fails to parse
|
|
128
|
-
const BLANK = /[ \t\r\f\v]/u;
|
|
129
|
-
|
|
130
|
-
/** The characters that end a word outside quotes and begin an operator: newline included. */
|
|
131
|
-
const OPERATOR = /[\n;&|()<>]/u;
|
|
132
|
-
|
|
133
|
-
/** The characters a backslash escapes inside double quotes; before any other it stands for itself. */
|
|
134
|
-
const DOUBLE_QUOTE_ESCAPES = new Set(["$", "`", '"', "\\"]);
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* The words of one command line, as POSIX token recognition reads quotes, backslashes,
|
|
138
|
-
* line continuations, comments and operators. A word an expansion may change (an unquoted
|
|
139
|
-
* `$`, backquote, glob character or leading `~`, or a `$` or backquote in double quotes)
|
|
140
|
-
* is computed, and so is the rest of a line whose quote is never closed. A computed word
|
|
141
|
-
* and each operator are undefined, so a flag's file is never read across them.
|
|
142
|
-
*/
|
|
143
|
-
function shellWords(command: string): readonly (string | undefined)[] {
|
|
144
|
-
const words: (string | undefined)[] = [];
|
|
145
|
-
let word: string | undefined;
|
|
146
|
-
let computed = false;
|
|
147
|
-
const end = (): void => {
|
|
148
|
-
if (word !== undefined) {
|
|
149
|
-
words.push(computed ? undefined : word);
|
|
150
|
-
}
|
|
151
|
-
word = undefined;
|
|
152
|
-
computed = false;
|
|
153
|
-
};
|
|
154
|
-
for (let at = 0; at < command.length; at += 1) {
|
|
155
|
-
const char = command.charAt(at);
|
|
156
|
-
if (char === "\\" && command.charAt(at + 1) === "\n") {
|
|
157
|
-
at += 1;
|
|
158
|
-
} else if (BLANK.test(char)) {
|
|
159
|
-
end();
|
|
160
|
-
} else if (OPERATOR.test(char)) {
|
|
161
|
-
end();
|
|
162
|
-
words.push(undefined);
|
|
163
|
-
} else if (char === "#" && word === undefined) {
|
|
164
|
-
const newline = command.indexOf("\n", at);
|
|
165
|
-
at = newline < 0 ? command.length : newline - 1;
|
|
166
|
-
} else if (char === "\\") {
|
|
167
|
-
at += 1;
|
|
168
|
-
word = (word ?? "") + command.charAt(at);
|
|
169
|
-
} else if (char === "'" || char === '"') {
|
|
170
|
-
const close = closingQuote(command, at);
|
|
171
|
-
if (close < 0) {
|
|
172
|
-
word ??= "";
|
|
173
|
-
computed = true;
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
const quoted =
|
|
177
|
-
char === "'"
|
|
178
|
-
? { text: command.slice(at + 1, close), computed: false }
|
|
179
|
-
: doubleQuoted(command.slice(at + 1, close));
|
|
180
|
-
word = (word ?? "") + quoted.text;
|
|
181
|
-
computed ||= quoted.computed;
|
|
182
|
-
at = close;
|
|
183
|
-
} else {
|
|
184
|
-
computed ||= /[$`*?[]/u.test(char) || (char === "~" && word === undefined);
|
|
185
|
-
word = (word ?? "") + char;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
end();
|
|
189
|
-
return words;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** The text between one pair of double quotes, unescaped, and whether an expansion may change it. */
|
|
193
|
-
function doubleQuoted(inner: string): { readonly text: string; readonly computed: boolean } {
|
|
194
|
-
let text = "";
|
|
195
|
-
let computed = false;
|
|
196
|
-
for (let at = 0; at < inner.length; at += 1) {
|
|
197
|
-
const char = inner.charAt(at);
|
|
198
|
-
const next = inner.charAt(at + 1);
|
|
199
|
-
if (char === "\\" && next === "\n") {
|
|
200
|
-
at += 1;
|
|
201
|
-
} else if (char === "\\" && DOUBLE_QUOTE_ESCAPES.has(next)) {
|
|
202
|
-
text += next;
|
|
203
|
-
at += 1;
|
|
204
|
-
} else {
|
|
205
|
-
computed ||= char === "$" || char === "`";
|
|
206
|
-
text += char;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return { text, computed };
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/** The index of the quote that closes the one at `open`, or -1 where none does. */
|
|
213
|
-
function closingQuote(command: string, open: number): number {
|
|
214
|
-
const quote = command.charAt(open);
|
|
215
|
-
for (let at = open + 1; at < command.length; at += 1) {
|
|
216
|
-
const char = command.charAt(at);
|
|
217
|
-
if (char === quote) {
|
|
218
|
-
return at;
|
|
219
|
-
}
|
|
220
|
-
if (quote === '"' && char === "\\") {
|
|
221
|
-
at += 1;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return -1;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
124
|
/**
|
|
228
125
|
* The files the scripts of the manifest in one directory name after a configuration flag,
|
|
229
126
|
* `--config <file>`, `-c <file>` or `--config=<file>`, each a JSON file or a module below
|
|
230
127
|
* the target root and in no `node_modules`.
|
|
231
128
|
*/
|
|
232
129
|
function scriptConfigurations(host: Host, root: string, dir: string): readonly string[] {
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
const manifest: unknown = JSON.parse(host.readFile(joinPath(dir, MANIFEST)));
|
|
236
|
-
scripts = isRecord(manifest) ? manifest["scripts"] : undefined;
|
|
237
|
-
} catch {
|
|
238
|
-
return [];
|
|
239
|
-
}
|
|
130
|
+
const scripts = manifestAt(host, dir)?.["scripts"];
|
|
240
131
|
if (!isRecord(scripts)) {
|
|
241
132
|
return [];
|
|
242
133
|
}
|
|
@@ -267,15 +158,6 @@ function scriptConfigurations(host: Host, root: string, dir: string): readonly s
|
|
|
267
158
|
return found;
|
|
268
159
|
}
|
|
269
160
|
|
|
270
|
-
/** The decoded value of one JSON file, or undefined where it cannot be read or parsed. */
|
|
271
|
-
function readDocument(host: Host, path: string): unknown {
|
|
272
|
-
try {
|
|
273
|
-
return JSON.parse(host.readFile(path)) as unknown;
|
|
274
|
-
} catch {
|
|
275
|
-
return undefined;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
161
|
/** The configuration files one project holds and sits beside. */
|
|
280
162
|
interface ConfigurationFiles {
|
|
281
163
|
/**
|
|
@@ -343,10 +225,10 @@ export function configurationFiles(
|
|
|
343
225
|
): ConfigurationFiles {
|
|
344
226
|
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
345
227
|
const manifests = new Map<string, boolean>();
|
|
346
|
-
const
|
|
228
|
+
const manifestHeld = (dir: string): boolean => {
|
|
347
229
|
let held = manifests.get(dir);
|
|
348
230
|
if (held === undefined) {
|
|
349
|
-
held = host
|
|
231
|
+
held = holdsManifest(host, dir);
|
|
350
232
|
manifests.set(dir, held);
|
|
351
233
|
}
|
|
352
234
|
return held;
|
|
@@ -357,34 +239,24 @@ export function configurationFiles(
|
|
|
357
239
|
for (const file of files.byPath.values()) {
|
|
358
240
|
const form = configurationModuleForm(basename(file.fileName));
|
|
359
241
|
const fileDir = dirnamePath(file.fileName);
|
|
360
|
-
if (form !== undefined &&
|
|
242
|
+
if (form !== undefined && manifestHeld(fileDir)) {
|
|
361
243
|
modules.push({ file, form, manifestDir: fileDir });
|
|
362
244
|
}
|
|
363
|
-
for (
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
) {
|
|
245
|
+
for (const dir of ancestors(dirnamePath(file.fileName), root)) {
|
|
246
|
+
if (dirs.has(dir)) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
368
249
|
dirs.add(dir);
|
|
369
250
|
}
|
|
370
251
|
}
|
|
371
252
|
|
|
372
253
|
const pending: { path: string; manifestDir: string }[] = [];
|
|
373
254
|
const named: { path: string; manifestDir: string }[] = [];
|
|
374
|
-
for (const dir of [...dirs].sort()) {
|
|
375
|
-
if (!
|
|
255
|
+
for (const dir of [...dirs].sort(bytewise)) {
|
|
256
|
+
if (!manifestHeld(dir)) {
|
|
376
257
|
continue;
|
|
377
258
|
}
|
|
378
|
-
|
|
379
|
-
try {
|
|
380
|
-
names = host
|
|
381
|
-
.readDirectory(dir)
|
|
382
|
-
.filter((entry) => !entry.directory && isConfigurationDocumentName(entry.name))
|
|
383
|
-
.map((entry) => entry.name)
|
|
384
|
-
.sort();
|
|
385
|
-
} catch {
|
|
386
|
-
names = [];
|
|
387
|
-
}
|
|
259
|
+
const names = filesIn(host, dir, isConfigurationDocumentName);
|
|
388
260
|
pending.push(...names.map((name) => ({ path: joinPath(dir, name), manifestDir: dir })));
|
|
389
261
|
for (const path of scriptConfigurations(host, root, dir)) {
|
|
390
262
|
const held = files.byName.get(path);
|
|
@@ -407,7 +279,7 @@ export function configurationFiles(
|
|
|
407
279
|
continue;
|
|
408
280
|
}
|
|
409
281
|
if (document === undefined) {
|
|
410
|
-
const value =
|
|
282
|
+
const value = readJSON(host, next.path);
|
|
411
283
|
if (value === undefined) {
|
|
412
284
|
unreadable.add(next.path);
|
|
413
285
|
continue;
|
|
@@ -435,23 +307,74 @@ export function configurationFiles(
|
|
|
435
307
|
outside:
|
|
436
308
|
parse === undefined
|
|
437
309
|
? []
|
|
438
|
-
: outsideModules(host, root, [...dirs], files,
|
|
310
|
+
: outsideModules(host, root, [...dirs], files, manifestHeld, parse, named),
|
|
439
311
|
};
|
|
440
312
|
}
|
|
441
313
|
|
|
442
|
-
/** The
|
|
443
|
-
function
|
|
444
|
-
|
|
445
|
-
|
|
314
|
+
/** The literal module specifier one `require(...)` or `import(...)` call names, if any. */
|
|
315
|
+
function calledSpecifier(node: Node): Node | undefined {
|
|
316
|
+
if (!isCallExpression(node) || node.arguments.length !== 1) {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
const callee = node.expression;
|
|
320
|
+
const loads =
|
|
321
|
+
callee.kind === SyntaxKind.ImportKeyword || (isIdentifier(callee) && callee.text === "require");
|
|
322
|
+
return loads ? node.arguments[0] : undefined;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* The relative specifiers one file's imports and re-exports name, and those its
|
|
327
|
+
* `require(...)` and `import(...)` calls name by a literal.
|
|
328
|
+
*/
|
|
329
|
+
export function relativeSpecifiers(file: SourceFile): readonly string[] {
|
|
330
|
+
const known = specifiersOf.get(file);
|
|
331
|
+
if (known !== undefined) {
|
|
332
|
+
return known;
|
|
333
|
+
}
|
|
334
|
+
const found: string[] = [];
|
|
335
|
+
const named = (specifier: Node | undefined): void => {
|
|
336
|
+
if (
|
|
337
|
+
specifier !== undefined &&
|
|
338
|
+
(isStringLiteral(specifier) || isNoSubstitutionTemplateLiteral(specifier)) &&
|
|
339
|
+
RELATIVE_PREFIXES.some((prefix) => specifier.text.startsWith(prefix))
|
|
340
|
+
) {
|
|
341
|
+
found.push(specifier.text);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
const visit = (node: Node): void => {
|
|
345
|
+
named(calledSpecifier(node));
|
|
346
|
+
node.forEachChild(visit);
|
|
347
|
+
};
|
|
348
|
+
for (const statement of file.statements) {
|
|
349
|
+
named(
|
|
446
350
|
isImportDeclaration(statement) || isExportDeclaration(statement)
|
|
447
351
|
? statement.moduleSpecifier
|
|
448
|
-
: undefined
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
352
|
+
: undefined,
|
|
353
|
+
);
|
|
354
|
+
visit(statement);
|
|
355
|
+
}
|
|
356
|
+
specifiersOf.set(file, found);
|
|
357
|
+
return found;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** What {@link relativeSpecifiers} found in each file, which every project of a run reads alike. */
|
|
361
|
+
const specifiersOf = new WeakMap<SourceFile, readonly string[]>();
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* The files no program holds that a chain from `seeds` reads: each seed, and each file
|
|
365
|
+
* below the target root one imports, re-exports or loads by a relative specifier that no
|
|
366
|
+
* program holds either, until no further file joins, each read against the manifest
|
|
367
|
+
* directory its seed names. A file that cannot be read is skipped.
|
|
368
|
+
*/
|
|
369
|
+
export function outsideChain(
|
|
370
|
+
host: Host,
|
|
371
|
+
targetRoot: string,
|
|
372
|
+
files: SourceFiles,
|
|
373
|
+
parse: ParseFile,
|
|
374
|
+
seeds: readonly { readonly path: string; readonly manifestDir: string }[],
|
|
375
|
+
): readonly OutsideModule[] {
|
|
376
|
+
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
377
|
+
return outsideModules(host, root, [], files, () => false, parse, seeds);
|
|
455
378
|
}
|
|
456
379
|
|
|
457
380
|
/**
|
|
@@ -497,25 +420,16 @@ function outsideModules(
|
|
|
497
420
|
root: string,
|
|
498
421
|
dirs: readonly string[],
|
|
499
422
|
files: SourceFiles,
|
|
500
|
-
|
|
423
|
+
manifestHeld: (dir: string) => boolean,
|
|
501
424
|
parse: ParseFile,
|
|
502
425
|
named: readonly { readonly path: string; readonly manifestDir: string }[],
|
|
503
426
|
): readonly OutsideModule[] {
|
|
504
427
|
const pending: { path: string; manifestDir: string }[] = [...named];
|
|
505
|
-
for (const dir of [...dirs].sort()) {
|
|
506
|
-
if (!
|
|
507
|
-
continue;
|
|
508
|
-
}
|
|
509
|
-
let names: readonly string[];
|
|
510
|
-
try {
|
|
511
|
-
names = host
|
|
512
|
-
.readDirectory(dir)
|
|
513
|
-
.filter((entry) => !entry.directory && configurationModuleForm(entry.name) !== undefined)
|
|
514
|
-
.map((entry) => entry.name)
|
|
515
|
-
.sort();
|
|
516
|
-
} catch {
|
|
428
|
+
for (const dir of [...dirs].sort(bytewise)) {
|
|
429
|
+
if (!manifestHeld(dir)) {
|
|
517
430
|
continue;
|
|
518
431
|
}
|
|
432
|
+
const names = filesIn(host, dir, (name) => configurationModuleForm(name) !== undefined);
|
|
519
433
|
pending.push(...names.map((name) => ({ path: joinPath(dir, name), manifestDir: dir })));
|
|
520
434
|
}
|
|
521
435
|
const found = new Map<string, { file: SourceFile; manifestDirs: string[] }>();
|
|
@@ -553,17 +467,12 @@ function outsideModules(
|
|
|
553
467
|
|
|
554
468
|
/** Every dependency the manifest in one directory declares, or none where it holds none to read. */
|
|
555
469
|
export function declaredIn(host: Host, dir: string): readonly string[] {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
value = JSON.parse(host.readFile(joinPath(dir, MANIFEST)));
|
|
559
|
-
} catch {
|
|
560
|
-
return [];
|
|
561
|
-
}
|
|
562
|
-
if (!isRecord(value)) {
|
|
470
|
+
const value = manifestAt(host, dir);
|
|
471
|
+
if (value === undefined) {
|
|
563
472
|
return [];
|
|
564
473
|
}
|
|
565
474
|
const names = new Set<string>();
|
|
566
|
-
for (const member of
|
|
475
|
+
for (const member of DEPENDENCY_SECTIONS) {
|
|
567
476
|
const section = value[member];
|
|
568
477
|
if (isRecord(section)) {
|
|
569
478
|
Object.keys(section).forEach((name) => names.add(name));
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { SymbolFlags, type NodeHandle, type Symbol as TSSymbol } from "@typescript/native/sync";
|
|
20
20
|
import type { AliasChains } from "./alias-chain.ts";
|
|
21
21
|
import { resolvedTargets } from "./calls.ts";
|
|
22
|
-
import type {
|
|
22
|
+
import type { DeclarationEntry, ResolvedConfig } from "./config.ts";
|
|
23
23
|
import { declaredComponent, type Inventory } from "./inventory.ts";
|
|
24
24
|
import { must, Unanswerable } from "./query.ts";
|
|
25
25
|
import { nameComponent } from "./ref.ts";
|
|
@@ -252,21 +252,21 @@ export function resolveEntries<Brand>(
|
|
|
252
252
|
}
|
|
253
253
|
const modules = modulesNamed(
|
|
254
254
|
project,
|
|
255
|
-
new Set(entries.flatMap((entry) => (
|
|
255
|
+
new Set(entries.flatMap((entry) => ("module" in entry ? [entry.module] : []))),
|
|
256
256
|
);
|
|
257
257
|
return entries.map((entry) => {
|
|
258
|
-
if (
|
|
258
|
+
if ("symbol" in entry) {
|
|
259
259
|
return { entry, handles: new Set<string>(), ids: new Set(byRef.get(entry.symbol) ?? []) };
|
|
260
260
|
}
|
|
261
261
|
const { components, static: isStatic } = componentsOf(
|
|
262
|
-
|
|
262
|
+
"module" in entry ? entry.name : entry.global,
|
|
263
263
|
);
|
|
264
264
|
const [first = "", ...rest] = components;
|
|
265
265
|
let start: TSSymbol | undefined;
|
|
266
266
|
if (isStatic && rest.length === 0) {
|
|
267
267
|
// Only a member is static, and a path of one component names no member.
|
|
268
268
|
start = undefined;
|
|
269
|
-
} else if (
|
|
269
|
+
} else if ("module" in entry) {
|
|
270
270
|
const module = modules.get(entry.module);
|
|
271
271
|
start = module === undefined ? undefined : memberOf(project, module, first, false);
|
|
272
272
|
} else if (nameComponent(first) === first) {
|
|
@@ -329,14 +329,10 @@ export function entriesAt<Brand>(
|
|
|
329
329
|
* program the display name the inventory gives it.
|
|
330
330
|
*/
|
|
331
331
|
export function spelledEntry(entry: DeclarationEntry, held: Inventory): string {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
return held.symbols.find((symbol) => symbol.ref === entry.symbol)?.name ?? entry.symbol;
|
|
335
|
-
case "module":
|
|
336
|
-
return entry.name;
|
|
337
|
-
case "global":
|
|
338
|
-
return entry.global;
|
|
332
|
+
if ("symbol" in entry) {
|
|
333
|
+
return held.symbols.find((symbol) => symbol.ref === entry.symbol)?.name ?? entry.symbol;
|
|
339
334
|
}
|
|
335
|
+
return "module" in entry ? entry.name : entry.global;
|
|
340
336
|
}
|
|
341
337
|
|
|
342
338
|
/** One entry of a configuration key that names a declaration, and the key's dotted path. */
|
|
@@ -353,14 +349,17 @@ const LIFECYCLE_KEY = "ts.lifecycle_contracts";
|
|
|
353
349
|
* the injection registrations, each lifecycle contract's components and then its bases,
|
|
354
350
|
* and the serializers.
|
|
355
351
|
*/
|
|
356
|
-
export function configuredDeclarations(config:
|
|
352
|
+
export function configuredDeclarations(config: ResolvedConfig): readonly ConfiguredDeclaration[] {
|
|
357
353
|
return [
|
|
358
|
-
...config.ts.
|
|
354
|
+
...config.ts.injection_registrations.map((entry) => ({
|
|
359
355
|
key: "ts.injection_registrations",
|
|
360
356
|
entry,
|
|
361
357
|
})),
|
|
362
|
-
...config.ts.
|
|
363
|
-
[...contract.components, ...contract.bases].map((entry) => ({
|
|
358
|
+
...config.ts.lifecycle_contracts.flatMap((contract) =>
|
|
359
|
+
[...(contract.components ?? []), ...(contract.bases ?? [])].map((entry) => ({
|
|
360
|
+
key: LIFECYCLE_KEY,
|
|
361
|
+
entry,
|
|
362
|
+
})),
|
|
364
363
|
),
|
|
365
364
|
...config.ts.serializers.map((entry) => ({ key: "ts.serializers", entry })),
|
|
366
365
|
];
|
|
@@ -396,12 +395,8 @@ export function declarationsNamed<Brand>(
|
|
|
396
395
|
* sign and its name, and a global entry's path after a number sign.
|
|
397
396
|
*/
|
|
398
397
|
export function configuredRef(entry: DeclarationEntry): string {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
return entry.symbol;
|
|
402
|
-
case "module":
|
|
403
|
-
return `${entry.module}#${entry.name}`;
|
|
404
|
-
case "global":
|
|
405
|
-
return `#${entry.global}`;
|
|
398
|
+
if ("symbol" in entry) {
|
|
399
|
+
return entry.symbol;
|
|
406
400
|
}
|
|
401
|
+
return "module" in entry ? `${entry.module}#${entry.name}` : `#${entry.global}`;
|
|
407
402
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Regenerate it with `UPDATE_GOLDEN=1 npx vitest --run src/conformance.corpus.test.ts`.
|
|
3
3
|
export const RECORD = {
|
|
4
4
|
conformance: {
|
|
5
|
-
corpusVersion: "
|
|
5
|
+
corpusVersion: "6.0.0",
|
|
6
6
|
result: "pass",
|
|
7
|
-
digest: "sha256:
|
|
7
|
+
digest: "sha256:0d33564807a356fd3e2760ddaa0645d758bdb9a96ee74a392675e444343bbf20",
|
|
8
8
|
},
|
|
9
9
|
gaps: [],
|
|
10
10
|
} as const;
|
package/src/consumers.ts
CHANGED
|
@@ -1,60 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* The consumers a scope declares, loaded beside the target: each a directory on the
|
|
3
|
-
* local filesystem whose compiler configurations open as projects of the run's one
|
|
4
|
-
* snapshot, and whose references to the target's declarations count against them.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Config } from "./config.ts";
|
|
8
|
-
import { consumerProjects } from "./discover.ts";
|
|
1
|
+
import type { PartialConfig } from "./config.ts";
|
|
9
2
|
import type { Host } from "./host.ts";
|
|
10
|
-
import { inventory
|
|
3
|
+
import { inventory } from "./inventory.ts";
|
|
11
4
|
import { relativePath } from "./paths.ts";
|
|
12
5
|
import { references, type ConsumerSide, type Reference } from "./references.ts";
|
|
13
|
-
import
|
|
14
|
-
import { narrowedTo, type Engine, type ProjectView } from "./session.ts";
|
|
15
|
-
|
|
16
|
-
/** One consumer the run loaded. */
|
|
17
|
-
export interface LoadedConsumer {
|
|
18
|
-
/** The name the consumer publishes itself under, which every finding names it by. */
|
|
19
|
-
readonly id: string;
|
|
20
|
-
/** The consumer's directory, absolute. */
|
|
21
|
-
readonly path: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** One declared consumer and the compiler configurations it opens as. */
|
|
25
|
-
interface ConsumerLoad {
|
|
26
|
-
readonly consumer: LoadedConsumer;
|
|
27
|
-
/** The configuration files, absolute, in discovery order, none a target project's. */
|
|
28
|
-
readonly configFiles: readonly string[];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** The name one module publishes itself under: the scope's, else its manifest's. */
|
|
32
|
-
export function moduleIdentity(host: Host, module: Module): string {
|
|
33
|
-
return module.id === "" ? packageScope(host, module.path)("index.ts").package : module.id;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Every consumer the scope declares, in its order, with the projects it opens as. A
|
|
38
|
-
* configuration that is also one of the target's projects, or an earlier consumer's, is
|
|
39
|
-
* that project's alone. A consumer whose directory is absent, is no directory or holds
|
|
40
|
-
* no configuration ends the run naming it, before any project opens.
|
|
41
|
-
*/
|
|
42
|
-
export function consumerLoads(
|
|
43
|
-
engine: Engine,
|
|
44
|
-
host: Host,
|
|
45
|
-
scope: Scope,
|
|
46
|
-
targetConfigFiles: readonly string[],
|
|
47
|
-
): readonly ConsumerLoad[] {
|
|
48
|
-
const opened = new Set(targetConfigFiles);
|
|
49
|
-
return scope.consumers.map((module) => {
|
|
50
|
-
const configFiles = consumerProjects(engine, host, module.path).filter((configFile) => {
|
|
51
|
-
const fresh = !opened.has(configFile);
|
|
52
|
-
opened.add(configFile);
|
|
53
|
-
return fresh;
|
|
54
|
-
});
|
|
55
|
-
return { consumer: { id: moduleIdentity(host, module), path: module.path }, configFiles };
|
|
56
|
-
});
|
|
57
|
-
}
|
|
6
|
+
import { narrowedTo, type ProjectView } from "./session.ts";
|
|
58
7
|
|
|
59
8
|
/**
|
|
60
9
|
* Every reference one consumer project's own files make to a declaration of the target.
|
|
@@ -68,7 +17,7 @@ export function consumerReferences<Brand>(
|
|
|
68
17
|
host: Host,
|
|
69
18
|
targetRoot: string,
|
|
70
19
|
consumer: ConsumerSide,
|
|
71
|
-
config:
|
|
20
|
+
config: PartialConfig,
|
|
72
21
|
): readonly Reference[] {
|
|
73
22
|
const held = inventory(
|
|
74
23
|
narrowedTo(project, (file) => relativePath(targetRoot, file.fileName) !== undefined),
|
|
@@ -76,10 +25,10 @@ export function consumerReferences<Brand>(
|
|
|
76
25
|
targetRoot,
|
|
77
26
|
);
|
|
78
27
|
const found = references(project, held, targetRoot, {
|
|
79
|
-
testFiles: config.ts.
|
|
28
|
+
testFiles: config.ts.test_files,
|
|
80
29
|
consumer,
|
|
81
30
|
}).references;
|
|
82
|
-
if (config.analysis.
|
|
31
|
+
if (config.analysis.consumer_tests !== "production") {
|
|
83
32
|
return found;
|
|
84
33
|
}
|
|
85
34
|
return found.map((reference) => (reference.test ? { ...reference, test: false } : reference));
|