gitnexus 1.4.8 → 1.4.10

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 (211) hide show
  1. package/README.md +7 -0
  2. package/dist/cli/index-repo.d.ts +15 -0
  3. package/dist/cli/index-repo.js +115 -0
  4. package/dist/cli/index.js +11 -2
  5. package/dist/cli/setup.js +12 -9
  6. package/dist/cli/wiki.d.ts +4 -0
  7. package/dist/cli/wiki.js +174 -53
  8. package/dist/config/supported-languages.d.ts +7 -5
  9. package/dist/config/supported-languages.js +6 -4
  10. package/dist/core/graph/graph.js +9 -1
  11. package/dist/core/graph/types.d.ts +10 -2
  12. package/dist/core/ingestion/call-processor.d.ts +18 -1
  13. package/dist/core/ingestion/call-processor.js +297 -38
  14. package/dist/core/ingestion/call-routing.d.ts +3 -18
  15. package/dist/core/ingestion/call-routing.js +0 -19
  16. package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
  17. package/dist/core/ingestion/cobol/cobol-copy-expander.js +385 -0
  18. package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +210 -0
  19. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1509 -0
  20. package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
  21. package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
  22. package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
  23. package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
  24. package/dist/core/ingestion/cobol-processor.d.ts +54 -0
  25. package/dist/core/ingestion/cobol-processor.js +1186 -0
  26. package/dist/core/ingestion/entry-point-scoring.d.ts +17 -0
  27. package/dist/core/ingestion/entry-point-scoring.js +18 -4
  28. package/dist/core/ingestion/export-detection.d.ts +47 -8
  29. package/dist/core/ingestion/export-detection.js +29 -50
  30. package/dist/core/ingestion/field-extractor.d.ts +29 -0
  31. package/dist/core/ingestion/field-extractor.js +25 -0
  32. package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
  33. package/dist/core/ingestion/field-extractors/configs/c-cpp.js +108 -0
  34. package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
  35. package/dist/core/ingestion/field-extractors/configs/csharp.js +73 -0
  36. package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
  37. package/dist/core/ingestion/field-extractors/configs/dart.js +76 -0
  38. package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
  39. package/dist/core/ingestion/field-extractors/configs/go.js +64 -0
  40. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +44 -0
  41. package/dist/core/ingestion/field-extractors/configs/helpers.js +134 -0
  42. package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
  43. package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
  44. package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
  45. package/dist/core/ingestion/field-extractors/configs/php.js +67 -0
  46. package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
  47. package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
  48. package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
  49. package/dist/core/ingestion/field-extractors/configs/ruby.js +75 -0
  50. package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
  51. package/dist/core/ingestion/field-extractors/configs/rust.js +55 -0
  52. package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
  53. package/dist/core/ingestion/field-extractors/configs/swift.js +63 -0
  54. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
  55. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +60 -0
  56. package/dist/core/ingestion/field-extractors/generic.d.ts +46 -0
  57. package/dist/core/ingestion/field-extractors/generic.js +111 -0
  58. package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
  59. package/dist/core/ingestion/field-extractors/typescript.js +291 -0
  60. package/dist/core/ingestion/field-types.d.ts +59 -0
  61. package/dist/core/ingestion/field-types.js +2 -0
  62. package/dist/core/ingestion/framework-detection.d.ts +87 -0
  63. package/dist/core/ingestion/framework-detection.js +65 -2
  64. package/dist/core/ingestion/heritage-processor.js +15 -17
  65. package/dist/core/ingestion/import-processor.d.ts +9 -10
  66. package/dist/core/ingestion/import-processor.js +59 -14
  67. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.d.ts +6 -9
  68. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.js +20 -2
  69. package/dist/core/ingestion/import-resolvers/dart.d.ts +7 -0
  70. package/dist/core/ingestion/import-resolvers/dart.js +44 -0
  71. package/dist/core/ingestion/{resolvers → import-resolvers}/go.d.ts +4 -5
  72. package/dist/core/ingestion/{resolvers → import-resolvers}/go.js +17 -0
  73. package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.d.ts +9 -1
  74. package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.js +56 -0
  75. package/dist/core/ingestion/{resolvers → import-resolvers}/php.d.ts +6 -10
  76. package/dist/core/ingestion/{resolvers → import-resolvers}/php.js +7 -2
  77. package/dist/core/ingestion/{resolvers → import-resolvers}/python.d.ts +9 -3
  78. package/dist/core/ingestion/{resolvers → import-resolvers}/python.js +35 -3
  79. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.d.ts +5 -2
  80. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.js +7 -2
  81. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.d.ts +5 -2
  82. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.js +41 -2
  83. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.d.ts +15 -7
  84. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.js +22 -3
  85. package/dist/core/ingestion/import-resolvers/swift.d.ts +7 -0
  86. package/dist/core/ingestion/import-resolvers/swift.js +23 -0
  87. package/dist/core/ingestion/import-resolvers/types.d.ts +44 -0
  88. package/dist/core/ingestion/import-resolvers/types.js +6 -0
  89. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.d.ts +0 -3
  90. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +0 -9
  91. package/dist/core/ingestion/language-config.d.ts +4 -1
  92. package/dist/core/ingestion/language-provider.d.ts +121 -0
  93. package/dist/core/ingestion/language-provider.js +24 -0
  94. package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
  95. package/dist/core/ingestion/languages/c-cpp.js +71 -0
  96. package/dist/core/ingestion/languages/cobol.d.ts +1 -0
  97. package/dist/core/ingestion/languages/cobol.js +26 -0
  98. package/dist/core/ingestion/languages/csharp.d.ts +8 -0
  99. package/dist/core/ingestion/languages/csharp.js +49 -0
  100. package/dist/core/ingestion/languages/dart.d.ts +12 -0
  101. package/dist/core/ingestion/languages/dart.js +58 -0
  102. package/dist/core/ingestion/languages/go.d.ts +11 -0
  103. package/dist/core/ingestion/languages/go.js +28 -0
  104. package/dist/core/ingestion/languages/index.d.ts +38 -0
  105. package/dist/core/ingestion/languages/index.js +63 -0
  106. package/dist/core/ingestion/languages/java.d.ts +9 -0
  107. package/dist/core/ingestion/languages/java.js +29 -0
  108. package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
  109. package/dist/core/ingestion/languages/kotlin.js +53 -0
  110. package/dist/core/ingestion/languages/php.d.ts +8 -0
  111. package/dist/core/ingestion/languages/php.js +145 -0
  112. package/dist/core/ingestion/languages/python.d.ts +12 -0
  113. package/dist/core/ingestion/languages/python.js +39 -0
  114. package/dist/core/ingestion/languages/ruby.d.ts +9 -0
  115. package/dist/core/ingestion/languages/ruby.js +44 -0
  116. package/dist/core/ingestion/languages/rust.d.ts +12 -0
  117. package/dist/core/ingestion/languages/rust.js +44 -0
  118. package/dist/core/ingestion/languages/swift.d.ts +12 -0
  119. package/dist/core/ingestion/languages/swift.js +133 -0
  120. package/dist/core/ingestion/languages/typescript.d.ts +10 -0
  121. package/dist/core/ingestion/languages/typescript.js +60 -0
  122. package/dist/core/ingestion/mro-processor.js +14 -15
  123. package/dist/core/ingestion/{named-binding-extraction.d.ts → named-binding-processor.d.ts} +0 -9
  124. package/dist/core/ingestion/named-binding-processor.js +42 -0
  125. package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
  126. package/dist/core/ingestion/named-bindings/csharp.js +37 -0
  127. package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
  128. package/dist/core/ingestion/named-bindings/java.js +29 -0
  129. package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
  130. package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
  131. package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
  132. package/dist/core/ingestion/named-bindings/php.js +61 -0
  133. package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
  134. package/dist/core/ingestion/named-bindings/python.js +49 -0
  135. package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
  136. package/dist/core/ingestion/named-bindings/rust.js +64 -0
  137. package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
  138. package/dist/core/ingestion/named-bindings/types.js +6 -0
  139. package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
  140. package/dist/core/ingestion/named-bindings/typescript.js +58 -0
  141. package/dist/core/ingestion/parsing-processor.d.ts +5 -1
  142. package/dist/core/ingestion/parsing-processor.js +115 -16
  143. package/dist/core/ingestion/pipeline.js +925 -424
  144. package/dist/core/ingestion/resolution-context.js +1 -1
  145. package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
  146. package/dist/core/ingestion/route-extractors/expo.js +36 -0
  147. package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
  148. package/dist/core/ingestion/route-extractors/middleware.js +143 -0
  149. package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
  150. package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
  151. package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
  152. package/dist/core/ingestion/route-extractors/php.js +21 -0
  153. package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
  154. package/dist/core/ingestion/route-extractors/response-shapes.js +290 -0
  155. package/dist/core/ingestion/tree-sitter-queries.d.ts +8 -7
  156. package/dist/core/ingestion/tree-sitter-queries.js +231 -9
  157. package/dist/core/ingestion/type-env.d.ts +14 -17
  158. package/dist/core/ingestion/type-env.js +66 -14
  159. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +1 -1
  160. package/dist/core/ingestion/type-extractors/csharp.js +1 -1
  161. package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
  162. package/dist/core/ingestion/type-extractors/dart.js +371 -0
  163. package/dist/core/ingestion/type-extractors/jvm.js +1 -1
  164. package/dist/core/ingestion/type-extractors/shared.d.ts +1 -13
  165. package/dist/core/ingestion/type-extractors/shared.js +9 -102
  166. package/dist/core/ingestion/type-extractors/swift.js +334 -4
  167. package/dist/core/ingestion/type-extractors/types.d.ts +3 -1
  168. package/dist/core/ingestion/{ast-helpers.d.ts → utils/ast-helpers.d.ts} +16 -13
  169. package/dist/core/ingestion/{ast-helpers.js → utils/ast-helpers.js} +111 -32
  170. package/dist/core/ingestion/{call-analysis.js → utils/call-analysis.js} +37 -0
  171. package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
  172. package/dist/core/ingestion/utils/event-loop.js +5 -0
  173. package/dist/core/ingestion/utils/language-detection.d.ts +9 -0
  174. package/dist/core/ingestion/utils/language-detection.js +70 -0
  175. package/dist/core/ingestion/utils/verbose.d.ts +1 -0
  176. package/dist/core/ingestion/utils/verbose.js +7 -0
  177. package/dist/core/ingestion/workers/parse-worker.d.ts +43 -2
  178. package/dist/core/ingestion/workers/parse-worker.js +361 -150
  179. package/dist/core/lbug/csv-generator.js +34 -1
  180. package/dist/core/lbug/lbug-adapter.js +6 -0
  181. package/dist/core/lbug/schema.d.ts +5 -3
  182. package/dist/core/lbug/schema.js +39 -2
  183. package/dist/core/tree-sitter/parser-loader.js +7 -1
  184. package/dist/core/wiki/cursor-client.d.ts +31 -0
  185. package/dist/core/wiki/cursor-client.js +127 -0
  186. package/dist/core/wiki/generator.d.ts +28 -9
  187. package/dist/core/wiki/generator.js +115 -18
  188. package/dist/core/wiki/graph-queries.d.ts +4 -0
  189. package/dist/core/wiki/graph-queries.js +7 -1
  190. package/dist/core/wiki/llm-client.d.ts +2 -0
  191. package/dist/core/wiki/llm-client.js +8 -4
  192. package/dist/core/wiki/prompts.d.ts +3 -3
  193. package/dist/core/wiki/prompts.js +6 -0
  194. package/dist/mcp/core/lbug-adapter.d.ts +5 -0
  195. package/dist/mcp/core/lbug-adapter.js +11 -1
  196. package/dist/mcp/local/local-backend.d.ts +16 -5
  197. package/dist/mcp/local/local-backend.js +711 -74
  198. package/dist/mcp/tools.js +71 -2
  199. package/dist/storage/repo-manager.d.ts +3 -0
  200. package/package.json +14 -14
  201. package/dist/core/ingestion/import-resolution.d.ts +0 -101
  202. package/dist/core/ingestion/import-resolution.js +0 -251
  203. package/dist/core/ingestion/named-binding-extraction.js +0 -373
  204. package/dist/core/ingestion/resolvers/index.d.ts +0 -18
  205. package/dist/core/ingestion/resolvers/index.js +0 -13
  206. package/dist/core/ingestion/type-extractors/index.d.ts +0 -22
  207. package/dist/core/ingestion/type-extractors/index.js +0 -31
  208. package/dist/core/ingestion/utils.d.ts +0 -20
  209. package/dist/core/ingestion/utils.js +0 -242
  210. package/scripts/patch-tree-sitter-swift.cjs +0 -74
  211. /package/dist/core/ingestion/{call-analysis.d.ts → utils/call-analysis.d.ts} +0 -0
