@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
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Call,
|
|
3
|
+
ExtractorOutput,
|
|
4
|
+
SubDeclaration,
|
|
5
|
+
TreeSitterNode,
|
|
6
|
+
TreeSitterTree,
|
|
7
|
+
} from '../types.js';
|
|
8
|
+
import { extractModifierVisibility, findChild, nodeEndLine } from './helpers.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extract symbols from Kotlin files.
|
|
12
|
+
*/
|
|
13
|
+
export function extractKotlinSymbols(tree: TreeSitterTree, _filePath: string): ExtractorOutput {
|
|
14
|
+
const ctx: ExtractorOutput = {
|
|
15
|
+
definitions: [],
|
|
16
|
+
calls: [],
|
|
17
|
+
imports: [],
|
|
18
|
+
classes: [],
|
|
19
|
+
exports: [],
|
|
20
|
+
typeMap: new Map(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
walkKotlinNode(tree.rootNode, ctx);
|
|
24
|
+
return ctx;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function walkKotlinNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
28
|
+
switch (node.type) {
|
|
29
|
+
case 'class_declaration':
|
|
30
|
+
handleKotlinClassDecl(node, ctx);
|
|
31
|
+
break;
|
|
32
|
+
case 'object_declaration':
|
|
33
|
+
handleKotlinObjectDecl(node, ctx);
|
|
34
|
+
break;
|
|
35
|
+
case 'function_declaration':
|
|
36
|
+
handleKotlinFunctionDecl(node, ctx);
|
|
37
|
+
break;
|
|
38
|
+
case 'import_header':
|
|
39
|
+
handleKotlinImport(node, ctx);
|
|
40
|
+
break;
|
|
41
|
+
case 'call_expression':
|
|
42
|
+
handleKotlinCallExpression(node, ctx);
|
|
43
|
+
break;
|
|
44
|
+
case 'navigation_expression':
|
|
45
|
+
handleKotlinNavExpression(node, ctx);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
50
|
+
const child = node.child(i);
|
|
51
|
+
if (child) walkKotlinNode(child, ctx);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ── Walk-path per-node-type handlers ────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
function hasKeywordChild(node: TreeSitterNode, keyword: string): boolean {
|
|
58
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
59
|
+
const child = node.child(i);
|
|
60
|
+
if (child && child.text === keyword) return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function hasModifier(node: TreeSitterNode, keyword: string): boolean {
|
|
66
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
67
|
+
const child = node.child(i);
|
|
68
|
+
if (!child) continue;
|
|
69
|
+
if (child.type === 'modifiers' && child.text.includes(keyword)) return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleKotlinClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
75
|
+
const isInterface = hasKeywordChild(node, 'interface');
|
|
76
|
+
const isEnum = hasModifier(node, 'enum');
|
|
77
|
+
|
|
78
|
+
const nameNode = findChild(node, 'type_identifier');
|
|
79
|
+
if (!nameNode) return;
|
|
80
|
+
const name = nameNode.text;
|
|
81
|
+
|
|
82
|
+
const kind = isInterface ? 'interface' : isEnum ? 'enum' : 'class';
|
|
83
|
+
|
|
84
|
+
const children: SubDeclaration[] = [];
|
|
85
|
+
if (isEnum) {
|
|
86
|
+
// Enum entries are inside class_body
|
|
87
|
+
const body = findChild(node, 'class_body');
|
|
88
|
+
if (body) {
|
|
89
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
90
|
+
const child = body.child(i);
|
|
91
|
+
if (child && child.type === 'enum_entry') {
|
|
92
|
+
const entryName = findChild(child, 'simple_identifier');
|
|
93
|
+
if (entryName) {
|
|
94
|
+
children.push({
|
|
95
|
+
name: entryName.text,
|
|
96
|
+
kind: 'constant',
|
|
97
|
+
line: child.startPosition.row + 1,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// Extract properties from class_body
|
|
105
|
+
const body = findChild(node, 'class_body');
|
|
106
|
+
if (body) {
|
|
107
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
108
|
+
const child = body.child(i);
|
|
109
|
+
if (child && child.type === 'property_declaration') {
|
|
110
|
+
const propName = findChild(child, 'variable_declaration');
|
|
111
|
+
if (propName) {
|
|
112
|
+
const id = findChild(propName, 'simple_identifier');
|
|
113
|
+
if (id) {
|
|
114
|
+
children.push({
|
|
115
|
+
name: id.text,
|
|
116
|
+
kind: 'property',
|
|
117
|
+
line: child.startPosition.row + 1,
|
|
118
|
+
visibility: extractModifierVisibility(child),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
ctx.definitions.push({
|
|
128
|
+
name,
|
|
129
|
+
kind,
|
|
130
|
+
line: node.startPosition.row + 1,
|
|
131
|
+
endLine: nodeEndLine(node),
|
|
132
|
+
children: children.length > 0 ? children : undefined,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Methods inside class_body
|
|
136
|
+
const body = findChild(node, 'class_body');
|
|
137
|
+
if (body) {
|
|
138
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
139
|
+
const child = body.child(i);
|
|
140
|
+
if (child && child.type === 'function_declaration') {
|
|
141
|
+
const methName = findChild(child, 'simple_identifier');
|
|
142
|
+
if (methName) {
|
|
143
|
+
ctx.definitions.push({
|
|
144
|
+
name: `${name}.${methName.text}`,
|
|
145
|
+
kind: 'method',
|
|
146
|
+
line: child.startPosition.row + 1,
|
|
147
|
+
endLine: child.endPosition.row + 1,
|
|
148
|
+
visibility: extractModifierVisibility(child),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Inheritance: delegation_specifier nodes are DIRECT children
|
|
156
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
157
|
+
const child = node.child(i);
|
|
158
|
+
if (!child || child.type !== 'delegation_specifier') continue;
|
|
159
|
+
|
|
160
|
+
// constructor_invocation > user_type > type_identifier (extends)
|
|
161
|
+
const ctorInvocation = findChild(child, 'constructor_invocation');
|
|
162
|
+
if (ctorInvocation) {
|
|
163
|
+
const userType = findChild(ctorInvocation, 'user_type');
|
|
164
|
+
if (userType) {
|
|
165
|
+
const typeId = findChild(userType, 'type_identifier');
|
|
166
|
+
if (typeId) {
|
|
167
|
+
ctx.classes.push({
|
|
168
|
+
name,
|
|
169
|
+
extends: typeId.text,
|
|
170
|
+
line: node.startPosition.row + 1,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// user_type > type_identifier (implements)
|
|
178
|
+
const userType = findChild(child, 'user_type');
|
|
179
|
+
if (userType) {
|
|
180
|
+
const typeId = findChild(userType, 'type_identifier');
|
|
181
|
+
if (typeId) {
|
|
182
|
+
ctx.classes.push({
|
|
183
|
+
name,
|
|
184
|
+
implements: typeId.text,
|
|
185
|
+
line: node.startPosition.row + 1,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function handleKotlinObjectDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
193
|
+
const nameNode = findChild(node, 'type_identifier');
|
|
194
|
+
if (!nameNode) return;
|
|
195
|
+
ctx.definitions.push({
|
|
196
|
+
name: nameNode.text,
|
|
197
|
+
kind: 'class',
|
|
198
|
+
line: node.startPosition.row + 1,
|
|
199
|
+
endLine: nodeEndLine(node),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Methods inside object body
|
|
203
|
+
const body = findChild(node, 'class_body');
|
|
204
|
+
if (body) {
|
|
205
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
206
|
+
const child = body.child(i);
|
|
207
|
+
if (child && child.type === 'function_declaration') {
|
|
208
|
+
const methName = findChild(child, 'simple_identifier');
|
|
209
|
+
if (methName) {
|
|
210
|
+
ctx.definitions.push({
|
|
211
|
+
name: `${nameNode.text}.${methName.text}`,
|
|
212
|
+
kind: 'method',
|
|
213
|
+
line: child.startPosition.row + 1,
|
|
214
|
+
endLine: child.endPosition.row + 1,
|
|
215
|
+
visibility: extractModifierVisibility(child),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function handleKotlinFunctionDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
224
|
+
// Skip methods already emitted by class/object handlers
|
|
225
|
+
if (
|
|
226
|
+
node.parent?.type === 'class_body' &&
|
|
227
|
+
(node.parent.parent?.type === 'class_declaration' ||
|
|
228
|
+
node.parent.parent?.type === 'object_declaration')
|
|
229
|
+
) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const nameNode = findChild(node, 'simple_identifier');
|
|
233
|
+
if (!nameNode) return;
|
|
234
|
+
const params = extractKotlinParameters(node);
|
|
235
|
+
ctx.definitions.push({
|
|
236
|
+
name: nameNode.text,
|
|
237
|
+
kind: 'function',
|
|
238
|
+
line: node.startPosition.row + 1,
|
|
239
|
+
endLine: nodeEndLine(node),
|
|
240
|
+
children: params.length > 0 ? params : undefined,
|
|
241
|
+
visibility: extractModifierVisibility(node),
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function handleKotlinImport(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
246
|
+
const identNode = findChild(node, 'identifier');
|
|
247
|
+
if (!identNode) return;
|
|
248
|
+
const fullPath = identNode.text;
|
|
249
|
+
const lastName = fullPath.split('.').pop() ?? fullPath;
|
|
250
|
+
ctx.imports.push({
|
|
251
|
+
source: fullPath,
|
|
252
|
+
names: [lastName],
|
|
253
|
+
line: node.startPosition.row + 1,
|
|
254
|
+
kotlinImport: true,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function handleKotlinCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
259
|
+
const funcNode = node.child(0);
|
|
260
|
+
if (!funcNode) return;
|
|
261
|
+
if (funcNode.type === 'simple_identifier') {
|
|
262
|
+
ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function handleKotlinNavExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
267
|
+
// navigation_expression: expr . identifier — only emit if parent is call_expression
|
|
268
|
+
if (node.parent?.type !== 'call_expression') return;
|
|
269
|
+
const lastChild = node.child(node.childCount - 1);
|
|
270
|
+
const firstChild = node.child(0);
|
|
271
|
+
if (lastChild && lastChild.type === 'simple_identifier' && firstChild) {
|
|
272
|
+
const call: Call = { name: lastChild.text, line: node.startPosition.row + 1 };
|
|
273
|
+
call.receiver = firstChild.text;
|
|
274
|
+
ctx.calls.push(call);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
279
|
+
|
|
280
|
+
function extractKotlinParameters(funcNode: TreeSitterNode): SubDeclaration[] {
|
|
281
|
+
const params: SubDeclaration[] = [];
|
|
282
|
+
const paramList = findChild(funcNode, 'function_value_parameters');
|
|
283
|
+
if (!paramList) return params;
|
|
284
|
+
for (let i = 0; i < paramList.childCount; i++) {
|
|
285
|
+
const param = paramList.child(i);
|
|
286
|
+
if (!param || param.type !== 'parameter') continue;
|
|
287
|
+
const nameNode = findChild(param, 'simple_identifier');
|
|
288
|
+
if (nameNode) {
|
|
289
|
+
params.push({ name: nameNode.text, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return params;
|
|
293
|
+
}
|
package/src/extractors/php.ts
CHANGED
|
@@ -5,7 +5,14 @@ import type {
|
|
|
5
5
|
TreeSitterNode,
|
|
6
6
|
TreeSitterTree,
|
|
7
7
|
} from '../types.js';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
extractBodyMembers,
|
|
10
|
+
extractModifierVisibility,
|
|
11
|
+
findChild,
|
|
12
|
+
lastPathSegment,
|
|
13
|
+
MAX_WALK_DEPTH,
|
|
14
|
+
nodeEndLine,
|
|
15
|
+
} from './helpers.js';
|
|
9
16
|
|
|
10
17
|
function extractPhpParameters(fnNode: TreeSitterNode): SubDeclaration[] {
|
|
11
18
|
const params: SubDeclaration[] = [];
|
|
@@ -25,6 +32,39 @@ function extractPhpParameters(fnNode: TreeSitterNode): SubDeclaration[] {
|
|
|
25
32
|
return params;
|
|
26
33
|
}
|
|
27
34
|
|
|
35
|
+
/** Extract property declarations from a PHP class member. */
|
|
36
|
+
function extractPhpProperties(member: TreeSitterNode, children: SubDeclaration[]): void {
|
|
37
|
+
for (let j = 0; j < member.childCount; j++) {
|
|
38
|
+
const el = member.child(j);
|
|
39
|
+
if (!el || el.type !== 'property_element') continue;
|
|
40
|
+
const varNode = findChild(el, 'variable_name');
|
|
41
|
+
if (varNode) {
|
|
42
|
+
children.push({
|
|
43
|
+
name: varNode.text,
|
|
44
|
+
kind: 'property',
|
|
45
|
+
line: member.startPosition.row + 1,
|
|
46
|
+
visibility: extractModifierVisibility(member),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Extract constant declarations from a PHP class member. */
|
|
53
|
+
function extractPhpConstants(member: TreeSitterNode, children: SubDeclaration[]): void {
|
|
54
|
+
for (let j = 0; j < member.childCount; j++) {
|
|
55
|
+
const el = member.child(j);
|
|
56
|
+
if (!el || el.type !== 'const_element') continue;
|
|
57
|
+
const nameNode = el.childForFieldName('name') || findChild(el, 'name');
|
|
58
|
+
if (nameNode) {
|
|
59
|
+
children.push({
|
|
60
|
+
name: nameNode.text,
|
|
61
|
+
kind: 'constant',
|
|
62
|
+
line: member.startPosition.row + 1,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
28
68
|
function extractPhpClassChildren(classNode: TreeSitterNode): SubDeclaration[] {
|
|
29
69
|
const children: SubDeclaration[] = [];
|
|
30
70
|
const body = classNode.childForFieldName('body') || findChild(classNode, 'declaration_list');
|
|
@@ -33,50 +73,16 @@ function extractPhpClassChildren(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
33
73
|
const member = body.child(i);
|
|
34
74
|
if (!member) continue;
|
|
35
75
|
if (member.type === 'property_declaration') {
|
|
36
|
-
|
|
37
|
-
const el = member.child(j);
|
|
38
|
-
if (!el || el.type !== 'property_element') continue;
|
|
39
|
-
const varNode = findChild(el, 'variable_name');
|
|
40
|
-
if (varNode) {
|
|
41
|
-
children.push({
|
|
42
|
-
name: varNode.text,
|
|
43
|
-
kind: 'property',
|
|
44
|
-
line: member.startPosition.row + 1,
|
|
45
|
-
visibility: extractModifierVisibility(member),
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
76
|
+
extractPhpProperties(member, children);
|
|
49
77
|
} else if (member.type === 'const_declaration') {
|
|
50
|
-
|
|
51
|
-
const el = member.child(j);
|
|
52
|
-
if (!el || el.type !== 'const_element') continue;
|
|
53
|
-
const nameNode = el.childForFieldName('name') || findChild(el, 'name');
|
|
54
|
-
if (nameNode) {
|
|
55
|
-
children.push({
|
|
56
|
-
name: nameNode.text,
|
|
57
|
-
kind: 'constant',
|
|
58
|
-
line: member.startPosition.row + 1,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
78
|
+
extractPhpConstants(member, children);
|
|
62
79
|
}
|
|
63
80
|
}
|
|
64
81
|
return children;
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
function extractPhpEnumCases(enumNode: TreeSitterNode): SubDeclaration[] {
|
|
68
|
-
|
|
69
|
-
const body = enumNode.childForFieldName('body') || findChild(enumNode, 'enum_declaration_list');
|
|
70
|
-
if (!body) return children;
|
|
71
|
-
for (let i = 0; i < body.childCount; i++) {
|
|
72
|
-
const member = body.child(i);
|
|
73
|
-
if (!member || member.type !== 'enum_case') continue;
|
|
74
|
-
const nameNode = member.childForFieldName('name');
|
|
75
|
-
if (nameNode) {
|
|
76
|
-
children.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return children;
|
|
85
|
+
return extractBodyMembers(enumNode, ['body', 'enum_declaration_list'], 'enum_case', 'constant');
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
/**
|
|
@@ -272,7 +278,7 @@ function handlePhpNamespaceUse(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
272
278
|
const nameNode = findChild(child, 'qualified_name') || findChild(child, 'name');
|
|
273
279
|
if (nameNode) {
|
|
274
280
|
const fullPath = nameNode.text;
|
|
275
|
-
const lastName = fullPath
|
|
281
|
+
const lastName = lastPathSegment(fullPath, '\\');
|
|
276
282
|
const alias = child.childForFieldName('alias');
|
|
277
283
|
ctx.imports.push({
|
|
278
284
|
source: fullPath,
|
|
@@ -284,7 +290,7 @@ function handlePhpNamespaceUse(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
284
290
|
}
|
|
285
291
|
if (child && (child.type === 'qualified_name' || child.type === 'name')) {
|
|
286
292
|
const fullPath = child.text;
|
|
287
|
-
const lastName = fullPath
|
|
293
|
+
const lastName = lastPathSegment(fullPath, '\\');
|
|
288
294
|
ctx.imports.push({
|
|
289
295
|
source: fullPath,
|
|
290
296
|
names: [lastName],
|
package/src/extractors/python.ts
CHANGED
|
@@ -4,9 +4,15 @@ 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
|
+
findParentNode,
|
|
11
|
+
MAX_WALK_DEPTH,
|
|
12
|
+
nodeEndLine,
|
|
13
|
+
pythonVisibility,
|
|
14
|
+
setTypeMapEntry,
|
|
15
|
+
} from './helpers.js';
|
|
10
16
|
|
|
11
17
|
/** Built-in globals that start with uppercase but are not user-defined types. */
|
|
12
18
|
const BUILTIN_GLOBALS_PY: Set<string> = new Set([
|
|
@@ -268,6 +274,37 @@ function extractPythonParameters(fnNode: TreeSitterNode): SubDeclaration[] {
|
|
|
268
274
|
return params;
|
|
269
275
|
}
|
|
270
276
|
|
|
277
|
+
/** Extract class-level assignment properties from expression statements. */
|
|
278
|
+
function extractClassAssignment(
|
|
279
|
+
child: TreeSitterNode,
|
|
280
|
+
seen: Set<string>,
|
|
281
|
+
props: SubDeclaration[],
|
|
282
|
+
): void {
|
|
283
|
+
const assignment = findChild(child, 'assignment');
|
|
284
|
+
if (!assignment) return;
|
|
285
|
+
const left = assignment.childForFieldName('left');
|
|
286
|
+
if (!left || left.type !== 'identifier' || seen.has(left.text)) return;
|
|
287
|
+
seen.add(left.text);
|
|
288
|
+
props.push({
|
|
289
|
+
name: left.text,
|
|
290
|
+
kind: 'property',
|
|
291
|
+
line: child.startPosition.row + 1,
|
|
292
|
+
visibility: pythonVisibility(left.text),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** If node is an __init__ method, walk its body for self.x assignments. */
|
|
297
|
+
function extractInitProperties(
|
|
298
|
+
node: TreeSitterNode,
|
|
299
|
+
seen: Set<string>,
|
|
300
|
+
props: SubDeclaration[],
|
|
301
|
+
): void {
|
|
302
|
+
const fnName = node.childForFieldName('name');
|
|
303
|
+
if (!fnName || fnName.text !== '__init__') return;
|
|
304
|
+
const initBody = node.childForFieldName('body') || findChild(node, 'block');
|
|
305
|
+
if (initBody) walkInitBody(initBody, seen, props);
|
|
306
|
+
}
|
|
307
|
+
|
|
271
308
|
function extractPythonClassProperties(classNode: TreeSitterNode): SubDeclaration[] {
|
|
272
309
|
const props: SubDeclaration[] = [];
|
|
273
310
|
const seen = new Set<string>();
|
|
@@ -279,42 +316,14 @@ function extractPythonClassProperties(classNode: TreeSitterNode): SubDeclaration
|
|
|
279
316
|
if (!child) continue;
|
|
280
317
|
|
|
281
318
|
if (child.type === 'expression_statement') {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
seen.add(left.text);
|
|
287
|
-
props.push({
|
|
288
|
-
name: left.text,
|
|
289
|
-
kind: 'property',
|
|
290
|
-
line: child.startPosition.row + 1,
|
|
291
|
-
visibility: pythonVisibility(left.text),
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (child.type === 'function_definition') {
|
|
298
|
-
const fnName = child.childForFieldName('name');
|
|
299
|
-
if (fnName && fnName.text === '__init__') {
|
|
300
|
-
const initBody = child.childForFieldName('body') || findChild(child, 'block');
|
|
301
|
-
if (initBody) {
|
|
302
|
-
walkInitBody(initBody, seen, props);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (child.type === 'decorated_definition') {
|
|
319
|
+
extractClassAssignment(child, seen, props);
|
|
320
|
+
} else if (child.type === 'function_definition') {
|
|
321
|
+
extractInitProperties(child, seen, props);
|
|
322
|
+
} else if (child.type === 'decorated_definition') {
|
|
308
323
|
for (let j = 0; j < child.childCount; j++) {
|
|
309
324
|
const inner = child.child(j);
|
|
310
325
|
if (inner && inner.type === 'function_definition') {
|
|
311
|
-
|
|
312
|
-
if (fnName && fnName.text === '__init__') {
|
|
313
|
-
const initBody = inner.childForFieldName('body') || findChild(inner, 'block');
|
|
314
|
-
if (initBody) {
|
|
315
|
-
walkInitBody(initBody, seen, props);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
326
|
+
extractInitProperties(inner, seen, props);
|
|
318
327
|
}
|
|
319
328
|
}
|
|
320
329
|
}
|
|
@@ -348,15 +357,37 @@ function extractPythonTypeMap(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
348
357
|
extractPythonTypeMapDepth(node, ctx, 0);
|
|
349
358
|
}
|
|
350
359
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
+
/** Handle typed_parameter or typed_default_parameter for type map. */
|
|
361
|
+
function handlePyTypedParam(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
362
|
+
const isDefault = node.type === 'typed_default_parameter';
|
|
363
|
+
const nameNode = isDefault ? node.childForFieldName('name') : node.child(0);
|
|
364
|
+
const typeNode = node.childForFieldName('type');
|
|
365
|
+
if (!nameNode || nameNode.type !== 'identifier' || !typeNode) return;
|
|
366
|
+
if (nameNode.text === 'self' || nameNode.text === 'cls') return;
|
|
367
|
+
const typeName = extractPythonTypeName(typeNode);
|
|
368
|
+
if (typeName && ctx.typeMap) setTypeMapEntry(ctx.typeMap, nameNode.text, typeName, 0.9);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Handle assignment for constructor/factory type inference. */
|
|
372
|
+
function handlePyAssignmentType(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
373
|
+
const left = node.childForFieldName('left');
|
|
374
|
+
const right = node.childForFieldName('right');
|
|
375
|
+
if (!left || left.type !== 'identifier' || !right || right.type !== 'call') return;
|
|
376
|
+
|
|
377
|
+
const fn = right.childForFieldName('function');
|
|
378
|
+
if (!fn) return;
|
|
379
|
+
if (fn.type === 'identifier') {
|
|
380
|
+
const name = fn.text;
|
|
381
|
+
if (name[0] && name[0] !== name[0].toLowerCase()) {
|
|
382
|
+
if (ctx.typeMap) setTypeMapEntry(ctx.typeMap, left.text, name, 1.0);
|
|
383
|
+
}
|
|
384
|
+
} else if (fn.type === 'attribute') {
|
|
385
|
+
const obj = fn.childForFieldName('object');
|
|
386
|
+
if (!obj || obj.type !== 'identifier') return;
|
|
387
|
+
const objName = obj.text;
|
|
388
|
+
if (objName[0] && objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS_PY.has(objName)) {
|
|
389
|
+
if (ctx.typeMap) setTypeMapEntry(ctx.typeMap, left.text, objName, 0.7);
|
|
390
|
+
}
|
|
360
391
|
}
|
|
361
392
|
}
|
|
362
393
|
|
|
@@ -367,57 +398,10 @@ function extractPythonTypeMapDepth(
|
|
|
367
398
|
): void {
|
|
368
399
|
if (depth >= MAX_WALK_DEPTH) return;
|
|
369
400
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (nameNode && nameNode.type === 'identifier' && typeNode) {
|
|
375
|
-
const typeName = extractPythonTypeName(typeNode);
|
|
376
|
-
if (typeName && nameNode.text !== 'self' && nameNode.text !== 'cls') {
|
|
377
|
-
if (ctx.typeMap) setIfHigherPy(ctx.typeMap, nameNode.text, typeName, 0.9);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// typed_default_parameter: name : type = default (confidence 0.9)
|
|
383
|
-
if (node.type === 'typed_default_parameter') {
|
|
384
|
-
const nameNode = node.childForFieldName('name');
|
|
385
|
-
const typeNode = node.childForFieldName('type');
|
|
386
|
-
if (nameNode && nameNode.type === 'identifier' && typeNode) {
|
|
387
|
-
const typeName = extractPythonTypeName(typeNode);
|
|
388
|
-
if (typeName && nameNode.text !== 'self' && nameNode.text !== 'cls') {
|
|
389
|
-
if (ctx.typeMap) setIfHigherPy(ctx.typeMap, nameNode.text, typeName, 0.9);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// assignment: x = SomeClass(...) → constructor (confidence 1.0)
|
|
395
|
-
// x = SomeClass.create(...) → factory (confidence 0.7)
|
|
396
|
-
if (node.type === 'assignment') {
|
|
397
|
-
const left = node.childForFieldName('left');
|
|
398
|
-
const right = node.childForFieldName('right');
|
|
399
|
-
if (left && left.type === 'identifier' && right && right.type === 'call') {
|
|
400
|
-
const fn = right.childForFieldName('function');
|
|
401
|
-
if (fn && fn.type === 'identifier') {
|
|
402
|
-
const name = fn.text;
|
|
403
|
-
if (name[0] && name[0] !== name[0].toLowerCase()) {
|
|
404
|
-
if (ctx.typeMap) setIfHigherPy(ctx.typeMap, left.text, name, 1.0);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
if (fn && fn.type === 'attribute') {
|
|
408
|
-
const obj = fn.childForFieldName('object');
|
|
409
|
-
if (obj && obj.type === 'identifier') {
|
|
410
|
-
const objName = obj.text;
|
|
411
|
-
if (
|
|
412
|
-
objName[0] &&
|
|
413
|
-
objName[0] !== objName[0].toLowerCase() &&
|
|
414
|
-
!BUILTIN_GLOBALS_PY.has(objName)
|
|
415
|
-
) {
|
|
416
|
-
if (ctx.typeMap) setIfHigherPy(ctx.typeMap, left.text, objName, 0.7);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
401
|
+
if (node.type === 'typed_parameter' || node.type === 'typed_default_parameter') {
|
|
402
|
+
handlePyTypedParam(node, ctx);
|
|
403
|
+
} else if (node.type === 'assignment') {
|
|
404
|
+
handlePyAssignmentType(node, ctx);
|
|
421
405
|
}
|
|
422
406
|
|
|
423
407
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -441,14 +425,7 @@ function extractPythonTypeName(typeNode: TreeSitterNode): string | null {
|
|
|
441
425
|
return null;
|
|
442
426
|
}
|
|
443
427
|
|
|
428
|
+
const PY_CLASS_TYPES = ['class_definition'] as const;
|
|
444
429
|
function findPythonParentClass(node: TreeSitterNode): string | null {
|
|
445
|
-
|
|
446
|
-
while (current) {
|
|
447
|
-
if (current.type === 'class_definition') {
|
|
448
|
-
const nameNode = current.childForFieldName('name');
|
|
449
|
-
return nameNode ? nameNode.text : null;
|
|
450
|
-
}
|
|
451
|
-
current = current.parent;
|
|
452
|
-
}
|
|
453
|
-
return null;
|
|
430
|
+
return findParentNode(node, PY_CLASS_TYPES);
|
|
454
431
|
}
|
package/src/extractors/ruby.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
TreeSitterNode,
|
|
6
6
|
TreeSitterTree,
|
|
7
7
|
} from '../types.js';
|
|
8
|
-
import { findChild, nodeEndLine } from './helpers.js';
|
|
8
|
+
import { findChild, findParentNode, lastPathSegment, nodeEndLine, stripQuotes } from './helpers.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Extract symbols from Ruby files.
|
|
@@ -176,10 +176,10 @@ function handleRubyRequire(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
176
176
|
for (let i = 0; i < args.childCount; i++) {
|
|
177
177
|
const arg = args.child(i);
|
|
178
178
|
if (arg && (arg.type === 'string' || arg.type === 'string_content')) {
|
|
179
|
-
const strContent = arg.text
|
|
179
|
+
const strContent = stripQuotes(arg.text);
|
|
180
180
|
ctx.imports.push({
|
|
181
181
|
source: strContent,
|
|
182
|
-
names: [strContent
|
|
182
|
+
names: [lastPathSegment(strContent)],
|
|
183
183
|
line: node.startPosition.row + 1,
|
|
184
184
|
rubyRequire: true,
|
|
185
185
|
});
|
|
@@ -190,7 +190,7 @@ function handleRubyRequire(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
190
190
|
if (content) {
|
|
191
191
|
ctx.imports.push({
|
|
192
192
|
source: content.text,
|
|
193
|
-
names: [content.text
|
|
193
|
+
names: [lastPathSegment(content.text)],
|
|
194
194
|
line: node.startPosition.row + 1,
|
|
195
195
|
rubyRequire: true,
|
|
196
196
|
});
|
|
@@ -221,16 +221,9 @@ function handleRubyModuleInclusion(
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
const RUBY_PARENT_TYPES = ['class', 'module'] as const;
|
|
224
225
|
function findRubyParentClass(node: TreeSitterNode): string | null {
|
|
225
|
-
|
|
226
|
-
while (current) {
|
|
227
|
-
if (current.type === 'class' || current.type === 'module') {
|
|
228
|
-
const nameNode = current.childForFieldName('name');
|
|
229
|
-
return nameNode ? nameNode.text : null;
|
|
230
|
-
}
|
|
231
|
-
current = current.parent;
|
|
232
|
-
}
|
|
233
|
-
return null;
|
|
226
|
+
return findParentNode(node, RUBY_PARENT_TYPES);
|
|
234
227
|
}
|
|
235
228
|
|
|
236
229
|
// ── Child extraction helpers ────────────────────────────────────────────────
|