gitnexus 1.5.3 → 1.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 +10 -0
- package/dist/_shared/graph/types.d.ts +1 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +1 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +3 -1
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/mro-strategy.d.ts +19 -0
- package/dist/_shared/mro-strategy.d.ts.map +1 -0
- package/dist/_shared/mro-strategy.js +2 -0
- package/dist/_shared/mro-strategy.js.map +1 -0
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +28 -4
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +2 -1
- package/dist/cli/group.d.ts +2 -0
- package/dist/cli/group.js +233 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/serve.js +4 -1
- package/dist/cli/setup.js +34 -3
- package/dist/config/ignore-service.js +8 -3
- package/dist/core/augmentation/engine.js +1 -1
- package/dist/core/git-staleness.d.ts +13 -0
- package/dist/core/git-staleness.js +29 -0
- package/dist/core/group/bridge-db.d.ts +82 -0
- package/dist/core/group/bridge-db.js +460 -0
- package/dist/core/group/bridge-schema.d.ts +27 -0
- package/dist/core/group/bridge-schema.js +55 -0
- package/dist/core/group/config-parser.d.ts +3 -0
- package/dist/core/group/config-parser.js +83 -0
- package/dist/core/group/contract-extractor.d.ts +7 -0
- package/dist/core/group/contract-extractor.js +1 -0
- package/dist/core/group/extractors/grpc-extractor.d.ts +16 -0
- package/dist/core/group/extractors/grpc-extractor.js +264 -0
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +428 -0
- package/dist/core/group/extractors/topic-extractor.d.ts +9 -0
- package/dist/core/group/extractors/topic-extractor.js +234 -0
- package/dist/core/group/matching.d.ts +13 -0
- package/dist/core/group/matching.js +198 -0
- package/dist/core/group/normalization.d.ts +3 -0
- package/dist/core/group/normalization.js +115 -0
- package/dist/core/group/service-boundary-detector.d.ts +8 -0
- package/dist/core/group/service-boundary-detector.js +155 -0
- package/dist/core/group/service.d.ts +46 -0
- package/dist/core/group/service.js +160 -0
- package/dist/core/group/storage.d.ts +9 -0
- package/dist/core/group/storage.js +91 -0
- package/dist/core/group/sync.d.ts +21 -0
- package/dist/core/group/sync.js +148 -0
- package/dist/core/group/types.d.ts +130 -0
- package/dist/core/group/types.js +1 -0
- package/dist/core/ingestion/binding-accumulator.d.ts +207 -0
- package/dist/core/ingestion/binding-accumulator.js +332 -0
- package/dist/core/ingestion/call-processor.d.ts +155 -24
- package/dist/core/ingestion/call-processor.js +1129 -247
- package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/generic.js +135 -0
- package/dist/core/ingestion/class-types.d.ts +34 -0
- package/dist/core/ingestion/class-types.js +1 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
- package/dist/core/ingestion/entry-point-scoring.js +1 -0
- package/dist/core/ingestion/field-types.d.ts +2 -2
- package/dist/core/ingestion/filesystem-walker.js +8 -0
- package/dist/core/ingestion/framework-detection.d.ts +1 -0
- package/dist/core/ingestion/framework-detection.js +1 -0
- package/dist/core/ingestion/heritage-processor.d.ts +8 -15
- package/dist/core/ingestion/heritage-processor.js +15 -28
- package/dist/core/ingestion/import-processor.d.ts +1 -11
- package/dist/core/ingestion/import-processor.js +0 -12
- package/dist/core/ingestion/import-resolvers/utils.js +1 -0
- package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/vue.js +9 -0
- package/dist/core/ingestion/language-provider.d.ts +6 -3
- package/dist/core/ingestion/languages/c-cpp.js +168 -1
- package/dist/core/ingestion/languages/csharp.js +20 -0
- package/dist/core/ingestion/languages/dart.js +26 -4
- package/dist/core/ingestion/languages/go.js +22 -0
- package/dist/core/ingestion/languages/index.d.ts +1 -0
- package/dist/core/ingestion/languages/index.js +2 -0
- package/dist/core/ingestion/languages/java.js +17 -0
- package/dist/core/ingestion/languages/kotlin.js +24 -1
- package/dist/core/ingestion/languages/php.js +23 -11
- package/dist/core/ingestion/languages/python.js +9 -0
- package/dist/core/ingestion/languages/ruby.js +28 -0
- package/dist/core/ingestion/languages/rust.js +38 -0
- package/dist/core/ingestion/languages/swift.js +31 -0
- package/dist/core/ingestion/languages/typescript.d.ts +1 -0
- package/dist/core/ingestion/languages/typescript.js +52 -3
- package/dist/core/ingestion/languages/vue.d.ts +13 -0
- package/dist/core/ingestion/languages/vue.js +81 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
- package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
- package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +13 -4
- package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
- package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.js +285 -0
- package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
- package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
- package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +85 -8
- package/dist/core/ingestion/method-extractors/generic.js +38 -15
- package/dist/core/ingestion/method-types.d.ts +25 -0
- package/dist/core/ingestion/model/field-registry.d.ts +18 -0
- package/dist/core/ingestion/model/field-registry.js +22 -0
- package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
- package/dist/core/ingestion/model/heritage-map.js +159 -0
- package/dist/core/ingestion/model/index.d.ts +20 -0
- package/dist/core/ingestion/model/index.js +41 -0
- package/dist/core/ingestion/model/method-registry.d.ts +62 -0
- package/dist/core/ingestion/model/method-registry.js +130 -0
- package/dist/core/ingestion/model/registration-table.d.ts +139 -0
- package/dist/core/ingestion/model/registration-table.js +224 -0
- package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
- package/dist/core/ingestion/model/resolution-context.js +337 -0
- package/dist/core/ingestion/model/resolve.d.ts +56 -0
- package/dist/core/ingestion/model/resolve.js +242 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
- package/dist/core/ingestion/model/semantic-model.js +120 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
- package/dist/core/ingestion/model/symbol-table.js +206 -0
- package/dist/core/ingestion/model/type-registry.d.ts +39 -0
- package/dist/core/ingestion/model/type-registry.js +62 -0
- package/dist/core/ingestion/mro-processor.d.ts +4 -3
- package/dist/core/ingestion/mro-processor.js +310 -106
- package/dist/core/ingestion/parsing-processor.d.ts +5 -4
- package/dist/core/ingestion/parsing-processor.js +210 -85
- package/dist/core/ingestion/pipeline.d.ts +2 -0
- package/dist/core/ingestion/pipeline.js +192 -68
- package/dist/core/ingestion/tree-sitter-queries.d.ts +5 -5
- package/dist/core/ingestion/tree-sitter-queries.js +21 -0
- package/dist/core/ingestion/type-env.d.ts +15 -2
- package/dist/core/ingestion/type-env.js +163 -102
- package/dist/core/ingestion/type-extractors/csharp.js +17 -0
- package/dist/core/ingestion/type-extractors/jvm.js +11 -0
- package/dist/core/ingestion/type-extractors/php.js +0 -55
- package/dist/core/ingestion/type-extractors/ruby.js +0 -32
- package/dist/core/ingestion/type-extractors/swift.js +13 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
- package/dist/core/ingestion/type-extractors/typescript.js +66 -69
- package/dist/core/ingestion/utils/ast-helpers.d.ts +33 -43
- package/dist/core/ingestion/utils/ast-helpers.js +129 -572
- package/dist/core/ingestion/utils/method-props.d.ts +32 -0
- package/dist/core/ingestion/utils/method-props.js +147 -0
- package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
- package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
- package/dist/core/ingestion/workers/parse-worker.js +463 -198
- package/dist/core/lbug/lbug-adapter.d.ts +6 -0
- package/dist/core/lbug/lbug-adapter.js +68 -3
- package/dist/core/lbug/pool-adapter.d.ts +76 -0
- package/dist/core/lbug/pool-adapter.js +522 -0
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +1 -1
- package/dist/core/search/bm25-index.js +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -0
- package/dist/core/wiki/graph-queries.js +1 -1
- package/dist/mcp/core/embedder.js +6 -5
- package/dist/mcp/core/lbug-adapter.d.ts +3 -63
- package/dist/mcp/core/lbug-adapter.js +3 -484
- package/dist/mcp/local/local-backend.d.ts +31 -2
- package/dist/mcp/local/local-backend.js +255 -46
- package/dist/mcp/resources.js +5 -4
- package/dist/mcp/staleness.d.ts +3 -13
- package/dist/mcp/staleness.js +2 -31
- package/dist/mcp/tools.js +80 -4
- package/dist/server/analyze-job.d.ts +2 -0
- package/dist/server/analyze-job.js +4 -0
- package/dist/server/api.d.ts +20 -1
- package/dist/server/api.js +306 -71
- package/dist/server/git-clone.d.ts +2 -1
- package/dist/server/git-clone.js +98 -5
- package/dist/storage/git.d.ts +13 -0
- package/dist/storage/git.js +25 -0
- package/dist/storage/repo-manager.js +1 -1
- package/package.json +8 -2
- package/scripts/patch-tree-sitter-swift.cjs +78 -0
- package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
- package/dist/core/ingestion/named-binding-processor.js +0 -42
- package/dist/core/ingestion/resolution-context.d.ts +0 -58
- package/dist/core/ingestion/resolution-context.js +0 -135
- package/dist/core/ingestion/symbol-table.d.ts +0 -79
- package/dist/core/ingestion/symbol-table.js +0 -115
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// gitnexus/src/core/ingestion/method-extractors/configs/swift.ts
|
|
2
|
+
// Verified against tree-sitter-swift 0.6.0
|
|
3
|
+
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
4
|
+
import { findVisibility, hasKeyword, hasModifier } from '../../field-extractors/configs/helpers.js';
|
|
5
|
+
import { extractSimpleTypeName } from '../../type-extractors/shared.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Swift helpers
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const SWIFT_VIS = new Set([
|
|
10
|
+
'public',
|
|
11
|
+
'private',
|
|
12
|
+
'fileprivate',
|
|
13
|
+
'internal',
|
|
14
|
+
'open',
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* Extract the method name from a function_declaration or protocol_function_declaration.
|
|
18
|
+
*
|
|
19
|
+
* In tree-sitter-swift, the name is stored in a `simple_identifier` child
|
|
20
|
+
* (not a 'name' field) on both function_declaration and protocol_function_declaration.
|
|
21
|
+
*/
|
|
22
|
+
function extractSwiftName(node) {
|
|
23
|
+
// Try field-based name first
|
|
24
|
+
const nameField = node.childForFieldName('name');
|
|
25
|
+
if (nameField)
|
|
26
|
+
return nameField.text;
|
|
27
|
+
// Walk named children for simple_identifier (the function name)
|
|
28
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
29
|
+
const child = node.namedChild(i);
|
|
30
|
+
if (child?.type === 'simple_identifier')
|
|
31
|
+
return child.text;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Extract the return type from a Swift function declaration.
|
|
37
|
+
*
|
|
38
|
+
* In tree-sitter-swift, the return type appears in a `type_annotation` child
|
|
39
|
+
* that follows the parameter list (after `->` in source). It may also appear
|
|
40
|
+
* as a direct type child (user_type, optional_type, tuple_type, array_type).
|
|
41
|
+
*/
|
|
42
|
+
function extractSwiftReturnType(node) {
|
|
43
|
+
// Look for the return type — typically the last type_annotation or a type node
|
|
44
|
+
// that appears after the parameter list.
|
|
45
|
+
// tree-sitter-swift places the return type inside a type child after '->'
|
|
46
|
+
let seenParams = false;
|
|
47
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
48
|
+
const child = node.namedChild(i);
|
|
49
|
+
if (!child)
|
|
50
|
+
continue;
|
|
51
|
+
if (child.type === 'parameter') {
|
|
52
|
+
seenParams = true;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// The parameter list may be unnamed children; track when we pass ')'
|
|
56
|
+
if (seenParams || child.type === 'type_annotation') {
|
|
57
|
+
if (child.type === 'type_annotation') {
|
|
58
|
+
const inner = child.firstNamedChild;
|
|
59
|
+
if (inner)
|
|
60
|
+
return inner.text?.trim();
|
|
61
|
+
}
|
|
62
|
+
if (child.type === 'user_type' ||
|
|
63
|
+
child.type === 'optional_type' ||
|
|
64
|
+
child.type === 'tuple_type' ||
|
|
65
|
+
child.type === 'array_type' ||
|
|
66
|
+
child.type === 'dictionary_type' ||
|
|
67
|
+
child.type === 'function_type') {
|
|
68
|
+
return child.text?.trim();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Fallback: scan all children (named + unnamed) for '->' then grab the next named child
|
|
73
|
+
let seenArrow = false;
|
|
74
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
75
|
+
const child = node.child(i);
|
|
76
|
+
if (!child)
|
|
77
|
+
continue;
|
|
78
|
+
if (!child.isNamed && child.text.trim() === '->') {
|
|
79
|
+
seenArrow = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (seenArrow && child.isNamed) {
|
|
83
|
+
return child.text?.trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Extract parameters from a Swift function declaration.
|
|
90
|
+
*
|
|
91
|
+
* In tree-sitter-swift, parameters are `parameter` named children directly on
|
|
92
|
+
* the function_declaration node. Each parameter has:
|
|
93
|
+
* - An external name (label) and/or internal name as simple_identifier children
|
|
94
|
+
* - A type_annotation child containing the type
|
|
95
|
+
* - An optional default value after '='
|
|
96
|
+
* - A possible `...` for variadic parameters
|
|
97
|
+
*/
|
|
98
|
+
function extractSwiftParameters(node) {
|
|
99
|
+
const params = [];
|
|
100
|
+
// In tree-sitter-swift 0.6.0, parameters are direct children of function_declaration.
|
|
101
|
+
// Default value tokens ('=', literal) are siblings of the parameter node at the
|
|
102
|
+
// function_declaration level, not children of the parameter node.
|
|
103
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
104
|
+
const child = node.child(i);
|
|
105
|
+
if (!child?.isNamed || child.type !== 'parameter')
|
|
106
|
+
continue;
|
|
107
|
+
// Extract parameter name — the last simple_identifier is the internal name
|
|
108
|
+
let paramName;
|
|
109
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
110
|
+
const part = child.namedChild(j);
|
|
111
|
+
if (part?.type === 'simple_identifier') {
|
|
112
|
+
paramName = part.text;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!paramName)
|
|
116
|
+
continue;
|
|
117
|
+
// Extract type — tree-sitter-swift uses user_type (not type_annotation)
|
|
118
|
+
let typeName = null;
|
|
119
|
+
let rawTypeName = null;
|
|
120
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
121
|
+
const part = child.namedChild(j);
|
|
122
|
+
if (part?.type === 'user_type' || part?.type === 'type_annotation') {
|
|
123
|
+
rawTypeName = part.text?.trim() ?? null;
|
|
124
|
+
const inner = part.firstNamedChild;
|
|
125
|
+
if (inner) {
|
|
126
|
+
typeName = extractSimpleTypeName(inner) ?? inner.text?.trim() ?? null;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
typeName = rawTypeName;
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
// Handle built-in types (array_type, dictionary_type, optional_type, tuple_type)
|
|
134
|
+
if (part?.type.endsWith('_type') && part.type !== 'simple_identifier') {
|
|
135
|
+
rawTypeName = part.text?.trim() ?? null;
|
|
136
|
+
typeName = extractSimpleTypeName(part) ?? rawTypeName;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Check for default value: '=' token appears as a sibling after the parameter node
|
|
141
|
+
let isOptional = false;
|
|
142
|
+
const nextSibling = node.child(i + 1);
|
|
143
|
+
if (nextSibling && !nextSibling.isNamed && nextSibling.text.trim() === '=') {
|
|
144
|
+
isOptional = true;
|
|
145
|
+
}
|
|
146
|
+
// Check for variadic: '...' token among parameter children
|
|
147
|
+
let isVariadic = false;
|
|
148
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
149
|
+
const c = child.child(j);
|
|
150
|
+
if (c && c.text.trim() === '...') {
|
|
151
|
+
isVariadic = true;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
params.push({
|
|
156
|
+
name: paramName,
|
|
157
|
+
type: typeName,
|
|
158
|
+
rawType: rawTypeName,
|
|
159
|
+
isOptional,
|
|
160
|
+
isVariadic,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return params;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Check if a method is inside a protocol.
|
|
167
|
+
*
|
|
168
|
+
* A protocol_function_declaration is always abstract. For function_declaration
|
|
169
|
+
* inside a protocol_body (if it appears there), it's also abstract when it has
|
|
170
|
+
* no body.
|
|
171
|
+
*/
|
|
172
|
+
function isSwiftAbstract(node, ownerNode) {
|
|
173
|
+
// protocol_function_declaration nodes are inherently abstract
|
|
174
|
+
if (node.type === 'protocol_function_declaration')
|
|
175
|
+
return true;
|
|
176
|
+
// function_declaration inside a protocol is abstract if it has no body
|
|
177
|
+
if (ownerNode.type === 'protocol_declaration') {
|
|
178
|
+
const body = node.childForFieldName('body');
|
|
179
|
+
if (!body) {
|
|
180
|
+
// Also check for function_body named child
|
|
181
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
182
|
+
const child = node.namedChild(i);
|
|
183
|
+
if (child?.type === 'function_body')
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Collect attribute nodes from a Swift function declaration.
|
|
194
|
+
*
|
|
195
|
+
* In tree-sitter-swift, attributes appear as `attribute` named children
|
|
196
|
+
* directly on the function_declaration node, or inside a `modifiers` wrapper.
|
|
197
|
+
* Each attribute node text starts with '@'.
|
|
198
|
+
*/
|
|
199
|
+
function extractSwiftAnnotations(node) {
|
|
200
|
+
const annotations = [];
|
|
201
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
202
|
+
const child = node.namedChild(i);
|
|
203
|
+
if (!child)
|
|
204
|
+
continue;
|
|
205
|
+
if (child.type === 'attribute') {
|
|
206
|
+
const text = child.text?.trim();
|
|
207
|
+
if (text) {
|
|
208
|
+
// Normalize: strip arguments, keep just the name
|
|
209
|
+
// e.g. "@objc(myMethod)" -> "@objc", "@available(iOS 13, *)" -> "@available"
|
|
210
|
+
const match = text.match(/^@(\w+)/);
|
|
211
|
+
if (match) {
|
|
212
|
+
annotations.push('@' + match[1]);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
annotations.push(text);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Also check inside modifiers wrapper
|
|
220
|
+
if (child.type === 'modifiers') {
|
|
221
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
222
|
+
const mod = child.namedChild(j);
|
|
223
|
+
if (mod?.type === 'attribute') {
|
|
224
|
+
const text = mod.text?.trim();
|
|
225
|
+
if (text) {
|
|
226
|
+
const match = text.match(/^@(\w+)/);
|
|
227
|
+
if (match) {
|
|
228
|
+
annotations.push('@' + match[1]);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
annotations.push(text);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return annotations;
|
|
239
|
+
}
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Swift config
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
export const swiftMethodConfig = {
|
|
244
|
+
language: SupportedLanguages.Swift,
|
|
245
|
+
// tree-sitter-swift 0.6.0 may use class_declaration for classes, structs, enums, extensions,
|
|
246
|
+
// and actors — but this cannot be verified until the grammar installs on Node 22+.
|
|
247
|
+
// TODO: Verify struct_declaration, enum_declaration, extension_declaration, actor_declaration
|
|
248
|
+
// node types once tree-sitter-swift loads on Node 22, and add them here if they are distinct.
|
|
249
|
+
// protocol_declaration is a separate, confirmed node type.
|
|
250
|
+
typeDeclarationNodes: ['class_declaration', 'protocol_declaration'],
|
|
251
|
+
// function_declaration for class/struct methods, protocol_function_declaration for protocol methods
|
|
252
|
+
methodNodeTypes: ['function_declaration', 'protocol_function_declaration'],
|
|
253
|
+
bodyNodeTypes: ['class_body', 'protocol_body'],
|
|
254
|
+
extractName: extractSwiftName,
|
|
255
|
+
extractReturnType: extractSwiftReturnType,
|
|
256
|
+
extractParameters: extractSwiftParameters,
|
|
257
|
+
extractVisibility(node) {
|
|
258
|
+
return findVisibility(node, SWIFT_VIS, 'internal', 'modifiers');
|
|
259
|
+
},
|
|
260
|
+
isStatic(node) {
|
|
261
|
+
return (hasKeyword(node, 'static') ||
|
|
262
|
+
hasKeyword(node, 'class') ||
|
|
263
|
+
hasModifier(node, 'modifiers', 'static') ||
|
|
264
|
+
hasModifier(node, 'modifiers', 'class'));
|
|
265
|
+
},
|
|
266
|
+
isAbstract: isSwiftAbstract,
|
|
267
|
+
isFinal(node) {
|
|
268
|
+
return hasKeyword(node, 'final') || hasModifier(node, 'modifiers', 'final');
|
|
269
|
+
},
|
|
270
|
+
isAsync(node) {
|
|
271
|
+
return hasKeyword(node, 'async') || hasModifier(node, 'modifiers', 'async');
|
|
272
|
+
},
|
|
273
|
+
isOverride(node) {
|
|
274
|
+
return hasKeyword(node, 'override') || hasModifier(node, 'modifiers', 'override');
|
|
275
|
+
},
|
|
276
|
+
extractAnnotations: extractSwiftAnnotations,
|
|
277
|
+
};
|
|
@@ -46,6 +46,7 @@ function extractTsJsParameters(node) {
|
|
|
46
46
|
type: typeNode
|
|
47
47
|
? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
|
|
48
48
|
: null,
|
|
49
|
+
rawType: typeNode?.text?.trim() ?? null,
|
|
49
50
|
isOptional: hasDefault,
|
|
50
51
|
isVariadic: isRest,
|
|
51
52
|
});
|
|
@@ -62,6 +63,7 @@ function extractTsJsParameters(node) {
|
|
|
62
63
|
type: typeNode
|
|
63
64
|
? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
|
|
64
65
|
: null,
|
|
66
|
+
rawType: typeNode?.text?.trim() ?? null,
|
|
65
67
|
isOptional: true,
|
|
66
68
|
isVariadic: false,
|
|
67
69
|
});
|
|
@@ -78,6 +80,7 @@ function extractTsJsParameters(node) {
|
|
|
78
80
|
type: typeNode
|
|
79
81
|
? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
|
|
80
82
|
: null,
|
|
83
|
+
rawType: typeNode?.text?.trim() ?? null,
|
|
81
84
|
isOptional: false,
|
|
82
85
|
isVariadic: true,
|
|
83
86
|
});
|
|
@@ -85,14 +88,26 @@ function extractTsJsParameters(node) {
|
|
|
85
88
|
}
|
|
86
89
|
case 'identifier': {
|
|
87
90
|
// JS: bare parameter name, no type info
|
|
88
|
-
params.push({
|
|
91
|
+
params.push({
|
|
92
|
+
name: param.text,
|
|
93
|
+
type: null,
|
|
94
|
+
rawType: null,
|
|
95
|
+
isOptional: false,
|
|
96
|
+
isVariadic: false,
|
|
97
|
+
});
|
|
89
98
|
break;
|
|
90
99
|
}
|
|
91
100
|
case 'assignment_pattern': {
|
|
92
101
|
// JS: param = defaultValue — the left side is the name, isOptional = true
|
|
93
102
|
const left = param.childForFieldName('left');
|
|
94
103
|
if (left) {
|
|
95
|
-
params.push({
|
|
104
|
+
params.push({
|
|
105
|
+
name: left.text,
|
|
106
|
+
type: null,
|
|
107
|
+
rawType: null,
|
|
108
|
+
isOptional: true,
|
|
109
|
+
isVariadic: false,
|
|
110
|
+
});
|
|
96
111
|
}
|
|
97
112
|
break;
|
|
98
113
|
}
|
|
@@ -100,22 +115,76 @@ function extractTsJsParameters(node) {
|
|
|
100
115
|
// JS: ...args
|
|
101
116
|
const inner = param.firstNamedChild;
|
|
102
117
|
if (inner) {
|
|
103
|
-
params.push({
|
|
118
|
+
params.push({
|
|
119
|
+
name: inner.text,
|
|
120
|
+
type: null,
|
|
121
|
+
rawType: null,
|
|
122
|
+
isOptional: false,
|
|
123
|
+
isVariadic: true,
|
|
124
|
+
});
|
|
104
125
|
}
|
|
105
126
|
break;
|
|
106
127
|
}
|
|
107
128
|
case 'object_pattern':
|
|
108
129
|
case 'array_pattern': {
|
|
109
130
|
// Destructured parameter — use full text as name
|
|
110
|
-
params.push({
|
|
131
|
+
params.push({
|
|
132
|
+
name: param.text,
|
|
133
|
+
type: null,
|
|
134
|
+
rawType: null,
|
|
135
|
+
isOptional: false,
|
|
136
|
+
isVariadic: false,
|
|
137
|
+
});
|
|
111
138
|
break;
|
|
112
139
|
}
|
|
113
140
|
}
|
|
114
141
|
}
|
|
115
142
|
return params;
|
|
116
143
|
}
|
|
144
|
+
/** Regex to extract @returns or @return from JSDoc comments: `@returns {Type}` */
|
|
145
|
+
const JSDOC_RETURN_RE = /@returns?\s*\{([^}]+)\}/;
|
|
146
|
+
/**
|
|
147
|
+
* Minimal sanitization for JSDoc return types — preserves generic wrappers
|
|
148
|
+
* (e.g. `Promise<User>`) so that extractReturnTypeName in call-processor
|
|
149
|
+
* can apply WRAPPER_GENERICS unwrapping. Only strips JSDoc-specific syntax markers.
|
|
150
|
+
*/
|
|
151
|
+
function sanitizeJsDocReturnType(raw) {
|
|
152
|
+
let type = raw.trim();
|
|
153
|
+
// Strip JSDoc nullable/non-nullable prefixes: ?User → User, !User → User
|
|
154
|
+
if (type.startsWith('?') || type.startsWith('!'))
|
|
155
|
+
type = type.slice(1);
|
|
156
|
+
// Strip module: prefix — module:models.User → models.User
|
|
157
|
+
if (type.startsWith('module:'))
|
|
158
|
+
type = type.slice(7);
|
|
159
|
+
// Reject unions (ambiguous)
|
|
160
|
+
if (type.includes('|'))
|
|
161
|
+
return undefined;
|
|
162
|
+
if (!type)
|
|
163
|
+
return undefined;
|
|
164
|
+
return type;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Walk backwards through preceding siblings looking for a JSDoc comment containing
|
|
168
|
+
* `@returns {Type}` or `@return {Type}`. Stops at the first non-comment named node
|
|
169
|
+
* (excluding decorators, which precede methods in TS/JS).
|
|
170
|
+
*/
|
|
171
|
+
function extractJsDocReturnType(node) {
|
|
172
|
+
let sibling = node.previousSibling;
|
|
173
|
+
while (sibling) {
|
|
174
|
+
if (sibling.type === 'comment') {
|
|
175
|
+
const match = JSDOC_RETURN_RE.exec(sibling.text);
|
|
176
|
+
if (match)
|
|
177
|
+
return sanitizeJsDocReturnType(match[1]);
|
|
178
|
+
}
|
|
179
|
+
else if (sibling.isNamed && sibling.type !== 'decorator')
|
|
180
|
+
break;
|
|
181
|
+
sibling = sibling.previousSibling;
|
|
182
|
+
}
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
117
185
|
/**
|
|
118
186
|
* Extract return type from return_type field, unwrapping type_annotation.
|
|
187
|
+
* Falls back to JSDoc `@returns {Type}` when the AST has no return type annotation.
|
|
119
188
|
*
|
|
120
189
|
* tree-sitter-typescript uses `return_type` as the field name (not `type` like JVM).
|
|
121
190
|
* The return_type field points to a type_annotation node that must be unwrapped.
|
|
@@ -126,11 +195,12 @@ function extractTsJsReturnType(node) {
|
|
|
126
195
|
if (returnType.type === 'type_annotation') {
|
|
127
196
|
const inner = returnType.firstNamedChild;
|
|
128
197
|
if (inner)
|
|
129
|
-
return
|
|
198
|
+
return inner.text?.trim();
|
|
130
199
|
}
|
|
131
|
-
return
|
|
200
|
+
return returnType.text?.trim();
|
|
132
201
|
}
|
|
133
|
-
return
|
|
202
|
+
// AST has no return type annotation — try JSDoc fallback
|
|
203
|
+
return extractJsDocReturnType(node);
|
|
134
204
|
}
|
|
135
205
|
/**
|
|
136
206
|
* Extract visibility from accessibility_modifier or #private name.
|
|
@@ -218,7 +288,14 @@ const shared = {
|
|
|
218
288
|
// are not discovered because class_expression is not in typeDeclarationNodes.
|
|
219
289
|
// - declare module / declare global augmentations — methods inside ambient_module_declaration
|
|
220
290
|
// wrappers are not surfaced because the top-level walker doesn't descend into them.
|
|
221
|
-
methodNodeTypes: [
|
|
291
|
+
methodNodeTypes: [
|
|
292
|
+
'method_definition',
|
|
293
|
+
'method_signature',
|
|
294
|
+
'abstract_method_signature',
|
|
295
|
+
'function_declaration',
|
|
296
|
+
'generator_function_declaration',
|
|
297
|
+
'function_signature',
|
|
298
|
+
],
|
|
222
299
|
bodyNodeTypes: ['class_body', 'interface_body'],
|
|
223
300
|
extractName(node) {
|
|
224
301
|
const nameNode = node.childForFieldName('name');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// gitnexus/src/core/ingestion/method-extractors/generic.ts
|
|
2
|
-
/** Owner node types where member functions are effectively static (JVM semantics). */
|
|
3
|
-
const STATIC_OWNER_TYPES = new Set(['companion_object', 'object_declaration']);
|
|
2
|
+
/** Owner node types where member functions are effectively static (JVM/Ruby semantics). */
|
|
3
|
+
const STATIC_OWNER_TYPES = new Set(['companion_object', 'object_declaration', 'singleton_class']);
|
|
4
4
|
/**
|
|
5
5
|
* Create a MethodExtractor from a declarative config.
|
|
6
6
|
*/
|
|
@@ -16,18 +16,26 @@ export function createMethodExtractor(config) {
|
|
|
16
16
|
extract(node, context) {
|
|
17
17
|
if (!typeDeclarationSet.has(node.type))
|
|
18
18
|
return null;
|
|
19
|
-
// Resolve owner name: field-based → type_identifier → simple_identifier → "Companion"
|
|
19
|
+
// Resolve owner name: config hook → field-based → type_identifier → simple_identifier → "Companion"
|
|
20
20
|
let ownerName;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
ownerName = nameField.text;
|
|
21
|
+
if (config.extractOwnerName) {
|
|
22
|
+
ownerName = config.extractOwnerName(node);
|
|
24
23
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
if (!ownerName) {
|
|
25
|
+
const nameField = node.childForFieldName('name');
|
|
26
|
+
if (nameField) {
|
|
27
|
+
ownerName = nameField.text;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
31
|
+
const child = node.namedChild(i);
|
|
32
|
+
if (child &&
|
|
33
|
+
(child.type === 'type_identifier' ||
|
|
34
|
+
child.type === 'simple_identifier' ||
|
|
35
|
+
child.type === 'identifier')) {
|
|
36
|
+
ownerName = child.text;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
}
|
|
33
41
|
}
|
|
@@ -50,6 +58,12 @@ export function createMethodExtractor(config) {
|
|
|
50
58
|
}
|
|
51
59
|
return { ownerName, methods };
|
|
52
60
|
},
|
|
61
|
+
extractFromNode(node, context) {
|
|
62
|
+
if (!methodNodeSet.has(node.type))
|
|
63
|
+
return null;
|
|
64
|
+
return buildMethod(node, node, context, config);
|
|
65
|
+
},
|
|
66
|
+
...(config.extractFunctionName ? { extractFunctionName: config.extractFunctionName } : {}),
|
|
53
67
|
};
|
|
54
68
|
}
|
|
55
69
|
function findBodies(node, bodyNodeSet) {
|
|
@@ -77,19 +91,27 @@ function findBodies(node, bodyNodeSet) {
|
|
|
77
91
|
}
|
|
78
92
|
return result;
|
|
79
93
|
}
|
|
80
|
-
function addNestedBodies(parent, bodyNodeSet, out) {
|
|
94
|
+
function addNestedBodies(parent, bodyNodeSet, out, seen) {
|
|
95
|
+
const visited = seen ?? new Set(out);
|
|
81
96
|
for (let i = 0; i < parent.namedChildCount; i++) {
|
|
82
97
|
const child = parent.namedChild(i);
|
|
83
|
-
if (child && bodyNodeSet.has(child.type) && !
|
|
98
|
+
if (child && bodyNodeSet.has(child.type) && !visited.has(child)) {
|
|
99
|
+
visited.add(child);
|
|
84
100
|
out.push(child);
|
|
85
101
|
}
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
104
|
function extractMethodsFromBody(body, ownerNode, context, config, methodNodeSet, out) {
|
|
89
105
|
for (let i = 0; i < body.namedChildCount; i++) {
|
|
90
|
-
|
|
106
|
+
let child = body.namedChild(i);
|
|
91
107
|
if (!child)
|
|
92
108
|
continue;
|
|
109
|
+
// C++ template methods are wrapped in template_declaration — unwrap to the inner node
|
|
110
|
+
if (child.type === 'template_declaration') {
|
|
111
|
+
const inner = child.namedChildren.find((c) => methodNodeSet.has(c.type));
|
|
112
|
+
if (inner)
|
|
113
|
+
child = inner;
|
|
114
|
+
}
|
|
93
115
|
if (methodNodeSet.has(child.type)) {
|
|
94
116
|
const method = buildMethod(child, ownerNode, context, config);
|
|
95
117
|
if (method)
|
|
@@ -130,6 +152,7 @@ function buildMethod(node, ownerNode, context, config) {
|
|
|
130
152
|
...(config.isOverride?.(node) ? { isOverride: true } : {}),
|
|
131
153
|
...(config.isAsync?.(node) ? { isAsync: true } : {}),
|
|
132
154
|
...(config.isPartial?.(node) ? { isPartial: true } : {}),
|
|
155
|
+
...(config.isConst?.(node) ? { isConst: true } : {}),
|
|
133
156
|
annotations: config.extractAnnotations?.(node) ?? [],
|
|
134
157
|
sourceFile: context.filePath,
|
|
135
158
|
line: node.startPosition.row + 1,
|
|
@@ -5,6 +5,10 @@ export type MethodVisibility = FieldVisibility;
|
|
|
5
5
|
export interface ParameterInfo {
|
|
6
6
|
name: string;
|
|
7
7
|
type: string | null;
|
|
8
|
+
/** Full type text including generic/template args (e.g. 'vector<int>', 'List<String>').
|
|
9
|
+
* Used by typeTagForId for overload disambiguation where generic args matter.
|
|
10
|
+
* Falls back to `type` when not set. */
|
|
11
|
+
rawType?: string | null;
|
|
8
12
|
isOptional: boolean;
|
|
9
13
|
isVariadic: boolean;
|
|
10
14
|
}
|
|
@@ -21,6 +25,7 @@ export interface MethodInfo {
|
|
|
21
25
|
isOverride?: boolean;
|
|
22
26
|
isAsync?: boolean;
|
|
23
27
|
isPartial?: boolean;
|
|
28
|
+
isConst?: boolean;
|
|
24
29
|
annotations: string[];
|
|
25
30
|
sourceFile: string;
|
|
26
31
|
line: number;
|
|
@@ -37,6 +42,17 @@ export interface MethodExtractor {
|
|
|
37
42
|
language: SupportedLanguages;
|
|
38
43
|
extract(node: SyntaxNode, context: MethodExtractorContext): ExtractedMethods | null;
|
|
39
44
|
isTypeDeclaration(node: SyntaxNode): boolean;
|
|
45
|
+
/** Extract method info from a standalone method node (e.g. Go top-level method_declaration). */
|
|
46
|
+
extractFromNode?(node: SyntaxNode, context: MethodExtractorContext): MethodInfo | null;
|
|
47
|
+
/** Extract function name + label from an AST node during parent-walk.
|
|
48
|
+
* Languages with non-standard AST structures (e.g. C/C++ declarator
|
|
49
|
+
* unwrapping, Swift init/deinit, Rust impl_item) provide this hook
|
|
50
|
+
* to replace the generic name-field lookup.
|
|
51
|
+
* Return null to fall through to the generic extractor. */
|
|
52
|
+
extractFunctionName?(node: SyntaxNode): {
|
|
53
|
+
funcName: string | null;
|
|
54
|
+
label: import('../../_shared/index.js').NodeLabel;
|
|
55
|
+
} | null;
|
|
40
56
|
}
|
|
41
57
|
export interface MethodExtractionConfig {
|
|
42
58
|
language: SupportedLanguages;
|
|
@@ -56,6 +72,15 @@ export interface MethodExtractionConfig {
|
|
|
56
72
|
isOverride?: (node: SyntaxNode) => boolean;
|
|
57
73
|
isAsync?: (node: SyntaxNode) => boolean;
|
|
58
74
|
isPartial?: (node: SyntaxNode) => boolean;
|
|
75
|
+
isConst?: (node: SyntaxNode) => boolean;
|
|
76
|
+
/** Resolve the owner name from a standalone method node (e.g. Go receiver type). */
|
|
77
|
+
extractOwnerName?: (node: SyntaxNode) => string | undefined;
|
|
59
78
|
/** Extract a primary constructor from the owner node itself (e.g. C# 12 class Point(int x, int y)). */
|
|
60
79
|
extractPrimaryConstructor?: (ownerNode: SyntaxNode, context: MethodExtractorContext) => MethodInfo | null;
|
|
80
|
+
/** Extract function name + label from an AST node during parent-walk.
|
|
81
|
+
* Passed through to the MethodExtractor by createMethodExtractor. */
|
|
82
|
+
extractFunctionName?: (node: SyntaxNode) => {
|
|
83
|
+
funcName: string | null;
|
|
84
|
+
label: import('../../_shared/index.js').NodeLabel;
|
|
85
|
+
} | null;
|
|
61
86
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field Registry
|
|
3
|
+
*
|
|
4
|
+
* Owner-scoped field/property index extracted from SymbolTable.
|
|
5
|
+
* Stores Property symbols keyed by `ownerNodeId\0fieldName` for O(1) lookup.
|
|
6
|
+
*/
|
|
7
|
+
import type { SymbolDefinition } from './symbol-table.js';
|
|
8
|
+
export interface FieldRegistry {
|
|
9
|
+
/** Look up a field/property by its owning class nodeId and field name. */
|
|
10
|
+
lookupFieldByOwner(ownerNodeId: string, fieldName: string): SymbolDefinition | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface MutableFieldRegistry extends FieldRegistry {
|
|
13
|
+
/** Register a field/property under its owner. */
|
|
14
|
+
register(ownerNodeId: string, fieldName: string, def: SymbolDefinition): void;
|
|
15
|
+
/** Clear all entries. */
|
|
16
|
+
clear(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare const createFieldRegistry: () => MutableFieldRegistry;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field Registry
|
|
3
|
+
*
|
|
4
|
+
* Owner-scoped field/property index extracted from SymbolTable.
|
|
5
|
+
* Stores Property symbols keyed by `ownerNodeId\0fieldName` for O(1) lookup.
|
|
6
|
+
*/
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Factory
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
export const createFieldRegistry = () => {
|
|
11
|
+
const fieldByOwner = new Map();
|
|
12
|
+
const lookupFieldByOwner = (ownerNodeId, fieldName) => {
|
|
13
|
+
return fieldByOwner.get(`${ownerNodeId}\0${fieldName}`);
|
|
14
|
+
};
|
|
15
|
+
const register = (ownerNodeId, fieldName, def) => {
|
|
16
|
+
fieldByOwner.set(`${ownerNodeId}\0${fieldName}`, def);
|
|
17
|
+
};
|
|
18
|
+
const clear = () => {
|
|
19
|
+
fieldByOwner.clear();
|
|
20
|
+
};
|
|
21
|
+
return { lookupFieldByOwner, register, clear };
|
|
22
|
+
};
|