@@ -0,0 +1,291 @@
1
+ // gitnexus/src/core/ingestion/field-extractors/typescript.ts
2
+ import { SupportedLanguages } from '../../../config/supported-languages.js';
3
+ import { BaseFieldExtractor } from '../field-extractor.js';
4
+ /**
5
+ * Hand-written TypeScript field extractor.
6
+ *
7
+ * This exists alongside the config-based extractor in configs/typescript-javascript.ts
8
+ * (used for JavaScript) because TypeScript has unique requirements:
9
+ * 1. type_alias_declaration with object type literals (e.g., type Config = { key: string })
10
+ * 2. Optional property detection appending '| undefined' to types
11
+ * 3. Nested type discovery within class/interface bodies
12
+ *
13
+ * The config-based extractor cannot express these TS-specific capabilities.
14
+ * JavaScript uses the config-based version since it lacks type syntax.
15
+ */
16
+ export class TypeScriptFieldExtractor extends BaseFieldExtractor {
17
+ language = SupportedLanguages.TypeScript;
18
+ /**
19
+ * Node types that represent type declarations with fields in TypeScript
20
+ */
21
+ static TYPE_DECLARATION_NODES = new Set([
22
+ 'class_declaration',
23
+ 'interface_declaration',
24
+ 'abstract_class_declaration',
25
+ 'type_alias_declaration', // for object type literals
26
+ ]);
27
+ /**
28
+ * Node types that contain field definitions within class bodies
29
+ */
30
+ static FIELD_NODE_TYPES = new Set([
31
+ 'public_field_definition', // class field: private users: User[]
32
+ 'property_signature', // interface property: name: string
33
+ 'field_definition', // fallback field type
34
+ ]);
35
+ /**
36
+ * Visibility modifiers in TypeScript
37
+ */
38
+ static VISIBILITY_MODIFIERS = new Set([
39
+ 'public',
40
+ 'private',
41
+ 'protected',
42
+ ]);
43
+ /**
44
+ * Check if this node represents a type declaration with fields
45
+ */
46
+ isTypeDeclaration(node) {
47
+ return TypeScriptFieldExtractor.TYPE_DECLARATION_NODES.has(node.type);
48
+ }
49
+ /**
50
+ * Extract visibility modifier from a field node
51
+ */
52
+ extractVisibility(node) {
53
+ // Check for accessibility_modifier named child (tree-sitter typescript)
54
+ for (let i = 0; i < node.namedChildCount; i++) {
55
+ const child = node.namedChild(i);
56
+ if (child && child.type === 'accessibility_modifier') {
57
+ const text = child.text.trim();
58
+ if (TypeScriptFieldExtractor.VISIBILITY_MODIFIERS.has(text)) {
59
+ return text;
60
+ }
61
+ }
62
+ }
63
+ // Check for modifiers in the field's unnamed children (fallback)
64
+ for (let i = 0; i < node.childCount; i++) {
65
+ const child = node.child(i);
66
+ if (child && !child.isNamed) {
67
+ const text = child.text.trim();
68
+ if (TypeScriptFieldExtractor.VISIBILITY_MODIFIERS.has(text)) {
69
+ return text;
70
+ }
71
+ }
72
+ }
73
+ // Check for modifier node (tree-sitter typescript may group these)
74
+ const modifiers = node.childForFieldName('modifiers');
75
+ if (modifiers) {
76
+ for (let i = 0; i < modifiers.childCount; i++) {
77
+ const modifier = modifiers.child(i);
78
+ const modText = modifier?.text.trim();
79
+ if (modText && TypeScriptFieldExtractor.VISIBILITY_MODIFIERS.has(modText)) {
80
+ return modText;
81
+ }
82
+ }
83
+ }
84
+ // TypeScript class members are public by default
85
+ return 'public';
86
+ }
87
+ /**
88
+ * Check if a field has the static modifier
89
+ */
90
+ isStatic(node) {
91
+ for (let i = 0; i < node.childCount; i++) {
92
+ const child = node.child(i);
93
+ if (child && !child.isNamed && child.text.trim() === 'static') {
94
+ return true;
95
+ }
96
+ }
97
+ const modifiers = node.childForFieldName('modifiers');
98
+ if (modifiers) {
99
+ for (let i = 0; i < modifiers.childCount; i++) {
100
+ const modifier = modifiers.child(i);
101
+ if (modifier && modifier.text === 'static') {
102
+ return true;
103
+ }
104
+ }
105
+ }
106
+ return false;
107
+ }
108
+ /**
109
+ * Check if a field has the readonly modifier
110
+ */
111
+ isReadonly(node) {
112
+ for (let i = 0; i < node.childCount; i++) {
113
+ const child = node.child(i);
114
+ if (child && !child.isNamed && child.text.trim() === 'readonly') {
115
+ return true;
116
+ }
117
+ }
118
+ const modifiers = node.childForFieldName('modifiers');
119
+ if (modifiers) {
120
+ for (let i = 0; i < modifiers.childCount; i++) {
121
+ const modifier = modifiers.child(i);
122
+ if (modifier && modifier.text === 'readonly') {
123
+ return true;
124
+ }
125
+ }
126
+ }
127
+ return false;
128
+ }
129
+ /**
130
+ * Check if a property is optional (has ?: syntax)
131
+ */
132
+ isOptional(node) {
133
+ // Look for the optional marker '?' in unnamed children
134
+ for (let i = 0; i < node.childCount; i++) {
135
+ const child = node.child(i);
136
+ if (child && !child.isNamed && child.text === '?') {
137
+ return true;
138
+ }
139
+ }
140
+ // Also check for optional_property_signature or marker in type
141
+ const kind = node.childForFieldName('kind');
142
+ if (kind && kind.text === '?') {
143
+ return true;
144
+ }
145
+ return false;
146
+ }
147
+ /**
148
+ * Extract the full type text, handling complex generic types.
149
+ *
150
+ * type_annotation nodes wrap the literal ': SomeType' — only that branch
151
+ * needs special handling to unwrap the inner child and skip the colon.
152
+ * All other node kinds are already the type text itself, so normalizeType
153
+ * is applied directly.
154
+ */
155
+ extractFullType(typeNode) {
156
+ if (!typeNode)
157
+ return null;
158
+ if (typeNode.type === 'type_annotation') {
159
+ const innerType = typeNode.firstNamedChild;
160
+ return innerType ? this.normalizeType(innerType.text) : null;
161
+ }
162
+ return this.normalizeType(typeNode.text);
163
+ }
164
+ /**
165
+ * Extract a single field from a field definition node
166
+ */
167
+ extractField(node, context) {
168
+ // Get the field name
169
+ const nameNode = node.childForFieldName('name') ?? node.childForFieldName('property');
170
+ if (!nameNode)
171
+ return null;
172
+ const name = nameNode.text;
173
+ if (!name)
174
+ return null;
175
+ // Get the type annotation
176
+ const typeNode = node.childForFieldName('type');
177
+ let type = this.extractFullType(typeNode);
178
+ // Try to resolve the type using the context
179
+ if (type) {
180
+ const resolvedType = this.resolveType(type, context);
181
+ type = resolvedType ?? type;
182
+ }
183
+ return {
184
+ name,
185
+ type,
186
+ visibility: this.extractVisibility(node),
187
+ isStatic: this.isStatic(node),
188
+ isReadonly: this.isReadonly(node),
189
+ sourceFile: context.filePath,
190
+ line: node.startPosition.row + 1,
191
+ };
192
+ }
193
+ /**
194
+ * Extract fields from a class body or interface body
195
+ */
196
+ extractFieldsFromBody(bodyNode, context) {
197
+ const fields = [];
198
+ // Find all field definition nodes within the body
199
+ for (let i = 0; i < bodyNode.namedChildCount; i++) {
200
+ const child = bodyNode.namedChild(i);
201
+ if (!child)
202
+ continue;
203
+ if (TypeScriptFieldExtractor.FIELD_NODE_TYPES.has(child.type)) {
204
+ const field = this.extractField(child, context);
205
+ if (field) {
206
+ fields.push(field);
207
+ }
208
+ }
209
+ }
210
+ return fields;
211
+ }
212
+ /**
213
+ * Extract fields from an object type (used in type aliases)
214
+ */
215
+ extractFieldsFromObjectType(objectTypeNode, context) {
216
+ const fields = [];
217
+ // Find all property_signature nodes within the object type
218
+ const propertySignatures = objectTypeNode.descendantsOfType('property_signature');
219
+ for (const propNode of propertySignatures) {
220
+ const field = this.extractField(propNode, context);
221
+ if (field) {
222
+ // Mark optional properties
223
+ if (this.isOptional(propNode) && field.type) {
224
+ field.type = field.type + ' | undefined';
225
+ }
226
+ fields.push(field);
227
+ }
228
+ }
229
+ return fields;
230
+ }
231
+ /**
232
+ * Extract fields from a class or interface declaration
233
+ */
234
+ extract(node, context) {
235
+ if (!this.isTypeDeclaration(node))
236
+ return null;
237
+ // Get the type name
238
+ const nameNode = node.childForFieldName('name');
239
+ if (!nameNode)
240
+ return null;
241
+ const typeName = nameNode.text;
242
+ const ownerFqn = typeName;
243
+ const fields = [];
244
+ const nestedTypes = [];
245
+ // Handle different declaration types
246
+ if (node.type === 'class_declaration' || node.type === 'abstract_class_declaration') {
247
+ // Find the class body
248
+ const bodyNode = node.childForFieldName('body');
249
+ if (bodyNode) {
250
+ const extractedFields = this.extractFieldsFromBody(bodyNode, context);
251
+ fields.push(...extractedFields);
252
+ }
253
+ }
254
+ else if (node.type === 'interface_declaration') {
255
+ // Find the interface body
256
+ const bodyNode = node.childForFieldName('body');
257
+ if (bodyNode) {
258
+ const extractedFields = this.extractFieldsFromBody(bodyNode, context);
259
+ fields.push(...extractedFields);
260
+ }
261
+ }
262
+ else if (node.type === 'type_alias_declaration') {
263
+ // Handle type aliases with object types
264
+ const valueNode = node.childForFieldName('value');
265
+ if (valueNode && valueNode.type === 'object_type') {
266
+ const extractedFields = this.extractFieldsFromObjectType(valueNode, context);
267
+ fields.push(...extractedFields);
268
+ }
269
+ }
270
+ // Find nested type declarations
271
+ const nestedClasses = node.descendantsOfType('class_declaration');
272
+ const nestedInterfaces = node.descendantsOfType('interface_declaration');
273
+ const nestedDeclarations = [...nestedClasses, ...nestedInterfaces];
274
+ for (const nested of nestedDeclarations) {
275
+ // Skip the current node itself
276
+ if (nested === node)
277
+ continue;
278
+ const nestedName = nested.childForFieldName('name');
279
+ if (nestedName) {
280
+ nestedTypes.push(nestedName.text);
281
+ }
282
+ }
283
+ return {
284
+ ownerFqn,
285
+ fields,
286
+ nestedTypes,
287
+ };
288
+ }
289
+ }
290
+ // Export a singleton instance for registration
291
+ export const typescriptFieldExtractor = new TypeScriptFieldExtractor();
@@ -0,0 +1,59 @@
1
+ import type { TypeEnvironment } from './type-env.js';
2
+ import type { SymbolTable } from './symbol-table.js';
3
+ import { SupportedLanguages } from '../../config/supported-languages.js';
4
+ /**
5
+ * Visibility levels used across all supported languages.
6
+ * - public / private / protected: universal modifiers
7
+ * - internal: C#, Kotlin (assembly/module scope)
8
+ * - package: Java (package-private, no keyword)
9
+ * - fileprivate: Swift (file scope)
10
+ * - open: Swift (subclassable across modules)
11
+ */
12
+ export type FieldVisibility = 'public' | 'private' | 'protected' | 'internal' | 'package' | 'fileprivate' | 'open';
13
+ /**
14
+ * Represents a field or property within a class/struct/interface
15
+ */
16
+ export interface FieldInfo {
17
+ /** Field name */
18
+ name: string;
19
+ /** Resolved type (may be primitive, FQN, or generic) */
20
+ type: string | null;
21
+ /** Visibility modifier */
22
+ visibility: FieldVisibility;
23
+ /** Is this a static member? */
24
+ isStatic: boolean;
25
+ /** Is this readonly/const? */
26
+ isReadonly: boolean;
27
+ /** Source file path */
28
+ sourceFile: string;
29
+ /** Line number */
30
+ line: number;
31
+ }
32
+ /**
33
+ * Maps owner type FQN to its fields
34
+ */
35
+ export type FieldTypeMap = Map<string, FieldInfo[]>;
36
+ /**
37
+ * Context for field extraction
38
+ */
39
+ export interface FieldExtractorContext {
40
+ /** Type environment for resolution */
41
+ typeEnv: TypeEnvironment;
42
+ /** Symbol table for FQN lookups */
43
+ symbolTable: SymbolTable;
44
+ /** Current file path */
45
+ filePath: string;
46
+ /** Language ID */
47
+ language: SupportedLanguages;
48
+ }
49
+ /**
50
+ * Result of field extraction from a type declaration
51
+ */
52
+ export interface ExtractedFields {
53
+ /** Owner type FQN */
54
+ ownerFqn: string;
55
+ /** Extracted fields */
56
+ fields: FieldInfo[];
57
+ /** Nested types found during extraction */
58
+ nestedTypes: string[];
59
+ }
@@ -0,0 +1,2 @@
1
+ // gitnexus/src/core/ingestion/field-types.ts
2
+ export {};
@@ -28,6 +28,7 @@ export declare function detectFrameworkFromPath(filePath: string): FrameworkHint
28
28
  */
