@cplieger/deadset-ts 8.0.0-dev.6 → 8.0.0-dev.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/analysis.js +37 -56
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/build-scripts.js +17 -29
- 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 +27 -168
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/consumers.js +2 -2
- package/dist/src/contract/config.generated.js +544 -0
- package/dist/src/contract/contract.generated.js +13 -0
- package/dist/src/contract/report.generated.js +3 -2
- package/dist/src/conventions.js +20 -60
- package/dist/src/dependencies.js +25 -43
- package/dist/src/discover.js +14 -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 +3 -10
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +0 -4
- package/dist/src/exempt.js +6 -22
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +5 -4
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/intra-function.js +1 -1
- package/dist/src/findings/non-code-artifacts.js +2 -2
- package/dist/src/findings/reads-and-writes.js +2 -1
- package/dist/src/findings/self-check.js +3 -2
- package/dist/src/findings/unused-declarations.js +1 -1
- package/dist/src/findings/visibility-narrowing.js +2 -2
- package/dist/src/findings-pass.js +7 -12
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +59 -0
- package/dist/src/fs/manifest.js +43 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/git-ignore.js +34 -25
- package/dist/src/html-entries.js +6 -33
- package/dist/src/in-operands.js +2 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/intra-function-parts.js +10 -13
- package/dist/src/inventory.js +2 -21
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +0 -7
- package/dist/src/manifest.js +5 -43
- package/dist/src/mdx-entries.js +3 -26
- 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/references.js +14 -27
- package/dist/src/report-schema.js +3 -225
- package/dist/src/report.js +22 -31
- package/dist/src/reporters/sarif.js +4 -2
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +245 -724
- package/dist/src/roots.js +7 -17
- package/dist/src/run.js +55 -61
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +34 -103
- package/dist/src/serialization-contract.js +5 -9
- package/dist/src/session.js +2 -1
- package/dist/src/suppress-file.js +21 -25
- package/dist/src/suppress.js +3 -3
- package/dist/src/symbol-keys.js +3 -5
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-globals.js +6 -28
- package/dist/src/test-joins.js +6 -6
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/{yaml-document.js → text/yaml.js} +38 -0
- package/dist/src/type-errors.js +14 -38
- package/dist/src/unseen-loads.js +2 -9
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +25 -26
- package/dist/src/verbs/describe.js +4 -4
- package/dist/src/verbs/explain.js +8 -6
- package/dist/src/verbs/print-projects.js +4 -3
- package/dist/src/verbs/print-retained.js +2 -1
- package/dist/src/verbs/print-roots.js +2 -1
- package/dist/src/verbs/version.js +2 -1
- package/dist/src/workflow-steps.js +9 -46
- package/dist/src/workspace-manifests.js +2 -2
- package/dist/src/workspace-programs.js +5 -3
- package/dist/src/workspace-resolution.js +13 -17
- package/dist/src/workspace.js +28 -116
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +55 -76
- package/src/automatic-types.ts +11 -29
- package/src/build-scripts.ts +17 -38
- package/src/component-layer.ts +4 -2
- package/src/components.ts +2 -4
- package/src/config.ts +31 -296
- package/src/configuration-files.ts +27 -170
- package/src/configured-declarations.ts +18 -23
- package/src/consumers.ts +4 -4
- package/src/contract/config.generated.ts +798 -0
- package/src/contract/contract.generated.ts +25 -0
- package/src/contract/report.generated.ts +3 -2
- package/src/conventions.ts +26 -74
- package/src/dependencies.ts +32 -50
- package/src/discover.ts +15 -40
- 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 +2 -13
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +0 -5
- package/src/exempt.ts +8 -30
- package/src/file-facts.ts +6 -24
- package/src/findings/completion.ts +5 -6
- package/src/findings/emitter.ts +2 -2
- package/src/findings/emitters.ts +1 -1
- package/src/findings/intra-function.ts +1 -1
- package/src/findings/non-code-artifacts.ts +4 -4
- package/src/findings/reads-and-writes.ts +2 -1
- package/src/findings/self-check.ts +3 -2
- package/src/findings/unused-declarations.ts +1 -1
- package/src/findings/visibility-narrowing.ts +2 -2
- package/src/findings-pass.ts +9 -15
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +74 -0
- package/src/fs/manifest.ts +52 -0
- package/src/fs/tree.ts +110 -0
- package/src/git-ignore.ts +38 -25
- package/src/host.ts +12 -5
- package/src/html-entries.ts +6 -33
- package/src/in-operands.ts +2 -1
- package/src/injection-container.ts +1 -1
- package/src/intra-function-parts.ts +10 -14
- package/src/inventory.ts +2 -20
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +0 -8
- package/src/manifest.ts +5 -46
- package/src/mdx-entries.ts +3 -26
- package/src/partial.ts +2 -1
- 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/references.ts +14 -29
- package/src/report-schema.ts +3 -301
- package/src/report.ts +24 -34
- package/src/reporters/sarif.ts +4 -4
- package/src/reporters/template.ts +4 -20
- package/src/resolve.ts +283 -1114
- package/src/roots.ts +7 -20
- package/src/run.ts +57 -75
- package/src/schema.ts +391 -388
- package/src/scope.ts +40 -126
- package/src/serialization-contract.ts +5 -10
- package/src/session.ts +2 -1
- package/src/suppress-file.ts +21 -29
- package/src/suppress.ts +3 -3
- package/src/symbol-keys.ts +2 -5
- package/src/template-field.ts +15 -25
- package/src/test-globals.ts +9 -27
- package/src/test-joins.ts +6 -8
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/shell.ts +161 -0
- package/src/{yaml-document.ts → text/yaml.ts} +46 -0
- package/src/type-errors.ts +25 -36
- package/src/unseen-loads.ts +1 -12
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +32 -42
- package/src/verbs/describe.ts +4 -4
- package/src/verbs/explain.ts +8 -10
- package/src/verbs/print-projects.ts +4 -3
- package/src/verbs/print-retained.ts +2 -1
- package/src/verbs/print-roots.ts +2 -1
- package/src/verbs/verb.ts +2 -2
- package/src/verbs/version.ts +2 -1
- package/src/workflow-steps.ts +9 -44
- package/src/workspace-manifests.ts +2 -2
- package/src/workspace-programs.ts +5 -3
- package/src/workspace-resolution.ts +21 -17
- package/src/workspace.ts +35 -121
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
package/src/automatic-types.ts
CHANGED
|
@@ -26,8 +26,10 @@ import {
|
|
|
26
26
|
type Statement,
|
|
27
27
|
} from "@typescript/native/ast";
|
|
28
28
|
import type { ParseFile } from "./configuration-files.ts";
|
|
29
|
-
import type {
|
|
30
|
-
import { dirnamePath, joinPath, resolvePath } from "./paths.ts";
|
|
29
|
+
import type { Host } from "./host.ts";
|
|
30
|
+
import { ancestors, dirnamePath, joinPath, resolvePath } from "./paths.ts";
|
|
31
|
+
import { entriesOf } from "./fs/tree.ts";
|
|
32
|
+
import { manifestAt } from "./fs/manifest.ts";
|
|
31
33
|
|
|
32
34
|
const TYPE_ROOT = "node_modules/@types";
|
|
33
35
|
|
|
@@ -122,19 +124,11 @@ function fileDeclarations(file: SourceFile, globals: string[], modules: string[]
|
|
|
122
124
|
|
|
123
125
|
/** The entry declaration file of one installed type package's directory. */
|
|
124
126
|
function entryOf(host: Host, dir: string): string {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
(manifest as Record<string, unknown>)["typings"])
|
|
131
|
-
: undefined;
|
|
132
|
-
if (typeof named === "string" && named !== "") {
|
|
133
|
-
const path = resolvePath(dir, named);
|
|
134
|
-
return path.endsWith(".ts") ? path : `${path}.d.ts`;
|
|
135
|
-
}
|
|
136
|
-
} catch {
|
|
137
|
-
// A package with no readable manifest is read from its index, as the compiler reads it.
|
|
127
|
+
const manifest = manifestAt(host, dir);
|
|
128
|
+
const named = manifest?.["types"] ?? manifest?.["typings"];
|
|
129
|
+
if (typeof named === "string" && named !== "") {
|
|
130
|
+
const path = resolvePath(dir, named);
|
|
131
|
+
return path.endsWith(".ts") ? path : `${path}.d.ts`;
|
|
138
132
|
}
|
|
139
133
|
return joinPath(dir, "index.d.ts");
|
|
140
134
|
}
|
|
@@ -201,13 +195,7 @@ export function automaticTypes(
|
|
|
201
195
|
};
|
|
202
196
|
const read = new Set<string>();
|
|
203
197
|
for (const root of typeRoots(configFile, options)) {
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
entries = host.readDirectory(root);
|
|
207
|
-
} catch {
|
|
208
|
-
entries = [];
|
|
209
|
-
}
|
|
210
|
-
for (const entry of entries) {
|
|
198
|
+
for (const entry of entriesOf(host, root)) {
|
|
211
199
|
if (read.has(entry.name) || host.kindOf(joinPath(root, entry.name)) !== "directory") {
|
|
212
200
|
continue;
|
|
213
201
|
}
|
|
@@ -236,11 +224,5 @@ function typeRoots(configFile: string, options: Readonly<Record<string, unknown>
|
|
|
236
224
|
(root): root is string => typeof root === "string" && root.endsWith(`/${TYPE_ROOT}`),
|
|
237
225
|
);
|
|
238
226
|
}
|
|
239
|
-
|
|
240
|
-
for (let dir = dirnamePath(configFile); ; dir = dirnamePath(dir)) {
|
|
241
|
-
roots.push(joinPath(dir, TYPE_ROOT));
|
|
242
|
-
if (dirnamePath(dir) === dir) {
|
|
243
|
-
return roots;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
227
|
+
return ancestors(dirnamePath(configFile)).map((dir) => joinPath(dir, TYPE_ROOT));
|
|
246
228
|
}
|
package/src/build-scripts.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
isArrayBindingPattern,
|
|
10
10
|
isArrayLiteralExpression,
|
|
11
11
|
isArrowFunction,
|
|
12
|
-
isAsExpression,
|
|
13
12
|
isCallExpression,
|
|
14
13
|
isConstructorDeclaration,
|
|
15
14
|
isFunctionDeclaration,
|
|
@@ -25,10 +24,8 @@ import {
|
|
|
25
24
|
isNoSubstitutionTemplateLiteral,
|
|
26
25
|
isObjectBindingPattern,
|
|
27
26
|
isObjectLiteralExpression,
|
|
28
|
-
isParenthesizedExpression,
|
|
29
27
|
isPropertyAccessExpression,
|
|
30
28
|
isPropertyAssignment,
|
|
31
|
-
isSatisfiesExpression,
|
|
32
29
|
isSetAccessorDeclaration,
|
|
33
30
|
isStringLiteral,
|
|
34
31
|
isVariableDeclaration,
|
|
@@ -39,11 +36,15 @@ import {
|
|
|
39
36
|
type SourceFile,
|
|
40
37
|
} from "@typescript/native/ast";
|
|
41
38
|
import { filesNamedBy, type ParseFile } from "./configuration-files.ts";
|
|
42
|
-
import { globExpression } from "./glob.ts";
|
|
43
39
|
import type { Host } from "./host.ts";
|
|
44
|
-
import {
|
|
45
|
-
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
|
|
40
|
+
import { ancestors, dirnamePath, relativePath, resolvePath } from "./paths.ts";
|
|
46
41
|
import type { SourceFiles } from "./source-files.ts";
|
|
42
|
+
import { bytewise } from "./text/compare.ts";
|
|
43
|
+
import { isRecord } from "./json-document.ts";
|
|
44
|
+
import { unwrapped } from "./unwrap.ts";
|
|
45
|
+
import { holdsManifest, inInstalledPackages, manifestAt } from "./fs/manifest.ts";
|
|
46
|
+
import { globExpression } from "./text/glob.ts";
|
|
47
|
+
import { scriptTokens } from "./text/shell.ts";
|
|
47
48
|
|
|
48
49
|
/** One bundler API: the module, the functions it exports that build, and the option naming entries. */
|
|
49
50
|
interface BundlerAPI {
|
|
@@ -78,8 +79,6 @@ const BUNDLERS: readonly BundlerAPI[] = [
|
|
|
78
79
|
|
|
79
80
|
const MODULE_EXTENSION = /\.(?:js|mjs|cjs|ts|mts|cts)$/u;
|
|
80
81
|
|
|
81
|
-
const MANIFEST = "package.json";
|
|
82
|
-
|
|
83
82
|
/** One own file a build script's bundler call names as an entry. */
|
|
84
83
|
interface BuildEntry {
|
|
85
84
|
readonly file: SourceFile;
|
|
@@ -87,19 +86,6 @@ interface BuildEntry {
|
|
|
87
86
|
readonly source: string;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
91
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** The expression a wrapper that changes no value holds. */
|
|
95
|
-
function unwrapped(node: Node): Node {
|
|
96
|
-
let at = node;
|
|
97
|
-
while (isParenthesizedExpression(at) || isAsExpression(at) || isSatisfiesExpression(at)) {
|
|
98
|
-
at = at.expression;
|
|
99
|
-
}
|
|
100
|
-
return at;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
89
|
function literalOf(node: Node): string | undefined {
|
|
104
90
|
const at = unwrapped(node);
|
|
105
91
|
return isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at) ? at.text : undefined;
|
|
@@ -462,7 +448,7 @@ function scriptEntries(file: SourceFile, dir: string, files: SourceFiles): reado
|
|
|
462
448
|
continue;
|
|
463
449
|
}
|
|
464
450
|
const [argument] = call.arguments;
|
|
465
|
-
let options = argument === undefined ? undefined : unwrapped(argument);
|
|
451
|
+
let options: Node | undefined = argument === undefined ? undefined : unwrapped(argument);
|
|
466
452
|
if (options !== undefined && isIdentifier(options)) {
|
|
467
453
|
options = shadowed.has(options.text) ? undefined : declared.get(options.text);
|
|
468
454
|
options = options === undefined ? undefined : unwrapped(options);
|
|
@@ -489,13 +475,7 @@ function scriptEntries(file: SourceFile, dir: string, files: SourceFiles): reado
|
|
|
489
475
|
|
|
490
476
|
/** The modules one manifest's scripts run, by absolute path, each below the target root. */
|
|
491
477
|
function scriptModules(host: Host, root: string, dir: string): readonly string[] {
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
manifest = JSON.parse(host.readFile(joinPath(dir, MANIFEST)));
|
|
495
|
-
} catch {
|
|
496
|
-
return [];
|
|
497
|
-
}
|
|
498
|
-
const scripts = isRecord(manifest) ? manifest["scripts"] : undefined;
|
|
478
|
+
const scripts = manifestAt(host, dir)?.["scripts"];
|
|
499
479
|
if (!isRecord(scripts)) {
|
|
500
480
|
return [];
|
|
501
481
|
}
|
|
@@ -509,14 +489,14 @@ function scriptModules(host: Host, root: string, dir: string): readonly string[]
|
|
|
509
489
|
if (
|
|
510
490
|
MODULE_EXTENSION.test(path) &&
|
|
511
491
|
relativePath(root, path) !== undefined &&
|
|
512
|
-
!path
|
|
492
|
+
!inInstalledPackages(path) &&
|
|
513
493
|
host.kindOf(path) === "file"
|
|
514
494
|
) {
|
|
515
495
|
found.add(path);
|
|
516
496
|
}
|
|
517
497
|
}
|
|
518
498
|
}
|
|
519
|
-
return [...found].sort();
|
|
499
|
+
return [...found].sort(bytewise);
|
|
520
500
|
}
|
|
521
501
|
|
|
522
502
|
/**
|
|
@@ -533,17 +513,16 @@ export function buildScriptEntries(
|
|
|
533
513
|
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
534
514
|
const dirs = new Set<string>([root]);
|
|
535
515
|
for (const file of files.byName.values()) {
|
|
536
|
-
for (
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
) {
|
|
516
|
+
for (const dir of ancestors(dirnamePath(file.fileName), root)) {
|
|
517
|
+
if (dirs.has(dir)) {
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
541
520
|
dirs.add(dir);
|
|
542
521
|
}
|
|
543
522
|
}
|
|
544
523
|
const found: BuildEntry[] = [];
|
|
545
|
-
for (const dir of [...dirs].sort()) {
|
|
546
|
-
if (host
|
|
524
|
+
for (const dir of [...dirs].sort(bytewise)) {
|
|
525
|
+
if (!holdsManifest(host, dir)) {
|
|
547
526
|
continue;
|
|
548
527
|
}
|
|
549
528
|
for (const path of scriptModules(host, root, dir)) {
|
package/src/component-layer.ts
CHANGED
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
import type { CreateSnapshotParams } from "@typescript/native/sync";
|
|
10
10
|
import type { Host } from "./host.ts";
|
|
11
|
+
import { INSTALLED_PACKAGES } from "./fs/manifest.ts";
|
|
11
12
|
import { dirnamePath, joinPath } from "./paths.ts";
|
|
13
|
+
import { PRODUCT } from "./product.ts";
|
|
12
14
|
|
|
13
15
|
/** The name the mapper's manifest declares and every configuration's entry names. */
|
|
14
|
-
const MAPPER_PACKAGE =
|
|
16
|
+
const MAPPER_PACKAGE = `${PRODUCT}-component-files`;
|
|
15
17
|
|
|
16
18
|
/** The file system one snapshot is created with. */
|
|
17
19
|
type SnapshotFileSystem = NonNullable<CreateSnapshotParams["fileSystem"]>;
|
|
@@ -150,7 +152,7 @@ export function componentLayer(
|
|
|
150
152
|
mappers,
|
|
151
153
|
);
|
|
152
154
|
if (mapper !== undefined) {
|
|
153
|
-
symlinks[joinPath(dirnamePath(configFile),
|
|
155
|
+
symlinks[joinPath(dirnamePath(configFile), INSTALLED_PACKAGES, MAPPER_PACKAGE)] = {
|
|
154
156
|
target: mapper.packageDirectory,
|
|
155
157
|
host: true,
|
|
156
158
|
};
|
package/src/components.ts
CHANGED
|
@@ -7,16 +7,14 @@
|
|
|
7
7
|
import type { Cascade } from "./config.ts";
|
|
8
8
|
import { OUTSIDE, type Graph } from "./graph.ts";
|
|
9
9
|
import type { InventorySymbol } from "./inventory.ts";
|
|
10
|
-
|
|
11
|
-
/** The name every component identifier this analyzer mints starts with. */
|
|
12
|
-
const ANALYZER = "deadset-ts";
|
|
10
|
+
import { PRODUCT } from "./product.ts";
|
|
13
11
|
|
|
14
12
|
/** The fewest digits a component identifier's number is written with. */
|
|
15
13
|
const ID_DIGITS = 4;
|
|
16
14
|
|
|
17
15
|
/** The identifier of the component at one place of the run's order, counted from one. */
|
|
18
16
|
export function componentId(place: number): string {
|
|
19
|
-
return `${
|
|
17
|
+
return `${PRODUCT}/c-${String(place).padStart(ID_DIGITS, "0")}`;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
/** The index of a declaration the component walk has not reached. */
|
package/src/config.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type Format,
|
|
5
|
-
type Language,
|
|
6
|
-
type Severity,
|
|
7
|
-
} from "./contract/contract.generated.ts";
|
|
1
|
+
import type { ResolvedConfig } from "./contract/config.generated.ts";
|
|
2
|
+
import { SEVERITIES, type Severity } from "./contract/contract.generated.ts";
|
|
3
|
+
import { LANGUAGE } from "./product.ts";
|
|
8
4
|
|
|
9
5
|
/**
|
|
10
6
|
* The name of the repository configuration at the target root, which is also the
|
|
@@ -13,254 +9,32 @@ import {
|
|
|
13
9
|
*/
|
|
14
10
|
export const REPOSITORY_DOCUMENT = "deadset.json";
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
* Whether the target is an application, whose every caller is in the analyzed
|
|
18
|
-
* graph, or a library, whose published API has callers outside it.
|
|
19
|
-
*/
|
|
20
|
-
export type TargetKind = "application" | "library";
|
|
12
|
+
export type { PartialConfig, ResolvedConfig } from "./contract/config.generated.ts";
|
|
21
13
|
|
|
22
|
-
/**
|
|
23
|
-
export type
|
|
14
|
+
/** Whether the target is an application or a library. */
|
|
15
|
+
export type TargetKind = Extract<ResolvedConfig["target"]["kind"], string>;
|
|
16
|
+
export type DeclarationEntry = ResolvedConfig["ts"]["serializers"][number];
|
|
17
|
+
export type LifecycleContract = ResolvedConfig["ts"]["lifecycle_contracts"][number];
|
|
18
|
+
export type BuildConfiguration = ResolvedConfig["analysis"]["configurations"][number];
|
|
19
|
+
export type ProjectConfiguration = Extract<BuildConfiguration, { readonly project: string }>;
|
|
20
|
+
export type TemplateDelimiters = ResolvedConfig["analysis"]["template_delimiters"];
|
|
21
|
+
export type Sort = ResolvedConfig["reporters"]["sort"];
|
|
22
|
+
export type Cascade = ResolvedConfig["reporters"]["cascade"];
|
|
24
23
|
|
|
25
|
-
/** The kind a target kind setting gives
|
|
26
|
-
export function kindOf(
|
|
27
|
-
return typeof
|
|
24
|
+
/** The kind a target kind setting gives this analyzer's declarations. */
|
|
25
|
+
export function kindOf(kind: ResolvedConfig["target"]["kind"]): TargetKind {
|
|
26
|
+
return typeof kind === "string" ? kind : kind[LANGUAGE];
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
/** Whether declarations in generated files are analyzed. */
|
|
31
|
-
export type GeneratedFiles = "exclude" | "include";
|
|
32
|
-
|
|
33
|
-
/** How a reference from a consumer's test file counts. */
|
|
34
|
-
export type ConsumerTests = "test" | "production";
|
|
35
|
-
|
|
36
|
-
/** The severities ranked, the strongest highest. */
|
|
37
|
-
const SEVERITY_RANK: Readonly<Record<Severity, number>> = { allow: 0, warn: 1, deny: 2 };
|
|
38
|
-
|
|
39
29
|
/** Whether a finding at one severity fails a run under the failing severity. */
|
|
40
30
|
export function fails(severity: Severity, failOn: Severity): boolean {
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** The order findings are rendered in. */
|
|
45
|
-
export type Sort = "position" | "size";
|
|
46
|
-
|
|
47
|
-
/** How much of a dead component a rendering names. */
|
|
48
|
-
export type Cascade = "roots" | "full";
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* A platform configuration: an operating system, an architecture and the build
|
|
52
|
-
* tags in effect. It is the shape a language built under build constraints reads,
|
|
53
|
-
* and this analyzer leaves it to that analysis.
|
|
54
|
-
*/
|
|
55
|
-
interface PlatformConfiguration {
|
|
56
|
-
readonly shape: "platform";
|
|
57
|
-
readonly id: string;
|
|
58
|
-
readonly os: string;
|
|
59
|
-
readonly arch: string;
|
|
60
|
-
readonly tags: readonly string[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* A project configuration: one compiler configuration file, as a path below the
|
|
65
|
-
* target root with `/` between segments.
|
|
66
|
-
*/
|
|
67
|
-
export interface ProjectConfiguration {
|
|
68
|
-
readonly shape: "project";
|
|
69
|
-
readonly id: string;
|
|
70
|
-
readonly project: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* One entry of the build matrix: a configuration the target builds under, in
|
|
75
|
-
* exactly one of the two shapes the matrix admits.
|
|
76
|
-
*/
|
|
77
|
-
export type BuildConfiguration = PlatformConfiguration | ProjectConfiguration;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* The pair of action delimiters a template is parsed with. Both members are
|
|
81
|
-
* required once a document names the object, so the pair is one setting rather
|
|
82
|
-
* than two.
|
|
83
|
-
*/
|
|
84
|
-
export interface TemplateDelimiters {
|
|
85
|
-
readonly left: string;
|
|
86
|
-
readonly right: string;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** How the analysis is scoped and filtered. */
|
|
90
|
-
export interface Analysis {
|
|
91
|
-
readonly languages: readonly Language[];
|
|
92
|
-
readonly minConfidence: Confidence;
|
|
93
|
-
readonly generatedFiles: GeneratedFiles;
|
|
94
|
-
readonly consumerTests: ConsumerTests;
|
|
95
|
-
readonly configurations: readonly BuildConfiguration[];
|
|
96
|
-
readonly matrixComplete: boolean;
|
|
97
|
-
readonly templateDirs: readonly string[];
|
|
98
|
-
readonly templateDelimiters: TemplateDelimiters;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** How findings are rendered. */
|
|
102
|
-
interface Reporters {
|
|
103
|
-
readonly formats: readonly Format[];
|
|
104
|
-
readonly sort: Sort;
|
|
105
|
-
readonly cascade: Cascade;
|
|
106
|
-
readonly maxFindings: number;
|
|
107
|
-
readonly failOn: Severity;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* One declaration a configuration entry names, in exactly one of three shapes: a
|
|
112
|
-
* declaration of the analyzed program by its stable symbol reference, a declaration a
|
|
113
|
-
* module exports by the bare specifier an import writes for the module and the
|
|
114
|
-
* declaration's path from its exports, or a declaration of the global scope by its
|
|
115
|
-
* path from that scope. A path joins the name and each member with dots and spells a
|
|
116
|
-
* static member with `:static` after it.
|
|
117
|
-
*/
|
|
118
|
-
export type DeclarationEntry =
|
|
119
|
-
| { readonly shape: "symbol"; readonly symbol: string }
|
|
120
|
-
| { readonly shape: "module"; readonly module: string; readonly name: string }
|
|
121
|
-
| { readonly shape: "global"; readonly global: string };
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* One framework's lifecycle contract: the declarations whose use makes a class one of
|
|
125
|
-
* the framework's components, the classes whose subclasses are its components, and the
|
|
126
|
-
* names of the members the framework calls on a component, each spelled as the last
|
|
127
|
-
* component of a member's stable symbol reference.
|
|
128
|
-
*/
|
|
129
|
-
export interface LifecycleContract {
|
|
130
|
-
readonly components: readonly DeclarationEntry[];
|
|
131
|
-
readonly bases: readonly DeclarationEntry[];
|
|
132
|
-
readonly members: readonly string[];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* One analyzer the orchestrator may run, in exactly one of two shapes: an installed
|
|
137
|
-
* analyzer, named by its command alone, or an acquirable one, which also names the
|
|
138
|
-
* artifact acquisition fetches and verifies. This analyzer validates and prints the
|
|
139
|
-
* list and runs nothing from it.
|
|
140
|
-
*/
|
|
141
|
-
export type Provider =
|
|
142
|
-
| {
|
|
143
|
-
readonly shape: "installed";
|
|
144
|
-
readonly name: string;
|
|
145
|
-
readonly languages: readonly Language[];
|
|
146
|
-
readonly command: string;
|
|
147
|
-
}
|
|
148
|
-
| {
|
|
149
|
-
readonly shape: "acquirable";
|
|
150
|
-
readonly name: string;
|
|
151
|
-
readonly languages: readonly Language[];
|
|
152
|
-
readonly command: string;
|
|
153
|
-
readonly source: string;
|
|
154
|
-
readonly version: string;
|
|
155
|
-
readonly digest: string;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
/** The analyzers the orchestrator runs. */
|
|
159
|
-
interface Providers {
|
|
160
|
-
readonly analyzers: readonly Provider[];
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** The section the TypeScript analyzer owns. */
|
|
164
|
-
export interface TSSection {
|
|
165
|
-
readonly testFiles: readonly string[];
|
|
166
|
-
readonly entryFiles: readonly string[];
|
|
167
|
-
readonly componentExtensions: readonly string[];
|
|
168
|
-
readonly disabledConventions: readonly string[];
|
|
169
|
-
readonly injectionRegistrations: readonly DeclarationEntry[];
|
|
170
|
-
readonly lifecycleContracts: readonly LifecycleContract[];
|
|
171
|
-
readonly serializers: readonly DeclarationEntry[];
|
|
172
|
-
/** Whether the maintainer declares the roots the analysis finds every root the target has. */
|
|
173
|
-
readonly rootsComplete: boolean;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* The resolved configuration: the closed key list of the Contract's
|
|
178
|
-
* configuration schema, decoded, with every default applied.
|
|
179
|
-
*
|
|
180
|
-
* `targetKind` is empty exactly in the configuration every default states, which
|
|
181
|
-
* is not a configuration a run may use: the field has no default and resolution
|
|
182
|
-
* refuses a result that carries none.
|
|
183
|
-
*
|
|
184
|
-
* `severity` is a map rather than an object because its keys come from a
|
|
185
|
-
* document, and an object keyed by document text answers for names it never
|
|
186
|
-
* held. The order it is written in is the emitter's, not the map's.
|
|
187
|
-
*/
|
|
188
|
-
export interface Config {
|
|
189
|
-
readonly contractVersion: string;
|
|
190
|
-
readonly targetKind: TargetKindSetting | "";
|
|
191
|
-
readonly analysis: Analysis;
|
|
192
|
-
readonly consumersComplete: boolean;
|
|
193
|
-
readonly rootPatterns: readonly string[];
|
|
194
|
-
readonly severity: ReadonlyMap<string, Severity>;
|
|
195
|
-
readonly exemptionsDisabled: readonly string[];
|
|
196
|
-
readonly reporters: Reporters;
|
|
197
|
-
readonly providers: Providers;
|
|
198
|
-
readonly ts: TSSection;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* The configuration every documented default states. `targetKind` is empty: the
|
|
203
|
-
* field has no default and is never inferred.
|
|
204
|
-
*/
|
|
205
|
-
export function defaultConfig(): Config {
|
|
206
|
-
return {
|
|
207
|
-
contractVersion: CONTRACT_VERSION,
|
|
208
|
-
targetKind: "",
|
|
209
|
-
analysis: {
|
|
210
|
-
languages: [],
|
|
211
|
-
minConfidence: "probable",
|
|
212
|
-
generatedFiles: "exclude",
|
|
213
|
-
consumerTests: "test",
|
|
214
|
-
configurations: [],
|
|
215
|
-
matrixComplete: false,
|
|
216
|
-
templateDirs: [],
|
|
217
|
-
templateDelimiters: { left: "{{", right: "}}" },
|
|
218
|
-
},
|
|
219
|
-
consumersComplete: false,
|
|
220
|
-
rootPatterns: [],
|
|
221
|
-
severity: new Map(),
|
|
222
|
-
exemptionsDisabled: [],
|
|
223
|
-
reporters: {
|
|
224
|
-
formats: ["text"],
|
|
225
|
-
sort: "position",
|
|
226
|
-
cascade: "roots",
|
|
227
|
-
maxFindings: 0,
|
|
228
|
-
failOn: "deny",
|
|
229
|
-
},
|
|
230
|
-
providers: {
|
|
231
|
-
analyzers: [
|
|
232
|
-
{ shape: "installed", name: "deadset-go", languages: ["go"], command: "deadset-go" },
|
|
233
|
-
{ shape: "installed", name: "deadset-ts", languages: ["ts"], command: "deadset-ts" },
|
|
234
|
-
],
|
|
235
|
-
},
|
|
236
|
-
ts: {
|
|
237
|
-
testFiles: [
|
|
238
|
-
"**/*.test.{ts,tsx,mts,cts}",
|
|
239
|
-
"**/*.test-d.{ts,tsx,mts,cts}",
|
|
240
|
-
"**/*.spec-d.{ts,tsx,mts,cts}",
|
|
241
|
-
"**/*.spec.*",
|
|
242
|
-
"**/__tests__/**",
|
|
243
|
-
"**/__mocks__/**",
|
|
244
|
-
"**/test-d/**",
|
|
245
|
-
],
|
|
246
|
-
entryFiles: [],
|
|
247
|
-
componentExtensions: [".vue", ".svelte", ".astro"],
|
|
248
|
-
disabledConventions: [],
|
|
249
|
-
injectionRegistrations: [],
|
|
250
|
-
lifecycleContracts: [],
|
|
251
|
-
serializers: [],
|
|
252
|
-
rootsComplete: false,
|
|
253
|
-
},
|
|
254
|
-
};
|
|
31
|
+
return SEVERITIES.indexOf(severity) >= SEVERITIES.indexOf(failOn);
|
|
255
32
|
}
|
|
256
33
|
|
|
257
34
|
/** Where a resolved setting came from, in the order the sources outrank each other. */
|
|
258
35
|
export type Source = "flag" | "repository" | "central" | "default";
|
|
259
36
|
|
|
260
|
-
/**
|
|
261
|
-
* One setting's source together with the file or flag that supplied it. `label`
|
|
262
|
-
* is empty exactly when `source` is `"default"`.
|
|
263
|
-
*/
|
|
37
|
+
/** One setting's source with the file or flag that supplied it, empty for a default. */
|
|
264
38
|
export interface Origin {
|
|
265
39
|
readonly source: Source;
|
|
266
40
|
readonly label: string;
|
|
@@ -275,63 +49,24 @@ export function renderOrigin(origin: Origin): string {
|
|
|
275
49
|
}
|
|
276
50
|
|
|
277
51
|
/**
|
|
278
|
-
* The origin of each resolved setting, keyed by the setting's dotted path. A
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* empty.
|
|
52
|
+
* The origin of each resolved setting, keyed by the setting's dotted path. A section
|
|
53
|
+
* has no entry; a keyed section carries one entry per member it names, or one for
|
|
54
|
+
* itself when it is empty.
|
|
282
55
|
*/
|
|
283
56
|
export type Provenance = ReadonlyMap<string, Origin>;
|
|
284
57
|
|
|
285
|
-
/**
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
* supplied each setting `flags` names, keyed by dotted setting path.
|
|
290
|
-
*/
|
|
291
|
-
export interface Inputs {
|
|
292
|
-
readonly flags?: string;
|
|
293
|
-
readonly repository?: string;
|
|
294
|
-
readonly central?: string;
|
|
295
|
-
readonly repositoryLabel?: string;
|
|
296
|
-
readonly centralLabel?: string;
|
|
297
|
-
readonly flagLabels?: ReadonlyMap<string, string>;
|
|
58
|
+
/** One configuration document: its text and the path it was read from. */
|
|
59
|
+
export interface Document {
|
|
60
|
+
readonly text: string;
|
|
61
|
+
readonly label: string;
|
|
298
62
|
}
|
|
299
63
|
|
|
300
|
-
/** Which refusal a {@link ConfigError} carries. */
|
|
301
|
-
type ErrorKind =
|
|
302
|
-
/**
|
|
303
|
-
* A document that is not one JSON instance of the closed key list: a syntax
|
|
304
|
-
* error, a value of the wrong type, a value outside the closed set a key
|
|
305
|
-
* declares, or a member written twice at one level.
|
|
306
|
-
*/
|
|
307
|
-
| "malformed"
|
|
308
|
-
/**
|
|
309
|
-
* A key the closed key list does not declare, or a severity key naming no live
|
|
310
|
-
* kind or a kind whose severity the Contract fixes.
|
|
311
|
-
*/
|
|
312
|
-
| "unimplemented-key"
|
|
313
|
-
/** A resolved configuration no source supplied a target kind for. */
|
|
314
|
-
| "missing-target-kind";
|
|
315
|
-
|
|
316
64
|
/**
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
* one caller that turns it into an exit code is the command line.
|
|
65
|
+
* The configuration sources one invocation carries. `flags` holds the text each
|
|
66
|
+
* setting option was given, by the setting's dotted path.
|
|
320
67
|
*/
|
|
321
|
-
export
|
|
322
|
-
|
|
323
|
-
readonly
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* The key or field the message names, spelled as the document spells it. It is
|
|
327
|
-
* empty when the refusal names none.
|
|
328
|
-
*/
|
|
329
|
-
readonly key: string;
|
|
330
|
-
|
|
331
|
-
constructor(kind: ErrorKind, key: string, message: string) {
|
|
332
|
-
super(message);
|
|
333
|
-
this.name = "ConfigError";
|
|
334
|
-
this.kind = kind;
|
|
335
|
-
this.key = key;
|
|
336
|
-
}
|
|
68
|
+
export interface Inputs {
|
|
69
|
+
readonly flags?: ReadonlyMap<string, string>;
|
|
70
|
+
readonly repository?: Document;
|
|
71
|
+
readonly central?: Document;
|
|
337
72
|
}
|