@cplieger/deadset-ts 8.0.0-dev.15 → 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/analysis.js +41 -37
- package/dist/src/commands/read.js +6 -7
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +3 -1
- package/dist/src/contract/config.generated.js +1 -1
- package/dist/src/contract/contract.generated.js +119 -2
- package/dist/src/dependencies.js +79 -48
- 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/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 -4
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/inventory/commonjs.js +62 -17
- package/dist/src/inventory/enumerate.js +2 -1
- 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 +15 -7
- 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/references.js +202 -32
- 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/source-files.js +5 -9
- 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 +2 -2
- package/src/analysis.ts +75 -52
- 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 +4 -0
- package/src/contract/config.generated.ts +1 -1
- package/src/contract/contract.generated.ts +138 -2
- package/src/dependencies.ts +96 -49
- 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 +1 -1
- 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 -5
- package/src/index.ts +1 -1
- package/src/injection-container.ts +1 -1
- package/src/inventory/commonjs.ts +102 -17
- package/src/inventory/enumerate.ts +2 -1
- 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 +27 -11
- 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/references.ts +281 -34
- 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/source-files.ts +5 -10
- 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 -444
- package/dist/src/own-body.js +0 -28
- package/dist/src/roots.js +0 -865
- package/dist/src/unseen-loads.js +0 -189
- package/src/build-scripts.ts +0 -536
- package/src/entry-points.ts +0 -584
- package/src/own-body.ts +0 -42
- package/src/unseen-loads.ts +0 -282
|
@@ -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/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();
|
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"
|
package/src/analysis.ts
CHANGED
|
@@ -14,17 +14,19 @@ import {
|
|
|
14
14
|
configuredDeclarations,
|
|
15
15
|
configuredRef,
|
|
16
16
|
declarationsNamed,
|
|
17
|
-
} from "./configured-declarations.ts";
|
|
17
|
+
} from "./roots/configured-declarations.ts";
|
|
18
18
|
import { decorator } from "./decorator.ts";
|
|
19
19
|
import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.ts";
|
|
20
20
|
import { deprecatedDeclarations, type Deprecation } from "./deprecation.ts";
|
|
21
21
|
import { moduleIdentity, type LoadedConsumer, type NotBuilt } from "./load/discover.ts";
|
|
22
22
|
import type { LibraryUnfound } from "./load/classify.ts";
|
|
23
23
|
import { loadRun, type LoadedRun } from "./load/load.ts";
|
|
24
|
-
import {
|
|
24
|
+
import type { AppliedConvention } from "./entries/conventions.ts";
|
|
25
|
+
import { readSources, type SourceFacts } from "./entries/sources.ts";
|
|
26
|
+
import { readWorkflows, type Workflows } from "./entries/workflow-steps.ts";
|
|
25
27
|
import { readEdgeSides } from "./edges.ts";
|
|
26
28
|
import { enumGroup } from "./enum-group.ts";
|
|
27
|
-
import { generatedFile, generatedFilesOf } from "./generated-file.ts";
|
|
29
|
+
import { generatedFile, generatedFilesOf, type GeneratedFact } from "./generated-file.ts";
|
|
28
30
|
import { inOperandNames } from "./in-operands.ts";
|
|
29
31
|
import { sourceFilesOf } from "./source-files.ts";
|
|
30
32
|
import {
|
|
@@ -53,7 +55,7 @@ import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfac
|
|
|
53
55
|
import { intraFunctionFacts, projectParts, type ProjectParts } from "./intra-function-parts.ts";
|
|
54
56
|
import { type Inventory, type InventorySymbol } from "./inventory.ts";
|
|
55
57
|
import { inventory } from "./inventory/enumerate.ts";
|
|
56
|
-
import { readManifest, type ManifestEntry } from "./manifest.ts";
|
|
58
|
+
import { readManifest, type ManifestEntry } from "./roots/manifest.ts";
|
|
57
59
|
import {
|
|
58
60
|
liveFilesAt,
|
|
59
61
|
matrixOf,
|
|
@@ -74,22 +76,20 @@ import {
|
|
|
74
76
|
import type { UnansweredQuestion } from "./query.ts";
|
|
75
77
|
import { byPosition, isComponentFile, type Position } from "./position.ts";
|
|
76
78
|
import type { TypeErrorSkip, UnansweredCount } from "./report.ts";
|
|
77
|
-
import {
|
|
79
|
+
import { skippedUnits, type SkippedUnit } from "./type-errors.ts";
|
|
78
80
|
import { reflectiveLookup } from "./reflective-lookup.ts";
|
|
79
81
|
import { references, testFileRulesOf, type Reference, type TestFileRule } from "./references.ts";
|
|
80
82
|
import {
|
|
81
|
-
|
|
83
|
+
rootSet,
|
|
82
84
|
unmatchedEverywhere,
|
|
83
|
-
type Root,
|
|
84
85
|
type RootKind,
|
|
85
86
|
type Roots,
|
|
86
87
|
type HeldScripts,
|
|
87
|
-
} from "./roots.ts";
|
|
88
|
+
} from "./roots/root-set.ts";
|
|
88
89
|
import type { Scope } from "./scope.ts";
|
|
89
90
|
import { decodedMembers, serializationContract, type Decoded } from "./serialization-contract.ts";
|
|
90
91
|
import { outsideTestReferences, testFilesAt, type OutsideTest } from "./outside-tests.ts";
|
|
91
|
-
import {
|
|
92
|
-
import { unseenLoadsOf, type UnseenLoad } from "./unseen-loads.ts";
|
|
92
|
+
import type { UnseenLoad } from "./roots/unseen-loads.ts";
|
|
93
93
|
import type { UnresolvedSpecifier } from "./load/specifiers.ts";
|
|
94
94
|
import type { UnreadInput } from "./load/plan.ts";
|
|
95
95
|
import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.ts";
|
|
@@ -103,6 +103,7 @@ import type { Exemption, Mode, SweepInput } from "./sweep.ts";
|
|
|
103
103
|
import { readTemplates, templateField } from "./template-field.ts";
|
|
104
104
|
import { bytewise } from "./text/compare.ts";
|
|
105
105
|
import { holdsManifest, manifestAt } from "./fs/manifest.ts";
|
|
106
|
+
import { runDirectories } from "./entries/run-directories.ts";
|
|
106
107
|
import { globExpression } from "./text/glob.ts";
|
|
107
108
|
|
|
108
109
|
/** The setting whose source decides where a finding about a configured root sits. */
|
|
@@ -176,10 +177,10 @@ interface ProjectRead {
|
|
|
176
177
|
readonly typeErrorSkips: readonly TypeErrorSkip[];
|
|
177
178
|
/** The lines each of those skips withholds every finding on. */
|
|
178
179
|
readonly skipped: readonly SkippedUnit[];
|
|
179
|
-
/** The project's generated files, by path below the target root, each with
|
|
180
|
-
readonly generated: ReadonlyMap<string,
|
|
181
|
-
/**
|
|
182
|
-
readonly
|
|
180
|
+
/** The project's generated files, by path below the target root, each with what decided it. */
|
|
181
|
+
readonly generated: ReadonlyMap<string, GeneratedFact>;
|
|
182
|
+
/** What the project's entry sources enter and name, read once. */
|
|
183
|
+
readonly sources: SourceFacts;
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
/** One target project the run analyzes, as its stage is handed it. */
|
|
@@ -196,6 +197,8 @@ interface ProjectsRead<Answer> {
|
|
|
196
197
|
readonly references: readonly Reference[];
|
|
197
198
|
/** The test files below the target root no project the run reads holds, parsed. */
|
|
198
199
|
readonly outsideTests: readonly OutsideTest[];
|
|
200
|
+
/** The target root's workflow steps, git hooks and makefile, read once for every project. */
|
|
201
|
+
readonly workflows: Workflows;
|
|
199
202
|
}
|
|
200
203
|
|
|
201
204
|
/**
|
|
@@ -216,14 +219,13 @@ function readProjects<Answer>(
|
|
|
216
219
|
const parse = (fileName: string, text: string) => engine.parseSourceFile(fileName, text);
|
|
217
220
|
return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
|
|
218
221
|
const { packages, conventions } = plan;
|
|
222
|
+
const workflows = readWorkflows(host, targetRoot);
|
|
219
223
|
const options = {
|
|
220
224
|
host,
|
|
221
225
|
manifest: packages.manifest,
|
|
222
226
|
otherPackages: packages.entries,
|
|
223
227
|
patterns: config.roots.patterns,
|
|
224
228
|
entryFiles: config.ts.entry_files,
|
|
225
|
-
conventions,
|
|
226
|
-
testFiles: config.ts.test_files,
|
|
227
229
|
parse,
|
|
228
230
|
publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
|
|
229
231
|
publishedMembers: packages.published,
|
|
@@ -233,19 +235,17 @@ function readProjects<Answer>(
|
|
|
233
235
|
const answers = classified.analyzed.map(({ plan: planned, project, skips, referenceOnly }) => {
|
|
234
236
|
const read = (): ProjectRead => {
|
|
235
237
|
const held = inventory(project, host, targetRoot);
|
|
236
|
-
const found = roots(project, held, targetRoot, options);
|
|
237
|
-
const kept = skippedRoots(project, held, skips);
|
|
238
|
-
const rooted =
|
|
239
|
-
kept.length === 0
|
|
240
|
-
? found
|
|
241
|
-
: {
|
|
242
|
-
...found,
|
|
243
|
-
liveUnderReachability: [
|
|
244
|
-
...found.liveUnderReachability,
|
|
245
|
-
...kept.map((id) => ({ id, kind: "type-error" as const, source: "" })),
|
|
246
|
-
],
|
|
247
|
-
};
|
|
248
238
|
const own = sourceFilesOf(project, targetRoot);
|
|
239
|
+
const sources = readSources({
|
|
240
|
+
host,
|
|
241
|
+
targetRoot,
|
|
242
|
+
files: own,
|
|
243
|
+
parse,
|
|
244
|
+
testFiles: config.ts.test_files,
|
|
245
|
+
conventions,
|
|
246
|
+
workflows,
|
|
247
|
+
});
|
|
248
|
+
const rooted = rootSet(project, held, targetRoot, { ...options, sources, skips });
|
|
249
249
|
return {
|
|
250
250
|
configuration: planned.id,
|
|
251
251
|
configFile: project.configFile,
|
|
@@ -257,8 +257,8 @@ function readProjects<Answer>(
|
|
|
257
257
|
.ownSourceFiles()
|
|
258
258
|
.filter((file) => referenceOnly(file.fileName))
|
|
259
259
|
.flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
|
|
260
|
-
generated: generatedFilesOf(own,
|
|
261
|
-
|
|
260
|
+
generated: generatedFilesOf(own, sources.generated),
|
|
261
|
+
sources,
|
|
262
262
|
};
|
|
263
263
|
};
|
|
264
264
|
for (const file of project.ownSourceFiles()) {
|
|
@@ -269,7 +269,7 @@ function readProjects<Answer>(
|
|
|
269
269
|
const consumed = new Map<string, Reference>();
|
|
270
270
|
for (const { project, consumer } of classified.consumed) {
|
|
271
271
|
const side = { id: consumer.id, root: consumer.path };
|
|
272
|
-
for (const reference of consumerReferences(project, host, targetRoot, side, config)) {
|
|
272
|
+
for (const reference of consumerReferences(project, host, targetRoot, side, config, parse)) {
|
|
273
273
|
consumed.set(referenceKey(reference), reference);
|
|
274
274
|
}
|
|
275
275
|
}
|
|
@@ -281,7 +281,7 @@ function readProjects<Answer>(
|
|
|
281
281
|
),
|
|
282
282
|
parse,
|
|
283
283
|
);
|
|
284
|
-
return { answers, references: [...consumed.values()], outsideTests };
|
|
284
|
+
return { answers, references: [...consumed.values()], outsideTests, workflows };
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
|
|
@@ -463,8 +463,6 @@ interface ReadProject<Extra> {
|
|
|
463
463
|
readonly componentWarnings: readonly ComponentWarning[];
|
|
464
464
|
/** Per own file below the target root, the module specifiers its imports write. */
|
|
465
465
|
readonly imports: ReadonlyMap<string, readonly string[]>;
|
|
466
|
-
/** The global augmentations a declaration outside the project names. */
|
|
467
|
-
readonly augmented: readonly Root[];
|
|
468
466
|
/** The data members its production code decodes into. */
|
|
469
467
|
readonly decoded: Decoded;
|
|
470
468
|
readonly extra: Extra;
|
|
@@ -499,6 +497,8 @@ interface ReadRun<Extra> {
|
|
|
499
497
|
readonly memberDirs: readonly string[];
|
|
500
498
|
/** The directory of every nested package, absolute. */
|
|
501
499
|
readonly nestedDirs: readonly string[];
|
|
500
|
+
/** The target root's workflow steps, git hooks and makefile, read once. */
|
|
501
|
+
readonly workflows: Workflows;
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
/** The manifest section of a package test evidence counts, and the sections that keep one out of it. */
|
|
@@ -564,6 +564,7 @@ function readRun<Extra>(
|
|
|
564
564
|
read: ProjectRead,
|
|
565
565
|
references: readonly Reference[],
|
|
566
566
|
testFiles: readonly string[],
|
|
567
|
+
unseenLoads: readonly UnseenLoad[],
|
|
567
568
|
) => Extra,
|
|
568
569
|
): ReadRun<Extra> {
|
|
569
570
|
const targetRoot = scope.target.path;
|
|
@@ -572,11 +573,15 @@ function readRun<Extra>(
|
|
|
572
573
|
? { delimiters: config.analysis.template_delimiters, files: [] }
|
|
573
574
|
: readTemplates(host, targetRoot, config.analysis);
|
|
574
575
|
const consumers = scope.consumers.map((consumer) => consumer.path);
|
|
576
|
+
const directories = runDirectories(host, targetRoot, (fileName, text) =>
|
|
577
|
+
engine.parseSourceFile(fileName, text),
|
|
578
|
+
);
|
|
575
579
|
const read = readProjects<ReadProject<Extra>>(engine, host, scope, config, (project, opened) => {
|
|
576
580
|
const projectRead = opened.read();
|
|
577
581
|
const resolved = references(project, projectRead.held, targetRoot, {
|
|
578
582
|
testFiles: config.ts.test_files,
|
|
579
|
-
testFileNames: projectRead.
|
|
583
|
+
testFileNames: projectRead.sources.testFiles,
|
|
584
|
+
directories,
|
|
580
585
|
});
|
|
581
586
|
const evidence = evidenceRecords(
|
|
582
587
|
{
|
|
@@ -605,11 +610,6 @@ function readRun<Extra>(
|
|
|
605
610
|
testFiles: resolved.testFilePaths,
|
|
606
611
|
evidence,
|
|
607
612
|
componentFiles: components.map(pathOf),
|
|
608
|
-
augmented: mergedGlobalInterfaces(
|
|
609
|
-
project,
|
|
610
|
-
projectRead.held,
|
|
611
|
-
sourceFilesOf(project, targetRoot),
|
|
612
|
-
).map((id): Root => ({ id, kind: "global-augmentation", source: "" })),
|
|
613
613
|
imports: new Map(
|
|
614
614
|
project.ownSourceFiles().flatMap((file) => {
|
|
615
615
|
const path = relativePath(targetRoot, file.fileName);
|
|
@@ -641,7 +641,16 @@ function readRun<Extra>(
|
|
|
641
641
|
productionFiles(project, targetRoot, resolved.testFilePaths),
|
|
642
642
|
consumers,
|
|
643
643
|
),
|
|
644
|
-
extra: extra(
|
|
644
|
+
extra: extra(
|
|
645
|
+
project,
|
|
646
|
+
projectRead,
|
|
647
|
+
resolved.references,
|
|
648
|
+
resolved.testFilePaths,
|
|
649
|
+
resolved.unseenLoads.map((position) => ({
|
|
650
|
+
configuration: projectRead.configuration,
|
|
651
|
+
position,
|
|
652
|
+
})),
|
|
653
|
+
),
|
|
645
654
|
};
|
|
646
655
|
});
|
|
647
656
|
const outsidePaths = read.result.outsideTests.map((one) => one.path);
|
|
@@ -658,7 +667,12 @@ function readRun<Extra>(
|
|
|
658
667
|
const { support, testUsed } = testSupportFiles(
|
|
659
668
|
withOutside.flatMap((one) => one.projectRead.held.symbols),
|
|
660
669
|
withOutside.flatMap((one) => one.references),
|
|
661
|
-
|
|
670
|
+
// An outside declaration naming a global augmentation calls nothing of its file.
|
|
671
|
+
withOutside.flatMap((one) =>
|
|
672
|
+
one.projectRead.rooted.liveUnderReachability.filter(
|
|
673
|
+
(root) => root.kind !== "global-augmentation",
|
|
674
|
+
),
|
|
675
|
+
),
|
|
662
676
|
withOutside.flatMap((one) => one.testFiles),
|
|
663
677
|
testEvidence(host, targetRoot, withOutside),
|
|
664
678
|
);
|
|
@@ -699,9 +713,7 @@ function readRun<Extra>(
|
|
|
699
713
|
configuration: projectRead.configuration,
|
|
700
714
|
symbols: projectRead.held.symbols,
|
|
701
715
|
references: [...made, ...evidenceReferences(projectRead.held.symbols, detected.inTestFiles)],
|
|
702
|
-
|
|
703
|
-
// naming one calls nothing of its file.
|
|
704
|
-
roots: [...projectRead.rooted.liveUnderReachability, ...one.augmented],
|
|
716
|
+
roots: projectRead.rooted.liveUnderReachability,
|
|
705
717
|
testFiles: [...one.testFiles, ...supportFiles],
|
|
706
718
|
...(supportFiles.length === 0 ? {} : { supportFiles }),
|
|
707
719
|
...(testUsedFiles.length === 0 ? {} : { testUsedFiles }),
|
|
@@ -769,6 +781,7 @@ function readRun<Extra>(
|
|
|
769
781
|
conventionUses: read.plan.conventions.uses,
|
|
770
782
|
memberDirs: read.plan.packages.members,
|
|
771
783
|
nestedDirs: read.plan.packages.nested,
|
|
784
|
+
workflows: read.result.workflows,
|
|
772
785
|
};
|
|
773
786
|
}
|
|
774
787
|
|
|
@@ -958,7 +971,7 @@ interface EmitterExtra {
|
|
|
958
971
|
readonly needs: ReturnType<typeof projectNeeds>;
|
|
959
972
|
readonly implementations: ReturnType<typeof implementations>;
|
|
960
973
|
readonly heldByInclusion: readonly string[];
|
|
961
|
-
readonly generated:
|
|
974
|
+
readonly generated: ReadonlyMap<string, GeneratedFact>;
|
|
962
975
|
readonly inOperands: readonly string[];
|
|
963
976
|
readonly rooted: Roots;
|
|
964
977
|
readonly directives: readonly InlineDirective[];
|
|
@@ -996,15 +1009,21 @@ export function readEmitterRun(
|
|
|
996
1009
|
config,
|
|
997
1010
|
mode,
|
|
998
1011
|
detectors,
|
|
999
|
-
(project, read, references, testFiles) => ({
|
|
1012
|
+
(project, read, references, testFiles, unseenLoads) => ({
|
|
1000
1013
|
deprecation: deprecatedDeclarations(project, read.held),
|
|
1001
1014
|
accessors: accessorsOf(project, read.held),
|
|
1002
|
-
needs: projectNeeds(
|
|
1003
|
-
|
|
1015
|
+
needs: projectNeeds(
|
|
1016
|
+
project,
|
|
1017
|
+
read.held,
|
|
1018
|
+
host,
|
|
1019
|
+
targetRoot,
|
|
1020
|
+
(fileName, text) => engine.parseSourceFile(fileName, text),
|
|
1021
|
+
read.sources.configuration,
|
|
1022
|
+
read.sources.workflows,
|
|
1004
1023
|
),
|
|
1005
1024
|
implementations: implementations(project, read.held),
|
|
1006
1025
|
heldByInclusion: heldByInclusion(project, targetRoot),
|
|
1007
|
-
generated:
|
|
1026
|
+
generated: read.generated,
|
|
1008
1027
|
inOperands: inOperandNames(project, targetRoot, testFiles),
|
|
1009
1028
|
rooted: read.rooted,
|
|
1010
1029
|
directives: inlineDirectives(project, read.held, targetRoot).filter(
|
|
@@ -1012,7 +1031,7 @@ export function readEmitterRun(
|
|
|
1012
1031
|
),
|
|
1013
1032
|
declarationsNamed: declarationsNamed(project, read.held, configuredDeclarations(config)),
|
|
1014
1033
|
parts: projectParts(project, read.held, references, targetRoot),
|
|
1015
|
-
unseenLoads
|
|
1034
|
+
unseenLoads,
|
|
1016
1035
|
}),
|
|
1017
1036
|
);
|
|
1018
1037
|
// Whether a declaration carries the marker decides its code, so one whose answer went
|
|
@@ -1101,6 +1120,7 @@ export function emitterInputOver(
|
|
|
1101
1120
|
dependencies: dependenciesOf(
|
|
1102
1121
|
host,
|
|
1103
1122
|
targetRoot,
|
|
1123
|
+
read.workflows,
|
|
1104
1124
|
[...projects.map((one) => one.extra.needs), configurationNeeds(read.conventionUses)],
|
|
1105
1125
|
swept.sweep.candidates.map((candidate) => candidate.id),
|
|
1106
1126
|
members.read,
|
|
@@ -1111,7 +1131,7 @@ export function emitterInputOver(
|
|
|
1111
1131
|
files: {
|
|
1112
1132
|
tree: sourceTree(host, targetRoot),
|
|
1113
1133
|
heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
|
|
1114
|
-
generated: new Set(projects.flatMap((one) => one.extra.generated)),
|
|
1134
|
+
generated: new Set(projects.flatMap((one) => [...one.extra.generated.keys()])),
|
|
1115
1135
|
inOperands: new Set(projects.flatMap((one) => one.extra.inOperands)),
|
|
1116
1136
|
unseenLoads: projects.flatMap((one) => one.extra.unseenLoads),
|
|
1117
1137
|
},
|
|
@@ -1211,6 +1231,7 @@ function readAnalysis(
|
|
|
1211
1231
|
one.heldScripts.map((held) => ({ ...held, configFile: one.configFile })),
|
|
1212
1232
|
),
|
|
1213
1233
|
unseenLoads: read.projects.flatMap((one) => one.extra.unseenLoads),
|
|
1234
|
+
generated: new Map(read.projects.flatMap((one) => [...one.extra.generated])),
|
|
1214
1235
|
},
|
|
1215
1236
|
configured: read.projects.map((one) => one.configured),
|
|
1216
1237
|
symbols,
|
|
@@ -1317,6 +1338,8 @@ interface RunFacts {
|
|
|
1317
1338
|
readonly heldScripts: readonly (HeldScripts & { readonly configFile: string })[];
|
|
1318
1339
|
/** The loads of production files whose target the run cannot resolve, per configuration. */
|
|
1319
1340
|
readonly unseenLoads: readonly UnseenLoad[];
|
|
1341
|
+
/** Every generated file of the run, by its path below the target root, each once. */
|
|
1342
|
+
readonly generated: ReadonlyMap<string, GeneratedFact>;
|
|
1320
1343
|
}
|
|
1321
1344
|
|
|
1322
1345
|
/** One configuration whose component files a run cannot read. */
|
package/src/automatic-types.ts
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
type SourceFile,
|
|
26
26
|
type Statement,
|
|
27
27
|
} from "@typescript/native/ast";
|
|
28
|
-
import type { ParseFile } from "./configuration-files.ts";
|
|
28
|
+
import type { ParseFile } from "./entries/configuration-files.ts";
|
|
29
29
|
import type { Host } from "./host.ts";
|
|
30
30
|
import { ancestors, dirnamePath, joinPath, resolvePath } from "./paths.ts";
|
|
31
31
|
import { entriesOf } from "./fs/tree.ts";
|