@optave/codegraph 3.1.4 → 3.2.0
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 +29 -72
- package/package.json +10 -8
- package/src/ast-analysis/engine.js +260 -246
- package/src/ast-analysis/shared.js +2 -14
- package/src/ast-analysis/visitors/cfg-visitor.js +635 -649
- package/src/ast-analysis/visitors/complexity-visitor.js +135 -139
- package/src/ast-analysis/visitors/dataflow-visitor.js +230 -224
- package/src/cli/commands/ast.js +4 -7
- package/src/cli/commands/audit.js +11 -11
- package/src/cli/commands/batch.js +6 -5
- package/src/cli/commands/branch-compare.js +1 -1
- package/src/cli/commands/brief.js +12 -0
- package/src/cli/commands/build.js +1 -1
- package/src/cli/commands/cfg.js +5 -8
- package/src/cli/commands/check.js +28 -36
- package/src/cli/commands/children.js +9 -7
- package/src/cli/commands/co-change.js +5 -3
- package/src/cli/commands/communities.js +2 -6
- package/src/cli/commands/complexity.js +5 -3
- package/src/cli/commands/context.js +9 -8
- package/src/cli/commands/cycles.js +12 -8
- package/src/cli/commands/dataflow.js +5 -8
- package/src/cli/commands/deps.js +9 -8
- package/src/cli/commands/diff-impact.js +2 -6
- package/src/cli/commands/embed.js +1 -1
- package/src/cli/commands/export.js +34 -31
- package/src/cli/commands/exports.js +2 -6
- package/src/cli/commands/flow.js +5 -8
- package/src/cli/commands/fn-impact.js +9 -8
- package/src/cli/commands/impact.js +2 -6
- package/src/cli/commands/info.js +2 -2
- package/src/cli/commands/map.js +1 -1
- package/src/cli/commands/mcp.js +1 -1
- package/src/cli/commands/models.js +1 -1
- package/src/cli/commands/owners.js +5 -3
- package/src/cli/commands/path.js +2 -2
- package/src/cli/commands/plot.js +40 -31
- package/src/cli/commands/query.js +9 -8
- package/src/cli/commands/registry.js +2 -2
- package/src/cli/commands/roles.js +5 -8
- package/src/cli/commands/search.js +9 -3
- package/src/cli/commands/sequence.js +5 -8
- package/src/cli/commands/snapshot.js +6 -1
- package/src/cli/commands/stats.js +1 -1
- package/src/cli/commands/structure.js +5 -4
- package/src/cli/commands/triage.js +41 -30
- package/src/cli/commands/watch.js +1 -1
- package/src/cli/commands/where.js +2 -6
- package/src/cli/index.js +11 -5
- package/src/cli/shared/open-graph.js +13 -0
- package/src/cli/shared/options.js +22 -2
- package/src/cli.js +1 -1
- package/src/db/connection.js +140 -11
- package/src/{db.js → db/index.js} +12 -5
- package/src/db/migrations.js +42 -65
- package/src/db/query-builder.js +72 -9
- package/src/db/repository/base.js +1 -1
- package/src/db/repository/graph-read.js +3 -3
- package/src/db/repository/in-memory-repository.js +30 -28
- package/src/db/repository/nodes.js +10 -17
- package/src/domain/analysis/brief.js +155 -0
- package/src/domain/analysis/context.js +392 -0
- package/src/domain/analysis/dependencies.js +395 -0
- package/src/{analysis → domain/analysis}/exports.js +11 -6
- package/src/domain/analysis/impact.js +581 -0
- package/src/domain/analysis/module-map.js +348 -0
- package/src/{analysis → domain/analysis}/roles.js +12 -9
- package/src/{analysis → domain/analysis}/symbol-lookup.js +19 -11
- package/src/{builder → domain/graph/builder}/helpers.js +4 -4
- package/src/{builder → domain/graph/builder}/incremental.js +119 -93
- package/src/domain/graph/builder/pipeline.js +156 -0
- package/src/domain/graph/builder/stages/build-edges.js +376 -0
- package/src/{builder → domain/graph/builder}/stages/build-structure.js +4 -4
- package/src/{builder → domain/graph/builder}/stages/collect-files.js +2 -2
- package/src/{builder → domain/graph/builder}/stages/detect-changes.js +204 -183
- package/src/{builder → domain/graph/builder}/stages/finalize.js +4 -4
- package/src/domain/graph/builder/stages/insert-nodes.js +203 -0
- package/src/{builder → domain/graph/builder}/stages/parse-files.js +2 -2
- package/src/{builder → domain/graph/builder}/stages/resolve-imports.js +1 -1
- package/src/{builder → domain/graph/builder}/stages/run-analyses.js +2 -2
- package/src/{change-journal.js → domain/graph/change-journal.js} +1 -1
- package/src/{cycles.js → domain/graph/cycles.js} +4 -4
- package/src/{journal.js → domain/graph/journal.js} +1 -1
- package/src/{resolve.js → domain/graph/resolve.js} +2 -2
- package/src/{watcher.js → domain/graph/watcher.js} +7 -7
- package/src/{parser.js → domain/parser.js} +24 -15
- package/src/{queries.js → domain/queries.js} +17 -16
- package/src/{embeddings → domain/search}/generator.js +3 -3
- package/src/{embeddings → domain/search}/models.js +2 -2
- package/src/{embeddings → domain/search}/search/cli-formatter.js +1 -1
- package/src/{embeddings → domain/search}/search/filters.js +9 -5
- package/src/{embeddings → domain/search}/search/hybrid.js +1 -1
- package/src/{embeddings → domain/search}/search/keyword.js +13 -6
- package/src/{embeddings → domain/search}/search/prepare.js +15 -7
- package/src/{embeddings → domain/search}/search/semantic.js +1 -1
- package/src/{embeddings → domain/search}/strategies/structured.js +1 -1
- package/src/extractors/csharp.js +224 -207
- package/src/extractors/go.js +176 -172
- package/src/extractors/hcl.js +94 -78
- package/src/extractors/java.js +213 -207
- package/src/extractors/javascript.js +275 -305
- package/src/extractors/php.js +234 -221
- package/src/extractors/python.js +252 -250
- package/src/extractors/ruby.js +192 -185
- package/src/extractors/rust.js +182 -167
- package/src/{ast.js → features/ast.js} +13 -11
- package/src/{audit.js → features/audit.js} +20 -46
- package/src/{batch.js → features/batch.js} +5 -5
- package/src/{boundaries.js → features/boundaries.js} +100 -85
- package/src/{branch-compare.js → features/branch-compare.js} +3 -3
- package/src/{cfg.js → features/cfg.js} +141 -150
- package/src/{check.js → features/check.js} +13 -30
- package/src/{cochange.js → features/cochange.js} +5 -5
- package/src/{communities.js → features/communities.js} +72 -57
- package/src/{complexity.js → features/complexity.js} +154 -143
- package/src/{dataflow.js → features/dataflow.js} +155 -158
- package/src/{export.js → features/export.js} +6 -6
- package/src/{flow.js → features/flow.js} +4 -4
- package/src/{viewer.js → features/graph-enrichment.js} +8 -8
- package/src/{manifesto.js → features/manifesto.js} +15 -12
- package/src/{owners.js → features/owners.js} +6 -5
- package/src/features/sequence.js +300 -0
- package/src/features/shared/find-nodes.js +31 -0
- package/src/{snapshot.js → features/snapshot.js} +3 -3
- package/src/{structure.js → features/structure.js} +139 -108
- package/src/features/triage.js +141 -0
- package/src/graph/builders/dependency.js +33 -14
- package/src/graph/classifiers/risk.js +3 -2
- package/src/graph/classifiers/roles.js +6 -3
- package/src/index.cjs +16 -0
- package/src/index.js +40 -39
- package/src/{native.js → infrastructure/native.js} +1 -1
- package/src/mcp/middleware.js +1 -1
- package/src/mcp/server.js +68 -59
- package/src/mcp/tool-registry.js +15 -2
- package/src/mcp/tools/ast-query.js +1 -1
- package/src/mcp/tools/audit.js +1 -1
- package/src/mcp/tools/batch-query.js +1 -1
- package/src/mcp/tools/branch-compare.js +3 -1
- package/src/mcp/tools/brief.js +8 -0
- package/src/mcp/tools/cfg.js +1 -1
- package/src/mcp/tools/check.js +3 -3
- package/src/mcp/tools/co-changes.js +1 -1
- package/src/mcp/tools/code-owners.js +1 -1
- package/src/mcp/tools/communities.js +1 -1
- package/src/mcp/tools/complexity.js +1 -1
- package/src/mcp/tools/dataflow.js +2 -2
- package/src/mcp/tools/execution-flow.js +2 -2
- package/src/mcp/tools/export-graph.js +2 -2
- package/src/mcp/tools/find-cycles.js +2 -2
- package/src/mcp/tools/index.js +2 -0
- package/src/mcp/tools/list-repos.js +1 -1
- package/src/mcp/tools/sequence.js +1 -1
- package/src/mcp/tools/structure.js +1 -1
- package/src/mcp/tools/triage.js +2 -2
- package/src/{commands → presentation}/audit.js +2 -2
- package/src/{commands → presentation}/batch.js +1 -1
- package/src/{commands → presentation}/branch-compare.js +2 -2
- package/src/presentation/brief.js +51 -0
- package/src/{commands → presentation}/cfg.js +1 -1
- package/src/{commands → presentation}/check.js +2 -2
- package/src/{commands → presentation}/communities.js +1 -1
- package/src/{commands → presentation}/complexity.js +1 -1
- package/src/{commands → presentation}/dataflow.js +1 -1
- package/src/{commands → presentation}/flow.js +2 -2
- package/src/{commands → presentation}/manifesto.js +1 -1
- package/src/{commands → presentation}/owners.js +1 -1
- package/src/presentation/queries-cli/exports.js +53 -0
- package/src/presentation/queries-cli/impact.js +214 -0
- package/src/presentation/queries-cli/index.js +5 -0
- package/src/presentation/queries-cli/inspect.js +329 -0
- package/src/presentation/queries-cli/overview.js +196 -0
- package/src/presentation/queries-cli/path.js +65 -0
- package/src/presentation/queries-cli.js +27 -0
- package/src/{commands → presentation}/query.js +1 -1
- package/src/presentation/result-formatter.js +126 -3
- package/src/{commands → presentation}/sequence.js +2 -2
- package/src/{commands → presentation}/structure.js +1 -1
- package/src/presentation/table.js +0 -8
- package/src/{commands → presentation}/triage.js +1 -1
- package/src/{constants.js → shared/constants.js} +1 -1
- package/src/shared/file-utils.js +2 -2
- package/src/shared/generators.js +9 -5
- package/src/shared/hierarchy.js +1 -1
- package/src/{kinds.js → shared/kinds.js} +1 -1
- package/src/analysis/context.js +0 -408
- package/src/analysis/dependencies.js +0 -341
- package/src/analysis/impact.js +0 -463
- package/src/analysis/module-map.js +0 -322
- package/src/builder/pipeline.js +0 -130
- package/src/builder/stages/build-edges.js +0 -297
- package/src/builder/stages/insert-nodes.js +0 -195
- package/src/mcp.js +0 -2
- package/src/queries-cli.js +0 -866
- package/src/sequence.js +0 -289
- package/src/triage.js +0 -126
- /package/src/{builder → domain/graph/builder}/context.js +0 -0
- /package/src/{builder.js → domain/graph/builder.js} +0 -0
- /package/src/{embeddings → domain/search}/index.js +0 -0
- /package/src/{embeddings → domain/search}/stores/fts5.js +0 -0
- /package/src/{embeddings → domain/search}/stores/sqlite-blob.js +0 -0
- /package/src/{embeddings → domain/search}/strategies/source.js +0 -0
- /package/src/{embeddings → domain/search}/strategies/text-utils.js +0 -0
- /package/src/{config.js → infrastructure/config.js} +0 -0
- /package/src/{logger.js → infrastructure/logger.js} +0 -0
- /package/src/{registry.js → infrastructure/registry.js} +0 -0
- /package/src/{update-check.js → infrastructure/update-check.js} +0 -0
- /package/src/{commands → presentation}/cochange.js +0 -0
- /package/src/{errors.js → shared/errors.js} +0 -0
- /package/src/{paginate.js → shared/paginate.js} +0 -0
package/src/extractors/rust.js
CHANGED
|
@@ -4,191 +4,206 @@ import { findChild, nodeEndLine, rustVisibility } from './helpers.js';
|
|
|
4
4
|
* Extract symbols from Rust files.
|
|
5
5
|
*/
|
|
6
6
|
export function extractRustSymbols(tree, _filePath) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const ctx = {
|
|
8
|
+
definitions: [],
|
|
9
|
+
calls: [],
|
|
10
|
+
imports: [],
|
|
11
|
+
classes: [],
|
|
12
|
+
exports: [],
|
|
13
|
+
};
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
walkRustNode(tree.rootNode, ctx);
|
|
16
|
+
return ctx;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function walkRustNode(node, ctx) {
|
|
20
|
+
switch (node.type) {
|
|
21
|
+
case 'function_item':
|
|
22
|
+
handleRustFuncItem(node, ctx);
|
|
23
|
+
break;
|
|
24
|
+
case 'struct_item':
|
|
25
|
+
handleRustStructItem(node, ctx);
|
|
26
|
+
break;
|
|
27
|
+
case 'enum_item':
|
|
28
|
+
handleRustEnumItem(node, ctx);
|
|
29
|
+
break;
|
|
30
|
+
case 'const_item':
|
|
31
|
+
handleRustConstItem(node, ctx);
|
|
32
|
+
break;
|
|
33
|
+
case 'trait_item':
|
|
34
|
+
handleRustTraitItem(node, ctx);
|
|
35
|
+
break;
|
|
36
|
+
case 'impl_item':
|
|
37
|
+
handleRustImplItem(node, ctx);
|
|
38
|
+
break;
|
|
39
|
+
case 'use_declaration':
|
|
40
|
+
handleRustUseDecl(node, ctx);
|
|
41
|
+
break;
|
|
42
|
+
case 'call_expression':
|
|
43
|
+
handleRustCallExpr(node, ctx);
|
|
44
|
+
break;
|
|
45
|
+
case 'macro_invocation':
|
|
46
|
+
handleRustMacroInvocation(node, ctx);
|
|
47
|
+
break;
|
|
23
48
|
}
|
|
24
49
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
case 'function_item': {
|
|
28
|
-
const nameNode = node.childForFieldName('name');
|
|
29
|
-
if (nameNode) {
|
|
30
|
-
const implType = findCurrentImpl(node);
|
|
31
|
-
const fullName = implType ? `${implType}.${nameNode.text}` : nameNode.text;
|
|
32
|
-
const kind = implType ? 'method' : 'function';
|
|
33
|
-
const params = extractRustParameters(node.childForFieldName('parameters'));
|
|
34
|
-
definitions.push({
|
|
35
|
-
name: fullName,
|
|
36
|
-
kind,
|
|
37
|
-
line: node.startPosition.row + 1,
|
|
38
|
-
endLine: nodeEndLine(node),
|
|
39
|
-
children: params.length > 0 ? params : undefined,
|
|
40
|
-
visibility: rustVisibility(node),
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
50
|
+
for (let i = 0; i < node.childCount; i++) walkRustNode(node.child(i), ctx);
|
|
51
|
+
}
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
const nameNode = node.childForFieldName('name');
|
|
48
|
-
if (nameNode) {
|
|
49
|
-
const fields = extractStructFields(node);
|
|
50
|
-
definitions.push({
|
|
51
|
-
name: nameNode.text,
|
|
52
|
-
kind: 'struct',
|
|
53
|
-
line: node.startPosition.row + 1,
|
|
54
|
-
endLine: nodeEndLine(node),
|
|
55
|
-
children: fields.length > 0 ? fields : undefined,
|
|
56
|
-
visibility: rustVisibility(node),
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
53
|
+
// ── Walk-path per-node-type handlers ────────────────────────────────────────
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
function handleRustFuncItem(node, ctx) {
|
|
56
|
+
// Skip default-impl functions already emitted by handleRustTraitItem
|
|
57
|
+
if (node.parent?.parent?.type === 'trait_item') return;
|
|
58
|
+
const nameNode = node.childForFieldName('name');
|
|
59
|
+
if (!nameNode) return;
|
|
60
|
+
const implType = findCurrentImpl(node);
|
|
61
|
+
const fullName = implType ? `${implType}.${nameNode.text}` : nameNode.text;
|
|
62
|
+
const kind = implType ? 'method' : 'function';
|
|
63
|
+
const params = extractRustParameters(node.childForFieldName('parameters'));
|
|
64
|
+
ctx.definitions.push({
|
|
65
|
+
name: fullName,
|
|
66
|
+
kind,
|
|
67
|
+
line: node.startPosition.row + 1,
|
|
68
|
+
endLine: nodeEndLine(node),
|
|
69
|
+
children: params.length > 0 ? params : undefined,
|
|
70
|
+
visibility: rustVisibility(node),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
74
|
+
function handleRustStructItem(node, ctx) {
|
|
75
|
+
const nameNode = node.childForFieldName('name');
|
|
76
|
+
if (!nameNode) return;
|
|
77
|
+
const fields = extractStructFields(node);
|
|
78
|
+
ctx.definitions.push({
|
|
79
|
+
name: nameNode.text,
|
|
80
|
+
kind: 'struct',
|
|
81
|
+
line: node.startPosition.row + 1,
|
|
82
|
+
endLine: nodeEndLine(node),
|
|
83
|
+
children: fields.length > 0 ? fields : undefined,
|
|
84
|
+
visibility: rustVisibility(node),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
endLine: child.endPosition.row + 1,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
88
|
+
function handleRustEnumItem(node, ctx) {
|
|
89
|
+
const nameNode = node.childForFieldName('name');
|
|
90
|
+
if (!nameNode) return;
|
|
91
|
+
const variants = extractEnumVariants(node);
|
|
92
|
+
ctx.definitions.push({
|
|
93
|
+
name: nameNode.text,
|
|
94
|
+
kind: 'enum',
|
|
95
|
+
line: node.startPosition.row + 1,
|
|
96
|
+
endLine: nodeEndLine(node),
|
|
97
|
+
children: variants.length > 0 ? variants : undefined,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function handleRustConstItem(node, ctx) {
|
|
102
|
+
const nameNode = node.childForFieldName('name');
|
|
103
|
+
if (!nameNode) return;
|
|
104
|
+
ctx.definitions.push({
|
|
105
|
+
name: nameNode.text,
|
|
106
|
+
kind: 'constant',
|
|
107
|
+
line: node.startPosition.row + 1,
|
|
108
|
+
endLine: nodeEndLine(node),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
122
111
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
112
|
+
function handleRustTraitItem(node, ctx) {
|
|
113
|
+
const nameNode = node.childForFieldName('name');
|
|
114
|
+
if (!nameNode) return;
|
|
115
|
+
ctx.definitions.push({
|
|
116
|
+
name: nameNode.text,
|
|
117
|
+
kind: 'trait',
|
|
118
|
+
line: node.startPosition.row + 1,
|
|
119
|
+
endLine: nodeEndLine(node),
|
|
120
|
+
});
|
|
121
|
+
const body = node.childForFieldName('body');
|
|
122
|
+
if (body) {
|
|
123
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
124
|
+
const child = body.child(i);
|
|
125
|
+
if (child && (child.type === 'function_signature_item' || child.type === 'function_item')) {
|
|
126
|
+
const methName = child.childForFieldName('name');
|
|
127
|
+
if (methName) {
|
|
128
|
+
ctx.definitions.push({
|
|
129
|
+
name: `${nameNode.text}.${methName.text}`,
|
|
130
|
+
kind: 'method',
|
|
131
|
+
line: child.startPosition.row + 1,
|
|
132
|
+
endLine: child.endPosition.row + 1,
|
|
131
133
|
});
|
|
132
134
|
}
|
|
133
|
-
break;
|
|
134
135
|
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
140
|
+
function handleRustImplItem(node, ctx) {
|
|
141
|
+
const typeNode = node.childForFieldName('type');
|
|
142
|
+
const traitNode = node.childForFieldName('trait');
|
|
143
|
+
if (typeNode && traitNode) {
|
|
144
|
+
ctx.classes.push({
|
|
145
|
+
name: typeNode.text,
|
|
146
|
+
implements: traitNode.text,
|
|
147
|
+
line: node.startPosition.row + 1,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
} else if (fn.type === 'scoped_identifier') {
|
|
166
|
-
const name = fn.childForFieldName('name');
|
|
167
|
-
if (name) {
|
|
168
|
-
const path = fn.childForFieldName('path');
|
|
169
|
-
const call = { name: name.text, line: node.startPosition.row + 1 };
|
|
170
|
-
if (path) call.receiver = path.text;
|
|
171
|
-
calls.push(call);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
152
|
+
function handleRustUseDecl(node, ctx) {
|
|
153
|
+
const argNode = node.child(1);
|
|
154
|
+
if (!argNode) return;
|
|
155
|
+
const usePaths = extractRustUsePath(argNode);
|
|
156
|
+
for (const imp of usePaths) {
|
|
157
|
+
ctx.imports.push({
|
|
158
|
+
source: imp.source,
|
|
159
|
+
names: imp.names,
|
|
160
|
+
line: node.startPosition.row + 1,
|
|
161
|
+
rustUse: true,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
177
165
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
166
|
+
function handleRustCallExpr(node, ctx) {
|
|
167
|
+
const fn = node.childForFieldName('function');
|
|
168
|
+
if (!fn) return;
|
|
169
|
+
if (fn.type === 'identifier') {
|
|
170
|
+
ctx.calls.push({ name: fn.text, line: node.startPosition.row + 1 });
|
|
171
|
+
} else if (fn.type === 'field_expression') {
|
|
172
|
+
const field = fn.childForFieldName('field');
|
|
173
|
+
if (field) {
|
|
174
|
+
const value = fn.childForFieldName('value');
|
|
175
|
+
const call = { name: field.text, line: node.startPosition.row + 1 };
|
|
176
|
+
if (value) call.receiver = value.text;
|
|
177
|
+
ctx.calls.push(call);
|
|
178
|
+
}
|
|
179
|
+
} else if (fn.type === 'scoped_identifier') {
|
|
180
|
+
const name = fn.childForFieldName('name');
|
|
181
|
+
if (name) {
|
|
182
|
+
const path = fn.childForFieldName('path');
|
|
183
|
+
const call = { name: name.text, line: node.startPosition.row + 1 };
|
|
184
|
+
if (path) call.receiver = path.text;
|
|
185
|
+
ctx.calls.push(call);
|
|
185
186
|
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
186
189
|
|
|
187
|
-
|
|
190
|
+
function handleRustMacroInvocation(node, ctx) {
|
|
191
|
+
const macroNode = node.child(0);
|
|
192
|
+
if (macroNode) {
|
|
193
|
+
ctx.calls.push({ name: `${macroNode.text}!`, line: node.startPosition.row + 1 });
|
|
188
194
|
}
|
|
195
|
+
}
|
|
189
196
|
|
|
190
|
-
|
|
191
|
-
|
|
197
|
+
function findCurrentImpl(node) {
|
|
198
|
+
let current = node.parent;
|
|
199
|
+
while (current) {
|
|
200
|
+
if (current.type === 'impl_item') {
|
|
201
|
+
const typeNode = current.childForFieldName('type');
|
|
202
|
+
return typeNode ? typeNode.text : null;
|
|
203
|
+
}
|
|
204
|
+
current = current.parent;
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import { AST_TYPE_MAPS } from '
|
|
11
|
-
import { buildExtensionSet } from '
|
|
12
|
-
import { walkWithVisitors } from '
|
|
13
|
-
import { createAstStoreVisitor } from '
|
|
14
|
-
import { bulkNodeIdsByFile, openReadonlyOrFail } from '
|
|
15
|
-
import {
|
|
16
|
-
import { debug } from '
|
|
17
|
-
import {
|
|
10
|
+
import { AST_TYPE_MAPS } from '../ast-analysis/rules/index.js';
|
|
11
|
+
import { buildExtensionSet } from '../ast-analysis/shared.js';
|
|
12
|
+
import { walkWithVisitors } from '../ast-analysis/visitor.js';
|
|
13
|
+
import { createAstStoreVisitor } from '../ast-analysis/visitors/ast-store-visitor.js';
|
|
14
|
+
import { bulkNodeIdsByFile, openReadonlyOrFail } from '../db/index.js';
|
|
15
|
+
import { buildFileConditionSQL } from '../db/query-builder.js';
|
|
16
|
+
import { debug } from '../infrastructure/logger.js';
|
|
17
|
+
import { outputResult } from '../infrastructure/result-formatter.js';
|
|
18
|
+
import { paginateResult } from '../shared/paginate.js';
|
|
18
19
|
|
|
19
20
|
// ─── Constants ────────────────────────────────────────────────────────
|
|
20
21
|
|
|
@@ -193,9 +194,10 @@ export function astQueryData(pattern, customDbPath, opts = {}) {
|
|
|
193
194
|
params.push(kind);
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
{
|
|
198
|
+
const fc = buildFileConditionSQL(file, 'a.file');
|
|
199
|
+
where += fc.sql;
|
|
200
|
+
params.push(...fc.params);
|
|
199
201
|
}
|
|
200
202
|
|
|
201
203
|
if (noTests) {
|
|
@@ -7,21 +7,27 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { openReadonlyOrFail } from '../db/index.js';
|
|
11
|
+
import { normalizeFileFilter } from '../db/query-builder.js';
|
|
12
|
+
import { bfsTransitiveCallers } from '../domain/analysis/impact.js';
|
|
13
|
+
import { explainData } from '../domain/queries.js';
|
|
14
|
+
import { loadConfig } from '../infrastructure/config.js';
|
|
15
|
+
import { isTestFile } from '../infrastructure/test-filter.js';
|
|
13
16
|
import { RULE_DEFS } from './manifesto.js';
|
|
14
|
-
import { explainData } from './queries.js';
|
|
15
17
|
|
|
16
18
|
// ─── Threshold resolution ───────────────────────────────────────────
|
|
17
19
|
|
|
18
20
|
const FUNCTION_RULES = RULE_DEFS.filter((d) => d.level === 'function');
|
|
19
21
|
|
|
20
|
-
function resolveThresholds(customDbPath) {
|
|
22
|
+
function resolveThresholds(customDbPath, config) {
|
|
21
23
|
try {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const cfg =
|
|
25
|
+
config ||
|
|
26
|
+
(() => {
|
|
27
|
+
const dbDir = path.dirname(customDbPath);
|
|
28
|
+
const repoRoot = path.resolve(dbDir, '..');
|
|
29
|
+
return loadConfig(repoRoot);
|
|
30
|
+
})();
|
|
25
31
|
const userRules = cfg.manifesto || {};
|
|
26
32
|
const resolved = {};
|
|
27
33
|
for (const def of FUNCTION_RULES) {
|
|
@@ -70,39 +76,6 @@ function checkBreaches(row, thresholds) {
|
|
|
70
76
|
return breaches;
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
// ─── BFS impact (inline, same algorithm as fnImpactData) ────────────
|
|
74
|
-
|
|
75
|
-
function computeImpact(db, nodeId, noTests, maxDepth) {
|
|
76
|
-
const visited = new Set([nodeId]);
|
|
77
|
-
const levels = {};
|
|
78
|
-
let frontier = [nodeId];
|
|
79
|
-
|
|
80
|
-
for (let d = 1; d <= maxDepth; d++) {
|
|
81
|
-
const nextFrontier = [];
|
|
82
|
-
for (const fid of frontier) {
|
|
83
|
-
const callers = db
|
|
84
|
-
.prepare(
|
|
85
|
-
`SELECT DISTINCT n.id, n.name, n.kind, n.file, n.line
|
|
86
|
-
FROM edges e JOIN nodes n ON e.source_id = n.id
|
|
87
|
-
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
88
|
-
)
|
|
89
|
-
.all(fid);
|
|
90
|
-
for (const c of callers) {
|
|
91
|
-
if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
|
|
92
|
-
visited.add(c.id);
|
|
93
|
-
nextFrontier.push(c.id);
|
|
94
|
-
if (!levels[d]) levels[d] = [];
|
|
95
|
-
levels[d].push({ name: c.name, kind: c.kind, file: c.file, line: c.line });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
frontier = nextFrontier;
|
|
100
|
-
if (frontier.length === 0) break;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return { totalDependents: visited.size - 1, levels };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
79
|
// ─── Phase 4.4 fields (graceful null fallback) ─────────────────────
|
|
107
80
|
|
|
108
81
|
function readPhase44(db, nodeId) {
|
|
@@ -128,7 +101,7 @@ function readPhase44(db, nodeId) {
|
|
|
128
101
|
export function auditData(target, customDbPath, opts = {}) {
|
|
129
102
|
const noTests = opts.noTests || false;
|
|
130
103
|
const maxDepth = opts.depth || 3;
|
|
131
|
-
const
|
|
104
|
+
const fileFilters = normalizeFileFilter(opts.file);
|
|
132
105
|
const kind = opts.kind;
|
|
133
106
|
|
|
134
107
|
// 1. Get structure via explainData
|
|
@@ -137,7 +110,8 @@ export function auditData(target, customDbPath, opts = {}) {
|
|
|
137
110
|
// Apply --file and --kind filters for function targets
|
|
138
111
|
let results = explained.results;
|
|
139
112
|
if (explained.kind === 'function') {
|
|
140
|
-
if (
|
|
113
|
+
if (fileFilters.length > 0)
|
|
114
|
+
results = results.filter((r) => fileFilters.some((f) => r.file.includes(f)));
|
|
141
115
|
if (kind) results = results.filter((r) => r.kind === kind);
|
|
142
116
|
}
|
|
143
117
|
|
|
@@ -147,7 +121,7 @@ export function auditData(target, customDbPath, opts = {}) {
|
|
|
147
121
|
|
|
148
122
|
// 2. Open DB for enrichment
|
|
149
123
|
const db = openReadonlyOrFail(customDbPath);
|
|
150
|
-
const thresholds = resolveThresholds(customDbPath);
|
|
124
|
+
const thresholds = resolveThresholds(customDbPath, opts.config);
|
|
151
125
|
|
|
152
126
|
let functions;
|
|
153
127
|
try {
|
|
@@ -189,7 +163,7 @@ function enrichFunction(db, r, noTests, maxDepth, thresholds) {
|
|
|
189
163
|
const nodeId = nodeRow?.id;
|
|
190
164
|
const health = nodeId ? buildHealth(db, nodeId, thresholds) : defaultHealth();
|
|
191
165
|
const impact = nodeId
|
|
192
|
-
?
|
|
166
|
+
? bfsTransitiveCallers(db, nodeId, { noTests, maxDepth })
|
|
193
167
|
: { totalDependents: 0, levels: {} };
|
|
194
168
|
const phase44 = nodeId
|
|
195
169
|
? readPhase44(db, nodeId)
|
|
@@ -260,7 +234,7 @@ function enrichSymbol(db, sym, file, noTests, maxDepth, thresholds) {
|
|
|
260
234
|
|
|
261
235
|
const health = nodeId ? buildHealth(db, nodeId, thresholds) : defaultHealth();
|
|
262
236
|
const impact = nodeId
|
|
263
|
-
?
|
|
237
|
+
? bfsTransitiveCallers(db, nodeId, { noTests, maxDepth })
|
|
264
238
|
: { totalDependents: 0, levels: {} };
|
|
265
239
|
const phase44 = nodeId
|
|
266
240
|
? readPhase44(db, nodeId)
|
|
@@ -5,10 +5,6 @@
|
|
|
5
5
|
* Designed for multi-agent swarms that need to dispatch 20+ queries in one call.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { complexityData } from './complexity.js';
|
|
9
|
-
import { dataflowData } from './dataflow.js';
|
|
10
|
-
import { ConfigError } from './errors.js';
|
|
11
|
-
import { flowData } from './flow.js';
|
|
12
8
|
import {
|
|
13
9
|
contextData,
|
|
14
10
|
explainData,
|
|
@@ -18,7 +14,11 @@ import {
|
|
|
18
14
|
fnImpactData,
|
|
19
15
|
impactAnalysisData,
|
|
20
16
|
whereData,
|
|
21
|
-
} from '
|
|
17
|
+
} from '../domain/queries.js';
|
|
18
|
+
import { ConfigError } from '../shared/errors.js';
|
|
19
|
+
import { complexityData } from './complexity.js';
|
|
20
|
+
import { dataflowData } from './dataflow.js';
|
|
21
|
+
import { flowData } from './flow.js';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Map of supported batch commands → their data function + first-arg semantics.
|