@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.
Files changed (224) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +261 -0
  3. package/dist/cli/ai-context.d.ts +23 -0
  4. package/dist/cli/ai-context.js +265 -0
  5. package/dist/cli/analyze.d.ts +12 -0
  6. package/dist/cli/analyze.js +345 -0
  7. package/dist/cli/augment.d.ts +13 -0
  8. package/dist/cli/augment.js +33 -0
  9. package/dist/cli/clean.d.ts +10 -0
  10. package/dist/cli/clean.js +60 -0
  11. package/dist/cli/eval-server.d.ts +37 -0
  12. package/dist/cli/eval-server.js +389 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +137 -0
  15. package/dist/cli/lazy-action.d.ts +6 -0
  16. package/dist/cli/lazy-action.js +18 -0
  17. package/dist/cli/list.d.ts +6 -0
  18. package/dist/cli/list.js +30 -0
  19. package/dist/cli/mcp.d.ts +8 -0
  20. package/dist/cli/mcp.js +36 -0
  21. package/dist/cli/serve.d.ts +4 -0
  22. package/dist/cli/serve.js +6 -0
  23. package/dist/cli/setup.d.ts +8 -0
  24. package/dist/cli/setup.js +367 -0
  25. package/dist/cli/sipher-patched.d.ts +2 -0
  26. package/dist/cli/sipher-patched.js +77 -0
  27. package/dist/cli/skill-gen.d.ts +26 -0
  28. package/dist/cli/skill-gen.js +549 -0
  29. package/dist/cli/status.d.ts +6 -0
  30. package/dist/cli/status.js +36 -0
  31. package/dist/cli/tool.d.ts +60 -0
  32. package/dist/cli/tool.js +180 -0
  33. package/dist/cli/wiki.d.ts +15 -0
  34. package/dist/cli/wiki.js +365 -0
  35. package/dist/config/ignore-service.d.ts +26 -0
  36. package/dist/config/ignore-service.js +284 -0
  37. package/dist/config/supported-languages.d.ts +15 -0
  38. package/dist/config/supported-languages.js +16 -0
  39. package/dist/core/augmentation/engine.d.ts +26 -0
  40. package/dist/core/augmentation/engine.js +240 -0
  41. package/dist/core/embeddings/embedder.d.ts +60 -0
  42. package/dist/core/embeddings/embedder.js +251 -0
  43. package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
  44. package/dist/core/embeddings/embedding-pipeline.js +356 -0
  45. package/dist/core/embeddings/index.d.ts +9 -0
  46. package/dist/core/embeddings/index.js +9 -0
  47. package/dist/core/embeddings/text-generator.d.ts +24 -0
  48. package/dist/core/embeddings/text-generator.js +182 -0
  49. package/dist/core/embeddings/types.d.ts +87 -0
  50. package/dist/core/embeddings/types.js +32 -0
  51. package/dist/core/graph/graph.d.ts +2 -0
  52. package/dist/core/graph/graph.js +66 -0
  53. package/dist/core/graph/types.d.ts +66 -0
  54. package/dist/core/graph/types.js +1 -0
  55. package/dist/core/ingestion/ast-cache.d.ts +11 -0
  56. package/dist/core/ingestion/ast-cache.js +35 -0
  57. package/dist/core/ingestion/call-processor.d.ts +23 -0
  58. package/dist/core/ingestion/call-processor.js +793 -0
  59. package/dist/core/ingestion/call-routing.d.ts +68 -0
  60. package/dist/core/ingestion/call-routing.js +129 -0
  61. package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
  62. package/dist/core/ingestion/cluster-enricher.js +170 -0
  63. package/dist/core/ingestion/community-processor.d.ts +39 -0
  64. package/dist/core/ingestion/community-processor.js +312 -0
  65. package/dist/core/ingestion/constants.d.ts +16 -0
  66. package/dist/core/ingestion/constants.js +16 -0
  67. package/dist/core/ingestion/entry-point-scoring.d.ts +40 -0
  68. package/dist/core/ingestion/entry-point-scoring.js +353 -0
  69. package/dist/core/ingestion/export-detection.d.ts +18 -0
  70. package/dist/core/ingestion/export-detection.js +231 -0
  71. package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
  72. package/dist/core/ingestion/filesystem-walker.js +81 -0
  73. package/dist/core/ingestion/framework-detection.d.ts +54 -0
  74. package/dist/core/ingestion/framework-detection.js +411 -0
  75. package/dist/core/ingestion/heritage-processor.d.ts +28 -0
  76. package/dist/core/ingestion/heritage-processor.js +251 -0
  77. package/dist/core/ingestion/import-processor.d.ts +34 -0
  78. package/dist/core/ingestion/import-processor.js +398 -0
  79. package/dist/core/ingestion/language-config.d.ts +46 -0
  80. package/dist/core/ingestion/language-config.js +167 -0
  81. package/dist/core/ingestion/mro-processor.d.ts +45 -0
  82. package/dist/core/ingestion/mro-processor.js +369 -0
  83. package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
  84. package/dist/core/ingestion/named-binding-extraction.js +363 -0
  85. package/dist/core/ingestion/parsing-processor.d.ts +19 -0
  86. package/dist/core/ingestion/parsing-processor.js +315 -0
  87. package/dist/core/ingestion/pipeline.d.ts +6 -0
  88. package/dist/core/ingestion/pipeline.js +401 -0
  89. package/dist/core/ingestion/process-processor.d.ts +51 -0
  90. package/dist/core/ingestion/process-processor.js +315 -0
  91. package/dist/core/ingestion/resolution-context.d.ts +53 -0
  92. package/dist/core/ingestion/resolution-context.js +132 -0
  93. package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
  94. package/dist/core/ingestion/resolvers/csharp.js +109 -0
  95. package/dist/core/ingestion/resolvers/go.d.ts +19 -0
  96. package/dist/core/ingestion/resolvers/go.js +42 -0
  97. package/dist/core/ingestion/resolvers/index.d.ts +18 -0
  98. package/dist/core/ingestion/resolvers/index.js +13 -0
  99. package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
  100. package/dist/core/ingestion/resolvers/jvm.js +87 -0
  101. package/dist/core/ingestion/resolvers/php.d.ts +15 -0
  102. package/dist/core/ingestion/resolvers/php.js +35 -0
  103. package/dist/core/ingestion/resolvers/python.d.ts +19 -0
  104. package/dist/core/ingestion/resolvers/python.js +52 -0
  105. package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
  106. package/dist/core/ingestion/resolvers/ruby.js +15 -0
  107. package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
  108. package/dist/core/ingestion/resolvers/rust.js +73 -0
  109. package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
  110. package/dist/core/ingestion/resolvers/standard.js +123 -0
  111. package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
  112. package/dist/core/ingestion/resolvers/utils.js +122 -0
  113. package/dist/core/ingestion/structure-processor.d.ts +2 -0
  114. package/dist/core/ingestion/structure-processor.js +36 -0
  115. package/dist/core/ingestion/symbol-table.d.ts +63 -0
  116. package/dist/core/ingestion/symbol-table.js +85 -0
  117. package/dist/core/ingestion/tree-sitter-queries.d.ts +15 -0
  118. package/dist/core/ingestion/tree-sitter-queries.js +888 -0
  119. package/dist/core/ingestion/type-env.d.ts +49 -0
  120. package/dist/core/ingestion/type-env.js +613 -0
  121. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
  122. package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
  123. package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
  124. package/dist/core/ingestion/type-extractors/csharp.js +383 -0
  125. package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
  126. package/dist/core/ingestion/type-extractors/go.js +467 -0
  127. package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
  128. package/dist/core/ingestion/type-extractors/index.js +31 -0
  129. package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
  130. package/dist/core/ingestion/type-extractors/jvm.js +681 -0
  131. package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
  132. package/dist/core/ingestion/type-extractors/php.js +549 -0
  133. package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
  134. package/dist/core/ingestion/type-extractors/python.js +455 -0
  135. package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
  136. package/dist/core/ingestion/type-extractors/ruby.js +389 -0
  137. package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
  138. package/dist/core/ingestion/type-extractors/rust.js +456 -0
  139. package/dist/core/ingestion/type-extractors/shared.d.ts +145 -0
  140. package/dist/core/ingestion/type-extractors/shared.js +810 -0
  141. package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
  142. package/dist/core/ingestion/type-extractors/swift.js +137 -0
  143. package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
  144. package/dist/core/ingestion/type-extractors/types.js +1 -0
  145. package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
  146. package/dist/core/ingestion/type-extractors/typescript.js +494 -0
  147. package/dist/core/ingestion/utils.d.ts +138 -0
  148. package/dist/core/ingestion/utils.js +1290 -0
  149. package/dist/core/ingestion/workers/parse-worker.d.ts +122 -0
  150. package/dist/core/ingestion/workers/parse-worker.js +1126 -0
  151. package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
  152. package/dist/core/ingestion/workers/worker-pool.js +128 -0
  153. package/dist/core/lbug/csv-generator.d.ts +33 -0
  154. package/dist/core/lbug/csv-generator.js +366 -0
  155. package/dist/core/lbug/lbug-adapter.d.ts +103 -0
  156. package/dist/core/lbug/lbug-adapter.js +769 -0
  157. package/dist/core/lbug/schema.d.ts +53 -0
  158. package/dist/core/lbug/schema.js +430 -0
  159. package/dist/core/search/bm25-index.d.ts +23 -0
  160. package/dist/core/search/bm25-index.js +96 -0
  161. package/dist/core/search/hybrid-search.d.ts +49 -0
  162. package/dist/core/search/hybrid-search.js +118 -0
  163. package/dist/core/tree-sitter/parser-loader.d.ts +5 -0
  164. package/dist/core/tree-sitter/parser-loader.js +63 -0
  165. package/dist/core/wiki/generator.d.ts +120 -0
  166. package/dist/core/wiki/generator.js +939 -0
  167. package/dist/core/wiki/graph-queries.d.ts +80 -0
  168. package/dist/core/wiki/graph-queries.js +238 -0
  169. package/dist/core/wiki/html-viewer.d.ts +10 -0
  170. package/dist/core/wiki/html-viewer.js +297 -0
  171. package/dist/core/wiki/llm-client.d.ts +43 -0
  172. package/dist/core/wiki/llm-client.js +186 -0
  173. package/dist/core/wiki/prompts.d.ts +53 -0
  174. package/dist/core/wiki/prompts.js +174 -0
  175. package/dist/lib/utils.d.ts +1 -0
  176. package/dist/lib/utils.js +3 -0
  177. package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
  178. package/dist/mcp/compatible-stdio-transport.js +200 -0
  179. package/dist/mcp/core/embedder.d.ts +27 -0
  180. package/dist/mcp/core/embedder.js +108 -0
  181. package/dist/mcp/core/lbug-adapter.d.ts +57 -0
  182. package/dist/mcp/core/lbug-adapter.js +455 -0
  183. package/dist/mcp/local/local-backend.d.ts +181 -0
  184. package/dist/mcp/local/local-backend.js +1722 -0
  185. package/dist/mcp/resources.d.ts +31 -0
  186. package/dist/mcp/resources.js +411 -0
  187. package/dist/mcp/server.d.ts +23 -0
  188. package/dist/mcp/server.js +296 -0
  189. package/dist/mcp/staleness.d.ts +15 -0
  190. package/dist/mcp/staleness.js +29 -0
  191. package/dist/mcp/tools.d.ts +24 -0
  192. package/dist/mcp/tools.js +292 -0
  193. package/dist/server/api.d.ts +10 -0
  194. package/dist/server/api.js +344 -0
  195. package/dist/server/mcp-http.d.ts +13 -0
  196. package/dist/server/mcp-http.js +100 -0
  197. package/dist/storage/git.d.ts +6 -0
  198. package/dist/storage/git.js +35 -0
  199. package/dist/storage/repo-manager.d.ts +138 -0
  200. package/dist/storage/repo-manager.js +299 -0
  201. package/dist/types/pipeline.d.ts +32 -0
  202. package/dist/types/pipeline.js +18 -0
  203. package/dist/unreal/bridge.d.ts +4 -0
  204. package/dist/unreal/bridge.js +113 -0
  205. package/dist/unreal/config.d.ts +6 -0
  206. package/dist/unreal/config.js +55 -0
  207. package/dist/unreal/types.d.ts +105 -0
  208. package/dist/unreal/types.js +1 -0
  209. package/hooks/claude/gitnexus-hook.cjs +238 -0
  210. package/hooks/claude/pre-tool-use.sh +79 -0
  211. package/hooks/claude/session-start.sh +42 -0
  212. package/package.json +100 -0
  213. package/scripts/ensure-cli-executable.cjs +21 -0
  214. package/scripts/patch-tree-sitter-swift.cjs +74 -0
  215. package/scripts/setup-unreal-gitnexus.ps1 +191 -0
  216. package/skills/gitnexus-cli.md +82 -0
  217. package/skills/gitnexus-debugging.md +89 -0
  218. package/skills/gitnexus-exploring.md +78 -0
  219. package/skills/gitnexus-guide.md +64 -0
  220. package/skills/gitnexus-impact-analysis.md +97 -0
  221. package/skills/gitnexus-pr-review.md +163 -0
  222. package/skills/gitnexus-refactoring.md +121 -0
  223. package/vendor/leiden/index.cjs +355 -0
  224. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,681 @@
