@zuvia-software-solutions/code-mapper 1.4.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 (213) hide show
  1. package/README.md +215 -0
  2. package/dist/cli/ai-context.d.ts +19 -0
  3. package/dist/cli/ai-context.js +168 -0
  4. package/dist/cli/analyze.d.ts +7 -0
  5. package/dist/cli/analyze.js +325 -0
  6. package/dist/cli/augment.d.ts +7 -0
  7. package/dist/cli/augment.js +27 -0
  8. package/dist/cli/clean.d.ts +5 -0
  9. package/dist/cli/clean.js +56 -0
  10. package/dist/cli/eval-server.d.ts +25 -0
  11. package/dist/cli/eval-server.js +365 -0
  12. package/dist/cli/index.d.ts +6 -0
  13. package/dist/cli/index.js +102 -0
  14. package/dist/cli/lazy-action.d.ts +6 -0
  15. package/dist/cli/lazy-action.js +19 -0
  16. package/dist/cli/list.d.ts +2 -0
  17. package/dist/cli/list.js +27 -0
  18. package/dist/cli/mcp.d.ts +8 -0
  19. package/dist/cli/mcp.js +35 -0
  20. package/dist/cli/refresh.d.ts +12 -0
  21. package/dist/cli/refresh.js +165 -0
  22. package/dist/cli/serve.d.ts +5 -0
  23. package/dist/cli/serve.js +8 -0
  24. package/dist/cli/setup.d.ts +6 -0
  25. package/dist/cli/setup.js +218 -0
  26. package/dist/cli/status.d.ts +2 -0
  27. package/dist/cli/status.js +33 -0
  28. package/dist/cli/tool.d.ts +28 -0
  29. package/dist/cli/tool.js +87 -0
  30. package/dist/config/ignore-service.d.ts +32 -0
  31. package/dist/config/ignore-service.js +282 -0
  32. package/dist/config/supported-languages.d.ts +23 -0
  33. package/dist/config/supported-languages.js +52 -0
  34. package/dist/core/augmentation/engine.d.ts +22 -0
  35. package/dist/core/augmentation/engine.js +232 -0
  36. package/dist/core/embeddings/embedder.d.ts +35 -0
  37. package/dist/core/embeddings/embedder.js +171 -0
  38. package/dist/core/embeddings/embedding-pipeline.d.ts +41 -0
  39. package/dist/core/embeddings/embedding-pipeline.js +402 -0
  40. package/dist/core/embeddings/index.d.ts +5 -0
  41. package/dist/core/embeddings/index.js +6 -0
  42. package/dist/core/embeddings/text-generator.d.ts +20 -0
  43. package/dist/core/embeddings/text-generator.js +159 -0
  44. package/dist/core/embeddings/types.d.ts +60 -0
  45. package/dist/core/embeddings/types.js +23 -0
  46. package/dist/core/graph/graph.d.ts +4 -0
  47. package/dist/core/graph/graph.js +65 -0
  48. package/dist/core/graph/types.d.ts +69 -0
  49. package/dist/core/graph/types.js +3 -0
  50. package/dist/core/incremental/child-process.d.ts +8 -0
  51. package/dist/core/incremental/child-process.js +649 -0
  52. package/dist/core/incremental/refresh-coordinator.d.ts +32 -0
  53. package/dist/core/incremental/refresh-coordinator.js +147 -0
  54. package/dist/core/incremental/types.d.ts +78 -0
  55. package/dist/core/incremental/types.js +153 -0
  56. package/dist/core/incremental/watcher.d.ts +63 -0
  57. package/dist/core/incremental/watcher.js +338 -0
  58. package/dist/core/ingestion/ast-cache.d.ts +12 -0
  59. package/dist/core/ingestion/ast-cache.js +34 -0
  60. package/dist/core/ingestion/call-processor.d.ts +34 -0
  61. package/dist/core/ingestion/call-processor.js +937 -0
  62. package/dist/core/ingestion/call-routing.d.ts +40 -0
  63. package/dist/core/ingestion/call-routing.js +97 -0
  64. package/dist/core/ingestion/cluster-enricher.d.ts +30 -0
  65. package/dist/core/ingestion/cluster-enricher.js +151 -0
  66. package/dist/core/ingestion/community-processor.d.ts +26 -0
  67. package/dist/core/ingestion/community-processor.js +272 -0
  68. package/dist/core/ingestion/constants.d.ts +5 -0
  69. package/dist/core/ingestion/constants.js +8 -0
  70. package/dist/core/ingestion/entry-point-scoring.d.ts +23 -0
  71. package/dist/core/ingestion/entry-point-scoring.js +317 -0
  72. package/dist/core/ingestion/export-detection.d.ts +11 -0
  73. package/dist/core/ingestion/export-detection.js +203 -0
  74. package/dist/core/ingestion/filesystem-walker.d.ts +18 -0
  75. package/dist/core/ingestion/filesystem-walker.js +64 -0
  76. package/dist/core/ingestion/framework-detection.d.ts +42 -0
  77. package/dist/core/ingestion/framework-detection.js +405 -0
  78. package/dist/core/ingestion/heritage-processor.d.ts +15 -0
  79. package/dist/core/ingestion/heritage-processor.js +237 -0
  80. package/dist/core/ingestion/import-processor.d.ts +31 -0
  81. package/dist/core/ingestion/import-processor.js +416 -0
  82. package/dist/core/ingestion/language-config.d.ts +32 -0
  83. package/dist/core/ingestion/language-config.js +161 -0
  84. package/dist/core/ingestion/mro-processor.d.ts +32 -0
  85. package/dist/core/ingestion/mro-processor.js +343 -0
  86. package/dist/core/ingestion/named-binding-extraction.d.ts +51 -0
  87. package/dist/core/ingestion/named-binding-extraction.js +343 -0
  88. package/dist/core/ingestion/parsing-processor.d.ts +20 -0
  89. package/dist/core/ingestion/parsing-processor.js +282 -0
  90. package/dist/core/ingestion/pipeline.d.ts +3 -0
  91. package/dist/core/ingestion/pipeline.js +416 -0
  92. package/dist/core/ingestion/process-processor.d.ts +42 -0
  93. package/dist/core/ingestion/process-processor.js +357 -0
  94. package/dist/core/ingestion/resolution-context.d.ts +40 -0
  95. package/dist/core/ingestion/resolution-context.js +171 -0
  96. package/dist/core/ingestion/resolvers/csharp.d.ts +10 -0
  97. package/dist/core/ingestion/resolvers/csharp.js +101 -0
  98. package/dist/core/ingestion/resolvers/go.d.ts +8 -0
  99. package/dist/core/ingestion/resolvers/go.js +33 -0
  100. package/dist/core/ingestion/resolvers/index.d.ts +14 -0
  101. package/dist/core/ingestion/resolvers/index.js +10 -0
  102. package/dist/core/ingestion/resolvers/jvm.d.ts +9 -0
  103. package/dist/core/ingestion/resolvers/jvm.js +74 -0
  104. package/dist/core/ingestion/resolvers/php.d.ts +7 -0
  105. package/dist/core/ingestion/resolvers/php.js +30 -0
  106. package/dist/core/ingestion/resolvers/ruby.d.ts +9 -0
  107. package/dist/core/ingestion/resolvers/ruby.js +13 -0
  108. package/dist/core/ingestion/resolvers/rust.d.ts +5 -0
  109. package/dist/core/ingestion/resolvers/rust.js +62 -0
  110. package/dist/core/ingestion/resolvers/standard.d.ts +16 -0
  111. package/dist/core/ingestion/resolvers/standard.js +144 -0
  112. package/dist/core/ingestion/resolvers/utils.d.ts +18 -0
  113. package/dist/core/ingestion/resolvers/utils.js +113 -0
  114. package/dist/core/ingestion/structure-processor.d.ts +4 -0
  115. package/dist/core/ingestion/structure-processor.js +39 -0
  116. package/dist/core/ingestion/symbol-table.d.ts +34 -0
  117. package/dist/core/ingestion/symbol-table.js +48 -0
  118. package/dist/core/ingestion/tree-sitter-queries.d.ts +20 -0
  119. package/dist/core/ingestion/tree-sitter-queries.js +691 -0
  120. package/dist/core/ingestion/type-env.d.ts +52 -0
  121. package/dist/core/ingestion/type-env.js +349 -0
  122. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +4 -0
  123. package/dist/core/ingestion/type-extractors/c-cpp.js +214 -0
  124. package/dist/core/ingestion/type-extractors/csharp.d.ts +4 -0
  125. package/dist/core/ingestion/type-extractors/csharp.js +224 -0
  126. package/dist/core/ingestion/type-extractors/go.d.ts +4 -0
  127. package/dist/core/ingestion/type-extractors/go.js +261 -0
  128. package/dist/core/ingestion/type-extractors/index.d.ts +20 -0
  129. package/dist/core/ingestion/type-extractors/index.js +30 -0
  130. package/dist/core/ingestion/type-extractors/jvm.d.ts +5 -0
  131. package/dist/core/ingestion/type-extractors/jvm.js +386 -0
  132. package/dist/core/ingestion/type-extractors/php.d.ts +4 -0
  133. package/dist/core/ingestion/type-extractors/php.js +280 -0
  134. package/dist/core/ingestion/type-extractors/python.d.ts +4 -0
  135. package/dist/core/ingestion/type-extractors/python.js +175 -0
  136. package/dist/core/ingestion/type-extractors/ruby.d.ts +12 -0
  137. package/dist/core/ingestion/type-extractors/ruby.js +218 -0
  138. package/dist/core/ingestion/type-extractors/rust.d.ts +4 -0
  139. package/dist/core/ingestion/type-extractors/rust.js +290 -0
  140. package/dist/core/ingestion/type-extractors/shared.d.ts +81 -0
  141. package/dist/core/ingestion/type-extractors/shared.js +322 -0
  142. package/dist/core/ingestion/type-extractors/swift.d.ts +4 -0
  143. package/dist/core/ingestion/type-extractors/swift.js +140 -0
  144. package/dist/core/ingestion/type-extractors/types.d.ts +111 -0
  145. package/dist/core/ingestion/type-extractors/types.js +4 -0
  146. package/dist/core/ingestion/type-extractors/typescript.d.ts +4 -0
  147. package/dist/core/ingestion/type-extractors/typescript.js +227 -0
  148. package/dist/core/ingestion/utils.d.ts +73 -0
  149. package/dist/core/ingestion/utils.js +992 -0
  150. package/dist/core/ingestion/workers/parse-worker.d.ts +99 -0
  151. package/dist/core/ingestion/workers/parse-worker.js +1055 -0
  152. package/dist/core/ingestion/workers/worker-pool.d.ts +15 -0
  153. package/dist/core/ingestion/workers/worker-pool.js +123 -0
  154. package/dist/core/lbug/csv-generator.d.ts +28 -0
  155. package/dist/core/lbug/csv-generator.js +355 -0
  156. package/dist/core/lbug/lbug-adapter.d.ts +96 -0
  157. package/dist/core/lbug/lbug-adapter.js +753 -0
  158. package/dist/core/lbug/schema.d.ts +46 -0
  159. package/dist/core/lbug/schema.js +402 -0
  160. package/dist/core/search/bm25-index.d.ts +20 -0
  161. package/dist/core/search/bm25-index.js +123 -0
  162. package/dist/core/search/hybrid-search.d.ts +32 -0
  163. package/dist/core/search/hybrid-search.js +131 -0
  164. package/dist/core/search/query-cache.d.ts +18 -0
  165. package/dist/core/search/query-cache.js +47 -0
  166. package/dist/core/search/query-expansion.d.ts +19 -0
  167. package/dist/core/search/query-expansion.js +75 -0
  168. package/dist/core/search/reranker.d.ts +29 -0
  169. package/dist/core/search/reranker.js +122 -0
  170. package/dist/core/search/types.d.ts +154 -0
  171. package/dist/core/search/types.js +51 -0
  172. package/dist/core/semantic/tsgo-service.d.ts +67 -0
  173. package/dist/core/semantic/tsgo-service.js +355 -0
  174. package/dist/core/tree-sitter/parser-loader.d.ts +12 -0
  175. package/dist/core/tree-sitter/parser-loader.js +71 -0
  176. package/dist/lib/memory-guard.d.ts +35 -0
  177. package/dist/lib/memory-guard.js +70 -0
  178. package/dist/lib/utils.d.ts +3 -0
  179. package/dist/lib/utils.js +6 -0
  180. package/dist/mcp/compatible-stdio-transport.d.ts +32 -0
  181. package/dist/mcp/compatible-stdio-transport.js +209 -0
  182. package/dist/mcp/core/embedder.d.ts +24 -0
  183. package/dist/mcp/core/embedder.js +168 -0
  184. package/dist/mcp/core/lbug-adapter.d.ts +29 -0
  185. package/dist/mcp/core/lbug-adapter.js +330 -0
  186. package/dist/mcp/local/local-backend.d.ts +188 -0
  187. package/dist/mcp/local/local-backend.js +2759 -0
  188. package/dist/mcp/resources.d.ts +22 -0
  189. package/dist/mcp/resources.js +379 -0
  190. package/dist/mcp/server.d.ts +10 -0
  191. package/dist/mcp/server.js +217 -0
  192. package/dist/mcp/staleness.d.ts +10 -0
  193. package/dist/mcp/staleness.js +25 -0
  194. package/dist/mcp/tools.d.ts +21 -0
  195. package/dist/mcp/tools.js +202 -0
  196. package/dist/server/api.d.ts +5 -0
  197. package/dist/server/api.js +340 -0
  198. package/dist/server/mcp-http.d.ts +7 -0
  199. package/dist/server/mcp-http.js +95 -0
  200. package/dist/storage/git.d.ts +6 -0
  201. package/dist/storage/git.js +35 -0
  202. package/dist/storage/repo-manager.d.ts +87 -0
  203. package/dist/storage/repo-manager.js +249 -0
  204. package/dist/types/pipeline.d.ts +35 -0
  205. package/dist/types/pipeline.js +20 -0
  206. package/hooks/claude/code-mapper-hook.cjs +238 -0
  207. package/hooks/claude/pre-tool-use.sh +79 -0
  208. package/hooks/claude/session-start.sh +42 -0
  209. package/models/mlx-embedder.py +185 -0
  210. package/package.json +100 -0
  211. package/scripts/patch-tree-sitter-swift.cjs +74 -0
  212. package/vendor/leiden/index.cjs +355 -0
  213. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,322 @@
