repo-codegraph 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +462 -2
  2. package/dist/analyzer/analyzeProject.d.ts +17 -0
  3. package/dist/analyzer/analyzeProject.d.ts.map +1 -0
  4. package/dist/analyzer/analyzeProject.js +338 -0
  5. package/dist/analyzer/analyzeProject.js.map +1 -0
  6. package/dist/analyzer/buildDefinitionGraph.d.ts +47 -0
  7. package/dist/analyzer/buildDefinitionGraph.d.ts.map +1 -0
  8. package/dist/analyzer/buildDefinitionGraph.js +60 -0
  9. package/dist/analyzer/buildDefinitionGraph.js.map +1 -0
  10. package/dist/analyzer/incrementalIndex.d.ts +21 -0
  11. package/dist/analyzer/incrementalIndex.d.ts.map +1 -0
  12. package/dist/analyzer/incrementalIndex.js +115 -0
  13. package/dist/analyzer/incrementalIndex.js.map +1 -0
  14. package/dist/cli.d.ts +3 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +249 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/files/discoverSourceFiles.d.ts +8 -0
  19. package/dist/files/discoverSourceFiles.d.ts.map +1 -0
  20. package/dist/files/discoverSourceFiles.js +46 -0
  21. package/dist/files/discoverSourceFiles.js.map +1 -0
  22. package/dist/git/diffImpact.d.ts +22 -0
  23. package/dist/git/diffImpact.d.ts.map +1 -0
  24. package/dist/git/diffImpact.js +113 -0
  25. package/dist/git/diffImpact.js.map +1 -0
  26. package/dist/graph/DirectedGraph.d.ts +44 -0
  27. package/dist/graph/DirectedGraph.d.ts.map +1 -0
  28. package/dist/graph/DirectedGraph.js +258 -0
  29. package/dist/graph/DirectedGraph.js.map +1 -0
  30. package/dist/graph/types.d.ts +13 -0
  31. package/dist/graph/types.d.ts.map +1 -0
  32. package/dist/graph/types.js +2 -0
  33. package/dist/graph/types.js.map +1 -0
  34. package/dist/index.d.ts +21 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +13 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/mcp/projectSession.d.ts +18 -0
  39. package/dist/mcp/projectSession.d.ts.map +1 -0
  40. package/dist/mcp/projectSession.js +86 -0
  41. package/dist/mcp/projectSession.js.map +1 -0
  42. package/dist/mcp/server.d.ts +23 -0
  43. package/dist/mcp/server.d.ts.map +1 -0
  44. package/dist/mcp/server.js +512 -0
  45. package/dist/mcp/server.js.map +1 -0
  46. package/dist/mcp/stdio.d.ts +3 -0
  47. package/dist/mcp/stdio.d.ts.map +1 -0
  48. package/dist/mcp/stdio.js +35 -0
  49. package/dist/mcp/stdio.js.map +1 -0
  50. package/dist/parser/extractDeclarations.d.ts +30 -0
  51. package/dist/parser/extractDeclarations.d.ts.map +1 -0
  52. package/dist/parser/extractDeclarations.js +83 -0
  53. package/dist/parser/extractDeclarations.js.map +1 -0
  54. package/dist/parser/parseSourceFile.d.ts +4 -0
  55. package/dist/parser/parseSourceFile.d.ts.map +1 -0
  56. package/dist/parser/parseSourceFile.js +9 -0
  57. package/dist/parser/parseSourceFile.js.map +1 -0
  58. package/dist/persistence/jsonPersistence.d.ts +7 -0
  59. package/dist/persistence/jsonPersistence.d.ts.map +1 -0
  60. package/dist/persistence/jsonPersistence.js +98 -0
  61. package/dist/persistence/jsonPersistence.js.map +1 -0
  62. package/dist/queries/analyzeImpact.d.ts +14 -0
  63. package/dist/queries/analyzeImpact.d.ts.map +1 -0
  64. package/dist/queries/analyzeImpact.js +56 -0
  65. package/dist/queries/analyzeImpact.js.map +1 -0
  66. package/dist/queries/codeGraphQueries.d.ts +7 -0
  67. package/dist/queries/codeGraphQueries.d.ts.map +1 -0
  68. package/dist/queries/codeGraphQueries.js +86 -0
  69. package/dist/queries/codeGraphQueries.js.map +1 -0
  70. package/dist/visualization/viewer.d.ts +17 -0
  71. package/dist/visualization/viewer.d.ts.map +1 -0
  72. package/dist/visualization/viewer.js +349 -0
  73. package/dist/visualization/viewer.js.map +1 -0
  74. package/package.json +55 -3
