@shvmgyl15/tsgraph 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.
Files changed (187) hide show
  1. package/AGENTS.md +64 -0
  2. package/README.md +128 -0
  3. package/TODOS.md +61 -0
  4. package/dist/analysis/analysis.test.d.ts +2 -0
  5. package/dist/analysis/analysis.test.d.ts.map +1 -0
  6. package/dist/analysis/analysis.test.js +359 -0
  7. package/dist/analysis/analysis.test.js.map +1 -0
  8. package/dist/analysis/complexity.d.ts +8 -0
  9. package/dist/analysis/complexity.d.ts.map +1 -0
  10. package/dist/analysis/complexity.js +88 -0
  11. package/dist/analysis/complexity.js.map +1 -0
  12. package/dist/analysis/coupling.d.ts +17 -0
  13. package/dist/analysis/coupling.d.ts.map +1 -0
  14. package/dist/analysis/coupling.js +71 -0
  15. package/dist/analysis/coupling.js.map +1 -0
  16. package/dist/analysis/hotspot.d.ts +10 -0
  17. package/dist/analysis/hotspot.d.ts.map +1 -0
  18. package/dist/analysis/hotspot.js +33 -0
  19. package/dist/analysis/hotspot.js.map +1 -0
  20. package/dist/analysis/index.d.ts +9 -0
  21. package/dist/analysis/index.d.ts.map +1 -0
  22. package/dist/analysis/index.js +5 -0
  23. package/dist/analysis/index.js.map +1 -0
  24. package/dist/boundaries/index.d.ts +25 -0
  25. package/dist/boundaries/index.d.ts.map +1 -0
  26. package/dist/boundaries/index.js +103 -0
  27. package/dist/boundaries/index.js.map +1 -0
  28. package/dist/boundaries/index.test.d.ts +2 -0
  29. package/dist/boundaries/index.test.d.ts.map +1 -0
  30. package/dist/boundaries/index.test.js +293 -0
  31. package/dist/boundaries/index.test.js.map +1 -0
  32. package/dist/changes/index.d.ts +28 -0
  33. package/dist/changes/index.d.ts.map +1 -0
  34. package/dist/changes/index.js +48 -0
  35. package/dist/changes/index.js.map +1 -0
  36. package/dist/changes/index.test.d.ts +2 -0
  37. package/dist/changes/index.test.d.ts.map +1 -0
  38. package/dist/changes/index.test.js +104 -0
  39. package/dist/changes/index.test.js.map +1 -0
  40. package/dist/cli/index.d.ts +3 -0
  41. package/dist/cli/index.d.ts.map +1 -0
  42. package/dist/cli/index.js +659 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/git/index.d.ts +16 -0
  45. package/dist/git/index.d.ts.map +1 -0
  46. package/dist/git/index.js +73 -0
  47. package/dist/git/index.js.map +1 -0
  48. package/dist/git/index.test.d.ts +2 -0
  49. package/dist/git/index.test.d.ts.map +1 -0
  50. package/dist/git/index.test.js +78 -0
  51. package/dist/git/index.test.js.map +1 -0
  52. package/dist/graph/types.d.ts +156 -0
  53. package/dist/graph/types.d.ts.map +1 -0
  54. package/dist/graph/types.js +166 -0
  55. package/dist/graph/types.js.map +1 -0
  56. package/dist/graph/types.test.d.ts +2 -0
  57. package/dist/graph/types.test.d.ts.map +1 -0
  58. package/dist/graph/types.test.js +326 -0
  59. package/dist/graph/types.test.js.map +1 -0
  60. package/dist/mcp/mcp.test.d.ts +2 -0
  61. package/dist/mcp/mcp.test.d.ts.map +1 -0
  62. package/dist/mcp/mcp.test.js +151 -0
  63. package/dist/mcp/mcp.test.js.map +1 -0
  64. package/dist/mcp/server.d.ts +2 -0
  65. package/dist/mcp/server.d.ts.map +1 -0
  66. package/dist/mcp/server.js +209 -0
  67. package/dist/mcp/server.js.map +1 -0
  68. package/dist/nextjs/index.d.ts +8 -0
  69. package/dist/nextjs/index.d.ts.map +1 -0
  70. package/dist/nextjs/index.js +16 -0
  71. package/dist/nextjs/index.js.map +1 -0
  72. package/dist/nextjs/nextjs.test.d.ts +2 -0
  73. package/dist/nextjs/nextjs.test.d.ts.map +1 -0
  74. package/dist/nextjs/nextjs.test.js +190 -0
  75. package/dist/nextjs/nextjs.test.js.map +1 -0
  76. package/dist/nextjs/pages.d.ts +4 -0
  77. package/dist/nextjs/pages.d.ts.map +1 -0
  78. package/dist/nextjs/pages.js +36 -0
  79. package/dist/nextjs/pages.js.map +1 -0
  80. package/dist/nextjs/react.d.ts +3 -0
  81. package/dist/nextjs/react.d.ts.map +1 -0
  82. package/dist/nextjs/react.js +86 -0
  83. package/dist/nextjs/react.js.map +1 -0
  84. package/dist/nextjs/router.d.ts +4 -0
  85. package/dist/nextjs/router.d.ts.map +1 -0
  86. package/dist/nextjs/router.js +86 -0
  87. package/dist/nextjs/router.js.map +1 -0
  88. package/dist/nextjs/routes.d.ts +4 -0
  89. package/dist/nextjs/routes.d.ts.map +1 -0
  90. package/dist/nextjs/routes.js +58 -0
  91. package/dist/nextjs/routes.js.map +1 -0
  92. package/dist/opencode/index.d.ts +7 -0
  93. package/dist/opencode/index.d.ts.map +1 -0
  94. package/dist/opencode/index.js +71 -0
  95. package/dist/opencode/index.js.map +1 -0
  96. package/dist/opencode/index.test.d.ts +2 -0
  97. package/dist/opencode/index.test.d.ts.map +1 -0
  98. package/dist/opencode/index.test.js +71 -0
  99. package/dist/opencode/index.test.js.map +1 -0
  100. package/dist/parser/index.d.ts +4 -0
  101. package/dist/parser/index.d.ts.map +1 -0
  102. package/dist/parser/index.js +282 -0
  103. package/dist/parser/index.js.map +1 -0
  104. package/dist/parser/parser.test.d.ts +2 -0
  105. package/dist/parser/parser.test.d.ts.map +1 -0
  106. package/dist/parser/parser.test.js +225 -0
  107. package/dist/parser/parser.test.js.map +1 -0
  108. package/dist/plan/index.d.ts +32 -0
  109. package/dist/plan/index.d.ts.map +1 -0
  110. package/dist/plan/index.js +107 -0
  111. package/dist/plan/index.js.map +1 -0
  112. package/dist/plan/index.test.d.ts +2 -0
  113. package/dist/plan/index.test.d.ts.map +1 -0
  114. package/dist/plan/index.test.js +143 -0
  115. package/dist/plan/index.test.js.map +1 -0
  116. package/dist/report/index.d.ts +9 -0
  117. package/dist/report/index.d.ts.map +1 -0
  118. package/dist/report/index.js +108 -0
  119. package/dist/report/index.js.map +1 -0
  120. package/dist/scanner/index.d.ts +13 -0
  121. package/dist/scanner/index.d.ts.map +1 -0
  122. package/dist/scanner/index.js +78 -0
  123. package/dist/scanner/index.js.map +1 -0
  124. package/dist/scanner/scanner.test.d.ts +2 -0
  125. package/dist/scanner/scanner.test.d.ts.map +1 -0
  126. package/dist/scanner/scanner.test.js +113 -0
  127. package/dist/scanner/scanner.test.js.map +1 -0
  128. package/dist/search/index.d.ts +32 -0
  129. package/dist/search/index.d.ts.map +1 -0
  130. package/dist/search/index.js +97 -0
  131. package/dist/search/index.js.map +1 -0
  132. package/dist/search/search.test.d.ts +2 -0
  133. package/dist/search/search.test.d.ts.map +1 -0
  134. package/dist/search/search.test.js +446 -0
  135. package/dist/search/search.test.js.map +1 -0
  136. package/dist/traversal/index.d.ts +5 -0
  137. package/dist/traversal/index.d.ts.map +1 -0
  138. package/dist/traversal/index.js +3 -0
  139. package/dist/traversal/index.js.map +1 -0
  140. package/dist/traversal/traversal.d.ts +31 -0
  141. package/dist/traversal/traversal.d.ts.map +1 -0
  142. package/dist/traversal/traversal.js +130 -0
  143. package/dist/traversal/traversal.js.map +1 -0
  144. package/dist/traversal/traversal.test.d.ts +2 -0
  145. package/dist/traversal/traversal.test.d.ts.map +1 -0
  146. package/dist/traversal/traversal.test.js +224 -0
  147. package/dist/traversal/traversal.test.js.map +1 -0
  148. package/opencode.json +24 -0
  149. package/package.json +29 -0
  150. package/src/analysis/analysis.test.ts +405 -0
  151. package/src/analysis/complexity.ts +107 -0
  152. package/src/analysis/coupling.ts +106 -0
  153. package/src/analysis/hotspot.ts +52 -0
  154. package/src/analysis/index.ts +17 -0
  155. package/src/boundaries/index.test.ts +335 -0
  156. package/src/boundaries/index.ts +137 -0
  157. package/src/changes/index.test.ts +114 -0
  158. package/src/changes/index.ts +95 -0
  159. package/src/cli/index.ts +736 -0
  160. package/src/git/index.test.ts +92 -0
  161. package/src/git/index.ts +86 -0
  162. package/src/graph/types.test.ts +383 -0
  163. package/src/graph/types.ts +353 -0
  164. package/src/mcp/mcp.test.ts +176 -0
  165. package/src/mcp/server.ts +217 -0
  166. package/src/nextjs/index.ts +23 -0
  167. package/src/nextjs/nextjs.test.ts +233 -0
  168. package/src/nextjs/pages.ts +43 -0
  169. package/src/nextjs/react.ts +100 -0
  170. package/src/nextjs/router.ts +102 -0
  171. package/src/nextjs/routes.ts +69 -0
  172. package/src/opencode/index.test.ts +90 -0
  173. package/src/opencode/index.ts +83 -0
  174. package/src/parser/index.ts +339 -0
  175. package/src/parser/parser.test.ts +282 -0
  176. package/src/plan/index.test.ts +162 -0
  177. package/src/plan/index.ts +161 -0
  178. package/src/report/index.ts +128 -0
  179. package/src/scanner/index.ts +97 -0
  180. package/src/scanner/scanner.test.ts +135 -0
  181. package/src/search/index.ts +163 -0
  182. package/src/search/search.test.ts +512 -0
  183. package/src/traversal/index.ts +5 -0
  184. package/src/traversal/traversal.test.ts +266 -0
  185. package/src/traversal/traversal.ts +185 -0
  186. package/tsconfig.json +20 -0
  187. package/vitest.config.ts +7 -0
