@cplieger/deadset-ts 3.5.0 → 3.7.0
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 +70 -14
- package/dist/src/components.js +5 -1
- package/dist/src/dependencies.js +493 -0
- package/dist/src/deprecation.js +83 -0
- package/dist/src/discover.js +1 -1
- package/dist/src/enum-group.js +217 -0
- package/dist/src/file-facts.js +101 -0
- package/dist/src/finding.js +0 -11
- package/dist/src/findings/boundary.js +1 -0
- package/dist/src/findings/completion.js +135 -0
- package/dist/src/findings/dependencies-and-module-machinery.js +57 -1
- package/dist/src/findings/emitters.js +10 -0
- package/dist/src/findings/interfaces.js +95 -2
- package/dist/src/findings/non-code-artifacts.js +97 -1
- package/dist/src/findings/reads-and-writes.js +146 -2
- package/dist/src/findings/unused-declarations.js +150 -1
- package/dist/src/findings/visibility-narrowing.js +239 -2
- package/dist/src/implementations.js +210 -0
- package/dist/src/inventory.js +2 -2
- package/dist/src/kinds.js +47 -45
- package/dist/src/resolve.js +1 -1
- package/dist/src/stores.js +32 -0
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +113 -16
- package/src/components.ts +6 -1
- package/src/dependencies.ts +617 -0
- package/src/deprecation.ts +101 -0
- package/src/discover.ts +1 -1
- package/src/enum-group.ts +265 -0
- package/src/file-facts.ts +143 -0
- package/src/finding.ts +76 -10
- package/src/findings/boundary.ts +39 -0
- package/src/findings/completion.ts +163 -0
- package/src/findings/dependencies-and-module-machinery.ts +64 -1
- package/src/findings/emitter.ts +24 -3
- package/src/findings/emitters.ts +13 -1
- package/src/findings/interfaces.ts +137 -3
- package/src/findings/non-code-artifacts.ts +124 -2
- package/src/findings/reads-and-writes.ts +196 -3
- package/src/findings/unused-declarations.ts +175 -1
- package/src/findings/visibility-narrowing.ts +319 -3
- package/src/implementations.ts +286 -0
- package/src/inventory.ts +2 -2
- package/src/kinds.ts +79 -45
- package/src/resolve.ts +1 -1
- package/src/stores.ts +77 -0
package/src/analysis.ts
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
import type { Diagnostic } from "@typescript/native/unstable/sync";
|
|
12
12
|
import type { Config, Provenance } from "./config.ts";
|
|
13
13
|
import { decorator } from "./decorator.ts";
|
|
14
|
+
import { dependenciesOf, projectNeeds } from "./dependencies.ts";
|
|
15
|
+
import { deprecatedDeclarations } from "./deprecation.ts";
|
|
14
16
|
import { diagnosticErrors, discoverProjects, DiscoveryError } from "./discover.ts";
|
|
17
|
+
import { enumGroup } from "./enum-group.ts";
|
|
15
18
|
import {
|
|
16
19
|
computeExemptions,
|
|
17
20
|
disabledClasses,
|
|
@@ -21,9 +24,12 @@ import {
|
|
|
21
24
|
type Detectors,
|
|
22
25
|
} from "./exempt.ts";
|
|
23
26
|
import type { TSExemptionClass } from "./exempt-classes.ts";
|
|
27
|
+
import { heldByInclusion, sourceTree } from "./file-facts.ts";
|
|
24
28
|
import type { Finding } from "./finding.ts";
|
|
29
|
+
import type { EmitterInput } from "./findings/emitter.ts";
|
|
25
30
|
import { frameworkLifecycle } from "./framework-lifecycle.ts";
|
|
26
31
|
import type { Host } from "./host.ts";
|
|
32
|
+
import { implementations, mergeImplementations } from "./implementations.ts";
|
|
27
33
|
import { injectionContainer } from "./injection-container.ts";
|
|
28
34
|
import { interfaceSatisfaction } from "./interface-satisfaction.ts";
|
|
29
35
|
import { inventory, type Inventory } from "./inventory.ts";
|
|
@@ -37,6 +43,7 @@ import { roots, unmatchedEverywhere, unmatchedRoots, type RootKind, type Roots }
|
|
|
37
43
|
import type { Scope } from "./scope.ts";
|
|
38
44
|
import { serializationContract } from "./serialization-contract.ts";
|
|
39
45
|
import { diagnosticsOf, runSession, type Engine, type ProjectView } from "./session.ts";
|
|
46
|
+
import { accessorsOf, storesOf } from "./stores.ts";
|
|
40
47
|
import type { Exemption, SweepInput } from "./sweep.ts";
|
|
41
48
|
import { readTemplates, templateField } from "./template-field.ts";
|
|
42
49
|
|
|
@@ -222,6 +229,7 @@ export interface RunSweep {
|
|
|
222
229
|
/** The exemption classes this analyzer detects, each by its detector; any other retains nothing. */
|
|
223
230
|
const DETECTORS: Detectors = new Map<TSExemptionClass, Detector>([
|
|
224
231
|
["interface-satisfaction", interfaceSatisfaction],
|
|
232
|
+
["enum-group", enumGroup],
|
|
225
233
|
["template-field", templateField],
|
|
226
234
|
["reflective-lookup", reflectiveLookup],
|
|
227
235
|
["decorator", decorator],
|
|
@@ -230,31 +238,40 @@ const DETECTORS: Detectors = new Map<TSExemptionClass, Detector>([
|
|
|
230
238
|
["serialization-contract", serializationContract],
|
|
231
239
|
]);
|
|
232
240
|
|
|
241
|
+
/** What the sweep of one run reads of each project, beside what a caller's stage adds. */
|
|
242
|
+
interface SweptProject<Extra> {
|
|
243
|
+
readonly configured: Configured;
|
|
244
|
+
readonly exempt: readonly Exemption[];
|
|
245
|
+
readonly extra: Extra;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** The run's sweep, the exemption records it was swept with, and each project's extra answer. */
|
|
249
|
+
interface SweptRun<Extra> {
|
|
250
|
+
readonly swept: RunSweep;
|
|
251
|
+
readonly exempt: readonly Exemption[];
|
|
252
|
+
readonly projects: readonly SweptProject<Extra>[];
|
|
253
|
+
}
|
|
254
|
+
|
|
233
255
|
/**
|
|
234
|
-
* Sweeps the run
|
|
235
|
-
*
|
|
236
|
-
* projects then merge into one matrix in the run's order, which is swept under the
|
|
237
|
-
* caller's marks and mode with the exemptions every project found. A record found in
|
|
238
|
-
* one configuration holds in every configuration that holds its declaration, because
|
|
239
|
-
* an exemption is evidence of a use the analysis cannot see and a use in one
|
|
240
|
-
* configuration is a use. A project that carries an error ends the run before any
|
|
241
|
-
* project is swept.
|
|
256
|
+
* Sweeps the run, reading each project's references and exemptions, and `extra`'s
|
|
257
|
+
* answer, while the project's view is open.
|
|
242
258
|
*/
|
|
243
|
-
|
|
259
|
+
function sweepRun<Extra>(
|
|
244
260
|
engine: Engine,
|
|
245
261
|
host: Host,
|
|
246
262
|
scope: Scope,
|
|
247
263
|
config: Config,
|
|
248
264
|
input: Pick<SweepInput, "marked" | "mode">,
|
|
249
|
-
detectors: Detectors
|
|
250
|
-
|
|
265
|
+
detectors: Detectors,
|
|
266
|
+
extra: <Brand>(project: ProjectView<Brand>, read: ProjectRead) => Extra,
|
|
267
|
+
): SweptRun<Extra> {
|
|
251
268
|
const targetRoot = scope.target.path;
|
|
252
269
|
const disabled = disabledClasses(config);
|
|
253
270
|
const templates = disabled.has("template-field")
|
|
254
271
|
? { delimiters: config.analysis.templateDelimiters, files: [] }
|
|
255
272
|
: readTemplates(host, targetRoot, config.analysis);
|
|
256
273
|
const consumers = scope.consumers.map((consumer) => consumer.path);
|
|
257
|
-
const
|
|
274
|
+
const projects = readProjects(engine, host, scope, config, (project, projectRead) => {
|
|
258
275
|
const resolved = references(project, projectRead.held, targetRoot, {
|
|
259
276
|
testFiles: config.ts.testFiles,
|
|
260
277
|
});
|
|
@@ -274,9 +291,89 @@ export function runSweep(
|
|
|
274
291
|
testFiles: new Set(resolved.testFilePaths),
|
|
275
292
|
},
|
|
276
293
|
);
|
|
277
|
-
return { configured, exempt };
|
|
294
|
+
return { configured, exempt, extra: extra(project, projectRead) };
|
|
278
295
|
});
|
|
279
|
-
const matrix = matrixOf(
|
|
280
|
-
const
|
|
281
|
-
|
|
296
|
+
const matrix = matrixOf(projects.map((one) => one.configured));
|
|
297
|
+
const exempt = exemptionsOf(projects.flatMap((one) => one.exempt));
|
|
298
|
+
const swept: SweepInput = { ...input, exempt };
|
|
299
|
+
return {
|
|
300
|
+
swept: { matrix, sweep: sweepMatrix(matrix, swept), retained: retainedIn(matrix, swept) },
|
|
301
|
+
exempt,
|
|
302
|
+
projects,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Sweeps the run the scope and the configuration describe. Each project's references
|
|
308
|
+
* and exemptions are read against its own inventory while its view is open; the
|
|
309
|
+
* projects then merge into one matrix in the run's order, which is swept under the
|
|
310
|
+
* caller's marks and mode with the exemptions every project found. A record found in
|
|
311
|
+
* one configuration holds in every configuration that holds its declaration, because
|
|
312
|
+
* an exemption is evidence of a use the analysis cannot see and a use in one
|
|
313
|
+
* configuration is a use. A project that carries an error ends the run before any
|
|
314
|
+
* project is swept.
|
|
315
|
+
*/
|
|
316
|
+
export function runSweep(
|
|
317
|
+
engine: Engine,
|
|
318
|
+
host: Host,
|
|
319
|
+
scope: Scope,
|
|
320
|
+
config: Config,
|
|
321
|
+
input: Pick<SweepInput, "marked" | "mode">,
|
|
322
|
+
detectors: Detectors = DETECTORS,
|
|
323
|
+
): RunSweep {
|
|
324
|
+
return sweepRun(engine, host, scope, config, input, detectors, () => undefined).swept;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* What every emitter reads of the run the scope and the configuration describe: the
|
|
329
|
+
* run's sweep, and the facts beside it each kind family reads, every per-project one
|
|
330
|
+
* read in the same session as the sweep. The run loads no consumer and reads no
|
|
331
|
+
* declared cross-language edge, so its boundary names neither.
|
|
332
|
+
*/
|
|
333
|
+
export function runEmitterInput(
|
|
334
|
+
engine: Engine,
|
|
335
|
+
host: Host,
|
|
336
|
+
scope: Scope,
|
|
337
|
+
config: Config,
|
|
338
|
+
input: Pick<SweepInput, "marked" | "mode">,
|
|
339
|
+
detectors: Detectors = DETECTORS,
|
|
340
|
+
): EmitterInput {
|
|
341
|
+
const targetRoot = scope.target.path;
|
|
342
|
+
const run = sweepRun(engine, host, scope, config, input, detectors, (project, read) => ({
|
|
343
|
+
deprecated: deprecatedDeclarations(project, read.held),
|
|
344
|
+
accessors: accessorsOf(project, read.held),
|
|
345
|
+
needs: projectNeeds(project, read.held, host),
|
|
346
|
+
implementations: implementations(project, read.held),
|
|
347
|
+
heldByInclusion: heldByInclusion(project, targetRoot),
|
|
348
|
+
}));
|
|
349
|
+
const { swept, projects } = run;
|
|
350
|
+
return {
|
|
351
|
+
config,
|
|
352
|
+
swept,
|
|
353
|
+
deprecated: new Set(projects.flatMap((one) => one.extra.deprecated)),
|
|
354
|
+
stores: storesOf(
|
|
355
|
+
projects.map((one) => ({
|
|
356
|
+
references: one.configured.references,
|
|
357
|
+
accessors: one.extra.accessors,
|
|
358
|
+
})),
|
|
359
|
+
run.exempt,
|
|
360
|
+
input.mode,
|
|
361
|
+
),
|
|
362
|
+
dependencies: dependenciesOf(
|
|
363
|
+
host,
|
|
364
|
+
targetRoot,
|
|
365
|
+
projects.map((one) => one.extra.needs),
|
|
366
|
+
swept.sweep.candidates.map((candidate) => candidate.id),
|
|
367
|
+
),
|
|
368
|
+
implementations: mergeImplementations(projects.map((one) => one.extra.implementations)),
|
|
369
|
+
files: {
|
|
370
|
+
tree: sourceTree(host, targetRoot),
|
|
371
|
+
heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
|
|
372
|
+
},
|
|
373
|
+
boundary: {
|
|
374
|
+
consumers: { declared: scope.consumers.map((consumer) => consumer.id), loaded: [] },
|
|
375
|
+
encapsulated: readManifest(host, targetRoot).declaresExports,
|
|
376
|
+
edges: [],
|
|
377
|
+
},
|
|
378
|
+
};
|
|
282
379
|
}
|
package/src/components.ts
CHANGED
|
@@ -14,6 +14,11 @@ const ANALYZER = "deadset-ts";
|
|
|
14
14
|
/** The fewest digits a component identifier's number is written with. */
|
|
15
15
|
const ID_DIGITS = 4;
|
|
16
16
|
|
|
17
|
+
/** The identifier of the component at one place of the run's order, counted from one. */
|
|
18
|
+
export function componentId(place: number): string {
|
|
19
|
+
return `${ANALYZER}/c-${String(place).padStart(ID_DIGITS, "0")}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
17
22
|
/** The index of a declaration the component walk has not reached. */
|
|
18
23
|
const UNVISITED = -1;
|
|
19
24
|
|
|
@@ -84,7 +89,7 @@ export function componentsOf(
|
|
|
84
89
|
return referenced[componentOf[position] ?? 0] !== true && dead[container] !== true;
|
|
85
90
|
});
|
|
86
91
|
return {
|
|
87
|
-
id:
|
|
92
|
+
id: componentId(place + 1),
|
|
88
93
|
members: group.map(idOf),
|
|
89
94
|
roots: roots.map(idOf),
|
|
90
95
|
deletableLines: linesSpanned(group.map((position) => graph.symbols[at[position] ?? 0])),
|