@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,383 @@
|
|
|
1
|
+
import { extractSimpleTypeName, extractVarName, findChildByType, unwrapAwait, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString } from './shared.js';
|
|
2
|
+
/** Known container property accessors that operate on the container itself (e.g., dict.Keys, dict.Values) */
|
|
3
|
+
const KNOWN_CONTAINER_PROPS = new Set(['Keys', 'Values']);
|
|
4
|
+
const DECLARATION_NODE_TYPES = new Set([
|
|
5
|
+
'local_declaration_statement',
|
|
6
|
+
'variable_declaration',
|
|
7
|
+
'field_declaration',
|
|
8
|
+
]);
|
|
9
|
+
/** C#: Type x = ...; var x = new Type(); */
|
|
10
|
+
const extractDeclaration = (node, env) => {
|
|
11
|
+
// C# tree-sitter: local_declaration_statement > variable_declaration > ...
|
|
12
|
+
// Recursively descend through wrapper nodes
|
|
13
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14
|
+
const child = node.namedChild(i);
|
|
15
|
+
if (!child)
|
|
16
|
+
continue;
|
|
17
|
+
if (child.type === 'variable_declaration' || child.type === 'local_declaration_statement') {
|
|
18
|
+
extractDeclaration(child, env);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// At variable_declaration level: first child is type, rest are variable_declarators
|
|
23
|
+
let typeNode = null;
|
|
24
|
+
const declarators = [];
|
|
25
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
26
|
+
const child = node.namedChild(i);
|
|
27
|
+
if (!child)
|
|
28
|
+
continue;
|
|
29
|
+
if (!typeNode && child.type !== 'variable_declarator' && child.type !== 'equals_value_clause') {
|
|
30
|
+
// First non-declarator child is the type (identifier, implicit_type, generic_name, etc.)
|
|
31
|
+
typeNode = child;
|
|
32
|
+
}
|
|
33
|
+
if (child.type === 'variable_declarator') {
|
|
34
|
+
declarators.push(child);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!typeNode || declarators.length === 0)
|
|
38
|
+
return;
|
|
39
|
+
// Handle 'var x = new Foo()' — infer from object_creation_expression
|
|
40
|
+
let typeName;
|
|
41
|
+
if (typeNode.type === 'implicit_type' && typeNode.text === 'var') {
|
|
42
|
+
// Try to infer from initializer: var x = new Foo()
|
|
43
|
+
// tree-sitter-c-sharp may put object_creation_expression as direct child
|
|
44
|
+
// or inside equals_value_clause depending on grammar version
|
|
45
|
+
if (declarators.length === 1) {
|
|
46
|
+
const initializer = findChildByType(declarators[0], 'object_creation_expression')
|
|
47
|
+
?? findChildByType(declarators[0], 'equals_value_clause')?.firstNamedChild;
|
|
48
|
+
if (initializer?.type === 'object_creation_expression') {
|
|
49
|
+
const ctorType = initializer.childForFieldName('type');
|
|
50
|
+
if (ctorType)
|
|
51
|
+
typeName = extractSimpleTypeName(ctorType);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
typeName = extractSimpleTypeName(typeNode);
|
|
57
|
+
}
|
|
58
|
+
if (!typeName)
|
|
59
|
+
return;
|
|
60
|
+
for (const decl of declarators) {
|
|
61
|
+
const nameNode = decl.childForFieldName('name') ?? decl.firstNamedChild;
|
|
62
|
+
if (nameNode) {
|
|
63
|
+
const varName = extractVarName(nameNode);
|
|
64
|
+
if (varName)
|
|
65
|
+
env.set(varName, typeName);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
/** C#: parameter → type name */
|
|
70
|
+
const extractParameter = (node, env) => {
|
|
71
|
+
let nameNode = null;
|
|
72
|
+
let typeNode = null;
|
|
73
|
+
if (node.type === 'parameter') {
|
|
74
|
+
typeNode = node.childForFieldName('type');
|
|
75
|
+
nameNode = node.childForFieldName('name');
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
nameNode = node.childForFieldName('name') ?? node.childForFieldName('pattern');
|
|
79
|
+
typeNode = node.childForFieldName('type');
|
|
80
|
+
}
|
|
81
|
+
if (!nameNode || !typeNode)
|
|
82
|
+
return;
|
|
83
|
+
const varName = extractVarName(nameNode);
|
|
84
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
85
|
+
if (varName && typeName)
|
|
86
|
+
env.set(varName, typeName);
|
|
87
|
+
};
|
|
88
|
+
/** C#: var x = SomeFactory(...) → bind x to SomeFactory (constructor-like call) */
|
|
89
|
+
const scanConstructorBinding = (node) => {
|
|
90
|
+
if (node.type !== 'variable_declaration')
|
|
91
|
+
return undefined;
|
|
92
|
+
// Find type and declarator children by iterating (C# grammar doesn't expose 'type' as a named field)
|
|
93
|
+
let typeNode = null;
|
|
94
|
+
let declarator = null;
|
|
95
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
96
|
+
const child = node.namedChild(i);
|
|
97
|
+
if (!child)
|
|
98
|
+
continue;
|
|
99
|
+
if (child.type === 'variable_declarator') {
|
|
100
|
+
if (!declarator)
|
|
101
|
+
declarator = child;
|
|
102
|
+
}
|
|
103
|
+
else if (!typeNode) {
|
|
104
|
+
typeNode = child;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Only handle implicit_type (var) — explicit types handled by extractDeclaration
|
|
108
|
+
if (!typeNode || typeNode.type !== 'implicit_type')
|
|
109
|
+
return undefined;
|
|
110
|
+
if (!declarator)
|
|
111
|
+
return undefined;
|
|
112
|
+
const nameNode = declarator.childForFieldName('name') ?? declarator.firstNamedChild;
|
|
113
|
+
if (!nameNode || nameNode.type !== 'identifier')
|
|
114
|
+
return undefined;
|
|
115
|
+
// Find the initializer value: either inside equals_value_clause or as a direct child
|
|
116
|
+
// (tree-sitter-c-sharp puts invocation_expression directly inside variable_declarator)
|
|
117
|
+
let value = null;
|
|
118
|
+
for (let i = 0; i < declarator.namedChildCount; i++) {
|
|
119
|
+
const child = declarator.namedChild(i);
|
|
120
|
+
if (!child)
|
|
121
|
+
continue;
|
|
122
|
+
if (child.type === 'equals_value_clause') {
|
|
123
|
+
value = child.firstNamedChild;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
if (child.type === 'invocation_expression' || child.type === 'object_creation_expression' || child.type === 'await_expression') {
|
|
127
|
+
value = child;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!value)
|
|
132
|
+
return undefined;
|
|
133
|
+
// Unwrap await: `var user = await svc.GetUserAsync()` → await_expression wraps invocation_expression
|
|
134
|
+
value = unwrapAwait(value);
|
|
135
|
+
if (!value)
|
|
136
|
+
return undefined;
|
|
137
|
+
// Skip object_creation_expression (new User()) — handled by extractInitializer
|
|
138
|
+
if (value.type === 'object_creation_expression')
|
|
139
|
+
return undefined;
|
|
140
|
+
if (value.type !== 'invocation_expression')
|
|
141
|
+
return undefined;
|
|
142
|
+
const func = value.firstNamedChild;
|
|
143
|
+
if (!func)
|
|
144
|
+
return undefined;
|
|
145
|
+
const calleeName = extractSimpleTypeName(func);
|
|
146
|
+
if (!calleeName)
|
|
147
|
+
return undefined;
|
|
148
|
+
return { varName: nameNode.text, calleeName };
|
|
149
|
+
};
|
|
150
|
+
const FOR_LOOP_NODE_TYPES = new Set([
|
|
151
|
+
'foreach_statement',
|
|
152
|
+
]);
|
|
153
|
+
/** Extract element type from a C# type annotation AST node.
|
|
154
|
+
* Handles generic_name (List<User>), array_type (User[]), nullable_type (?).
|
|
155
|
+
* `pos` selects which type arg: 'first' for keys, 'last' for values (default). */
|
|
156
|
+
const extractCSharpElementTypeFromTypeNode = (typeNode, pos = 'last', depth = 0) => {
|
|
157
|
+
if (depth > 50)
|
|
158
|
+
return undefined;
|
|
159
|
+
// generic_name: List<User>, IEnumerable<User>, Dictionary<string, User>
|
|
160
|
+
// C# uses generic_name (not generic_type)
|
|
161
|
+
if (typeNode.type === 'generic_name') {
|
|
162
|
+
const argList = findChildByType(typeNode, 'type_argument_list');
|
|
163
|
+
if (argList && argList.namedChildCount >= 1) {
|
|
164
|
+
if (pos === 'first') {
|
|
165
|
+
const firstArg = argList.namedChild(0);
|
|
166
|
+
if (firstArg)
|
|
167
|
+
return extractSimpleTypeName(firstArg);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const lastArg = argList.namedChild(argList.namedChildCount - 1);
|
|
171
|
+
if (lastArg)
|
|
172
|
+
return extractSimpleTypeName(lastArg);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// array_type: User[]
|
|
177
|
+
if (typeNode.type === 'array_type') {
|
|
178
|
+
const elemNode = typeNode.firstNamedChild;
|
|
179
|
+
if (elemNode)
|
|
180
|
+
return extractSimpleTypeName(elemNode);
|
|
181
|
+
}
|
|
182
|
+
// nullable_type: unwrap and recurse (List<User>? → List<User> → User)
|
|
183
|
+
if (typeNode.type === 'nullable_type') {
|
|
184
|
+
const inner = typeNode.firstNamedChild;
|
|
185
|
+
if (inner)
|
|
186
|
+
return extractCSharpElementTypeFromTypeNode(inner, pos, depth + 1);
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
};
|
|
190
|
+
/** Walk up from a foreach to the enclosing method and search parameters. */
|
|
191
|
+
const findCSharpParamElementType = (iterableName, startNode, pos = 'last') => {
|
|
192
|
+
let current = startNode.parent;
|
|
193
|
+
while (current) {
|
|
194
|
+
if (current.type === 'method_declaration' || current.type === 'local_function_statement') {
|
|
195
|
+
const paramsNode = current.childForFieldName('parameters');
|
|
196
|
+
if (paramsNode) {
|
|
197
|
+
for (let i = 0; i < paramsNode.namedChildCount; i++) {
|
|
198
|
+
const param = paramsNode.namedChild(i);
|
|
199
|
+
if (!param || param.type !== 'parameter')
|
|
200
|
+
continue;
|
|
201
|
+
const nameNode = param.childForFieldName('name');
|
|
202
|
+
if (nameNode?.text !== iterableName)
|
|
203
|
+
continue;
|
|
204
|
+
const typeNode = param.childForFieldName('type');
|
|
205
|
+
if (typeNode)
|
|
206
|
+
return extractCSharpElementTypeFromTypeNode(typeNode, pos);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
current = current.parent;
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
};
|
|
215
|
+
/** C#: foreach (User user in users) — extract loop variable binding.
|
|
216
|
+
* Tier 1c: for `foreach (var user in users)`, resolves element type from iterable. */
|
|
217
|
+
const extractForLoopBinding = (node, { scopeEnv, declarationTypeNodes, scope, returnTypeLookup }) => {
|
|
218
|
+
const typeNode = node.childForFieldName('type');
|
|
219
|
+
const nameNode = node.childForFieldName('left');
|
|
220
|
+
if (!typeNode || !nameNode)
|
|
221
|
+
return;
|
|
222
|
+
const varName = extractVarName(nameNode);
|
|
223
|
+
if (!varName)
|
|
224
|
+
return;
|
|
225
|
+
// Explicit type (existing behavior): foreach (User user in users)
|
|
226
|
+
if (!(typeNode.type === 'implicit_type' && typeNode.text === 'var')) {
|
|
227
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
228
|
+
if (typeName)
|
|
229
|
+
scopeEnv.set(varName, typeName);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
// Tier 1c: implicit type (var) — resolve from iterable's container type
|
|
233
|
+
const rightNode = node.childForFieldName('right');
|
|
234
|
+
let iterableName;
|
|
235
|
+
let methodName;
|
|
236
|
+
let callExprElementType;
|
|
237
|
+
if (rightNode?.type === 'identifier') {
|
|
238
|
+
iterableName = rightNode.text;
|
|
239
|
+
}
|
|
240
|
+
else if (rightNode?.type === 'member_access_expression') {
|
|
241
|
+
// C# property access: data.Keys, data.Values → member_access_expression
|
|
242
|
+
// Also handles bare member access: this.users, repo.users → use property as iterableName
|
|
243
|
+
const obj = rightNode.childForFieldName('expression');
|
|
244
|
+
const prop = rightNode.childForFieldName('name');
|
|
245
|
+
const propText = prop?.type === 'identifier' ? prop.text : undefined;
|
|
246
|
+
if (propText && KNOWN_CONTAINER_PROPS.has(propText)) {
|
|
247
|
+
if (obj?.type === 'identifier') {
|
|
248
|
+
iterableName = obj.text;
|
|
249
|
+
}
|
|
250
|
+
else if (obj?.type === 'member_access_expression') {
|
|
251
|
+
// Nested member access: this.data.Values → obj is "this.data", extract "data"
|
|
252
|
+
const innerProp = obj.childForFieldName('name');
|
|
253
|
+
if (innerProp)
|
|
254
|
+
iterableName = innerProp.text;
|
|
255
|
+
}
|
|
256
|
+
methodName = propText;
|
|
257
|
+
}
|
|
258
|
+
else if (propText) {
|
|
259
|
+
// Bare member access: this.users → use property name for scopeEnv lookup
|
|
260
|
+
iterableName = propText;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else if (rightNode?.type === 'invocation_expression') {
|
|
264
|
+
// C# method call: data.Select(...) → invocation_expression > member_access_expression
|
|
265
|
+
// Direct function call: GetUsers() → invocation_expression > identifier
|
|
266
|
+
const fn = rightNode.firstNamedChild;
|
|
267
|
+
if (fn?.type === 'member_access_expression') {
|
|
268
|
+
const obj = fn.childForFieldName('expression');
|
|
269
|
+
const prop = fn.childForFieldName('name');
|
|
270
|
+
if (obj?.type === 'identifier')
|
|
271
|
+
iterableName = obj.text;
|
|
272
|
+
if (prop?.type === 'identifier')
|
|
273
|
+
methodName = prop.text;
|
|
274
|
+
}
|
|
275
|
+
else if (fn?.type === 'identifier') {
|
|
276
|
+
// Direct function call: foreach (var u in GetUsers())
|
|
277
|
+
const rawReturn = returnTypeLookup.lookupRawReturnType(fn.text);
|
|
278
|
+
if (rawReturn)
|
|
279
|
+
callExprElementType = extractElementTypeFromString(rawReturn);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!iterableName && !callExprElementType)
|
|
283
|
+
return;
|
|
284
|
+
let elementType;
|
|
285
|
+
if (callExprElementType) {
|
|
286
|
+
elementType = callExprElementType;
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
const containerTypeName = scopeEnv.get(iterableName);
|
|
290
|
+
const typeArgPos = methodToTypeArgPosition(methodName, containerTypeName);
|
|
291
|
+
elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractCSharpElementTypeFromTypeNode, findCSharpParamElementType, typeArgPos);
|
|
292
|
+
}
|
|
293
|
+
if (elementType)
|
|
294
|
+
scopeEnv.set(varName, elementType);
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* C# pattern binding extractor for `obj is Type variable` (type pattern).
|
|
298
|
+
*
|
|
299
|
+
* AST structure:
|
|
300
|
+
* is_pattern_expression
|
|
301
|
+
* expression: (the variable being tested)
|
|
302
|
+
* pattern: declaration_pattern
|
|
303
|
+
* type: (the declared type)
|
|
304
|
+
* name: single_variable_designation > identifier (the new variable name)
|
|
305
|
+
*
|
|
306
|
+
* Conservative: returns undefined when the pattern field is absent, is not a
|
|
307
|
+
* declaration_pattern, or when the type/name cannot be extracted.
|
|
308
|
+
* No scopeEnv lookup is needed — the pattern explicitly declares the new variable's type.
|
|
309
|
+
*/
|
|
310
|
+
const extractPatternBinding = (node) => {
|
|
311
|
+
// is_pattern_expression: `obj is User user` — has a declaration_pattern child
|
|
312
|
+
if (node.type === 'is_pattern_expression') {
|
|
313
|
+
const pattern = node.childForFieldName('pattern');
|
|
314
|
+
if (pattern?.type !== 'declaration_pattern' && pattern?.type !== 'recursive_pattern')
|
|
315
|
+
return undefined;
|
|
316
|
+
const typeNode = pattern.childForFieldName('type');
|
|
317
|
+
const nameNode = pattern.childForFieldName('name');
|
|
318
|
+
if (!typeNode || !nameNode)
|
|
319
|
+
return undefined;
|
|
320
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
321
|
+
const varName = extractVarName(nameNode);
|
|
322
|
+
if (!typeName || !varName)
|
|
323
|
+
return undefined;
|
|
324
|
+
return { varName, typeName };
|
|
325
|
+
}
|
|
326
|
+
// declaration_pattern / recursive_pattern: standalone in switch statements and switch expressions
|
|
327
|
+
// `case User u:` or `User u =>` or `User { Name: "Alice" } u =>`
|
|
328
|
+
// Both use the same 'type' and 'name' fields.
|
|
329
|
+
if (node.type === 'declaration_pattern' || node.type === 'recursive_pattern') {
|
|
330
|
+
const typeNode = node.childForFieldName('type');
|
|
331
|
+
const nameNode = node.childForFieldName('name');
|
|
332
|
+
if (!typeNode || !nameNode)
|
|
333
|
+
return undefined;
|
|
334
|
+
const typeName = extractSimpleTypeName(typeNode);
|
|
335
|
+
const varName = extractVarName(nameNode);
|
|
336
|
+
if (!typeName || !varName)
|
|
337
|
+
return undefined;
|
|
338
|
+
return { varName, typeName };
|
|
339
|
+
}
|
|
340
|
+
return undefined;
|
|
341
|
+
};
|
|
342
|
+
/** C#: var alias = u → variable_declarator with name + equals_value_clause.
|
|
343
|
+
* Only local_declaration_statement and variable_declaration contain variable_declarator children;
|
|
344
|
+
* is_pattern_expression and field_declaration never do — skip them early. */
|
|
345
|
+
const extractPendingAssignment = (node, scopeEnv) => {
|
|
346
|
+
if (node.type === 'is_pattern_expression' || node.type === 'field_declaration')
|
|
347
|
+
return undefined;
|
|
348
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
349
|
+
const child = node.namedChild(i);
|
|
350
|
+
if (!child || child.type !== 'variable_declarator')
|
|
351
|
+
continue;
|
|
352
|
+
const nameNode = child.childForFieldName('name');
|
|
353
|
+
if (!nameNode)
|
|
354
|
+
continue;
|
|
355
|
+
const lhs = nameNode.text;
|
|
356
|
+
if (scopeEnv.has(lhs))
|
|
357
|
+
continue;
|
|
358
|
+
// C# wraps value in equals_value_clause; fall back to last named child
|
|
359
|
+
let evc = null;
|
|
360
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
361
|
+
if (child.child(j)?.type === 'equals_value_clause') {
|
|
362
|
+
evc = child.child(j);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const valueNode = evc?.firstNamedChild ?? child.namedChild(child.namedChildCount - 1);
|
|
367
|
+
if (valueNode && valueNode !== nameNode && (valueNode.type === 'identifier' || valueNode.type === 'simple_identifier')) {
|
|
368
|
+
return { kind: 'copy', lhs, rhs: valueNode.text };
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return undefined;
|
|
372
|
+
};
|
|
373
|
+
export const typeConfig = {
|
|
374
|
+
declarationNodeTypes: DECLARATION_NODE_TYPES,
|
|
375
|
+
forLoopNodeTypes: FOR_LOOP_NODE_TYPES,
|
|
376
|
+
patternBindingNodeTypes: new Set(['is_pattern_expression', 'declaration_pattern', 'recursive_pattern']),
|
|
377
|
+
extractDeclaration,
|
|
378
|
+
extractParameter,
|
|
379
|
+
scanConstructorBinding,
|
|
380
|
+
extractForLoopBinding,
|
|
381
|
+
extractPendingAssignment,
|
|
382
|
+
extractPatternBinding,
|
|
383
|
+
};
|