@optave/codegraph 3.0.1 → 3.0.2
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 +21 -18
- package/package.json +5 -5
- package/src/builder.js +18 -5
- package/src/complexity.js +0 -3
- package/src/dataflow.js +760 -272
- package/src/parser.js +54 -0
package/README.md
CHANGED
|
@@ -195,6 +195,7 @@ Full agent setup: [AI Agent Guide](docs/guides/ai-agent-guide.md) · [CLAU
|
|
|
195
195
|
| 👀 | **Watch mode** | Incrementally update the graph as files change |
|
|
196
196
|
| 🤖 | **MCP server** | 30-tool MCP server for AI assistants; single-repo by default, opt-in multi-repo |
|
|
197
197
|
| ⚡ | **Always fresh** | Three-tier incremental detection — sub-second rebuilds even on large codebases |
|
|
198
|
+
| 🔬 | **Data flow analysis** | Intraprocedural parameter tracking, return consumers, argument flows, and mutation detection — all 11 languages |
|
|
198
199
|
| 🧮 | **Complexity metrics** | Cognitive, cyclomatic, nesting depth, Halstead, and Maintainability Index per function |
|
|
199
200
|
| 🏘️ | **Community detection** | Louvain clustering to discover natural module boundaries and architectural drift |
|
|
200
201
|
| 📜 | **Manifesto rule engine** | Configurable pass/fail rules with warn/fail thresholds for CI gates via `check` (exit code 1 on fail) |
|
|
@@ -208,7 +209,7 @@ Full agent setup: [AI Agent Guide](docs/guides/ai-agent-guide.md) · [CLAU
|
|
|
208
209
|
| 📋 | **Composite audit** | Single `audit` command combining explain + impact + health metrics per function — one call instead of 3-4 |
|
|
209
210
|
| 🚦 | **Triage queue** | `triage` merges connectivity, hotspots, roles, and complexity into a ranked audit priority queue |
|
|
210
211
|
| 📦 | **Batch querying** | Accept a list of targets and return all results in one JSON payload — enables multi-agent parallel dispatch |
|
|
211
|
-
| 🔬 | **Dataflow analysis** | Track how data moves through functions with `flows_to`, `returns`, and `mutates` edges — included by default
|
|
212
|
+
| 🔬 | **Dataflow analysis** | Track how data moves through functions with `flows_to`, `returns`, and `mutates` edges — all 11 languages, included by default, skip with `--no-dataflow` |
|
|
212
213
|
| 🧩 | **Control flow graph** | Intraprocedural CFG construction for all 11 languages — `cfg` command with text/DOT/Mermaid output, included by default, skip with `--no-cfg` |
|
|
213
214
|
| 🔎 | **AST node querying** | Stored queryable AST nodes (calls, `new`, string, regex, throw, await) — `ast` command with SQL GLOB pattern matching |
|
|
214
215
|
| 🧬 | **Expanded node/edge types** | `parameter`, `property`, `constant` node kinds with `parent_id` for sub-declaration queries; `contains`, `parameter_of`, `receiver` edge kinds |
|
|
@@ -225,6 +226,7 @@ See [docs/examples](docs/examples) for real-world CLI and MCP usage examples.
|
|
|
225
226
|
```bash
|
|
226
227
|
codegraph build [dir] # Parse and build the dependency graph
|
|
227
228
|
codegraph build --no-incremental # Force full rebuild
|
|
229
|
+
codegraph build --dataflow # Extract data flow edges (flows_to, returns, mutates)
|
|
228
230
|
codegraph build --engine wasm # Force WASM engine (skip native)
|
|
229
231
|
codegraph watch [dir] # Watch for changes, update graph incrementally
|
|
230
232
|
```
|
|
@@ -327,7 +329,8 @@ codegraph ast -k call # Filter by kind: call, new, string, regex
|
|
|
327
329
|
codegraph ast -k throw --file src/ # Combine kind and file filters
|
|
328
330
|
```
|
|
329
331
|
|
|
330
|
-
> **Note:** Dataflow
|
|
332
|
+
> **Note:** Dataflow and CFG are included by default for all 11 languages. Use `--no-dataflow` / `--no-cfg` for faster builds.
|
|
333
|
+
|
|
331
334
|
|
|
332
335
|
### Audit, Triage & Batch
|
|
333
336
|
|
|
@@ -477,15 +480,15 @@ codegraph registry remove <name> # Unregister
|
|
|
477
480
|
|
|
478
481
|
| Language | Extensions | Coverage |
|
|
479
482
|
|---|---|---|
|
|
480
|
-
|  | `.js`, `.jsx`, `.mjs`, `.cjs` | Full — functions, classes, imports, call sites |
|
|
481
|
-
|  | `.ts`, `.tsx` | Full — interfaces, type aliases, `.d.ts
|
|
482
|
-
|  | `.py` | Functions, classes, methods, imports, decorators |
|
|
483
|
-
|  | `.go` | Functions, methods, structs, interfaces, imports, call sites |
|
|
484
|
-
|  | `.rs` | Functions, methods, structs, traits, `use` imports, call sites |
|
|
485
|
-
|  | `.java` | Classes, methods, constructors, interfaces, imports, call sites |
|
|
486
|
-
|  | `.cs` | Classes, structs, records, interfaces, enums, methods, constructors, using directives, invocations |
|
|
487
|
-
|  | `.php` | Functions, classes, interfaces, traits, enums, methods, namespace use, calls |
|
|
488
|
-
|  | `.rb` | Classes, modules, methods, singleton methods, require/require_relative, include/extend |
|
|
483
|
+
|  | `.js`, `.jsx`, `.mjs`, `.cjs` | Full — functions, classes, imports, call sites, dataflow |
|
|
484
|
+
|  | `.ts`, `.tsx` | Full — interfaces, type aliases, `.d.ts`, dataflow |
|
|
485
|
+
|  | `.py` | Functions, classes, methods, imports, decorators, dataflow |
|
|
486
|
+
|  | `.go` | Functions, methods, structs, interfaces, imports, call sites, dataflow |
|
|
487
|
+
|  | `.rs` | Functions, methods, structs, traits, `use` imports, call sites, dataflow |
|
|
488
|
+
|  | `.java` | Classes, methods, constructors, interfaces, imports, call sites, dataflow |
|
|
489
|
+
|  | `.cs` | Classes, structs, records, interfaces, enums, methods, constructors, using directives, invocations, dataflow |
|
|
490
|
+
|  | `.php` | Functions, classes, interfaces, traits, enums, methods, namespace use, calls, dataflow |
|
|
491
|
+
|  | `.rb` | Classes, modules, methods, singleton methods, require/require_relative, include/extend, dataflow |
|
|
489
492
|
|  | `.tf`, `.hcl` | Resource, data, variable, module, output blocks |
|
|
490
493
|
|
|
491
494
|
## ⚙️ How It Works
|
|
@@ -552,14 +555,14 @@ Self-measured on every release via CI ([build benchmarks](generated/benchmarks/B
|
|
|
552
555
|
|
|
553
556
|
| Metric | Latest |
|
|
554
557
|
|---|---|
|
|
555
|
-
| Build speed (native) | **
|
|
556
|
-
| Build speed (WASM) | **
|
|
558
|
+
| Build speed (native) | **14.1 ms/file** |
|
|
559
|
+
| Build speed (WASM) | **24.4 ms/file** |
|
|
557
560
|
| Query time | **3ms** |
|
|
558
|
-
| No-op rebuild (native) | **
|
|
559
|
-
| 1-file rebuild (native) | **
|
|
560
|
-
| Query: fn-deps | **0.
|
|
561
|
+
| No-op rebuild (native) | **5ms** |
|
|
562
|
+
| 1-file rebuild (native) | **915ms** |
|
|
563
|
+
| Query: fn-deps | **0.9ms** |
|
|
561
564
|
| Query: path | **0.8ms** |
|
|
562
|
-
| ~50,000 files (est.) | **~
|
|
565
|
+
| ~50,000 files (est.) | **~705.0s build** |
|
|
563
566
|
|
|
564
567
|
Metrics are normalized per file for cross-version comparability. Times above are for a full initial build — incremental rebuilds only re-parse changed files.
|
|
565
568
|
|
|
@@ -804,7 +807,7 @@ const { results: fused } = await multiSearchData(
|
|
|
804
807
|
- **No full type inference** — parses `.d.ts` interfaces but doesn't use TypeScript's type checker for overload resolution
|
|
805
808
|
- **Dynamic calls are best-effort** — complex computed property access and `eval` patterns are not resolved
|
|
806
809
|
- **Python imports** — resolves relative imports but doesn't follow `sys.path` or virtual environment packages
|
|
807
|
-
- **Dataflow analysis** —
|
|
810
|
+
- **Dataflow analysis** — intraprocedural (single-function scope), not interprocedural
|
|
808
811
|
|
|
809
812
|
## 🗺️ Roadmap
|
|
810
813
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optave/codegraph",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Local code graph CLI — parse codebases with tree-sitter, build dependency graphs, query them",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
73
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
74
|
-
"@optave/codegraph-darwin-arm64": "3.0.
|
|
75
|
-
"@optave/codegraph-darwin-x64": "3.0.
|
|
76
|
-
"@optave/codegraph-linux-x64-gnu": "3.0.
|
|
77
|
-
"@optave/codegraph-win32-x64-msvc": "3.0.
|
|
74
|
+
"@optave/codegraph-darwin-arm64": "3.0.2",
|
|
75
|
+
"@optave/codegraph-darwin-x64": "3.0.2",
|
|
76
|
+
"@optave/codegraph-linux-x64-gnu": "3.0.2",
|
|
77
|
+
"@optave/codegraph-win32-x64-msvc": "3.0.2"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@biomejs/biome": "^2.4.4",
|
package/src/builder.js
CHANGED
|
@@ -1272,7 +1272,7 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1272
1272
|
}
|
|
1273
1273
|
_t.rolesMs = performance.now() - _t.roles0;
|
|
1274
1274
|
|
|
1275
|
-
// For incremental builds, filter out reverse-dep-only files from AST/complexity
|
|
1275
|
+
// For incremental builds, filter out reverse-dep-only files from AST/complexity/CFG/dataflow
|
|
1276
1276
|
// — their content didn't change, so existing ast_nodes/function_complexity rows are valid.
|
|
1277
1277
|
let astComplexitySymbols = allSymbols;
|
|
1278
1278
|
if (!isFullBuild) {
|
|
@@ -1287,13 +1287,12 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1287
1287
|
}
|
|
1288
1288
|
}
|
|
1289
1289
|
debug(
|
|
1290
|
-
`AST/complexity: processing ${astComplexitySymbols.size} changed files (skipping ${reverseDepFiles.size} reverse-deps)`,
|
|
1290
|
+
`AST/complexity/CFG/dataflow: processing ${astComplexitySymbols.size} changed files (skipping ${reverseDepFiles.size} reverse-deps)`,
|
|
1291
1291
|
);
|
|
1292
1292
|
}
|
|
1293
1293
|
}
|
|
1294
1294
|
|
|
1295
1295
|
// AST node extraction (calls, new, string, regex, throw, await)
|
|
1296
|
-
// Must run before complexity which releases _tree references
|
|
1297
1296
|
_t.ast0 = performance.now();
|
|
1298
1297
|
if (opts.ast !== false) {
|
|
1299
1298
|
try {
|
|
@@ -1317,12 +1316,25 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1317
1316
|
}
|
|
1318
1317
|
_t.complexityMs = performance.now() - _t.complexity0;
|
|
1319
1318
|
|
|
1319
|
+
// Pre-parse files missing WASM trees (native builds) so CFG + dataflow
|
|
1320
|
+
// share a single parse pass instead of each creating parsers independently
|
|
1321
|
+
if (opts.cfg !== false || opts.dataflow !== false) {
|
|
1322
|
+
_t.wasmPre0 = performance.now();
|
|
1323
|
+
try {
|
|
1324
|
+
const { ensureWasmTrees } = await import('./parser.js');
|
|
1325
|
+
await ensureWasmTrees(astComplexitySymbols, rootDir);
|
|
1326
|
+
} catch (err) {
|
|
1327
|
+
debug(`WASM pre-parse failed: ${err.message}`);
|
|
1328
|
+
}
|
|
1329
|
+
_t.wasmPreMs = performance.now() - _t.wasmPre0;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1320
1332
|
// CFG analysis (skip with --no-cfg)
|
|
1321
1333
|
if (opts.cfg !== false) {
|
|
1322
1334
|
_t.cfg0 = performance.now();
|
|
1323
1335
|
try {
|
|
1324
1336
|
const { buildCFGData } = await import('./cfg.js');
|
|
1325
|
-
await buildCFGData(db,
|
|
1337
|
+
await buildCFGData(db, astComplexitySymbols, rootDir, engineOpts);
|
|
1326
1338
|
} catch (err) {
|
|
1327
1339
|
debug(`CFG analysis failed: ${err.message}`);
|
|
1328
1340
|
}
|
|
@@ -1334,7 +1346,7 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1334
1346
|
_t.dataflow0 = performance.now();
|
|
1335
1347
|
try {
|
|
1336
1348
|
const { buildDataflowEdges } = await import('./dataflow.js');
|
|
1337
|
-
await buildDataflowEdges(db,
|
|
1349
|
+
await buildDataflowEdges(db, astComplexitySymbols, rootDir, engineOpts);
|
|
1338
1350
|
} catch (err) {
|
|
1339
1351
|
debug(`Dataflow analysis failed: ${err.message}`);
|
|
1340
1352
|
}
|
|
@@ -1434,6 +1446,7 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1434
1446
|
rolesMs: +_t.rolesMs.toFixed(1),
|
|
1435
1447
|
astMs: +_t.astMs.toFixed(1),
|
|
1436
1448
|
complexityMs: +_t.complexityMs.toFixed(1),
|
|
1449
|
+
...(_t.wasmPreMs != null && { wasmPreMs: +_t.wasmPreMs.toFixed(1) }),
|
|
1437
1450
|
...(_t.cfgMs != null && { cfgMs: +_t.cfgMs.toFixed(1) }),
|
|
1438
1451
|
...(_t.dataflowMs != null && { dataflowMs: +_t.dataflowMs.toFixed(1) }),
|
|
1439
1452
|
},
|