@optave/codegraph 3.1.0 → 3.1.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.
- package/README.md +5 -5
- package/grammars/tree-sitter-go.wasm +0 -0
- package/package.json +8 -9
- package/src/ast-analysis/rules/csharp.js +201 -0
- package/src/ast-analysis/rules/go.js +182 -0
- package/src/ast-analysis/rules/index.js +82 -0
- package/src/ast-analysis/rules/java.js +175 -0
- package/src/ast-analysis/rules/javascript.js +246 -0
- package/src/ast-analysis/rules/php.js +219 -0
- package/src/ast-analysis/rules/python.js +196 -0
- package/src/ast-analysis/rules/ruby.js +204 -0
- package/src/ast-analysis/rules/rust.js +173 -0
- package/src/ast-analysis/shared.js +223 -0
- package/src/ast.js +15 -28
- package/src/audit.js +4 -5
- package/src/boundaries.js +1 -1
- package/src/branch-compare.js +84 -79
- package/src/builder.js +0 -5
- package/src/cfg.js +106 -338
- package/src/check.js +3 -3
- package/src/cli.js +99 -179
- package/src/cochange.js +1 -1
- package/src/communities.js +13 -16
- package/src/complexity.js +196 -1239
- package/src/cycles.js +1 -1
- package/src/dataflow.js +269 -694
- package/src/db/connection.js +88 -0
- package/src/db/migrations.js +312 -0
- package/src/db/query-builder.js +280 -0
- package/src/db/repository.js +134 -0
- package/src/db.js +19 -399
- package/src/embedder.js +145 -141
- package/src/export.js +1 -1
- package/src/flow.js +161 -162
- package/src/index.js +34 -1
- package/src/kinds.js +49 -0
- package/src/manifesto.js +3 -8
- package/src/mcp.js +37 -20
- package/src/owners.js +132 -132
- package/src/queries-cli.js +866 -0
- package/src/queries.js +1323 -2267
- package/src/result-formatter.js +21 -0
- package/src/sequence.js +177 -182
- package/src/structure.js +200 -199
- package/src/test-filter.js +7 -0
- package/src/triage.js +120 -162
- package/src/viewer.js +1 -1
package/src/branch-compare.js
CHANGED
|
@@ -12,7 +12,9 @@ import os from 'node:os';
|
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import Database from 'better-sqlite3';
|
|
14
14
|
import { buildGraph } from './builder.js';
|
|
15
|
-
import {
|
|
15
|
+
import { kindIcon } from './queries.js';
|
|
16
|
+
import { outputResult } from './result-formatter.js';
|
|
17
|
+
import { isTestFile } from './test-filter.js';
|
|
16
18
|
|
|
17
19
|
// ─── Git Helpers ────────────────────────────────────────────────────────
|
|
18
20
|
|
|
@@ -81,55 +83,57 @@ function makeSymbolKey(kind, file, name) {
|
|
|
81
83
|
|
|
82
84
|
function loadSymbolsFromDb(dbPath, changedFiles, noTests) {
|
|
83
85
|
const db = new Database(dbPath, { readonly: true });
|
|
84
|
-
|
|
86
|
+
try {
|
|
87
|
+
const symbols = new Map();
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
89
|
+
if (changedFiles.length === 0) {
|
|
90
|
+
return symbols;
|
|
91
|
+
}
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
93
|
+
// Query nodes in changed files
|
|
94
|
+
const placeholders = changedFiles.map(() => '?').join(', ');
|
|
95
|
+
const rows = db
|
|
96
|
+
.prepare(
|
|
97
|
+
`SELECT n.id, n.name, n.kind, n.file, n.line, n.end_line
|
|
98
|
+
FROM nodes n
|
|
99
|
+
WHERE n.file IN (${placeholders})
|
|
100
|
+
AND n.kind NOT IN ('file', 'directory')
|
|
101
|
+
ORDER BY n.file, n.line`,
|
|
102
|
+
)
|
|
103
|
+
.all(...changedFiles);
|
|
104
|
+
|
|
105
|
+
// Compute fan_in and fan_out for each node
|
|
106
|
+
const fanInStmt = db.prepare(
|
|
107
|
+
`SELECT COUNT(*) AS cnt FROM edges WHERE target_id = ? AND kind = 'calls'`,
|
|
108
|
+
);
|
|
109
|
+
const fanOutStmt = db.prepare(
|
|
110
|
+
`SELECT COUNT(*) AS cnt FROM edges WHERE source_id = ? AND kind = 'calls'`,
|
|
111
|
+
);
|
|
110
112
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
113
|
+
for (const row of rows) {
|
|
114
|
+
if (noTests && isTestFile(row.file)) continue;
|
|
115
|
+
|
|
116
|
+
const lineCount = row.end_line ? row.end_line - row.line + 1 : 0;
|
|
117
|
+
const fanIn = fanInStmt.get(row.id).cnt;
|
|
118
|
+
const fanOut = fanOutStmt.get(row.id).cnt;
|
|
119
|
+
const key = makeSymbolKey(row.kind, row.file, row.name);
|
|
120
|
+
|
|
121
|
+
symbols.set(key, {
|
|
122
|
+
id: row.id,
|
|
123
|
+
name: row.name,
|
|
124
|
+
kind: row.kind,
|
|
125
|
+
file: row.file,
|
|
126
|
+
line: row.line,
|
|
127
|
+
lineCount,
|
|
128
|
+
fanIn,
|
|
129
|
+
fanOut,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
return symbols;
|
|
134
|
+
} finally {
|
|
135
|
+
db.close();
|
|
136
|
+
}
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
// ─── Caller BFS ─────────────────────────────────────────────────────────
|
|
@@ -138,40 +142,43 @@ function loadCallersFromDb(dbPath, nodeIds, maxDepth, noTests) {
|
|
|
138
142
|
if (nodeIds.length === 0) return [];
|
|
139
143
|
|
|
140
144
|
const db = new Database(dbPath, { readonly: true });
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
visited.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
145
|
+
try {
|
|
146
|
+
const allCallers = new Set();
|
|
147
|
+
|
|
148
|
+
for (const startId of nodeIds) {
|
|
149
|
+
const visited = new Set([startId]);
|
|
150
|
+
let frontier = [startId];
|
|
151
|
+
|
|
152
|
+
for (let d = 1; d <= maxDepth; d++) {
|
|
153
|
+
const nextFrontier = [];
|
|
154
|
+
for (const fid of frontier) {
|
|
155
|
+
const callers = db
|
|
156
|
+
.prepare(
|
|
157
|
+
`SELECT DISTINCT n.id, n.name, n.kind, n.file, n.line
|
|
158
|
+
FROM edges e JOIN nodes n ON e.source_id = n.id
|
|
159
|
+
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
160
|
+
)
|
|
161
|
+
.all(fid);
|
|
162
|
+
|
|
163
|
+
for (const c of callers) {
|
|
164
|
+
if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
|
|
165
|
+
visited.add(c.id);
|
|
166
|
+
nextFrontier.push(c.id);
|
|
167
|
+
allCallers.add(
|
|
168
|
+
JSON.stringify({ name: c.name, kind: c.kind, file: c.file, line: c.line }),
|
|
169
|
+
);
|
|
170
|
+
}
|
|
165
171
|
}
|
|
166
172
|
}
|
|
173
|
+
frontier = nextFrontier;
|
|
174
|
+
if (frontier.length === 0) break;
|
|
167
175
|
}
|
|
168
|
-
frontier = nextFrontier;
|
|
169
|
-
if (frontier.length === 0) break;
|
|
170
176
|
}
|
|
171
|
-
}
|
|
172
177
|
|
|
173
|
-
|
|
174
|
-
|
|
178
|
+
return [...allCallers].map((s) => JSON.parse(s));
|
|
179
|
+
} finally {
|
|
180
|
+
db.close();
|
|
181
|
+
}
|
|
175
182
|
}
|
|
176
183
|
|
|
177
184
|
// ─── Symbol Comparison ──────────────────────────────────────────────────
|
|
@@ -554,10 +561,8 @@ function formatText(data) {
|
|
|
554
561
|
export async function branchCompare(baseRef, targetRef, opts = {}) {
|
|
555
562
|
const data = await branchCompareData(baseRef, targetRef, opts);
|
|
556
563
|
|
|
557
|
-
if (opts.
|
|
558
|
-
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
564
|
+
if (opts.format === 'json') opts = { ...opts, json: true };
|
|
565
|
+
if (outputResult(data, null, opts)) return;
|
|
561
566
|
|
|
562
567
|
if (opts.format === 'mermaid') {
|
|
563
568
|
console.log(branchCompareMermaid(data));
|
package/src/builder.js
CHANGED
|
@@ -1448,16 +1448,12 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1448
1448
|
}
|
|
1449
1449
|
|
|
1450
1450
|
if (needsWasmTrees) {
|
|
1451
|
-
_t.wasmPre0 = performance.now();
|
|
1452
1451
|
try {
|
|
1453
1452
|
const { ensureWasmTrees } = await import('./parser.js');
|
|
1454
1453
|
await ensureWasmTrees(astComplexitySymbols, rootDir);
|
|
1455
1454
|
} catch (err) {
|
|
1456
1455
|
debug(`WASM pre-parse failed: ${err.message}`);
|
|
1457
1456
|
}
|
|
1458
|
-
_t.wasmPreMs = performance.now() - _t.wasmPre0;
|
|
1459
|
-
} else {
|
|
1460
|
-
_t.wasmPreMs = 0;
|
|
1461
1457
|
}
|
|
1462
1458
|
}
|
|
1463
1459
|
|
|
@@ -1601,7 +1597,6 @@ export async function buildGraph(rootDir, opts = {}) {
|
|
|
1601
1597
|
rolesMs: +_t.rolesMs.toFixed(1),
|
|
1602
1598
|
astMs: +_t.astMs.toFixed(1),
|
|
1603
1599
|
complexityMs: +_t.complexityMs.toFixed(1),
|
|
1604
|
-
...(_t.wasmPreMs != null && { wasmPreMs: +_t.wasmPreMs.toFixed(1) }),
|
|
1605
1600
|
...(_t.cfgMs != null && { cfgMs: +_t.cfgMs.toFixed(1) }),
|
|
1606
1601
|
...(_t.dataflowMs != null && { dataflowMs: +_t.dataflowMs.toFixed(1) }),
|
|
1607
1602
|
},
|