@duytransipher/gitnexus 1.4.6-sipher.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/LICENSE +73 -0
- package/README.md +261 -0
- package/dist/cli/ai-context.d.ts +23 -0
- package/dist/cli/ai-context.js +265 -0
- package/dist/cli/analyze.d.ts +12 -0
- package/dist/cli/analyze.js +345 -0
- package/dist/cli/augment.d.ts +13 -0
- package/dist/cli/augment.js +33 -0
- package/dist/cli/clean.d.ts +10 -0
- package/dist/cli/clean.js +60 -0
- package/dist/cli/eval-server.d.ts +37 -0
- package/dist/cli/eval-server.js +389 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +137 -0
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +30 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +36 -0
- package/dist/cli/serve.d.ts +4 -0
- package/dist/cli/serve.js +6 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +367 -0
- package/dist/cli/sipher-patched.d.ts +2 -0
- package/dist/cli/sipher-patched.js +77 -0
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +549 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +36 -0
- package/dist/cli/tool.d.ts +60 -0
- package/dist/cli/tool.js +180 -0
- package/dist/cli/wiki.d.ts +15 -0
- package/dist/cli/wiki.js +365 -0
- package/dist/config/ignore-service.d.ts +26 -0
- package/dist/config/ignore-service.js +284 -0
- package/dist/config/supported-languages.d.ts +15 -0
- package/dist/config/supported-languages.js +16 -0
- package/dist/core/augmentation/engine.d.ts +26 -0
- package/dist/core/augmentation/engine.js +240 -0
- package/dist/core/embeddings/embedder.d.ts +60 -0
- package/dist/core/embeddings/embedder.js +251 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
- package/dist/core/embeddings/embedding-pipeline.js +356 -0
- package/dist/core/embeddings/index.d.ts +9 -0
- package/dist/core/embeddings/index.js +9 -0
- package/dist/core/embeddings/text-generator.d.ts +24 -0
- package/dist/core/embeddings/text-generator.js +182 -0
- package/dist/core/embeddings/types.d.ts +87 -0
- package/dist/core/embeddings/types.js +32 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +66 -0
- package/dist/core/graph/types.d.ts +66 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/ingestion/ast-cache.d.ts +11 -0
- package/dist/core/ingestion/ast-cache.js +35 -0
- package/dist/core/ingestion/call-processor.d.ts +23 -0
- package/dist/core/ingestion/call-processor.js +793 -0
- package/dist/core/ingestion/call-routing.d.ts +68 -0
- package/dist/core/ingestion/call-routing.js +129 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +170 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +312 -0
- package/dist/core/ingestion/constants.d.ts +16 -0
- package/dist/core/ingestion/constants.js +16 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +40 -0
- package/dist/core/ingestion/entry-point-scoring.js +353 -0
- package/dist/core/ingestion/export-detection.d.ts +18 -0
- package/dist/core/ingestion/export-detection.js +231 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
- package/dist/core/ingestion/filesystem-walker.js +81 -0
- package/dist/core/ingestion/framework-detection.d.ts +54 -0
- package/dist/core/ingestion/framework-detection.js +411 -0
- package/dist/core/ingestion/heritage-processor.d.ts +28 -0
- package/dist/core/ingestion/heritage-processor.js +251 -0
- package/dist/core/ingestion/import-processor.d.ts +34 -0
- package/dist/core/ingestion/import-processor.js +398 -0
- package/dist/core/ingestion/language-config.d.ts +46 -0
- package/dist/core/ingestion/language-config.js +167 -0
- package/dist/core/ingestion/mro-processor.d.ts +45 -0
- package/dist/core/ingestion/mro-processor.js +369 -0
- package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
- package/dist/core/ingestion/named-binding-extraction.js +363 -0
- package/dist/core/ingestion/parsing-processor.d.ts +19 -0
- package/dist/core/ingestion/parsing-processor.js +315 -0
- package/dist/core/ingestion/pipeline.d.ts +6 -0
- package/dist/core/ingestion/pipeline.js +401 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +315 -0
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
- package/dist/core/ingestion/resolvers/csharp.js +109 -0
- package/dist/core/ingestion/resolvers/go.d.ts +19 -0
- package/dist/core/ingestion/resolvers/go.js +42 -0
- package/dist/core/ingestion/resolvers/index.d.ts +18 -0
- package/dist/core/ingestion/resolvers/index.js +13 -0
- package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
- package/dist/core/ingestion/resolvers/jvm.js +87 -0
- package/dist/core/ingestion/resolvers/php.d.ts +15 -0
- package/dist/core/ingestion/resolvers/php.js +35 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
- package/dist/core/ingestion/resolvers/rust.js +73 -0
- package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
- package/dist/core/ingestion/resolvers/standard.js +123 -0
- package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
- package/dist/core/ingestion/resolvers/utils.js +122 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/symbol-table.d.ts +63 -0
- package/dist/core/ingestion/symbol-table.js +85 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +15 -0
- package/dist/core/ingestion/tree-sitter-queries.js +888 -0
- package/dist/core/ingestion/type-env.d.ts +49 -0
- package/dist/core/ingestion/type-env.js +613 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +383 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +467 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
- package/dist/core/ingestion/type-extractors/index.js +31 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +681 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +549 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +455 -0
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +456 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +145 -0
- package/dist/core/ingestion/type-extractors/shared.js +810 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +137 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
- package/dist/core/ingestion/type-extractors/types.js +1 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +494 -0
- package/dist/core/ingestion/utils.d.ts +138 -0
- package/dist/core/ingestion/utils.js +1290 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +122 -0
- package/dist/core/ingestion/workers/parse-worker.js +1126 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
- package/dist/core/ingestion/workers/worker-pool.js +128 -0
- package/dist/core/lbug/csv-generator.d.ts +33 -0
- package/dist/core/lbug/csv-generator.js +366 -0
- package/dist/core/lbug/lbug-adapter.d.ts +103 -0
- package/dist/core/lbug/lbug-adapter.js +769 -0
- package/dist/core/lbug/schema.d.ts +53 -0
- package/dist/core/lbug/schema.js +430 -0
- package/dist/core/search/bm25-index.d.ts +23 -0
- package/dist/core/search/bm25-index.js +96 -0
- package/dist/core/search/hybrid-search.d.ts +49 -0
- package/dist/core/search/hybrid-search.js +118 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +5 -0
- package/dist/core/tree-sitter/parser-loader.js +63 -0
- package/dist/core/wiki/generator.d.ts +120 -0
- package/dist/core/wiki/generator.js +939 -0
- package/dist/core/wiki/graph-queries.d.ts +80 -0
- package/dist/core/wiki/graph-queries.js +238 -0
- package/dist/core/wiki/html-viewer.d.ts +10 -0
- package/dist/core/wiki/html-viewer.js +297 -0
- package/dist/core/wiki/llm-client.d.ts +43 -0
- package/dist/core/wiki/llm-client.js +186 -0
- package/dist/core/wiki/prompts.d.ts +53 -0
- package/dist/core/wiki/prompts.js +174 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +200 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +108 -0
- package/dist/mcp/core/lbug-adapter.d.ts +57 -0
- package/dist/mcp/core/lbug-adapter.js +455 -0
- package/dist/mcp/local/local-backend.d.ts +181 -0
- package/dist/mcp/local/local-backend.js +1722 -0
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +411 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +296 -0
- package/dist/mcp/staleness.d.ts +15 -0
- package/dist/mcp/staleness.js +29 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.js +292 -0
- package/dist/server/api.d.ts +10 -0
- package/dist/server/api.js +344 -0
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +100 -0
- package/dist/storage/git.d.ts +6 -0
- package/dist/storage/git.js +35 -0
- package/dist/storage/repo-manager.d.ts +138 -0
- package/dist/storage/repo-manager.js +299 -0
- package/dist/types/pipeline.d.ts +32 -0
- package/dist/types/pipeline.js +18 -0
- package/dist/unreal/bridge.d.ts +4 -0
- package/dist/unreal/bridge.js +113 -0
- package/dist/unreal/config.d.ts +6 -0
- package/dist/unreal/config.js +55 -0
- package/dist/unreal/types.d.ts +105 -0
- package/dist/unreal/types.js +1 -0
- package/hooks/claude/gitnexus-hook.cjs +238 -0
- package/hooks/claude/pre-tool-use.sh +79 -0
- package/hooks/claude/session-start.sh +42 -0
- package/package.json +100 -0
- package/scripts/ensure-cli-executable.cjs +21 -0
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/scripts/setup-unreal-gitnexus.ps1 +191 -0
- package/skills/gitnexus-cli.md +82 -0
- package/skills/gitnexus-debugging.md +89 -0
- package/skills/gitnexus-exploring.md +78 -0
- package/skills/gitnexus-guide.md +64 -0
- package/skills/gitnexus-impact-analysis.md +97 -0
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/gitnexus-refactoring.md +121 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { extractSimpleTypeName, extractVarName, extractElementTypeFromString, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition } from './shared.js';
|
|
2
|
+
const DECLARATION_NODE_TYPES = new Set([
|
|
3
|
+
'var_declaration',
|
|
4
|
+
'var_spec',
|
|
5
|
+
'short_var_declaration',
|
|
6
|
+
]);
|
|
7
|
+
/** Go: var x Foo */
|
|
8
|
+
const extractGoVarDeclaration = (node, env) => {
|
|
9
|
+
// Go var_declaration contains var_spec children
|
|
10
|
+
if (node.type === 'var_declaration') {
|
|
11
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
12
|
+
const spec = node.namedChild(i);
|
|
13
|
+
if (spec?.type === 'var_spec')
|
|
14
|
+
extractGoVarDeclaration(spec, env);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
// var_spec: name type [= value]
|
|
19
|
+
const nameNode = node.childForFieldName('name');
|
|
20
|
+
const typeNode = node.childForFieldName('type');
|
|
21
|
+
if (!nameNode || !typeNode)
|
|
22
|
+
return;
|
|
23
|
+
const varName = extractVarName(nameNode);
|
|
24
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
25
|
+
if (varName && typeName)
|
|
26
|
+
env.set(varName, typeName);
|
|
27
|
+
};
|
|
28
|
+
/** Go: x := Foo{...} — infer type from composite literal (handles multi-assignment) */
|
|
29
|
+
const extractGoShortVarDeclaration = (node, env) => {
|
|
30
|
+
const left = node.childForFieldName('left');
|
|
31
|
+
const right = node.childForFieldName('right');
|
|
32
|
+
if (!left || !right)
|
|
33
|
+
return;
|
|
34
|
+
// Collect LHS names and RHS values (may be expression_lists for multi-assignment)
|
|
35
|
+
const lhsNodes = [];
|
|
36
|
+
const rhsNodes = [];
|
|
37
|
+
if (left.type === 'expression_list') {
|
|
38
|
+
for (let i = 0; i < left.namedChildCount; i++) {
|
|
39
|
+
const c = left.namedChild(i);
|
|
40
|
+
if (c)
|
|
41
|
+
lhsNodes.push(c);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
lhsNodes.push(left);
|
|
46
|
+
}
|
|
47
|
+
if (right.type === 'expression_list') {
|
|
48
|
+
for (let i = 0; i < right.namedChildCount; i++) {
|
|
49
|
+
const c = right.namedChild(i);
|
|
50
|
+
if (c)
|
|
51
|
+
rhsNodes.push(c);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
rhsNodes.push(right);
|
|
56
|
+
}
|
|
57
|
+
// Pair each LHS name with its corresponding RHS value
|
|
58
|
+
const count = Math.min(lhsNodes.length, rhsNodes.length);
|
|
59
|
+
for (let i = 0; i < count; i++) {
|
|
60
|
+
let valueNode = rhsNodes[i];
|
|
61
|
+
// Unwrap &User{} — unary_expression (address-of) wrapping composite_literal
|
|
62
|
+
if (valueNode.type === 'unary_expression' && valueNode.firstNamedChild?.type === 'composite_literal') {
|
|
63
|
+
valueNode = valueNode.firstNamedChild;
|
|
64
|
+
}
|
|
65
|
+
// Go built-in new(User) — call_expression with 'new' callee and type argument
|
|
66
|
+
// Go built-in make([]User, 0) / make(map[string]User) — extract element/value type
|
|
67
|
+
if (valueNode.type === 'call_expression') {
|
|
68
|
+
const funcNode = valueNode.childForFieldName('function');
|
|
69
|
+
if (funcNode?.text === 'new') {
|
|
70
|
+
const args = valueNode.childForFieldName('arguments');
|
|
71
|
+
if (args?.firstNamedChild) {
|
|
72
|
+
const typeName = extractSimpleTypeName(args.firstNamedChild);
|
|
73
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
74
|
+
if (varName && typeName)
|
|
75
|
+
env.set(varName, typeName);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (funcNode?.text === 'make') {
|
|
79
|
+
const args = valueNode.childForFieldName('arguments');
|
|
80
|
+
const firstArg = args?.firstNamedChild;
|
|
81
|
+
if (firstArg) {
|
|
82
|
+
let innerType = null;
|
|
83
|
+
if (firstArg.type === 'slice_type') {
|
|
84
|
+
innerType = firstArg.childForFieldName('element');
|
|
85
|
+
}
|
|
86
|
+
else if (firstArg.type === 'map_type') {
|
|
87
|
+
innerType = firstArg.childForFieldName('value');
|
|
88
|
+
}
|
|
89
|
+
if (innerType) {
|
|
90
|
+
const typeName = extractSimpleTypeName(innerType);
|
|
91
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
92
|
+
if (varName && typeName)
|
|
93
|
+
env.set(varName, typeName);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
// Go type assertion: user := iface.(User) — type_assertion_expression with 'type' field
|
|
100
|
+
if (valueNode.type === 'type_assertion_expression') {
|
|
101
|
+
const typeNode = valueNode.childForFieldName('type');
|
|
102
|
+
if (typeNode) {
|
|
103
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
104
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
105
|
+
if (varName && typeName)
|
|
106
|
+
env.set(varName, typeName);
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (valueNode.type !== 'composite_literal')
|
|
111
|
+
continue;
|
|
112
|
+
const typeNode = valueNode.childForFieldName('type');
|
|
113
|
+
if (!typeNode)
|
|
114
|
+
continue;
|
|
115
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
116
|
+
if (!typeName)
|
|
117
|
+
continue;
|
|
118
|
+
const varName = extractVarName(lhsNodes[i]);
|
|
119
|
+
if (varName)
|
|
120
|
+
env.set(varName, typeName);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const extractDeclaration = (node, env) => {
|
|
124
|
+
if (node.type === 'var_declaration' || node.type === 'var_spec') {
|
|
125
|
+
extractGoVarDeclaration(node, env);
|
|
126
|
+
}
|
|
127
|
+
else if (node.type === 'short_var_declaration') {
|
|
128
|
+
extractGoShortVarDeclaration(node, env);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
/** Go: parameter → name type */
|
|
132
|
+
const extractParameter = (node, env) => {
|
|
133
|
+
let nameNode = null;
|
|
134
|
+
let typeNode = null;
|
|
135
|
+
if (node.type === 'parameter') {
|
|
136
|
+
nameNode = node.childForFieldName('name');
|
|
137
|
+
typeNode = node.childForFieldName('type');
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
nameNode = node.childForFieldName('name') ?? node.childForFieldName('pattern');
|
|
141
|
+
typeNode = node.childForFieldName('type');
|
|
142
|
+
}
|
|
143
|
+
if (!nameNode || !typeNode)
|
|
144
|
+
return;
|
|
145
|
+
const varName = extractVarName(nameNode);
|
|
146
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
147
|
+
if (varName && typeName)
|
|
148
|
+
env.set(varName, typeName);
|
|
149
|
+
};
|
|
150
|
+
/** Go: user := NewUser(...) — infer type from single-assignment call expression */
|
|
151
|
+
const scanConstructorBinding = (node) => {
|
|
152
|
+
if (node.type !== 'short_var_declaration')
|
|
153
|
+
return undefined;
|
|
154
|
+
const left = node.childForFieldName('left');
|
|
155
|
+
const right = node.childForFieldName('right');
|
|
156
|
+
if (!left || !right)
|
|
157
|
+
return undefined;
|
|
158
|
+
const leftIds = left.type === 'expression_list' ? left.namedChildren : [left];
|
|
159
|
+
const rightExprs = right.type === 'expression_list' ? right.namedChildren : [right];
|
|
160
|
+
// Multi-return: user, err := NewUser() — bind first var when second is err/ok/_
|
|
161
|
+
if (leftIds.length === 2 && rightExprs.length === 1) {
|
|
162
|
+
const secondVar = leftIds[1];
|
|
163
|
+
const isErrorOrDiscard = secondVar.text === '_' ||
|
|
164
|
+
secondVar.text === 'err' ||
|
|
165
|
+
secondVar.text === 'ok' ||
|
|
166
|
+
secondVar.text === 'error';
|
|
167
|
+
if (isErrorOrDiscard && leftIds[0].type === 'identifier') {
|
|
168
|
+
if (rightExprs[0].type !== 'call_expression')
|
|
169
|
+
return undefined;
|
|
170
|
+
const func = rightExprs[0].childForFieldName('function');
|
|
171
|
+
if (!func)
|
|
172
|
+
return undefined;
|
|
173
|
+
if (func.text === 'new' || func.text === 'make')
|
|
174
|
+
return undefined;
|
|
175
|
+
const calleeName = extractSimpleTypeName(func);
|
|
176
|
+
if (!calleeName)
|
|
177
|
+
return undefined;
|
|
178
|
+
return { varName: leftIds[0].text, calleeName };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Single assignment only
|
|
182
|
+
if (leftIds.length !== 1 || leftIds[0].type !== 'identifier')
|
|
183
|
+
return undefined;
|
|
184
|
+
if (rightExprs.length !== 1 || rightExprs[0].type !== 'call_expression')
|
|
185
|
+
return undefined;
|
|
186
|
+
const func = rightExprs[0].childForFieldName('function');
|
|
187
|
+
if (!func)
|
|
188
|
+
return undefined;
|
|
189
|
+
// Skip new() and make() — already handled by extractDeclaration
|
|
190
|
+
if (func.text === 'new' || func.text === 'make')
|
|
191
|
+
return undefined;
|
|
192
|
+
const calleeName = extractSimpleTypeName(func);
|
|
193
|
+
if (!calleeName)
|
|
194
|
+
return undefined;
|
|
195
|
+
return { varName: leftIds[0].text, calleeName };
|
|
196
|
+
};
|
|
197
|
+
const FOR_LOOP_NODE_TYPES = new Set([
|
|
198
|
+
'for_statement',
|
|
199
|
+
]);
|
|
200
|
+
/** Go function/method node types that carry a parameter list. */
|
|
201
|
+
const GO_FUNCTION_NODE_TYPES = new Set([
|
|
202
|
+
'function_declaration', 'method_declaration', 'func_literal',
|
|
203
|
+
]);
|
|
204
|
+
/**
|
|
205
|
+
* Extract element type from a Go type annotation AST node.
|
|
206
|
+
* Handles:
|
|
207
|
+
* slice_type "[]User" → element field → type_identifier "User"
|
|
208
|
+
* array_type "[10]User" → element field → type_identifier "User"
|
|
209
|
+
* Falls back to text-based extraction via extractElementTypeFromString.
|
|
210
|
+
*/
|
|
211
|
+
const extractGoElementTypeFromTypeNode = (typeNode, pos = 'last') => {
|
|
212
|
+
// slice_type: []User — element field is the element type
|
|
213
|
+
if (typeNode.type === 'slice_type' || typeNode.type === 'array_type') {
|
|
214
|
+
const elemNode = typeNode.childForFieldName('element');
|
|
215
|
+
if (elemNode)
|
|
216
|
+
return extractSimpleTypeName(elemNode);
|
|
217
|
+
}
|
|
218
|
+
// map_type: map[string]User — value field is the element type (for range, second var gets value)
|
|
219
|
+
if (typeNode.type === 'map_type') {
|
|
220
|
+
const valueNode = typeNode.childForFieldName('value');
|
|
221
|
+
if (valueNode)
|
|
222
|
+
return extractSimpleTypeName(valueNode);
|
|
223
|
+
}
|
|
224
|
+
// channel_type: chan User — the type argument is the element type
|
|
225
|
+
if (typeNode.type === 'channel_type') {
|
|
226
|
+
const valueNode = typeNode.childForFieldName('value') ?? typeNode.lastNamedChild;
|
|
227
|
+
if (valueNode)
|
|
228
|
+
return extractSimpleTypeName(valueNode);
|
|
229
|
+
}
|
|
230
|
+
// generic_type: Go 1.18+ generics (e.g., MySlice[User], Cache[string, User])
|
|
231
|
+
// Use position-aware arg selection: 'first' for keys, 'last' for values.
|
|
232
|
+
if (typeNode.type === 'generic_type') {
|
|
233
|
+
const args = extractGenericTypeArgs(typeNode);
|
|
234
|
+
if (args.length >= 1)
|
|
235
|
+
return pos === 'first' ? args[0] : args[args.length - 1];
|
|
236
|
+
}
|
|
237
|
+
// Fallback: text-based extraction ([]User → User, User[] → User)
|
|
238
|
+
return extractElementTypeFromString(typeNode.text, pos);
|
|
239
|
+
};
|
|
240
|
+
/** Check if a Go type node represents a channel type. Used to determine
|
|
241
|
+
* whether single-var range yields the element (channels) vs index (slices/maps). */
|
|
242
|
+
const isChannelType = (iterableName, scopeEnv, declarationTypeNodes, scope) => {
|
|
243
|
+
if (declarationTypeNodes && scope) {
|
|
244
|
+
const typeNode = declarationTypeNodes.get(`${scope}\0${iterableName}`);
|
|
245
|
+
if (typeNode)
|
|
246
|
+
return typeNode.type === 'channel_type';
|
|
247
|
+
}
|
|
248
|
+
const t = scopeEnv.get(iterableName);
|
|
249
|
+
return !!t && t.startsWith('chan ');
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* Walk up the AST from a for-statement to find the enclosing function declaration,
|
|
253
|
+
* then search its parameters for one named `iterableName`.
|
|
254
|
+
* Returns the element type extracted from its type annotation, or undefined.
|
|
255
|
+
*
|
|
256
|
+
* Go parameter_declaration has:
|
|
257
|
+
* name field: identifier (the parameter name)
|
|
258
|
+
* type field: the type node (slice_type for []User)
|
|
259
|
+
*/
|
|
260
|
+
const findGoParamElementType = (iterableName, startNode, pos = 'last') => {
|
|
261
|
+
let current = startNode.parent;
|
|
262
|
+
while (current) {
|
|
263
|
+
if (GO_FUNCTION_NODE_TYPES.has(current.type)) {
|
|
264
|
+
const paramsNode = current.childForFieldName('parameters');
|
|
265
|
+
if (paramsNode) {
|
|
266
|
+
for (let i = 0; i < paramsNode.namedChildCount; i++) {
|
|
267
|
+
const paramDecl = paramsNode.namedChild(i);
|
|
268
|
+
if (!paramDecl || paramDecl.type !== 'parameter_declaration')
|
|
269
|
+
continue;
|
|
270
|
+
// parameter_declaration: name type — name field is the identifier
|
|
271
|
+
const nameNode = paramDecl.childForFieldName('name');
|
|
272
|
+
if (nameNode?.text === iterableName) {
|
|
273
|
+
const typeNode = paramDecl.childForFieldName('type');
|
|
274
|
+
if (typeNode)
|
|
275
|
+
return extractGoElementTypeFromTypeNode(typeNode, pos);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
current = current.parent;
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Go: for _, user := range users where users has a known slice type.
|
|
287
|
+
*
|
|
288
|
+
* Go uses a single `for_statement` node for all for-loop forms. We detect
|
|
289
|
+
* range-based loops by looking for a `range_clause` child node. C-style for
|
|
290
|
+
* loops (with `for_clause`) and infinite loops (no clause) are ignored.
|
|
291
|
+
*
|
|
292
|
+
* Tier 1c: resolves the element type via three strategies in priority order:
|
|
293
|
+
* 1. declarationTypeNodes — raw type annotation AST node
|
|
294
|
+
* 2. scopeEnv string — extractElementTypeFromString on the stored type
|
|
295
|
+
* 3. AST walk — walks up to the enclosing function's parameters to read []User directly
|
|
296
|
+
* For `_, user := range users`, the loop variable is the second identifier in
|
|
297
|
+
* the `left` expression_list (index is discarded, value is the element).
|
|
298
|
+
*/
|
|
299
|
+
const extractForLoopBinding = (node, { scopeEnv, declarationTypeNodes, scope, returnTypeLookup }) => {
|
|
300
|
+
if (node.type !== 'for_statement')
|
|
301
|
+
return;
|
|
302
|
+
// Find the range_clause child — this distinguishes range loops from other for forms.
|
|
303
|
+
let rangeClause = null;
|
|
304
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
305
|
+
const child = node.namedChild(i);
|
|
306
|
+
if (child?.type === 'range_clause') {
|
|
307
|
+
rangeClause = child;
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!rangeClause)
|
|
312
|
+
return;
|
|
313
|
+
// The iterable is the `right` field of the range_clause.
|
|
314
|
+
const rightNode = rangeClause.childForFieldName('right');
|
|
315
|
+
let iterableName;
|
|
316
|
+
let callExprElementType;
|
|
317
|
+
if (rightNode?.type === 'identifier') {
|
|
318
|
+
iterableName = rightNode.text;
|
|
319
|
+
}
|
|
320
|
+
else if (rightNode?.type === 'selector_expression') {
|
|
321
|
+
const field = rightNode.childForFieldName('field');
|
|
322
|
+
if (field)
|
|
323
|
+
iterableName = field.text;
|
|
324
|
+
}
|
|
325
|
+
else if (rightNode?.type === 'call_expression') {
|
|
326
|
+
// Range over a call result: `for _, v := range getItems()` or `for _, v := range repo.All()`
|
|
327
|
+
const funcNode = rightNode.childForFieldName('function');
|
|
328
|
+
let callee;
|
|
329
|
+
if (funcNode?.type === 'identifier') {
|
|
330
|
+
callee = funcNode.text;
|
|
331
|
+
}
|
|
332
|
+
else if (funcNode?.type === 'selector_expression') {
|
|
333
|
+
const field = funcNode.childForFieldName('field');
|
|
334
|
+
if (field)
|
|
335
|
+
callee = field.text;
|
|
336
|
+
}
|
|
337
|
+
if (callee) {
|
|
338
|
+
const rawReturn = returnTypeLookup.lookupRawReturnType(callee);
|
|
339
|
+
if (rawReturn)
|
|
340
|
+
callExprElementType = extractElementTypeFromString(rawReturn);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (!iterableName && !callExprElementType)
|
|
344
|
+
return;
|
|
345
|
+
let elementType;
|
|
346
|
+
if (callExprElementType) {
|
|
347
|
+
elementType = callExprElementType;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const containerTypeName = scopeEnv.get(iterableName);
|
|
351
|
+
const typeArgPos = methodToTypeArgPosition(undefined, containerTypeName);
|
|
352
|
+
elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractGoElementTypeFromTypeNode, findGoParamElementType, typeArgPos);
|
|
353
|
+
}
|
|
354
|
+
if (!elementType)
|
|
355
|
+
return;
|
|
356
|
+
// The loop variable(s) are in the `left` field.
|
|
357
|
+
// Go range semantics:
|
|
358
|
+
// Slice/Array/String: single-var → INDEX (int); two-var → (index, element)
|
|
359
|
+
// Map: single-var → KEY; two-var → (key, value)
|
|
360
|
+
// Channel: single-var → ELEMENT (channels have no index)
|
|
361
|
+
const leftNode = rangeClause.childForFieldName('left');
|
|
362
|
+
if (!leftNode)
|
|
363
|
+
return;
|
|
364
|
+
let loopVarNode = null;
|
|
365
|
+
if (leftNode.type === 'expression_list') {
|
|
366
|
+
if (leftNode.namedChildCount >= 2) {
|
|
367
|
+
// Two-var form: `_, user` or `i, user` — second variable gets element/value type
|
|
368
|
+
loopVarNode = leftNode.namedChild(1);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
// Single-var in expression_list — yields INDEX for slices/maps, ELEMENT for channels.
|
|
372
|
+
// For call-expression iterables (iterableName undefined), conservative: treat as non-channel.
|
|
373
|
+
// Channels are rarely returned from function calls, and even if they were, skipping here
|
|
374
|
+
// just means we miss a binding rather than create an incorrect one.
|
|
375
|
+
if (iterableName && isChannelType(iterableName, scopeEnv, declarationTypeNodes, scope)) {
|
|
376
|
+
loopVarNode = leftNode.namedChild(0);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
return; // index-only range on slice/map — skip
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
// Plain identifier (single-var form without expression_list)
|
|
385
|
+
// For call-expression iterables (iterableName undefined), conservative: treat as non-channel.
|
|
386
|
+
// Channels are rarely returned from function calls, and even if they were, skipping here
|
|
387
|
+
// just means we miss a binding rather than create an incorrect one.
|
|
388
|
+
if (iterableName && isChannelType(iterableName, scopeEnv, declarationTypeNodes, scope)) {
|
|
389
|
+
loopVarNode = leftNode;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
return; // index-only range on slice/map — skip
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (!loopVarNode)
|
|
396
|
+
return;
|
|
397
|
+
// Skip the blank identifier `_`
|
|
398
|
+
if (loopVarNode.text === '_')
|
|
399
|
+
return;
|
|
400
|
+
const loopVarName = extractVarName(loopVarNode);
|
|
401
|
+
if (loopVarName)
|
|
402
|
+
scopeEnv.set(loopVarName, elementType);
|
|
403
|
+
};
|
|
404
|
+
/** Go: alias := u (short_var_declaration) or var b = u (var_spec) */
|
|
405
|
+
const extractPendingAssignment = (node, scopeEnv) => {
|
|
406
|
+
if (node.type === 'short_var_declaration') {
|
|
407
|
+
const left = node.childForFieldName('left');
|
|
408
|
+
const right = node.childForFieldName('right');
|
|
409
|
+
if (!left || !right)
|
|
410
|
+
return undefined;
|
|
411
|
+
const lhsNode = left.type === 'expression_list' ? left.firstNamedChild : left;
|
|
412
|
+
const rhsNode = right.type === 'expression_list' ? right.firstNamedChild : right;
|
|
413
|
+
if (!lhsNode || !rhsNode)
|
|
414
|
+
return undefined;
|
|
415
|
+
if (lhsNode.type !== 'identifier')
|
|
416
|
+
return undefined;
|
|
417
|
+
const lhs = lhsNode.text;
|
|
418
|
+
if (scopeEnv.has(lhs))
|
|
419
|
+
return undefined;
|
|
420
|
+
if (rhsNode.type === 'identifier')
|
|
421
|
+
return { kind: 'copy', lhs, rhs: rhsNode.text };
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
if (node.type === 'var_spec' || node.type === 'var_declaration') {
|
|
425
|
+
// var_declaration contains var_spec children; var_spec has name + expression_list value
|
|
426
|
+
const specs = [];
|
|
427
|
+
if (node.type === 'var_declaration') {
|
|
428
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
429
|
+
const c = node.namedChild(i);
|
|
430
|
+
if (c?.type === 'var_spec')
|
|
431
|
+
specs.push(c);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
specs.push(node);
|
|
436
|
+
}
|
|
437
|
+
for (const spec of specs) {
|
|
438
|
+
const nameNode = spec.childForFieldName('name');
|
|
439
|
+
if (!nameNode || nameNode.type !== 'identifier')
|
|
440
|
+
continue;
|
|
441
|
+
const lhs = nameNode.text;
|
|
442
|
+
if (scopeEnv.has(lhs))
|
|
443
|
+
continue;
|
|
444
|
+
// Check if the last named child is a bare identifier (no type annotation between name and value)
|
|
445
|
+
let exprList = null;
|
|
446
|
+
for (let i = 0; i < spec.childCount; i++) {
|
|
447
|
+
if (spec.child(i)?.type === 'expression_list') {
|
|
448
|
+
exprList = spec.child(i);
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const rhsNode = exprList?.firstNamedChild;
|
|
453
|
+
if (rhsNode?.type === 'identifier')
|
|
454
|
+
return { kind: 'copy', lhs, rhs: rhsNode.text };
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return undefined;
|
|
458
|
+
};
|
|
459
|
+
export const typeConfig = {
|
|
460
|
+
declarationNodeTypes: DECLARATION_NODE_TYPES,
|
|
461
|
+
forLoopNodeTypes: FOR_LOOP_NODE_TYPES,
|
|
462
|
+
extractDeclaration,
|
|
463
|
+
extractParameter,
|
|
464
|
+
scanConstructorBinding,
|
|
465
|
+
extractForLoopBinding,
|
|
466
|
+
extractPendingAssignment,
|
|
467
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-language type extraction configurations.
|
|
3
|
+
* Assembled here into a dispatch map keyed by SupportedLanguages.
|
|
4
|
+
*/
|
|
5
|
+
import type { LanguageTypeConfig } from './types.js';
|
|
6
|
+
export declare const typeConfigs: {
|
|
7
|
+
javascript: LanguageTypeConfig;
|
|
8
|
+
typescript: LanguageTypeConfig;
|
|
9
|
+
java: LanguageTypeConfig;
|
|
10
|
+
kotlin: LanguageTypeConfig;
|
|
11
|
+
csharp: LanguageTypeConfig;
|
|
12
|
+
go: LanguageTypeConfig;
|
|
13
|
+
rust: LanguageTypeConfig;
|
|
14
|
+
python: LanguageTypeConfig;
|
|
15
|
+
swift: LanguageTypeConfig;
|
|
16
|
+
c: LanguageTypeConfig;
|
|
17
|
+
cpp: LanguageTypeConfig;
|
|
18
|
+
php: LanguageTypeConfig;
|
|
19
|
+
ruby: LanguageTypeConfig;
|
|
20
|
+
};
|
|
21
|
+
export type { LanguageTypeConfig, TypeBindingExtractor, ParameterExtractor, ConstructorBindingScanner, ForLoopExtractor, PendingAssignmentExtractor, PatternBindingExtractor, } from './types.js';
|
|
22
|
+
export { TYPED_PARAMETER_TYPES, extractSimpleTypeName, extractGenericTypeArgs, extractVarName, findChildByType, extractRubyConstructorAssignment } from './shared.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-language type extraction configurations.
|
|
3
|
+
* Assembled here into a dispatch map keyed by SupportedLanguages.
|
|
4
|
+
*/
|
|
5
|
+
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
6
|
+
import { typeConfig as typescriptConfig } from './typescript.js';
|
|
7
|
+
import { javaTypeConfig, kotlinTypeConfig } from './jvm.js';
|
|
8
|
+
import { typeConfig as csharpConfig } from './csharp.js';
|
|
9
|
+
import { typeConfig as goConfig } from './go.js';
|
|
10
|
+
import { typeConfig as rustConfig } from './rust.js';
|
|
11
|
+
import { typeConfig as pythonConfig } from './python.js';
|
|
12
|
+
import { typeConfig as swiftConfig } from './swift.js';
|
|
13
|
+
import { typeConfig as cCppConfig } from './c-cpp.js';
|
|
14
|
+
import { typeConfig as phpConfig } from './php.js';
|
|
15
|
+
import { typeConfig as rubyConfig } from './ruby.js';
|
|
16
|
+
export const typeConfigs = {
|
|
17
|
+
[SupportedLanguages.JavaScript]: typescriptConfig,
|
|
18
|
+
[SupportedLanguages.TypeScript]: typescriptConfig,
|
|
19
|
+
[SupportedLanguages.Java]: javaTypeConfig,
|
|
20
|
+
[SupportedLanguages.Kotlin]: kotlinTypeConfig,
|
|
21
|
+
[SupportedLanguages.CSharp]: csharpConfig,
|
|
22
|
+
[SupportedLanguages.Go]: goConfig,
|
|
23
|
+
[SupportedLanguages.Rust]: rustConfig,
|
|
24
|
+
[SupportedLanguages.Python]: pythonConfig,
|
|
25
|
+
[SupportedLanguages.Swift]: swiftConfig,
|
|
26
|
+
[SupportedLanguages.C]: cCppConfig,
|
|
27
|
+
[SupportedLanguages.CPlusPlus]: cCppConfig,
|
|
28
|
+
[SupportedLanguages.PHP]: phpConfig,
|
|
29
|
+
[SupportedLanguages.Ruby]: rubyConfig,
|
|
30
|
+
};
|
|
31
|
+
export { TYPED_PARAMETER_TYPES, extractSimpleTypeName, extractGenericTypeArgs, extractVarName, findChildByType, extractRubyConstructorAssignment } from './shared.js';
|