@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/cfg.js
CHANGED
|
@@ -7,265 +7,25 @@
|
|
|
7
7
|
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import { COMPLEXITY_RULES } from './
|
|
10
|
+
import { CFG_RULES, COMPLEXITY_RULES } from './ast-analysis/rules/index.js';
|
|
11
|
+
import {
|
|
12
|
+
makeCfgRules as _makeCfgRules,
|
|
13
|
+
buildExtensionSet,
|
|
14
|
+
buildExtToLangMap,
|
|
15
|
+
findFunctionNode,
|
|
16
|
+
} from './ast-analysis/shared.js';
|
|
11
17
|
import { openReadonlyOrFail } from './db.js';
|
|
12
18
|
import { info } from './logger.js';
|
|
13
|
-
import { paginateResult
|
|
14
|
-
import { LANGUAGE_REGISTRY } from './parser.js';
|
|
15
|
-
import { isTestFile } from './queries.js';
|
|
16
|
-
|
|
17
|
-
// ─── CFG Node Type Rules (extends COMPLEXITY_RULES) ──────────────────────
|
|
18
|
-
|
|
19
|
-
const CFG_DEFAULTS = {
|
|
20
|
-
ifNode: null,
|
|
21
|
-
ifNodes: null,
|
|
22
|
-
elifNode: null,
|
|
23
|
-
elseClause: null,
|
|
24
|
-
elseViaAlternative: false,
|
|
25
|
-
ifConsequentField: null,
|
|
26
|
-
forNodes: new Set(),
|
|
27
|
-
whileNode: null,
|
|
28
|
-
whileNodes: null,
|
|
29
|
-
doNode: null,
|
|
30
|
-
infiniteLoopNode: null,
|
|
31
|
-
unlessNode: null,
|
|
32
|
-
untilNode: null,
|
|
33
|
-
switchNode: null,
|
|
34
|
-
switchNodes: null,
|
|
35
|
-
caseNode: null,
|
|
36
|
-
caseNodes: null,
|
|
37
|
-
defaultNode: null,
|
|
38
|
-
tryNode: null,
|
|
39
|
-
catchNode: null,
|
|
40
|
-
finallyNode: null,
|
|
41
|
-
returnNode: null,
|
|
42
|
-
throwNode: null,
|
|
43
|
-
breakNode: null,
|
|
44
|
-
continueNode: null,
|
|
45
|
-
blockNode: null,
|
|
46
|
-
blockNodes: null,
|
|
47
|
-
labeledNode: null,
|
|
48
|
-
functionNodes: new Set(),
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const CFG_RULE_KEYS = new Set(Object.keys(CFG_DEFAULTS));
|
|
52
|
-
|
|
53
|
-
export function makeCfgRules(overrides) {
|
|
54
|
-
for (const key of Object.keys(overrides)) {
|
|
55
|
-
if (!CFG_RULE_KEYS.has(key)) {
|
|
56
|
-
throw new Error(`CFG rules: unknown key "${key}"`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const rules = { ...CFG_DEFAULTS, ...overrides };
|
|
60
|
-
if (!(rules.functionNodes instanceof Set) || rules.functionNodes.size === 0) {
|
|
61
|
-
throw new Error('CFG rules: functionNodes must be a non-empty Set');
|
|
62
|
-
}
|
|
63
|
-
if (!(rules.forNodes instanceof Set)) {
|
|
64
|
-
throw new Error('CFG rules: forNodes must be a Set');
|
|
65
|
-
}
|
|
66
|
-
return rules;
|
|
67
|
-
}
|
|
19
|
+
import { paginateResult } from './paginate.js';
|
|
68
20
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
defaultNode: 'switch_default',
|
|
78
|
-
tryNode: 'try_statement',
|
|
79
|
-
catchNode: 'catch_clause',
|
|
80
|
-
finallyNode: 'finally_clause',
|
|
81
|
-
returnNode: 'return_statement',
|
|
82
|
-
throwNode: 'throw_statement',
|
|
83
|
-
breakNode: 'break_statement',
|
|
84
|
-
continueNode: 'continue_statement',
|
|
85
|
-
blockNode: 'statement_block',
|
|
86
|
-
labeledNode: 'labeled_statement',
|
|
87
|
-
functionNodes: new Set([
|
|
88
|
-
'function_declaration',
|
|
89
|
-
'function_expression',
|
|
90
|
-
'arrow_function',
|
|
91
|
-
'method_definition',
|
|
92
|
-
'generator_function',
|
|
93
|
-
'generator_function_declaration',
|
|
94
|
-
]),
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const PYTHON_CFG = makeCfgRules({
|
|
98
|
-
ifNode: 'if_statement',
|
|
99
|
-
elifNode: 'elif_clause',
|
|
100
|
-
elseClause: 'else_clause',
|
|
101
|
-
forNodes: new Set(['for_statement']),
|
|
102
|
-
whileNode: 'while_statement',
|
|
103
|
-
switchNode: 'match_statement',
|
|
104
|
-
caseNode: 'case_clause',
|
|
105
|
-
tryNode: 'try_statement',
|
|
106
|
-
catchNode: 'except_clause',
|
|
107
|
-
finallyNode: 'finally_clause',
|
|
108
|
-
returnNode: 'return_statement',
|
|
109
|
-
throwNode: 'raise_statement',
|
|
110
|
-
breakNode: 'break_statement',
|
|
111
|
-
continueNode: 'continue_statement',
|
|
112
|
-
blockNode: 'block',
|
|
113
|
-
functionNodes: new Set(['function_definition']),
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const GO_CFG = makeCfgRules({
|
|
117
|
-
ifNode: 'if_statement',
|
|
118
|
-
elseViaAlternative: true,
|
|
119
|
-
forNodes: new Set(['for_statement']),
|
|
120
|
-
switchNodes: new Set([
|
|
121
|
-
'expression_switch_statement',
|
|
122
|
-
'type_switch_statement',
|
|
123
|
-
'select_statement',
|
|
124
|
-
]),
|
|
125
|
-
caseNode: 'expression_case',
|
|
126
|
-
caseNodes: new Set(['type_case', 'communication_case']),
|
|
127
|
-
defaultNode: 'default_case',
|
|
128
|
-
returnNode: 'return_statement',
|
|
129
|
-
breakNode: 'break_statement',
|
|
130
|
-
continueNode: 'continue_statement',
|
|
131
|
-
blockNode: 'block',
|
|
132
|
-
labeledNode: 'labeled_statement',
|
|
133
|
-
functionNodes: new Set(['function_declaration', 'method_declaration', 'func_literal']),
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const RUST_CFG = makeCfgRules({
|
|
137
|
-
ifNode: 'if_expression',
|
|
138
|
-
ifNodes: new Set(['if_let_expression']),
|
|
139
|
-
elseClause: 'else_clause',
|
|
140
|
-
forNodes: new Set(['for_expression']),
|
|
141
|
-
whileNode: 'while_expression',
|
|
142
|
-
whileNodes: new Set(['while_let_expression']),
|
|
143
|
-
infiniteLoopNode: 'loop_expression',
|
|
144
|
-
switchNode: 'match_expression',
|
|
145
|
-
caseNode: 'match_arm',
|
|
146
|
-
returnNode: 'return_expression',
|
|
147
|
-
breakNode: 'break_expression',
|
|
148
|
-
continueNode: 'continue_expression',
|
|
149
|
-
blockNode: 'block',
|
|
150
|
-
functionNodes: new Set(['function_item', 'closure_expression']),
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
const JAVA_CFG = makeCfgRules({
|
|
154
|
-
ifNode: 'if_statement',
|
|
155
|
-
elseViaAlternative: true,
|
|
156
|
-
forNodes: new Set(['for_statement', 'enhanced_for_statement']),
|
|
157
|
-
whileNode: 'while_statement',
|
|
158
|
-
doNode: 'do_statement',
|
|
159
|
-
switchNode: 'switch_expression',
|
|
160
|
-
caseNode: 'switch_block_statement_group',
|
|
161
|
-
caseNodes: new Set(['switch_rule']),
|
|
162
|
-
tryNode: 'try_statement',
|
|
163
|
-
catchNode: 'catch_clause',
|
|
164
|
-
finallyNode: 'finally_clause',
|
|
165
|
-
returnNode: 'return_statement',
|
|
166
|
-
throwNode: 'throw_statement',
|
|
167
|
-
breakNode: 'break_statement',
|
|
168
|
-
continueNode: 'continue_statement',
|
|
169
|
-
blockNode: 'block',
|
|
170
|
-
labeledNode: 'labeled_statement',
|
|
171
|
-
functionNodes: new Set(['method_declaration', 'constructor_declaration', 'lambda_expression']),
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const CSHARP_CFG = makeCfgRules({
|
|
175
|
-
ifNode: 'if_statement',
|
|
176
|
-
elseViaAlternative: true,
|
|
177
|
-
forNodes: new Set(['for_statement', 'foreach_statement']),
|
|
178
|
-
whileNode: 'while_statement',
|
|
179
|
-
doNode: 'do_statement',
|
|
180
|
-
switchNode: 'switch_statement',
|
|
181
|
-
caseNode: 'switch_section',
|
|
182
|
-
tryNode: 'try_statement',
|
|
183
|
-
catchNode: 'catch_clause',
|
|
184
|
-
finallyNode: 'finally_clause',
|
|
185
|
-
returnNode: 'return_statement',
|
|
186
|
-
throwNode: 'throw_statement',
|
|
187
|
-
breakNode: 'break_statement',
|
|
188
|
-
continueNode: 'continue_statement',
|
|
189
|
-
blockNode: 'block',
|
|
190
|
-
labeledNode: 'labeled_statement',
|
|
191
|
-
functionNodes: new Set([
|
|
192
|
-
'method_declaration',
|
|
193
|
-
'constructor_declaration',
|
|
194
|
-
'lambda_expression',
|
|
195
|
-
'local_function_statement',
|
|
196
|
-
]),
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const RUBY_CFG = makeCfgRules({
|
|
200
|
-
ifNode: 'if',
|
|
201
|
-
elifNode: 'elsif',
|
|
202
|
-
elseClause: 'else',
|
|
203
|
-
forNodes: new Set(['for']),
|
|
204
|
-
whileNode: 'while',
|
|
205
|
-
unlessNode: 'unless',
|
|
206
|
-
untilNode: 'until',
|
|
207
|
-
switchNode: 'case',
|
|
208
|
-
caseNode: 'when',
|
|
209
|
-
defaultNode: 'else',
|
|
210
|
-
tryNode: 'begin',
|
|
211
|
-
catchNode: 'rescue',
|
|
212
|
-
finallyNode: 'ensure',
|
|
213
|
-
returnNode: 'return',
|
|
214
|
-
breakNode: 'break',
|
|
215
|
-
continueNode: 'next',
|
|
216
|
-
blockNodes: new Set(['then', 'do', 'body_statement']),
|
|
217
|
-
functionNodes: new Set(['method', 'singleton_method']),
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const PHP_CFG = makeCfgRules({
|
|
221
|
-
ifNode: 'if_statement',
|
|
222
|
-
elifNode: 'else_if_clause',
|
|
223
|
-
elseClause: 'else_clause',
|
|
224
|
-
ifConsequentField: 'body',
|
|
225
|
-
forNodes: new Set(['for_statement', 'foreach_statement']),
|
|
226
|
-
whileNode: 'while_statement',
|
|
227
|
-
doNode: 'do_statement',
|
|
228
|
-
switchNode: 'switch_statement',
|
|
229
|
-
caseNode: 'case_statement',
|
|
230
|
-
defaultNode: 'default_statement',
|
|
231
|
-
tryNode: 'try_statement',
|
|
232
|
-
catchNode: 'catch_clause',
|
|
233
|
-
finallyNode: 'finally_clause',
|
|
234
|
-
returnNode: 'return_statement',
|
|
235
|
-
throwNode: 'throw_expression',
|
|
236
|
-
breakNode: 'break_statement',
|
|
237
|
-
continueNode: 'continue_statement',
|
|
238
|
-
blockNode: 'compound_statement',
|
|
239
|
-
functionNodes: new Set([
|
|
240
|
-
'function_definition',
|
|
241
|
-
'method_declaration',
|
|
242
|
-
'anonymous_function_creation_expression',
|
|
243
|
-
'arrow_function',
|
|
244
|
-
]),
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
export const CFG_RULES = new Map([
|
|
248
|
-
['javascript', JS_TS_CFG],
|
|
249
|
-
['typescript', JS_TS_CFG],
|
|
250
|
-
['tsx', JS_TS_CFG],
|
|
251
|
-
['python', PYTHON_CFG],
|
|
252
|
-
['go', GO_CFG],
|
|
253
|
-
['rust', RUST_CFG],
|
|
254
|
-
['java', JAVA_CFG],
|
|
255
|
-
['csharp', CSHARP_CFG],
|
|
256
|
-
['ruby', RUBY_CFG],
|
|
257
|
-
['php', PHP_CFG],
|
|
258
|
-
]);
|
|
259
|
-
|
|
260
|
-
const CFG_LANG_IDS = new Set(CFG_RULES.keys());
|
|
261
|
-
|
|
262
|
-
// JS/TS extensions
|
|
263
|
-
const CFG_EXTENSIONS = new Set();
|
|
264
|
-
for (const entry of LANGUAGE_REGISTRY) {
|
|
265
|
-
if (CFG_LANG_IDS.has(entry.id)) {
|
|
266
|
-
for (const ext of entry.extensions) CFG_EXTENSIONS.add(ext);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
21
|
+
import { outputResult } from './result-formatter.js';
|
|
22
|
+
import { isTestFile } from './test-filter.js';
|
|
23
|
+
|
|
24
|
+
// Re-export for backward compatibility
|
|
25
|
+
export { CFG_RULES };
|
|
26
|
+
export { _makeCfgRules as makeCfgRules };
|
|
27
|
+
|
|
28
|
+
const CFG_EXTENSIONS = buildExtensionSet(CFG_RULES);
|
|
269
29
|
|
|
270
30
|
// ─── Core Algorithm: AST → CFG ──────────────────────────────────────────
|
|
271
31
|
|
|
@@ -327,11 +87,23 @@ export function buildFunctionCFG(functionNode, langId) {
|
|
|
327
87
|
*/
|
|
328
88
|
function getStatements(node) {
|
|
329
89
|
if (!node) return [];
|
|
330
|
-
// Block-like nodes
|
|
331
|
-
if (
|
|
90
|
+
// Block-like nodes (including statement_list wrappers from tree-sitter-go 0.25+)
|
|
91
|
+
if (
|
|
92
|
+
node.type === 'statement_list' ||
|
|
93
|
+
node.type === rules.blockNode ||
|
|
94
|
+
rules.blockNodes?.has(node.type)
|
|
95
|
+
) {
|
|
332
96
|
const stmts = [];
|
|
333
97
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
334
|
-
|
|
98
|
+
const child = node.namedChild(i);
|
|
99
|
+
if (child.type === 'statement_list') {
|
|
100
|
+
// Unwrap nested statement_list (block → statement_list → stmts)
|
|
101
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
102
|
+
stmts.push(child.namedChild(j));
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
stmts.push(child);
|
|
106
|
+
}
|
|
335
107
|
}
|
|
336
108
|
return stmts;
|
|
337
109
|
}
|
|
@@ -888,7 +660,14 @@ export function buildFunctionCFG(functionNode, langId) {
|
|
|
888
660
|
for (let j = 0; j < caseClause.namedChildCount; j++) {
|
|
889
661
|
const child = caseClause.namedChild(j);
|
|
890
662
|
if (child !== valueNode && child !== patternNode && child.type !== 'switch_label') {
|
|
891
|
-
|
|
663
|
+
if (child.type === 'statement_list') {
|
|
664
|
+
// Unwrap statement_list (tree-sitter-go 0.25+)
|
|
665
|
+
for (let k = 0; k < child.namedChildCount; k++) {
|
|
666
|
+
caseStmts.push(child.namedChild(k));
|
|
667
|
+
}
|
|
668
|
+
} else {
|
|
669
|
+
caseStmts.push(child);
|
|
670
|
+
}
|
|
892
671
|
}
|
|
893
672
|
}
|
|
894
673
|
}
|
|
@@ -1050,12 +829,7 @@ export async function buildCFGData(db, fileSymbols, rootDir, _engineOpts) {
|
|
|
1050
829
|
|
|
1051
830
|
// Always build ext→langId map so native-only builds (where _langId is unset)
|
|
1052
831
|
// can still derive the language from the file extension.
|
|
1053
|
-
const extToLang =
|
|
1054
|
-
for (const entry of LANGUAGE_REGISTRY) {
|
|
1055
|
-
for (const ext of entry.extensions) {
|
|
1056
|
-
extToLang.set(ext, entry.id);
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
832
|
+
const extToLang = buildExtToLangMap();
|
|
1059
833
|
|
|
1060
834
|
for (const [relPath, symbols] of fileSymbols) {
|
|
1061
835
|
if (!symbols._tree) {
|
|
@@ -1084,7 +858,7 @@ export async function buildCFGData(db, fileSymbols, rootDir, _engineOpts) {
|
|
|
1084
858
|
getParserFn = mod.getParser;
|
|
1085
859
|
}
|
|
1086
860
|
|
|
1087
|
-
|
|
861
|
+
// findFunctionNode imported from ./ast-analysis/shared.js at module level
|
|
1088
862
|
|
|
1089
863
|
const insertBlock = db.prepare(
|
|
1090
864
|
`INSERT INTO cfg_blocks (function_node_id, block_index, block_type, start_line, end_line, label)
|
|
@@ -1119,7 +893,7 @@ export async function buildCFGData(db, fileSymbols, rootDir, _engineOpts) {
|
|
|
1119
893
|
if (!tree && !allNative) {
|
|
1120
894
|
if (!getParserFn) continue;
|
|
1121
895
|
langId = extToLang.get(ext);
|
|
1122
|
-
if (!langId || !
|
|
896
|
+
if (!langId || !CFG_RULES.has(langId)) continue;
|
|
1123
897
|
|
|
1124
898
|
const absPath = path.join(rootDir, relPath);
|
|
1125
899
|
let code;
|
|
@@ -1255,72 +1029,73 @@ function findNodes(db, name, opts = {}) {
|
|
|
1255
1029
|
*/
|
|
1256
1030
|
export function cfgData(name, customDbPath, opts = {}) {
|
|
1257
1031
|
const db = openReadonlyOrFail(customDbPath);
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
db
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1032
|
+
try {
|
|
1033
|
+
const noTests = opts.noTests || false;
|
|
1034
|
+
|
|
1035
|
+
if (!hasCfgTables(db)) {
|
|
1036
|
+
return {
|
|
1037
|
+
name,
|
|
1038
|
+
results: [],
|
|
1039
|
+
warning:
|
|
1040
|
+
'No CFG data found. Rebuild with `codegraph build` (CFG is now included by default).',
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1269
1043
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
}
|
|
1044
|
+
const nodes = findNodes(db, name, { noTests, file: opts.file, kind: opts.kind });
|
|
1045
|
+
if (nodes.length === 0) {
|
|
1046
|
+
return { name, results: [] };
|
|
1047
|
+
}
|
|
1275
1048
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1049
|
+
const blockStmt = db.prepare(
|
|
1050
|
+
`SELECT id, block_index, block_type, start_line, end_line, label
|
|
1051
|
+
FROM cfg_blocks WHERE function_node_id = ?
|
|
1052
|
+
ORDER BY block_index`,
|
|
1053
|
+
);
|
|
1054
|
+
const edgeStmt = db.prepare(
|
|
1055
|
+
`SELECT e.kind,
|
|
1056
|
+
sb.block_index AS source_index, sb.block_type AS source_type,
|
|
1057
|
+
tb.block_index AS target_index, tb.block_type AS target_type
|
|
1058
|
+
FROM cfg_edges e
|
|
1059
|
+
JOIN cfg_blocks sb ON e.source_block_id = sb.id
|
|
1060
|
+
JOIN cfg_blocks tb ON e.target_block_id = tb.id
|
|
1061
|
+
WHERE e.function_node_id = ?
|
|
1062
|
+
ORDER BY sb.block_index, tb.block_index`,
|
|
1063
|
+
);
|
|
1291
1064
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1065
|
+
const results = nodes.map((node) => {
|
|
1066
|
+
const cfgBlocks = blockStmt.all(node.id);
|
|
1067
|
+
const cfgEdges = edgeStmt.all(node.id);
|
|
1068
|
+
|
|
1069
|
+
return {
|
|
1070
|
+
name: node.name,
|
|
1071
|
+
kind: node.kind,
|
|
1072
|
+
file: node.file,
|
|
1073
|
+
line: node.line,
|
|
1074
|
+
blocks: cfgBlocks.map((b) => ({
|
|
1075
|
+
index: b.block_index,
|
|
1076
|
+
type: b.block_type,
|
|
1077
|
+
startLine: b.start_line,
|
|
1078
|
+
endLine: b.end_line,
|
|
1079
|
+
label: b.label,
|
|
1080
|
+
})),
|
|
1081
|
+
edges: cfgEdges.map((e) => ({
|
|
1082
|
+
source: e.source_index,
|
|
1083
|
+
sourceType: e.source_type,
|
|
1084
|
+
target: e.target_index,
|
|
1085
|
+
targetType: e.target_type,
|
|
1086
|
+
kind: e.kind,
|
|
1087
|
+
})),
|
|
1088
|
+
summary: {
|
|
1089
|
+
blockCount: cfgBlocks.length,
|
|
1090
|
+
edgeCount: cfgEdges.length,
|
|
1091
|
+
},
|
|
1092
|
+
};
|
|
1093
|
+
});
|
|
1321
1094
|
|
|
1322
|
-
|
|
1323
|
-
|
|
1095
|
+
return paginateResult({ name, results }, 'results', opts);
|
|
1096
|
+
} finally {
|
|
1097
|
+
db.close();
|
|
1098
|
+
}
|
|
1324
1099
|
}
|
|
1325
1100
|
|
|
1326
1101
|
// ─── Export Formats ─────────────────────────────────────────────────────
|
|
@@ -1418,14 +1193,7 @@ function edgeStyle(kind) {
|
|
|
1418
1193
|
export function cfg(name, customDbPath, opts = {}) {
|
|
1419
1194
|
const data = cfgData(name, customDbPath, opts);
|
|
1420
1195
|
|
|
1421
|
-
if (opts
|
|
1422
|
-
console.log(JSON.stringify(data, null, 2));
|
|
1423
|
-
return;
|
|
1424
|
-
}
|
|
1425
|
-
if (opts.ndjson) {
|
|
1426
|
-
printNdjson(data.results);
|
|
1427
|
-
return;
|
|
1428
|
-
}
|
|
1196
|
+
if (outputResult(data, 'results', opts)) return;
|
|
1429
1197
|
|
|
1430
1198
|
if (data.warning) {
|
|
1431
1199
|
console.log(`\u26A0 ${data.warning}`);
|
package/src/check.js
CHANGED
|
@@ -5,7 +5,8 @@ import { loadConfig } from './config.js';
|
|
|
5
5
|
import { findCycles } from './cycles.js';
|
|
6
6
|
import { findDbPath, openReadonlyOrFail } from './db.js';
|
|
7
7
|
import { matchOwners, parseCodeowners } from './owners.js';
|
|
8
|
-
import {
|
|
8
|
+
import { outputResult } from './result-formatter.js';
|
|
9
|
+
import { isTestFile } from './test-filter.js';
|
|
9
10
|
|
|
10
11
|
// ─── Diff Parser ──────────────────────────────────────────────────────
|
|
11
12
|
|
|
@@ -361,8 +362,7 @@ export function check(customDbPath, opts = {}) {
|
|
|
361
362
|
process.exit(1);
|
|
362
363
|
}
|
|
363
364
|
|
|
364
|
-
if (opts
|
|
365
|
-
console.log(JSON.stringify(data, null, 2));
|
|
365
|
+
if (outputResult(data, null, opts)) {
|
|
366
366
|
if (!data.passed) process.exit(1);
|
|
367
367
|
return;
|
|
368
368
|
}
|