@cplieger/deadset-ts 5.2.1 → 5.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/convention-rows.js +20 -0
- package/dist/src/conventions.js +8 -1
- package/dist/src/inventory.js +13 -1
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/convention-rows.ts +21 -0
- package/src/conventions.ts +11 -1
- package/src/inventory.ts +18 -1
- package/src/workspace-run.ts +3 -4
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
deadset-ts finds dead code in TypeScript projects, down to class members, type members and dead stores inside functions, and writes a report your CI can fail on.
|
|
6
6
|
|
|
7
|
-
It reads your `tsconfig.json` projects, `allowJs` JavaScript and Vue, Svelte and Astro scripts included, with the type information of TypeScript 7.1.0-dev.
|
|
7
|
+
It reads your `tsconfig.json` projects, `allowJs` JavaScript and Vue, Svelte and Astro scripts included, with the type information of TypeScript 7.1.0-dev.20261006.1, its one dependency. Your project keeps its own TypeScript version. A type error under that version skips the function or statement that holds it. deadset-ts reports and never edits your code. It is pre-release, tested only on Linux, needs Node.js 24 or later and is licensed under GPL-3.0-or-later.
|
|
8
8
|
|
|
9
9
|
## Why use it
|
|
10
10
|
|
|
@@ -31,6 +31,7 @@ const APP_DIRECTORY_ENTRIES = [
|
|
|
31
31
|
];
|
|
32
32
|
const SOLIDSTART_PLUGIN = { module: "@solidjs/start/config", export: "solidStart" };
|
|
33
33
|
const NUXT_CONFIG = [`nuxt.config.${ANY_MODULE}`];
|
|
34
|
+
const STRYKER_CONFIG = "{stryker,.stryker}.{conf,config}.{json,js,mjs,cjs}";
|
|
34
35
|
/** Every row, ordered by name and then by range. */
|
|
35
36
|
export const CONVENTION_ROWS = [
|
|
36
37
|
{
|
|
@@ -258,6 +259,25 @@ export const CONVENTION_ROWS = [
|
|
|
258
259
|
],
|
|
259
260
|
moves: [],
|
|
260
261
|
},
|
|
262
|
+
{
|
|
263
|
+
name: "stryker",
|
|
264
|
+
package: "@stryker-mutator/core",
|
|
265
|
+
range: ">=7.0.0 <11.0.0",
|
|
266
|
+
entries: [],
|
|
267
|
+
moves: [],
|
|
268
|
+
shortNames: [
|
|
269
|
+
{
|
|
270
|
+
property: "testRunner",
|
|
271
|
+
files: [STRYKER_CONFIG],
|
|
272
|
+
package: "@stryker-mutator/{}-runner",
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
property: "checkers",
|
|
276
|
+
files: [STRYKER_CONFIG],
|
|
277
|
+
package: "@stryker-mutator/{}-checker",
|
|
278
|
+
},
|
|
279
|
+
],
|
|
280
|
+
},
|
|
261
281
|
{
|
|
262
282
|
name: "sveltekit",
|
|
263
283
|
package: "@sveltejs/kit",
|
package/dist/src/conventions.js
CHANGED
|
@@ -11,6 +11,7 @@ import { CONVENTION_ROWS, } from "./convention-rows.js";
|
|
|
11
11
|
import { globExpression } from "./glob.js";
|
|
12
12
|
import { dirnamePath, joinPath, normalizePath, relativePath, resolvePath } from "./paths.js";
|
|
13
13
|
import { satisfies } from "./version-range.js";
|
|
14
|
+
const JSON_EXTENSION = ".json";
|
|
14
15
|
/** The sections an installed package is required by, so its absence fails the run. */
|
|
15
16
|
const REQUIRED_SECTIONS = ["dependencies", "devDependencies"];
|
|
16
17
|
const DEPENDENCY_SECTIONS = [
|
|
@@ -114,8 +115,14 @@ function isModuleExports(node) {
|
|
|
114
115
|
node.expression.text === "module" &&
|
|
115
116
|
node.name.text === "exports");
|
|
116
117
|
}
|
|
117
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* Every expression or declaration one file exports as its default, in any module syntax.
|
|
120
|
+
* A JSON module's default export is its document's value.
|
|
121
|
+
*/
|
|
118
122
|
function defaultExports(file) {
|
|
123
|
+
if (file.fileName.endsWith(JSON_EXTENSION)) {
|
|
124
|
+
return file.statements.flatMap((statement) => isExpressionStatement(statement) ? [statement.expression] : []);
|
|
125
|
+
}
|
|
119
126
|
const found = [];
|
|
120
127
|
for (const statement of file.statements) {
|
|
121
128
|
if (isExportAssignment(statement)) {
|
package/dist/src/inventory.js
CHANGED
|
@@ -215,6 +215,12 @@ function nameNodeOf(node) {
|
|
|
215
215
|
export function nodeKey(file, node) {
|
|
216
216
|
return `${file.fileName}:${String(node.pos)}:${String(node.end)}:${String(node.kind)}`;
|
|
217
217
|
}
|
|
218
|
+
/** Whether `node` is written inside `declaration`, compared by file and range. */
|
|
219
|
+
function writtenInside(declaration, node) {
|
|
220
|
+
return (node.getSourceFile().fileName === declaration.getSourceFile().fileName &&
|
|
221
|
+
declaration.pos <= node.pos &&
|
|
222
|
+
node.end <= declaration.end);
|
|
223
|
+
}
|
|
218
224
|
/** `export default`, up to the keyword that stands where an unnamed default export's name would. */
|
|
219
225
|
const DEFAULT_EXPORT = /^export\s+(?=default\b)/u;
|
|
220
226
|
/**
|
|
@@ -360,6 +366,7 @@ export function inventory(project, host, targetRoot) {
|
|
|
360
366
|
});
|
|
361
367
|
containers.push({
|
|
362
368
|
owner: record,
|
|
369
|
+
declaration: node,
|
|
363
370
|
nameNode: node.name,
|
|
364
371
|
members: node.members,
|
|
365
372
|
memberKind: "class-member",
|
|
@@ -379,6 +386,7 @@ export function inventory(project, host, targetRoot) {
|
|
|
379
386
|
});
|
|
380
387
|
containers.push({
|
|
381
388
|
owner: record,
|
|
389
|
+
declaration: node,
|
|
382
390
|
nameNode: node.name,
|
|
383
391
|
members: node.members,
|
|
384
392
|
memberKind: "interface-method",
|
|
@@ -402,6 +410,7 @@ export function inventory(project, host, targetRoot) {
|
|
|
402
410
|
if (members.length > 0) {
|
|
403
411
|
containers.push({
|
|
404
412
|
owner: record,
|
|
413
|
+
declaration: node,
|
|
405
414
|
nameNode: undefined,
|
|
406
415
|
members,
|
|
407
416
|
memberKind: "type-member",
|
|
@@ -422,6 +431,7 @@ export function inventory(project, host, targetRoot) {
|
|
|
422
431
|
});
|
|
423
432
|
containers.push({
|
|
424
433
|
owner: record,
|
|
434
|
+
declaration: node,
|
|
425
435
|
nameNode: node.name,
|
|
426
436
|
members: node.members,
|
|
427
437
|
memberKind: "enum-member",
|
|
@@ -604,7 +614,9 @@ export function inventory(project, host, targetRoot) {
|
|
|
604
614
|
outside += declarations.length;
|
|
605
615
|
continue;
|
|
606
616
|
}
|
|
607
|
-
|
|
617
|
+
// A merged symbol's table holds the members every one of its declarations writes,
|
|
618
|
+
// and each member is kept once, by the declaration that writes it.
|
|
619
|
+
for (const held of own.filter((one) => writtenInside(container.declaration, one.node))) {
|
|
608
620
|
keepMember(container, held.node, seen, areStatic);
|
|
609
621
|
}
|
|
610
622
|
}
|
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/deadset-ts",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Deterministic dead-code analysis for TypeScript, class and type members included",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"lint:fix": "eslint . --fix && prettier --write ."
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@typescript/native": "npm:typescript@7.1.0-dev.
|
|
32
|
+
"@typescript/native": "npm:typescript@7.1.0-dev.20261006.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@eslint/js": "10.0.1",
|
package/src/convention-rows.ts
CHANGED
|
@@ -98,6 +98,8 @@ const SOLIDSTART_PLUGIN = { module: "@solidjs/start/config", export: "solidStart
|
|
|
98
98
|
|
|
99
99
|
const NUXT_CONFIG = [`nuxt.config.${ANY_MODULE}`];
|
|
100
100
|
|
|
101
|
+
const STRYKER_CONFIG = "{stryker,.stryker}.{conf,config}.{json,js,mjs,cjs}";
|
|
102
|
+
|
|
101
103
|
/** Every row, ordered by name and then by range. */
|
|
102
104
|
export const CONVENTION_ROWS: readonly ConventionRow[] = [
|
|
103
105
|
{
|
|
@@ -325,6 +327,25 @@ export const CONVENTION_ROWS: readonly ConventionRow[] = [
|
|
|
325
327
|
],
|
|
326
328
|
moves: [],
|
|
327
329
|
},
|
|
330
|
+
{
|
|
331
|
+
name: "stryker",
|
|
332
|
+
package: "@stryker-mutator/core",
|
|
333
|
+
range: ">=7.0.0 <11.0.0",
|
|
334
|
+
entries: [],
|
|
335
|
+
moves: [],
|
|
336
|
+
shortNames: [
|
|
337
|
+
{
|
|
338
|
+
property: "testRunner",
|
|
339
|
+
files: [STRYKER_CONFIG],
|
|
340
|
+
package: "@stryker-mutator/{}-runner",
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
property: "checkers",
|
|
344
|
+
files: [STRYKER_CONFIG],
|
|
345
|
+
package: "@stryker-mutator/{}-checker",
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
},
|
|
328
349
|
{
|
|
329
350
|
name: "sveltekit",
|
|
330
351
|
package: "@sveltejs/kit",
|
package/src/conventions.ts
CHANGED
|
@@ -122,6 +122,8 @@ interface ConventionEntry {
|
|
|
122
122
|
/** Parses one file's text with no program. */
|
|
123
123
|
type ParseSource = (fileName: string, text: string) => SourceFile;
|
|
124
124
|
|
|
125
|
+
const JSON_EXTENSION = ".json";
|
|
126
|
+
|
|
125
127
|
/** The sections an installed package is required by, so its absence fails the run. */
|
|
126
128
|
const REQUIRED_SECTIONS = ["dependencies", "devDependencies"] as const;
|
|
127
129
|
|
|
@@ -248,8 +250,16 @@ function isModuleExports(node: Node): boolean {
|
|
|
248
250
|
);
|
|
249
251
|
}
|
|
250
252
|
|
|
251
|
-
/**
|
|
253
|
+
/**
|
|
254
|
+
* Every expression or declaration one file exports as its default, in any module syntax.
|
|
255
|
+
* A JSON module's default export is its document's value.
|
|
256
|
+
*/
|
|
252
257
|
function defaultExports(file: SourceFile): readonly Node[] {
|
|
258
|
+
if (file.fileName.endsWith(JSON_EXTENSION)) {
|
|
259
|
+
return file.statements.flatMap((statement) =>
|
|
260
|
+
isExpressionStatement(statement) ? [statement.expression] : [],
|
|
261
|
+
);
|
|
262
|
+
}
|
|
253
263
|
const found: Node[] = [];
|
|
254
264
|
for (const statement of file.statements) {
|
|
255
265
|
if (isExportAssignment(statement)) {
|
package/src/inventory.ts
CHANGED
|
@@ -208,6 +208,8 @@ interface Building {
|
|
|
208
208
|
/** A container whose members are read from a symbol table, from the tree, or both. */
|
|
209
209
|
interface Container {
|
|
210
210
|
readonly owner: Building;
|
|
211
|
+
/** The declaration that writes the container, which owns the members written inside it. */
|
|
212
|
+
readonly declaration: Node;
|
|
211
213
|
/** The container's name node, which is what a batch resolves to its symbol. */
|
|
212
214
|
readonly nameNode: Node | undefined;
|
|
213
215
|
readonly members: readonly Node[];
|
|
@@ -473,6 +475,15 @@ export function nodeKey(file: SourceFile, node: Node): string {
|
|
|
473
475
|
return `${file.fileName}:${String(node.pos)}:${String(node.end)}:${String(node.kind)}`;
|
|
474
476
|
}
|
|
475
477
|
|
|
478
|
+
/** Whether `node` is written inside `declaration`, compared by file and range. */
|
|
479
|
+
function writtenInside(declaration: Node, node: Node): boolean {
|
|
480
|
+
return (
|
|
481
|
+
node.getSourceFile().fileName === declaration.getSourceFile().fileName &&
|
|
482
|
+
declaration.pos <= node.pos &&
|
|
483
|
+
node.end <= declaration.end
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
|
|
476
487
|
/** `export default`, up to the keyword that stands where an unnamed default export's name would. */
|
|
477
488
|
const DEFAULT_EXPORT = /^export\s+(?=default\b)/u;
|
|
478
489
|
|
|
@@ -642,6 +653,7 @@ export function inventory<Brand>(
|
|
|
642
653
|
});
|
|
643
654
|
containers.push({
|
|
644
655
|
owner: record,
|
|
656
|
+
declaration: node,
|
|
645
657
|
nameNode: node.name,
|
|
646
658
|
members: node.members,
|
|
647
659
|
memberKind: "class-member",
|
|
@@ -661,6 +673,7 @@ export function inventory<Brand>(
|
|
|
661
673
|
});
|
|
662
674
|
containers.push({
|
|
663
675
|
owner: record,
|
|
676
|
+
declaration: node,
|
|
664
677
|
nameNode: node.name,
|
|
665
678
|
members: node.members,
|
|
666
679
|
memberKind: "interface-method",
|
|
@@ -684,6 +697,7 @@ export function inventory<Brand>(
|
|
|
684
697
|
if (members.length > 0) {
|
|
685
698
|
containers.push({
|
|
686
699
|
owner: record,
|
|
700
|
+
declaration: node,
|
|
687
701
|
nameNode: undefined,
|
|
688
702
|
members,
|
|
689
703
|
memberKind: "type-member",
|
|
@@ -704,6 +718,7 @@ export function inventory<Brand>(
|
|
|
704
718
|
});
|
|
705
719
|
containers.push({
|
|
706
720
|
owner: record,
|
|
721
|
+
declaration: node,
|
|
707
722
|
nameNode: node.name,
|
|
708
723
|
members: node.members,
|
|
709
724
|
memberKind: "enum-member",
|
|
@@ -897,7 +912,9 @@ export function inventory<Brand>(
|
|
|
897
912
|
outside += declarations.length;
|
|
898
913
|
continue;
|
|
899
914
|
}
|
|
900
|
-
|
|
915
|
+
// A merged symbol's table holds the members every one of its declarations writes,
|
|
916
|
+
// and each member is kept once, by the declaration that writes it.
|
|
917
|
+
for (const held of own.filter((one) => writtenInside(container.declaration, one.node))) {
|
|
901
918
|
keepMember(container, held.node, seen, areStatic);
|
|
902
919
|
}
|
|
903
920
|
}
|
package/src/workspace-run.ts
CHANGED
|
@@ -41,10 +41,9 @@ export interface WorkspaceRun {
|
|
|
41
41
|
referenceOnly(configFile: string, compiled?: readonly string[]): (file: string) => boolean;
|
|
42
42
|
/**
|
|
43
43
|
* Whether one file a target configuration's program holds is the target's own. A
|
|
44
|
-
* workspace package's file is by its path alone
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* reached it as a library's.
|
|
44
|
+
* workspace package's file is by its path alone: the run reads another package from
|
|
45
|
+
* its source, so the compiler holds that package's files as the importer's own, not
|
|
46
|
+
* as a library's. Any other file is unless the compiler reached it as a library's.
|
|
48
47
|
*/
|
|
49
48
|
ownFile(file: string, fromExternalLibrary: boolean): boolean;
|
|
50
49
|
/** The target's own manifest, its targets read back to source. */
|