@cplieger/deadset-ts 8.0.0-dev.14 → 8.0.0-dev.16
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/src/alias-chain.js +2 -2
- package/dist/src/analysis.js +43 -38
- package/dist/src/commands/read.js +6 -7
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +4 -2
- package/dist/src/contract/config.generated.js +1 -1
- package/dist/src/contract/contract.generated.js +120 -2
- package/dist/src/dependencies.js +81 -49
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +20 -58
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
- package/dist/src/entries/conventions.js +739 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +3 -3
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +2 -2
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +669 -0
- package/dist/src/entries/test-runners.js +684 -0
- package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/file-facts.js +1 -1
- package/dist/src/findings/emitters.js +5 -8
- package/dist/src/findings/self-check.js +36 -20
- package/dist/src/findings-pass.js +5 -6
- package/dist/src/framework-lifecycle.js +1 -1
- package/dist/src/fs/manifest.js +15 -20
- package/dist/src/generated-file.js +172 -29
- package/dist/src/graph.js +2 -5
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/inventory/commonjs.js +507 -0
- package/dist/src/inventory/enumerate.js +167 -0
- package/dist/src/inventory/syntax.js +236 -0
- package/dist/src/inventory.js +305 -705
- package/dist/src/javascript-file.js +26 -11
- package/dist/src/load/classify.js +28 -9
- package/dist/src/load/diagnostics.js +8 -1
- package/dist/src/load/discover.js +16 -8
- package/dist/src/load/package-scope.js +56 -0
- package/dist/src/load/plan.js +2 -2
- package/dist/src/load/synthesize.js +5 -5
- package/dist/src/load/workspace-manifests.js +1 -1
- package/dist/src/matrix.js +6 -13
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/paths.js +16 -0
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +140 -0
- package/dist/src/position.js +41 -0
- package/dist/src/ref.js +11 -20
- package/dist/src/references.js +281 -50
- package/dist/src/resolve.js +1 -1
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +4 -4
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
- package/dist/src/{manifest.js → roots/manifest.js} +4 -4
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +489 -0
- package/dist/src/roots/unseen-loads.js +208 -0
- package/dist/src/serialization-contract.js +1 -1
- package/dist/src/session.js +3 -0
- package/dist/src/source-files.js +5 -9
- package/dist/src/suppress-inline.js +33 -81
- package/dist/src/suppress.js +30 -32
- package/dist/src/test-support.js +4 -2
- package/dist/src/verbs/analyze.js +13 -1
- package/dist/src/verbs/describe.js +5 -3
- package/jsr.json +1 -1
- package/package.json +3 -3
- package/src/alias-chain.ts +2 -2
- package/src/analysis.ts +77 -53
- package/src/automatic-types.ts +1 -1
- package/src/commands/read.ts +6 -8
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +5 -1
- package/src/contract/config.generated.ts +1 -1
- package/src/contract/contract.generated.ts +139 -2
- package/src/dependencies.ts +98 -50
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +23 -75
- package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
- package/src/{conventions.ts → entries/conventions.ts} +347 -522
- package/src/{html-entries.ts → entries/html-entries.ts} +5 -5
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +4 -4
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +857 -0
- package/src/entries/test-runners.ts +868 -0
- package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
- package/src/exempt.ts +3 -2
- package/src/extensions.ts +45 -0
- package/src/facts.ts +44 -0
- package/src/file-facts.ts +2 -2
- package/src/findings/emitters.ts +14 -10
- package/src/findings/self-check.ts +41 -22
- package/src/findings/visibility-narrowing.ts +1 -1
- package/src/findings-pass.ts +5 -12
- package/src/framework-lifecycle.ts +1 -1
- package/src/fs/manifest.ts +25 -21
- package/src/generated-file.ts +240 -36
- package/src/graph.ts +3 -6
- package/src/index.ts +1 -1
- package/src/injection-container.ts +1 -1
- package/src/inventory/commonjs.ts +696 -0
- package/src/inventory/enumerate.ts +203 -0
- package/src/inventory/syntax.ts +311 -0
- package/src/inventory.ts +424 -878
- package/src/javascript-file.ts +29 -12
- package/src/load/classify.ts +49 -13
- package/src/load/diagnostics.ts +11 -1
- package/src/load/discover.ts +28 -12
- package/src/load/package-scope.ts +74 -0
- package/src/load/plan.ts +11 -2
- package/src/load/synthesize.ts +6 -6
- package/src/load/test-globals.ts +1 -1
- package/src/load/workspace-manifests.ts +1 -1
- package/src/load/workspace-run.ts +1 -1
- package/src/matrix.ts +7 -14
- package/src/outside-tests.ts +1 -1
- package/src/paths.ts +18 -0
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +205 -0
- package/src/position.ts +42 -0
- package/src/ref.ts +11 -20
- package/src/references.ts +383 -73
- package/src/report.ts +1 -1
- package/src/resolve.ts +1 -1
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +7 -7
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
- package/src/{manifest.ts → roots/manifest.ts} +5 -5
- package/src/roots/published-reach.ts +481 -0
- package/src/{roots.ts → roots/root-set.ts} +203 -630
- package/src/roots/unseen-loads.ts +307 -0
- package/src/serialization-contract.ts +1 -1
- package/src/session.ts +17 -1
- package/src/source-files.ts +5 -10
- package/src/suppress-inline.ts +53 -89
- package/src/suppress.ts +48 -33
- package/src/test-support.ts +8 -3
- package/src/verbs/analyze.ts +17 -4
- package/src/verbs/describe.ts +5 -2
- package/src/verbs/explain.ts +1 -1
- package/dist/src/build-scripts.js +0 -418
- package/dist/src/conventions.js +0 -907
- package/dist/src/entry-points.js +0 -513
- package/dist/src/roots.js +0 -865
- package/dist/src/unseen-loads.js +0 -100
- package/src/build-scripts.ts +0 -536
- package/src/entry-points.ts +0 -661
- package/src/unseen-loads.ts +0 -134
|
@@ -12,7 +12,7 @@ import { SignatureKind, SymbolFlags, TypeFlags, } from "@typescript/native/sync"
|
|
|
12
12
|
import { aliasChains } from "./alias-chain.js";
|
|
13
13
|
import { calleeName, resolvedTargets, valuesPassed } from "./calls.js";
|
|
14
14
|
import { classMembers, memberComponent, typesAt } from "./class-members.js";
|
|
15
|
-
import { names, namesADeclaration, resolveEntries, spelledEntry, } from "./configured-declarations.js";
|
|
15
|
+
import { names, namesADeclaration, resolveEntries, spelledEntry, } from "./roots/configured-declarations.js";
|
|
16
16
|
import { nodeKey } from "./inventory.js";
|
|
17
17
|
import { renderPosition } from "./position.js";
|
|
18
18
|
import { must, Unanswerable } from "./query.js";
|
package/dist/src/session.js
CHANGED
|
@@ -138,6 +138,9 @@ function viewOf(project, configFile, engine, log) {
|
|
|
138
138
|
ownKeys ??= new Set(ownSourceFiles().map((file) => file.path));
|
|
139
139
|
return ownKeys;
|
|
140
140
|
},
|
|
141
|
+
resolvedFileNames: (specifiers) => batched(engine, specifiers, (node) => project.program.getResolvedModuleFromModuleSpecifier.gen(node, node.getSourceFile().fileName)).map((resolved) => resolved === undefined || resolved.resolvedFileName === ""
|
|
142
|
+
? undefined
|
|
143
|
+
: resolved.resolvedFileName),
|
|
141
144
|
handle: (node) => ({ node }),
|
|
142
145
|
symbolsAt: (handles, cap) => queries.symbolsAt(handles.map(({ node }) => node), cap),
|
|
143
146
|
resolvedSymbolAt: ({ node }) => queries.resolvedSymbol(node),
|
package/dist/src/source-files.js
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { commonDirectory, emittedFrom } from "./load/emit-map.js";
|
|
7
7
|
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
8
|
+
import { OUTPUT_EXTENSIONS } from "./extensions.js";
|
|
8
9
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
9
10
|
const SUBPATH_WILDCARD = "*";
|
|
10
11
|
/** The extension a source file's name drops when the project writes it out. */
|
|
11
12
|
const SOURCE_EXTENSION = /\.[cm]?[jt]sx?$/u;
|
|
12
|
-
/** The extensions the project may write a source file's output under. */
|
|
13
|
-
const OUTPUT_EXTENSIONS = [".js", ".mjs", ".cjs", ".jsx", ".d.ts", ".d.mts", ".d.cts"];
|
|
14
13
|
/**
|
|
15
14
|
* Whether one path is what a subpath pattern stands for: the text before the
|
|
16
15
|
* wildcard, any run of characters including the solidus, then the text after it.
|
|
@@ -43,13 +42,10 @@ function layoutOf(project, fileNames) {
|
|
|
43
42
|
};
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
|
-
* The lookups over one project's own files.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* extension is one the compiler emits from a source extension, and a path below the
|
|
51
|
-
* output directory is read below the directory the compiler emits from, which the
|
|
52
|
-
* configuration declares or which is the directory every input file shares.
|
|
45
|
+
* The lookups over one project's own files. A path naming an emitted file is read back to its
|
|
46
|
+
* source through the project's own emit mapping alone: the extension is one the compiler emits
|
|
47
|
+
* from a source extension, and a path below the output directory is read below the directory
|
|
48
|
+
* the compiler emits from, which the configuration declares or every input file shares.
|
|
53
49
|
*/
|
|
54
50
|
export function sourceFilesOf(project, targetRoot) {
|
|
55
51
|
const byName = new Map();
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* below it, or on its own line where it trails a token there.
|
|
5
5
|
*/
|
|
6
6
|
import { CODE } from "./contract/contract.generated.js";
|
|
7
|
-
import {
|
|
7
|
+
import { SyntaxKind } from "@typescript/native/ast";
|
|
8
8
|
import { importBindings } from "./import-bindings.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { nodeKey } from "./inventory.js";
|
|
10
|
+
import { relativePath } from "./paths.js";
|
|
11
|
+
import { byPosition, lineEnd, positionKey, renderPosition, startLine, tokenStart, } from "./position.js";
|
|
11
12
|
import { importRef } from "./ref.js";
|
|
12
|
-
import { signatureOf } from "./signatures.js";
|
|
13
13
|
import { isPartKind, SuppressionError, siteText, } from "./suppress.js";
|
|
14
14
|
/**
|
|
15
15
|
* The three expressions the grammar applies to the text of each line comment, in this
|
|
@@ -55,43 +55,6 @@ const LITERALS = new Set([
|
|
|
55
55
|
SyntaxKind.RegularExpressionLiteral,
|
|
56
56
|
SyntaxKind.JsxText,
|
|
57
57
|
]);
|
|
58
|
-
/** Whether one character ends a line, under the language's line terminators. */
|
|
59
|
-
function endsLine(char) {
|
|
60
|
-
return char === "\n" || char === "\r" || char === "\u2028" || char === "\u2029";
|
|
61
|
-
}
|
|
62
|
-
/** The offset where the line holding `from` ends. */
|
|
63
|
-
function lineEnd(text, from) {
|
|
64
|
-
let at = from;
|
|
65
|
-
while (at < text.length && !endsLine(text[at])) {
|
|
66
|
-
at += 1;
|
|
67
|
-
}
|
|
68
|
-
return at;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* The offset of the first token at or after `from`: whitespace, comments and a leading
|
|
72
|
-
* hashbang are trivia.
|
|
73
|
-
*/
|
|
74
|
-
export function tokenStart(text, from) {
|
|
75
|
-
let at = from;
|
|
76
|
-
if (at === 0 && text.startsWith("#!")) {
|
|
77
|
-
at = lineEnd(text, 0);
|
|
78
|
-
}
|
|
79
|
-
for (;;) {
|
|
80
|
-
if (/\s/u.test(text[at] ?? "")) {
|
|
81
|
-
at += 1;
|
|
82
|
-
}
|
|
83
|
-
else if (text.startsWith("//", at)) {
|
|
84
|
-
at = lineEnd(text, at);
|
|
85
|
-
}
|
|
86
|
-
else if (text.startsWith("/*", at)) {
|
|
87
|
-
const close = text.indexOf("*/", at + 2);
|
|
88
|
-
at = close < 0 ? text.length : close + 2;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
return at;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
58
|
/**
|
|
96
59
|
* Every `//` line comment of one file, in file order. The text between tokens is read as
|
|
97
60
|
* the language reads it: a block comment holds no line comment, and the literal tokens the
|
|
@@ -140,55 +103,42 @@ function lineComments(file) {
|
|
|
140
103
|
function bindingKey(one) {
|
|
141
104
|
return `${one.declared?.id ?? ""}\u0000${one.part.id}`;
|
|
142
105
|
}
|
|
106
|
+
/** The placed declarations of a project by the path of the file each is in. */
|
|
107
|
+
function placedByPath(held, symbols) {
|
|
108
|
+
const byPath = new Map();
|
|
109
|
+
for (const [id, placed] of held.placement) {
|
|
110
|
+
const one = symbols.get(id);
|
|
111
|
+
const holder = symbols.get(placed.holder);
|
|
112
|
+
if (one === undefined || holder === undefined) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const at = byPath.get(one.position.path) ?? [];
|
|
116
|
+
at.push({ one, holder, startLines: placed.startLines, partLines: placed.partLines });
|
|
117
|
+
byPath.set(one.position.path, at);
|
|
118
|
+
}
|
|
119
|
+
return byPath;
|
|
120
|
+
}
|
|
143
121
|
/**
|
|
144
|
-
* The declarations of one file by the line each
|
|
145
|
-
*
|
|
146
|
-
* keyword, and a variable written on a later line of the statement also begins there. A
|
|
147
|
-
* function also begins, for a directive, on the line of each of its parameters, and a
|
|
148
|
-
* class, for a part kind, on the lines of its constructor and its constructor's parameters.
|
|
122
|
+
* The declarations of one file by the line a directive binds each on, as the inventory
|
|
123
|
+
* places them, and each import binding of the file on its statement's lines.
|
|
149
124
|
*/
|
|
150
|
-
function declarationLines(file,
|
|
125
|
+
function declarationLines(file, placed, held, targetRoot) {
|
|
151
126
|
const below = new Map();
|
|
152
|
-
const add = (
|
|
153
|
-
const line = file.getLineAndCharacterOfPosition(tokenStart(file.text, offset)).line + 1;
|
|
127
|
+
const add = (line, one) => {
|
|
154
128
|
const at = below.get(line) ?? [];
|
|
155
129
|
if (!at.some((known) => bindingKey(known) === bindingKey(one))) {
|
|
156
130
|
at.push(one);
|
|
157
131
|
}
|
|
158
132
|
below.set(line, at);
|
|
159
133
|
};
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
};
|
|
164
|
-
const visit = (node) => {
|
|
165
|
-
const one = declaredAt(node);
|
|
166
|
-
const owner = isConstructorDeclaration(node) ? declaredAt(node.parent) : undefined;
|
|
167
|
-
if (owner !== undefined && isConstructorDeclaration(node)) {
|
|
168
|
-
for (const at of [node, ...node.parameters.filter((one) => !isParameterProperty(one))]) {
|
|
169
|
-
add(at.pos, { declared: undefined, part: owner });
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
const holder = one !== undefined && isParameterProperty(node) ? declaredAt(node.parent.parent) : one;
|
|
173
|
-
if (one !== undefined && holder !== undefined) {
|
|
174
|
-
add(node.pos, { declared: one, part: holder });
|
|
134
|
+
for (const { one, holder, startLines, partLines } of placed) {
|
|
135
|
+
for (const line of startLines) {
|
|
136
|
+
add(line, { declared: one, part: holder });
|
|
175
137
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// line above it, inside the parameter list, and the directive binds the function.
|
|
179
|
-
for (const parameter of signatureOf(node)?.parameters ?? []) {
|
|
180
|
-
add(parameter.pos, { declared: one, part: one });
|
|
181
|
-
}
|
|
182
|
-
const list = node.parent;
|
|
183
|
-
if (node.kind === SyntaxKind.VariableDeclaration &&
|
|
184
|
-
list.kind === SyntaxKind.VariableDeclarationList &&
|
|
185
|
-
list.parent.kind === SyntaxKind.VariableStatement) {
|
|
186
|
-
add(list.parent.pos, { declared: one, part: one });
|
|
187
|
-
}
|
|
138
|
+
for (const line of partLines) {
|
|
139
|
+
add(line, { declared: undefined, part: one });
|
|
188
140
|
}
|
|
189
|
-
|
|
190
|
-
};
|
|
191
|
-
file.forEachChild(visit);
|
|
141
|
+
}
|
|
192
142
|
// An import binding is a subject of its own, bound on its line as a declaration is.
|
|
193
143
|
const fileId = held.declarations.get(nodeKey(file, file));
|
|
194
144
|
const moduleRef = held.symbols.find((symbol) => symbol.id === fileId)?.ref ?? "";
|
|
@@ -200,7 +150,7 @@ function declarationLines(file, held, symbols, targetRoot) {
|
|
|
200
150
|
statement = statement.parent;
|
|
201
151
|
}
|
|
202
152
|
for (const at of [statement.pos, name.getStart()]) {
|
|
203
|
-
add(at, { declared: one, part: one });
|
|
153
|
+
add(startLine(file, at), { declared: one, part: one });
|
|
204
154
|
}
|
|
205
155
|
}
|
|
206
156
|
return below;
|
|
@@ -221,13 +171,15 @@ export function inlineDirectives(project, held, targetRoot) {
|
|
|
221
171
|
const symbols = new Map(held.symbols
|
|
222
172
|
.filter((symbol) => symbol.kind !== "file")
|
|
223
173
|
.map((symbol) => [symbol.id, { id: symbol.id, ref: symbol.ref, position: symbol.position }]));
|
|
174
|
+
const placed = placedByPath(held, symbols);
|
|
224
175
|
const found = [];
|
|
225
176
|
for (const file of project.ownSourceFiles()) {
|
|
226
177
|
const comments = lineComments(file).filter((comment) => CANDIDATE.test(comment.text));
|
|
227
178
|
if (comments.length === 0) {
|
|
228
179
|
continue;
|
|
229
180
|
}
|
|
230
|
-
const
|
|
181
|
+
const path = relativePath(targetRoot, file.fileName) ?? "";
|
|
182
|
+
const below = declarationLines(file, placed.get(path) ?? [], held, targetRoot);
|
|
231
183
|
for (const comment of comments) {
|
|
232
184
|
const site = renderPosition(file, targetRoot, comment.offset);
|
|
233
185
|
const target = trails(file, comment.offset) ? site.line : site.line + 1;
|
package/dist/src/suppress.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* ignore entry or a baseline row. A bound record marks its declaration live before the
|
|
5
5
|
* sweep, unless its code reports a part or a dependency row, and is in effect when it
|
|
6
6
|
* withholds a finding its code would have produced there, dormant when the configuration
|
|
7
|
-
* withholds every such finding anyway, and stale otherwise.
|
|
7
|
+
* or a hold withholds every such finding anyway, and stale otherwise.
|
|
8
8
|
*/
|
|
9
|
-
import { KIND_ROWS, SYMBOL_SUBJECTS, } from "./contract/contract.generated.js";
|
|
9
|
+
import { KIND_ROWS, REMEDIES, SYMBOL_SUBJECTS, } from "./contract/contract.generated.js";
|
|
10
10
|
import { UsageError } from "./usage.js";
|
|
11
11
|
import { positionKey } from "./position.js";
|
|
12
12
|
import { isRef } from "./ref.js";
|
|
@@ -66,6 +66,8 @@ export function isSymbolRef(value) {
|
|
|
66
66
|
export function blankReason(reason) {
|
|
67
67
|
return reason === undefined || /^[ \t\r\n]*$/u.test(reason);
|
|
68
68
|
}
|
|
69
|
+
/** No hold. */
|
|
70
|
+
const NO_HOLDS = { withholds: () => false, holdsRecord: () => false };
|
|
69
71
|
/** The subject of the kind each live code names. */
|
|
70
72
|
const SUBJECT_OF_CODE = new Map(KIND_ROWS.map((row) => [row.code, row.subject]));
|
|
71
73
|
/** The subject a finding about one symbol kind is about. */
|
|
@@ -78,32 +80,25 @@ function subjectOf(kind) {
|
|
|
78
80
|
function rowOf(subject) {
|
|
79
81
|
return subject === "file" || subject === "dependency" || subject === "record";
|
|
80
82
|
}
|
|
81
|
-
/**
|
|
82
|
-
* Whether a finding's subject is a row of a document rather than a declaration. Apart
|
|
83
|
-
* from a dependency row, nothing withholds a finding about one.
|
|
84
|
-
*/
|
|
83
|
+
/** Whether a finding's subject is a row of a document rather than a declaration. */
|
|
85
84
|
export function isRowSubject(kind) {
|
|
86
85
|
return rowOf(subjectOf(kind));
|
|
87
86
|
}
|
|
88
|
-
/**
|
|
89
|
-
export function
|
|
90
|
-
return
|
|
87
|
+
/** The subject a code reports, which kinds.json's remedies table answers for. */
|
|
88
|
+
export function subjectOfCode(code) {
|
|
89
|
+
return SUBJECT_OF_CODE.get(code);
|
|
91
90
|
}
|
|
92
91
|
/**
|
|
93
|
-
* Whether a
|
|
94
|
-
*
|
|
95
|
-
*
|
|
92
|
+
* Whether a record of `mechanism` can name a finding about `subject`, as kinds.json's
|
|
93
|
+
* remedies table lists the suppressions of each subject. A subject the table does not
|
|
94
|
+
* know is a declaration's.
|
|
96
95
|
*/
|
|
97
|
-
export function
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
/** Whether a code reports a dependency row, which only an ignore entry or a baseline row names. */
|
|
101
|
-
export function isDependencyCode(code) {
|
|
102
|
-
return SUBJECT_OF_CODE.get(code) === "dependency";
|
|
96
|
+
export function names(subject, mechanism) {
|
|
97
|
+
return REMEDIES[subject ?? "declaration"].suppressions.includes(mechanism);
|
|
103
98
|
}
|
|
104
|
-
/** Whether a
|
|
105
|
-
export function
|
|
106
|
-
return
|
|
99
|
+
/** Whether a finding about a symbol of `kind` is one a record of `mechanism` can name. */
|
|
100
|
+
export function namesKind(kind, mechanism) {
|
|
101
|
+
return names(subjectOf(kind), mechanism);
|
|
107
102
|
}
|
|
108
103
|
/**
|
|
109
104
|
* Whether a finding's subject is a part of the declaration its reference names: a part
|
|
@@ -136,14 +131,13 @@ export function pairs(record, finding) {
|
|
|
136
131
|
if (record.code !== finding.code) {
|
|
137
132
|
return false;
|
|
138
133
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
record.symbol === finding.symbol.ref &&
|
|
142
|
-
record.path === finding.position.path);
|
|
143
|
-
}
|
|
144
|
-
if (isRowSubject(finding.symbol.kind)) {
|
|
134
|
+
const subject = subjectOf(finding.symbol.kind);
|
|
135
|
+
if (!names(subject, record.mechanism)) {
|
|
145
136
|
return false;
|
|
146
137
|
}
|
|
138
|
+
if (subject === "dependency") {
|
|
139
|
+
return record.symbol === finding.symbol.ref && record.path === finding.position.path;
|
|
140
|
+
}
|
|
147
141
|
if (record.bound !== "" && record.bound === positionKey(finding.position)) {
|
|
148
142
|
return true;
|
|
149
143
|
}
|
|
@@ -155,10 +149,10 @@ export function pairs(record, finding) {
|
|
|
155
149
|
* there: swept with no mark for a liveness kind, and as swept otherwise. The first record
|
|
156
150
|
* in reading order claims a finding, so a second naming it is stale; a part-kind record
|
|
157
151
|
* claims every finding of its code about a part of its declaration. A record is dormant
|
|
158
|
-
* when the dials withhold every finding it claims,
|
|
159
|
-
*
|
|
152
|
+
* when the dials or `holds` withhold every finding it claims, or when it claims none and
|
|
153
|
+
* its code is at `allow` or a hold keeps its declaration live.
|
|
160
154
|
*/
|
|
161
|
-
export function ledgerOf(records, would, dials) {
|
|
155
|
+
export function ledgerOf(records, would, dials, holds = NO_HOLDS) {
|
|
162
156
|
const taken = new Set();
|
|
163
157
|
const verdicts = [];
|
|
164
158
|
for (const record of records) {
|
|
@@ -166,13 +160,17 @@ export function ledgerOf(records, would, dials) {
|
|
|
166
160
|
const first = would.find(open);
|
|
167
161
|
const claimed = first === undefined ? [] : isPartKind(record.code) ? would.filter(open) : [first];
|
|
168
162
|
if (claimed.length === 0) {
|
|
169
|
-
verdicts.push(record.bound !== "" && dials.allows(record.code)
|
|
163
|
+
verdicts.push(record.bound !== "" && (dials.allows(record.code) || holds.holdsRecord(record))
|
|
164
|
+
? "dormant"
|
|
165
|
+
: "stale");
|
|
170
166
|
continue;
|
|
171
167
|
}
|
|
172
168
|
for (const finding of claimed) {
|
|
173
169
|
taken.add(claimKey(finding));
|
|
174
170
|
}
|
|
175
|
-
verdicts.push(claimed.every((finding) => dials.withholds(finding)
|
|
171
|
+
verdicts.push(claimed.every((finding) => dials.withholds(finding) || holds.withholds(finding))
|
|
172
|
+
? "dormant"
|
|
173
|
+
: "in-effect");
|
|
176
174
|
}
|
|
177
175
|
return {
|
|
178
176
|
verdicts,
|
package/dist/src/test-support.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* another such file, so it is judged with the tests: what it references is referenced by
|
|
6
6
|
* test code.
|
|
7
7
|
*/
|
|
8
|
-
import { CONVENTION_ROWS, TEST_LIBRARIES, TEST_LIBRARY_SCOPES } from "./convention-rows.js";
|
|
8
|
+
import { CONVENTION_ROWS, TEST_LIBRARIES, TEST_LIBRARY_SCOPES } from "./entries/convention-rows.js";
|
|
9
9
|
import { packageOfSpecifier } from "./dependencies.js";
|
|
10
10
|
/** The root kind that never takes a file out of test-support code: the skip only withholds. */
|
|
11
11
|
const SKIP_ROOT = "type-error";
|
|
@@ -14,7 +14,9 @@ const SKIP_ROOT = "type-error";
|
|
|
14
14
|
* convention row reads test files for, and the convention table's test libraries.
|
|
15
15
|
*/
|
|
16
16
|
const TEST_PACKAGES = new Set([
|
|
17
|
-
...CONVENTION_ROWS.filter((row) => row.testFiles !== undefined
|
|
17
|
+
...CONVENTION_ROWS.filter((row) => row.testFiles !== undefined ||
|
|
18
|
+
row.testDirectories !== undefined ||
|
|
19
|
+
row.testRunner !== undefined).map((row) => row.package),
|
|
18
20
|
...TEST_LIBRARIES,
|
|
19
21
|
]);
|
|
20
22
|
/**
|
|
@@ -3,6 +3,7 @@ import { runAnalysis, runBaselineWrite, unansweredCounts, } from "../analysis.js
|
|
|
3
3
|
import { kindOf } from "../config.js";
|
|
4
4
|
import { CONFORMANCE, DECLARED_GAPS } from "../conformance.js";
|
|
5
5
|
import { analyzerProvenance, verdictOf } from "../findings-pass.js";
|
|
6
|
+
import { factsDocument } from "../facts.js";
|
|
6
7
|
import { dirnamePath, joinPath, normalizePath, relativePath, resolvePath } from "../paths.js";
|
|
7
8
|
import { moduleIdentity } from "../load/discover.js";
|
|
8
9
|
import { partialNotes } from "../partial.js";
|
|
@@ -21,7 +22,7 @@ import { diagnose, message } from "../product.js";
|
|
|
21
22
|
import { ownVersion } from "./version.js";
|
|
22
23
|
/** The options `analyze` takes beside the ones every verb takes. */
|
|
23
24
|
export const ANALYZE_OPTIONS = {
|
|
24
|
-
plain: ["report", "baseline-write", "exit-code", "template"],
|
|
25
|
+
plain: ["report", "facts", "baseline-write", "exit-code", "template"],
|
|
25
26
|
repeatable: ["format"],
|
|
26
27
|
};
|
|
27
28
|
/** The two values `--exit-code` takes; on, the default, puts the run's verdict in the exit code. */
|
|
@@ -211,8 +212,13 @@ export const analyzeVerb = ({ err, host, inputs, scope, openClient, option, repe
|
|
|
211
212
|
const { config, provenance } = resolve(inputs());
|
|
212
213
|
const invoked = host.workingDirectory();
|
|
213
214
|
const baseline = option("baseline-write");
|
|
215
|
+
const facts = option("facts");
|
|
216
|
+
if (facts === "") {
|
|
217
|
+
throw new UsageError("--facts names the path the facts document is written to, and named none");
|
|
218
|
+
}
|
|
214
219
|
const documents = {
|
|
215
220
|
report: resolvePath(invoked, reportPath),
|
|
221
|
+
facts: facts === undefined ? undefined : resolvePath(invoked, facts),
|
|
216
222
|
formats: formatsOf(repeated("format"), config.reporters.formats),
|
|
217
223
|
baseline: baseline === undefined ? undefined : resolvePath(invoked, baseline),
|
|
218
224
|
};
|
|
@@ -281,6 +287,12 @@ export const analyzeVerb = ({ err, host, inputs, scope, openClient, option, repe
|
|
|
281
287
|
throw productFault(`built a report that breaks the report schema at ${refused.pointer || "the document"}: ${refused.keyword}: ${refused.reason}`);
|
|
282
288
|
}
|
|
283
289
|
writeDocument(host, documents.report, "name a path the run can write", () => json(report));
|
|
290
|
+
const factsPath = documents.facts;
|
|
291
|
+
if (factsPath !== undefined) {
|
|
292
|
+
writeDocument(host, factsPath, "name a path the run can write", () => [
|
|
293
|
+
factsDocument(version, run.generated),
|
|
294
|
+
]);
|
|
295
|
+
}
|
|
284
296
|
const options = {
|
|
285
297
|
readSource: (path) => host.readFile(joinPath(targetRoot, path)),
|
|
286
298
|
template,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { CONTRACT_VERSION, EXIT_CLEAN, EXIT_USAGE, SCHEMA_VERSIONS, } from "../contract/contract.generated.js";
|
|
1
|
+
import { CONTRACT_VERSION, EXIT_CLEAN, EXIT_USAGE, FACTS_VERSION, SCHEMA_VERSIONS, } from "../contract/contract.generated.js";
|
|
2
2
|
import { CONFORMANCE } from "../conformance.js";
|
|
3
3
|
import {} from "./verb.js";
|
|
4
4
|
import { diagnose, LANGUAGE, PRODUCT } from "../product.js";
|
|
5
5
|
import { ownVersion } from "./version.js";
|
|
6
6
|
/**
|
|
7
7
|
* The document `describe` writes: the analyzer, the Contract version it implements, the
|
|
8
|
-
* report schema versions it reads, the languages it claims,
|
|
9
|
-
* the conformance corpus, a member the document omits where
|
|
8
|
+
* report schema versions it reads, the languages it claims, the facts version it writes,
|
|
9
|
+
* and its recorded result over the conformance corpus, a member the document omits where
|
|
10
|
+
* no run is recorded.
|
|
10
11
|
*/
|
|
11
12
|
export function describeDocument(version, recorded) {
|
|
12
13
|
const document = {
|
|
@@ -15,6 +16,7 @@ export function describeDocument(version, recorded) {
|
|
|
15
16
|
contract_version: CONTRACT_VERSION,
|
|
16
17
|
schema_versions_accepted: SCHEMA_VERSIONS,
|
|
17
18
|
languages: [LANGUAGE],
|
|
19
|
+
facts_version_written: FACTS_VERSION,
|
|
18
20
|
...(recorded === undefined
|
|
19
21
|
? {}
|
|
20
22
|
: {
|
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/deadset-ts",
|
|
3
|
-
"version": "8.0.0-dev.
|
|
3
|
+
"version": "8.0.0-dev.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Deterministic dead-code analysis for TypeScript, class and type members included",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"lint:fix": "eslint . --fix && prettier --write ."
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@typescript/native": "npm:typescript@7.1.0-dev.
|
|
35
|
+
"@typescript/native": "npm:typescript@7.1.0-dev.20261103.1"
|
|
36
36
|
},
|
|
37
37
|
"overrides": {
|
|
38
38
|
"qs": "^6.15.2"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@stryker-mutator/typescript-checker": "10.1.1",
|
|
44
44
|
"@stryker-mutator/vitest-runner": "10.1.1",
|
|
45
45
|
"@types/node": "24.19.2",
|
|
46
|
-
"eslint": "10.
|
|
46
|
+
"eslint": "10.14.0",
|
|
47
47
|
"fast-check": "4.10.2",
|
|
48
48
|
"prettier": "3.9.10",
|
|
49
49
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
package/src/alias-chain.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
isNamespaceImport,
|
|
15
15
|
} from "@typescript/native/ast";
|
|
16
16
|
import { SymbolFlags, type Symbol as TSSymbol } from "@typescript/native/sync";
|
|
17
|
-
import {
|
|
17
|
+
import { isParameterProperty, nodeKey, type Inventory } from "./inventory.ts";
|
|
18
18
|
import { UNANSWERED, type Answer } from "./query.ts";
|
|
19
19
|
import type { ProjectView } from "./session.ts";
|
|
20
20
|
|
|
@@ -132,7 +132,7 @@ export function aliasChains<Brand>(project: ProjectView<Brand>, held: Inventory)
|
|
|
132
132
|
names.add(node.expression.text);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
const byName =
|
|
135
|
+
const byName = held.byName;
|
|
136
136
|
const ids = [...names].flatMap((name) => byName.get(name) ?? []);
|
|
137
137
|
return [...new Set([...ids, ...(module ? files : [])])].map((id) => ({
|
|
138
138
|
id,
|