gitnexus 1.4.7 → 1.4.9

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 (242) hide show
  1. package/README.md +29 -1
  2. package/dist/cli/ai-context.d.ts +1 -1
  3. package/dist/cli/ai-context.js +1 -1
  4. package/dist/cli/analyze.d.ts +2 -0
  5. package/dist/cli/analyze.js +54 -21
  6. package/dist/cli/index-repo.d.ts +15 -0
  7. package/dist/cli/index-repo.js +115 -0
  8. package/dist/cli/index.js +13 -3
  9. package/dist/cli/setup.js +90 -10
  10. package/dist/cli/wiki.d.ts +4 -0
  11. package/dist/cli/wiki.js +174 -53
  12. package/dist/config/supported-languages.d.ts +33 -1
  13. package/dist/config/supported-languages.js +32 -0
  14. package/dist/core/embeddings/embedder.d.ts +6 -1
  15. package/dist/core/embeddings/embedder.js +65 -5
  16. package/dist/core/embeddings/embedding-pipeline.js +11 -9
  17. package/dist/core/embeddings/http-client.d.ts +31 -0
  18. package/dist/core/embeddings/http-client.js +179 -0
  19. package/dist/core/embeddings/index.d.ts +1 -0
  20. package/dist/core/embeddings/index.js +1 -0
  21. package/dist/core/embeddings/types.d.ts +1 -1
  22. package/dist/core/graph/graph.js +9 -1
  23. package/dist/core/graph/types.d.ts +11 -2
  24. package/dist/core/ingestion/call-processor.d.ts +66 -2
  25. package/dist/core/ingestion/call-processor.js +650 -30
  26. package/dist/core/ingestion/call-routing.d.ts +9 -18
  27. package/dist/core/ingestion/call-routing.js +0 -19
  28. package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
  29. package/dist/core/ingestion/cobol/cobol-copy-expander.js +385 -0
  30. package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +210 -0
  31. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1509 -0
  32. package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
  33. package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
  34. package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
  35. package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
  36. package/dist/core/ingestion/cobol-processor.d.ts +54 -0
  37. package/dist/core/ingestion/cobol-processor.js +1186 -0
  38. package/dist/core/ingestion/entry-point-scoring.d.ts +17 -0
  39. package/dist/core/ingestion/entry-point-scoring.js +52 -28
  40. package/dist/core/ingestion/export-detection.d.ts +47 -8
  41. package/dist/core/ingestion/export-detection.js +29 -50
  42. package/dist/core/ingestion/field-extractor.d.ts +29 -0
  43. package/dist/core/ingestion/field-extractor.js +25 -0
  44. package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
  45. package/dist/core/ingestion/field-extractors/configs/c-cpp.js +108 -0
  46. package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
  47. package/dist/core/ingestion/field-extractors/configs/csharp.js +73 -0
  48. package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
  49. package/dist/core/ingestion/field-extractors/configs/dart.js +76 -0
  50. package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
  51. package/dist/core/ingestion/field-extractors/configs/go.js +64 -0
  52. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +44 -0
  53. package/dist/core/ingestion/field-extractors/configs/helpers.js +134 -0
  54. package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
  55. package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
  56. package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
  57. package/dist/core/ingestion/field-extractors/configs/php.js +67 -0
  58. package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
  59. package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
  60. package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
  61. package/dist/core/ingestion/field-extractors/configs/ruby.js +75 -0
  62. package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
  63. package/dist/core/ingestion/field-extractors/configs/rust.js +55 -0
  64. package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
  65. package/dist/core/ingestion/field-extractors/configs/swift.js +63 -0
  66. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
  67. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +60 -0
  68. package/dist/core/ingestion/field-extractors/generic.d.ts +46 -0
  69. package/dist/core/ingestion/field-extractors/generic.js +111 -0
  70. package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
  71. package/dist/core/ingestion/field-extractors/typescript.js +291 -0
  72. package/dist/core/ingestion/field-types.d.ts +59 -0
  73. package/dist/core/ingestion/field-types.js +2 -0
  74. package/dist/core/ingestion/framework-detection.d.ts +97 -2
  75. package/dist/core/ingestion/framework-detection.js +114 -14
  76. package/dist/core/ingestion/heritage-processor.js +62 -66
  77. package/dist/core/ingestion/import-processor.d.ts +9 -10
  78. package/dist/core/ingestion/import-processor.js +150 -196
  79. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.d.ts +6 -9
  80. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.js +20 -2
  81. package/dist/core/ingestion/import-resolvers/dart.d.ts +7 -0
  82. package/dist/core/ingestion/import-resolvers/dart.js +44 -0
  83. package/dist/core/ingestion/{resolvers → import-resolvers}/go.d.ts +4 -5
  84. package/dist/core/ingestion/{resolvers → import-resolvers}/go.js +17 -0
  85. package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.d.ts +10 -1
  86. package/dist/core/ingestion/import-resolvers/jvm.js +159 -0
  87. package/dist/core/ingestion/import-resolvers/php.d.ts +25 -0
  88. package/dist/core/ingestion/import-resolvers/php.js +80 -0
  89. package/dist/core/ingestion/{resolvers → import-resolvers}/python.d.ts +9 -3
  90. package/dist/core/ingestion/{resolvers → import-resolvers}/python.js +35 -3
  91. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.d.ts +5 -2
  92. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.js +7 -2
  93. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.d.ts +5 -2
  94. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.js +41 -2
  95. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.d.ts +15 -7
  96. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.js +22 -3
  97. package/dist/core/ingestion/import-resolvers/swift.d.ts +7 -0
  98. package/dist/core/ingestion/import-resolvers/swift.js +23 -0
  99. package/dist/core/ingestion/import-resolvers/types.d.ts +44 -0
  100. package/dist/core/ingestion/import-resolvers/types.js +6 -0
  101. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.d.ts +2 -0
  102. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +7 -0
  103. package/dist/core/ingestion/language-config.d.ts +6 -0
  104. package/dist/core/ingestion/language-config.js +13 -0
  105. package/dist/core/ingestion/language-provider.d.ts +121 -0
  106. package/dist/core/ingestion/language-provider.js +24 -0
  107. package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
  108. package/dist/core/ingestion/languages/c-cpp.js +71 -0
  109. package/dist/core/ingestion/languages/cobol.d.ts +1 -0
  110. package/dist/core/ingestion/languages/cobol.js +26 -0
  111. package/dist/core/ingestion/languages/csharp.d.ts +8 -0
  112. package/dist/core/ingestion/languages/csharp.js +49 -0
  113. package/dist/core/ingestion/languages/dart.d.ts +12 -0
  114. package/dist/core/ingestion/languages/dart.js +58 -0
  115. package/dist/core/ingestion/languages/go.d.ts +11 -0
  116. package/dist/core/ingestion/languages/go.js +28 -0
  117. package/dist/core/ingestion/languages/index.d.ts +38 -0
  118. package/dist/core/ingestion/languages/index.js +63 -0
  119. package/dist/core/ingestion/languages/java.d.ts +9 -0
  120. package/dist/core/ingestion/languages/java.js +29 -0
  121. package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
  122. package/dist/core/ingestion/languages/kotlin.js +53 -0
  123. package/dist/core/ingestion/languages/php.d.ts +8 -0
  124. package/dist/core/ingestion/languages/php.js +145 -0
  125. package/dist/core/ingestion/languages/python.d.ts +12 -0
  126. package/dist/core/ingestion/languages/python.js +39 -0
  127. package/dist/core/ingestion/languages/ruby.d.ts +9 -0
  128. package/dist/core/ingestion/languages/ruby.js +44 -0
  129. package/dist/core/ingestion/languages/rust.d.ts +12 -0
  130. package/dist/core/ingestion/languages/rust.js +44 -0
  131. package/dist/core/ingestion/languages/swift.d.ts +12 -0
  132. package/dist/core/ingestion/languages/swift.js +133 -0
  133. package/dist/core/ingestion/languages/typescript.d.ts +10 -0
  134. package/dist/core/ingestion/languages/typescript.js +60 -0
  135. package/dist/core/ingestion/markdown-processor.d.ts +17 -0
  136. package/dist/core/ingestion/markdown-processor.js +124 -0
  137. package/dist/core/ingestion/mro-processor.js +22 -18
  138. package/dist/core/ingestion/named-binding-processor.d.ts +18 -0
  139. package/dist/core/ingestion/named-binding-processor.js +42 -0
  140. package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
  141. package/dist/core/ingestion/named-bindings/csharp.js +37 -0
  142. package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
  143. package/dist/core/ingestion/named-bindings/java.js +29 -0
  144. package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
  145. package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
  146. package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
  147. package/dist/core/ingestion/named-bindings/php.js +61 -0
  148. package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
  149. package/dist/core/ingestion/named-bindings/python.js +49 -0
  150. package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
  151. package/dist/core/ingestion/named-bindings/rust.js +64 -0
  152. package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
  153. package/dist/core/ingestion/named-bindings/types.js +6 -0
  154. package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
  155. package/dist/core/ingestion/named-bindings/typescript.js +58 -0
  156. package/dist/core/ingestion/parsing-processor.d.ts +6 -2
  157. package/dist/core/ingestion/parsing-processor.js +125 -85
  158. package/dist/core/ingestion/pipeline.d.ts +10 -0
  159. package/dist/core/ingestion/pipeline.js +1235 -317
  160. package/dist/core/ingestion/resolution-context.d.ts +5 -0
  161. package/dist/core/ingestion/resolution-context.js +8 -5
  162. package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
  163. package/dist/core/ingestion/route-extractors/expo.js +36 -0
  164. package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
  165. package/dist/core/ingestion/route-extractors/middleware.js +143 -0
  166. package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
  167. package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
  168. package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
  169. package/dist/core/ingestion/route-extractors/php.js +21 -0
  170. package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
  171. package/dist/core/ingestion/route-extractors/response-shapes.js +290 -0
  172. package/dist/core/ingestion/symbol-table.d.ts +16 -0
  173. package/dist/core/ingestion/symbol-table.js +20 -6
  174. package/dist/core/ingestion/tree-sitter-queries.d.ts +10 -9
  175. package/dist/core/ingestion/tree-sitter-queries.js +274 -11
  176. package/dist/core/ingestion/type-env.d.ts +42 -18
  177. package/dist/core/ingestion/type-env.js +481 -106
  178. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +5 -0
  179. package/dist/core/ingestion/type-extractors/c-cpp.js +119 -0
  180. package/dist/core/ingestion/type-extractors/csharp.js +149 -16
  181. package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
  182. package/dist/core/ingestion/type-extractors/dart.js +371 -0
  183. package/dist/core/ingestion/type-extractors/jvm.js +169 -66
  184. package/dist/core/ingestion/type-extractors/rust.js +35 -1
  185. package/dist/core/ingestion/type-extractors/shared.d.ts +1 -15
  186. package/dist/core/ingestion/type-extractors/shared.js +14 -112
  187. package/dist/core/ingestion/type-extractors/swift.js +338 -7
  188. package/dist/core/ingestion/type-extractors/types.d.ts +40 -8
  189. package/dist/core/ingestion/type-extractors/typescript.js +141 -9
  190. package/dist/core/ingestion/utils/ast-helpers.d.ts +83 -0
  191. package/dist/core/ingestion/utils/ast-helpers.js +817 -0
  192. package/dist/core/ingestion/utils/call-analysis.d.ts +73 -0
  193. package/dist/core/ingestion/utils/call-analysis.js +527 -0
  194. package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
  195. package/dist/core/ingestion/utils/event-loop.js +5 -0
  196. package/dist/core/ingestion/utils/language-detection.d.ts +9 -0
  197. package/dist/core/ingestion/utils/language-detection.js +70 -0
  198. package/dist/core/ingestion/utils/verbose.d.ts +1 -0
  199. package/dist/core/ingestion/utils/verbose.js +7 -0
  200. package/dist/core/ingestion/workers/parse-worker.d.ts +55 -5
  201. package/dist/core/ingestion/workers/parse-worker.js +415 -225
  202. package/dist/core/lbug/csv-generator.js +51 -1
  203. package/dist/core/lbug/lbug-adapter.d.ts +10 -0
  204. package/dist/core/lbug/lbug-adapter.js +75 -4
  205. package/dist/core/lbug/schema.d.ts +8 -4
  206. package/dist/core/lbug/schema.js +65 -4
  207. package/dist/core/tree-sitter/parser-loader.js +7 -1
  208. package/dist/core/wiki/cursor-client.d.ts +31 -0
  209. package/dist/core/wiki/cursor-client.js +127 -0
  210. package/dist/core/wiki/generator.d.ts +28 -9
  211. package/dist/core/wiki/generator.js +115 -18
  212. package/dist/core/wiki/graph-queries.d.ts +4 -0
  213. package/dist/core/wiki/graph-queries.js +7 -1
  214. package/dist/core/wiki/llm-client.d.ts +2 -0
  215. package/dist/core/wiki/llm-client.js +8 -4
  216. package/dist/core/wiki/prompts.d.ts +3 -3
  217. package/dist/core/wiki/prompts.js +6 -0
  218. package/dist/mcp/core/embedder.js +11 -3
  219. package/dist/mcp/core/lbug-adapter.d.ts +5 -0
  220. package/dist/mcp/core/lbug-adapter.js +23 -2
  221. package/dist/mcp/local/local-backend.d.ts +38 -5
  222. package/dist/mcp/local/local-backend.js +804 -63
  223. package/dist/mcp/resources.js +2 -0
  224. package/dist/mcp/tools.js +73 -4
  225. package/dist/server/api.d.ts +19 -1
  226. package/dist/server/api.js +66 -6
  227. package/dist/storage/git.d.ts +12 -0
  228. package/dist/storage/git.js +21 -0
  229. package/dist/storage/repo-manager.d.ts +3 -0
  230. package/package.json +25 -16
  231. package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
  232. package/dist/core/ingestion/named-binding-extraction.js +0 -363
  233. package/dist/core/ingestion/resolvers/index.d.ts +0 -18
  234. package/dist/core/ingestion/resolvers/index.js +0 -13
  235. package/dist/core/ingestion/resolvers/jvm.js +0 -87
  236. package/dist/core/ingestion/resolvers/php.d.ts +0 -15
  237. package/dist/core/ingestion/resolvers/php.js +0 -35
  238. package/dist/core/ingestion/type-extractors/index.d.ts +0 -22
  239. package/dist/core/ingestion/type-extractors/index.js +0 -31
  240. package/dist/core/ingestion/utils.d.ts +0 -138
  241. package/dist/core/ingestion/utils.js +0 -1290
  242. package/scripts/patch-tree-sitter-swift.cjs +0 -74
