@cplieger/deadset-ts 2.1.0 → 2.2.1

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 CHANGED
@@ -8,7 +8,7 @@ deadset-ts is a command-line analyzer for TypeScript and JavaScript projects. It
8
8
 
9
9
  deadset-ts is report-only. It never edits source, and it refuses any `--fix` flag.
10
10
 
11
- **Status: pre-release.** This version implements contract 2.0.0 and ships the analyzer's foundation: one compiler session per run over every `tsconfig` project discovered under the target (the explicit scope, every `tsconfig*.json`, each project's `references`), a fail-closed read of every project's diagnostics, configuration decoding against the contract's closed key list with `print-config` and its provenance, `print-projects`, the report-only guard, the symbol inventory of every declaration a project's own files hold down to its class and type members, and the one-pass reference resolution over that inventory. The inventory and the reference pass are library functions the package exports; no verb reports findings yet, so `analyze`, `explain`, `print-roots`, `print-retained` and `describe` exit with a usage message. The one runtime dependency is the `typescript` package at exactly 7.0.2, installed under the `@typescript/native` name until TypeScript 7.1 ships a compiler API the tooling can share.
11
+ **Status: pre-release.** This version implements contract 2.1.0 and ships the analyzer's foundation: one compiler session per run over every `tsconfig` project discovered under the target (the explicit scope, every `tsconfig*.json`, each project's `references`), a fail-closed read of every project's diagnostics, configuration decoding against the contract's closed key list with `print-config` and its provenance, `print-projects`, the report-only guard, the symbol inventory of every declaration a project's own files hold down to its class and type members, and the one-pass reference resolution over that inventory. The inventory and the reference pass are library functions the package exports; no verb reports findings yet, so `analyze`, `explain`, `print-roots`, `print-retained` and `describe` exit with a usage message. The one runtime dependency is the `typescript` package at exactly 7.0.2, installed under the `@typescript/native` name until TypeScript 7.1 ships a compiler API the tooling can share.
12
12
 
13
13
  ## Install
14
14
 
@@ -70,7 +70,7 @@ The symbol inventory:
70
70
  The reference pass:
71
71
 
72
72
  - `references(project, held, targetRoot, options)`: every reference from one project's own files to a declaration of its inventory, in position order, with the rules that classified files as test files.
73
- - `DEFAULT_BATCH_CAP`: the batch size a run takes when the configuration names none.
73
+ - `DEFAULT_BATCH_CAP`: the batch size the reference pass takes when its caller passes none; it is an option of the pass, not a configuration key. [Batch-cap calibration](docs/batch-cap-calibration.md) is the measurement that set it.
74
74
  - `Reference`, `References`, `ReferenceOptions`, `ReferenceCost`, `TestFileRule`, `Resolution`, `Use`: one reference, one project's set of them, how a run resolves them, what that cost, one test-file rule, which accessor answered a reference, and whether it reads or writes.
75
75
 
76
76
  Positions:
@@ -1,4 +1,5 @@
1
1
  import { isArrayLiteralExpression, isBinaryExpression, isDeleteExpression, isElementAccessExpression, isForInStatement, isForOfStatement, isObjectLiteralExpression, isParenthesizedExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isSpreadElement, SyntaxKind, } from "@typescript/native/unstable/ast";
2
+ import { SymbolFlags } from "@typescript/native/unstable/sync";
2
3
  import { nodeKey } from "./inventory.js";
3
4
  import { byPosition, renderPosition } from "./position.js";
4
5
  /**
@@ -31,21 +32,6 @@ const ASSIGNMENTS = new Set([
31
32
  SyntaxKind.QuestionQuestionEqualsToken,
32
33
  SyntaxKind.CaretEqualsToken,
33
34
  ]);
34
- /**
35
- * The declaration forms that name something declared elsewhere. Each is a link rather
36
- * than a declaration of what it names, so a reference through one names the next link
37
- * and, at the end of the chain, the declaration itself: a re-export something imports
38
- * is used, and so is the declaration behind it.
39
- */
40
- const ALIASES = new Set([
41
- SyntaxKind.ImportClause,
42
- SyntaxKind.ImportEqualsDeclaration,
43
- SyntaxKind.ImportSpecifier,
44
- SyntaxKind.NamespaceImport,
45
- SyntaxKind.ExportAssignment,
46
- SyntaxKind.ExportSpecifier,
47
- SyntaxKind.NamespaceExport,
48
- ]);
49
35
  /** Whether one node is an identifier or a private name, the two forms a name takes. */