package/README.md CHANGED
@@ -1,3 +1,463 @@
1
- # Temporary Holding Version
1
+ # Codegraph
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Codegraph statically analyzes TypeScript repositories and exposes source-code
4
+ relationships as a directed graph. The current in-memory engine discovers source
5
+ files, parses declarations, resolves internal modules and compiler-resolvable calls,
6
+ answers graph queries, calculates reverse impact, and maps tracked Git changes to
7
+ the smallest enclosing current symbol.
8
+
9
+ ![Codegraph interactive network visualization](docs/assets/interactive-network-graph.png)
10
+
11
+ ## Current capabilities
12
+
13
+ - File, function, class, interface, and method nodes with source ranges.
14
+ - `DEFINES`, `IMPORTS`, and `CALLS` edges with provenance and confidence.
15
+ - Relative imports, configured TypeScript path aliases, and barrel re-exports.
16
+ - Default, named, namespace, aliased, and side-effect import syntax.
17
+ - Direct, imported, `this`, concrete-object, injected-object, and interface calls
18
+ when TypeScript can resolve an indexed declaration.
19
+ - Symbol search, dependencies, dependents, shortest paths, reverse impact, and
20
+ Git-diff impact analysis.
21
+ - A local stdio MCP server with bounded, source-linked tools for coding agents.
22
+ - A local, interactive force-directed visualization with search, filters, and
23
+ focused dependency neighborhoods.
24
+
25
+ ## CLI
26
+
27
+ During development:
28
+
29
+ ```bash
30
+ npm run codegraph -- index .
31
+ npm run codegraph -- find AuthService --root .
32
+ npm run codegraph -- deps AuthService.login --root .
33
+ npm run codegraph -- dependents AuthService.login --root .
34
+ npm run codegraph -- path AuthController.login TokenService.generate --root .
35
+ npm run codegraph -- impact AuthService.validateToken --root .
36
+ npm run codegraph -- diff --root .
37
+ npm run codegraph -- visualize .
38
+ ```
39
+
40
+ `index` writes a versioned JSON snapshot to `.codegraph/index.json`. Query
41
+ commands rebuild from source by default; pass `--graph` to explicitly reuse the
42
+ snapshot when startup speed matters:
43
+
44
+ ```bash
45
+ npm run codegraph -- index .
46
+ npm run codegraph -- find AuthService --graph .codegraph/index.json
47
+ npm run codegraph -- impact AuthService.login --graph .codegraph/index.json
48
+ ```
49
+
50
+ After indexing, open the interactive network in the default browser:
51
+
52
+ ```bash
53
+ npm run codegraph -- visualize .
54
+ ```
55
+
56
+ The viewer reads `.codegraph/index.json`, binds only to `127.0.0.1`, and contains
57
+ no CDN scripts or hosted services, so the graph stays on the user's machine.
58
+ Use `--graph <file>` for a custom index, `--port <number>` for a fixed port, or
59
+ `--no-open` to print the URL without launching a browser. Scroll to zoom, drag
60
+ to pan, search by file or symbol, filter relationship types, and click a node to
61
+ focus on its immediate incoming and outgoing neighborhood.
62
+ Hovering over a node reveals its file or symbol name without permanently
63
+ cluttering the graph with labels.
64
+
65
+ To create a self-contained file that can be opened in an IDE HTML preview,
66
+ export the same visualization instead of starting the local server:
67
+
68
+ ```bash
69
+ npm run codegraph -- visualize . --output .codegraph/visualization.html
70
+ ```
71
+
72
+ All graph data, styles, and interaction code are embedded in the generated HTML;
73
+ it does not fetch the index or load scripts from the network.
74
+
75
+ The **Ask Codegraph** box supports local graph questions such as “What calls
76
+ `analyzeProject`?”, “What does `runCli` call?”, “What imports `server.ts`?”, and
77
+ “Where is `ProjectSession` defined?”. It matches the question to indexed files
78
+ and symbols, selects the relevant relationship and direction, focuses the graph,
79
+ and lists connected nodes. This is deterministic graph querying rather than an
80
+ LLM, so it does not send repository data to an external service.
81
+ Source paths in node details and question results are IDE deep links; clicking
82
+ one opens the indexed file at its source line in VS Code-compatible editors.
83
+ Change-impact questions use incoming `CALLS` relationships, so they show callers
84
+ that may be affected rather than functions the changed symbol itself depends on.
85
+
86
+ After source files change, update the saved index incrementally:
87
+
88
+ ```bash
89
+ npm run codegraph -- update .
90
+ ```
91
+
92
+ `update` hashes current source files, detects additions, edits, and deletions,
93
+ expands the affected set through reverse imports, replaces stale nodes and edges,
94
+ and reuses unaffected graph data. Use `--graph <file>` when the index is stored
95
+ somewhere other than `.codegraph/index.json`.
96
+
97
+ Use `--output <file>` to choose another index location. A cached graph can become
98
+ stale after source edits, so rerun `index` before relying on cached results. JSON
99
+ is used because the current workflow writes and loads the whole graph and benefits
100
+ from a portable, inspectable format. SQLite should be reconsidered when incremental
101
+ indexing requires partial updates, database indexes, transactions, or concurrent
102
+ readers.
103
+
104
+ `deps` and `dependents` follow `CALLS` for symbols and `IMPORTS` for file paths.
105
+ `path` uses BFS and therefore returns a minimum-edge path across `CALLS` and
106
+ `IMPORTS`. `impact` performs reverse BFS with cycle protection.
107
+
108
+ ## MCP for coding agents
109
+
110
+ The npm package includes a second executable, `codegraph-mcp`. It is a local
111
+ stdio process, not a hosted service: the coding agent starts it inside the
112
+ consumer repository and communicates with it using MCP messages.
113
+
114
+ Install the package in the TypeScript project that should be analyzed:
115
+
116
+ ```bash
117
+ npm install --save-dev codegraph
118
+ ```
119
+
120
+ The MCP client launches the project-local executable with:
121
+
122
+ ```bash
123
+ npx --no-install codegraph-mcp --root .
124
+ ```
125
+
126
+ `--root` identifies the repository Codegraph should index and defaults to the
127
+ process working directory. Use `--index <file>` to override the default
128
+ `.codegraph/index.json` location.
129
+
130
+ ### Codex
131
+
132
+ Run from the consumer project root:
133
+
134
+ ```bash
135
+ codex mcp add codegraph -- npx --no-install codegraph-mcp --root .
136
+ codex mcp list
137
+ ```
138
+
139
+ ### Claude Code
140
+
141
+ Run from the consumer project root:
142
+
143
+ ```bash
144
+ claude mcp add codegraph --scope project -- npx --no-install codegraph-mcp --root .
145
+ claude mcp list
146
+ ```
147
+
148
+ Claude Code stores the shared project configuration in `.mcp.json`.
149
+
150
+ ### Cursor
151
+
152
+ Create `.cursor/mcp.json` in the consumer project:
153
+
154
+ ```json
155
+ {
156
+ "mcpServers": {
157
+ "codegraph": {
158
+ "command": "npx",
159
+ "args": ["--no-install", "codegraph-mcp", "--root", "."]
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ Restart Cursor after adding the configuration.
166
+
167
+ ### Other MCP clients
168
+
169
+ Any MCP client that supports local stdio servers can use the same executable.
170
+ The configuration filename and location depend on the client, but the common
171
+ configuration shape is:
172
+
173
+ ```json
174
+ {
175
+ "mcpServers": {
176
+ "codegraph": {
177
+ "command": "npx",
178
+ "args": ["--no-install", "codegraph-mcp", "--root", "."]
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ The server exposes a deliberately small surface:
185
+
186
+ | Tool | Purpose |
187
+ | --- | --- |
188
+ | `find_symbol` | Resolve a name to stable node IDs and source ranges. |
189
+ | `get_dependencies` | Follow immediate outgoing `CALLS` or `IMPORTS`. |
190
+ | `get_dependents` | Follow immediate incoming `CALLS` or `IMPORTS`. |
191
+ | `find_path` | Find a bounded minimum-edge path between two nodes. |
192
+ | `analyze_impact` | Calculate bounded direct and transitive reverse impact. |
193
+ | `analyze_diff` | Map the tracked Git diff to symbols and blast radius. |
194
+ | `refresh_index` | Refresh the in-memory graph and persisted JSON index. |
195
+
196
+ All query tools are read-only. Results include repository-relative source paths
197
+ and ranges so an agent can read only the relevant code with its normal file
198
+ tools. Limits and depth bounds prevent dumping the complete graph into model
199
+ context. The server builds a fresh in-memory graph on the first query; agents
200
+ should call `refresh_index` after editing source files.
201
+
202
+ To make tool selection more reliable, add equivalent instructions to
203
+ `AGENTS.md`, `CLAUDE.md`, or the MCP client's project rules:
204
+
205
+ ```md
206
+ Use the CodeGraph MCP tools when investigating this TypeScript codebase.
207
+
208
+ Before modifying an existing symbol:
209
+
210
+ 1. Use `find_symbol` to locate it.
211
+ 2. Use `get_dependencies` to understand what it uses.
212
+ 3. Use `get_dependents` or `analyze_impact` to identify what could break.
213
+ 4. After editing source files, call `refresh_index`.
214
+ 5. Use `analyze_diff` to review the impact of the changes.
215
+
216
+ Prefer concise CodeGraph results over reading unrelated files.
217
+ ```
218
+
219
+ Applications embedding Codegraph can also construct the server themselves and
220
+ connect any MCP transport:
221
+
222
+ ```ts
223
+ import { createCodeGraphMcpServer } from "codegraph/mcp";
224
+
225
+ const server = createCodeGraphMcpServer({ rootDirectory: process.cwd() });
226
+ ```
227
+
228
+ ## Static-analysis limits
229
+
230
+ - Dynamic element calls such as `handlers[type]()` may remain unresolved.
231
+ - Calls inside arrow functions and anonymous function expressions are not assigned
232
+ to a caller node yet because those declarations are not modeled.
233
+ - Interface dispatch points to the compile-time interface method with `inferred`
234
+ confidence; it does not guess a runtime implementation.
235
+ - Package and standard-library targets are intentionally outside the project graph.
236
+ - Multiple calls between the same two symbols currently produce one `CALLS` edge.
237
+ - Overloads and declaration merging can collide under the current syntax-derived
238
+ symbol IDs and need semantic identity work.
239
+ - `codegraph diff` analyzes tracked changes relative to `HEAD`. Untracked files and
240
+ deleted symbols are not recoverable from the current AST, and changed lines outside
241
+ modeled declarations are reported as unmapped.
242
+ - Query commands rebuild from source unless `--graph` explicitly selects a persisted
243
+ JSON index. `update` performs incremental graph replacement, but it still creates a
244
+ fresh project-wide TypeScript Program so semantic resolution remains correct.
245
+
246
+ ## Releasing
247
+
248
+ The first npm release was published manually. Subsequent versions publish
249
+ automatically when a GitHub Release is published. Before creating the release:
250
+
251
+ 1. Update `version` in `package.json` and `package-lock.json`.
252
+ 2. Merge that version change to `main`.
253
+ 3. Create and publish a GitHub Release whose tag is exactly `v<version>` (for
254
+ example, package version `0.2.0` requires tag `v0.2.0`).
255
+
256
+ The release workflow verifies the tag, installs from the lockfile, runs the type
257
+ check, tests, and build, then publishes the public package to npm. The npm package
258
+ must have `.github/workflows/publish.yml` configured as a GitHub Actions trusted
259
+ publisher for repository `RuchiPurohit/codegraph` with direct `npm publish`
260
+ allowed. No long-lived npm token is required.
261
+
262
+ ## The graph model
263
+
264
+ A **node** (or vertex) represents an entity. An **edge** represents a relationship
265
+ between two nodes. In a directed graph, the arrow has meaning:
266
+
267
+ ```text
268
+ AuthController.login --CALLS--> AuthService.login --CALLS--> TokenService.generate
269
+ ```
270
+
271
+ The first method calls—and therefore depends on—the second. If `A -> B` means A
272
+ depends on B, `dependencies(A)` follows outgoing arrows and `dependents(B)` follows
273
+ incoming arrows backward. These queries answer different questions:
274
+
275
+ ```text
276
+ dependencies(AuthController.login) = [AuthService.login]
277
+ dependents(AuthService.login) = [AuthController.login]
278
+ ```
279
+
280
+ An **outgoing edge** starts at the node being examined; an **incoming edge** ends
281
+ there. An **adjacency list** stores each node beside its outgoing relationships. A
282
+ **reverse adjacency list** stores incoming relationships too. A **traversal** visits
283
+ reachable nodes by following edges. A **cycle** is a path that returns to an already
284
+ visited node, such as `A -> B -> C -> A`. Nodes are **disconnected** when no path in
285
+ the chosen direction connects them; a traversal from one component cannot visit
286
+ another.
287
+
288
+ A directed graph fits Codegraph because relationships such as `CALLS`, `IMPORTS`,
289
+ and `EXTENDS` are directional. Who a function calls and who calls that function are
290
+ both important, but they are not interchangeable.
291
+
292
+ ## Representation choice
293
+
294
+ Let `V` be the number of nodes and `E` the number of edges.
295
+
296
+ | Representation | Storage | Add edge | Get outgoing neighbors | Good fit? |
297
+ | --- | ---: | ---: | ---: | --- |
298
+ | Adjacency matrix | `O(V²)` | `O(1)` | `O(V)` | Fast edge checks, but wasteful for sparse graphs |
299
+ | Adjacency list | `O(V + E)` | expected `O(1)` | `O(out-degree)` | Best fit for Codegraph |
300
+ | Edge list | `O(E)` | `O(1)` | `O(E)` | Simple storage, slow relationship queries |
301
+
302
+ Source-code graphs are generally sparse: each symbol relates to a small fraction
303
+ of all symbols. An adjacency list stores relationships that actually exist. This
304
+ implementation stores both outgoing and reverse adjacency, using more memory—each
305
+ edge is indexed twice—to make both dependencies and dependents efficient.
306
+
307
+ The nested shape is:
308
+
309
+ ```text
310
+ Map<node id, Map<neighbor id, Map<edge type, edge>>>
311
+ ```
312
+
313
+ The final map makes `(from, to, type)` the edge identity. Thus duplicate `CALLS`
314
+ edges are rejected, while `A --CALLS--> B` and `A --IMPORTS--> B` can coexist.
315
+ `Map` also preserves insertion order, producing deterministic traversal results.
316
+
317
+ Approximate operation costs are:
318
+
319
+ | Operation | Time | Extra space |
320
+ | --- | ---: | ---: |
321
+ | Add node | expected `O(1)` | `O(1)` |
322
+ | Add edge | expected `O(1)` | `O(1)` (indexed twice) |
323
+ | Get dependencies | `O(out-neighbors)` | output size |
324
+ | Get dependents | `O(in-neighbors)` | output size |
325
+ | BFS / DFS | `O(V + E)` reachable | `O(V)` reachable |
326
+ | Find path with BFS | `O(V + E)` reachable | `O(V)` reachable |
327
+
328
+ An adjacency matrix would be worth reconsidering only for a small, very dense graph
329
+ where constant-time arbitrary edge checks dominate. An edge list may be useful as a
330
+ serialization format later, but is not a good query index.
331
+
332
+ ## Types and TypeScript concepts
333
+
334
+ `GraphNode<NodeData>` separates stable identity (`id`) from domain data. Later,
335
+ `NodeData` can describe a file or symbol without teaching the graph engine those
336
+ concepts. `GraphEdge<EdgeType, EdgeData>` stores direction, relationship type, and
337
+ optional metadata. Later, edge data might hold source location or resolution status.
338
+
339
+ `DirectedGraph<NodeData, EdgeType, EdgeData>` introduces only three useful generics:
340
+
341
+ - `NodeData`: the application-specific node payload; defaults to `unknown`.
342
+ - `EdgeType extends string`: restricts relationships to string names while allowing
343
+ a union such as `"CALLS" | "IMPORTS"`.
344
+ - `EdgeData`: optional relationship metadata; defaults to `unknown`.
345
+
346
+ `unknown` is safer than `any`: consumers must narrow it before using it. `readonly`
347
+ prevents mutation through these public types, although it is shallow and does not
348
+ deep-freeze nested objects. `Map<K, V>` associates unique keys with values; `Set<T>`
349
+ stores unique values and is used by traversals to remember visited node IDs.
350
+
351
+ ## Behavioral decisions
352
+
353
+ - Duplicate node IDs throw. Silent overwrite could hide a symbol-ID bug.
354
+ - Edges require both endpoints to exist. This keeps every adjacency entry valid.
355
+ - Duplicate `(from, to, type)` edges throw. Different edge types may coexist.
356
+ - Neighbor and dependency queries return unique destination nodes, even if several
357
+ edge types connect the same pair.
358
+ - `getNode` returns `undefined` when absent, matching normal `Map.get` semantics.
359
+ - Operations that require an existing node throw for a missing ID.
360
+ - Self-edges are allowed. The generic engine models facts; later domain layers can
361
+ decide whether a particular self-relationship is meaningful.
362
+ - `findPath(A, A)` returns `[A]`, the valid zero-edge path from a node to itself.
363
+
364
+ ## Important code path walkthrough
365
+
366
+ ### 1. Types
367
+
368
+ [`src/graph/types.ts`](src/graph/types.ts) defines generic nodes and edges. They know
369
+ nothing about source files, functions, ASTs, or Codegraph-specific relationships.
370
+
371
+ ### 2. Internal data structures
372
+
373
+ [`src/graph/DirectedGraph.ts`](src/graph/DirectedGraph.ts) holds a node `Map` and two
374
+ adjacency maps. Their `private` modifier hides implementation details. Their
375
+ `readonly` modifier prevents assigning a different map to a field; the contents of
376
+ the existing map intentionally remain mutable.
377
+
378
+ ### 3. `addNode`
379
+
380
+ `addNode` checks `nodes.has(id)`, stores the node, and creates empty outgoing and
381
+ incoming buckets. Creating all three together maintains the graph invariant. The
382
+ expected time and added space are both `O(1)`.
383
+
384
+ ### 4. `addEdge`
385
+
386
+ `addEdge` first validates both endpoints. It indexes the same immutable edge object
387
+ under the source's outgoing map and destination's incoming map. A nested map lookup
388
+ detects duplicates without building a delimiter-based string key (which could have
389
+ escaping or collision problems). Expected insertion time is `O(1)`.
390
+
391
+ ### 5. Outgoing adjacency
392
+
393
+ For `A -> B`, the outgoing index stores B under A. Reading A's keys therefore gives
394
+ its direct dependencies. Multiple edge types to B live one level deeper and do not
395
+ duplicate B in node-level queries.
396
+
397
+ ### 6. Reverse adjacency
398
+
399
+ The incoming index stores A under B for the same edge. Without it, finding B's
400
+ dependents would scan every edge, costing `O(E)`. The tradeoff is a second index and
401
+ therefore `O(E)` additional references.
402
+
403
+ ### 7. Dependencies and dependents
404
+
405
+ `getDependencies` reads outgoing neighbor IDs; `getDependents` reads incoming IDs.
406
+ Both translate IDs back to nodes. Work is proportional to the number of direct
407
+ neighbors returned.
408
+
409
+ ### 8. BFS
410
+
411
+ Breadth-first search uses a first-in, first-out queue, so it visits all nodes one edge
412
+ away before nodes two edges away. `nextIndex` advances through an array instead of
413
+ calling `shift()`, which would repeatedly move remaining elements. Nodes enter the
414
+ visited `Set` when enqueued, preventing duplicates and guaranteeing termination on
415
+ cycles. Across the reachable graph, time is `O(V + E)` and space is `O(V)`.
416
+
417
+ ### 9. DFS
418
+
419
+ Depth-first search uses an explicit last-in, first-out stack rather than recursion.
420
+ This avoids overflowing JavaScript's call stack on a deep repository graph. Neighbors
421
+ are pushed in reverse so the earliest inserted neighbor is visited first. DFS has the
422
+ same asymptotic bounds as BFS, but explores deeply before returning to siblings.
423
+ Neither order is universally better; they answer different traversal needs.
424
+
425
+ ### 10. `findPath`
426
+
427
+ Path search uses BFS, which finds a minimum-edge path in an unweighted graph. When B
428
+ is first discovered from A it records `parent[B] = A`. On reaching the target, it
429
+ walks parents backward and reverses the result. A parent map is more memory-efficient
430
+ than copying a complete path into every queue entry. Time is `O(V + E)` and auxiliary
431
+ space is `O(V)` over reachable nodes.
432
+
433
+ ### 11. Tests
434
+
435
+ [`test/DirectedGraph.test.ts`](test/DirectedGraph.test.ts) covers nodes, duplicate and
436
+ invalid edges, multiple relationship types, self-edges, directionality, deterministic
437
+ BFS/DFS, cycles, disconnected components, shortest paths, missing paths, and the
438
+ zero-edge path. Node's built-in test runner supplies test organization and assertions;
439
+ Node loads the TypeScript files through `tsx` without a separate test framework.
440
+
441
+ ## Run it
442
+
443
+ ```bash
444
+ npm install
445
+ npm test
446
+ npm run check
447
+ npm run build
448
+ npm run example
449
+ ```
450
+
451
+ ## Understanding check
452
+
453
+ 1. If `A -> B` means A depends on B, what do `getDependencies("A")` and
454
+ `getDependents("B")` each return?
455
+ 2. Why does this implementation pay the memory cost of an incoming adjacency map?
456
+ 3. Why does adding a duplicate node throw instead of overwrite?
457
+ 4. Why is an edge identified by `from + to + type`, rather than only `from + to`?
458
+ 5. Why must both endpoint nodes exist before adding an edge?
459
+ 6. What different jobs do `Map` and `Set` perform here?
460
+ 7. Why is a node marked visited when BFS enqueues it rather than when it is removed?
461
+ 8. Why does BFS produce a shortest path by edge count in this unweighted graph?
462
+ 9. Why can iterative DFS be safer than recursive DFS for a large codebase?
463
+ 10. Why do BFS and DFS take `O(V + E)` time and `O(V)` extra space in the worst case?
@@ -0,0 +1,17 @@
1
+ import { type CodeGraph } from "./buildDefinitionGraph.js";
2
+ export type AnalysisDiagnosticKind = "compiler" | "unresolved-import" | "external-import" | "unresolved-call" | "external-call" | "unmodeled-caller" | "ambiguous-call";
3
+ export interface AnalysisDiagnostic {
4
+ readonly kind: AnalysisDiagnosticKind;
5
+ readonly message: string;
6
+ readonly file: string | null;
7
+ readonly line: number | null;
8
+ readonly column: number | null;
9
+ }
10
+ export interface ProjectAnalysis {
11
+ readonly rootDirectory: string;
12
+ readonly graph: CodeGraph;
13
+ readonly diagnostics: readonly AnalysisDiagnostic[];
14
+ readonly fileHashes: Readonly<Record<string, string>>;
15
+ }
16
+ export declare function analyzeProject(rootDirectory: string): Promise<ProjectAnalysis>;
17
+ //# sourceMappingURL=analyzeProject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeProject.d.ts","sourceRoot":"","sources":["../../src/analyzer/analyzeProject.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,SAAS,EAIf,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,sBAAsB,GAC9B,UAAU,GACV,mBAAmB,GACnB,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,GACf,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACvD;AAED,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,eAAe,CAAC,CA+C1B"}