@titan-design/code-graph 0.7.0 → 0.8.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/README.md CHANGED
@@ -18,7 +18,7 @@ const { snapshotId, files, nodes, edges, reused } = await indexPaths(store, {
18
18
  ref: "head",
19
19
  });
20
20
  listNodes(store, snapshotId); // file / module / external nodes, symbols on request
21
- listEdges(store, snapshotId); // imports / re-exports, references on request
21
+ listEdges(store, snapshotId); // imports / re-exports, references and calls on request
22
22
  ```
23
23
 
24
24
  ## What was extracted, and what was not
@@ -166,7 +166,7 @@ wrong time model for a population re-indexed all at once), `metric`, `id_alias`,
166
166
  `file_fingerprint`.
167
167
 
168
168
  The symbol layer is hidden by default. `listNodes` drops `symbol` nodes and `listEdges` drops
169
- `references` edges unless you ask for them, so a caller reasoning about module structure sees
169
+ `references` and `calls` edges unless you ask for them (`includeReferences` covers both), so a caller reasoning about module structure sees
170
170
  the graph it expects and does not have one import of thirty names read as thirty
171
171
  dependencies.
172
172
 
@@ -342,6 +342,23 @@ Python, and are written on every function or file, zeros included:
342
342
  `...`, `continue`, a bare or `None`/`null`/`undefined` return, or one call to a logger,
343
343
  `print`, `warn` or `console`).
344
344
 
345
+ Call-graph metrics (TP-323) come from `calls` edges, one per caller and callee symbol, each
346
+ carrying the literal arguments of every call site in `attrs.sites`. TypeScript resolves a
347
+ call or `new` through the type checker to one in-repo declaration. Python resolves only a
348
+ bare name declared at module level in the same file, a bare name bound by `from <in-repo
349
+ module> import`, and `self.<name>()` to a method of the enclosing class or a base class
350
+ declared in the same file. Anything else is dropped, never guessed, and an edge whose target
351
+ has no symbol node is pruned. The caller is the enclosing function, method or class, or the
352
+ file for a module-level call. Each function, method and class gets `symbol_caller_count`
353
+ (distinct callers, recursion excluded) and `symbol_single_caller_helper` (1 when a
354
+ non-exported, non-dunder symbol has exactly one caller and it is a symbol). A callable with 2
355
+ or more resolved call sites also gets `symbol_constant_params`: parameters every site passes
356
+ the same literal, or none passes. Callers found only through unresolved calls are missing, so
357
+ a private method that tests call on an instance can read as a single-caller helper. These
358
+ metrics need edges from every file, so they are recomputed on each index. Under reuse, an
359
+ unchanged caller's edge to a callee that moved behind a re-export stays pruned until the
360
+ caller changes, as `references` edges do.
361
+
345
362
  PageRank, relevance, and symbol coupling run at query time over one snapshot:
346
363
 
347
364
  ```ts
package/dist/index.d.ts CHANGED
@@ -121,7 +121,7 @@ declare class CodeGraphStore {
121
121
  listNodes(snapshotId: number, opts?: {
122
122
  includeSymbols?: boolean;
123
123
  }): GraphNode[];
124
- /** See {@link listNodes}: `references` edges are the symbol layer, excluded by default. */
124
+ /** See {@link listNodes}: `references` and `calls` edges are the symbol layer, excluded by default. */
125
125
  listEdges(snapshotId: number, opts?: {
126
126
  includeReferences?: boolean;
127
127
  }): GraphEdge[];
@@ -137,7 +137,7 @@ declare class CodeGraphStore {
137
137
  limit?: number;
138
138
  kind?: string;
139
139
  }): TopMetricRow[];
140
- /** Edges into or out of one node; `references` edges are excluded unless asked, as in {@link listEdges}. */
140
+ /** Edges into or out of one node; symbol-layer edges are excluded unless asked, as in {@link listEdges}. */
141
141
  listEdgesTouching(snapshotId: number, nodeId: string, opts?: {
142
142
  includeReferences?: boolean;
143
143
  }): GraphEdge[];
