@optave/codegraph 3.0.4 → 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 +59 -52
- package/grammars/tree-sitter-go.wasm +0 -0
- package/package.json +9 -10
- 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 +274 -159
- package/src/cfg.js +111 -341
- package/src/check.js +3 -3
- package/src/cli.js +122 -167
- 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 +274 -697
- 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 -392
- package/src/embedder.js +145 -141
- package/src/export.js +1 -1
- package/src/flow.js +160 -228
- package/src/index.js +36 -2
- package/src/kinds.js +49 -0
- package/src/manifesto.js +3 -8
- package/src/mcp.js +97 -20
- package/src/owners.js +132 -132
- package/src/parser.js +58 -131
- package/src/queries-cli.js +866 -0
- package/src/queries.js +1356 -2261
- package/src/resolve.js +11 -2
- package/src/result-formatter.js +21 -0
- package/src/sequence.js +364 -0
- 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/flow.js
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { openReadonlyOrFail } from './db.js';
|
|
9
|
-
import { paginateResult
|
|
10
|
-
import {
|
|
9
|
+
import { paginateResult } from './paginate.js';
|
|
10
|
+
import { CORE_SYMBOL_KINDS, findMatchingNodes, kindIcon } from './queries.js';
|
|
11
|
+
import { outputResult } from './result-formatter.js';
|
|
11
12
|
import { FRAMEWORK_ENTRY_PREFIXES } from './structure.js';
|
|
13
|
+
import { isTestFile } from './test-filter.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Determine the entry point type from a node name based on framework prefixes.
|
|
@@ -35,46 +37,49 @@ export function entryPointType(name) {
|
|
|
35
37
|
*/
|
|
36
38
|
export function listEntryPointsData(dbPath, opts = {}) {
|
|
37
39
|
const db = openReadonlyOrFail(dbPath);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let rows = db
|
|
45
|
-
.prepare(
|
|
46
|
-
`SELECT n.name, n.kind, n.file, n.line, n.role
|
|
47
|
-
FROM nodes n
|
|
48
|
-
WHERE (
|
|
49
|
-
(${prefixConditions})
|
|
50
|
-
OR n.role = 'entry'
|
|
51
|
-
)
|
|
52
|
-
AND n.kind NOT IN ('file', 'directory')
|
|
53
|
-
ORDER BY n.name`,
|
|
54
|
-
)
|
|
55
|
-
.all(...prefixParams);
|
|
56
|
-
|
|
57
|
-
if (noTests) rows = rows.filter((r) => !isTestFile(r.file));
|
|
58
|
-
|
|
59
|
-
const entries = rows.map((r) => ({
|
|
60
|
-
name: r.name,
|
|
61
|
-
kind: r.kind,
|
|
62
|
-
file: r.file,
|
|
63
|
-
line: r.line,
|
|
64
|
-
role: r.role,
|
|
65
|
-
type: entryPointType(r.name) || (r.role === 'entry' ? 'exported' : null),
|
|
66
|
-
}));
|
|
67
|
-
|
|
68
|
-
const byType = {};
|
|
69
|
-
for (const e of entries) {
|
|
70
|
-
const t = e.type || 'other';
|
|
71
|
-
if (!byType[t]) byType[t] = [];
|
|
72
|
-
byType[t].push(e);
|
|
73
|
-
}
|
|
40
|
+
try {
|
|
41
|
+
const noTests = opts.noTests || false;
|
|
42
|
+
|
|
43
|
+
// Find all framework-prefixed nodes
|
|
44
|
+
const prefixConditions = FRAMEWORK_ENTRY_PREFIXES.map(() => 'n.name LIKE ?').join(' OR ');
|
|
45
|
+
const prefixParams = FRAMEWORK_ENTRY_PREFIXES.map((p) => `${p}%`);
|
|
74
46
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
47
|
+
let rows = db
|
|
48
|
+
.prepare(
|
|
49
|
+
`SELECT n.name, n.kind, n.file, n.line, n.role
|
|
50
|
+
FROM nodes n
|
|
51
|
+
WHERE (
|
|
52
|
+
(${prefixConditions})
|
|
53
|
+
OR n.role = 'entry'
|
|
54
|
+
)
|
|
55
|
+
AND n.kind NOT IN ('file', 'directory')
|
|
56
|
+
ORDER BY n.name`,
|
|
57
|
+
)
|
|
58
|
+
.all(...prefixParams);
|
|
59
|
+
|
|
60
|
+
if (noTests) rows = rows.filter((r) => !isTestFile(r.file));
|
|
61
|
+
|
|
62
|
+
const entries = rows.map((r) => ({
|
|
63
|
+
name: r.name,
|
|
64
|
+
kind: r.kind,
|
|
65
|
+
file: r.file,
|
|
66
|
+
line: r.line,
|
|
67
|
+
role: r.role,
|
|
68
|
+
type: entryPointType(r.name) || (r.role === 'entry' ? 'exported' : null),
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
const byType = {};
|
|
72
|
+
for (const e of entries) {
|
|
73
|
+
const t = e.type || 'other';
|
|
74
|
+
if (!byType[t]) byType[t] = [];
|
|
75
|
+
byType[t].push(e);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const base = { entries, byType, count: entries.length };
|
|
79
|
+
return paginateResult(base, 'entries', { limit: opts.limit, offset: opts.offset });
|
|
80
|
+
} finally {
|
|
81
|
+
db.close();
|
|
82
|
+
}
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
@@ -91,199 +96,136 @@ export function listEntryPointsData(dbPath, opts = {}) {
|
|
|
91
96
|
*/
|
|
92
97
|
export function flowData(name, dbPath, opts = {}) {
|
|
93
98
|
const db = openReadonlyOrFail(dbPath);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
try {
|
|
100
|
+
const maxDepth = opts.depth || 10;
|
|
101
|
+
const noTests = opts.noTests || false;
|
|
102
|
+
const flowOpts = { ...opts, kinds: opts.kind ? [opts.kind] : CORE_SYMBOL_KINDS };
|
|
103
|
+
|
|
104
|
+
// Phase 1: Direct LIKE match on full name (use all 10 core symbol kinds,
|
|
105
|
+
// not just FUNCTION_KINDS, so flow can trace from interfaces/types/structs/etc.)
|
|
106
|
+
let matchNode = findMatchingNodes(db, name, flowOpts)[0] ?? null;
|
|
107
|
+
|
|
108
|
+
// Phase 2: Prefix-stripped matching — try adding framework prefixes
|
|
109
|
+
if (!matchNode) {
|
|
110
|
+
for (const prefix of FRAMEWORK_ENTRY_PREFIXES) {
|
|
111
|
+
matchNode = findMatchingNodes(db, `${prefix}${name}`, flowOpts)[0] ?? null;
|
|
112
|
+
if (matchNode) break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
99
115
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
if (!matchNode) {
|
|
117
|
+
return {
|
|
118
|
+
entry: null,
|
|
119
|
+
depth: maxDepth,
|
|
120
|
+
steps: [],
|
|
121
|
+
leaves: [],
|
|
122
|
+
cycles: [],
|
|
123
|
+
totalReached: 0,
|
|
124
|
+
truncated: false,
|
|
125
|
+
};
|
|
105
126
|
}
|
|
106
|
-
}
|
|
107
127
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
totalReached: 0,
|
|
117
|
-
truncated: false,
|
|
128
|
+
const epType = entryPointType(matchNode.name);
|
|
129
|
+
const entry = {
|
|
130
|
+
name: matchNode.name,
|
|
131
|
+
kind: matchNode.kind,
|
|
132
|
+
file: matchNode.file,
|
|
133
|
+
line: matchNode.line,
|
|
134
|
+
type: epType || 'exported',
|
|
135
|
+
role: matchNode.role,
|
|
118
136
|
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const epType = entryPointType(matchNode.name);
|
|
122
|
-
const entry = {
|
|
123
|
-
name: matchNode.name,
|
|
124
|
-
kind: matchNode.kind,
|
|
125
|
-
file: matchNode.file,
|
|
126
|
-
line: matchNode.line,
|
|
127
|
-
type: epType || 'exported',
|
|
128
|
-
role: matchNode.role,
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// Forward BFS through callees
|
|
132
|
-
const visited = new Set([matchNode.id]);
|
|
133
|
-
let frontier = [matchNode.id];
|
|
134
|
-
const steps = [];
|
|
135
|
-
const cycles = [];
|
|
136
|
-
let truncated = false;
|
|
137
|
-
|
|
138
|
-
// Track which nodes are at each depth and their depth for leaf detection
|
|
139
|
-
const nodeDepths = new Map();
|
|
140
|
-
const idToNode = new Map();
|
|
141
|
-
idToNode.set(matchNode.id, entry);
|
|
142
|
-
|
|
143
|
-
for (let d = 1; d <= maxDepth; d++) {
|
|
144
|
-
const nextFrontier = [];
|
|
145
|
-
const levelNodes = [];
|
|
146
|
-
|
|
147
|
-
for (const fid of frontier) {
|
|
148
|
-
const callees = db
|
|
149
|
-
.prepare(
|
|
150
|
-
`SELECT DISTINCT n.id, n.name, n.kind, n.file, n.line, n.role
|
|
151
|
-
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
152
|
-
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
153
|
-
)
|
|
154
|
-
.all(fid);
|
|
155
|
-
|
|
156
|
-
for (const c of callees) {
|
|
157
|
-
if (noTests && isTestFile(c.file)) continue;
|
|
158
137
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
138
|
+
// Forward BFS through callees
|
|
139
|
+
const visited = new Set([matchNode.id]);
|
|
140
|
+
let frontier = [matchNode.id];
|
|
141
|
+
const steps = [];
|
|
142
|
+
const cycles = [];
|
|
143
|
+
let truncated = false;
|
|
144
|
+
|
|
145
|
+
// Track which nodes are at each depth and their depth for leaf detection
|
|
146
|
+
const nodeDepths = new Map();
|
|
147
|
+
const idToNode = new Map();
|
|
148
|
+
idToNode.set(matchNode.id, entry);
|
|
149
|
+
|
|
150
|
+
for (let d = 1; d <= maxDepth; d++) {
|
|
151
|
+
const nextFrontier = [];
|
|
152
|
+
const levelNodes = [];
|
|
153
|
+
|
|
154
|
+
for (const fid of frontier) {
|
|
155
|
+
const callees = db
|
|
156
|
+
.prepare(
|
|
157
|
+
`SELECT DISTINCT n.id, n.name, n.kind, n.file, n.line, n.role
|
|
158
|
+
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
159
|
+
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
160
|
+
)
|
|
161
|
+
.all(fid);
|
|
162
|
+
|
|
163
|
+
for (const c of callees) {
|
|
164
|
+
if (noTests && isTestFile(c.file)) continue;
|
|
165
|
+
|
|
166
|
+
if (visited.has(c.id)) {
|
|
167
|
+
// Cycle detected
|
|
168
|
+
const fromNode = idToNode.get(fid);
|
|
169
|
+
if (fromNode) {
|
|
170
|
+
cycles.push({ from: fromNode.name, to: c.name, depth: d });
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
164
173
|
}
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
visited.add(c.id);
|
|
176
|
+
nextFrontier.push(c.id);
|
|
177
|
+
const nodeInfo = { name: c.name, kind: c.kind, file: c.file, line: c.line };
|
|
178
|
+
levelNodes.push(nodeInfo);
|
|
179
|
+
nodeDepths.set(c.id, d);
|
|
180
|
+
idToNode.set(c.id, nodeInfo);
|
|
181
|
+
}
|
|
174
182
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (levelNodes.length > 0) {
|
|
178
|
-
steps.push({ depth: d, nodes: levelNodes });
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
frontier = nextFrontier;
|
|
182
|
-
if (frontier.length === 0) break;
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
184
|
+
if (levelNodes.length > 0) {
|
|
185
|
+
steps.push({ depth: d, nodes: levelNodes });
|
|
186
|
+
}
|
|
188
187
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const leaves = [];
|
|
192
|
-
for (const [id, depth] of nodeDepths) {
|
|
193
|
-
const outgoing = db
|
|
194
|
-
.prepare(
|
|
195
|
-
`SELECT DISTINCT n.id
|
|
196
|
-
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
197
|
-
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
198
|
-
)
|
|
199
|
-
.all(id);
|
|
188
|
+
frontier = nextFrontier;
|
|
189
|
+
if (frontier.length === 0) break;
|
|
200
190
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (node) {
|
|
204
|
-
leaves.push({ ...node, depth });
|
|
191
|
+
if (d === maxDepth && frontier.length > 0) {
|
|
192
|
+
truncated = true;
|
|
205
193
|
}
|
|
206
194
|
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
db.close();
|
|
210
|
-
const base = {
|
|
211
|
-
entry,
|
|
212
|
-
depth: maxDepth,
|
|
213
|
-
steps,
|
|
214
|
-
leaves,
|
|
215
|
-
cycles,
|
|
216
|
-
totalReached: visited.size - 1, // exclude the entry node itself
|
|
217
|
-
truncated,
|
|
218
|
-
};
|
|
219
|
-
return paginateResult(base, 'steps', { limit: opts.limit, offset: opts.offset });
|
|
220
|
-
}
|
|
221
195
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
'type',
|
|
234
|
-
'struct',
|
|
235
|
-
'enum',
|
|
236
|
-
'trait',
|
|
237
|
-
'record',
|
|
238
|
-
'module',
|
|
239
|
-
];
|
|
240
|
-
const placeholders = kinds.map(() => '?').join(', ');
|
|
241
|
-
const params = [`%${name}%`, ...kinds];
|
|
242
|
-
|
|
243
|
-
let fileCondition = '';
|
|
244
|
-
if (opts.file) {
|
|
245
|
-
fileCondition = ' AND n.file LIKE ?';
|
|
246
|
-
params.push(`%${opts.file}%`);
|
|
247
|
-
}
|
|
196
|
+
// Identify leaves: visited nodes that have no outgoing 'calls' edges to other visited nodes
|
|
197
|
+
// (or no outgoing calls at all)
|
|
198
|
+
const leaves = [];
|
|
199
|
+
for (const [id, depth] of nodeDepths) {
|
|
200
|
+
const outgoing = db
|
|
201
|
+
.prepare(
|
|
202
|
+
`SELECT DISTINCT n.id
|
|
203
|
+
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
204
|
+
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
205
|
+
)
|
|
206
|
+
.all(id);
|
|
248
207
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
) fi ON fi.target_id = n.id
|
|
256
|
-
WHERE n.name LIKE ? AND n.kind IN (${placeholders})${fileCondition}`,
|
|
257
|
-
)
|
|
258
|
-
.all(...params);
|
|
259
|
-
|
|
260
|
-
const noTests = opts.noTests || false;
|
|
261
|
-
const nodes = noTests ? rows.filter((n) => !isTestFile(n.file)) : rows;
|
|
262
|
-
|
|
263
|
-
if (nodes.length === 0) return null;
|
|
264
|
-
|
|
265
|
-
const lowerQuery = name.toLowerCase();
|
|
266
|
-
for (const node of nodes) {
|
|
267
|
-
const lowerName = node.name.toLowerCase();
|
|
268
|
-
const bareName = lowerName.includes('.') ? lowerName.split('.').pop() : lowerName;
|
|
269
|
-
|
|
270
|
-
let matchScore;
|
|
271
|
-
if (lowerName === lowerQuery || bareName === lowerQuery) {
|
|
272
|
-
matchScore = 100;
|
|
273
|
-
} else if (lowerName.startsWith(lowerQuery) || bareName.startsWith(lowerQuery)) {
|
|
274
|
-
matchScore = 60;
|
|
275
|
-
} else if (lowerName.includes(`.${lowerQuery}`) || lowerName.includes(`${lowerQuery}.`)) {
|
|
276
|
-
matchScore = 40;
|
|
277
|
-
} else {
|
|
278
|
-
matchScore = 10;
|
|
208
|
+
if (outgoing.length === 0) {
|
|
209
|
+
const node = idToNode.get(id);
|
|
210
|
+
if (node) {
|
|
211
|
+
leaves.push({ ...node, depth });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
279
214
|
}
|
|
280
215
|
|
|
281
|
-
const
|
|
282
|
-
|
|
216
|
+
const base = {
|
|
217
|
+
entry,
|
|
218
|
+
depth: maxDepth,
|
|
219
|
+
steps,
|
|
220
|
+
leaves,
|
|
221
|
+
cycles,
|
|
222
|
+
totalReached: visited.size - 1, // exclude the entry node itself
|
|
223
|
+
truncated,
|
|
224
|
+
};
|
|
225
|
+
return paginateResult(base, 'steps', { limit: opts.limit, offset: opts.offset });
|
|
226
|
+
} finally {
|
|
227
|
+
db.close();
|
|
283
228
|
}
|
|
284
|
-
|
|
285
|
-
nodes.sort((a, b) => b._relevance - a._relevance);
|
|
286
|
-
return nodes[0];
|
|
287
229
|
}
|
|
288
230
|
|
|
289
231
|
/**
|
|
@@ -296,14 +238,7 @@ export function flow(name, dbPath, opts = {}) {
|
|
|
296
238
|
limit: opts.limit,
|
|
297
239
|
offset: opts.offset,
|
|
298
240
|
});
|
|
299
|
-
if (opts
|
|
300
|
-
printNdjson(data, 'entries');
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
if (opts.json) {
|
|
304
|
-
console.log(JSON.stringify(data, null, 2));
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
241
|
+
if (outputResult(data, 'entries', opts)) return;
|
|
307
242
|
if (data.count === 0) {
|
|
308
243
|
console.log('No entry points found. Run "codegraph build" first.');
|
|
309
244
|
return;
|
|
@@ -320,10 +255,7 @@ export function flow(name, dbPath, opts = {}) {
|
|
|
320
255
|
}
|
|
321
256
|
|
|
322
257
|
const data = flowData(name, dbPath, opts);
|
|
323
|
-
if (opts
|
|
324
|
-
console.log(JSON.stringify(data, null, 2));
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
258
|
+
if (outputResult(data, 'steps', opts)) return;
|
|
327
259
|
|
|
328
260
|
if (!data.entry) {
|
|
329
261
|
console.log(`No matching entry point or function found for "${name}".`);
|
package/src/index.js
CHANGED
|
@@ -77,12 +77,24 @@ export {
|
|
|
77
77
|
} from './dataflow.js';
|
|
78
78
|
// Database utilities
|
|
79
79
|
export {
|
|
80
|
+
countEdges,
|
|
81
|
+
countFiles,
|
|
82
|
+
countNodes,
|
|
83
|
+
fanInJoinSQL,
|
|
84
|
+
fanOutJoinSQL,
|
|
80
85
|
findDbPath,
|
|
86
|
+
findNodesForTriage,
|
|
87
|
+
findNodesWithFanIn,
|
|
81
88
|
getBuildMeta,
|
|
82
89
|
initSchema,
|
|
90
|
+
iterateFunctionNodes,
|
|
91
|
+
kindInClause,
|
|
92
|
+
listFunctionNodes,
|
|
93
|
+
NodeQuery,
|
|
83
94
|
openDb,
|
|
84
95
|
openReadonlyOrFail,
|
|
85
96
|
setBuildMeta,
|
|
97
|
+
testFilterSQL,
|
|
86
98
|
} from './db.js';
|
|
87
99
|
// Embeddings
|
|
88
100
|
export {
|
|
@@ -121,7 +133,6 @@ export { isNativeAvailable } from './native.js';
|
|
|
121
133
|
export { matchOwners, owners, ownersData, ownersForFiles, parseCodeowners } from './owners.js';
|
|
122
134
|
// Pagination utilities
|
|
123
135
|
export { MCP_DEFAULTS, MCP_MAX_LIMIT, paginate, paginateResult, printNdjson } from './paginate.js';
|
|
124
|
-
|
|
125
136
|
// Unified parser API
|
|
126
137
|
export { getActiveEngine, isWasmAvailable, parseFileAuto, parseFilesAuto } from './parser.js';
|
|
127
138
|
// Query functions (data-returning)
|
|
@@ -141,7 +152,6 @@ export {
|
|
|
141
152
|
FALSE_POSITIVE_CALLER_THRESHOLD,
|
|
142
153
|
FALSE_POSITIVE_NAMES,
|
|
143
154
|
fileDepsData,
|
|
144
|
-
fileExports,
|
|
145
155
|
fnDepsData,
|
|
146
156
|
fnImpactData,
|
|
147
157
|
impactAnalysisData,
|
|
@@ -159,6 +169,24 @@ export {
|
|
|
159
169
|
VALID_ROLES,
|
|
160
170
|
whereData,
|
|
161
171
|
} from './queries.js';
|
|
172
|
+
// Query CLI display wrappers
|
|
173
|
+
export {
|
|
174
|
+
children,
|
|
175
|
+
context,
|
|
176
|
+
diffImpact,
|
|
177
|
+
explain,
|
|
178
|
+
fileDeps,
|
|
179
|
+
fileExports,
|
|
180
|
+
fnDeps,
|
|
181
|
+
fnImpact,
|
|
182
|
+
impactAnalysis,
|
|
183
|
+
moduleMap,
|
|
184
|
+
queryName,
|
|
185
|
+
roles,
|
|
186
|
+
stats,
|
|
187
|
+
symbolPath,
|
|
188
|
+
where,
|
|
189
|
+
} from './queries-cli.js';
|
|
162
190
|
// Registry (multi-repo)
|
|
163
191
|
export {
|
|
164
192
|
listRepos,
|
|
@@ -170,6 +198,10 @@ export {
|
|
|
170
198
|
saveRegistry,
|
|
171
199
|
unregisterRepo,
|
|
172
200
|
} from './registry.js';
|
|
201
|
+
// Result formatting
|
|
202
|
+
export { outputResult } from './result-formatter.js';
|
|
203
|
+
// Sequence diagram generation
|
|
204
|
+
export { sequence, sequenceData, sequenceToMermaid } from './sequence.js';
|
|
173
205
|
// Snapshot management
|
|
174
206
|
export {
|
|
175
207
|
snapshotDelete,
|
|
@@ -191,6 +223,8 @@ export {
|
|
|
191
223
|
moduleBoundariesData,
|
|
192
224
|
structureData,
|
|
193
225
|
} from './structure.js';
|
|
226
|
+
// Test file detection
|
|
227
|
+
export { isTestFile, TEST_PATTERN } from './test-filter.js';
|
|
194
228
|
// Triage — composite risk audit
|
|
195
229
|
export { triage, triageData } from './triage.js';
|
|
196
230
|
// Interactive HTML viewer
|
package/src/kinds.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// ── Symbol kind constants ───────────────────────────────────────────
|
|
2
|
+
// Original 10 kinds — used as default query scope
|
|
3
|
+
export const CORE_SYMBOL_KINDS = [
|
|
4
|
+
'function',
|
|
5
|
+
'method',
|
|
6
|
+
'class',
|
|
7
|
+
'interface',
|
|
8
|
+
'type',
|
|
9
|
+
'struct',
|
|
10
|
+
'enum',
|
|
11
|
+
'trait',
|
|
12
|
+
'record',
|
|
13
|
+
'module',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// Sub-declaration kinds (Phase 1)
|
|
17
|
+
export const EXTENDED_SYMBOL_KINDS = [
|
|
18
|
+
'parameter',
|
|
19
|
+
'property',
|
|
20
|
+
'constant',
|
|
21
|
+
// Phase 2 (reserved, not yet extracted):
|
|
22
|
+
// 'constructor', 'namespace', 'decorator', 'getter', 'setter',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// Full set for --kind validation and MCP enum
|
|
26
|
+
export const EVERY_SYMBOL_KIND = [...CORE_SYMBOL_KINDS, ...EXTENDED_SYMBOL_KINDS];
|
|
27
|
+
|
|
28
|
+
// Backward compat: ALL_SYMBOL_KINDS stays as the core 10
|
|
29
|
+
export const ALL_SYMBOL_KINDS = CORE_SYMBOL_KINDS;
|
|
30
|
+
|
|
31
|
+
// ── Edge kind constants ─────────────────────────────────────────────
|
|
32
|
+
// Core edge kinds — coupling and dependency relationships
|
|
33
|
+
export const CORE_EDGE_KINDS = [
|
|
34
|
+
'imports',
|
|
35
|
+
'imports-type',
|
|
36
|
+
'reexports',
|
|
37
|
+
'calls',
|
|
38
|
+
'extends',
|
|
39
|
+
'implements',
|
|
40
|
+
'contains',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// Structural edge kinds — parent/child and type relationships
|
|
44
|
+
export const STRUCTURAL_EDGE_KINDS = ['parameter_of', 'receiver'];
|
|
45
|
+
|
|
46
|
+
// Full set for MCP enum and validation
|
|
47
|
+
export const EVERY_EDGE_KIND = [...CORE_EDGE_KINDS, ...STRUCTURAL_EDGE_KINDS];
|
|
48
|
+
|
|
49
|
+
export const VALID_ROLES = ['entry', 'core', 'utility', 'adapter', 'dead', 'leaf'];
|
package/src/manifesto.js
CHANGED
|
@@ -3,7 +3,8 @@ import { loadConfig } from './config.js';
|
|
|
3
3
|
import { findCycles } from './cycles.js';
|
|
4
4
|
import { openReadonlyOrFail } from './db.js';
|
|
5
5
|
import { debug } from './logger.js';
|
|
6
|
-
import { paginateResult
|
|
6
|
+
import { paginateResult } from './paginate.js';
|
|
7
|
+
import { outputResult } from './result-formatter.js';
|
|
7
8
|
|
|
8
9
|
// ─── Rule Definitions ─────────────────────────────────────────────────
|
|
9
10
|
|
|
@@ -434,13 +435,7 @@ export function manifestoData(customDbPath, opts = {}) {
|
|
|
434
435
|
export function manifesto(customDbPath, opts = {}) {
|
|
435
436
|
const data = manifestoData(customDbPath, opts);
|
|
436
437
|
|
|
437
|
-
if (opts
|
|
438
|
-
printNdjson(data, 'violations');
|
|
439
|
-
if (!data.passed) process.exit(1);
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
if (opts.json) {
|
|
443
|
-
console.log(JSON.stringify(data, null, 2));
|
|
438
|
+
if (outputResult(data, 'violations', opts)) {
|
|
444
439
|
if (!data.passed) process.exit(1);
|
|
445
440
|
return;
|
|
446
441
|
}
|