@nithin554/code-crawler 0.1.39 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -47
- package/dist/crawler.d.ts +27 -1
- package/dist/crawler.js +360 -11
- package/dist/crawler.js.map +1 -1
- package/dist/graph/queries.d.ts +70 -4
- package/dist/graph/queries.js +125 -1
- package/dist/graph/queries.js.map +1 -1
- package/dist/graph/schema.d.ts +24 -2
- package/dist/graph/schema.js +9 -0
- package/dist/graph/schema.js.map +1 -1
- package/dist/parser/controlFlow.d.ts +27 -0
- package/dist/parser/controlFlow.js +82 -0
- package/dist/parser/controlFlow.js.map +1 -0
- package/dist/parser/language.d.ts +101 -2
- package/dist/parser/languages/index.js +4 -0
- package/dist/parser/languages/index.js.map +1 -1
- package/dist/parser/languages/java.js +160 -6
- package/dist/parser/languages/java.js.map +1 -1
- package/dist/parser/languages/python.d.ts +2 -0
- package/dist/parser/languages/python.js +956 -0
- package/dist/parser/languages/python.js.map +1 -0
- package/dist/parser/languages/typescript.d.ts +2 -0
- package/dist/parser/languages/typescript.js +1111 -0
- package/dist/parser/languages/typescript.js.map +1 -0
- package/dist/parser/moduleId.d.ts +35 -0
- package/dist/parser/moduleId.js +93 -0
- package/dist/parser/moduleId.js.map +1 -0
- package/dist/parser/treeSitter.d.ts +6 -0
- package/dist/parser/treeSitter.js +13 -2
- package/dist/parser/treeSitter.js.map +1 -1
- package/dist/resolver/common.d.ts +52 -0
- package/dist/resolver/common.js +624 -0
- package/dist/resolver/common.js.map +1 -0
- package/dist/resolver/dynamic.js +66 -1
- package/dist/resolver/dynamic.js.map +1 -1
- package/dist/resolver/genericResolver.d.ts +45 -0
- package/dist/resolver/genericResolver.js +235 -0
- package/dist/resolver/genericResolver.js.map +1 -0
- package/dist/resolver/types.d.ts +24 -1
- package/dist/resolver/types.js +50 -0
- package/dist/resolver/types.js.map +1 -1
- package/dist/server.js +108 -5
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
**Static + dynamic call tracing MCP server backed by a persistent property graph of your codebase.**
|
|
4
4
|
|
|
5
5
|
Code-Crawler indexes a project into a SQLite-backed property graph — files, packages,
|
|
6
|
-
classes, methods, fields, imports, annotations, **call
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
modules, classes, interfaces, methods, fields, imports, annotations/decorators, **call
|
|
7
|
+
edges**, **virtual dispatch**, **aspect advice**, and the wiring frameworks add
|
|
8
|
+
(**entry points**, **routes**, **injected dependencies**, **reflective lookups**) — then
|
|
9
|
+
exposes that graph to LLM clients as MCP tools: find callers, trace call paths, explore
|
|
10
|
+
neighborhoods, follow runtime dispatch, and search symbols across the whole codebase.
|
|
11
|
+
|
|
12
|
+
Supports **Java**, **Python**, and **TypeScript/JavaScript** projects, and can index all
|
|
13
|
+
three into the same graph.
|
|
10
14
|
|
|
11
15
|
📖 **Documentation site:** <https://nithin554.github.io/code-crawler/>
|
|
16
|
+
📘 **Task-oriented guide:** [`USAGE.md`](USAGE.md)
|
|
17
|
+
🗺️ **Roadmap:** [`ROADMAP.md`](ROADMAP.md)
|
|
12
18
|
|
|
13
19
|
```
|
|
14
20
|
┌─────────────────────── MCP (stdio) ───────────────────────┐
|
|
@@ -41,18 +47,36 @@ and answers them instantly with bounded recursive SQL queries.
|
|
|
41
47
|
|
|
42
48
|
## Features
|
|
43
49
|
|
|
44
|
-
- **
|
|
45
|
-
|
|
50
|
+
- **Three languages, one graph**: Java (`tree-sitter-java`), Python
|
|
51
|
+
(`tree-sitter-python`), and TypeScript/JavaScript (`tree-sitter-typescript`,
|
|
52
|
+
`tree-sitter-tsx`, `tree-sitter-javascript`) — all WASM, no native build step.
|
|
53
|
+
Language is detected per file, so a polyglot repo lands in a single graph.
|
|
46
54
|
- **Dynamic tracing on a static graph** — `DYNAMIC_DISPATCH` edges connect interface/base
|
|
47
55
|
calls to every override in the project, and `ADVISES` edges weave AspectJ/Spring AOP
|
|
48
56
|
advice into execution traces (`before`, `after`, `around`, `after-returning`,
|
|
49
57
|
`after-throwing`, named `@Pointcut` references, `&&`/`||`/`!` and `execution`, `within`,
|
|
50
58
|
`@annotation`, `@within`, `target`, `this`, `args` primitives).
|
|
51
|
-
- **
|
|
52
|
-
and
|
|
53
|
-
|
|
59
|
+
- **Run-time indirection is named, not lost** — Java reflection/`ServiceLoader`, Python
|
|
60
|
+
`getattr`/`importlib`, and JS `require`/dynamic `import()` produce `REFLECTS` edges to
|
|
61
|
+
the resolved symbol when the target is statically determinable, or to a
|
|
62
|
+
`__reflect__:` marker when it is not.
|
|
63
|
+
- **Framework wiring** — dependency injection (`@Autowired`, NestJS constructor
|
|
64
|
+
injection, FastAPI `Depends`) becomes `INJECTS` edges, and HTTP routes
|
|
65
|
+
(`@GetMapping`, `@RequestMapping`, NestJS `@Controller`/`@Get`, FastAPI/Flask
|
|
66
|
+
decorators, Express `app.get`) become `ROUTES` edges to the handler, which is also
|
|
67
|
+
marked as an entry point.
|
|
68
|
+
- **Control flow on call edges** — every `CALLS` edge records whether the call is
|
|
69
|
+
conditional and the compact source text of its enclosing guards/loops, so an agent can
|
|
70
|
+
tell a happy path from an error path without reading the file.
|
|
71
|
+
- **External dependencies are explicit** — third-party imports and runtime globals
|
|
72
|
+
become package-level `external_symbol` nodes with `REFERENCES` edges and a
|
|
73
|
+
`find_external_dependencies` summary, distinct from project code.
|
|
74
|
+
- **Annotations as first-class nodes** — `@Transactional`, `@Cacheable`, `@Async`,
|
|
75
|
+
`@Retryable`, Python decorators, and TS decorators become `annotation` nodes with
|
|
76
|
+
`ANNOTATED_WITH` edges, so you can query decorators on types, methods, and fields.
|
|
54
77
|
- **Call resolution heuristics** that go beyond naive string matching:
|
|
55
78
|
receiver types inferred from locals, parameters, fields, `new T()` expressions,
|
|
79
|
+
`self`/`this` scoping, dotted paths (`service.repo.find`), loop-variable element types,
|
|
56
80
|
bare/`this`/`super` calls, static/qualified calls, and superclass chains.
|
|
57
81
|
Unresolvable calls become `unknown_symbol` phantom nodes with `resolved:false` edges,
|
|
58
82
|
so the graph stays traversable.
|
|
@@ -70,7 +94,7 @@ Requires Node.js ≥ 20.
|
|
|
70
94
|
```bash
|
|
71
95
|
npm install
|
|
72
96
|
npm run build # tsc → dist/
|
|
73
|
-
npm test # vitest (
|
|
97
|
+
npm test # vitest (125 tests)
|
|
74
98
|
```
|
|
75
99
|
|
|
76
100
|
## CLI
|
|
@@ -129,10 +153,15 @@ if green, **auto-releases**:
|
|
|
129
153
|
Point the client at the same command. The typical flow for an LLM agent:
|
|
130
154
|
|
|
131
155
|
1. `crawl_project` the repo once.
|
|
132
|
-
2. `
|
|
133
|
-
3. `
|
|
134
|
-
4. `
|
|
156
|
+
2. `find_entry_points` to see where execution actually starts (routes, listeners, mains).
|
|
157
|
+
3. `search_symbols` to locate the symbol of interest.
|
|
158
|
+
4. `get_callers` / `get_callees` / `trace_path` to reason about the call graph.
|
|
159
|
+
5. `trace_execution` to follow runtime dispatch and aspect advice; `find_aspects`,
|
|
135
160
|
`get_decorators`, and `find_annotated` to inspect behaviour-changing annotations.
|
|
161
|
+
6. `find_routes`, `find_injections`, `find_reflections`, and `find_external_dependencies`
|
|
162
|
+
to map framework wiring and third-party surface.
|
|
163
|
+
|
|
164
|
+
See [`USAGE.md`](USAGE.md) for the full task-oriented walkthrough.
|
|
136
165
|
|
|
137
166
|
## MCP surface
|
|
138
167
|
|
|
@@ -154,6 +183,11 @@ Point the client at the same command. The typical flow for an LLM agent:
|
|
|
154
183
|
| `find_annotated` | Every symbol annotated with a given annotation |
|
|
155
184
|
| `find_hotspots` | Rank methods by fan-in, fan-out, and advice interceptions |
|
|
156
185
|
| `find_dead_code` | Methods with no incoming call/dispatch/advice edges |
|
|
186
|
+
| `find_entry_points` | Framework-invoked roots: HTTP routes, listeners, schedulers, CLI mains, tests |
|
|
187
|
+
| `find_routes` | HTTP route → handler mappings (`@GetMapping`, NestJS, FastAPI, Express) |
|
|
188
|
+
| `find_injections` | DI-supplied dependencies (`@Autowired`, NestJS, FastAPI `Depends`) |
|
|
189
|
+
| `find_reflections` | Run-time lookups: `Class.forName`, `getattr`, `importlib`, dynamic `import()` |
|
|
190
|
+
| `find_external_dependencies` | Third-party packages with reference and file counts |
|
|
157
191
|
| `get_subgraph` | Neighborhood extraction for visualization |
|
|
158
192
|
| `get_schema` | Describe the graph model |
|
|
159
193
|
| `clear_index` | Reset the database |
|
|
@@ -163,15 +197,18 @@ Point the client at the same command. The typical flow for an LLM agent:
|
|
|
163
197
|
|
|
164
198
|
## Graph model
|
|
165
199
|
|
|
166
|
-
**Nodes** — `kind` is one of `file | package | class | interface | enum | method |
|
|
167
|
-
constructor | field | import | aspect | annotation_type | annotation |
|
|
168
|
-
Every node has a globally unique `qualifiedName` and a JSON `properties`
|
|
169
|
-
(signature, modifiers, lines, annotations, ...).
|
|
200
|
+
**Nodes** — `kind` is one of `file | package | module | class | interface | enum | method |
|
|
201
|
+
constructor | field | import | external_symbol | aspect | annotation_type | annotation |
|
|
202
|
+
unknown_symbol`. Every node has a globally unique `qualifiedName` and a JSON `properties`
|
|
203
|
+
blob (signature, modifiers, lines, annotations, ...).
|
|
170
204
|
|
|
171
205
|
**Edges** — `kind` is one of `CALLS | DECLARED_IN | CONTAINS | IMPLEMENTS | EXTENDS |
|
|
172
|
-
IMPORTS | REFERENCES | DYNAMIC_DISPATCH | ADVISES | ANNOTATED_WITH
|
|
173
|
-
`line`, `resolved`,
|
|
174
|
-
|
|
206
|
+
IMPORTS | REFERENCES | DYNAMIC_DISPATCH | ADVISES | ANNOTATED_WITH | REFLECTS | INJECTS |
|
|
207
|
+
ROUTES`. `CALLS` edges carry `line`, `resolved`, `confidence`, and — when the call sits
|
|
208
|
+
behind control flow — `conditional`, `controlFlow`, and `guards`; `ANNOTATED_WITH` edges
|
|
209
|
+
carry `line` and `arguments`; `ADVISES` edges carry `adviceKind` and the resolved
|
|
210
|
+
`pointcut`; `INJECTS` carries `injectedName` and `framework`; `REFLECTS` carries
|
|
211
|
+
`mechanism`; `REFERENCES` carries `external`.
|
|
175
212
|
|
|
176
213
|
Id scheme:
|
|
177
214
|
|
|
@@ -184,6 +221,13 @@ Id scheme:
|
|
|
184
221
|
| annotation | `@Transactional` |
|
|
185
222
|
| import | `__import__:java.util.List` |
|
|
186
223
|
| unresolved call | `__unknown__:System.out.println` |
|
|
224
|
+
| Python/TS module | `module:app.service` |
|
|
225
|
+
| module-level function | `module:app.api#read_order` |
|
|
226
|
+
| module-level field | `module:app.service$AUDIT_LOG` |
|
|
227
|
+
| inline arrow handler | `module:src.routes#<anonymous@7>` |
|
|
228
|
+
| external package | `ext:fastapi` |
|
|
229
|
+
| reflective marker | `__reflect__:./plugins/${name}` |
|
|
230
|
+
| injection marker | `__inject__:Repo` |
|
|
187
231
|
|
|
188
232
|
## Dynamic behaviour
|
|
189
233
|
|
|
@@ -236,7 +280,79 @@ Framework decorators (`@Transactional`, `@Cacheable`, `@Async`, `@Retryable`,
|
|
|
236
280
|
`@PreAuthorize`, `@Scheduled`, ...) are additionally flagged `decorator: true` so
|
|
237
281
|
`get_decorators` and `find_annotated` can surface runtime-semantic annotations.
|
|
238
282
|
|
|
239
|
-
|
|
283
|
+
Python decorators and TypeScript decorators are modelled the same way: `@router.get(...)`,
|
|
284
|
+
`@injectable`, `@Controller(...)`, `@Get(':id')` and friends land in `annotations` on the
|
|
285
|
+
declaring type/method, and framework ones additionally produce routes, injections, or
|
|
286
|
+
entry-point marks.
|
|
287
|
+
|
|
288
|
+
### Reflection and run-time indirection
|
|
289
|
+
|
|
290
|
+
Lookups the compiler cannot see through are recorded as `REFLECTS` edges. When the target
|
|
291
|
+
is statically determinable — a string literal, a literal prefix plus a variable
|
|
292
|
+
(`importlib.import_module("app.plugins." + name)`), `getattr(obj, "run")`,
|
|
293
|
+
`require("./x")` — the edge points at the resolved symbol. Otherwise it points at a
|
|
294
|
+
`__reflect__:` marker carrying the `mechanism`:
|
|
295
|
+
|
|
296
|
+
```text
|
|
297
|
+
module:app.dynamic#load_plugin --REFLECTS--> __reflect__:app.plugins. (importlib.import_module)
|
|
298
|
+
module:src.dynamic#loadPlugin --REFLECTS--> __reflect__:./plugins/${name} (import())
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Dynamic module prefixes that belong to the project's own namespace stay in-project; only
|
|
302
|
+
genuinely foreign packages become external dependencies.
|
|
303
|
+
|
|
304
|
+
### Dependency injection
|
|
305
|
+
|
|
306
|
+
Dependencies the framework supplies are `INJECTS` edges instead of missing calls
|
|
307
|
+
(`find_injections`):
|
|
308
|
+
|
|
309
|
+
| Framework | Detected from |
|
|
310
|
+
| --- | --- |
|
|
311
|
+
| Spring | `@Autowired` fields/methods/constructors |
|
|
312
|
+
| NestJS | constructor parameters with decorators; `@Injectable()` classes |
|
|
313
|
+
| FastAPI | `Depends(...)` parameters |
|
|
314
|
+
| dependency-injector | constructor parameters of `@injectable` classes |
|
|
315
|
+
| plain TS/JS | constructor parameters typed with a project class |
|
|
316
|
+
|
|
317
|
+
Primitive and structural parameter types (`string`, `{ id: string }`, `list[str]`) are
|
|
318
|
+
counted but produce no edge, so `@Body() body: { id: string }` does not pollute the graph.
|
|
319
|
+
|
|
320
|
+
### Framework entry points and routes
|
|
321
|
+
|
|
322
|
+
Methods a framework invokes have no source-level caller, so marking them keeps dead-code
|
|
323
|
+
analysis honest and gives `trace_execution` a root (`find_entry_points`, `find_routes`):
|
|
324
|
+
|
|
325
|
+
| Language | Recognised |
|
|
326
|
+
| --- | --- |
|
|
327
|
+
| Java | `@GetMapping`, `@PostMapping`, `@RequestMapping`, `@Scheduled`, `@EventListener`, listener annotations, tests, `main` |
|
|
328
|
+
| Python | FastAPI (`@router.get`, `@app.post`), Flask (`@bp.route`), `if __name__ == "__main__"`, `pytest` tests |
|
|
329
|
+
| TypeScript | NestJS `@Controller` + `@Get`/`@Post`/... , Express `app.get('/x', handler)`, Jest tests |
|
|
330
|
+
|
|
331
|
+
Express handlers written inline get a synthetic method node
|
|
332
|
+
(`module:src.routes#<anonymous@7>`) so their body still gets call edges, containment, and
|
|
333
|
+
a route edge.
|
|
334
|
+
|
|
335
|
+
### Control flow on call edges
|
|
336
|
+
|
|
337
|
+
Each `CALLS` edge records whether it is guarded:
|
|
338
|
+
|
|
339
|
+
```json
|
|
340
|
+
{
|
|
341
|
+
"kind": "CALLS",
|
|
342
|
+
"source": "app.repository.OrderRepository#create",
|
|
343
|
+
"target": "ext:builtins",
|
|
344
|
+
"properties": { "line": 14, "conditional": true, "controlFlow": ["branch", "loop"],
|
|
345
|
+
"guards": ["row.get(\"id\") == order_id", "self.rows"] }
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
`controlFlow` uses `branch | loop | exception | predicate`. Guards are source text, not
|
|
350
|
+
symbolic constraints: they tell an agent *that* a call is conditional and *what* the
|
|
351
|
+
condition looked like, without pretending to model its truth value.
|
|
352
|
+
|
|
353
|
+
## Resolution heuristics
|
|
354
|
+
|
|
355
|
+
Java:
|
|
240
356
|
|
|
241
357
|
1. **Constructor calls** (`new Foo(...)`) → resolve `Foo` → `#<init>` (default ctor if implicit).
|
|
242
358
|
2. **Bare / `this.` / `super.` calls** → enclosing type + superclass chain.
|
|
@@ -246,53 +362,93 @@ Framework decorators (`@Transactional`, `@Cacheable`, `@Async`, `@Retryable`,
|
|
|
246
362
|
5. **Otherwise** → phantom `unknown_symbol` node, `resolved:false`, with the inference
|
|
247
363
|
failure reason attached to the edge.
|
|
248
364
|
|
|
365
|
+
Python and TypeScript add module-aware resolution on top of the same pipeline:
|
|
366
|
+
|
|
367
|
+
1. **Import-aware scope** — `from app.repository import OrderRepository` maps the local
|
|
368
|
+
name to `app.repository.OrderRepository`; relative and project modules are resolved by
|
|
369
|
+
suffix, bare specifiers fall back to package roots.
|
|
370
|
+
2. **`self.x` / `this.x`** resolve against the enclosing class's fields; a receiver that
|
|
371
|
+
starts with `self`/`this`/`cls`/`super` never becomes an external package.
|
|
372
|
+
3. **Dotted receivers** (`service.repo.find`) are walked segment by segment: the first
|
|
373
|
+
segment resolves to a type, the next to a field on it, and container members such as
|
|
374
|
+
`list.append` are recognised as builtin rather than unknown.
|
|
375
|
+
4. **Locals** are typed from parameters, annotated assignments, `new T()`, and inferred
|
|
376
|
+
loop/variable element types (`for row in self.rows:` → `row: dict`).
|
|
377
|
+
5. **Module functions** (`module:app.api#read_order`) participate in dispatch, routes, and
|
|
378
|
+
entry-point marking exactly like class methods.
|
|
379
|
+
|
|
249
380
|
Each resolved edge carries a `confidence` score and a human-readable `reason` trace
|
|
250
381
|
(e.g. `via local orders: OrderService`), so LLM clients can weigh how much to trust it.
|
|
251
382
|
|
|
252
|
-
##
|
|
383
|
+
## Implemented languages
|
|
253
384
|
|
|
254
|
-
|
|
385
|
+
| Language | Extensions | Extracted | Dynamic features |
|
|
386
|
+
| --- | --- | --- | --- |
|
|
387
|
+
| Java | `.java` | packages, classes, interfaces, enums, records, annotations, constructors, methods, fields | virtual dispatch, AspectJ/Spring AOP advice, `@Autowired`, `@RequestMapping` family, `Class.forName`, `ServiceLoader` |
|
|
388
|
+
| Python | `.py` | modules, classes, functions, methods, fields, decorators | `@injectable`/`Depends` injection, FastAPI/Flask routes, `getattr`, `importlib`, `__main__`, tests |
|
|
389
|
+
| TypeScript | `.ts`, `.tsx` | modules, classes, interfaces, type aliases, enums, methods, fields, arrow functions | NestJS/Angular decorators, DI constructor injection, NestJS/Express routes, `import()`, `require()` |
|
|
390
|
+
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | modules, classes, functions, fields | decorators, Express routes, `require()` |
|
|
391
|
+
|
|
392
|
+
Crawling a directory mixes all of them automatically — language is chosen per file from
|
|
393
|
+
the extension, and a single crawl can return `languages: ["java", "python", "typescript"]`.
|
|
394
|
+
|
|
395
|
+
Adding a language requires:
|
|
255
396
|
|
|
256
397
|
1. `src/parser/languages/<lang>.ts` — a `LanguageConfig` implementing `parseFile`
|
|
257
|
-
(package
|
|
398
|
+
(module/package extraction, type/member extraction, raw call sites, local type tables).
|
|
258
399
|
2. Register it in `src/parser/languages/index.ts`.
|
|
259
|
-
3. `src/resolver/<lang>Resolver.ts
|
|
260
|
-
|
|
400
|
+
3. Optionally a `src/resolver/<lang>Resolver.ts`; most languages work with the shared
|
|
401
|
+
`src/resolver/genericResolver.ts` and only override language-specific builtins.
|
|
261
402
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
queries, and MCP surface all stay the same.
|
|
403
|
+
The graph schema, store, traversal queries, and MCP surface stay the same for every
|
|
404
|
+
language. Natural next targets: Go, C#, Ruby, Rust.
|
|
265
405
|
|
|
266
|
-
|
|
406
|
+
Not yet modelled, by design:
|
|
267
407
|
|
|
268
|
-
-
|
|
269
|
-
|
|
270
|
-
-
|
|
408
|
+
- Value flow and branch feasibility — edges say *that* a call is conditional and record
|
|
409
|
+
the guard text, not which branch is taken.
|
|
410
|
+
- Cross-repository resolution — libraries outside the crawled tree are summarised as
|
|
411
|
+
`ext:` packages rather than crawled.
|
|
412
|
+
- Fully dynamic targets (`getattr(obj, name)`, `require(userInput)`) point at a
|
|
413
|
+
`__reflect__:` marker instead of a symbol; there is nothing static to point at.
|
|
414
|
+
- Runtime DI graphs assembled from configuration files rather than code.
|
|
271
415
|
|
|
272
416
|
## Architecture
|
|
273
417
|
|
|
274
418
|
```
|
|
275
419
|
src/
|
|
276
|
-
├── index.ts
|
|
277
|
-
├── server.ts
|
|
278
|
-
├── crawler.ts
|
|
279
|
-
├── config.ts
|
|
420
|
+
├── index.ts CLI (crawl | status | query | serve)
|
|
421
|
+
├── server.ts MCP server: tools, resources, prompt (thin handlers)
|
|
422
|
+
├── crawler.ts file discovery → parse → index → resolve → persist
|
|
423
|
+
├── config.ts env-overridable configuration
|
|
280
424
|
├── graph/
|
|
281
|
-
│ ├── schema.ts
|
|
282
|
-
│ ├── store.ts
|
|
283
|
-
│ └── queries.ts
|
|
425
|
+
│ ├── schema.ts node/edge kinds, id scheme, property shapes
|
|
426
|
+
│ ├── store.ts better-sqlite3 schema + idempotent file-scoped upserts
|
|
427
|
+
│ └── queries.ts recursive-CTE traversal (callers/callees/path/subgraph)
|
|
284
428
|
├── parser/
|
|
285
|
-
│ ├── language.ts
|
|
286
|
-
│ ├── treeSitter.ts
|
|
429
|
+
│ ├── language.ts LanguageConfig contract
|
|
430
|
+
│ ├── treeSitter.ts WASM runtime + grammar loading + CST walk helpers
|
|
431
|
+
│ ├── controlFlow.ts enclosing branch/loop/try/catch + guard text
|
|
432
|
+
│ ├── moduleId.ts import-aware module id derivation
|
|
287
433
|
│ └── languages/
|
|
288
|
-
│ ├── index.ts
|
|
289
|
-
│
|
|
434
|
+
│ ├── index.ts language registry + per-file language detection
|
|
435
|
+
│ ├── java.ts Java structural extraction
|
|
436
|
+
│ ├── python.ts Python structural extraction
|
|
437
|
+
│ └── typescript.ts TypeScript, TSX and JavaScript extraction
|
|
290
438
|
└── resolver/
|
|
291
|
-
├── types.ts
|
|
292
|
-
├──
|
|
293
|
-
|
|
439
|
+
├── types.ts TypeIndex (global name/method index) + ResolvedCall
|
|
440
|
+
├── common.ts builtin types, external packages, receiver inference
|
|
441
|
+
├── dynamic.ts virtual dispatch + AspectJ pointcut matching/advice edges
|
|
442
|
+
├── genericResolver.ts shared resolution for module-based languages
|
|
443
|
+
└── javaResolver.ts Java call-target resolution heuristics
|
|
294
444
|
```
|
|
295
445
|
|
|
446
|
+
## Roadmap
|
|
447
|
+
|
|
448
|
+
Language-agnostic architecture, more languages, and better resolution are tracked in
|
|
449
|
+
[`ROADMAP.md`](ROADMAP.md). The near-term focus is making a new language a one-module
|
|
450
|
+
change, then using that to add Go, C#, and Kotlin.
|
|
451
|
+
|
|
296
452
|
## Documentation site
|
|
297
453
|
|
|
298
454
|
The static documentation site in `docs/` is deployed to GitHub Pages by
|
package/dist/crawler.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { GraphStore } from "./graph/store.js";
|
|
2
2
|
import type { GraphEdge, GraphNode } from "./graph/schema.js";
|
|
3
|
-
import type { ParsedFile } from "./parser/language.js";
|
|
3
|
+
import type { EntryPointInfo, ParsedFile } from "./parser/language.js";
|
|
4
4
|
import { buildTypeIndex } from "./resolver/types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Project crawler: discover source files, parse them, build a global type
|
|
@@ -29,6 +29,16 @@ export interface CrawlResult {
|
|
|
29
29
|
aspects: number;
|
|
30
30
|
/** Number of annotation/decorator usages indexed. */
|
|
31
31
|
decorators: number;
|
|
32
|
+
/** Framework-invoked roots (routes, listeners, schedulers, CLI, tests). */
|
|
33
|
+
entryPoints: number;
|
|
34
|
+
/** Framework-supplied dependency edges. */
|
|
35
|
+
injections: number;
|
|
36
|
+
/** Run-time lookup edges (reflection, dynamic import, getattr). */
|
|
37
|
+
reflections: number;
|
|
38
|
+
/** Distinct external packages/specifiers referenced by the project. */
|
|
39
|
+
externalDependencies: number;
|
|
40
|
+
/** Route registrations mapped to handler methods. */
|
|
41
|
+
routes: number;
|
|
32
42
|
languages: string[];
|
|
33
43
|
durationMs: number;
|
|
34
44
|
}
|
|
@@ -45,6 +55,22 @@ export declare function buildCallEdges(parsed: ParsedFile, index: ReturnType<typ
|
|
|
45
55
|
phantomNodes: GraphNode[];
|
|
46
56
|
resolved: number;
|
|
47
57
|
unresolved: number;
|
|
58
|
+
external: number;
|
|
59
|
+
externalPackages: Set<string>;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Framework wiring that the language parsers surface but the plain call
|
|
63
|
+
* resolver cannot see: external dependencies, dependency injection,
|
|
64
|
+
* reflective lookups and route registrations.
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildDependencyGraph(parsed: ParsedFile, index: ReturnType<typeof buildTypeIndex>, knownNodeIds: Set<string>): {
|
|
67
|
+
nodes: GraphNode[];
|
|
68
|
+
edges: GraphEdge[];
|
|
69
|
+
entryPointMarks: Map<string, EntryPointInfo>;
|
|
70
|
+
injections: number;
|
|
71
|
+
reflections: number;
|
|
72
|
+
routes: number;
|
|
73
|
+
externalDependencies: Set<string>;
|
|
48
74
|
};
|
|
49
75
|
/**
|
|
50
76
|
* Crawl a project directory and index it into the store.
|