pi-shazam 0.1.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/dist/core/cache.d.ts +50 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +116 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/encoding.d.ts +25 -0
- package/dist/core/encoding.d.ts.map +1 -0
- package/dist/core/encoding.js +109 -0
- package/dist/core/encoding.js.map +1 -0
- package/dist/core/graph.d.ts +146 -0
- package/dist/core/graph.d.ts.map +1 -0
- package/dist/core/graph.js +224 -0
- package/dist/core/graph.js.map +1 -0
- package/dist/core/pagerank.d.ts +19 -0
- package/dist/core/pagerank.d.ts.map +1 -0
- package/dist/core/pagerank.js +106 -0
- package/dist/core/pagerank.js.map +1 -0
- package/dist/core/scanner.d.ts +19 -0
- package/dist/core/scanner.d.ts.map +1 -0
- package/dist/core/scanner.js +266 -0
- package/dist/core/scanner.js.map +1 -0
- package/dist/core/treesitter-queries.d.ts +19 -0
- package/dist/core/treesitter-queries.d.ts.map +1 -0
- package/dist/core/treesitter-queries.js +222 -0
- package/dist/core/treesitter-queries.js.map +1 -0
- package/dist/core/treesitter.d.ts +67 -0
- package/dist/core/treesitter.d.ts.map +1 -0
- package/dist/core/treesitter.js +624 -0
- package/dist/core/treesitter.js.map +1 -0
- package/dist/hooks/after-write.d.ts +32 -0
- package/dist/hooks/after-write.d.ts.map +1 -0
- package/dist/hooks/after-write.js +111 -0
- package/dist/hooks/after-write.js.map +1 -0
- package/dist/hooks/before-start.d.ts +23 -0
- package/dist/hooks/before-start.d.ts.map +1 -0
- package/dist/hooks/before-start.js +43 -0
- package/dist/hooks/before-start.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +106 -0
- package/dist/index.js.map +1 -0
- package/dist/lsp/client.d.ts +77 -0
- package/dist/lsp/client.d.ts.map +1 -0
- package/dist/lsp/client.js +355 -0
- package/dist/lsp/client.js.map +1 -0
- package/dist/lsp/manager.d.ts +85 -0
- package/dist/lsp/manager.d.ts.map +1 -0
- package/dist/lsp/manager.js +362 -0
- package/dist/lsp/manager.js.map +1 -0
- package/dist/lsp/servers.d.ts +43 -0
- package/dist/lsp/servers.d.ts.map +1 -0
- package/dist/lsp/servers.js +140 -0
- package/dist/lsp/servers.js.map +1 -0
- package/dist/lsp/setup.d.ts +24 -0
- package/dist/lsp/setup.d.ts.map +1 -0
- package/dist/lsp/setup.js +140 -0
- package/dist/lsp/setup.js.map +1 -0
- package/dist/tools/call_chain.d.ts +9 -0
- package/dist/tools/call_chain.d.ts.map +1 -0
- package/dist/tools/call_chain.js +151 -0
- package/dist/tools/call_chain.js.map +1 -0
- package/dist/tools/check.d.ts +18 -0
- package/dist/tools/check.d.ts.map +1 -0
- package/dist/tools/check.js +141 -0
- package/dist/tools/check.js.map +1 -0
- package/dist/tools/codequery.d.ts +19 -0
- package/dist/tools/codequery.d.ts.map +1 -0
- package/dist/tools/codequery.js +128 -0
- package/dist/tools/codequery.js.map +1 -0
- package/dist/tools/codesearch.d.ts +8 -0
- package/dist/tools/codesearch.d.ts.map +1 -0
- package/dist/tools/codesearch.js +101 -0
- package/dist/tools/codesearch.js.map +1 -0
- package/dist/tools/file_detail.d.ts +9 -0
- package/dist/tools/file_detail.d.ts.map +1 -0
- package/dist/tools/file_detail.js +125 -0
- package/dist/tools/file_detail.js.map +1 -0
- package/dist/tools/fix.d.ts +25 -0
- package/dist/tools/fix.d.ts.map +1 -0
- package/dist/tools/fix.js +257 -0
- package/dist/tools/fix.js.map +1 -0
- package/dist/tools/hotspots.d.ts +9 -0
- package/dist/tools/hotspots.d.ts.map +1 -0
- package/dist/tools/hotspots.js +107 -0
- package/dist/tools/hotspots.js.map +1 -0
- package/dist/tools/impact.d.ts +14 -0
- package/dist/tools/impact.d.ts.map +1 -0
- package/dist/tools/impact.js +160 -0
- package/dist/tools/impact.js.map +1 -0
- package/dist/tools/orphan.d.ts +9 -0
- package/dist/tools/orphan.d.ts.map +1 -0
- package/dist/tools/orphan.js +124 -0
- package/dist/tools/orphan.js.map +1 -0
- package/dist/tools/overview.d.ts +9 -0
- package/dist/tools/overview.d.ts.map +1 -0
- package/dist/tools/overview.js +137 -0
- package/dist/tools/overview.js.map +1 -0
- package/dist/tools/ready.d.ts +18 -0
- package/dist/tools/ready.d.ts.map +1 -0
- package/dist/tools/ready.js +145 -0
- package/dist/tools/ready.js.map +1 -0
- package/dist/tools/refs.d.ts +9 -0
- package/dist/tools/refs.d.ts.map +1 -0
- package/dist/tools/refs.js +129 -0
- package/dist/tools/refs.js.map +1 -0
- package/dist/tools/routes.d.ts +8 -0
- package/dist/tools/routes.d.ts.map +1 -0
- package/dist/tools/routes.js +83 -0
- package/dist/tools/routes.js.map +1 -0
- package/dist/tools/state_map.d.ts +8 -0
- package/dist/tools/state_map.d.ts.map +1 -0
- package/dist/tools/state_map.js +95 -0
- package/dist/tools/state_map.js.map +1 -0
- package/dist/tools/symbol.d.ts +9 -0
- package/dist/tools/symbol.d.ts.map +1 -0
- package/dist/tools/symbol.js +84 -0
- package/dist/tools/symbol.js.map +1 -0
- package/dist/tools/verify.d.ts +24 -0
- package/dist/tools/verify.d.ts.map +1 -0
- package/dist/tools/verify.js +212 -0
- package/dist/tools/verify.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-shazam core/graph — Symbol dependency graph data model.
|
|
3
|
+
*
|
|
4
|
+
* Ported from repomap/src/__init__.py (Symbol, Edge, RepoGraph dataclasses).
|
|
5
|
+
* All other core/ modules depend on these types.
|
|
6
|
+
*/
|
|
7
|
+
// ── Factory ──────────────────────────────────────────────────────────────────
|
|
8
|
+
export function createRepoGraph() {
|
|
9
|
+
return {
|
|
10
|
+
symbols: new Map(),
|
|
11
|
+
outgoing: new Map(),
|
|
12
|
+
incoming: new Map(),
|
|
13
|
+
fileSymbols: new Map(),
|
|
14
|
+
fileImports: new Map(),
|
|
15
|
+
fileCalls: new Map(),
|
|
16
|
+
fileImportBindings: new Map(),
|
|
17
|
+
fileExports: new Map(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
// ── Symbol factory ───────────────────────────────────────────────────────────
|
|
21
|
+
export function createSymbol(id, name, kind, file, line, overrides = {}) {
|
|
22
|
+
return {
|
|
23
|
+
id,
|
|
24
|
+
name,
|
|
25
|
+
kind,
|
|
26
|
+
file,
|
|
27
|
+
line,
|
|
28
|
+
endLine: overrides.endLine ?? line,
|
|
29
|
+
col: overrides.col ?? 0,
|
|
30
|
+
visibility: overrides.visibility ?? "public",
|
|
31
|
+
docstring: overrides.docstring ?? "",
|
|
32
|
+
signature: overrides.signature ?? "",
|
|
33
|
+
returnType: overrides.returnType ?? "",
|
|
34
|
+
params: overrides.params ?? "",
|
|
35
|
+
pagerank: overrides.pagerank ?? 0.0,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// ── Edge factory ─────────────────────────────────────────────────────────────
|
|
39
|
+
export function createEdge(source, target, weight, kind, confidence = 1.0) {
|
|
40
|
+
return { source, target, weight, kind, confidence };
|
|
41
|
+
}
|
|
42
|
+
export function serializeSymbol(sym) {
|
|
43
|
+
return {
|
|
44
|
+
id: sym.id,
|
|
45
|
+
name: sym.name,
|
|
46
|
+
kind: sym.kind,
|
|
47
|
+
file: sym.file,
|
|
48
|
+
line: sym.line,
|
|
49
|
+
endLine: sym.endLine,
|
|
50
|
+
col: sym.col,
|
|
51
|
+
visibility: sym.visibility,
|
|
52
|
+
signature: sym.signature,
|
|
53
|
+
returnType: sym.returnType,
|
|
54
|
+
params: sym.params,
|
|
55
|
+
docstring: sym.docstring,
|
|
56
|
+
pagerank: sym.pagerank,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function serializeEdge(edge) {
|
|
60
|
+
return {
|
|
61
|
+
source: edge.source,
|
|
62
|
+
target: edge.target,
|
|
63
|
+
weight: edge.weight,
|
|
64
|
+
kind: edge.kind,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function serializeGraph(graph) {
|
|
68
|
+
const symbols = [];
|
|
69
|
+
for (const sym of graph.symbols.values()) {
|
|
70
|
+
symbols.push(serializeSymbol(sym));
|
|
71
|
+
}
|
|
72
|
+
const edges = [];
|
|
73
|
+
for (const [, edgeList] of graph.outgoing) {
|
|
74
|
+
for (const edge of edgeList) {
|
|
75
|
+
edges.push(serializeEdge(edge));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
symbols,
|
|
80
|
+
edges,
|
|
81
|
+
version: 1,
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function edgeIdentity(edge) {
|
|
86
|
+
return `${edge.source}|${edge.target}|${edge.kind}`;
|
|
87
|
+
}
|
|
88
|
+
function edgeIdentityFromRow(row) {
|
|
89
|
+
return `${row.source}|${row.target}|${row.kind}`;
|
|
90
|
+
}
|
|
91
|
+
function stableKey(sym) {
|
|
92
|
+
return `${sym.file}::${sym.name}::${sym.kind}`;
|
|
93
|
+
}
|
|
94
|
+
export function compareGraphSnapshots(currentSymbols, currentEdges, previousSymbols, previousEdges) {
|
|
95
|
+
const currentSymMap = new Map(currentSymbols.map((s) => [s.id, s]));
|
|
96
|
+
const prevSymMap = new Map(previousSymbols.map((s) => [s.id, s]));
|
|
97
|
+
const currentIds = new Set(currentSymMap.keys());
|
|
98
|
+
const prevIds = new Set(prevSymMap.keys());
|
|
99
|
+
let addedIds = [...currentIds].filter((id) => !prevIds.has(id));
|
|
100
|
+
let removedIds = [...prevIds].filter((id) => !currentIds.has(id));
|
|
101
|
+
// Stable key matching for line-drift reconciliation
|
|
102
|
+
const addedByKey = new Map();
|
|
103
|
+
for (const sid of addedIds) {
|
|
104
|
+
const s = currentSymMap.get(sid);
|
|
105
|
+
const key = stableKey(s);
|
|
106
|
+
const arr = addedByKey.get(key) || [];
|
|
107
|
+
arr.push(sid);
|
|
108
|
+
addedByKey.set(key, arr);
|
|
109
|
+
}
|
|
110
|
+
const removedByKey = new Map();
|
|
111
|
+
for (const sid of removedIds) {
|
|
112
|
+
const s = prevSymMap.get(sid);
|
|
113
|
+
const key = stableKey(s);
|
|
114
|
+
const arr = removedByKey.get(key) || [];
|
|
115
|
+
arr.push(sid);
|
|
116
|
+
removedByKey.set(key, arr);
|
|
117
|
+
}
|
|
118
|
+
const reconciledPairs = [];
|
|
119
|
+
for (const [key, adds] of addedByKey) {
|
|
120
|
+
const rems = removedByKey.get(key) || [];
|
|
121
|
+
for (let i = 0; i < Math.min(adds.length, rems.length); i++) {
|
|
122
|
+
reconciledPairs.push([rems[i], adds[i]]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const reconciledAdded = new Set(reconciledPairs.map((p) => p[1]));
|
|
126
|
+
const reconciledRemoved = new Set(reconciledPairs.map((p) => p[0]));
|
|
127
|
+
addedIds = addedIds.filter((id) => !reconciledAdded.has(id));
|
|
128
|
+
removedIds = removedIds.filter((id) => !reconciledRemoved.has(id));
|
|
129
|
+
// Modified: same ID, signature or location changed
|
|
130
|
+
const commonIds = [...currentIds].filter((id) => prevIds.has(id));
|
|
131
|
+
const modifiedSymbols = [];
|
|
132
|
+
for (const id of commonIds) {
|
|
133
|
+
const cur = currentSymMap.get(id);
|
|
134
|
+
const prev = prevSymMap.get(id);
|
|
135
|
+
const sigChanged = cur.signature !== prev.signature;
|
|
136
|
+
const locChanged = cur.line !== prev.line ||
|
|
137
|
+
cur.endLine !== prev.endLine ||
|
|
138
|
+
cur.file !== prev.file;
|
|
139
|
+
if (sigChanged || locChanged) {
|
|
140
|
+
modifiedSymbols.push({
|
|
141
|
+
id: cur.id,
|
|
142
|
+
name: cur.name,
|
|
143
|
+
file: cur.file,
|
|
144
|
+
visibility: cur.visibility,
|
|
145
|
+
kind: cur.kind,
|
|
146
|
+
lineChange: `${prev.line} -> ${cur.line}`,
|
|
147
|
+
oldSignature: prev.signature,
|
|
148
|
+
newSignature: cur.signature,
|
|
149
|
+
signatureChanged: sigChanged,
|
|
150
|
+
risk: sigChanged ? "HIGH" : "LOW",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Reconciled pairs as modified
|
|
155
|
+
for (const [prevId, curId] of reconciledPairs) {
|
|
156
|
+
const cur = currentSymMap.get(curId);
|
|
157
|
+
const prev = prevSymMap.get(prevId);
|
|
158
|
+
const sigChanged = cur.signature !== prev.signature;
|
|
159
|
+
modifiedSymbols.push({
|
|
160
|
+
id: cur.id,
|
|
161
|
+
name: cur.name,
|
|
162
|
+
file: cur.file,
|
|
163
|
+
visibility: cur.visibility,
|
|
164
|
+
kind: cur.kind,
|
|
165
|
+
lineChange: `${prev.line} -> ${cur.line}`,
|
|
166
|
+
oldSignature: prev.signature,
|
|
167
|
+
newSignature: cur.signature,
|
|
168
|
+
signatureChanged: sigChanged,
|
|
169
|
+
risk: sigChanged ? "HIGH" : "LOW",
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// Edge changes
|
|
173
|
+
const currentEdgeSet = new Set(currentEdges.map(edgeIdentity));
|
|
174
|
+
const prevEdgeSet = new Set(previousEdges.map(edgeIdentityFromRow));
|
|
175
|
+
const edgesAdded = [...currentEdgeSet].filter((e) => !prevEdgeSet.has(e));
|
|
176
|
+
const edgesRemoved = [...prevEdgeSet].filter((e) => !currentEdgeSet.has(e));
|
|
177
|
+
return {
|
|
178
|
+
summary: {
|
|
179
|
+
added: addedIds.length,
|
|
180
|
+
removed: removedIds.length,
|
|
181
|
+
modified: modifiedSymbols.length,
|
|
182
|
+
edgesAdded: edgesAdded.length,
|
|
183
|
+
edgesRemoved: edgesRemoved.length,
|
|
184
|
+
},
|
|
185
|
+
addedSymbols: addedIds.map((id) => {
|
|
186
|
+
const s = currentSymMap.get(id);
|
|
187
|
+
return { id: s.id, name: s.name, file: s.file, line: s.line };
|
|
188
|
+
}),
|
|
189
|
+
removedSymbols: removedIds.map((id) => {
|
|
190
|
+
const s = prevSymMap.get(id);
|
|
191
|
+
return { id: s.id, name: s.name, file: s.file, line: s.line };
|
|
192
|
+
}),
|
|
193
|
+
modifiedSymbols,
|
|
194
|
+
callChainChanges: {
|
|
195
|
+
newCalls: edgesAdded.slice(0, 20).map((e) => {
|
|
196
|
+
const [from, to, kind] = e.split("|");
|
|
197
|
+
return { from, to, kind };
|
|
198
|
+
}),
|
|
199
|
+
removedCalls: edgesRemoved.slice(0, 20).map((e) => {
|
|
200
|
+
const [from, to, kind] = e.split("|");
|
|
201
|
+
return { from, to, kind };
|
|
202
|
+
}),
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// ── Constants ────────────────────────────────────────────────────────────────
|
|
207
|
+
export const LOW_SIGNAL_KINDS = new Set([
|
|
208
|
+
"element",
|
|
209
|
+
"selector",
|
|
210
|
+
"class_selector",
|
|
211
|
+
"id_selector",
|
|
212
|
+
"json_key",
|
|
213
|
+
]);
|
|
214
|
+
export const BOILERPLATE_NAMES = new Set(["__init__", "__main__"]);
|
|
215
|
+
export function signalWeightForSymbol(kind, name, visibility) {
|
|
216
|
+
if (LOW_SIGNAL_KINDS.has(kind))
|
|
217
|
+
return 0.002;
|
|
218
|
+
if (BOILERPLATE_NAMES.has(name))
|
|
219
|
+
return 0.35;
|
|
220
|
+
if (name.startsWith("_") && visibility === "private")
|
|
221
|
+
return 0.85;
|
|
222
|
+
return 1.0;
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../core/graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-shazam core/pagerank — PageRank importance scoring on RepoGraph.
|
|
3
|
+
*
|
|
4
|
+
* Ported from repomap/src/ranking.py (GraphAnalyzer.calculate_pagerank).
|
|
5
|
+
*
|
|
6
|
+
* The algorithm is pure iterative PageRank with convergence detection.
|
|
7
|
+
* No external dependencies beyond the graph data model.
|
|
8
|
+
*/
|
|
9
|
+
import type { RepoGraph } from "./graph.js";
|
|
10
|
+
/**
|
|
11
|
+
* Calculate PageRank scores for all symbols in the graph.
|
|
12
|
+
* Scores are stored directly on each symbol's `.pagerank` field.
|
|
13
|
+
*
|
|
14
|
+
* Damping factor: 0.85 (standard PageRank)
|
|
15
|
+
* Max iterations: 50
|
|
16
|
+
* Convergence tolerance: 1e-6
|
|
17
|
+
*/
|
|
18
|
+
export declare function calculatePageRank(graph: RepoGraph, damping?: number, maxIter?: number, tol?: number): void;
|
|
19
|
+
//# sourceMappingURL=pagerank.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagerank.d.ts","sourceRoot":"","sources":["../../core/pagerank.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,MAAa,EACtB,OAAO,GAAE,MAAW,EACpB,GAAG,GAAE,MAAa,GAChB,IAAI,CAgGN"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-shazam core/pagerank — PageRank importance scoring on RepoGraph.
|
|
3
|
+
*
|
|
4
|
+
* Ported from repomap/src/ranking.py (GraphAnalyzer.calculate_pagerank).
|
|
5
|
+
*
|
|
6
|
+
* The algorithm is pure iterative PageRank with convergence detection.
|
|
7
|
+
* No external dependencies beyond the graph data model.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Calculate PageRank scores for all symbols in the graph.
|
|
11
|
+
* Scores are stored directly on each symbol's `.pagerank` field.
|
|
12
|
+
*
|
|
13
|
+
* Damping factor: 0.85 (standard PageRank)
|
|
14
|
+
* Max iterations: 50
|
|
15
|
+
* Convergence tolerance: 1e-6
|
|
16
|
+
*/
|
|
17
|
+
export function calculatePageRank(graph, damping = 0.85, maxIter = 50, tol = 1e-6) {
|
|
18
|
+
const ids = [...graph.symbols.keys()];
|
|
19
|
+
const n = ids.length;
|
|
20
|
+
if (n === 0)
|
|
21
|
+
return;
|
|
22
|
+
// Initial uniform distribution
|
|
23
|
+
const pr = new Map();
|
|
24
|
+
for (const id of ids) {
|
|
25
|
+
pr.set(id, 1.0 / n);
|
|
26
|
+
}
|
|
27
|
+
// Compute outgoing weight sums
|
|
28
|
+
const outW = new Map();
|
|
29
|
+
for (const id of ids) {
|
|
30
|
+
const edges = graph.outgoing.get(id);
|
|
31
|
+
if (!edges || edges.length === 0) {
|
|
32
|
+
outW.set(id, 0);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
let sum = 0;
|
|
36
|
+
for (const e of edges) {
|
|
37
|
+
sum += e.weight;
|
|
38
|
+
}
|
|
39
|
+
outW.set(id, sum);
|
|
40
|
+
}
|
|
41
|
+
// Active sources: nodes with positive outgoing weight
|
|
42
|
+
const activeSrcs = new Set();
|
|
43
|
+
for (const id of ids) {
|
|
44
|
+
const w = outW.get(id) || 0;
|
|
45
|
+
if (w > 0 && !isNaN(w) && isFinite(w)) {
|
|
46
|
+
activeSrcs.add(id);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Build incoming index: tgt -> [(src, weight), ...]
|
|
50
|
+
const inc = new Map();
|
|
51
|
+
for (const [src, edges] of graph.outgoing) {
|
|
52
|
+
if (!activeSrcs.has(src))
|
|
53
|
+
continue;
|
|
54
|
+
for (const e of edges) {
|
|
55
|
+
const arr = inc.get(e.target) || [];
|
|
56
|
+
arr.push([src, e.weight]);
|
|
57
|
+
inc.set(e.target, arr);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const base = (1 - damping) / n;
|
|
61
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
62
|
+
const newPr = new Map();
|
|
63
|
+
for (const id of ids) {
|
|
64
|
+
let score = base;
|
|
65
|
+
const incoming = inc.get(id);
|
|
66
|
+
if (incoming) {
|
|
67
|
+
for (const [src, w] of incoming) {
|
|
68
|
+
const srcPr = pr.get(src) || 0;
|
|
69
|
+
const srcOutW = outW.get(src) || 1;
|
|
70
|
+
score += (damping * srcPr * w) / srcOutW;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
newPr.set(id, score);
|
|
74
|
+
}
|
|
75
|
+
// Normalize
|
|
76
|
+
let total = 0;
|
|
77
|
+
for (const score of newPr.values()) {
|
|
78
|
+
total += score;
|
|
79
|
+
}
|
|
80
|
+
total = total || 1.0;
|
|
81
|
+
for (const [id, score] of newPr) {
|
|
82
|
+
newPr.set(id, score / total);
|
|
83
|
+
}
|
|
84
|
+
// Convergence check
|
|
85
|
+
let delta = 0;
|
|
86
|
+
for (const id of ids) {
|
|
87
|
+
const oldScore = pr.get(id) || 0;
|
|
88
|
+
const newScore = newPr.get(id) || 0;
|
|
89
|
+
delta = Math.max(delta, Math.abs(newScore - oldScore));
|
|
90
|
+
}
|
|
91
|
+
// Update pr for next iteration
|
|
92
|
+
for (const [id, score] of newPr) {
|
|
93
|
+
pr.set(id, score);
|
|
94
|
+
}
|
|
95
|
+
if (delta < tol)
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
// Store scores back on symbols
|
|
99
|
+
for (const [id, score] of pr) {
|
|
100
|
+
const sym = graph.symbols.get(id);
|
|
101
|
+
if (sym) {
|
|
102
|
+
sym.pagerank = score;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=pagerank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagerank.js","sourceRoot":"","sources":["../../core/pagerank.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-shazam core/scanner — Project scanning + graph building.
|
|
3
|
+
*
|
|
4
|
+
* Walks project directories, parses source files with tree-sitter,
|
|
5
|
+
* extracts symbols/imports/calls, and builds the full RepoGraph.
|
|
6
|
+
*
|
|
7
|
+
* This is the main entry point that all tools compose from.
|
|
8
|
+
*/
|
|
9
|
+
import type { RepoGraph } from "./graph.js";
|
|
10
|
+
/**
|
|
11
|
+
* Scan a project directory, parse all source files, build the dependency graph,
|
|
12
|
+
* and compute PageRank scores.
|
|
13
|
+
*
|
|
14
|
+
* @param projectPath - Absolute or relative path to the project root
|
|
15
|
+
* @param log - Optional logger
|
|
16
|
+
* @returns The fully built RepoGraph with PageRank scores set
|
|
17
|
+
*/
|
|
18
|
+
export declare function scanProject(projectPath: string, log?: (msg: string) => void): RepoGraph;
|
|
19
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../core/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,YAAY,CAAC;AAgC1D;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAC1B,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GACzB,SAAS,CAuIX"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-shazam core/scanner — Project scanning + graph building.
|
|
3
|
+
*
|
|
4
|
+
* Walks project directories, parses source files with tree-sitter,
|
|
5
|
+
* extracts symbols/imports/calls, and builds the full RepoGraph.
|
|
6
|
+
*
|
|
7
|
+
* This is the main entry point that all tools compose from.
|
|
8
|
+
*/
|
|
9
|
+
import { readdirSync } from "node:fs";
|
|
10
|
+
import { join, relative, resolve } from "node:path";
|
|
11
|
+
import { TreeSitterAdapter, EXT_TO_LANG } from "./treesitter.js";
|
|
12
|
+
import { createRepoGraph, createEdge, } from "./graph.js";
|
|
13
|
+
import { calculatePageRank } from "./pagerank.js";
|
|
14
|
+
import { readFileAdaptive } from "./encoding.js";
|
|
15
|
+
// ── Constants ────────────────────────────────────────────────────────────────
|
|
16
|
+
/** Directories to skip during project scan */
|
|
17
|
+
const SKIP_DIRS = new Set([
|
|
18
|
+
"node_modules",
|
|
19
|
+
"dist",
|
|
20
|
+
".git",
|
|
21
|
+
".worktrees",
|
|
22
|
+
".cache",
|
|
23
|
+
".pi-shazam",
|
|
24
|
+
".qoder",
|
|
25
|
+
"__pycache__",
|
|
26
|
+
"target", // Rust
|
|
27
|
+
".venv",
|
|
28
|
+
"venv",
|
|
29
|
+
".tox",
|
|
30
|
+
"coverage",
|
|
31
|
+
".nyc_output",
|
|
32
|
+
]);
|
|
33
|
+
/** Maximum files to scan (safety limit) */
|
|
34
|
+
const MAX_FILES = 20_000;
|
|
35
|
+
/** File extensions to scan */
|
|
36
|
+
const SOURCE_EXTS = new Set(Object.keys(EXT_TO_LANG));
|
|
37
|
+
// ── Scanner ──────────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Scan a project directory, parse all source files, build the dependency graph,
|
|
40
|
+
* and compute PageRank scores.
|
|
41
|
+
*
|
|
42
|
+
* @param projectPath - Absolute or relative path to the project root
|
|
43
|
+
* @param log - Optional logger
|
|
44
|
+
* @returns The fully built RepoGraph with PageRank scores set
|
|
45
|
+
*/
|
|
46
|
+
export function scanProject(projectPath, log) {
|
|
47
|
+
const root = resolve(projectPath);
|
|
48
|
+
const logger = log ?? (() => { });
|
|
49
|
+
const adapter = new TreeSitterAdapter(logger);
|
|
50
|
+
const graph = createRepoGraph();
|
|
51
|
+
// Collect all source files
|
|
52
|
+
const files = collectSourceFiles(root, MAX_FILES);
|
|
53
|
+
logger(`Scanned ${files.length} source files`);
|
|
54
|
+
// Phase 1: Extract symbols from all files
|
|
55
|
+
const fileSymbolMap = new Map();
|
|
56
|
+
for (const relPath of files) {
|
|
57
|
+
const absPath = join(root, relPath);
|
|
58
|
+
const ext = relPath.slice(relPath.lastIndexOf(".")).toLowerCase();
|
|
59
|
+
const lang = EXT_TO_LANG[ext];
|
|
60
|
+
if (!lang)
|
|
61
|
+
continue;
|
|
62
|
+
try {
|
|
63
|
+
const source = readFileAdaptive(absPath);
|
|
64
|
+
const tree = adapter.parse(source, lang);
|
|
65
|
+
if (!tree)
|
|
66
|
+
continue;
|
|
67
|
+
const symbols = adapter.extractSymbols(tree, lang, relPath);
|
|
68
|
+
fileSymbolMap.set(relPath, symbols);
|
|
69
|
+
for (const sym of symbols) {
|
|
70
|
+
graph.symbols.set(sym.id, sym);
|
|
71
|
+
const fileSyms = graph.fileSymbols.get(relPath) || [];
|
|
72
|
+
fileSyms.push(sym.id);
|
|
73
|
+
graph.fileSymbols.set(relPath, fileSyms);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Skip unparseable files
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
logger(`Extracted ${graph.symbols.size} symbols`);
|
|
81
|
+
// Phase 2: Extract imports and calls, build edges
|
|
82
|
+
for (const relPath of files) {
|
|
83
|
+
const absPath = join(root, relPath);
|
|
84
|
+
const ext = relPath.slice(relPath.lastIndexOf(".")).toLowerCase();
|
|
85
|
+
const lang = EXT_TO_LANG[ext];
|
|
86
|
+
if (!lang)
|
|
87
|
+
continue;
|
|
88
|
+
try {
|
|
89
|
+
const source = readFileAdaptive(absPath);
|
|
90
|
+
const tree = adapter.parse(source, lang);
|
|
91
|
+
if (!tree)
|
|
92
|
+
continue;
|
|
93
|
+
// Import edges: file-level imports → link imported symbols to files
|
|
94
|
+
const imports = adapter.extractImports(tree, lang);
|
|
95
|
+
if (imports.length > 0) {
|
|
96
|
+
graph.fileImports.set(relPath, imports.map(([m]) => m));
|
|
97
|
+
// Create edges from this file's symbols to symbols in imported files
|
|
98
|
+
const thisFileSyms = graph.fileSymbols.get(relPath) || [];
|
|
99
|
+
for (const [importedModule] of imports) {
|
|
100
|
+
const resolvedImport = resolveImport(importedModule, relPath);
|
|
101
|
+
const targetFileSyms = graph.fileSymbols.get(resolvedImport) || [];
|
|
102
|
+
for (const srcId of thisFileSyms) {
|
|
103
|
+
for (const tgtId of targetFileSyms) {
|
|
104
|
+
addEdge(graph, createEdge(srcId, tgtId, 0.3, "import", 0.5));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Call edges: function calls → link caller to callee
|
|
110
|
+
const calls = adapter.extractCalls(tree, lang);
|
|
111
|
+
if (calls.length > 0) {
|
|
112
|
+
graph.fileCalls.set(relPath, calls);
|
|
113
|
+
const thisFileSyms = graph.fileSymbols.get(relPath) || [];
|
|
114
|
+
for (const [calledName, callLine] of calls) {
|
|
115
|
+
// Find the most specific symbol in this file that could be the caller
|
|
116
|
+
// (the symbol definition that contains this call line)
|
|
117
|
+
const callerSyms = findCallerSymbols(thisFileSyms, graph.symbols, callLine);
|
|
118
|
+
// Find callee symbols across the entire project
|
|
119
|
+
const calleeSyms = findCalleeSymbols(calledName, graph.symbols);
|
|
120
|
+
for (const caller of callerSyms) {
|
|
121
|
+
for (const callee of calleeSyms) {
|
|
122
|
+
if (caller.id !== callee.id) {
|
|
123
|
+
addEdge(graph, createEdge(caller.id, callee.id, 1.0, "call", 0.9));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// JS/TS import bindings (precise symbol-level imports)
|
|
130
|
+
const jsImports = adapter.extractJsTsImportBindings(tree, lang);
|
|
131
|
+
if (jsImports.length > 0) {
|
|
132
|
+
graph.fileImportBindings.set(relPath, jsImports);
|
|
133
|
+
for (const binding of jsImports) {
|
|
134
|
+
// Find the local symbol that represents this import binding
|
|
135
|
+
const localSym = findSymbolByNameInFile(binding.localName, relPath, graph.symbols);
|
|
136
|
+
if (!localSym)
|
|
137
|
+
continue;
|
|
138
|
+
// Find the source symbol in the imported module
|
|
139
|
+
const resolvedModule = resolveImport(binding.module, relPath);
|
|
140
|
+
const sourceSym = findSymbolByNameInFile(binding.importedName, resolvedModule, graph.symbols);
|
|
141
|
+
if (sourceSym) {
|
|
142
|
+
addEdge(graph, createEdge(localSym.id, sourceSym.id, 0.8, "import-binding", 1.0));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Skip unparseable files
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Phase 3: Compute PageRank
|
|
152
|
+
calculatePageRank(graph);
|
|
153
|
+
return graph;
|
|
154
|
+
}
|
|
155
|
+
// ── File collection ──────────────────────────────────────────────────────────
|
|
156
|
+
function collectSourceFiles(root, maxFiles) {
|
|
157
|
+
const files = [];
|
|
158
|
+
function walk(dir) {
|
|
159
|
+
if (files.length >= maxFiles)
|
|
160
|
+
return;
|
|
161
|
+
let entries;
|
|
162
|
+
try {
|
|
163
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
if (files.length >= maxFiles)
|
|
170
|
+
return;
|
|
171
|
+
const relPath = relative(root, join(dir, entry.name));
|
|
172
|
+
if (entry.isDirectory()) {
|
|
173
|
+
if (SKIP_DIRS.has(entry.name))
|
|
174
|
+
continue;
|
|
175
|
+
if (entry.name.startsWith(".") && !SKIP_DIRS.has(entry.name))
|
|
176
|
+
continue;
|
|
177
|
+
walk(join(dir, entry.name));
|
|
178
|
+
}
|
|
179
|
+
else if (entry.isFile()) {
|
|
180
|
+
const ext = entry.name.slice(entry.name.lastIndexOf(".")).toLowerCase();
|
|
181
|
+
if (SOURCE_EXTS.has(ext)) {
|
|
182
|
+
files.push(relPath);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
walk(root);
|
|
188
|
+
return files;
|
|
189
|
+
}
|
|
190
|
+
// ── Edge helpers ─────────────────────────────────────────────────────────────
|
|
191
|
+
function addEdge(graph, edge) {
|
|
192
|
+
const outgoing = graph.outgoing.get(edge.source) || [];
|
|
193
|
+
outgoing.push(edge);
|
|
194
|
+
graph.outgoing.set(edge.source, outgoing);
|
|
195
|
+
const incoming = graph.incoming.get(edge.target) || [];
|
|
196
|
+
incoming.push(edge);
|
|
197
|
+
graph.incoming.set(edge.target, incoming);
|
|
198
|
+
}
|
|
199
|
+
// ── Import resolution ─────────────────────────────────────────────────────────
|
|
200
|
+
/**
|
|
201
|
+
* Resolve a relative import path to a file path that matches the fileSymbols keys.
|
|
202
|
+
* Handles extensionless imports (e.g., "./foo" → "./foo.ts" or "./foo/index.ts").
|
|
203
|
+
*/
|
|
204
|
+
function resolveImport(importPath, fromFile) {
|
|
205
|
+
// If it's a relative import, resolve against the fromFile's directory
|
|
206
|
+
if (importPath.startsWith(".")) {
|
|
207
|
+
const fromDir = fromFile.includes("/")
|
|
208
|
+
? fromFile.slice(0, fromFile.lastIndexOf("/"))
|
|
209
|
+
: ".";
|
|
210
|
+
let resolved = join(fromDir, importPath);
|
|
211
|
+
// Try common extensions and index files
|
|
212
|
+
const candidates = [
|
|
213
|
+
resolved,
|
|
214
|
+
`${resolved}.ts`,
|
|
215
|
+
`${resolved}.tsx`,
|
|
216
|
+
`${resolved}.js`,
|
|
217
|
+
`${resolved}.jsx`,
|
|
218
|
+
`${resolved}/index.ts`,
|
|
219
|
+
`${resolved}/index.tsx`,
|
|
220
|
+
`${resolved}/index.js`,
|
|
221
|
+
];
|
|
222
|
+
return candidates[0];
|
|
223
|
+
}
|
|
224
|
+
// For bare module imports (e.g., "react", "lodash"), we can't resolve
|
|
225
|
+
// them to project files, so we return the import path as-is
|
|
226
|
+
return importPath;
|
|
227
|
+
}
|
|
228
|
+
// ── Symbol lookup helpers ────────────────────────────────────────────────────
|
|
229
|
+
function findCallerSymbols(fileSymIds, symbols, callLine) {
|
|
230
|
+
// Find symbols in the file that contain this call line within their range
|
|
231
|
+
const candidates = [];
|
|
232
|
+
for (const id of fileSymIds) {
|
|
233
|
+
const sym = symbols.get(id);
|
|
234
|
+
if (!sym)
|
|
235
|
+
continue;
|
|
236
|
+
if (sym.line <= callLine && callLine <= sym.endLine) {
|
|
237
|
+
candidates.push(sym);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Return the most specific (narrowest range) match first
|
|
241
|
+
candidates.sort((a, b) => {
|
|
242
|
+
const aRange = a.endLine - a.line;
|
|
243
|
+
const bRange = b.endLine - b.line;
|
|
244
|
+
return aRange - bRange || a.line - b.line;
|
|
245
|
+
});
|
|
246
|
+
// Return the most specific one
|
|
247
|
+
return candidates.length > 0 ? [candidates[0]] : [];
|
|
248
|
+
}
|
|
249
|
+
function findCalleeSymbols(name, symbols) {
|
|
250
|
+
const results = [];
|
|
251
|
+
for (const sym of symbols.values()) {
|
|
252
|
+
if (sym.name === name) {
|
|
253
|
+
results.push(sym);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return results;
|
|
257
|
+
}
|
|
258
|
+
function findSymbolByNameInFile(name, file, symbols) {
|
|
259
|
+
for (const sym of symbols.values()) {
|
|
260
|
+
if (sym.file === file && sym.name === name) {
|
|
261
|
+
return sym;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=scanner.js.map
|