@@ -0,0 +1,446 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import { makeGraph, makeSymbolNode, makeCallEdge, makeImportEdge, makePackageNode, makeFileNode, serialize, } from "../graph/types.js";
6
+ import { loadGraph, findCallers, findCallees, findNode, readSource, querySymbols, findImports, findPublic, focusPackage, context, } from "./index.js";
7
+ function createTempDir() {
8
+ return fs.mkdtempSync(path.join(os.tmpdir(), "tsgraph-test-"));
9
+ }
10
+ const baseSymbols = [
11
+ makeSymbolNode({
12
+ id: "src/main.ts::serve",
13
+ name: "serve",
14
+ kind: "function",
15
+ file: "src/main.ts",
16
+ line: 10,
17
+ endLine: 20,
18
+ packageName: "app",
19
+ isExported: true,
20
+ }),
21
+ makeSymbolNode({
22
+ id: "src/main.ts::greet",
23
+ name: "greet",
24
+ kind: "function",
25
+ file: "src/main.ts",
26
+ line: 22,
27
+ endLine: 25,
28
+ packageName: "app",
29
+ isExported: true,
30
+ }),
31
+ makeSymbolNode({
32
+ id: "src/main.ts::log",
33
+ name: "log",
34
+ kind: "function",
35
+ file: "src/main.ts",
36
+ line: 27,
37
+ endLine: 29,
38
+ packageName: "app",
39
+ isExported: false,
40
+ }),
41
+ makeSymbolNode({
42
+ id: "src/utils.ts::helper",
43
+ name: "helper",
44
+ kind: "function",
45
+ file: "src/utils.ts",
46
+ line: 5,
47
+ endLine: 7,
48
+ packageName: "app",
49
+ isExported: false,
50
+ }),
51
+ ];
52
+ const baseCalls = [
53
+ makeCallEdge({
54
+ callerSymbolId: "src/main.ts::serve",
55
+ callerName: "serve",
56
+ calleeRaw: "greet",
57
+ file: "src/main.ts",
58
+ line: 12,
59
+ }),
60
+ makeCallEdge({
61
+ callerSymbolId: "src/main.ts::serve",
62
+ callerName: "serve",
63
+ calleeRaw: "log",
64
+ file: "src/main.ts",
65
+ line: 14,
66
+ }),
67
+ makeCallEdge({
68
+ callerSymbolId: "src/main.ts::greet",
69
+ callerName: "greet",
70
+ calleeRaw: "log",
71
+ file: "src/main.ts",
72
+ line: 23,
73
+ }),
74
+ ];
75
+ const baseImports = [
76
+ makeImportEdge({
77
+ fromFile: "src/main.ts",
78
+ fromPackage: "app",
79
+ importPath: "react",
80
+ alias: "React",
81
+ isDefault: true,
82
+ }),
83
+ makeImportEdge({
84
+ fromFile: "src/main.ts",
85
+ fromPackage: "app",
86
+ importPath: "react",
87
+ alias: "useState",
88
+ isDefault: false,
89
+ }),
90
+ makeImportEdge({
91
+ fromFile: "src/utils.ts",
92
+ fromPackage: "app",
93
+ importPath: "lodash",
94
+ alias: "_",
95
+ isDefault: true,
96
+ }),
97
+ ];
98
+ function buildTestGraph() {
99
+ return makeGraph({
100
+ root: "/test",
101
+ packages: [
102
+ makePackageNode({ name: "app" }),
103
+ makePackageNode({ name: "lib" }),
104
+ ],
105
+ files: [
106
+ makeFileNode({ path: "src/main.ts", packageName: "app" }),
107
+ makeFileNode({ path: "src/utils.ts", packageName: "app" }),
108
+ ],
109
+ symbols: baseSymbols,
110
+ calls: baseCalls,
111
+ imports: baseImports,
112
+ });
113
+ }
114
+ describe("loadGraph", () => {
115
+ it("round-trips from serialized file", () => {
116
+ const dir = createTempDir();
117
+ const graphPath = path.join(dir, "graph.json");
118
+ const original = buildTestGraph();
119
+ fs.writeFileSync(graphPath, serialize(original), "utf-8");
120
+ const loaded = loadGraph(graphPath);
121
+ expect(loaded.version).toBe(original.version);
122
+ expect(loaded.symbols).toHaveLength(original.symbols.length);
123
+ expect(loaded.calls).toHaveLength(original.calls.length);
124
+ fs.rmSync(dir, { recursive: true });
125
+ });
126
+ it("throws on missing file", () => {
127
+ expect(() => loadGraph("/nonexistent/graph.json")).toThrow();
128
+ });
129
+ });
130
+ describe("findCallers", () => {
131
+ it("finds callers of a referenced symbol", () => {
132
+ const graph = buildTestGraph();
133
+ const results = findCallers(graph, "greet");
134
+ expect(results).toHaveLength(1);
135
+ expect(results[0].callerSymbol.name).toBe("serve");
136
+ expect(results[0].edges).toHaveLength(1);
137
+ });
138
+ it("finds multiple callers of a symbol", () => {
139
+ const graph = buildTestGraph();
140
+ const results = findCallers(graph, "log");
141
+ expect(results).toHaveLength(2);
142
+ const names = results.map((r) => r.callerSymbol.name).sort();
143
+ expect(names).toEqual(["greet", "serve"]);
144
+ });
145
+ it("returns empty for unreferenced symbol", () => {
146
+ const graph = buildTestGraph();
147
+ const results = findCallers(graph, "helper");
148
+ expect(results).toHaveLength(0);
149
+ });
150
+ it("returns empty for unknown symbol", () => {
151
+ const graph = buildTestGraph();
152
+ const results = findCallers(graph, "nonexistent");
153
+ expect(results).toHaveLength(0);
154
+ });
155
+ });
156
+ describe("findCallees", () => {
157
+ it("finds callees of a function", () => {
158
+ const graph = buildTestGraph();
159
+ const results = findCallees(graph, "serve");
160
+ expect(results).toHaveLength(2);
161
+ const names = results.map((r) => r.calleeRaw).sort();
162
+ expect(names).toEqual(["greet", "log"]);
163
+ });
164
+ it("finds callees with multiple call sites", () => {
165
+ const graph = buildTestGraph();
166
+ const results = findCallees(graph, "greet");
167
+ expect(results).toHaveLength(1);
168
+ expect(results[0].calleeRaw).toBe("log");
169
+ expect(results[0].edges).toHaveLength(1);
170
+ });
171
+ it("returns empty for leaf function", () => {
172
+ const graph = buildTestGraph();
173
+ const results = findCallees(graph, "log");
174
+ expect(results).toHaveLength(0);
175
+ });
176
+ it("returns empty for unknown symbol", () => {
177
+ const graph = buildTestGraph();
178
+ const results = findCallees(graph, "noop");
179
+ expect(results).toHaveLength(0);
180
+ });
181
+ });
182
+ describe("findNode", () => {
183
+ it("finds a symbol by exact name", () => {
184
+ const graph = buildTestGraph();
185
+ const n = findNode(graph, "serve");
186
+ expect(n).toBeTruthy();
187
+ expect(n.kind).toBe("function");
188
+ expect(n.file).toBe("src/main.ts");
189
+ });
190
+ it("returns undefined for missing symbol", () => {
191
+ const graph = buildTestGraph();
192
+ const n = findNode(graph, "noop");
193
+ expect(n).toBeUndefined();
194
+ });
195
+ it("returns first match when names collide", () => {
196
+ const graph = buildTestGraph();
197
+ // Two symbols with same name in different files
198
+ graph.symbols.push(makeSymbolNode({
199
+ id: "src/other.ts::serve",
200
+ name: "serve",
201
+ file: "src/other.ts",
202
+ }));
203
+ const n = findNode(graph, "serve");
204
+ expect(n).toBeTruthy();
205
+ expect(n.file).toBe("src/main.ts"); // first in array
206
+ });
207
+ });
208
+ describe("readSource", () => {
209
+ it("extracts the correct line range from a file", () => {
210
+ const dir = createTempDir();
211
+ const root = dir;
212
+ const filePath = path.join(root, "src/main.ts");
213
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
214
+ fs.writeFileSync(filePath, [
215
+ "line 1",
216
+ "line 2",
217
+ "line 3",
218
+ "line 4",
219
+ "line 5",
220
+ ].join("\n"), "utf-8");
221
+ const graph = makeGraph({
222
+ root,
223
+ files: [makeFileNode({ path: "src/main.ts" })],
224
+ symbols: [
225
+ makeSymbolNode({
226
+ id: "src/main.ts::foo",
227
+ name: "foo",
228
+ file: "src/main.ts",
229
+ line: 2,
230
+ endLine: 4,
231
+ }),
232
+ ],
233
+ });
234
+ const sym = graph.symbols[0];
235
+ const src = readSource(graph, sym);
236
+ expect(src).toContain("line 2");
237
+ expect(src).toContain("line 3");
238
+ expect(src).toContain("line 4");
239
+ expect(src).not.toContain("line 1");
240
+ expect(src).not.toContain("line 5");
241
+ // should include line numbers
242
+ expect(src).toMatch(/^2 /m);
243
+ expect(src).toMatch(/^3 /m);
244
+ expect(src).toMatch(/^4 /m);
245
+ fs.rmSync(dir, { recursive: true });
246
+ });
247
+ it("throws on missing file", () => {
248
+ const graph = makeGraph({
249
+ root: "/nonexistent",
250
+ symbols: [
251
+ makeSymbolNode({ name: "foo", file: "foo.ts", line: 1, endLine: 3 }),
252
+ ],
253
+ });
254
+ expect(() => readSource(graph, graph.symbols[0])).toThrow();
255
+ });
256
+ });
257
+ describe("querySymbols", () => {
258
+ it("matches symbol name case-insensitively", () => {
259
+ const graph = buildTestGraph();
260
+ const results = querySymbols(graph, "GREET");
261
+ expect(results).toHaveLength(1);
262
+ expect(results[0].name).toBe("greet");
263
+ });
264
+ it("matches file path", () => {
265
+ const graph = buildTestGraph();
266
+ const results = querySymbols(graph, "utils");
267
+ expect(results).toHaveLength(1);
268
+ expect(results[0].name).toBe("helper");
269
+ });
270
+ it("matches package name", () => {
271
+ const graph = buildTestGraph();
272
+ const results = querySymbols(graph, "app");
273
+ // all 4 symbols are in package "app"
274
+ expect(results.length).toBeGreaterThanOrEqual(4);
275
+ });
276
+ it("returns all symbols for empty pattern", () => {
277
+ const graph = buildTestGraph();
278
+ const results = querySymbols(graph, "");
279
+ expect(results).toHaveLength(graph.symbols.length);
280
+ });
281
+ it("returns empty for no match", () => {
282
+ const graph = buildTestGraph();
283
+ const results = querySymbols(graph, "zzznone");
284
+ expect(results).toHaveLength(0);
285
+ });
286
+ });
287
+ describe("findImports", () => {
288
+ it("matches import path substring", () => {
289
+ const graph = buildTestGraph();
290
+ const results = findImports(graph, "react");
291
+ expect(results).toHaveLength(2);
292
+ });
293
+ it("returns empty for no match", () => {
294
+ const graph = buildTestGraph();
295
+ const results = findImports(graph, "noop");
296
+ expect(results).toHaveLength(0);
297
+ });
298
+ it("is case-insensitive", () => {
299
+ const graph = buildTestGraph();
300
+ const results = findImports(graph, "LODASH");
301
+ expect(results).toHaveLength(1);
302
+ expect(results[0].importPath).toBe("lodash");
303
+ });
304
+ });
305
+ describe("findPublic", () => {
306
+ it("returns only exported symbols", () => {
307
+ const graph = buildTestGraph();
308
+ const results = findPublic(graph);
309
+ expect(results).toHaveLength(2);
310
+ expect(results.every((s) => s.isExported)).toBe(true);
311
+ const names = results.map((s) => s.name).sort();
312
+ expect(names).toEqual(["greet", "serve"]);
313
+ });
314
+ it("scopes to a package when specified", () => {
315
+ const graph = buildTestGraph();
316
+ // Add an exported symbol in package "lib"
317
+ graph.symbols.push(makeSymbolNode({
318
+ id: "lib/helper.ts::run",
319
+ name: "run",
320
+ kind: "function",
321
+ packageName: "lib",
322
+ isExported: true,
323
+ }));
324
+ const results = findPublic(graph, "lib");
325
+ expect(results).toHaveLength(1);
326
+ expect(results[0].name).toBe("run");
327
+ });
328
+ it("returns empty when no exported symbols in package", () => {
329
+ const graph = buildTestGraph();
330
+ const results = findPublic(graph, "missing-pkg");
331
+ expect(results).toHaveLength(0);
332
+ });
333
+ });
334
+ describe("focusPackage", () => {
335
+ it("returns package assets", () => {
336
+ const graph = buildTestGraph();
337
+ const result = focusPackage(graph, "app");
338
+ expect(result).toBeTruthy();
339
+ expect(result.pkg.name).toBe("app");
340
+ expect(result.files).toHaveLength(2);
341
+ expect(result.symbols).toHaveLength(4);
342
+ expect(result.imports).toHaveLength(3);
343
+ });
344
+ it("returns undefined for missing package", () => {
345
+ const graph = buildTestGraph();
346
+ const result = focusPackage(graph, "no-pkg");
347
+ expect(result).toBeUndefined();
348
+ });
349
+ });
350
+ describe("context", () => {
351
+ it("bundles node, source, callers, and callees", () => {
352
+ const dir = createTempDir();
353
+ const root = dir;
354
+ const filePath = path.join(root, "src/main.ts");
355
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
356
+ const fileLines = [
357
+ "",
358
+ "",
359
+ "",
360
+ "",
361
+ "",
362
+ "",
363
+ "",
364
+ "",
365
+ "",
366
+ "function serve() {",
367
+ " greet();",
368
+ " log();",
369
+ "}",
370
+ "",
371
+ "",
372
+ "function greet() {",
373
+ " log();",
374
+ "}",
375
+ ];
376
+ fs.writeFileSync(filePath, fileLines.join("\n"), "utf-8");
377
+ const graph = makeGraph({
378
+ root,
379
+ packages: [makePackageNode({ name: "app" })],
380
+ files: [makeFileNode({ path: "src/main.ts", packageName: "app" })],
381
+ symbols: [
382
+ makeSymbolNode({
383
+ id: "src/main.ts::serve",
384
+ name: "serve",
385
+ kind: "function",
386
+ file: "src/main.ts",
387
+ line: 10,
388
+ endLine: 13,
389
+ packageName: "app",
390
+ isExported: true,
391
+ }),
392
+ makeSymbolNode({
393
+ id: "src/main.ts::greet",
394
+ name: "greet",
395
+ kind: "function",
396
+ file: "src/main.ts",
397
+ line: 16,
398
+ endLine: 18,
399
+ packageName: "app",
400
+ isExported: true,
401
+ }),
402
+ ],
403
+ calls: [
404
+ makeCallEdge({
405
+ callerSymbolId: "src/main.ts::serve",
406
+ callerName: "serve",
407
+ calleeRaw: "greet",
408
+ file: "src/main.ts",
409
+ line: 11,
410
+ }),
411
+ makeCallEdge({
412
+ callerSymbolId: "src/main.ts::serve",
413
+ callerName: "serve",
414
+ calleeRaw: "log",
415
+ file: "src/main.ts",
416
+ line: 12,
417
+ }),
418
+ ],
419
+ });
420
+ const ctx = context(graph, "serve");
421
+ expect(ctx.node).toBeTruthy();
422
+ expect(ctx.node.name).toBe("serve");
423
+ expect(ctx.source).toBeTruthy();
424
+ expect(ctx.source).toContain("greet");
425
+ expect(ctx.callers).toHaveLength(0);
426
+ expect(ctx.callees).toHaveLength(2);
427
+ fs.rmSync(dir, { recursive: true });
428
+ });
429
+ it("returns empty source when file is missing", () => {
430
+ const graph = buildTestGraph();
431
+ const ctx = context(graph, "serve");
432
+ expect(ctx.node).toBeTruthy();
433
+ expect(ctx.source).toBeUndefined();
434
+ expect(ctx.callers).toHaveLength(0);
435
+ expect(ctx.callees).toHaveLength(2);
436
+ });
437
+ it("returns partial result for missing symbol", () => {
438
+ const graph = buildTestGraph();
439
+ const ctx = context(graph, "noop");
440
+ expect(ctx.node).toBeUndefined();
441
+ expect(ctx.source).toBeUndefined();
442
+ expect(ctx.callers).toHaveLength(0);
443
+ expect(ctx.callees).toHaveLength(0);
444
+ });
445
+ });
446
+ //# sourceMappingURL=search.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../src/search/search.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { impact, findPath, findOrphans, trace } from "./traversal.js";
2
+ import type { ImpactNode, PathNode, OrphanResult, TraceResult, TraceMatch } from "./traversal.js";
3
+ export { impact, findPath, findOrphans, trace };
4
+ export type { ImpactNode, PathNode, OrphanResult, TraceResult, TraceMatch };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/traversal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAElG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { impact, findPath, findOrphans, trace } from "./traversal.js";
2
+ export { impact, findPath, findOrphans, trace };
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/traversal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { Graph, SymbolNode } from "../graph/types.js";
2
+ export interface ImpactNode {
3
+ symbol: SymbolNode;
4
+ depth: number;
5
+ callChain: string[];
6
+ }
7
+ export declare function impact(graph: Graph, symbolName: string, maxDepth?: number): ImpactNode[];
8
+ export interface PathNode {
9
+ name: string;
10
+ kind: string;
11
+ file: string;
12
+ line: number;
13
+ }
14
+ export declare function findPath(graph: Graph, fromName: string, toName: string, maxDepth?: number): PathNode[] | undefined;
15
+ export interface OrphanResult {
16
+ symbol: SymbolNode;
17
+ reason: string;
18
+ }
19
+ export declare function findOrphans(graph: Graph): OrphanResult[];
20
+ export interface TraceMatch {
21
+ symbol: SymbolNode;
22
+ file: string;
23
+ line: number;
24
+ contextLine: string;
25
+ }
26
+ export interface TraceResult {
27
+ match: TraceMatch;
28
+ callers: ImpactNode[];
29
+ }
30
+ export declare function trace(graph: Graph, searchString: string, maxDepth?: number): TraceResult[];
31
+ //# sourceMappingURL=traversal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traversal.d.ts","sourceRoot":"","sources":["../../src/traversal/traversal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAU,GACnB,UAAU,EAAE,CAgCd;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,QAAQ,CACtB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAW,GACpB,QAAQ,EAAE,GAAG,SAAS,CA2CxB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,YAAY,EAAE,CAoBxD;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,wBAAgB,KAAK,CACnB,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,MAAM,EACpB,QAAQ,GAAE,MAAU,GACnB,WAAW,EAAE,CAoCf"}
@@ -0,0 +1,130 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ export function impact(graph, symbolName, maxDepth = 5) {
4
+ const start = graph.symbols.find((s) => s.name === symbolName);
5
+ if (!start)
6
+ return [];
7
+ const results = [];
8
+ const visited = new Set();
9
+ const queue = [
10
+ { sym: start, depth: 0, chain: [start.name] },
11
+ ];
12
+ visited.add(start.id);
13
+ while (queue.length > 0) {
14
+ const { sym, depth, chain } = queue.shift();
15
+ if (depth > 0) {
16
+ results.push({ symbol: sym, depth, callChain: chain });
17
+ }
18
+ if (depth >= maxDepth)
19
+ continue;
20
+ const callers = graph.calls.filter((c) => c.calleeRaw === sym.name);
21
+ for (const edge of callers) {
22
+ const caller = graph.symbols.find((s) => s.id === edge.callerSymbolId);
23
+ if (!caller || visited.has(caller.id))
24
+ continue;
25
+ visited.add(caller.id);
26
+ queue.push({
27
+ sym: caller,
28
+ depth: depth + 1,
29
+ chain: [...chain, caller.name],
30
+ });
31
+ }
32
+ }
33
+ return results;
34
+ }
35
+ export function findPath(graph, fromName, toName, maxDepth = 10) {
36
+ const from = graph.symbols.find((s) => s.name === fromName);
37
+ const to = graph.symbols.find((s) => s.name === toName);
38
+ if (!from || !to)
39
+ return undefined;
40
+ if (from.id === to.id)
41
+ return [{ name: from.name, kind: from.kind, file: from.file, line: from.line }];
42
+ const visited = new Set();
43
+ const parent = new Map();
44
+ const queue = [from.id];
45
+ visited.add(from.id);
46
+ while (queue.length > 0) {
47
+ const currentId = queue.shift();
48
+ const current = graph.symbols.find((s) => s.id === currentId);
49
+ if (!current)
50
+ continue;
51
+ const calleeEdges = graph.calls.filter((c) => c.callerSymbolId === currentId);
52
+ for (const edge of calleeEdges) {
53
+ const callee = graph.symbols.find((s) => s.name === edge.calleeRaw);
54
+ if (!callee || visited.has(callee.id))
55
+ continue;
56
+ visited.add(callee.id);
57
+ parent.set(callee.id, {
58
+ prev: currentId,
59
+ edge: { name: callee.name, kind: callee.kind, file: callee.file, line: callee.line },
60
+ });
61
+ if (callee.id === to.id) {
62
+ const pathNodes = [];
63
+ let step = to.id;
64
+ while (step) {
65
+ const sym = graph.symbols.find((s) => s.id === step);
66
+ pathNodes.unshift({ name: sym.name, kind: sym.kind, file: sym.file, line: sym.line });
67
+ const p = parent.get(step);
68
+ step = p?.prev;
69
+ }
70
+ return pathNodes;
71
+ }
72
+ queue.push(callee.id);
73
+ }
74
+ }
75
+ return undefined;
76
+ }
77
+ export function findOrphans(graph) {
78
+ const calledNames = new Set(graph.calls.map((c) => c.calleeRaw));
79
+ const testTargets = new Set(graph.testEdges.map((t) => t.target));
80
+ const results = [];
81
+ for (const sym of graph.symbols) {
82
+ if (sym.isExported) {
83
+ const incomingCallers = graph.calls.filter((c) => c.calleeRaw === sym.name);
84
+ if (incomingCallers.length === 0 && !testTargets.has(sym.name)) {
85
+ results.push({ symbol: sym, reason: "exported but no callers or tests" });
86
+ }
87
+ }
88
+ else {
89
+ if (!calledNames.has(sym.name) && !testTargets.has(sym.name)) {
90
+ results.push({ symbol: sym, reason: "unexported, no callers or tests" });
91
+ }
92
+ }
93
+ }
94
+ return results;
95
+ }
96
+ export function trace(graph, searchString, maxDepth = 5) {
97
+ const lowerSearch = searchString.toLowerCase();
98
+ const results = [];
99
+ for (const sym of graph.symbols) {
100
+ if (sym.kind !== "function" && sym.kind !== "method")
101
+ continue;
102
+ const filePath = path.join(graph.root, sym.file);
103
+ let content;
104
+ try {
105
+ content = fs.readFileSync(filePath, "utf-8");
106
+ }
107
+ catch {
108
+ continue;
109
+ }
110
+ const lines = content.split("\n");
111
+ const start = Math.max(0, sym.line - 1);
112
+ const end = Math.min(lines.length, sym.endLine);
113
+ for (let i = start; i < end; i++) {
114
+ if (lines[i].toLowerCase().includes(lowerSearch)) {
115
+ const impactNodes = impact(graph, sym.name, maxDepth);
116
+ results.push({
117
+ match: {
118
+ symbol: sym,
119
+ file: sym.file,
120
+ line: i + 1,
121
+ contextLine: lines[i].trim(),
122
+ },
123
+ callers: impactNodes,
124
+ });
125
+ }
126
+ }
127
+ }
128
+ return results;
129
+ }
130
+ //# sourceMappingURL=traversal.js.map