50
36
  function isName(node) {
51
37
  return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
@@ -303,11 +289,17 @@ export function references(project, held, targetRoot, options) {
303
289
  * is the declaration behind it, so both are named; a link this project does not
304
290
  * declare is stepped over rather than recorded.
305
291
  *
306
- * A declaration handle carries the file it is in and the syntax it is written as, so
307
- * both questions the walk asks of a declaration are answered before it is resolved: a
308
- * declaration outside the project's own files belongs to another program and is never
309
- * read, which is what keeps the pass from fetching a library file to discover that the
310
- * inventory does not hold what is in it.
292
+ * A symbol is asked to step only where the binder flagged it an alias, which is the
293
+ * same condition the step itself asserts on. The declaration's syntax is not that
294
+ * condition and does not stand in for it: a default export of an expression is
295
+ * written as one of the alias forms and names nothing declared elsewhere, so it is
296
+ * recorded as the declaration it is and the chain ends there.
297
+ *
298
+ * A declaration handle carries the file it is in, so the question the walk asks of a
299
+ * declaration is answered before it is resolved: a declaration outside the project's
300
+ * own files belongs to another program and is never read, which is what keeps the
301
+ * pass from fetching a library file to discover that the inventory does not hold what
302
+ * is in it.
311
303
  */
312
304
  const targetsOf = (symbol) => {
313
305
  const cached = reached.get(symbol.id);
@@ -320,9 +312,8 @@ export function references(project, held, targetRoot, options) {
320
312
  let stepped = false;
321
313
  while (at !== undefined && !walked.has(at.id)) {
322
314
  walked.add(at.id);
323
- let alias = false;
315
+ const alias = (at.flags & SymbolFlags.Alias) !== 0;
324
316
  for (const handle of at.declarations) {
325
- alias = alias || ALIASES.has(handle.kind);
326
317
  if (!ownFiles.has(handle.path)) {
327
318
  continue;
328
319
  }
@@ -4,4 +4,4 @@
4
4
  * independently of the analyzer's own version, which is the one the host answers
5
5
  * from the package the analyzer was installed from.
6
6
  */
7
- export const CONTRACT_VERSION = "2.0.0";
7
+ export const CONTRACT_VERSION = "2.1.0";
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/deadset-ts",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "license": "GPL-3.0-or-later",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/deadset-ts",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Deterministic dead-code analysis for TypeScript, class and type members included",
package/src/references.ts CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  type Node,
19
19
  type SourceFile,
20
20
  } from "@typescript/native/unstable/ast";
21
- import type { Symbol as TSSymbol } from "@typescript/native/unstable/sync";
21
+ import { SymbolFlags, type Symbol as TSSymbol } from "@typescript/native/unstable/sync";
22
22
  import { nodeKey, type Inventory } from "./inventory.ts";
23
23
  import { byPosition, renderPosition, type Position } from "./position.ts";
24
24
  import type { ProjectView } from "./session.ts";
@@ -159,22 +159,6 @@ const ASSIGNMENTS: ReadonlySet<SyntaxKind> = new Set([
159
159
  SyntaxKind.CaretEqualsToken,
160
160
  ]);
161
161
 
162
- /**
163
- * The declaration forms that name something declared elsewhere. Each is a link rather
164
- * than a declaration of what it names, so a reference through one names the next link
165
- * and, at the end of the chain, the declaration itself: a re-export something imports
166
- * is used, and so is the declaration behind it.
167
- */
168
- const ALIASES: ReadonlySet<SyntaxKind> = new Set([
169
- SyntaxKind.ImportClause,
170
- SyntaxKind.ImportEqualsDeclaration,
171
- SyntaxKind.ImportSpecifier,
172
- SyntaxKind.NamespaceImport,
173
- SyntaxKind.ExportAssignment,
174
- SyntaxKind.ExportSpecifier,
175
- SyntaxKind.NamespaceExport,
176
- ]);
177
-
178
162
  /** Whether one node is an identifier or a private name, the two forms a name takes. */
179
163
  function isName(node: Node): boolean {
180
164
  return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
@@ -479,11 +463,17 @@ export function references<Brand>(
479
463
  * is the declaration behind it, so both are named; a link this project does not
480
464
  * declare is stepped over rather than recorded.
481
465
  *
482
- * A declaration handle carries the file it is in and the syntax it is written as, so
483
- * both questions the walk asks of a declaration are answered before it is resolved: a
484
- * declaration outside the project's own files belongs to another program and is never
485
- * read, which is what keeps the pass from fetching a library file to discover that the
486
- * inventory does not hold what is in it.
466
+ * A symbol is asked to step only where the binder flagged it an alias, which is the
467
+ * same condition the step itself asserts on. The declaration's syntax is not that
468
+ * condition and does not stand in for it: a default export of an expression is
469
+ * written as one of the alias forms and names nothing declared elsewhere, so it is
470
+ * recorded as the declaration it is and the chain ends there.
471
+ *
472
+ * A declaration handle carries the file it is in, so the question the walk asks of a
473
+ * declaration is answered before it is resolved: a declaration outside the project's
474
+ * own files belongs to another program and is never read, which is what keeps the
475
+ * pass from fetching a library file to discover that the inventory does not hold what
476
+ * is in it.
487
477
  */
488
478
  const targetsOf = (symbol: TSSymbol): readonly Target[] => {
489
479
  const cached = reached.get(symbol.id);
@@ -496,9 +486,8 @@ export function references<Brand>(
496
486
  let stepped = false;
497
487
  while (at !== undefined && !walked.has(at.id)) {
498
488
  walked.add(at.id);
499
- let alias = false;
489
+ const alias = (at.flags & SymbolFlags.Alias) !== 0;
500
490
  for (const handle of at.declarations) {
501
- alias = alias || ALIASES.has(handle.kind);
502
491
  if (!ownFiles.has(handle.path)) {
503
492
  continue;
504
493
  }
package/src/version.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * independently of the analyzer's own version, which is the one the host answers
5
5
  * from the package the analyzer was installed from.
6
6
  */
7
- export const CONTRACT_VERSION = "2.0.0";
7
+ export const CONTRACT_VERSION = "2.1.0";