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