@shrkcrft/graph 0.1.0-alpha.16 → 0.1.0-alpha.18
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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/indexer/call-graph-support.d.ts +3 -0
- package/dist/indexer/call-graph-support.d.ts.map +1 -0
- package/dist/indexer/call-graph-support.js +32 -0
- package/dist/indexer/extract-ts-file.d.ts +26 -0
- package/dist/indexer/extract-ts-file.d.ts.map +1 -1
- package/dist/indexer/extract-ts-file.js +162 -20
- package/dist/indexer/incremental-updater.d.ts +21 -3
- package/dist/indexer/incremental-updater.d.ts.map +1 -1
- package/dist/indexer/incremental-updater.js +45 -10
- package/dist/indexer/index-builder.d.ts.map +1 -1
- package/dist/indexer/index-builder.js +12 -4
- package/dist/indexer/resolve-imports.d.ts +1 -0
- package/dist/indexer/resolve-imports.d.ts.map +1 -1
- package/dist/indexer/resolve-imports.js +26 -1
- package/dist/indexer/resolve-reexports.d.ts +32 -0
- package/dist/indexer/resolve-reexports.d.ts.map +1 -0
- package/dist/indexer/resolve-reexports.js +123 -0
- package/dist/query/graph-api-cache.d.ts +21 -0
- package/dist/query/graph-api-cache.d.ts.map +1 -0
- package/dist/query/graph-api-cache.js +54 -0
- package/dist/query/query-api.d.ts +126 -0
- package/dist/query/query-api.d.ts.map +1 -1
- package/dist/query/query-api.js +334 -0
- package/package.json +5 -4
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { IEdge } from '../schema/edge.js';
|
|
2
|
+
import type { INode } from '../schema/node.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve barrel re-export chains so a reference/call edge that targets a
|
|
5
|
+
* symbol re-exported through a package barrel points at the REAL declaring
|
|
6
|
+
* symbol instead of a phantom `symbol:<barrel>#<name>` that never existed.
|
|
7
|
+
*
|
|
8
|
+
* Why this matters: cross-package consumers import from a package barrel
|
|
9
|
+
* (`import { X } from '@scope/pkg'`), which the resolver maps to the barrel
|
|
10
|
+
* `index.ts`. The binder then targets `symbol:<barrel>#X` — but `X` is
|
|
11
|
+
* declared in a sub-file the barrel re-exports (`export * from './x'` /
|
|
12
|
+
* `export { X } from './x'`), so `callersOf(<real X>)` misses every one of
|
|
13
|
+
* those consumers and `graph callers` returns a confidently-wrong all-clear.
|
|
14
|
+
* This pass rewrites those edges to the real symbol id.
|
|
15
|
+
*
|
|
16
|
+
* Conservative + deterministic:
|
|
17
|
+
* - Only edges whose target symbol does NOT exist (a phantom) are
|
|
18
|
+
* considered; every valid edge is returned untouched.
|
|
19
|
+
* - Re-export chains are followed with a visited-set cycle guard, so a
|
|
20
|
+
* re-export cycle terminates instead of looping.
|
|
21
|
+
* - Renamed re-exports (`export { a as b } from './x'`) are intentionally
|
|
22
|
+
* left unresolved — the exposed name differs from the declaration, so
|
|
23
|
+
* there is no safe deterministic match.
|
|
24
|
+
*
|
|
25
|
+
* Target file paths come from the `ImportsFile` edges the barrel already
|
|
26
|
+
* emits for its `export … from` specifiers, so this is a pure pass over
|
|
27
|
+
* `(nodes, edges)` with no extra resolver state — it runs identically in the
|
|
28
|
+
* full and incremental builders. The caller is responsible for de-duping
|
|
29
|
+
* (a rewrite can collide a rewritten edge id with an existing one).
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveReExportedReferenceEdges(nodes: readonly INode[], edges: readonly IEdge[]): IEdge[];
|
|
32
|
+
//# sourceMappingURL=resolve-reexports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-reexports.d.ts","sourceRoot":"","sources":["../../src/indexer/resolve-reexports.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAS/C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,SAAS,KAAK,EAAE,EACvB,KAAK,EAAE,SAAS,KAAK,EAAE,GACtB,KAAK,EAAE,CA4ET"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { EdgeKind } from "../schema/edge-kind.js";
|
|
3
|
+
import { NodeKind } from "../schema/node-kind.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve barrel re-export chains so a reference/call edge that targets a
|
|
6
|
+
* symbol re-exported through a package barrel points at the REAL declaring
|
|
7
|
+
* symbol instead of a phantom `symbol:<barrel>#<name>` that never existed.
|
|
8
|
+
*
|
|
9
|
+
* Why this matters: cross-package consumers import from a package barrel
|
|
10
|
+
* (`import { X } from '@scope/pkg'`), which the resolver maps to the barrel
|
|
11
|
+
* `index.ts`. The binder then targets `symbol:<barrel>#X` — but `X` is
|
|
12
|
+
* declared in a sub-file the barrel re-exports (`export * from './x'` /
|
|
13
|
+
* `export { X } from './x'`), so `callersOf(<real X>)` misses every one of
|
|
14
|
+
* those consumers and `graph callers` returns a confidently-wrong all-clear.
|
|
15
|
+
* This pass rewrites those edges to the real symbol id.
|
|
16
|
+
*
|
|
17
|
+
* Conservative + deterministic:
|
|
18
|
+
* - Only edges whose target symbol does NOT exist (a phantom) are
|
|
19
|
+
* considered; every valid edge is returned untouched.
|
|
20
|
+
* - Re-export chains are followed with a visited-set cycle guard, so a
|
|
21
|
+
* re-export cycle terminates instead of looping.
|
|
22
|
+
* - Renamed re-exports (`export { a as b } from './x'`) are intentionally
|
|
23
|
+
* left unresolved — the exposed name differs from the declaration, so
|
|
24
|
+
* there is no safe deterministic match.
|
|
25
|
+
*
|
|
26
|
+
* Target file paths come from the `ImportsFile` edges the barrel already
|
|
27
|
+
* emits for its `export … from` specifiers, so this is a pure pass over
|
|
28
|
+
* `(nodes, edges)` with no extra resolver state — it runs identically in the
|
|
29
|
+
* full and incremental builders. The caller is responsible for de-duping
|
|
30
|
+
* (a rewrite can collide a rewritten edge id with an existing one).
|
|
31
|
+
*/
|
|
32
|
+
export function resolveReExportedReferenceEdges(nodes, edges) {
|
|
33
|
+
const symbolIds = new Set();
|
|
34
|
+
for (const n of nodes)
|
|
35
|
+
if (n.kind === NodeKind.Symbol)
|
|
36
|
+
symbolIds.add(n.id);
|
|
37
|
+
// file path → (re-export specifier → resolved target file path).
|
|
38
|
+
const importTargets = new Map();
|
|
39
|
+
// file path → its re-exports.
|
|
40
|
+
const reExportsByFile = new Map();
|
|
41
|
+
for (const e of edges) {
|
|
42
|
+
if (e.kind === EdgeKind.ImportsFile) {
|
|
43
|
+
if (!e.from.startsWith('file:') || !e.to.startsWith('file:'))
|
|
44
|
+
continue;
|
|
45
|
+
const spec = e.data?.['specifier'];
|
|
46
|
+
if (typeof spec !== 'string')
|
|
47
|
+
continue;
|
|
48
|
+
const from = e.from.slice('file:'.length);
|
|
49
|
+
let m = importTargets.get(from);
|
|
50
|
+
if (!m) {
|
|
51
|
+
m = new Map();
|
|
52
|
+
importTargets.set(from, m);
|
|
53
|
+
}
|
|
54
|
+
if (!m.has(spec))
|
|
55
|
+
m.set(spec, e.to.slice('file:'.length));
|
|
56
|
+
}
|
|
57
|
+
else if (e.kind === EdgeKind.ReExportsSymbol) {
|
|
58
|
+
if (!e.from.startsWith('file:'))
|
|
59
|
+
continue;
|
|
60
|
+
const name = e.data?.['name'];
|
|
61
|
+
const specifier = e.data?.['specifier'];
|
|
62
|
+
if (typeof name !== 'string' || typeof specifier !== 'string')
|
|
63
|
+
continue;
|
|
64
|
+
const from = e.from.slice('file:'.length);
|
|
65
|
+
let arr = reExportsByFile.get(from);
|
|
66
|
+
if (!arr) {
|
|
67
|
+
arr = [];
|
|
68
|
+
reExportsByFile.set(from, arr);
|
|
69
|
+
}
|
|
70
|
+
arr.push({ name, star: e.data?.['star'] === true, specifier });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const resolve = (file, name, visited) => {
|
|
74
|
+
const key = `${file}#${name}`;
|
|
75
|
+
if (visited.has(key))
|
|
76
|
+
return undefined;
|
|
77
|
+
visited.add(key);
|
|
78
|
+
const direct = `symbol:${file}#${name}`;
|
|
79
|
+
if (symbolIds.has(direct))
|
|
80
|
+
return direct;
|
|
81
|
+
const reExports = reExportsByFile.get(file);
|
|
82
|
+
const specMap = importTargets.get(file);
|
|
83
|
+
if (!reExports || !specMap)
|
|
84
|
+
return undefined;
|
|
85
|
+
for (const re of reExports) {
|
|
86
|
+
if (!re.star && re.name !== name)
|
|
87
|
+
continue;
|
|
88
|
+
const targetPath = specMap.get(re.specifier);
|
|
89
|
+
if (!targetPath)
|
|
90
|
+
continue;
|
|
91
|
+
const r = resolve(targetPath, name, visited);
|
|
92
|
+
if (r)
|
|
93
|
+
return r;
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
return edges.map((e) => {
|
|
98
|
+
// Re-target the same symbol-pointing edges that cross a package barrel:
|
|
99
|
+
// references/calls AND the typed heritage edges. Without heritage here, a
|
|
100
|
+
// `class X implements I` where `I` is imported from a package barrel would
|
|
101
|
+
// point at the unresolved barrel placeholder and `subtypesOf(I)` would
|
|
102
|
+
// silently return nothing cross-package.
|
|
103
|
+
if (e.kind !== EdgeKind.CallsSymbol &&
|
|
104
|
+
e.kind !== EdgeKind.ReferencesSymbol &&
|
|
105
|
+
e.kind !== EdgeKind.ExtendsSymbol &&
|
|
106
|
+
e.kind !== EdgeKind.ImplementsSymbol) {
|
|
107
|
+
return e;
|
|
108
|
+
}
|
|
109
|
+
if (!e.to.startsWith('symbol:') || symbolIds.has(e.to))
|
|
110
|
+
return e;
|
|
111
|
+
const body = e.to.slice('symbol:'.length);
|
|
112
|
+
const hash = body.lastIndexOf('#');
|
|
113
|
+
if (hash <= 0)
|
|
114
|
+
return e;
|
|
115
|
+
const resolved = resolve(body.slice(0, hash), body.slice(hash + 1), new Set());
|
|
116
|
+
if (!resolved || resolved === e.to)
|
|
117
|
+
return e;
|
|
118
|
+
return { ...e, to: resolved, id: edgeId(e.from, resolved, e.kind) };
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function edgeId(from, to, kind) {
|
|
122
|
+
return createHash('sha1').update(`${from}|${to}|${kind}`).digest('hex');
|
|
123
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GraphQueryApi } from './query-api.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load the graph query API for a project, cached across calls keyed by the
|
|
4
|
+
* store's `meta.json` mtime+size.
|
|
5
|
+
*
|
|
6
|
+
* The MCP server is long-lived and every graph tool used to re-read + re-parse
|
|
7
|
+
* the ~12MB on-disk store and rebuild four in-memory indexes on EVERY request
|
|
8
|
+
* (~30–165ms). The store only changes when the index is rebuilt
|
|
9
|
+
* (`graph index` / `updateChanged` rewrite `meta.json`, bumping its mtime), so
|
|
10
|
+
* keying the cache on that stat reloads only when it genuinely changed —
|
|
11
|
+
* including when a SEPARATE process (a CLI `graph index`) rebuilt it. The query
|
|
12
|
+
* API is read-only, so sharing one instance across calls is safe.
|
|
13
|
+
*
|
|
14
|
+
* Returns `null` when no index exists. NOTE: this caches the STORE, not
|
|
15
|
+
* working-tree freshness — source-file edits are still detected per-query via
|
|
16
|
+
* {@link GraphQueryApi.staleFilesAmong}; the two are orthogonal.
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadGraphApiCached(projectRoot: string): GraphQueryApi | null;
|
|
19
|
+
/** Drop all cached snapshots (tests / explicit invalidation). */
|
|
20
|
+
export declare function clearGraphApiCache(): void;
|
|
21
|
+
//# sourceMappingURL=graph-api-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-api-cache.d.ts","sourceRoot":"","sources":["../../src/query/graph-api-cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAW/C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAyB5E;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { statSync } from 'node:fs';
|
|
2
|
+
import * as nodePath from 'node:path';
|
|
3
|
+
import { GraphStore } from "../store/graph-store.js";
|
|
4
|
+
import { GraphQueryApi } from "./query-api.js";
|
|
5
|
+
const CACHE = new Map();
|
|
6
|
+
const MAX_ENTRIES = 4;
|
|
7
|
+
/**
|
|
8
|
+
* Load the graph query API for a project, cached across calls keyed by the
|
|
9
|
+
* store's `meta.json` mtime+size.
|
|
10
|
+
*
|
|
11
|
+
* The MCP server is long-lived and every graph tool used to re-read + re-parse
|
|
12
|
+
* the ~12MB on-disk store and rebuild four in-memory indexes on EVERY request
|
|
13
|
+
* (~30–165ms). The store only changes when the index is rebuilt
|
|
14
|
+
* (`graph index` / `updateChanged` rewrite `meta.json`, bumping its mtime), so
|
|
15
|
+
* keying the cache on that stat reloads only when it genuinely changed —
|
|
16
|
+
* including when a SEPARATE process (a CLI `graph index`) rebuilt it. The query
|
|
17
|
+
* API is read-only, so sharing one instance across calls is safe.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` when no index exists. NOTE: this caches the STORE, not
|
|
20
|
+
* working-tree freshness — source-file edits are still detected per-query via
|
|
21
|
+
* {@link GraphQueryApi.staleFilesAmong}; the two are orthogonal.
|
|
22
|
+
*/
|
|
23
|
+
export function loadGraphApiCached(projectRoot) {
|
|
24
|
+
const metaPath = nodePath.join(projectRoot, '.sharkcraft', 'graph', 'meta.json');
|
|
25
|
+
let st;
|
|
26
|
+
try {
|
|
27
|
+
st = statSync(metaPath);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
CACHE.delete(projectRoot);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const key = `${Math.floor(st.mtimeMs)}:${st.size}`;
|
|
34
|
+
const hit = CACHE.get(projectRoot);
|
|
35
|
+
if (hit && hit.key === key)
|
|
36
|
+
return hit.api;
|
|
37
|
+
const store = new GraphStore(projectRoot);
|
|
38
|
+
if (!store.exists()) {
|
|
39
|
+
CACHE.delete(projectRoot);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const api = new GraphQueryApi(store.loadSnapshot());
|
|
43
|
+
if (!CACHE.has(projectRoot) && CACHE.size >= MAX_ENTRIES) {
|
|
44
|
+
const oldest = CACHE.keys().next().value;
|
|
45
|
+
if (oldest !== undefined)
|
|
46
|
+
CACHE.delete(oldest);
|
|
47
|
+
}
|
|
48
|
+
CACHE.set(projectRoot, { key, api });
|
|
49
|
+
return api;
|
|
50
|
+
}
|
|
51
|
+
/** Drop all cached snapshots (tests / explicit invalidation). */
|
|
52
|
+
export function clearGraphApiCache() {
|
|
53
|
+
CACHE.clear();
|
|
54
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IEdge } from '../schema/edge.js';
|
|
2
|
+
import { EdgeKind } from '../schema/edge-kind.js';
|
|
2
3
|
import type { IGraphSnapshot } from '../schema/graph-snapshot.js';
|
|
3
4
|
import type { INode } from '../schema/node.js';
|
|
4
5
|
import { type IFileCycle } from './cycle-detection.js';
|
|
@@ -38,6 +39,57 @@ export interface IFindSymbolOptions {
|
|
|
38
39
|
/** Exact match required (no case-insensitive / prefix matching). */
|
|
39
40
|
exact?: boolean;
|
|
40
41
|
}
|
|
42
|
+
export interface IStaleResultFiles {
|
|
43
|
+
/** Result files whose on-disk content changed since indexing (line numbers / membership may be stale). */
|
|
44
|
+
modified: readonly string[];
|
|
45
|
+
/** Result files that no longer exist on disk (should be dropped from results). */
|
|
46
|
+
deleted: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
export interface ICallSite {
|
|
49
|
+
/** The file node that calls / references the symbol. */
|
|
50
|
+
node: INode;
|
|
51
|
+
/**
|
|
52
|
+
* Representative source line of the use. The indexer de-dupes reference
|
|
53
|
+
* edges by (target, kind), so this is the FIRST recorded call/reference
|
|
54
|
+
* site in that file — enough for an agent to jump straight to, not an
|
|
55
|
+
* exhaustive list of every occurrence.
|
|
56
|
+
*/
|
|
57
|
+
line?: number;
|
|
58
|
+
}
|
|
59
|
+
/** A single hop along a directed code path: `from` uses `to` via `kind`. */
|
|
60
|
+
export interface IGraphPathHop {
|
|
61
|
+
from: INode;
|
|
62
|
+
to: INode;
|
|
63
|
+
kind: EdgeKind;
|
|
64
|
+
/** Representative source line of the use (call/reference edges carry one). */
|
|
65
|
+
line?: number;
|
|
66
|
+
}
|
|
67
|
+
/** Result of a directed reachability query between two code nodes. */
|
|
68
|
+
export interface IGraphPath {
|
|
69
|
+
/** True when a directed `from → … → to` path exists within the depth cap. */
|
|
70
|
+
found: boolean;
|
|
71
|
+
from?: INode;
|
|
72
|
+
to?: INode;
|
|
73
|
+
/** The shortest path, hop by hop. Empty when `from === to` or not found. */
|
|
74
|
+
hops: readonly IGraphPathHop[];
|
|
75
|
+
/** Nodes visited before answering — context for a "no path" result. */
|
|
76
|
+
explored: number;
|
|
77
|
+
/** Why the query could not run / find a path (endpoint missing, depth cap). */
|
|
78
|
+
reason?: string;
|
|
79
|
+
}
|
|
80
|
+
/** A load-bearing node and how many distinct files depend on it. */
|
|
81
|
+
export interface IGraphHub {
|
|
82
|
+
node: INode;
|
|
83
|
+
/** Distinct dependents: referencing files for a symbol, importers for a file. */
|
|
84
|
+
inDegree: number;
|
|
85
|
+
}
|
|
86
|
+
/** The most-depended-on code in the snapshot — what to change carefully. */
|
|
87
|
+
export interface IGraphHubs {
|
|
88
|
+
/** Most-referenced symbols (functions / classes / types). */
|
|
89
|
+
symbols: readonly IGraphHub[];
|
|
90
|
+
/** Most-imported files. */
|
|
91
|
+
files: readonly IGraphHub[];
|
|
92
|
+
}
|
|
41
93
|
/**
|
|
42
94
|
* Read-only query layer over an in-memory graph snapshot.
|
|
43
95
|
*
|
|
@@ -76,6 +128,37 @@ export declare class GraphQueryApi {
|
|
|
76
128
|
callersOf(symbolNodeId: string): readonly INode[];
|
|
77
129
|
/** Files that *reference* the given symbol (any use, including calls). */
|
|
78
130
|
referencesOf(symbolNodeId: string): readonly INode[];
|
|
131
|
+
/**
|
|
132
|
+
* Symbols that EXTEND or IMPLEMENT the given symbol — the precise "who
|
|
133
|
+
* implements this interface / who subclasses this" answer that a generic
|
|
134
|
+
* reference cannot give (a reference might be a call, a type annotation, or
|
|
135
|
+
* a heritage clause; these are typed `extends-symbol`/`implements-symbol`
|
|
136
|
+
* edges only). Returns the subtype symbol nodes.
|
|
137
|
+
*/
|
|
138
|
+
subtypesOf(symbolNodeId: string): readonly INode[];
|
|
139
|
+
/** Symbols the given symbol EXTENDS or IMPLEMENTS (its supertypes). */
|
|
140
|
+
supertypesOf(symbolNodeId: string): readonly INode[];
|
|
141
|
+
/**
|
|
142
|
+
* Like {@link callersOf}, but keeps the call-site line carried on each
|
|
143
|
+
* edge so a caller can render `path:line` (jump-straight-to-source)
|
|
144
|
+
* instead of just the file path — the difference between "grep, then grep
|
|
145
|
+
* again inside each file" and a direct hit.
|
|
146
|
+
*/
|
|
147
|
+
callerSitesOf(symbolNodeId: string): readonly ICallSite[];
|
|
148
|
+
/** Like {@link referencesOf}, but keeps the representative use-site line. */
|
|
149
|
+
referenceSitesOf(symbolNodeId: string): readonly ICallSite[];
|
|
150
|
+
/**
|
|
151
|
+
* Targeted, cheap staleness check over a handful of RESULT file paths (the
|
|
152
|
+
* declaring file + caller/dependent files of a query) — NOT a full tree
|
|
153
|
+
* walk. For each project-relative path that the index knows about: stat it
|
|
154
|
+
* (mtime+size gate, sha1 only on mismatch) and classify as `modified`
|
|
155
|
+
* (content changed → results may be wrong: stale lines / a removed caller
|
|
156
|
+
* still listed) or `deleted` (gone from disk → drop it). Lets a query flag
|
|
157
|
+
* or prune a silently-stale answer for a file the agent just edited without
|
|
158
|
+
* paying for a whole-repo freshness walk. `cwd` is passed explicitly: the
|
|
159
|
+
* snapshot's index-time absolute root is wrong if the repo moved.
|
|
160
|
+
*/
|
|
161
|
+
staleFilesAmong(cwd: string, paths: readonly string[]): IStaleResultFiles;
|
|
79
162
|
/** Packages that this package depends on (PackageDependsOn). */
|
|
80
163
|
packageDeps(packageName: string): readonly INode[];
|
|
81
164
|
/** Packages that depend on this package (reverse PackageDependsOn). */
|
|
@@ -91,5 +174,48 @@ export declare class GraphQueryApi {
|
|
|
91
174
|
cycles(): readonly IFileCycle[];
|
|
92
175
|
/** 1-hop neighbours of a node, both in + out. */
|
|
93
176
|
neighbours(nodeId: string): IGraphNeighbours | undefined;
|
|
177
|
+
/**
|
|
178
|
+
* Shortest directed code path from `fromId` to `toId` over the
|
|
179
|
+
* "code uses code" edges (imports / calls / references / declares /
|
|
180
|
+
* re-exports / extends / implements). Answers "is A actually wired to B?"
|
|
181
|
+
* deterministically: a found path lists every hop with its edge kind (and
|
|
182
|
+
* call-site line where the edge carries one) so a caller sees HOW they are
|
|
183
|
+
* wired — a chain of `imports-file` hops reads very differently from a
|
|
184
|
+
* `calls-symbol` one. Breadth-first, so the returned path is minimal-hop;
|
|
185
|
+
* `explored` reports how many nodes were visited so a "no path" answer is
|
|
186
|
+
* honestly bounded rather than read as "definitely unrelated".
|
|
187
|
+
*/
|
|
188
|
+
pathBetween(fromId: string, toId: string, opts?: {
|
|
189
|
+
maxDepth?: number;
|
|
190
|
+
}): IGraphPath;
|
|
191
|
+
/** Walk the BFS `parent` map back from `toId` to `fromId` into ordered hops. */
|
|
192
|
+
private reconstructPath;
|
|
193
|
+
/**
|
|
194
|
+
* The most-depended-on code in the snapshot: symbols ranked by how many
|
|
195
|
+
* distinct files reference/call them and files ranked by how many distinct
|
|
196
|
+
* files import them. This is the "load-bearing code" view — the surface an
|
|
197
|
+
* agent should change most carefully and a human should understand first.
|
|
198
|
+
* In-degree counts DISTINCT dependent files (a file that calls a symbol
|
|
199
|
+
* ten times counts once), so the rank reflects blast radius, not call volume.
|
|
200
|
+
*/
|
|
201
|
+
/**
|
|
202
|
+
* The DIRECT dependents of a node — what breaks if you change it, one hop out.
|
|
203
|
+
* Kind-aware, because the edge that carries "depends on" differs by kind:
|
|
204
|
+
* - Symbol: the files that reference/call it, PLUS the files declaring its
|
|
205
|
+
* subtypes (a class that `import type`s an interface has no value-reference
|
|
206
|
+
* edge, so subtypes must be added explicitly or implementers are missed).
|
|
207
|
+
* Falls back to the importers of its declaring file when nothing references
|
|
208
|
+
* the symbol directly.
|
|
209
|
+
* - File: its importers (`imports-file`).
|
|
210
|
+
* - Package: the packages that depend on it.
|
|
211
|
+
* The shared building block for impact reverse-closures (CLI + MCP) — keep this
|
|
212
|
+
* the ONE source of truth so the two surfaces never disagree on a symbol's
|
|
213
|
+
* blast radius (they once did: an importers-only closure returned NOTHING for a
|
|
214
|
+
* symbol, a confidently-wrong "nothing breaks").
|
|
215
|
+
*/
|
|
216
|
+
directDependentsOf(anchor: INode): readonly INode[];
|
|
217
|
+
/** The file that declares a symbol (the `declares-symbol` source), if known. */
|
|
218
|
+
declaringFileOf(symbolId: string): INode | undefined;
|
|
219
|
+
topHubs(limit?: number, pathPrefix?: string): IGraphHubs;
|
|
94
220
|
}
|
|
95
221
|
//# sourceMappingURL=query-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-api.d.ts","sourceRoot":"","sources":["../../src/query/query-api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"query-api.d.ts","sourceRoot":"","sources":["../../src/query/query-api.ts"],"names":[],"mappings":"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"}
|