29
29
  export declare const FRAMEWORK_AST_PATTERNS: {
30
30
  nestjs: string[];
31
+ 'expo-router': string[];
31
32
  express: string[];
32
33
  fastapi: string[];
33
34
  flask: string[];
@@ -42,6 +43,8 @@ export declare const FRAMEWORK_AST_PATTERNS: {
42
43
  echo: string[];
43
44
  fiber: string[];
44
45
  'go-grpc': string[];
46
+ prisma: string[];
47
+ supabase: string[];
45
48
  laravel: string[];
46
49
  actix: string[];
47
50
  axum: string[];
@@ -53,6 +56,90 @@ export declare const FRAMEWORK_AST_PATTERNS: {
53
56
  vapor: string[];
54
57
  rails: string[];
55
58
  sinatra: string[];
59
+ flutter: string[];
60
+ riverpod: string[];
61
+ };
62
+ export declare const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE: {
63
+ javascript: {
64
+ framework: string;
65
+ entryPointMultiplier: number;
66
+ reason: string;
67
+ patterns: string[];
68
+ }[];
69
+ typescript: {
70
+ framework: string;
71
+ entryPointMultiplier: number;
72
+ reason: string;
73
+ patterns: string[];
74
+ }[];
75
+ python: {
76
+ framework: string;
77
+ entryPointMultiplier: number;
78
+ reason: string;
79
+ patterns: string[];
80
+ }[];
81
+ java: {
82
+ framework: string;
83
+ entryPointMultiplier: number;
84
+ reason: string;
85
+ patterns: string[];
86
+ }[];
87
+ kotlin: {
88
+ framework: string;
89
+ entryPointMultiplier: number;
90
+ reason: string;
91
+ patterns: string[];
92
+ }[];
93
+ csharp: {
94
+ framework: string;
95
+ entryPointMultiplier: number;
96
+ reason: string;
97
+ patterns: string[];
98
+ }[];
99
+ php: {
100
+ framework: string;
101
+ entryPointMultiplier: number;
102
+ reason: string;
103
+ patterns: string[];
104
+ }[];
105
+ go: {
106
+ framework: string;
107
+ entryPointMultiplier: number;
108
+ reason: string;
109
+ patterns: string[];
110
+ }[];
111
+ rust: {
112
+ framework: string;
113
+ entryPointMultiplier: number;
114
+ reason: string;
115
+ patterns: string[];
116
+ }[];
117
+ c: any[];
118
+ cpp: {
119
+ framework: string;
120
+ entryPointMultiplier: number;
121
+ reason: string;
122
+ patterns: string[];
123
+ }[];
124
+ swift: {
125
+ framework: string;
126
+ entryPointMultiplier: number;
127
+ reason: string;
128
+ patterns: string[];
129
+ }[];
130
+ ruby: {
131
+ framework: string;
132
+ entryPointMultiplier: number;
133
+ reason: string;
134
+ patterns: string[];
135
+ }[];
136
+ dart: {
137
+ framework: string;
138
+ entryPointMultiplier: number;
139
+ reason: string;
140
+ patterns: string[];
141
+ }[];
142
+ cobol: any[];
56
143
  };
57
144
  /**
58
145
  * Detect framework entry points from AST definition text (decorators/annotations/attributes).
@@ -42,9 +42,32 @@ export function detectFrameworkFromPath(filePath) {
42
42
  return { framework: 'nextjs-api', entryPointMultiplier: 3.0, reason: 'nextjs-api-route' };
43
43
  }
44
44
  // Next.js - Layout files (moderate - they're entry-ish but not the main entry)
45
- if (p.includes('/app/') && (p.endsWith('layout.tsx') || p.endsWith('layout.ts'))) {
45
+ if (p.includes('/app/') && !p.includes('_layout') && (p.endsWith('layout.tsx') || p.endsWith('layout.ts'))) {
46
46
  return { framework: 'nextjs-app', entryPointMultiplier: 2.0, reason: 'nextjs-layout' };
47
47
  }
48
+ // Expo Router - screen/layout/api files in app/ directory
49
+ if (p.includes('/app/') && (p.endsWith('.tsx') || p.endsWith('.ts') || p.endsWith('.jsx') || p.endsWith('.js'))) {
50
+ const fn = p.split('/').pop() || '';
51
+ if (fn.startsWith('_layout')) {
52
+ return { framework: 'expo-router', entryPointMultiplier: 2.0, reason: 'expo-layout' };
53
+ }
54
+ if (fn.startsWith('+') && !fn.startsWith('+api')) {
55
+ return { framework: 'expo-router', entryPointMultiplier: 1.5, reason: 'expo-special-route' };
56
+ }
57
+ if (fn.endsWith('+api.ts') || fn.endsWith('+api.tsx')) {
58
+ return { framework: 'expo-router', entryPointMultiplier: 3.0, reason: 'expo-api-route' };
59
+ }
60
+ return { framework: 'expo-router', entryPointMultiplier: 2.5, reason: 'expo-screen' };
61
+ }
62
+ // Prisma schema (ORM data model definition)
63
+ if (p.includes('/prisma/') && p.endsWith('schema.prisma')) {
64
+ return { framework: 'prisma', entryPointMultiplier: 1.5, reason: 'prisma-schema' };
65
+ }
66
+ // Supabase client files
67
+ if ((p.includes('/lib/supabase') || p.includes('/utils/supabase') || p.includes('/supabase/')) &&
68
+ (p.endsWith('.ts') || p.endsWith('.js'))) {
69
+ return { framework: 'supabase', entryPointMultiplier: 1.5, reason: 'supabase-client' };
70
+ }
48
71
  // Express / Node.js routes
49
72
  if (p.includes('/routes/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
50
73
  return { framework: 'express', entryPointMultiplier: 2.5, reason: 'routes-folder' };
@@ -302,6 +325,31 @@ export function detectFrameworkFromPath(filePath) {
302
325
  if (p.includes('/router/') && p.endsWith('.swift')) {
303
326
  return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
304
327
  }
328
+ // ========== DART / FLUTTER ==========
329
+ // Flutter main/app entry points
330
+ if (p.endsWith('/main.dart') || p.endsWith('/app.dart')) {
331
+ return { framework: 'flutter', entryPointMultiplier: 3.0, reason: 'flutter-main' };
332
+ }
333
+ // Flutter screens/pages/views (high priority - route entry points)
334
+ if ((p.includes('/screens/') || p.includes('/pages/') || p.includes('/views/')) && p.endsWith('.dart')) {
335
+ return { framework: 'flutter', entryPointMultiplier: 2.5, reason: 'flutter-screen' };
336
+ }
337
+ // Flutter routes
338
+ if (p.includes('/routes/') && p.endsWith('.dart')) {
339
+ return { framework: 'flutter', entryPointMultiplier: 2.5, reason: 'flutter-routes' };
340
+ }
341
+ // Flutter BLoC / controllers / presentation (state management entry points)
342
+ if ((p.includes('/bloc/') || p.includes('/controllers/') || p.includes('/cubit/') || p.includes('/presentation/')) && p.endsWith('.dart')) {
343
+ return { framework: 'flutter', entryPointMultiplier: 2.0, reason: 'flutter-state-management' };
344
+ }
345
+ // Flutter services / domain
346
+ if ((p.includes('/services/') || p.includes('/domain/')) && p.endsWith('.dart')) {
347
+ return { framework: 'flutter', entryPointMultiplier: 1.8, reason: 'flutter-service' };
348
+ }
349
+ // Flutter widgets (reusable components)
350
+ if (p.includes('/widgets/') && p.endsWith('.dart')) {
351
+ return { framework: 'flutter', entryPointMultiplier: 1.5, reason: 'flutter-widget' };
352
+ }
305
353
  // ========== GENERIC PATTERNS ==========
306
354
  // Any language: index files in API folders
307
355
  if (p.includes('/api/') && (p.endsWith('/index.ts') || p.endsWith('/index.js') ||
@@ -321,6 +369,7 @@ export function detectFrameworkFromPath(filePath) {
321
369
  export const FRAMEWORK_AST_PATTERNS = {
322
370
  // JavaScript/TypeScript decorators
323
371
  'nestjs': ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
372
+ 'expo-router': ['router.push', 'router.replace', 'router.navigate', 'useRouter', 'useLocalSearchParams', 'useSegments', 'expo-router'],
324
373
  'express': ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
325
374
  // Python decorators
326
375
  'fastapi': ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
@@ -340,6 +389,9 @@ export const FRAMEWORK_AST_PATTERNS = {
340
389
  'echo': ['echo.Context', 'echo.New'],
341
390
  'fiber': ['fiber.Ctx', 'fiber.New', 'fiber.App'],
342
391
  'go-grpc': ['grpc.Server', 'RegisterServer', 'pb.Unimplemented'],
392
+ // ORM patterns
393
+ 'prisma': ['prisma.', 'PrismaClient', '@prisma/client'],
394
+ 'supabase': ['supabase.from', 'createClient', '@supabase/supabase-js'],
343
395
  // PHP/Laravel
344
396
  'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete',
345
397
  'Route::resource', 'Route::apiResource', '#[Route('],
@@ -358,13 +410,19 @@ export const FRAMEWORK_AST_PATTERNS = {
358
410
  'rails': ['ApplicationController', 'ApplicationRecord', 'ActiveRecord::Base',
359
411
  'before_action', 'after_action', 'has_many', 'belongs_to', 'has_one', 'validates'],
360
412
  'sinatra': ['Sinatra::Base', 'Sinatra::Application'],
413
+ // Dart/Flutter
414
+ 'flutter': ['StatelessWidget', 'StatefulWidget', 'BuildContext', 'Widget build',
415
+ 'ChangeNotifier', 'GetxController', 'Cubit<', 'Bloc<', 'ConsumerWidget'],
416
+ 'riverpod': ['@riverpod', 'ref.watch', 'ref.read', 'AsyncNotifier', 'Notifier'],
361
417
  };
362
- const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
418
+ export const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
363
419
  [SupportedLanguages.JavaScript]: [
364
420
  { framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
421
+ { framework: 'expo-router', entryPointMultiplier: 2.5, reason: 'expo-router-navigation', patterns: FRAMEWORK_AST_PATTERNS['expo-router'] },
365
422
  ],
366
423
  [SupportedLanguages.TypeScript]: [
367
424
  { framework: 'nestjs', entryPointMultiplier: 3.2, reason: 'nestjs-decorator', patterns: FRAMEWORK_AST_PATTERNS.nestjs },
425
+ { framework: 'expo-router', entryPointMultiplier: 2.5, reason: 'expo-router-navigation', patterns: FRAMEWORK_AST_PATTERNS['expo-router'] },
368
426
  ],
369
427
  [SupportedLanguages.Python]: [
370
428
  { framework: 'fastapi', entryPointMultiplier: 3.0, reason: 'fastapi-decorator', patterns: FRAMEWORK_AST_PATTERNS.fastapi },
@@ -415,6 +473,11 @@ const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
415
473
  { framework: 'rails', entryPointMultiplier: 3.0, reason: 'rails-pattern', patterns: FRAMEWORK_AST_PATTERNS.rails },
416
474
  { framework: 'sinatra', entryPointMultiplier: 2.8, reason: 'sinatra-pattern', patterns: FRAMEWORK_AST_PATTERNS.sinatra },
417
475
  ],
476
+ [SupportedLanguages.Dart]: [
477
+ { framework: 'flutter', entryPointMultiplier: 2.5, reason: 'flutter-widget', patterns: FRAMEWORK_AST_PATTERNS.flutter },
478
+ { framework: 'riverpod', entryPointMultiplier: 2.8, reason: 'riverpod-pattern', patterns: FRAMEWORK_AST_PATTERNS.riverpod },
479
+ ],
480
+ [SupportedLanguages.Cobol]: [], // Standalone regex processor — no AST framework patterns
418
481
  };
419
482
  /** Pre-lowercased patterns for O(1) pattern matching at runtime */
420
483
  const AST_PATTERNS_LOWERED = Object.fromEntries(Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [
@@ -15,20 +15,19 @@
15
15
  */
16
16
  import Parser from 'tree-sitter';
17
17
  import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
18
- import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
19
18
  import { generateId } from '../../lib/utils.js';
20
- import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
21
- import { SupportedLanguages } from '../../config/supported-languages.js';
19
+ import { getLanguageFromFilename } from './utils/language-detection.js';
20
+ import { isVerboseIngestionEnabled } from './utils/verbose.js';
21
+ import { yieldToEventLoop } from './utils/event-loop.js';
22
+ import { getProvider } from './languages/index.js';
22
23
  import { getTreeSitterBufferSize } from './constants.js';
23
24
  import { TIER_CONFIDENCE } from './resolution-context.js';
24
- /** C#/Java convention: interfaces start with I followed by an uppercase letter */
25
- const INTERFACE_NAME_RE = /^I[A-Z]/;
26
25
  /**
27
26
  * Determine whether a heritage.extends capture is actually an IMPLEMENTS relationship.
28
- * Uses the symbol table first (authoritative — Tier 1); falls back to a language-gated
29
- * heuristic for external symbols not present in the graph:
30
- * - C# / Java: `I[A-Z]` naming convention
31
- * - Swift: default IMPLEMENTS (protocol conformance is the norm)
27
+ * Uses the symbol table first (authoritative — Tier 1); falls back to provider-defined
28
+ * heuristics for external symbols not present in the graph:
29
+ * - interfaceNamePattern: matched against parent name (e.g., /^I[A-Z]/ for C#/Java)
30
+ * - heritageDefaultEdge: 'IMPLEMENTS' causes all unresolved parents to map to IMPLEMENTS
32
31
  * - All others: default EXTENDS
33
32
  */
34
33
  const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
@@ -39,14 +38,12 @@ const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
39
38
  ? { type: 'IMPLEMENTS', idPrefix: 'Interface' }
40
39
  : { type: 'EXTENDS', idPrefix: 'Class' };
41
40
  }
42
- // Unresolved symbol — fall back to language-specific heuristic
43
- if (language === SupportedLanguages.CSharp || language === SupportedLanguages.Java) {
44
- if (INTERFACE_NAME_RE.test(parentName)) {
45
- return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
46
- }
41
+ // Unresolved symbol — fall back to provider-defined heuristics
42
+ const provider = getProvider(language);
43
+ if (provider.interfaceNamePattern?.test(parentName)) {
44
+ return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
47
45
  }
48
- else if (language === SupportedLanguages.Swift) {
49
- // Protocol conformance is far more common than class inheritance in Swift
46
+ if (provider.heritageDefaultEdge === 'IMPLEMENTS') {
50
47
  return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
51
48
  }
52
49
  return { type: 'EXTENDS', idPrefix: 'Class' };
@@ -82,7 +79,8 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
82
79
  }
83
80
  continue;
84
81
  }
85
- const queryStr = LANGUAGE_QUERIES[language];
82
+ const provider = getProvider(language);
83
+ const queryStr = provider.treeSitterQueries;
86
84
  if (!queryStr)
87
85
  continue;
88
86
  // 2. Load the language
@@ -1,9 +1,10 @@
1
1
  import { KnowledgeGraph } from '../graph/types.js';
2
2
  import { ASTCache } from './ast-cache.js';
3
+ import type { LanguageProvider } from './language-provider.js';
3
4
  import type { ExtractedImport } from './workers/parse-worker.js';
4
5
  import type { ResolutionContext } from './resolution-context.js';
5
- import type { SuffixIndex } from './resolvers/index.js';
6
- export type { SuffixIndex, TsconfigPaths, GoModuleConfig, CSharpProjectConfig, ComposerConfig } from './resolvers/index.js';
6
+ import type { ImportResolutionContext } from './import-resolvers/types.js';
7
+ import type { SyntaxNode } from './utils/ast-helpers.js';
7
8
  export type ImportMap = Map<string, Set<string>>;
8
9
  export type PackageMap = Map<string, Set<string>>;
9
10
  export interface NamedImportBinding {
@@ -16,15 +17,13 @@ export type NamedImportMap = Map<string, Map<string, NamedImportBinding>>;
16
17
  * Used by the symbol resolver for Go and C# directory-level import matching.
17
18
  */
18
19
  export declare function isFileInPackageDir(filePath: string, dirSuffix: string): boolean;
19
- /** Pre-built lookup structures for import resolution. Build once, reuse across chunks. */
20
- export interface ImportResolutionContext {
21
- allFilePaths: Set<string>;
22
- allFileList: string[];
23
- normalizedFileList: string[];
24
- index: SuffixIndex;
25
- resolveCache: Map<string, string | null>;
26
- }
27
20
  export declare function buildImportResolutionContext(allPaths: string[]): ImportResolutionContext;
21
+ /**
22
+ * Clean and preprocess a raw import source text into a resolved import path.
23
+ * Strips quotes/angle brackets (universal) and applies provider-specific
24
+ * transformations (currently only Kotlin wildcard import detection).
25
+ */
26
+ export declare function preprocessImportPath(sourceText: string, importNode: SyntaxNode, provider: LanguageProvider): string | null;
28
27
  export declare const processImports: (graph: KnowledgeGraph, files: {
29
28
  path: string;
30
29
  content: string;