1
+ import { extractSimpleTypeName, extractVarName, findChildByType, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString } from './shared.js';
2
+ // ── Java ──────────────────────────────────────────────────────────────────
3
+ const JAVA_DECLARATION_NODE_TYPES = new Set([
4
+ 'local_variable_declaration',
5
+ 'field_declaration',
6
+ ]);
7
+ /** Java: Type x = ...; Type x; */
8
+ const extractJavaDeclaration = (node, env) => {
9
+ const typeNode = node.childForFieldName('type');
10
+ if (!typeNode)
11
+ return;
12
+ const typeName = extractSimpleTypeName(typeNode);
13
+ if (!typeName || typeName === 'var')
14
+ return; // skip Java 10 var — handled by extractInitializer
15
+ // Find variable_declarator children
16
+ for (let i = 0; i < node.namedChildCount; i++) {
17
+ const child = node.namedChild(i);
18
+ if (child?.type !== 'variable_declarator')
19
+ continue;
20
+ const nameNode = child.childForFieldName('name');
21
+ if (nameNode) {
22
+ const varName = extractVarName(nameNode);
23
+ if (varName)
24
+ env.set(varName, typeName);
25
+ }
26
+ }
27
+ };
28
+ /** Java 10+: var x = new User() — infer type from object_creation_expression */
29
+ const extractJavaInitializer = (node, env, _classNames) => {
30
+ for (let i = 0; i < node.namedChildCount; i++) {
31
+ const child = node.namedChild(i);
32
+ if (child?.type !== 'variable_declarator')
33
+ continue;
34
+ const nameNode = child.childForFieldName('name');
35
+ const valueNode = child.childForFieldName('value');
36
+ if (!nameNode || !valueNode)
37
+ continue;
38
+ // Skip declarators that already have a binding from extractDeclaration
39
+ const varName = extractVarName(nameNode);
40
+ if (!varName || env.has(varName))
41
+ continue;
42
+ if (valueNode.type !== 'object_creation_expression')
43
+ continue;
44
+ const ctorType = valueNode.childForFieldName('type');
45
+ if (!ctorType)
46
+ continue;
47
+ const typeName = extractSimpleTypeName(ctorType);
48
+ if (typeName)
49
+ env.set(varName, typeName);
50
+ }
51
+ };
52
+ /** Java: formal_parameter → type name */
53
+ const extractJavaParameter = (node, env) => {
54
+ let nameNode = null;
55
+ let typeNode = null;
56
+ if (node.type === 'formal_parameter') {
57
+ typeNode = node.childForFieldName('type');
58
+ nameNode = node.childForFieldName('name');
59
+ }
60
+ else {
61
+ // Generic fallback
62
+ nameNode = node.childForFieldName('name') ?? node.childForFieldName('pattern');
63
+ typeNode = node.childForFieldName('type');
64
+ }
65
+ if (!nameNode || !typeNode)
66
+ return;
67
+ const varName = extractVarName(nameNode);
68
+ const typeName = extractSimpleTypeName(typeNode);
69
+ if (varName && typeName)
70
+ env.set(varName, typeName);
71
+ };
72
+ /** Java: var x = SomeFactory.create() — constructor binding for `var` with method_invocation */
73
+ const scanJavaConstructorBinding = (node) => {
74
+ if (node.type !== 'local_variable_declaration')
75
+ return undefined;
76
+ const typeNode = node.childForFieldName('type');
77
+ if (!typeNode)
78
+ return undefined;
79
+ if (typeNode.text !== 'var')
80
+ return undefined;
81
+ const declarator = findChildByType(node, 'variable_declarator');
82
+ if (!declarator)
83
+ return undefined;
84
+ const nameNode = declarator.childForFieldName('name');
85
+ const value = declarator.childForFieldName('value');
86
+ if (!nameNode || !value)
87
+ return undefined;
88
+ if (value.type === 'object_creation_expression')
89
+ return undefined;
90
+ if (value.type !== 'method_invocation')
91
+ return undefined;
92
+ const methodName = value.childForFieldName('name');
93
+ if (!methodName)
94
+ return undefined;
95
+ return { varName: nameNode.text, calleeName: methodName.text };
96
+ };
97
+ const JAVA_FOR_LOOP_NODE_TYPES = new Set([
98
+ 'enhanced_for_statement',
99
+ ]);
100
+ /** Extract element type from a Java type annotation AST node.
101
+ * Handles generic_type (List<User>), array_type (User[]). */
102
+ const extractJavaElementTypeFromTypeNode = (typeNode, pos = 'last') => {
103
+ if (typeNode.type === 'generic_type') {
104
+ const args = extractGenericTypeArgs(typeNode);
105
+ if (args.length >= 1)
106
+ return pos === 'first' ? args[0] : args[args.length - 1];
107
+ }
108
+ if (typeNode.type === 'array_type') {
109
+ const elemNode = typeNode.firstNamedChild;
110
+ if (elemNode)
111
+ return extractSimpleTypeName(elemNode);
112
+ }
113
+ return undefined;
114
+ };
115
+ /** Walk up from a for-each to the enclosing method_declaration and search parameters. */
116
+ const findJavaParamElementType = (iterableName, startNode, pos = 'last') => {
117
+ let current = startNode.parent;
118
+ while (current) {
119
+ if (current.type === 'method_declaration' || current.type === 'constructor_declaration') {
120
+ const paramsNode = current.childForFieldName('parameters');
121
+ if (paramsNode) {
122
+ for (let i = 0; i < paramsNode.namedChildCount; i++) {
123
+ const param = paramsNode.namedChild(i);
124
+ if (!param || param.type !== 'formal_parameter')
125
+ continue;
126
+ const nameNode = param.childForFieldName('name');
127
+ if (nameNode?.text !== iterableName)
128
+ continue;
129
+ const typeNode = param.childForFieldName('type');
130
+ if (typeNode)
131
+ return extractJavaElementTypeFromTypeNode(typeNode, pos);
132
+ }
133
+ }
134
+ break;
135
+ }
136
+ current = current.parent;
137
+ }
138
+ return undefined;
139
+ };
140
+ /** Java: for (User user : users) — extract loop variable binding.
141
+ * Tier 1c: for `for (var user : users)`, resolves element type from iterable. */
142
+ const extractJavaForLoopBinding = (node, { scopeEnv, declarationTypeNodes, scope, returnTypeLookup }) => {
143
+ const typeNode = node.childForFieldName('type');
144
+ const nameNode = node.childForFieldName('name');
145
+ if (!typeNode || !nameNode)
146
+ return;
147
+ const varName = extractVarName(nameNode);
148
+ if (!varName)
149
+ return;
150
+ // Explicit type (existing behavior): for (User user : users)
151
+ const typeName = extractSimpleTypeName(typeNode);
152
+ if (typeName && typeName !== 'var') {
153
+ scopeEnv.set(varName, typeName);
154
+ return;
155
+ }
156
+ // Tier 1c: var — resolve from iterable's container type
157
+ const iterableNode = node.childForFieldName('value');
158
+ if (!iterableNode)
159
+ return;
160
+ let iterableName;
161
+ let methodName;
162
+ let callExprElementType;
163
+ if (iterableNode.type === 'identifier') {
164
+ iterableName = iterableNode.text;
165
+ }
166
+ else if (iterableNode.type === 'field_access') {
167
+ const field = iterableNode.childForFieldName('field');
168
+ if (field)
169
+ iterableName = field.text;
170
+ }
171
+ else if (iterableNode.type === 'method_invocation') {
172
+ // data.keySet() → method_invocation > object: identifier + name: identifier
173
+ // Also handles this.data.values() → object is field_access, extract inner field name
174
+ const obj = iterableNode.childForFieldName('object');
175
+ const name = iterableNode.childForFieldName('name');
176
+ if (obj?.type === 'identifier') {
177
+ iterableName = obj.text;
178
+ }
179
+ else if (obj?.type === 'field_access') {
180
+ const innerField = obj.childForFieldName('field');
181
+ if (innerField)
182
+ iterableName = innerField.text;
183
+ }
184
+ else if (!obj && name) {
185
+ // Direct function call: for (var u : getUsers()) — no receiver object
186
+ const rawReturn = returnTypeLookup.lookupRawReturnType(name.text);
187
+ if (rawReturn)
188
+ callExprElementType = extractElementTypeFromString(rawReturn);
189
+ }
190
+ if (name)
191
+ methodName = name.text;
192
+ }
193
+ if (!iterableName && !callExprElementType)
194
+ return;
195
+ let elementType;
196
+ if (callExprElementType) {
197
+ elementType = callExprElementType;
198
+ }
199
+ else {
200
+ const containerTypeName = scopeEnv.get(iterableName);
201
+ const typeArgPos = methodToTypeArgPosition(methodName, containerTypeName);
202
+ elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractJavaElementTypeFromTypeNode, findJavaParamElementType, typeArgPos);
203
+ }
204
+ if (elementType)
205
+ scopeEnv.set(varName, elementType);
206
+ };
207
+ /** Java: var alias = u → local_variable_declaration > variable_declarator with name/value */
208
+ const extractJavaPendingAssignment = (node, scopeEnv) => {
209
+ for (let i = 0; i < node.namedChildCount; i++) {
210
+ const child = node.namedChild(i);
211
+ if (!child || child.type !== 'variable_declarator')
212
+ continue;
213
+ const nameNode = child.childForFieldName('name');
214
+ const valueNode = child.childForFieldName('value');
215
+ if (!nameNode || !valueNode)
216
+ continue;
217
+ const lhs = nameNode.text;
218
+ if (scopeEnv.has(lhs))
219
+ continue;
220
+ if (valueNode.type === 'identifier' || valueNode.type === 'simple_identifier')
221
+ return { kind: 'copy', lhs, rhs: valueNode.text };
222
+ }
223
+ return undefined;
224
+ };
225
+ /**
226
+ * Java 16+ `instanceof` pattern variable: `x instanceof User user`
227
+ *
228
+ * AST structure:
229
+ * instanceof_expression
230
+ * left: expression (the variable being tested)
231
+ * instanceof keyword
232
+ * right: type (the type to test against)
233
+ * name: identifier (the pattern variable — optional, Java 16+)
234
+ *
235
+ * Conservative: returns undefined when the `name` field is absent (plain instanceof
236
+ * without pattern variable, e.g. `x instanceof User`) or when the type cannot be
237
+ * extracted. The source variable's existing type is NOT used — the pattern explicitly
238
+ * declares the new type, so no scopeEnv lookup is needed.
239
+ */
240
+ const extractJavaPatternBinding = (node) => {
241
+ if (node.type === 'type_pattern') {
242
+ // Java 17+ switch pattern: case User u -> ...
243
+ // type_pattern has positional children (NO named fields):
244
+ // namedChild(0) = type (type_identifier, e.g., User)
245
+ // namedChild(1) = identifier (e.g., u)
246
+ const typeNode = node.namedChild(0);
247
+ const nameNode = node.namedChild(1);
248
+ if (!typeNode || !nameNode)
249
+ return undefined;
250
+ const typeName = extractSimpleTypeName(typeNode);
251
+ const varName = extractVarName(nameNode);
252
+ if (!typeName || !varName)
253
+ return undefined;
254
+ return { varName, typeName };
255
+ }
256
+ if (node.type !== 'instanceof_expression')
257
+ return undefined;
258
+ const nameNode = node.childForFieldName('name');
259
+ if (!nameNode)
260
+ return undefined;
261
+ const typeNode = node.childForFieldName('right');
262
+ if (!typeNode)
263
+ return undefined;
264
+ const typeName = extractSimpleTypeName(typeNode);
265
+ const varName = extractVarName(nameNode);
266
+ if (!typeName || !varName)
267
+ return undefined;
268
+ return { varName, typeName };
269
+ };
270
+ export const javaTypeConfig = {
271
+ declarationNodeTypes: JAVA_DECLARATION_NODE_TYPES,
272
+ forLoopNodeTypes: JAVA_FOR_LOOP_NODE_TYPES,
273
+ patternBindingNodeTypes: new Set(['instanceof_expression', 'type_pattern']),
274
+ extractDeclaration: extractJavaDeclaration,
275
+ extractParameter: extractJavaParameter,
276
+ extractInitializer: extractJavaInitializer,
277
+ scanConstructorBinding: scanJavaConstructorBinding,
278
+ extractForLoopBinding: extractJavaForLoopBinding,
279
+ extractPendingAssignment: extractJavaPendingAssignment,
280
+ extractPatternBinding: extractJavaPatternBinding,
281
+ };
282
+ // ── Kotlin ────────────────────────────────────────────────────────────────
283
+ const KOTLIN_DECLARATION_NODE_TYPES = new Set([
284
+ 'property_declaration',
285
+ 'variable_declaration',
286
+ ]);
287
+ /** Kotlin: val x: Foo = ... */
288
+ const extractKotlinDeclaration = (node, env) => {
289
+ if (node.type === 'property_declaration') {
290
+ // Kotlin property_declaration: name/type are inside a variable_declaration child
291
+ const varDecl = findChildByType(node, 'variable_declaration');
292
+ if (varDecl) {
293
+ const nameNode = findChildByType(varDecl, 'simple_identifier');
294
+ const typeNode = findChildByType(varDecl, 'user_type');
295
+ if (!nameNode || !typeNode)
296
+ return;
297
+ const varName = extractVarName(nameNode);
298
+ const typeName = extractSimpleTypeName(typeNode);
299
+ if (varName && typeName)
300
+ env.set(varName, typeName);
301
+ return;
302
+ }
303
+ // Fallback: try direct fields
304
+ const nameNode = node.childForFieldName('name')
305
+ ?? findChildByType(node, 'simple_identifier');
306
+ const typeNode = node.childForFieldName('type')
307
+ ?? findChildByType(node, 'user_type');
308
+ if (!nameNode || !typeNode)
309
+ return;
310
+ const varName = extractVarName(nameNode);
311
+ const typeName = extractSimpleTypeName(typeNode);
312
+ if (varName && typeName)
313
+ env.set(varName, typeName);
314
+ }
315
+ else if (node.type === 'variable_declaration') {
316
+ // variable_declaration directly inside functions
317
+ const nameNode = findChildByType(node, 'simple_identifier');
318
+ const typeNode = findChildByType(node, 'user_type');
319
+ if (nameNode && typeNode) {
320
+ const varName = extractVarName(nameNode);
321
+ const typeName = extractSimpleTypeName(typeNode);
322
+ if (varName && typeName)
323
+ env.set(varName, typeName);
324
+ }
325
+ }
326
+ };
327
+ /** Kotlin: parameter / formal_parameter → type name.
328
+ * Kotlin's tree-sitter grammar uses positional children (simple_identifier, user_type)
329
+ * rather than named fields (name, type) on `parameter` nodes, so we fall back to
330
+ * findChildByType when childForFieldName returns null. */
331
+ const extractKotlinParameter = (node, env) => {
332
+ let nameNode = null;
333
+ let typeNode = null;
334
+ if (node.type === 'formal_parameter') {
335
+ typeNode = node.childForFieldName('type');
336
+ nameNode = node.childForFieldName('name');
337
+ }
338
+ else {
339
+ nameNode = node.childForFieldName('name') ?? node.childForFieldName('pattern');
340
+ typeNode = node.childForFieldName('type');
341
+ }
342
+ // Fallback: Kotlin `parameter` nodes use positional children, not named fields
343
+ if (!nameNode)
344
+ nameNode = findChildByType(node, 'simple_identifier');
345
+ if (!typeNode)
346
+ typeNode = findChildByType(node, 'user_type');
347
+ if (!nameNode || !typeNode)
348
+ return;
349
+ const varName = extractVarName(nameNode);
350
+ const typeName = extractSimpleTypeName(typeNode);
351
+ if (varName && typeName)
352
+ env.set(varName, typeName);
353
+ };
354
+ /** Kotlin: val user = User() — infer type from call_expression when callee is a known class.
355
+ * Kotlin constructors are syntactically identical to function calls, so we verify
356
+ * against classNames (which may include cross-file SymbolTable lookups). */
357
+ const extractKotlinInitializer = (node, env, classNames) => {
358
+ if (node.type !== 'property_declaration')
359
+ return;
360
+ // Skip if there's an explicit type annotation — Tier 0 already handled it
361
+ const varDecl = findChildByType(node, 'variable_declaration');
362
+ if (varDecl && findChildByType(varDecl, 'user_type'))
363
+ return;
364
+ // Get the initializer value — the call_expression after '='
365
+ const value = node.childForFieldName('value')
366
+ ?? findChildByType(node, 'call_expression');
367
+ if (!value || value.type !== 'call_expression')
368
+ return;
369
+ // The callee is the first child of call_expression (simple_identifier for direct calls)
370
+ const callee = value.firstNamedChild;
371
+ if (!callee || callee.type !== 'simple_identifier')
372
+ return;
373
+ const calleeName = callee.text;
374
+ if (!calleeName || !classNames.has(calleeName))
375
+ return;
376
+ // Extract the variable name from the variable_declaration inside property_declaration
377
+ const nameNode = varDecl
378
+ ? findChildByType(varDecl, 'simple_identifier')
379
+ : findChildByType(node, 'simple_identifier');
380
+ if (!nameNode)
381
+ return;
382
+ const varName = extractVarName(nameNode);
383
+ if (varName)
384
+ env.set(varName, calleeName);
385
+ };
386
+ /** Kotlin: val x = User(...) — constructor binding for property_declaration with call_expression */
387
+ const scanKotlinConstructorBinding = (node) => {
388
+ if (node.type !== 'property_declaration')
389
+ return undefined;
390
+ const varDecl = findChildByType(node, 'variable_declaration');
391
+ if (!varDecl)
392
+ return undefined;
393
+ if (findChildByType(varDecl, 'user_type'))
394
+ return undefined;
395
+ const callExpr = findChildByType(node, 'call_expression');
396
+ if (!callExpr)
397
+ return undefined;
398
+ const callee = callExpr.firstNamedChild;
399
+ if (!callee)
400
+ return undefined;
401
+ let calleeName;
402
+ if (callee.type === 'simple_identifier') {
403
+ calleeName = callee.text;
404
+ }
405
+ else if (callee.type === 'navigation_expression') {
406
+ // Extract method name from qualified call: service.getUser() → getUser
407
+ const suffix = callee.lastNamedChild;
408
+ if (suffix?.type === 'navigation_suffix') {
409
+ const methodName = suffix.lastNamedChild;
410
+ if (methodName?.type === 'simple_identifier') {
411
+ calleeName = methodName.text;
412
+ }
413
+ }
414
+ }
415
+ if (!calleeName)
416
+ return undefined;
417
+ const nameNode = findChildByType(varDecl, 'simple_identifier');
418
+ if (!nameNode)
419
+ return undefined;
420
+ return { varName: nameNode.text, calleeName };
421
+ };
422
+ const KOTLIN_FOR_LOOP_NODE_TYPES = new Set([
423
+ 'for_statement',
424
+ ]);
425
+ /** Extract element type from a Kotlin type annotation AST node (user_type wrapping generic).
426
+ * Kotlin: user_type → [type_identifier, type_arguments → [type_projection → user_type]]
427
+ * Handles the type_projection wrapper that Kotlin uses for generic type arguments. */
428
+ const extractKotlinElementTypeFromTypeNode = (typeNode, pos = 'last') => {
429
+ if (typeNode.type === 'user_type') {
430
+ const argsNode = findChildByType(typeNode, 'type_arguments');
431
+ if (argsNode && argsNode.namedChildCount >= 1) {
432
+ const targetArg = pos === 'first'
433
+ ? argsNode.namedChild(0)
434
+ : argsNode.namedChild(argsNode.namedChildCount - 1);
435
+ if (!targetArg)
436
+ return undefined;
437
+ // Kotlin wraps type args in type_projection — unwrap to get the inner type
438
+ const inner = targetArg.type === 'type_projection'
439
+ ? targetArg.firstNamedChild
440
+ : targetArg;
441
+ if (inner)
442
+ return extractSimpleTypeName(inner);
443
+ }
444
+ }
445
+ return undefined;
446
+ };
447
+ /** Walk up from a for-loop to the enclosing function_declaration and search parameters.
448
+ * Kotlin parameters use positional children (simple_identifier, user_type), not named fields. */
449
+ const findKotlinParamElementType = (iterableName, startNode, pos = 'last') => {
450
+ let current = startNode.parent;
451
+ while (current) {
452
+ if (current.type === 'function_declaration') {
453
+ const paramsNode = findChildByType(current, 'function_value_parameters');
454
+ if (paramsNode) {
455
+ for (let i = 0; i < paramsNode.namedChildCount; i++) {
456
+ const param = paramsNode.namedChild(i);
457
+ if (!param || param.type !== 'parameter')
458
+ continue;
459
+ const nameNode = findChildByType(param, 'simple_identifier');
460
+ if (nameNode?.text !== iterableName)
461
+ continue;
462
+ const typeNode = findChildByType(param, 'user_type');
463
+ if (typeNode)
464
+ return extractKotlinElementTypeFromTypeNode(typeNode, pos);
465
+ }
466
+ }
467
+ break;
468
+ }
469
+ current = current.parent;
470
+ }
471
+ return undefined;
472
+ };
473
+ /** Kotlin: for (user: User in users) — extract loop variable binding.
474
+ * Tier 1c: for `for (user in users)` without annotation, resolves from iterable. */
475
+ const extractKotlinForLoopBinding = (node, ctx) => {
476
+ const { scopeEnv, declarationTypeNodes, scope, returnTypeLookup } = ctx;
477
+ const varDecl = findChildByType(node, 'variable_declaration');
478
+ if (!varDecl)
479
+ return;
480
+ const nameNode = findChildByType(varDecl, 'simple_identifier');
481
+ if (!nameNode)
482
+ return;
483
+ const varName = extractVarName(nameNode);
484
+ if (!varName)
485
+ return;
486
+ // Explicit type annotation (existing behavior): for (user: User in users)
487
+ const typeNode = findChildByType(varDecl, 'user_type');
488
+ if (typeNode) {
489
+ const typeName = extractSimpleTypeName(typeNode);
490
+ if (typeName)
491
+ scopeEnv.set(varName, typeName);
492
+ return;
493
+ }
494
+ // Tier 1c: no annotation — resolve from iterable's container type
495
+ // Kotlin for-loop children: [variable_declaration, iterable_expr, control_structure_body]
496
+ // The iterable is the second named child of the for_statement (after variable_declaration)
497
+ let iterableName;
498
+ let methodName;
499
+ let fallbackIterableName;
500
+ let callExprElementType;
501
+ let foundVarDecl = false;
502
+ for (let i = 0; i < node.namedChildCount; i++) {
503
+ const child = node.namedChild(i);
504
+ if (child === varDecl) {
505
+ foundVarDecl = true;
506
+ continue;
507
+ }
508
+ if (!foundVarDecl || !child)
509
+ continue;
510
+ if (child.type === 'simple_identifier') {
511
+ iterableName = child.text;
512
+ break;
513
+ }
514
+ if (child.type === 'navigation_expression') {
515
+ // data.keys → navigation_expression > simple_identifier(data) + navigation_suffix > simple_identifier(keys)
516
+ const obj = child.firstNamedChild;
517
+ const suffix = findChildByType(child, 'navigation_suffix');
518
+ const prop = suffix ? findChildByType(suffix, 'simple_identifier') : null;
519
+ const hasCallSuffix = suffix ? findChildByType(suffix, 'call_suffix') !== null : false;
520
+ // Always try object as iterable + property as method first (handles data.values, data.keys).
521
+ // For bare property access without call_suffix, also save property as fallback
522
+ // (handles this.users, repo.items where the property IS the iterable).
523
+ if (obj?.type === 'simple_identifier')
524
+ iterableName = obj.text;
525
+ if (prop)
526
+ methodName = prop.text;
527
+ if (!hasCallSuffix && prop) {
528
+ fallbackIterableName = prop.text;
529
+ }
530
+ break;
531
+ }
532
+ if (child.type === 'call_expression') {
533
+ // data.values() → call_expression > navigation_expression > simple_identifier + navigation_suffix
534
+ const callee = child.firstNamedChild;
535
+ if (callee?.type === 'navigation_expression') {
536
+ const obj = callee.firstNamedChild;
537
+ if (obj?.type === 'simple_identifier')
538
+ iterableName = obj.text;
539
+ const suffix = findChildByType(callee, 'navigation_suffix');
540
+ if (suffix) {
541
+ const prop = findChildByType(suffix, 'simple_identifier');
542
+ if (prop)
543
+ methodName = prop.text;
544
+ }
545
+ }
546
+ else if (callee?.type === 'simple_identifier') {
547
+ // Direct function call: for (u in getUsers())
548
+ const rawReturn = returnTypeLookup.lookupRawReturnType(callee.text);
549
+ if (rawReturn)
550
+ callExprElementType = extractElementTypeFromString(rawReturn);
551
+ }
552
+ break;
553
+ }
554
+ }
555
+ if (!iterableName && !callExprElementType)
556
+ return;
557
+ let elementType;
558
+ if (callExprElementType) {
559
+ elementType = callExprElementType;
560
+ }
561
+ else {
562
+ let containerTypeName = scopeEnv.get(iterableName);
563
+ // Fallback: if object has no type in scope, try the property as the iterable name.
564
+ // Handles patterns like this.users where the property itself is the iterable variable.
565
+ if (!containerTypeName && fallbackIterableName) {
566
+ iterableName = fallbackIterableName;
567
+ methodName = undefined;
568
+ containerTypeName = scopeEnv.get(iterableName);
569
+ }
570
+ const typeArgPos = methodToTypeArgPosition(methodName, containerTypeName);
571
+ elementType = resolveIterableElementType(iterableName, node, scopeEnv, declarationTypeNodes, scope, extractKotlinElementTypeFromTypeNode, findKotlinParamElementType, typeArgPos);
572
+ }
573
+ if (elementType)
574
+ scopeEnv.set(varName, elementType);
575
+ };
576
+ /** Kotlin: val alias = u → property_declaration or variable_declaration.
577
+ * property_declaration has: binding_pattern_kind("val"), variable_declaration("alias"),
578
+ * "=", and the RHS value (simple_identifier "u").
579
+ * variable_declaration appears directly inside functions and has simple_identifier children. */
580
+ const extractKotlinPendingAssignment = (node, scopeEnv) => {
581
+ if (node.type === 'property_declaration') {
582
+ // Find the variable name from variable_declaration child
583
+ const varDecl = findChildByType(node, 'variable_declaration');
584
+ if (!varDecl)
585
+ return undefined;
586
+ const nameNode = varDecl.firstNamedChild;
587
+ if (!nameNode || nameNode.type !== 'simple_identifier')
588
+ return undefined;
589
+ const lhs = nameNode.text;
590
+ if (scopeEnv.has(lhs))
591
+ return undefined;
592
+ // Find the RHS: a simple_identifier sibling after the "=" token
593
+ let foundEq = false;
594
+ for (let i = 0; i < node.childCount; i++) {
595
+ const child = node.child(i);
596
+ if (!child)
597
+ continue;
598
+ if (child.type === '=') {
599
+ foundEq = true;
600
+ continue;
601
+ }
602
+ if (foundEq && child.type === 'simple_identifier') {
603
+ return { kind: 'copy', lhs, rhs: child.text };
604
+ }
605
+ }
606
+ return undefined;
607
+ }
608
+ if (node.type === 'variable_declaration') {
609
+ // variable_declaration directly inside functions: simple_identifier children
610
+ const nameNode = findChildByType(node, 'simple_identifier');
611
+ if (!nameNode)
612
+ return undefined;
613
+ const lhs = nameNode.text;
614
+ if (scopeEnv.has(lhs))
615
+ return undefined;
616
+ // Look for RHS simple_identifier after "=" in the parent (property_declaration)
617
+ // variable_declaration itself doesn't contain "=" — it's in the parent
618
+ const parent = node.parent;
619
+ if (!parent)
620
+ return undefined;
621
+ let foundEq = false;
622
+ for (let i = 0; i < parent.childCount; i++) {
623
+ const child = parent.child(i);
624
+ if (!child)
625
+ continue;
626
+ if (child.type === '=') {
627
+ foundEq = true;
628
+ continue;
629
+ }
630
+ if (foundEq && child.type === 'simple_identifier') {
631
+ return { kind: 'copy', lhs, rhs: child.text };
632
+ }
633
+ }
634
+ return undefined;
635
+ }
636
+ return undefined;
637
+ };
638
+ /** Walk up from a node to find an ancestor of a given type. */
639
+ const findAncestorByType = (node, type) => {
640
+ let current = node.parent;
641
+ while (current) {
642
+ if (current.type === type)
643
+ return current;
644
+ current = current.parent;
645
+ }
646
+ return undefined;
647
+ };
648
+ const extractKotlinPatternBinding = (node) => {
649
+ if (node.type !== 'type_test')
650
+ return undefined;
651
+ const typeNode = node.lastNamedChild;
652
+ if (!typeNode)
653
+ return undefined;
654
+ const typeName = extractSimpleTypeName(typeNode);
655
+ if (!typeName)
656
+ return undefined;
657
+ const whenExpr = findAncestorByType(node, 'when_expression');
658
+ if (!whenExpr)
659
+ return undefined;
660
+ const whenSubject = whenExpr.namedChild(0);
661
+ const subject = whenSubject?.firstNamedChild ?? whenSubject;
662
+ if (!subject)
663
+ return undefined;
664
+ const varName = extractVarName(subject);
665
+ if (!varName)
666
+ return undefined;
667
+ return { varName, typeName };
668
+ };
669
+ export const kotlinTypeConfig = {
670
+ allowPatternBindingOverwrite: true,
671
+ declarationNodeTypes: KOTLIN_DECLARATION_NODE_TYPES,
672
+ forLoopNodeTypes: KOTLIN_FOR_LOOP_NODE_TYPES,
673
+ patternBindingNodeTypes: new Set(['type_test']),
674
+ extractDeclaration: extractKotlinDeclaration,
675
+ extractParameter: extractKotlinParameter,
676
+ extractInitializer: extractKotlinInitializer,
677
+ scanConstructorBinding: scanKotlinConstructorBinding,
678
+ extractForLoopBinding: extractKotlinForLoopBinding,
679
+ extractPendingAssignment: extractKotlinPendingAssignment,
680
+ extractPatternBinding: extractKotlinPatternBinding,
681
+ };
@@ -0,0 +1,2 @@
1
+ import type { LanguageTypeConfig } from './types.js';
2
+ export declare const typeConfig: LanguageTypeConfig;