@cplieger/deadset-ts 7.2.0-dev.1 → 7.2.0-dev.2
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/dependencies.js +0 -4
- package/dist/src/deprecation.js +1 -1
- package/dist/src/findings/completion.js +1 -1
- package/dist/src/findings/interfaces.js +1 -8
- package/dist/src/findings/unused-declarations.js +5 -8
- package/dist/src/html-entries.js +0 -3
- package/dist/src/intra-function-parts.js +2 -14
- package/dist/src/inventory.js +1 -3
- package/dist/src/matrix.js +1 -8
- package/dist/src/module-declarations.js +0 -3
- package/dist/src/type-errors.js +2 -1
- package/dist/src/workspace-resolution.js +5 -8
- package/dist/src/workspace.js +2 -2
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/dependencies.ts +0 -4
- package/src/deprecation.ts +1 -1
- package/src/findings/completion.ts +1 -4
- package/src/findings/interfaces.ts +1 -9
- package/src/findings/unused-declarations.ts +5 -12
- package/src/html-entries.ts +0 -3
- package/src/intra-function-parts.ts +4 -16
- package/src/inventory.ts +1 -3
- package/src/matrix.ts +1 -9
- package/src/module-declarations.ts +0 -3
- package/src/type-errors.ts +2 -1
- package/src/workspace-resolution.ts +5 -8
- package/src/workspace.ts +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# deadset-ts
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@cplieger/deadset-ts) [](https://jsr.io/@cplieger/deadset-ts)
|
|
3
|
+
[](https://www.npmjs.com/package/@cplieger/deadset-ts) [](https://jsr.io/@cplieger/deadset-ts) [](https://github.com/cplieger/deadset-ts/issues?q=label%3Astryker-tracker)
|
|
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
|
|
package/dist/src/dependencies.js
CHANGED
|
@@ -466,15 +466,11 @@ function skipWhitespace(text, at) {
|
|
|
466
466
|
*/
|
|
467
467
|
function membersAt(text, at) {
|
|
468
468
|
const found = new Map();
|
|
469
|
-
if (text.charAt(at) !== "{") {
|
|
470
|
-
return found;
|
|
471
|
-
}
|
|
472
469
|
let cursor = skipWhitespace(text, at + 1);
|
|
473
470
|
while (text.charAt(cursor) === '"') {
|
|
474
471
|
const keyEnd = valueEnd(text, cursor);
|
|
475
472
|
const key = JSON.parse(text.slice(cursor, keyEnd));
|
|
476
473
|
const value = skipWhitespace(text, skipWhitespace(text, keyEnd) + 1);
|
|
477
|
-
found.delete(key);
|
|
478
474
|
found.set(key, { key: cursor, value });
|
|
479
475
|
cursor = skipWhitespace(text, valueEnd(text, value));
|
|
480
476
|
if (text.charAt(cursor) === ",") {
|
package/dist/src/deprecation.js
CHANGED
|
@@ -47,7 +47,7 @@ export function deprecatedDeclarations(project, held) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
const id = held.declarations.get(nodeKey(file, node));
|
|
50
|
-
if (id !== undefined
|
|
50
|
+
if (id !== undefined) {
|
|
51
51
|
named.push({ id, handle: project.handle(nameNode(node)) });
|
|
52
52
|
}
|
|
53
53
|
node.forEachChild(visit);
|
|
@@ -145,7 +145,7 @@ function findingComponents(swept, cascade) {
|
|
|
145
145
|
},
|
|
146
146
|
];
|
|
147
147
|
})
|
|
148
|
-
.sort((a, b) => byPosition(a.position, b.position)
|
|
148
|
+
.sort((a, b) => byPosition(a.position, b.position));
|
|
149
149
|
return (id) => {
|
|
150
150
|
const component = held.get(id);
|
|
151
151
|
return component === undefined
|
|
@@ -10,13 +10,6 @@ const UNCALLED_MESSAGE = "no call site invokes or selects the method through the
|
|
|
10
10
|
function positionOf(symbol) {
|
|
11
11
|
return { ...symbol.position, endLine: Math.max(symbol.position.line, symbol.endLine) };
|
|
12
12
|
}
|
|
13
|
-
/** Two strings ordered bytewise. */
|
|
14
|
-
function compare(a, b) {
|
|
15
|
-
if (a === b) {
|
|
16
|
-
return 0;
|
|
17
|
-
}
|
|
18
|
-
return a < b ? -1 : 1;
|
|
19
|
-
}
|
|
20
13
|
/** One run's declarations and candidates, indexed for the two kinds. */
|
|
21
14
|
function indexed(input) {
|
|
22
15
|
const union = input.swept.matrix.union;
|
|
@@ -31,7 +24,7 @@ function indexed(input) {
|
|
|
31
24
|
.map(symbolOf)
|
|
32
25
|
.filter((symbol) => symbol !== undefined)
|
|
33
26
|
.map((symbol) => ({ ref: symbol.ref, name: symbol.name, position: positionOf(symbol) }))
|
|
34
|
-
.sort((a, b) => byPosition(a.position, b.position)
|
|
27
|
+
.sort((a, b) => byPosition(a.position, b.position)),
|
|
35
28
|
};
|
|
36
29
|
}
|
|
37
30
|
/** The finding one code makes about one declaration. */
|
|
@@ -39,19 +39,17 @@ const WORDS = {
|
|
|
39
39
|
const TEST_OF_DEAD_CODE = "every target symbol this test references is reported dead";
|
|
40
40
|
/**
|
|
41
41
|
* The code one candidate is reported under, or none, each symbol once under the most
|
|
42
|
-
* specific code: a test of dead code first; no other test-file declaration
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
42
|
+
* specific code: a test of dead code first; no other test-file declaration or enum
|
|
43
|
+
* member nothing names; a test-support declaration test code references as test-only
|
|
44
|
+
* use; then deprecation, a test reference, and the unreferenced codes, an unimportable
|
|
45
|
+
* unused export being the unreachable kind's.
|
|
46
46
|
*/
|
|
47
47
|
function codeOf(judged) {
|
|
48
48
|
const { candidate, symbol } = judged;
|
|
49
49
|
if (candidate.testOfDeadCode) {
|
|
50
50
|
return "DS1005";
|
|
51
51
|
}
|
|
52
|
-
if ((judged.test && !candidate.unreferencedTest) ||
|
|
53
|
-
judged.containerDead ||
|
|
54
|
-
NOT_THIS_FAMILY.has(symbol.kind)) {
|
|
52
|
+
if ((judged.test && !candidate.unreferencedTest) || NOT_THIS_FAMILY.has(symbol.kind)) {
|
|
55
53
|
return undefined;
|
|
56
54
|
}
|
|
57
55
|
const referenced = candidate.productionRefs + candidate.testRefs > 0;
|
|
@@ -192,7 +190,6 @@ function familyFindings(input, fallen) {
|
|
|
192
190
|
candidate,
|
|
193
191
|
symbol,
|
|
194
192
|
test: union.test[at] === true,
|
|
195
|
-
containerDead: containerDead && !fallen,
|
|
196
193
|
deprecated: input.deprecated.has(symbol.id),
|
|
197
194
|
unreachable: unreachable.has(symbol.id),
|
|
198
195
|
};
|
package/dist/src/html-entries.js
CHANGED
|
@@ -303,7 +303,6 @@ function readsBinding(use, declared, ids) {
|
|
|
303
303
|
export function projectParts(project, held, references, targetRoot) {
|
|
304
304
|
const files = project.ownSourceFiles();
|
|
305
305
|
const extended = extendedNames(files);
|
|
306
|
-
const kinds = new Map(held.symbols.map((symbol) => [symbol.id, symbol.kind]));
|
|
307
306
|
const parts = [];
|
|
308
307
|
const signatures = [];
|
|
309
308
|
const calls = new Map();
|
|
@@ -313,12 +312,7 @@ export function projectParts(project, held, references, targetRoot) {
|
|
|
313
312
|
const contextual = [];
|
|
314
313
|
for (const file of files) {
|
|
315
314
|
// A parameter property's own parts stay with the parameter when its member goes.
|
|
316
|
-
const declarationAt = (node) =>
|
|
317
|
-
const id = held.declarations.get(nodeKey(file, node));
|
|
318
|
-
return id === undefined || kinds.get(id) === "file" || isParameterProperty(node)
|
|
319
|
-
? undefined
|
|
320
|
-
: id;
|
|
321
|
-
};
|
|
315
|
+
const declarationAt = (node) => isParameterProperty(node) ? undefined : held.declarations.get(nodeKey(file, node));
|
|
322
316
|
// A part no declaration holds belongs to the file, which is judged while the file is live.
|
|
323
317
|
const fileId = held.declarations.get(nodeKey(file, file));
|
|
324
318
|
const holderOf = (node) => {
|
|
@@ -560,10 +554,6 @@ function valueSignature(node) {
|
|
|
560
554
|
function parameterNames(signature) {
|
|
561
555
|
const found = [];
|
|
562
556
|
const patternNames = (pattern, at) => {
|
|
563
|
-
if (isIdentifier(pattern)) {
|
|
564
|
-
found.push({ name: pattern, at, pattern: true, exempt: false });
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
557
|
const rest = isObjectBindingPattern(pattern) &&
|
|
568
558
|
pattern.elements.some((element) => element.dotDotDotToken !== undefined);
|
|
569
559
|
for (const element of pattern.elements) {
|
|
@@ -741,9 +731,7 @@ function deadStores(file, root, block, holder, locals, ids) {
|
|
|
741
731
|
for (const write of writes) {
|
|
742
732
|
// The rest of the write's own statement runs after it: a later declarator may read the local.
|
|
743
733
|
const own = statements[write.at];
|
|
744
|
-
const sameStatement = own !== undefined && write.target === local.name
|
|
745
|
-
? usesIn(own).filter((use) => use !== local.name)
|
|
746
|
-
: [];
|
|
734
|
+
const sameStatement = own !== undefined && write.target === local.name ? usesIn(own) : [];
|
|
747
735
|
if (sameStatement.length > 0) {
|
|
748
736
|
continue;
|
|
749
737
|
}
|
package/dist/src/inventory.js
CHANGED
|
@@ -733,9 +733,7 @@ export function inventory(project, host, targetRoot) {
|
|
|
733
733
|
});
|
|
734
734
|
}
|
|
735
735
|
const byId = new Map(building.map((record) => [positionKey(record.position), record]));
|
|
736
|
-
const symbols = building
|
|
737
|
-
.map(render)
|
|
738
|
-
.sort((a, b) => byPosition(a.position, b.position) || (a.ref < b.ref ? -1 : 1));
|
|
736
|
+
const symbols = building.map(render).sort((a, b) => byPosition(a.position, b.position));
|
|
739
737
|
return {
|
|
740
738
|
symbols,
|
|
741
739
|
declarations: new Map([...byNode].map(([key, record]) => [key, positionKey(record.position)])),
|
package/dist/src/matrix.js
CHANGED
|
@@ -7,13 +7,6 @@ import { componentsOf } from "./components.js";
|
|
|
7
7
|
import { graphOf, OUTSIDE } from "./graph.js";
|
|
8
8
|
import { byPosition } from "./position.js";
|
|
9
9
|
import { reachedWithTheTests, sweep, } from "./sweep.js";
|
|
10
|
-
/** Two strings ordered bytewise. */
|
|
11
|
-
function compare(a, b) {
|
|
12
|
-
if (a === b) {
|
|
13
|
-
return 0;
|
|
14
|
-
}
|
|
15
|
-
return a < b ? -1 : 1;
|
|
16
|
-
}
|
|
17
10
|
/**
|
|
18
11
|
* What makes one reference one reference, whichever configuration made it. A consumer's
|
|
19
12
|
* position is rendered against its own root, so the consumer is part of what it names.
|
|
@@ -76,7 +69,7 @@ export function matrixOf(per) {
|
|
|
76
69
|
references.push(reference);
|
|
77
70
|
}
|
|
78
71
|
});
|
|
79
|
-
symbols.sort((a, b) => byPosition(a.position, b.position)
|
|
72
|
+
symbols.sort((a, b) => byPosition(a.position, b.position));
|
|
80
73
|
return {
|
|
81
74
|
configurations: per.map((one) => one.configuration),
|
|
82
75
|
graphs: per.map((one) => graphOf(one.symbols, one.references, one.roots, one.testFiles, one.supportFiles)),
|
|
@@ -79,9 +79,6 @@ function namesModule(specifier, name) {
|
|
|
79
79
|
* the members that hold the export names given.
|
|
80
80
|
*/
|
|
81
81
|
function namedBy(held) {
|
|
82
|
-
if (held.modules.size === 0) {
|
|
83
|
-
return () => [];
|
|
84
|
-
}
|
|
85
82
|
const refs = new Map();
|
|
86
83
|
const children = new Map();
|
|
87
84
|
for (const symbol of held.symbols) {
|
package/dist/src/type-errors.js
CHANGED
|
@@ -84,7 +84,8 @@ function declaringManifest(host, dir, targetRoot, name) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
// The target root is not below itself, so the walk stops after reading its manifest.
|
|
88
|
+
if (relativePath(targetRoot, at) === undefined) {
|
|
88
89
|
return undefined;
|
|
89
90
|
}
|
|
90
91
|
}
|
|
@@ -19,7 +19,6 @@ const DEPENDENCY_MEMBERS = [
|
|
|
19
19
|
"optionalDependencies",
|
|
20
20
|
];
|
|
21
21
|
const SOURCE = /(?<!\.d)\.(?:[mc]?ts|tsx)$/u;
|
|
22
|
-
const OUTPUT = /(?:\.d\.[mc]?ts|\.[mc]?js|\.jsx)$/u;
|
|
23
22
|
function isRecord(value) {
|
|
24
23
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
24
|
}
|
|
@@ -39,7 +38,7 @@ export function packageNameOf(specifier) {
|
|
|
39
38
|
return first;
|
|
40
39
|
}
|
|
41
40
|
function inside(dir, path) {
|
|
42
|
-
return
|
|
41
|
+
return relativePath(dir, path) !== undefined;
|
|
43
42
|
}
|
|
44
43
|
/** The `exports` entry one subpath selects, with what a pattern's `*` matched. */
|
|
45
44
|
function exportsEntry(exportsField, subpath) {
|
|
@@ -199,12 +198,10 @@ export function workspaceResolver(host, workspace) {
|
|
|
199
198
|
return found;
|
|
200
199
|
}
|
|
201
200
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
return found;
|
|
207
|
-
}
|
|
201
|
+
const beside = emittedFrom(path, { sourceDirs: [] });
|
|
202
|
+
const found = beside.find((candidate) => host.kindOf(candidate) === "file");
|
|
203
|
+
if (found !== undefined) {
|
|
204
|
+
return found;
|
|
208
205
|
}
|
|
209
206
|
return compiled(member, path) && host.kindOf(path) === "file" ? path : undefined;
|
|
210
207
|
};
|
package/dist/src/workspace.js
CHANGED
|
@@ -198,14 +198,14 @@ function memberDirectories(host, root, patterns) {
|
|
|
198
198
|
}
|
|
199
199
|
return [...included].filter((dir) => {
|
|
200
200
|
const below = relativePath(root, dir);
|
|
201
|
-
const segments = below === undefined
|
|
201
|
+
const segments = below === undefined ? [] : below.split("/");
|
|
202
202
|
return dir === root || !excluded.some((pattern) => pathMatches(pattern, segments));
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
205
|
/** Whether a workspace's patterns name one directory below its root, read without listing any. */
|
|
206
206
|
function namesDirectory(root, patterns, dir) {
|
|
207
207
|
const below = relativePath(root, dir);
|
|
208
|
-
if (below === undefined || below
|
|
208
|
+
if (below === undefined || below.startsWith("..")) {
|
|
209
209
|
return false;
|
|
210
210
|
}
|
|
211
211
|
const path = below.split("/");
|
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/deadset-ts",
|
|
3
|
-
"version": "7.2.0-dev.
|
|
3
|
+
"version": "7.2.0-dev.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Deterministic dead-code analysis for TypeScript, class and type members included",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@stryker-mutator/core": "10.0.0",
|
|
41
41
|
"@stryker-mutator/typescript-checker": "10.0.0",
|
|
42
42
|
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
43
|
-
"@types/node": "24.19.
|
|
43
|
+
"@types/node": "24.19.2",
|
|
44
44
|
"eslint": "10.12.0",
|
|
45
45
|
"fast-check": "4.10.2",
|
|
46
46
|
"prettier": "3.9.9",
|
package/src/dependencies.ts
CHANGED
|
@@ -616,15 +616,11 @@ function skipWhitespace(text: string, at: number): number {
|
|
|
616
616
|
*/
|
|
617
617
|
function membersAt(text: string, at: number): Map<string, { key: number; value: number }> {
|
|
618
618
|
const found = new Map<string, { key: number; value: number }>();
|
|
619
|
-
if (text.charAt(at) !== "{") {
|
|
620
|
-
return found;
|
|
621
|
-
}
|
|
622
619
|
let cursor = skipWhitespace(text, at + 1);
|
|
623
620
|
while (text.charAt(cursor) === '"') {
|
|
624
621
|
const keyEnd = valueEnd(text, cursor);
|
|
625
622
|
const key = JSON.parse(text.slice(cursor, keyEnd)) as string;
|
|
626
623
|
const value = skipWhitespace(text, skipWhitespace(text, keyEnd) + 1);
|
|
627
|
-
found.delete(key);
|
|
628
624
|
found.set(key, { key: cursor, value });
|
|
629
625
|
cursor = skipWhitespace(text, valueEnd(text, value));
|
|
630
626
|
if (text.charAt(cursor) === ",") {
|
package/src/deprecation.ts
CHANGED
|
@@ -73,7 +73,7 @@ export function deprecatedDeclarations<Brand>(
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
const id = held.declarations.get(nodeKey(file, node));
|
|
76
|
-
if (id !== undefined
|
|
76
|
+
if (id !== undefined) {
|
|
77
77
|
named.push({ id, handle: project.handle(nameNode(node)) });
|
|
78
78
|
}
|
|
79
79
|
node.forEachChild(visit);
|
|
@@ -181,10 +181,7 @@ function findingComponents(
|
|
|
181
181
|
},
|
|
182
182
|
];
|
|
183
183
|
})
|
|
184
|
-
.sort(
|
|
185
|
-
(a, b) =>
|
|
186
|
-
byPosition(a.position, b.position) || (a.ref === b.ref ? 0 : a.ref < b.ref ? -1 : 1),
|
|
187
|
-
);
|
|
184
|
+
.sort((a, b) => byPosition(a.position, b.position));
|
|
188
185
|
return (id) => {
|
|
189
186
|
const component = held.get(id);
|
|
190
187
|
return component === undefined
|
|
@@ -19,14 +19,6 @@ function positionOf(symbol: InventorySymbol): FindingPosition {
|
|
|
19
19
|
return { ...symbol.position, endLine: Math.max(symbol.position.line, symbol.endLine) };
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/** Two strings ordered bytewise. */
|
|
23
|
-
function compare(a: string, b: string): number {
|
|
24
|
-
if (a === b) {
|
|
25
|
-
return 0;
|
|
26
|
-
}
|
|
27
|
-
return a < b ? -1 : 1;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
22
|
/** One run's declarations and candidates, indexed for the two kinds. */
|
|
31
23
|
function indexed(input: EmitterInput): {
|
|
32
24
|
readonly symbolOf: (id: string) => InventorySymbol | undefined;
|
|
@@ -49,7 +41,7 @@ function indexed(input: EmitterInput): {
|
|
|
49
41
|
.map(symbolOf)
|
|
50
42
|
.filter((symbol): symbol is InventorySymbol => symbol !== undefined)
|
|
51
43
|
.map((symbol) => ({ ref: symbol.ref, name: symbol.name, position: positionOf(symbol) }))
|
|
52
|
-
.sort((a, b) => byPosition(a.position, b.position)
|
|
44
|
+
.sort((a, b) => byPosition(a.position, b.position)),
|
|
53
45
|
};
|
|
54
46
|
}
|
|
55
47
|
|
|
@@ -52,8 +52,6 @@ interface Judged {
|
|
|
52
52
|
readonly symbol: InventorySymbol;
|
|
53
53
|
/** Whether a test file declares it. */
|
|
54
54
|
readonly test: boolean;
|
|
55
|
-
/** Whether its container is itself dead, so it falls with the container. */
|
|
56
|
-
readonly containerDead: boolean;
|
|
57
55
|
readonly deprecated: boolean;
|
|
58
56
|
/** Whether the unreachable-export kind reports it. */
|
|
59
57
|
readonly unreachable: boolean;
|
|
@@ -61,21 +59,17 @@ interface Judged {
|
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
61
|
* The code one candidate is reported under, or none, each symbol once under the most
|
|
64
|
-
* specific code: a test of dead code first; no other test-file declaration
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
62
|
+
* specific code: a test of dead code first; no other test-file declaration or enum
|
|
63
|
+
* member nothing names; a test-support declaration test code references as test-only
|
|
64
|
+
* use; then deprecation, a test reference, and the unreferenced codes, an unimportable
|
|
65
|
+
* unused export being the unreachable kind's.
|
|
68
66
|
*/
|
|
69
67
|
function codeOf(judged: Judged): string | undefined {
|
|
70
68
|
const { candidate, symbol } = judged;
|
|
71
69
|
if (candidate.testOfDeadCode) {
|
|
72
70
|
return "DS1005";
|
|
73
71
|
}
|
|
74
|
-
if (
|
|
75
|
-
(judged.test && !candidate.unreferencedTest) ||
|
|
76
|
-
judged.containerDead ||
|
|
77
|
-
NOT_THIS_FAMILY.has(symbol.kind)
|
|
78
|
-
) {
|
|
72
|
+
if ((judged.test && !candidate.unreferencedTest) || NOT_THIS_FAMILY.has(symbol.kind)) {
|
|
79
73
|
return undefined;
|
|
80
74
|
}
|
|
81
75
|
const referenced = candidate.productionRefs + candidate.testRefs > 0;
|
|
@@ -233,7 +227,6 @@ function familyFindings(input: EmitterInput, fallen: boolean): Finding[] {
|
|
|
233
227
|
candidate,
|
|
234
228
|
symbol,
|
|
235
229
|
test: union.test[at] === true,
|
|
236
|
-
containerDead: containerDead && !fallen,
|
|
237
230
|
deprecated: input.deprecated.has(symbol.id),
|
|
238
231
|
unreachable: unreachable.has(symbol.id),
|
|
239
232
|
};
|
package/src/html-entries.ts
CHANGED
|
@@ -529,7 +529,6 @@ export function projectParts<Brand>(
|
|
|
529
529
|
): ProjectParts {
|
|
530
530
|
const files = project.ownSourceFiles();
|
|
531
531
|
const extended = extendedNames(files);
|
|
532
|
-
const kinds = new Map(held.symbols.map((symbol) => [symbol.id, symbol.kind]));
|
|
533
532
|
const parts: PartFact[] = [];
|
|
534
533
|
const signatures: SignatureFact[] = [];
|
|
535
534
|
const calls = new Map<string, CallUse>();
|
|
@@ -540,12 +539,8 @@ export function projectParts<Brand>(
|
|
|
540
539
|
|
|
541
540
|
for (const file of files) {
|
|
542
541
|
// A parameter property's own parts stay with the parameter when its member goes.
|
|
543
|
-
const declarationAt = (node: Node): string | undefined =>
|
|
544
|
-
|
|
545
|
-
return id === undefined || kinds.get(id) === "file" || isParameterProperty(node)
|
|
546
|
-
? undefined
|
|
547
|
-
: id;
|
|
548
|
-
};
|
|
542
|
+
const declarationAt = (node: Node): string | undefined =>
|
|
543
|
+
isParameterProperty(node) ? undefined : held.declarations.get(nodeKey(file, node));
|
|
549
544
|
// A part no declaration holds belongs to the file, which is judged while the file is live.
|
|
550
545
|
const fileId = held.declarations.get(nodeKey(file, file));
|
|
551
546
|
const holderOf = (node: Node): string | undefined => {
|
|
@@ -804,11 +799,7 @@ function valueSignature(node: Node): SignatureNode | undefined {
|
|
|
804
799
|
*/
|
|
805
800
|
function parameterNames(signature: SignatureNode): ParameterName[] {
|
|
806
801
|
const found: ParameterName[] = [];
|
|
807
|
-
const patternNames = (pattern: BindingName, at: number): void => {
|
|
808
|
-
if (isIdentifier(pattern)) {
|
|
809
|
-
found.push({ name: pattern, at, pattern: true, exempt: false });
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
802
|
+
const patternNames = (pattern: Exclude<BindingName, Identifier>, at: number): void => {
|
|
812
803
|
const rest =
|
|
813
804
|
isObjectBindingPattern(pattern) &&
|
|
814
805
|
pattern.elements.some((element) => element.dotDotDotToken !== undefined);
|
|
@@ -1039,10 +1030,7 @@ function deadStores(
|
|
|
1039
1030
|
for (const write of writes) {
|
|
1040
1031
|
// The rest of the write's own statement runs after it: a later declarator may read the local.
|
|
1041
1032
|
const own = statements[write.at];
|
|
1042
|
-
const sameStatement =
|
|
1043
|
-
own !== undefined && write.target === local.name
|
|
1044
|
-
? usesIn(own).filter((use) => use !== local.name)
|
|
1045
|
-
: [];
|
|
1033
|
+
const sameStatement = own !== undefined && write.target === local.name ? usesIn(own) : [];
|
|
1046
1034
|
if (sameStatement.length > 0) {
|
|
1047
1035
|
continue;
|
|
1048
1036
|
}
|
package/src/inventory.ts
CHANGED
|
@@ -1042,9 +1042,7 @@ export function inventory<Brand>(
|
|
|
1042
1042
|
}
|
|
1043
1043
|
|
|
1044
1044
|
const byId = new Map(building.map((record) => [positionKey(record.position), record]));
|
|
1045
|
-
const symbols = building
|
|
1046
|
-
.map(render)
|
|
1047
|
-
.sort((a, b) => byPosition(a.position, b.position) || (a.ref < b.ref ? -1 : 1));
|
|
1045
|
+
const symbols = building.map(render).sort((a, b) => byPosition(a.position, b.position));
|
|
1048
1046
|
|
|
1049
1047
|
return {
|
|
1050
1048
|
symbols,
|
package/src/matrix.ts
CHANGED
|
@@ -94,14 +94,6 @@ export interface SweepResult {
|
|
|
94
94
|
readonly components: readonly Component[];
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
/** Two strings ordered bytewise. */
|
|
98
|
-
function compare(a: string, b: string): number {
|
|
99
|
-
if (a === b) {
|
|
100
|
-
return 0;
|
|
101
|
-
}
|
|
102
|
-
return a < b ? -1 : 1;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
97
|
/**
|
|
106
98
|
* What makes one reference one reference, whichever configuration made it. A consumer's
|
|
107
99
|
* position is rendered against its own root, so the consumer is part of what it names.
|
|
@@ -163,7 +155,7 @@ export function matrixOf(per: readonly Configured[]): Matrix {
|
|
|
163
155
|
references.push(reference);
|
|
164
156
|
}
|
|
165
157
|
});
|
|
166
|
-
symbols.sort((a, b) => byPosition(a.position, b.position)
|
|
158
|
+
symbols.sort((a, b) => byPosition(a.position, b.position));
|
|
167
159
|
|
|
168
160
|
return {
|
|
169
161
|
configurations: per.map((one) => one.configuration),
|
|
@@ -113,9 +113,6 @@ interface Named {
|
|
|
113
113
|
function namedBy(
|
|
114
114
|
held: Inventory,
|
|
115
115
|
): (specifier: string, names: readonly string[]) => readonly Named[] {
|
|
116
|
-
if (held.modules.size === 0) {
|
|
117
|
-
return () => [];
|
|
118
|
-
}
|
|
119
116
|
const refs = new Map<string, string>();
|
|
120
117
|
const children = new Map<string, InventorySymbol[]>();
|
|
121
118
|
for (const symbol of held.symbols) {
|
package/src/type-errors.ts
CHANGED
|
@@ -151,7 +151,8 @@ function declaringManifest(
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
|
|
154
|
+
// The target root is not below itself, so the walk stops after reading its manifest.
|
|
155
|
+
if (relativePath(targetRoot, at) === undefined) {
|
|
155
156
|
return undefined;
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -45,7 +45,6 @@ const DEPENDENCY_MEMBERS = [
|
|
|
45
45
|
] as const;
|
|
46
46
|
|
|
47
47
|
const SOURCE = /(?<!\.d)\.(?:[mc]?ts|tsx)$/u;
|
|
48
|
-
const OUTPUT = /(?:\.d\.[mc]?ts|\.[mc]?js|\.jsx)$/u;
|
|
49
48
|
|
|
50
49
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
51
50
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -70,7 +69,7 @@ export function packageNameOf(specifier: string): string | undefined {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
function inside(dir: string, path: string): boolean {
|
|
73
|
-
return
|
|
72
|
+
return relativePath(dir, path) !== undefined;
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
/** The `exports` entry one subpath selects, with what a pattern's `*` matched. */
|
|
@@ -274,12 +273,10 @@ export function workspaceResolver(host: Host, workspace: Workspace): WorkspaceRe
|
|
|
274
273
|
return found;
|
|
275
274
|
}
|
|
276
275
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return found;
|
|
282
|
-
}
|
|
276
|
+
const beside = emittedFrom(path, { sourceDirs: [] });
|
|
277
|
+
const found = beside.find((candidate) => host.kindOf(candidate) === "file");
|
|
278
|
+
if (found !== undefined) {
|
|
279
|
+
return found;
|
|
283
280
|
}
|
|
284
281
|
return compiled(member, path) && host.kindOf(path) === "file" ? path : undefined;
|
|
285
282
|
};
|
package/src/workspace.ts
CHANGED
|
@@ -266,7 +266,7 @@ function memberDirectories(
|
|
|
266
266
|
}
|
|
267
267
|
return [...included].filter((dir) => {
|
|
268
268
|
const below = relativePath(root, dir);
|
|
269
|
-
const segments = below === undefined
|
|
269
|
+
const segments = below === undefined ? [] : below.split("/");
|
|
270
270
|
return dir === root || !excluded.some((pattern) => pathMatches(pattern, segments));
|
|
271
271
|
});
|
|
272
272
|
}
|
|
@@ -274,7 +274,7 @@ function memberDirectories(
|
|
|
274
274
|
/** Whether a workspace's patterns name one directory below its root, read without listing any. */
|
|
275
275
|
function namesDirectory(root: string, patterns: readonly string[], dir: string): boolean {
|
|
276
276
|
const below = relativePath(root, dir);
|
|
277
|
-
if (below === undefined || below
|
|
277
|
+
if (below === undefined || below.startsWith("..")) {
|
|
278
278
|
return false;
|
|
279
279
|
}
|
|
280
280
|
const path = below.split("/");
|