@@ -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 {};
@@ -9,6 +9,7 @@
9
9
  * DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
10
10
  * (no bonus, no penalty) - same behavior as before this feature.
11
11
  */
12
+ import { SupportedLanguages } from '../../config/supported-languages.js';
12
13
  export interface FrameworkHint {
13
14
  framework: string;
14
15
  entryPointMultiplier: number;
@@ -27,6 +28,7 @@ export declare function detectFrameworkFromPath(filePath: string): FrameworkHint
27
28
  */
28
29
  export declare const FRAMEWORK_AST_PATTERNS: {
29
30
  nestjs: string[];
31
+ 'expo-router': string[];
30
32
  express: string[];
31
33
  fastapi: string[];
32
34
  flask: string[];
@@ -37,15 +39,108 @@ export declare const FRAMEWORK_AST_PATTERNS: {
37
39
  blazor: string[];
38
40
  efcore: string[];
39
41
  'go-http': string[];
42
+ gin: string[];
43
+ echo: string[];
44
+ fiber: string[];
45
+ 'go-grpc': string[];
46
+ prisma: string[];
47
+ supabase: string[];
40
48
  laravel: string[];
41
49
  actix: string[];
42
50
  axum: string[];
43
51
  rocket: string[];
52
+ tokio: string[];
53
+ qt: string[];
44
54
  uikit: string[];
45
55
  swiftui: string[];
46
- combine: string[];
56
+ vapor: string[];
57
+ rails: string[];
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[];
47
143
  };
48
- import { SupportedLanguages } from '../../config/supported-languages.js';
49
144
  /**
50
145
  * Detect framework entry points from AST definition text (decorators/annotations/attributes).
51
146
  * Returns null if no known pattern is found.
@@ -9,6 +9,7 @@
9
9
  * DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
10
10
  * (no bonus, no penalty) - same behavior as before this feature.
11
11
  */
12
+ import { SupportedLanguages } from '../../config/supported-languages.js';
12
13
  // ============================================================================
13
14
  // PATH-BASED FRAMEWORK DETECTION
14
15
  // ============================================================================
@@ -41,9 +42,32 @@ export function detectFrameworkFromPath(filePath) {
41
42
  return { framework: 'nextjs-api', entryPointMultiplier: 3.0, reason: 'nextjs-api-route' };
42
43
  }
43
44
  // Next.js - Layout files (moderate - they're entry-ish but not the main entry)
44
- 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'))) {
45
46
  return { framework: 'nextjs-app', entryPointMultiplier: 2.0, reason: 'nextjs-layout' };
46
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
+ }
47
71
  // Express / Node.js routes
48
72
  if (p.includes('/routes/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
49
73
  return { framework: 'express', entryPointMultiplier: 2.5, reason: 'routes-folder' };
@@ -180,8 +204,8 @@ export function detectFrameworkFromPath(filePath) {
180
204
  if (p.includes('/controllers/') && p.endsWith('.go')) {
181
205
  return { framework: 'go-mvc', entryPointMultiplier: 2.5, reason: 'go-controller' };
182
206
  }
183
- // Go main.go files (THE entry point)
184
- if (p.endsWith('/main.go') || p.endsWith('/cmd/') && p.endsWith('.go')) {
207
+ // Go main.go files (THE entry point) — only match main.go, not arbitrary .go files under cmd/
208
+ if (p.endsWith('/main.go')) {
185
209
  return { framework: 'go', entryPointMultiplier: 3.0, reason: 'go-main' };
186
210
  }
187
211
  // ========== RUST FRAMEWORKS ==========
@@ -301,6 +325,31 @@ export function detectFrameworkFromPath(filePath) {
301
325
  if (p.includes('/router/') && p.endsWith('.swift')) {
302
326
  return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
303
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
+ }
304
353
  // ========== GENERIC PATTERNS ==========
305
354
  // Any language: index files in API folders
306
355
  if (p.includes('/api/') && (p.endsWith('/index.ts') || p.endsWith('/index.js') ||
@@ -320,6 +369,7 @@ export function detectFrameworkFromPath(filePath) {
320
369
  export const FRAMEWORK_AST_PATTERNS = {
321
370
  // JavaScript/TypeScript decorators
322
371
  'nestjs': ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
372
+ 'expo-router': ['router.push', 'router.replace', 'router.navigate', 'useRouter', 'useLocalSearchParams', 'useSegments', 'expo-router'],
323
373
  'express': ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
324
374
  // Python decorators
325
375
  'fastapi': ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
@@ -333,27 +383,46 @@ export const FRAMEWORK_AST_PATTERNS = {
333
383
  'signalr': ['[HubMethodName]', ': Hub', ': Hub<'],
334
384
  'blazor': ['@page', '[Parameter]', '@inject'],
335
385
  'efcore': ['DbContext', 'DbSet<', 'OnModelCreating'],
336
- // Go patterns (function signatures)
337
- 'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'],
386
+ // Go patterns (function signatures include framework types)
387
+ 'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP', 'http.ResponseWriter', 'http.Request'],
388
+ 'gin': ['gin.Context', 'gin.Default', 'gin.New'],
389
+ 'echo': ['echo.Context', 'echo.New'],
390
+ 'fiber': ['fiber.Ctx', 'fiber.New', 'fiber.App'],
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'],
338
395
  // PHP/Laravel
339
396
  'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete',
340
397
  'Route::resource', 'Route::apiResource', '#[Route('],
341
- // Rust macros
342
- 'actix': ['#[get', '#[post', '#[put', '#[delete'],
343
- 'axum': ['Router::new'],
344
- 'rocket': ['#[get', '#[post'],
398
+ // Rust macros (proc-macro attributes in definition text)
399
+ 'actix': ['#[get', '#[post', '#[put', '#[delete', '#[actix_web', 'HttpRequest', 'HttpResponse'],
400
+ 'axum': ['Router::new', 'axum::extract', 'axum::routing'],
401
+ 'rocket': ['#[get', '#[post', '#[launch', 'rocket::'],
402
+ 'tokio': ['#[tokio::main]', '#[tokio::test]'],
403
+ // C++ patterns (Qt, Boost)
404
+ 'qt': ['Q_OBJECT', 'Q_INVOKABLE', 'Q_PROPERTY', 'Q_SIGNALS', 'Q_SLOTS', 'Q_SIGNAL', 'Q_SLOT', 'QWidget', 'QApplication'],
345
405
  // Swift/iOS
346
- 'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController'],
347
- 'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject'],
348
- 'combine': ['sink', 'assign', 'Publisher', 'Subscriber'],
406
+ 'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController', '@IBOutlet', '@IBAction', '@objc'],
407
+ 'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject', '@EnvironmentObject', '@Published'],
408
+ 'vapor': ['app.get', 'app.post', 'req.content.decode', 'Vapor'],
409
+ // Ruby patterns (class-level macros in definition text)
410
+ 'rails': ['ApplicationController', 'ApplicationRecord', 'ActiveRecord::Base',
411
+ 'before_action', 'after_action', 'has_many', 'belongs_to', 'has_one', 'validates'],
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'],
349
417
  };
350
- import { SupportedLanguages } from '../../config/supported-languages.js';
351
- const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
418
+ export const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
352
419
  [SupportedLanguages.JavaScript]: [
353
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'] },
354
422
  ],
355
423
  [SupportedLanguages.TypeScript]: [
356
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'] },
357
426
  ],
358
427
  [SupportedLanguages.Python]: [
359
428
  { framework: 'fastapi', entryPointMultiplier: 3.0, reason: 'fastapi-decorator', patterns: FRAMEWORK_AST_PATTERNS.fastapi },
@@ -378,6 +447,37 @@ const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
378
447
  [SupportedLanguages.PHP]: [
379
448
  { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'php-route-attribute', patterns: FRAMEWORK_AST_PATTERNS.laravel },
380
449
  ],
450
+ [SupportedLanguages.Go]: [
451
+ { framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-http-handler', patterns: FRAMEWORK_AST_PATTERNS['go-http'] },
452
+ { framework: 'gin', entryPointMultiplier: 3.0, reason: 'gin-handler', patterns: FRAMEWORK_AST_PATTERNS.gin },
453
+ { framework: 'echo', entryPointMultiplier: 3.0, reason: 'echo-handler', patterns: FRAMEWORK_AST_PATTERNS.echo },
454
+ { framework: 'fiber', entryPointMultiplier: 3.0, reason: 'fiber-handler', patterns: FRAMEWORK_AST_PATTERNS.fiber },
455
+ { framework: 'go-grpc', entryPointMultiplier: 2.8, reason: 'grpc-service', patterns: FRAMEWORK_AST_PATTERNS['go-grpc'] },
456
+ ],
457
+ [SupportedLanguages.Rust]: [
458
+ { framework: 'actix-web', entryPointMultiplier: 3.0, reason: 'actix-attribute', patterns: FRAMEWORK_AST_PATTERNS.actix },
459
+ { framework: 'axum', entryPointMultiplier: 3.0, reason: 'axum-routing', patterns: FRAMEWORK_AST_PATTERNS.axum },
460
+ { framework: 'rocket', entryPointMultiplier: 3.0, reason: 'rocket-attribute', patterns: FRAMEWORK_AST_PATTERNS.rocket },
461
+ { framework: 'tokio', entryPointMultiplier: 2.5, reason: 'tokio-runtime', patterns: FRAMEWORK_AST_PATTERNS.tokio },
462
+ ],
463
+ [SupportedLanguages.C]: [], // C has no framework-specific AST patterns (POSIX/socket patterns are in entry-point-scoring)
464
+ [SupportedLanguages.CPlusPlus]: [
465
+ { framework: 'qt', entryPointMultiplier: 2.8, reason: 'qt-macro', patterns: FRAMEWORK_AST_PATTERNS.qt },
466
+ ],
467
+ [SupportedLanguages.Swift]: [
468
+ { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-lifecycle', patterns: FRAMEWORK_AST_PATTERNS.uikit },
469
+ { framework: 'swiftui', entryPointMultiplier: 2.8, reason: 'swiftui-pattern', patterns: FRAMEWORK_AST_PATTERNS.swiftui },
470
+ { framework: 'vapor', entryPointMultiplier: 3.0, reason: 'vapor-routing', patterns: FRAMEWORK_AST_PATTERNS.vapor },
471
+ ],
472
+ [SupportedLanguages.Ruby]: [
473
+ { framework: 'rails', entryPointMultiplier: 3.0, reason: 'rails-pattern', patterns: FRAMEWORK_AST_PATTERNS.rails },
474
+ { framework: 'sinatra', entryPointMultiplier: 2.8, reason: 'sinatra-pattern', patterns: FRAMEWORK_AST_PATTERNS.sinatra },
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
381
481
  };
382
482
  /** Pre-lowercased patterns for O(1) pattern matching at runtime */
383
483
  const AST_PATTERNS_LOWERED = Object.fromEntries(Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [