@optave/codegraph 3.5.0 → 3.6.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 +35 -14
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/connection.d.ts +12 -2
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +81 -53
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +38 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +3 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +69 -3
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +7 -51
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +7 -5
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +2 -2
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +124 -105
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +164 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +6 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +6 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +306 -292
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -83
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/features/ast.d.ts +2 -0
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +9 -24
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +47 -3
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +118 -62
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -36
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +182 -7
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/package.json +13 -7
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/connection.ts +90 -59
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +36 -32
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +71 -3
- package/src/domain/graph/builder/stages/build-edges.ts +10 -75
- package/src/domain/graph/builder/stages/build-structure.ts +9 -7
- package/src/domain/graph/builder/stages/collect-files.ts +2 -2
- package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
- package/src/domain/graph/builder/stages/finalize.ts +159 -125
- package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +168 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/go.ts +152 -134
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +6 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +328 -281
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -85
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/features/ast.ts +10 -25
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +51 -4
- package/src/features/cfg.ts +158 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +46 -37
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +189 -7
package/src/extractors/go.ts
CHANGED
|
@@ -4,9 +4,16 @@ import type {
|
|
|
4
4
|
SubDeclaration,
|
|
5
5
|
TreeSitterNode,
|
|
6
6
|
TreeSitterTree,
|
|
7
|
-
TypeMapEntry,
|
|
8
7
|
} from '../types.js';
|
|
9
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
findChild,
|
|
10
|
+
goVisibility,
|
|
11
|
+
lastPathSegment,
|
|
12
|
+
MAX_WALK_DEPTH,
|
|
13
|
+
nodeEndLine,
|
|
14
|
+
setTypeMapEntry,
|
|
15
|
+
stripQuotes,
|
|
16
|
+
} from './helpers.js';
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* Extract symbols from Go files.
|
|
@@ -106,43 +113,63 @@ function handleGoTypeDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
106
113
|
if (!spec || spec.type !== 'type_spec') continue;
|
|
107
114
|
const nameNode = spec.childForFieldName('name');
|
|
108
115
|
const typeNode = spec.childForFieldName('type');
|
|
109
|
-
if (nameNode
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
116
|
+
if (!nameNode || !typeNode) continue;
|
|
117
|
+
|
|
118
|
+
if (typeNode.type === 'struct_type') {
|
|
119
|
+
handleGoStructType(node, nameNode, typeNode, ctx);
|
|
120
|
+
} else if (typeNode.type === 'interface_type') {
|
|
121
|
+
handleGoInterfaceType(node, nameNode, typeNode, ctx);
|
|
122
|
+
} else {
|
|
123
|
+
ctx.definitions.push({
|
|
124
|
+
name: nameNode.text,
|
|
125
|
+
kind: 'type',
|
|
126
|
+
line: node.startPosition.row + 1,
|
|
127
|
+
endLine: nodeEndLine(node),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Handle a struct type_spec: emit struct definition with field children. */
|
|
134
|
+
function handleGoStructType(
|
|
135
|
+
declNode: TreeSitterNode,
|
|
136
|
+
nameNode: TreeSitterNode,
|
|
137
|
+
typeNode: TreeSitterNode,
|
|
138
|
+
ctx: ExtractorOutput,
|
|
139
|
+
): void {
|
|
140
|
+
const fields = extractStructFields(typeNode);
|
|
141
|
+
ctx.definitions.push({
|
|
142
|
+
name: nameNode.text,
|
|
143
|
+
kind: 'struct',
|
|
144
|
+
line: declNode.startPosition.row + 1,
|
|
145
|
+
endLine: nodeEndLine(declNode),
|
|
146
|
+
children: fields.length > 0 ? fields : undefined,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Handle an interface type_spec: emit interface definition + method definitions. */
|
|
151
|
+
function handleGoInterfaceType(
|
|
152
|
+
declNode: TreeSitterNode,
|
|
153
|
+
nameNode: TreeSitterNode,
|
|
154
|
+
typeNode: TreeSitterNode,
|
|
155
|
+
ctx: ExtractorOutput,
|
|
156
|
+
): void {
|
|
157
|
+
ctx.definitions.push({
|
|
158
|
+
name: nameNode.text,
|
|
159
|
+
kind: 'interface',
|
|
160
|
+
line: declNode.startPosition.row + 1,
|
|
161
|
+
endLine: nodeEndLine(declNode),
|
|
162
|
+
});
|
|
163
|
+
for (let j = 0; j < typeNode.childCount; j++) {
|
|
164
|
+
const member = typeNode.child(j);
|
|
165
|
+
if (member && member.type === 'method_elem') {
|
|
166
|
+
const methName = member.childForFieldName('name');
|
|
167
|
+
if (methName) {
|
|
141
168
|
ctx.definitions.push({
|
|
142
|
-
name: nameNode.text
|
|
143
|
-
kind: '
|
|
144
|
-
line:
|
|
145
|
-
endLine:
|
|
169
|
+
name: `${nameNode.text}.${methName.text}`,
|
|
170
|
+
kind: 'method',
|
|
171
|
+
line: member.startPosition.row + 1,
|
|
172
|
+
endLine: member.endPosition.row + 1,
|
|
146
173
|
});
|
|
147
174
|
}
|
|
148
175
|
}
|
|
@@ -170,9 +197,9 @@ function handleGoImportDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
170
197
|
function extractGoImportSpec(spec: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
171
198
|
const pathNode = spec.childForFieldName('path');
|
|
172
199
|
if (pathNode) {
|
|
173
|
-
const importPath = pathNode.text
|
|
200
|
+
const importPath = stripQuotes(pathNode.text);
|
|
174
201
|
const nameNode = spec.childForFieldName('name');
|
|
175
|
-
const alias = nameNode ? nameNode.text : (importPath
|
|
202
|
+
const alias = nameNode ? nameNode.text : lastPathSegment(importPath);
|
|
176
203
|
ctx.imports.push({
|
|
177
204
|
source: importPath,
|
|
178
205
|
names: [alias],
|
|
@@ -220,113 +247,104 @@ function extractGoTypeMap(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
220
247
|
extractGoTypeMapDepth(node, ctx, 0);
|
|
221
248
|
}
|
|
222
249
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
type: string
|
|
227
|
-
confidence: number,
|
|
250
|
+
/** Map identifiers in a typed declaration node to their type (confidence 0.9). */
|
|
251
|
+
function handleTypedIdentifiers(
|
|
252
|
+
node: TreeSitterNode,
|
|
253
|
+
typeMap: Map<string, { type: string; confidence: number }>,
|
|
228
254
|
): void {
|
|
229
|
-
const
|
|
230
|
-
if (!
|
|
231
|
-
|
|
255
|
+
const typeNode = node.childForFieldName('type');
|
|
256
|
+
if (!typeNode) return;
|
|
257
|
+
const typeName = extractGoTypeName(typeNode);
|
|
258
|
+
if (!typeName) return;
|
|
259
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
260
|
+
const child = node.child(i);
|
|
261
|
+
if (child && child.type === 'identifier') {
|
|
262
|
+
setTypeMapEntry(typeMap, child.text, typeName, 0.9);
|
|
263
|
+
}
|
|
232
264
|
}
|
|
233
265
|
}
|
|
234
266
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
267
|
+
/** Infer type from a single RHS expression in a short var declaration. */
|
|
268
|
+
function inferShortVarType(
|
|
269
|
+
varNode: TreeSitterNode,
|
|
270
|
+
rhs: TreeSitterNode,
|
|
271
|
+
typeMap: Map<string, { type: string; confidence: number }>,
|
|
272
|
+
): void {
|
|
273
|
+
// x := Struct{...} — composite literal (confidence 1.0)
|
|
274
|
+
if (rhs.type === 'composite_literal') {
|
|
275
|
+
const typeNode = rhs.childForFieldName('type');
|
|
241
276
|
if (typeNode) {
|
|
242
277
|
const typeName = extractGoTypeName(typeNode);
|
|
243
|
-
if (typeName)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
278
|
+
if (typeName) setTypeMapEntry(typeMap, varNode.text, typeName, 1.0);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// x := &Struct{...} — address-of composite literal (confidence 1.0)
|
|
282
|
+
if (rhs.type === 'unary_expression') {
|
|
283
|
+
const operand = rhs.childForFieldName('operand');
|
|
284
|
+
if (operand && operand.type === 'composite_literal') {
|
|
285
|
+
const typeNode = operand.childForFieldName('type');
|
|
286
|
+
if (typeNode) {
|
|
287
|
+
const typeName = extractGoTypeName(typeNode);
|
|
288
|
+
if (typeName) setTypeMapEntry(typeMap, varNode.text, typeName, 1.0);
|
|
250
289
|
}
|
|
251
290
|
}
|
|
252
291
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const child = node.child(i);
|
|
262
|
-
if (child && child.type === 'identifier') {
|
|
263
|
-
if (ctx.typeMap) setIfHigher(ctx.typeMap, child.text, typeName, 0.9);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
292
|
+
// x := NewFoo() or x := pkg.NewFoo() — factory function (confidence 0.7)
|
|
293
|
+
if (rhs.type === 'call_expression') {
|
|
294
|
+
const fn = rhs.childForFieldName('function');
|
|
295
|
+
if (fn && fn.type === 'selector_expression') {
|
|
296
|
+
const field = fn.childForFieldName('field');
|
|
297
|
+
if (field?.text.startsWith('New')) {
|
|
298
|
+
const typeName = field.text.slice(3);
|
|
299
|
+
if (typeName) setTypeMapEntry(typeMap, varNode.text, typeName, 0.7);
|
|
266
300
|
}
|
|
301
|
+
} else if (fn && fn.type === 'identifier' && fn.text.startsWith('New')) {
|
|
302
|
+
const typeName = fn.text.slice(3);
|
|
303
|
+
if (typeName) setTypeMapEntry(typeMap, varNode.text, typeName, 0.7);
|
|
267
304
|
}
|
|
268
305
|
}
|
|
306
|
+
}
|
|
269
307
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const typeName = extractGoTypeName(typeNode);
|
|
311
|
-
if (typeName && ctx.typeMap) setIfHigher(ctx.typeMap, varNode.text, typeName, 1.0);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
// x := NewFoo() or x := pkg.NewFoo() — factory function (confidence 0.7)
|
|
316
|
-
if (rhs.type === 'call_expression') {
|
|
317
|
-
const fn = rhs.childForFieldName('function');
|
|
318
|
-
if (fn && fn.type === 'selector_expression') {
|
|
319
|
-
const field = fn.childForFieldName('field');
|
|
320
|
-
if (field?.text.startsWith('New')) {
|
|
321
|
-
const typeName = field.text.slice(3);
|
|
322
|
-
if (typeName && ctx.typeMap) setIfHigher(ctx.typeMap, varNode.text, typeName, 0.7);
|
|
323
|
-
}
|
|
324
|
-
} else if (fn && fn.type === 'identifier' && fn.text.startsWith('New')) {
|
|
325
|
-
const typeName = fn.text.slice(3);
|
|
326
|
-
if (typeName && ctx.typeMap) setIfHigher(ctx.typeMap, varNode.text, typeName, 0.7);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
308
|
+
/** Handle short_var_declaration: x := Struct{}, x := &Struct{}, x := NewFoo(). */
|
|
309
|
+
function handleShortVarDecl(
|
|
310
|
+
node: TreeSitterNode,
|
|
311
|
+
typeMap: Map<string, { type: string; confidence: number }>,
|
|
312
|
+
): void {
|
|
313
|
+
const left = node.childForFieldName('left');
|
|
314
|
+
const right = node.childForFieldName('right');
|
|
315
|
+
if (!left || !right) return;
|
|
316
|
+
|
|
317
|
+
const lefts =
|
|
318
|
+
left.type === 'expression_list'
|
|
319
|
+
? Array.from({ length: left.childCount }, (_, i) => left.child(i)).filter(
|
|
320
|
+
(c): c is TreeSitterNode => c?.type === 'identifier',
|
|
321
|
+
)
|
|
322
|
+
: left.type === 'identifier'
|
|
323
|
+
? [left]
|
|
324
|
+
: [];
|
|
325
|
+
const rights =
|
|
326
|
+
right.type === 'expression_list'
|
|
327
|
+
? Array.from({ length: right.childCount }, (_, i) => right.child(i)).filter(
|
|
328
|
+
(c): c is TreeSitterNode => !!c?.type,
|
|
329
|
+
)
|
|
330
|
+
: [right];
|
|
331
|
+
|
|
332
|
+
for (let idx = 0; idx < lefts.length; idx++) {
|
|
333
|
+
const varNode = lefts[idx];
|
|
334
|
+
const rhs = rights[idx];
|
|
335
|
+
if (!varNode || !rhs) continue;
|
|
336
|
+
inferShortVarType(varNode, rhs, typeMap);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function extractGoTypeMapDepth(node: TreeSitterNode, ctx: ExtractorOutput, depth: number): void {
|
|
341
|
+
if (depth >= MAX_WALK_DEPTH) return;
|
|
342
|
+
|
|
343
|
+
if (ctx.typeMap) {
|
|
344
|
+
if (node.type === 'var_spec' || node.type === 'parameter_declaration') {
|
|
345
|
+
handleTypedIdentifiers(node, ctx.typeMap);
|
|
346
|
+
} else if (node.type === 'short_var_declaration') {
|
|
347
|
+
handleShortVarDecl(node, ctx.typeMap);
|
|
330
348
|
}
|
|
331
349
|
}
|
|
332
350
|
|
package/src/extractors/hcl.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
TreeSitterNode,
|
|
7
7
|
TreeSitterTree,
|
|
8
8
|
} from '../types.js';
|
|
9
|
-
import { nodeEndLine } from './helpers.js';
|
|
9
|
+
import { nodeEndLine, stripQuotes } from './helpers.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Extract symbols from HCL (Terraform) files.
|
|
@@ -80,18 +80,18 @@ function resolveHclBlockName(blockType: string, strings: TreeSitterNode[]): stri
|
|
|
80
80
|
const s0 = strings[0];
|
|
81
81
|
const s1 = strings[1];
|
|
82
82
|
if (blockType === 'resource' && s0 && s1) {
|
|
83
|
-
return `${s0.text
|
|
83
|
+
return `${stripQuotes(s0.text)}.${stripQuotes(s1.text)}`;
|
|
84
84
|
}
|
|
85
85
|
if (blockType === 'data' && s0 && s1) {
|
|
86
|
-
return `data.${s0.text
|
|
86
|
+
return `data.${stripQuotes(s0.text)}.${stripQuotes(s1.text)}`;
|
|
87
87
|
}
|
|
88
88
|
if ((blockType === 'variable' || blockType === 'output' || blockType === 'module') && s0) {
|
|
89
|
-
return `${blockType}.${s0.text
|
|
89
|
+
return `${blockType}.${stripQuotes(s0.text)}`;
|
|
90
90
|
}
|
|
91
91
|
if (blockType === 'locals') return 'locals';
|
|
92
92
|
if (blockType === 'terraform' || blockType === 'provider') {
|
|
93
93
|
let name = blockType;
|
|
94
|
-
if (s0) name += `.${s0.text
|
|
94
|
+
if (s0) name += `.${stripQuotes(s0.text)}`;
|
|
95
95
|
return name;
|
|
96
96
|
}
|
|
97
97
|
return '';
|
|
@@ -126,7 +126,7 @@ function extractHclModuleSource(
|
|
|
126
126
|
const key = attr.childForFieldName('key') || attr.child(0);
|
|
127
127
|
const val = attr.childForFieldName('val') || attr.child(2);
|
|
128
128
|
if (key && key.text === 'source' && val) {
|
|
129
|
-
const src = val.text
|
|
129
|
+
const src = stripQuotes(val.text);
|
|
130
130
|
if (src.startsWith('./') || src.startsWith('../')) {
|
|
131
131
|
ctx.imports.push({ source: src, names: [], line: attr.startPosition.row + 1 });
|
|
132
132
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TreeSitterNode } from '../types.js';
|
|
1
|
+
import type { SubDeclaration, TreeSitterNode, TypeMapEntry } from '../types.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Maximum recursion depth for tree-sitter AST walkers.
|
|
@@ -18,6 +18,22 @@ export function findChild(node: TreeSitterNode, type: string): TreeSitterNode |
|
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Merge a type-map entry, keeping the higher-confidence one.
|
|
23
|
+
* Shared across all language extractors that build type maps for call resolution.
|
|
24
|
+
*/
|
|
25
|
+
export function setTypeMapEntry(
|
|
26
|
+
typeMap: Map<string, TypeMapEntry>,
|
|
27
|
+
name: string,
|
|
28
|
+
type: string,
|
|
29
|
+
confidence: number,
|
|
30
|
+
): void {
|
|
31
|
+
const existing = typeMap.get(name);
|
|
32
|
+
if (!existing || confidence > existing.confidence) {
|
|
33
|
+
typeMap.set(name, { type, confidence });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
/**
|
|
22
38
|
* Extract visibility from a node by scanning its children for modifier keywords.
|
|
23
39
|
* Works for Java, C#, PHP, and similar languages where modifiers are child nodes.
|
|
@@ -70,6 +86,82 @@ export function rustVisibility(node: TreeSitterNode): 'public' | 'private' {
|
|
|
70
86
|
return 'private';
|
|
71
87
|
}
|
|
72
88
|
|
|
89
|
+
// ── Parser abstraction helpers ─────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Walk up the parent chain to find an enclosing node whose type is in `typeNames`.
|
|
93
|
+
* Returns the text of `nameField` (default `'name'`) on the matching ancestor, or null.
|
|
94
|
+
*
|
|
95
|
+
* Replaces per-language `findParentClass` / `findParentType` / `findCurrentImpl` helpers.
|
|
96
|
+
*/
|
|
97
|
+
export function findParentNode(
|
|
98
|
+
node: TreeSitterNode,
|
|
99
|
+
typeNames: readonly string[],
|
|
100
|
+
nameField: string = 'name',
|
|
101
|
+
): string | null {
|
|
102
|
+
let current = node.parent;
|
|
103
|
+
while (current) {
|
|
104
|
+
if (typeNames.includes(current.type)) {
|
|
105
|
+
const nameNode = current.childForFieldName(nameField);
|
|
106
|
+
return nameNode ? nameNode.text : null;
|
|
107
|
+
}
|
|
108
|
+
current = current.parent;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Extract child declarations from a container node's body.
|
|
115
|
+
* Finds the body via `bodyFields` (tries childForFieldName then findChild for each),
|
|
116
|
+
* iterates its children, filters by `memberType`, extracts `nameField`, and returns SubDeclarations.
|
|
117
|
+
*
|
|
118
|
+
* Replaces per-language extractStructFields / extractEnumVariants / extractEnumConstants helpers
|
|
119
|
+
* for the common case where each member has a direct name field.
|
|
120
|
+
*/
|
|
121
|
+
export function extractBodyMembers(
|
|
122
|
+
containerNode: TreeSitterNode,
|
|
123
|
+
bodyFields: readonly string[],
|
|
124
|
+
memberType: string,
|
|
125
|
+
kind: SubDeclaration['kind'],
|
|
126
|
+
nameField: string = 'name',
|
|
127
|
+
visibility?: (member: TreeSitterNode) => SubDeclaration['visibility'],
|
|
128
|
+
): SubDeclaration[] {
|
|
129
|
+
const members: SubDeclaration[] = [];
|
|
130
|
+
let body: TreeSitterNode | null = null;
|
|
131
|
+
for (const field of bodyFields) {
|
|
132
|
+
body = containerNode.childForFieldName(field) || findChild(containerNode, field);
|
|
133
|
+
if (body) break;
|
|
134
|
+
}
|
|
135
|
+
if (!body) return members;
|
|
136
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
137
|
+
const member = body.child(i);
|
|
138
|
+
if (!member || member.type !== memberType) continue;
|
|
139
|
+
const nn = member.childForFieldName(nameField);
|
|
140
|
+
if (nn) {
|
|
141
|
+
const entry: SubDeclaration = { name: nn.text, kind, line: member.startPosition.row + 1 };
|
|
142
|
+
if (visibility) entry.visibility = visibility(member);
|
|
143
|
+
members.push(entry);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return members;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Strip leading/trailing quotes (single, double, or backtick) from a string.
|
|
151
|
+
* Strips only the leading/trailing delimiter; interior quotes are untouched.
|
|
152
|
+
*/
|
|
153
|
+
export function stripQuotes(text: string): string {
|
|
154
|
+
return text.replace(/^['"`]|['"`]$/g, '');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Extract the last segment of a delimited path.
|
|
159
|
+
* e.g. `lastPathSegment('java.util.List', '.')` → `'List'`
|
|
160
|
+
*/
|
|
161
|
+
export function lastPathSegment(path: string, separator: string = '/'): string {
|
|
162
|
+
return path.split(separator).pop() ?? path;
|
|
163
|
+
}
|
|
164
|
+
|
|
73
165
|
export function extractModifierVisibility(
|
|
74
166
|
node: TreeSitterNode,
|
|
75
167
|
modifierTypes: Set<string> = DEFAULT_MODIFIER_TYPES,
|
package/src/extractors/index.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
export { extractBashSymbols } from './bash.js';
|
|
2
|
+
export { extractCSymbols } from './c.js';
|
|
3
|
+
export { extractCppSymbols } from './cpp.js';
|
|
1
4
|
export { extractCSharpSymbols } from './csharp.js';
|
|
2
5
|
export { extractGoSymbols } from './go.js';
|
|
3
6
|
export { extractHCLSymbols } from './hcl.js';
|
|
4
7
|
export { extractJavaSymbols } from './java.js';
|
|
5
8
|
export { extractSymbols } from './javascript.js';
|
|
9
|
+
export { extractKotlinSymbols } from './kotlin.js';
|
|
6
10
|
export { extractPHPSymbols } from './php.js';
|
|
7
11
|
export { extractPythonSymbols } from './python.js';
|
|
8
12
|
export { extractRubySymbols } from './ruby.js';
|
|
9
13
|
export { extractRustSymbols } from './rust.js';
|
|
14
|
+
export { extractScalaSymbols } from './scala.js';
|
|
15
|
+
export { extractSwiftSymbols } from './swift.js';
|
package/src/extractors/java.ts
CHANGED
|
@@ -6,7 +6,14 @@ import type {
|
|
|
6
6
|
TreeSitterTree,
|
|
7
7
|
TypeMapEntry,
|
|
8
8
|
} from '../types.js';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
extractBodyMembers,
|
|
11
|
+
extractModifierVisibility,
|
|
12
|
+
findChild,
|
|
13
|
+
findParentNode,
|
|
14
|
+
lastPathSegment,
|
|
15
|
+
nodeEndLine,
|
|
16
|
+
} from './helpers.js';
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* Extract symbols from Java files.
|
|
@@ -104,6 +111,25 @@ function handleJavaClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
|
|
114
|
+
const JAVA_TYPE_NODE_TYPES = new Set(['type_identifier', 'identifier', 'generic_type']);
|
|
115
|
+
|
|
116
|
+
/** Resolve interface name from a type node (handles generic_type unwrapping). */
|
|
117
|
+
function resolveJavaIfaceName(node: TreeSitterNode): string | undefined {
|
|
118
|
+
return node.type === 'generic_type' ? node.child(0)?.text : node.text;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Push a single interface type node as an implements entry. */
|
|
122
|
+
function pushJavaIface(
|
|
123
|
+
node: TreeSitterNode,
|
|
124
|
+
className: string,
|
|
125
|
+
line: number,
|
|
126
|
+
ctx: ExtractorOutput,
|
|
127
|
+
): void {
|
|
128
|
+
if (!JAVA_TYPE_NODE_TYPES.has(node.type)) return;
|
|
129
|
+
const ifaceName = resolveJavaIfaceName(node);
|
|
130
|
+
if (ifaceName) ctx.classes.push({ name: className, implements: ifaceName, line });
|
|
131
|
+
}
|
|
132
|
+
|
|
107
133
|
function extractJavaInterfaces(
|
|
108
134
|
interfaces: TreeSitterNode,
|
|
109
135
|
className: string,
|
|
@@ -112,28 +138,15 @@ function extractJavaInterfaces(
|
|
|
112
138
|
): void {
|
|
113
139
|
for (let i = 0; i < interfaces.childCount; i++) {
|
|
114
140
|
const child = interfaces.child(i);
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
) {
|
|
122
|
-
if (child.type === 'type_list') {
|
|
123
|
-
for (let j = 0; j < child.childCount; j++) {
|
|
124
|
-
const t = child.child(j);
|
|
125
|
-
if (
|
|
126
|
-
t &&
|
|
127
|
-
(t.type === 'type_identifier' || t.type === 'identifier' || t.type === 'generic_type')
|
|
128
|
-
) {
|
|
129
|
-
const ifaceName = t.type === 'generic_type' ? t.child(0)?.text : t.text;
|
|
130
|
-
if (ifaceName) ctx.classes.push({ name: className, implements: ifaceName, line });
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
} else {
|
|
134
|
-
const ifaceName = child.type === 'generic_type' ? child.child(0)?.text : child.text;
|
|
135
|
-
if (ifaceName) ctx.classes.push({ name: className, implements: ifaceName, line });
|
|
141
|
+
if (!child) continue;
|
|
142
|
+
|
|
143
|
+
if (child.type === 'type_list') {
|
|
144
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
145
|
+
const t = child.child(j);
|
|
146
|
+
if (t) pushJavaIface(t, className, line, ctx);
|
|
136
147
|
}
|
|
148
|
+
} else {
|
|
149
|
+
pushJavaIface(child, className, line, ctx);
|
|
137
150
|
}
|
|
138
151
|
}
|
|
139
152
|
}
|
|
@@ -218,7 +231,7 @@ function handleJavaImportDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
218
231
|
const child = node.child(i);
|
|
219
232
|
if (child && (child.type === 'scoped_identifier' || child.type === 'identifier')) {
|
|
220
233
|
const fullPath = child.text;
|
|
221
|
-
const lastName = fullPath
|
|
234
|
+
const lastName = lastPathSegment(fullPath, '.');
|
|
222
235
|
ctx.imports.push({
|
|
223
236
|
source: fullPath,
|
|
224
237
|
names: [lastName],
|
|
@@ -263,20 +276,13 @@ function handleJavaObjectCreation(node: TreeSitterNode, ctx: ExtractorOutput): v
|
|
|
263
276
|
if (typeName) ctx.calls.push({ name: typeName, line: node.startPosition.row + 1 });
|
|
264
277
|
}
|
|
265
278
|
|
|
279
|
+
const JAVA_PARENT_TYPES = [
|
|
280
|
+
'class_declaration',
|
|
281
|
+
'enum_declaration',
|
|
282
|
+
'interface_declaration',
|
|
283
|
+
] as const;
|
|
266
284
|
function findJavaParentClass(node: TreeSitterNode): string | null {
|
|
267
|
-
|
|
268
|
-
while (current) {
|
|
269
|
-
if (
|
|
270
|
-
current.type === 'class_declaration' ||
|
|
271
|
-
current.type === 'enum_declaration' ||
|
|
272
|
-
current.type === 'interface_declaration'
|
|
273
|
-
) {
|
|
274
|
-
const nameNode = current.childForFieldName('name');
|
|
275
|
-
return nameNode ? nameNode.text : null;
|
|
276
|
-
}
|
|
277
|
-
current = current.parent;
|
|
278
|
-
}
|
|
279
|
-
return null;
|
|
285
|
+
return findParentNode(node, JAVA_PARENT_TYPES);
|
|
280
286
|
}
|
|
281
287
|
|
|
282
288
|
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
@@ -333,16 +339,5 @@ function extractClassFields(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
333
339
|
}
|
|
334
340
|
|
|
335
341
|
function extractEnumConstants(enumNode: TreeSitterNode): SubDeclaration[] {
|
|
336
|
-
|
|
337
|
-
const body = enumNode.childForFieldName('body') || findChild(enumNode, 'enum_body');
|
|
338
|
-
if (!body) return constants;
|
|
339
|
-
for (let i = 0; i < body.childCount; i++) {
|
|
340
|
-
const member = body.child(i);
|
|
341
|
-
if (!member || member.type !== 'enum_constant') continue;
|
|
342
|
-
const nameNode = member.childForFieldName('name');
|
|
343
|
-
if (nameNode) {
|
|
344
|
-
constants.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return constants;
|
|
342
|
+
return extractBodyMembers(enumNode, ['body', 'enum_body'], 'enum_constant', 'constant');
|
|
348
343
|
}
|