@@ -205,7 +205,7 @@ declare function runPrune(store: CodeGraphStore, options?: PruneOptions & {
205
205
  * index version is never reused, so a change to node/edge shape or to a metric's
206
206
  * value for the same bytes can never be carried forward from an incompatible graph.
207
207
  */
208
- declare const INDEX_VERSION = "0.17.0";
208
+ declare const INDEX_VERSION = "0.18.0";
209
209
  interface IndexOptions {
210
210
  /** Roots to walk. Node ids are still rooted at the git toplevel, so importers across roots share an id space. */
211
211
  paths: string[];
@@ -448,7 +448,7 @@ declare function readSourceFiles(filePaths: readonly string[]): Promise<ReadFile
448
448
  * Everything from a prior snapshot needed to rebuild an unchanged file's
449
449
  * contribution to the graph without re-parsing it: its content fingerprint,
450
450
  * the node table (to look up external-node names), outbound edges grouped by
451
- * source, and the source-content metrics (loc, complexity, lcom4, ...).
451
+ * source file (a symbol's `calls` edges under the file declaring it), and the source-content metrics (loc, complexity, lcom4, ...).
452
452
  */
453
453
  interface ReuseBasis {
454
454
  snapshotId: number;
@@ -494,10 +494,11 @@ declare function edgeWeight(e: GraphEdge): number;
494
494
  /**
495
495
  * Drop `references` edges (C-53) whose target `symbol` node doesn't exist — an
496
496
  * aliased re-export chain, or a barrel that changed under a reused file, can
497
- * resolve a name to an origin that doesn't declare it. Only `references` can
498
- * dangle (imports/re-exports resolve to always-emitted file/external nodes);
499
- * metrics already guard unknown ids, so this just keeps the persisted edge set
500
- * clean. Mutates `edges` in place.
497
+ * resolve a name to an origin that doesn't declare it. `calls` edges (TP-323)
498
+ * are dropped the same way, which is how a callee name that maps to no symbol
499
+ * node is discarded rather than guessed. Only these two can dangle
500
+ * (imports/re-exports resolve to always-emitted file/external nodes). Mutates
501
+ * `edges` in place.
501
502
  */
502
503
  declare function pruneDanglingReferences(nodes: ReadonlyMap<string, GraphNode>, edges: Map<string, GraphEdge>): void;
503
504
  /**
@@ -1120,7 +1121,7 @@ type MetricDirection = "higher-worse" | "lower-worse" | "neutral";
1120
1121
  /** A missing row reads as zero (a sparse writer's floor) or is left out of means, percentiles, and ranks. */
1121
1122
  type MetricAbsence = "zero" | "exclude";
1122
1123
  /** The code-graph module that writes the metric, for provenance. */
1123
- type MetricSource = "degree" | "source-metrics" | "lcom" | "exception-handling" | "dead-code" | "growth-risk" | "history" | "test-linker" | "coverage";
1124
+ type MetricSource = "degree" | "source-metrics" | "lcom" | "call-graph" | "exception-handling" | "dead-code" | "growth-risk" | "history" | "test-linker" | "coverage";
1124
1125
  interface MetricDescriptor {
1125
1126
  /** The stored name, or a template such as `churn_{w}` when {@link windowed} is set. */
1126
1127
  name: string;
@@ -1190,6 +1191,10 @@ interface MetricOutlierRule {
1190
1191
  percentile: number;
1191
1192
  /** Fewest nodes that must carry the metric before any is judged; defaults to 20. */
1192
1193
  minSample?: number;
1194
+ /** A node is flagged only if its value also exceeds this absolute floor, guarding sparse metrics whose percentile sits at or near zero. */
1195
+ floor?: number;
1196
+ /** When true, rank and gate on the pool of carriers with a non-zero value only; zero-valued nodes are never flagged. */
1197
+ rankNonZero?: boolean;
1193
1198
  severity?: Severity;
1194
1199
  }
1195
1200
  interface ForbidImportRule {