1
+ // code-mapper/src/core/ingestion/type-extractors/shared.ts
2
+ /** @file shared.ts
3
+ * @description Shared utilities for type extraction across all languages */
4
+ // Nullable wrapper types that unwrap to their inner type for receiver resolution
5
+ // e.g. Optional<User> -> "User", Option<User> -> "User"
6
+ // Only nullable wrappers -- NOT containers (List, Vec) or async wrappers (Promise, Future)
7
+ // See call-processor.ts WRAPPER_GENERICS for the full set used in return-type inference
8
+ const NULLABLE_WRAPPER_TYPES = new Set([
9
+ 'Optional', // Java
10
+ 'Option', // Rust, Scala
11
+ 'Maybe', // Haskell-style, Kotlin Arrow
12
+ ]);
13
+ /**
14
+ * Extract the simple type name from a type AST node
15
+ *
16
+ * Handles generic types (List<User> -> List), qualified names (models.User -> User),
17
+ * and nullable types (User? -> User). Returns undefined for complex types
18
+ */
19
+ export const extractSimpleTypeName = (typeNode) => {
20
+ // Direct type identifier (includes Ruby 'constant' for class names)
21
+ if (typeNode.type === 'type_identifier' || typeNode.type === 'identifier'
22
+ || typeNode.type === 'simple_identifier' || typeNode.type === 'constant') {
23
+ return typeNode.text;
24
+ }
25
+ // Qualified/scoped names: take the last segment (e.g. models.User -> User, Models::User -> User)
26
+ if (typeNode.type === 'scoped_identifier' || typeNode.type === 'qualified_identifier'
27
+ || typeNode.type === 'scoped_type_identifier' || typeNode.type === 'qualified_name'
28
+ || typeNode.type === 'qualified_type'
29
+ || typeNode.type === 'member_expression' || typeNode.type === 'member_access_expression'
30
+ || typeNode.type === 'attribute'
31
+ || typeNode.type === 'scope_resolution'
32
+ || typeNode.type === 'selector_expression') {
33
+ const last = typeNode.lastNamedChild;
34
+ if (last && (last.type === 'type_identifier' || last.type === 'identifier'
35
+ || last.type === 'simple_identifier' || last.type === 'name'
36
+ || last.type === 'constant' || last.type === 'property_identifier'
37
+ || last.type === 'field_identifier')) {
38
+ return last.text;
39
+ }
40
+ }
41
+ // Generic types: extract the base type (e.g. List<User> -> List)
42
+ // For nullable wrappers (Optional<User>, Option<User>), unwrap to inner type
43
+ if (typeNode.type === 'generic_type' || typeNode.type === 'parameterized_type') {
44
+ const base = typeNode.childForFieldName('name')
45
+ ?? typeNode.childForFieldName('type')
46
+ ?? typeNode.firstNamedChild;
47
+ if (!base)
48
+ return undefined;
49
+ const baseName = extractSimpleTypeName(base);
50
+ // Unwrap known nullable wrappers: Optional<User> -> User, Option<User> -> User
51
+ if (baseName && NULLABLE_WRAPPER_TYPES.has(baseName)) {
52
+ const args = extractGenericTypeArgs(typeNode);
53
+ if (args.length >= 1)
54
+ return args[0];
55
+ }
56
+ return baseName;
57
+ }
58
+ // Nullable types (Kotlin User?, C# User?)
59
+ if (typeNode.type === 'nullable_type') {
60
+ const inner = typeNode.firstNamedChild;
61
+ if (inner)
62
+ return extractSimpleTypeName(inner);
63
+ }
64
+ // Nullable union types (TS/JS: User | null, User | undefined, User | null | undefined)
65
+ // Extract the single non-null/undefined type from the union
66
+ if (typeNode.type === 'union_type') {
67
+ const nonNullTypes = [];
68
+ for (let i = 0; i < typeNode.namedChildCount; i++) {
69
+ const child = typeNode.namedChild(i);
70
+ if (!child)
71
+ continue;
72
+ // Skip null/undefined/void literal types
73
+ const text = child.text;
74
+ if (text === 'null' || text === 'undefined' || text === 'void')
75
+ continue;
76
+ nonNullTypes.push(child);
77
+ }
78
+ // Only unwrap if exactly one meaningful type remains
79
+ if (nonNullTypes.length === 1) {
80
+ return extractSimpleTypeName(nonNullTypes[0]);
81
+ }
82
+ }
83
+ // Type annotations that wrap the actual type (TS/Python: `: Foo`, Kotlin: user_type)
84
+ if (typeNode.type === 'type_annotation' || typeNode.type === 'type'
85
+ || typeNode.type === 'user_type') {
86
+ const inner = typeNode.firstNamedChild;
87
+ if (inner)
88
+ return extractSimpleTypeName(inner);
89
+ }
90
+ // Pointer/reference types (C++, Rust): User*, &User, &mut User
91
+ if (typeNode.type === 'pointer_type' || typeNode.type === 'reference_type') {
92
+ const inner = typeNode.firstNamedChild;
93
+ if (inner)
94
+ return extractSimpleTypeName(inner);
95
+ }
96
+ // PHP primitive_type (string, int, float, bool)
97
+ if (typeNode.type === 'primitive_type') {
98
+ return typeNode.text;
99
+ }
100
+ // PHP named_type / optional_type
101
+ if (typeNode.type === 'named_type' || typeNode.type === 'optional_type') {
102
+ const inner = typeNode.childForFieldName('name') ?? typeNode.firstNamedChild;
103
+ if (inner)
104
+ return extractSimpleTypeName(inner);
105
+ }
106
+ // Name node (PHP)
107
+ if (typeNode.type === 'name') {
108
+ return typeNode.text;
109
+ }
110
+ return undefined;
111
+ };
112
+ /**
113
+ * Extract variable name from a declarator or pattern node
114
+ *
115
+ * Returns the simple identifier text, or undefined for destructuring/complex patterns
116
+ */
117
+ export const extractVarName = (node) => {
118
+ if (node.type === 'identifier' || node.type === 'simple_identifier'
119
+ || node.type === 'variable_name' || node.type === 'name'
120
+ || node.type === 'constant') {
121
+ return node.text;
122
+ }
123
+ // variable_declarator (Java/C#): has a 'name' field
124
+ if (node.type === 'variable_declarator') {
125
+ const nameChild = node.childForFieldName('name');
126
+ if (nameChild)
127
+ return extractVarName(nameChild);
128
+ }
129
+ // Rust: let mut x = ... -- mut_pattern wraps an identifier
130
+ if (node.type === 'mut_pattern') {
131
+ const inner = node.firstNamedChild;
132
+ if (inner)
133
+ return extractVarName(inner);
134
+ }
135
+ return undefined;
136
+ };
137
+ /** Node types for function/method parameters with type annotations */
138
+ export const TYPED_PARAMETER_TYPES = new Set([
139
+ 'required_parameter', // TS: (x: Foo)
140
+ 'optional_parameter', // TS: (x?: Foo)
141
+ 'formal_parameter', // Java/Kotlin
142
+ 'parameter', // C#/Rust/Go/Python/Swift
143
+ 'parameter_declaration', // C/C++ void f(Type name)
144
+ 'simple_parameter', // PHP function(Foo $x)
145
+ 'property_promotion_parameter', // PHP 8.0+ constructor promotion: __construct(private Foo $x)
146
+ ]);
147
+ /**
148
+ * Extract type arguments from a generic type node
149
+ *
150
+ * e.g. List<User, String> -> ['User', 'String'], Vec<User> -> ['User']
151
+ * Used by extractSimpleTypeName to unwrap nullable wrappers (Optional<User> -> User)
152
+ *
153
+ * Handles language-specific AST structures:
154
+ * - TS/Java/Rust/Go: generic_type > type_arguments > type nodes
155
+ * - C#: generic_type > type_argument_list > type nodes
156
+ * - Kotlin: generic_type > type_arguments > type_projection > type nodes
157
+ *
158
+ * Note: Go slices/maps use slice_type/map_type, not generic_type -- those are
159
+ * NOT handled here; use language-specific extractors for Go container types
160
+ *
161
+ * @param typeNode A generic_type or parameterized_type AST node (returns [] for non-generic types)
162
+ * @returns Array of resolved type argument names (unresolvable arguments are omitted)
163
+ */
164
+ export const extractGenericTypeArgs = (typeNode) => {
165
+ // Unwrap wrapper nodes that may sit above the generic_type
166
+ if (typeNode.type === 'type_annotation' || typeNode.type === 'type'
167
+ || typeNode.type === 'user_type' || typeNode.type === 'nullable_type'
168
+ || typeNode.type === 'optional_type') {
169
+ const inner = typeNode.firstNamedChild;
170
+ if (inner)
171
+ return extractGenericTypeArgs(inner);
172
+ return [];
173
+ }
174
+ // Only process generic/parameterized type nodes
175
+ if (typeNode.type !== 'generic_type' && typeNode.type !== 'parameterized_type') {
176
+ return [];
177
+ }
178
+ // Find the type_arguments / type_argument_list child
179
+ let argsNode = null;
180
+ for (let i = 0; i < typeNode.namedChildCount; i++) {
181
+ const child = typeNode.namedChild(i);
182
+ if (child && (child.type === 'type_arguments' || child.type === 'type_argument_list')) {
183
+ argsNode = child;
184
+ break;
185
+ }
186
+ }
187
+ if (!argsNode)
188
+ return [];
189
+ const result = [];
190
+ for (let i = 0; i < argsNode.namedChildCount; i++) {
191
+ let argNode = argsNode.namedChild(i);
192
+ if (!argNode)
193
+ continue;
194
+ // Kotlin: type_arguments > type_projection > user_type > type_identifier
195
+ if (argNode.type === 'type_projection') {
196
+ argNode = argNode.firstNamedChild;
197
+ if (!argNode)
198
+ continue;
199
+ }
200
+ const name = extractSimpleTypeName(argNode);
201
+ if (name)
202
+ result.push(name);
203
+ }
204
+ return result;
205
+ };
206
+ /**
207
+ * Match Ruby constructor assignment: `user = User.new` or `service = Models::User.new`
208
+ *
209
+ * Handles both simple constants and scope_resolution (namespaced) receivers
210
+ * @returns `{ varName, calleeName }` or undefined if not a Ruby constructor assignment
211
+ */
212
+ export const extractRubyConstructorAssignment = (node) => {
213
+ if (node.type !== 'assignment')
214
+ return undefined;
215
+ const left = node.childForFieldName('left');
216
+ const right = node.childForFieldName('right');
217
+ if (!left || !right)
218
+ return undefined;
219
+ if (left.type !== 'identifier' && left.type !== 'constant')
220
+ return undefined;
221
+ if (right.type !== 'call')
222
+ return undefined;
223
+ const method = right.childForFieldName('method');
224
+ if (!method || method.text !== 'new')
225
+ return undefined;
226
+ const receiver = right.childForFieldName('receiver');
227
+ if (!receiver)
228
+ return undefined;
229
+ let calleeName;
230
+ if (receiver.type === 'constant') {
231
+ calleeName = receiver.text;
232
+ }
233
+ else if (receiver.type === 'scope_resolution') {
234
+ // Models::User -> extract last segment "User"
235
+ const last = receiver.lastNamedChild;
236
+ if (!last || last.type !== 'constant')
237
+ return undefined;
238
+ calleeName = last.text;
239
+ }
240
+ else {
241
+ return undefined;
242
+ }
243
+ return { varName: left.text, calleeName };
244
+ };
245
+ /**
246
+ * Check if an AST node has an explicit type annotation
247
+ *
248
+ * Checks both named fields ('type') and child nodes ('type_annotation')
249
+ * Used by constructor binding scanners to skip annotated declarations
250
+ */
251
+ export const hasTypeAnnotation = (node) => {
252
+ if (node.childForFieldName('type'))
253
+ return true;
254
+ for (let i = 0; i < node.childCount; i++) {
255
+ if (node.child(i)?.type === 'type_annotation')
256
+ return true;
257
+ }
258
+ return false;
259
+ };
260
+ // Bare nullable keywords that should not produce a receiver binding
261
+ const NULLABLE_KEYWORDS = new Set(['null', 'undefined', 'void', 'None', 'nil']);
262
+ /**
263
+ * Strip nullable wrappers from a type name string
264
+ *
265
+ * Used by both lookupInEnv (TypeEnv annotations) and extractReturnTypeName
266
+ * (return-type text) to normalize types before receiver lookup
267
+ *
268
+ * "User | null" -> "User"
269
+ * "User | undefined" -> "User"
270
+ * "User | null | undefined" -> "User"
271
+ * "User?" -> "User"
272
+ * "User | Repo" -> undefined (genuine union -- refuse)
273
+ * "null" -> undefined
274
+ */
275
+ export const stripNullable = (typeName) => {
276
+ let text = typeName.trim();
277
+ if (!text)
278
+ return undefined;
279
+ if (NULLABLE_KEYWORDS.has(text))
280
+ return undefined;
281
+ // Strip nullable suffix: User? -> User
282
+ if (text.endsWith('?'))
283
+ text = text.slice(0, -1).trim();
284
+ // Strip union with null/undefined/None/nil/void
285
+ if (text.includes('|')) {
286
+ const parts = text.split('|').map(p => p.trim()).filter(p => p !== '' && !NULLABLE_KEYWORDS.has(p));
287
+ if (parts.length === 1)
288
+ return parts[0];
289
+ return undefined; // genuine union or all-nullable -- refuse
290
+ }
291
+ return text || undefined;
292
+ };
293
+ /**
294
+ * Unwrap an await_expression to get the inner value
295
+ *
296
+ * Returns the node itself if not an await_expression, or null if input is null
297
+ */
298
+ export const unwrapAwait = (node) => {
299
+ if (!node)
300
+ return null;
301
+ return node.type === 'await_expression' ? node.firstNamedChild : node;
302
+ };
303
+ /**
304
+ * Extract the callee name from a call_expression node
305
+ *
306
+ * Navigates to the 'function' field (or first named child) and extracts a simple type name
307
+ */
308
+ export const extractCalleeName = (callNode) => {
309
+ const func = callNode.childForFieldName('function') ?? callNode.firstNamedChild;
310
+ if (!func)
311
+ return undefined;
312
+ return extractSimpleTypeName(func);
313
+ };
314
+ /** Find the first named child with the given node type */
315
+ export const findChildByType = (node, type) => {
316
+ for (let i = 0; i < node.namedChildCount; i++) {
317
+ const child = node.namedChild(i);
318
+ if (child?.type === type)
319
+ return child;
320
+ }
321
+ return null;
322
+ };
@@ -0,0 +1,4 @@
1
+ /** @file swift.ts
2
+ * @description Type extraction for Swift (property declarations, initializer inference) */
3
+ import type { LanguageTypeConfig } from './types.js';
4
+ export declare const typeConfig: LanguageTypeConfig;
@@ -0,0 +1,140 @@
1
+ // code-mapper/src/core/ingestion/type-extractors/swift.ts
2
+ /** @file swift.ts
3
+ * @description Type extraction for Swift (property declarations, initializer inference) */
4
+ import { extractSimpleTypeName, extractVarName, findChildByType, hasTypeAnnotation } from './shared.js';
5
+ const DECLARATION_NODE_TYPES = new Set([
6
+ 'property_declaration',
7
+ ]);
8
+ // Swift: let x: Foo = ...
9
+ const extractDeclaration = (node, env) => {
10
+ // Swift property_declaration has pattern and type_annotation
11
+ const pattern = node.childForFieldName('pattern')
12
+ ?? findChildByType(node, 'pattern');
13
+ const typeAnnotation = node.childForFieldName('type')
14
+ ?? findChildByType(node, 'type_annotation');
15
+ if (!pattern || !typeAnnotation)
16
+ return;
17
+ const varName = extractVarName(pattern) ?? pattern.text;
18
+ const typeName = extractSimpleTypeName(typeAnnotation);
19
+ if (varName && typeName)
20
+ env.set(varName, typeName);
21
+ };
22
+ // Swift: parameter -> name: type
23
+ const extractParameter = (node, env) => {
24
+ let nameNode = null;
25
+ let typeNode = null;
26
+ if (node.type === 'parameter') {
27
+ nameNode = node.childForFieldName('name')
28
+ ?? node.childForFieldName('internal_name');
29
+ typeNode = node.childForFieldName('type');
30
+ }
31
+ else {
32
+ nameNode = node.childForFieldName('name') ?? node.childForFieldName('pattern');
33
+ typeNode = node.childForFieldName('type');
34
+ }
35
+ if (!nameNode || !typeNode)
36
+ return;
37
+ const varName = extractVarName(nameNode);
38
+ const typeName = extractSimpleTypeName(typeNode);
39
+ if (varName && typeName)
40
+ env.set(varName, typeName);
41
+ };
42
+ // Swift: let user = User(name: "alice") -- infer type from call when callee is a known class
43
+ // Swift initializers are syntactically identical to function calls, so we verify
44
+ // against classNames (which may include cross-file SymbolTable lookups)
45
+ const extractInitializer = (node, env, classNames) => {
46
+ if (node.type !== 'property_declaration')
47
+ return;
48
+ // Skip if has type annotation -- extractDeclaration handled it
49
+ if (node.childForFieldName('type') || findChildByType(node, 'type_annotation'))
50
+ return;
51
+ // Find pattern (variable name)
52
+ const pattern = node.childForFieldName('pattern') ?? findChildByType(node, 'pattern');
53
+ if (!pattern)
54
+ return;
55
+ const varName = extractVarName(pattern) ?? pattern.text;
56
+ if (!varName || env.has(varName))
57
+ return;
58
+ // Find call_expression in the value
59
+ const callExpr = findChildByType(node, 'call_expression');
60
+ if (!callExpr)
61
+ return;
62
+ const callee = callExpr.firstNamedChild;
63
+ if (!callee)
64
+ return;
65
+ // Direct call: User(name: "alice")
66
+ if (callee.type === 'simple_identifier') {
67
+ const calleeName = callee.text;
68
+ if (calleeName && classNames.has(calleeName)) {
69
+ env.set(varName, calleeName);
70
+ }
71
+ return;
72
+ }
73
+ // Explicit init: User.init(name: "alice") -- navigation_expression with .init suffix
74
+ if (callee.type === 'navigation_expression') {
75
+ const receiver = callee.firstNamedChild;
76
+ const suffix = callee.lastNamedChild;
77
+ if (receiver?.type === 'simple_identifier' && suffix?.text === 'init') {
78
+ const calleeName = receiver.text;
79
+ if (calleeName && classNames.has(calleeName)) {
80
+ env.set(varName, calleeName);
81
+ }
82
+ }
83
+ }
84
+ };
85
+ // Swift: let user = User(name: "alice") -- scan property_declaration for constructor binding
86
+ const scanConstructorBinding = (node) => {
87
+ if (node.type !== 'property_declaration')
88
+ return undefined;
89
+ if (hasTypeAnnotation(node))
90
+ return undefined;
91
+ const pattern = node.childForFieldName('pattern');
92
+ if (!pattern)
93
+ return undefined;
94
+ const varName = pattern.text;
95
+ if (!varName)
96
+ return undefined;
97
+ let callExpr = null;
98
+ for (let i = 0; i < node.namedChildCount; i++) {
99
+ const child = node.namedChild(i);
100
+ if (child?.type === 'call_expression') {
101
+ callExpr = child;
102
+ break;
103
+ }
104
+ }
105
+ if (!callExpr)
106
+ return undefined;
107
+ const callee = callExpr.firstNamedChild;
108
+ if (!callee)
109
+ return undefined;
110
+ if (callee.type === 'simple_identifier') {
111
+ return { varName, calleeName: callee.text };
112
+ }
113
+ if (callee.type === 'navigation_expression') {
114
+ const receiver = callee.firstNamedChild;
115
+ const suffix = callee.lastNamedChild;
116
+ if (receiver?.type === 'simple_identifier' && suffix?.text === 'init') {
117
+ return { varName, calleeName: receiver.text };
118
+ }
119
+ // General qualified call: service.getUser() -> extract method name
120
+ // tree-sitter-swift may wrap the identifier in navigation_suffix, so
121
+ // check both direct simple_identifier and navigation_suffix > simple_identifier
122
+ if (suffix?.type === 'simple_identifier') {
123
+ return { varName, calleeName: suffix.text };
124
+ }
125
+ if (suffix?.type === 'navigation_suffix') {
126
+ const inner = suffix.lastNamedChild;
127
+ if (inner?.type === 'simple_identifier') {
128
+ return { varName, calleeName: inner.text };
129
+ }
130
+ }
131
+ }
132
+ return undefined;
133
+ };
134
+ export const typeConfig = {
135
+ declarationNodeTypes: DECLARATION_NODE_TYPES,
136
+ extractDeclaration,
137
+ extractParameter,
138
+ extractInitializer,
139
+ scanConstructorBinding,
140
+ };
@@ -0,0 +1,111 @@
1
+ /** @file types.ts
2
+ * @description Type definitions for per-language type extraction used by TypeEnv */
3
+ import type { SyntaxNode } from '../utils.js';
4
+ /** Extracts type bindings from a declaration node into the env map */
5
+ export type TypeBindingExtractor = (node: SyntaxNode, env: Map<string, string>) => void;
6
+ /** Extracts type bindings from a parameter node into the env map */
7
+ export type ParameterExtractor = (node: SyntaxNode, env: Map<string, string>) => void;
8
+ /** Minimal interface for checking whether a name is a known class/struct -- only `.has()` is needed */
9
+ export type ClassNameLookup = {
10
+ has(name: string): boolean;
11
+ };
12
+ /** Extracts type bindings from a constructor-call initializer, with access to known class names */
13
+ export type InitializerExtractor = (node: SyntaxNode, env: Map<string, string>, classNames: ClassNameLookup) => void;
14
+ /**
15
+ * Scans an AST node for untyped `var = callee()` patterns for return-type inference
16
+ * @returns `{ varName, calleeName }` if matched, undefined otherwise
17
+ * `receiverClassName` is an optional hint for method calls on known receivers
18
+ * (e.g. `$this->getUser()` in PHP provides the enclosing class name)
19
+ */
20
+ export type ConstructorBindingScanner = (node: SyntaxNode) => {
21
+ varName: string;
22
+ calleeName: string;
23
+ receiverClassName?: string;
24
+ } | undefined;
25
+ /**
26
+ * Extracts a return type string from a method/function definition node
27
+ *
28
+ * Used for languages where return types live in comments (e.g. YARD `@return [Type]`)
29
+ * rather than AST fields. Returns undefined if no return type can be determined
30
+ */
31
+ export type ReturnTypeExtractor = (node: SyntaxNode) => string | undefined;
32
+ /** Extracts loop variable type binding from a for-each statement */
33
+ export type ForLoopExtractor = (node: SyntaxNode, scopeEnv: Map<string, string>) => void;
34
+ /**
35
+ * Extracts a plain-identifier assignment for Tier 2 propagation
36
+ *
37
+ * For `const b = a`, returns `{ lhs: 'b', rhs: 'a' }` when the LHS has no resolved type
38
+ * Returns undefined if the node is not a plain identifier assignment
39
+ */
40
+ export type PendingAssignmentExtractor = (node: SyntaxNode, scopeEnv: ReadonlyMap<string, string>) => {
41
+ lhs: string;
42
+ rhs: string;
43
+ } | undefined;
44
+ /**
45
+ * Extracts a typed variable binding from a pattern-matching construct
46
+ *
47
+ * Returns `{ varName, typeName }` for patterns that introduce new variables
48
+ * Examples: `if let Some(user) = opt` (Rust), `x instanceof User user` (Java)
49
+ * Conservative: returns undefined when the source variable's type is unknown
50
+ *
51
+ * @param scopeEnv Read-only view of already-resolved type bindings in the current scope
52
+ * @param declarationTypeNodes Maps `scope\0varName` to the original declaration's type
53
+ * annotation AST node, allowing generic type argument extraction (e.g. T from Result<T,E>)
54
+ * that is stripped during normal TypeEnv extraction
55
+ * @param scope Current scope key (e.g. `"process@42"`) for declarationTypeNodes lookups
56
+ */
57
+ export type PatternBindingExtractor = (node: SyntaxNode, scopeEnv: ReadonlyMap<string, string>, declarationTypeNodes: ReadonlyMap<string, SyntaxNode>, scope: string) => {
58
+ varName: string;
59
+ typeName: string;
60
+ } | undefined;
61
+ /** Per-language type extraction configuration */
62
+ export interface LanguageTypeConfig {
63
+ /** Node types that represent typed declarations for this language */
64
+ declarationNodeTypes: ReadonlySet<string>;
65
+ /** AST node types for for-each/for-in statements with explicit element types */
66
+ forLoopNodeTypes?: ReadonlySet<string>;
67
+ /** Extract a (varName -> typeName) binding from a declaration node */
68
+ extractDeclaration: TypeBindingExtractor;
69
+ /** Extract a (varName -> typeName) binding from a parameter node */
70
+ extractParameter: ParameterExtractor;
71
+ /**
72
+ * Extract a (varName -> typeName) binding from a constructor-call initializer
73
+ *
74
+ * Called as fallback when extractDeclaration produces no binding for a declaration node
75
+ * Only for languages with syntactic constructor markers (new, composite_literal, ::new)
76
+ * Receives classNames -- the set of class/struct names visible in the current file's AST
77
+ */
78
+ extractInitializer?: InitializerExtractor;
79
+ /**
80
+ * Scan for untyped `var = callee()` assignments for return-type inference
81
+ *
82
+ * Called on every AST node during buildTypeEnv walk; returns undefined for non-matches
83
+ * The callee binding is unverified -- the caller must confirm against the SymbolTable
84
+ */
85
+ scanConstructorBinding?: ConstructorBindingScanner;
86
+ /**
87
+ * Extract return type from comment-based annotations (e.g. YARD `@return [Type]`)
88
+ *
89
+ * Called as fallback when extractMethodSignature finds no AST-based return type
90
+ */
91
+ extractReturnType?: ReturnTypeExtractor;
92
+ /** Extract loop variable -> type binding from a for-each AST node */
93
+ extractForLoopBinding?: ForLoopExtractor;
94
+ /**
95
+ * Extract plain-identifier assignment (e.g. `const b = a`) for Tier 2 chain propagation
96
+ *
97
+ * Called on declaration/assignment nodes; returns {lhs, rhs} when the RHS is a bare
98
+ * identifier and the LHS has no resolved type yet. Language-specific because AST shapes
99
+ * differ widely
100
+ */
101
+ extractPendingAssignment?: PendingAssignmentExtractor;
102
+ /**
103
+ * Extract a typed variable binding from a pattern-matching construct
104
+ *
105
+ * Called on every AST node; returns { varName, typeName } when the node introduces a new
106
+ * typed variable via pattern matching (e.g. `if let Some(x) = opt`, `x instanceof T t`)
107
+ * Receives the current scope's resolved bindings (read-only) to look up the source
108
+ * variable's type. Returns undefined for non-matching nodes or unknown source types
109
+ */
110
+ extractPatternBinding?: PatternBindingExtractor;
111
+ }
@@ -0,0 +1,4 @@
1
+ // code-mapper/src/core/ingestion/type-extractors/types.ts
2
+ /** @file types.ts
3
+ * @description Type definitions for per-language type extraction used by TypeEnv */
4
+ export {};
@@ -0,0 +1,4 @@
1
+ /** @file typescript.ts
2
+ * @description Type extraction for TypeScript and JavaScript (including JSDoc annotations) */
3
+ import type { LanguageTypeConfig } from './types.js';
4
+ export declare const typeConfig: LanguageTypeConfig;