@untangle-code/parser-registry 0.0.0-stage → 0.1.1

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 (345) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +352 -2
  4. package/THIRD_PARTY_LICENSES.md +91 -0
  5. package/dist/boundaries/expression.d.ts +10 -0
  6. package/dist/boundaries/expression.d.ts.map +1 -0
  7. package/dist/boundaries/expression.js +95 -0
  8. package/dist/boundaries/expression.js.map +1 -0
  9. package/dist/boundaries/extract.d.ts +12 -0
  10. package/dist/boundaries/extract.d.ts.map +1 -0
  11. package/dist/boundaries/extract.js +259 -0
  12. package/dist/boundaries/extract.js.map +1 -0
  13. package/dist/boundaries/python.d.ts +6 -0
  14. package/dist/boundaries/python.d.ts.map +1 -0
  15. package/dist/boundaries/python.js +154 -0
  16. package/dist/boundaries/python.js.map +1 -0
  17. package/dist/index.d.ts +26 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +19 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/languages/astgrep-backend/adapter.d.ts +101 -0
  22. package/dist/languages/astgrep-backend/adapter.d.ts.map +1 -0
  23. package/dist/languages/astgrep-backend/adapter.js +130 -0
  24. package/dist/languages/astgrep-backend/adapter.js.map +1 -0
  25. package/dist/languages/astgrep-backend/index.d.ts +29 -0
  26. package/dist/languages/astgrep-backend/index.d.ts.map +1 -0
  27. package/dist/languages/astgrep-backend/index.js +28 -0
  28. package/dist/languages/astgrep-backend/index.js.map +1 -0
  29. package/dist/languages/astgrep-backend/lang/bash.d.ts +38 -0
  30. package/dist/languages/astgrep-backend/lang/bash.d.ts.map +1 -0
  31. package/dist/languages/astgrep-backend/lang/bash.js +42 -0
  32. package/dist/languages/astgrep-backend/lang/bash.js.map +1 -0
  33. package/dist/languages/astgrep-backend/lang/c.d.ts +33 -0
  34. package/dist/languages/astgrep-backend/lang/c.d.ts.map +1 -0
  35. package/dist/languages/astgrep-backend/lang/c.js +85 -0
  36. package/dist/languages/astgrep-backend/lang/c.js.map +1 -0
  37. package/dist/languages/astgrep-backend/lang/cpp.d.ts +27 -0
  38. package/dist/languages/astgrep-backend/lang/cpp.d.ts.map +1 -0
  39. package/dist/languages/astgrep-backend/lang/cpp.js +38 -0
  40. package/dist/languages/astgrep-backend/lang/cpp.js.map +1 -0
  41. package/dist/languages/astgrep-backend/lang/csharp.d.ts +24 -0
  42. package/dist/languages/astgrep-backend/lang/csharp.d.ts.map +1 -0
  43. package/dist/languages/astgrep-backend/lang/csharp.js +102 -0
  44. package/dist/languages/astgrep-backend/lang/csharp.js.map +1 -0
  45. package/dist/languages/astgrep-backend/lang/index.d.ts +29 -0
  46. package/dist/languages/astgrep-backend/lang/index.d.ts.map +1 -0
  47. package/dist/languages/astgrep-backend/lang/index.js +22 -0
  48. package/dist/languages/astgrep-backend/lang/index.js.map +1 -0
  49. package/dist/languages/astgrep-backend/lang/java.d.ts +26 -0
  50. package/dist/languages/astgrep-backend/lang/java.d.ts.map +1 -0
  51. package/dist/languages/astgrep-backend/lang/java.js +89 -0
  52. package/dist/languages/astgrep-backend/lang/java.js.map +1 -0
  53. package/dist/languages/astgrep-backend/lang/kotlin.d.ts +44 -0
  54. package/dist/languages/astgrep-backend/lang/kotlin.d.ts.map +1 -0
  55. package/dist/languages/astgrep-backend/lang/kotlin.js +94 -0
  56. package/dist/languages/astgrep-backend/lang/kotlin.js.map +1 -0
  57. package/dist/languages/astgrep-backend/lang/php.d.ts +23 -0
  58. package/dist/languages/astgrep-backend/lang/php.d.ts.map +1 -0
  59. package/dist/languages/astgrep-backend/lang/php.js +80 -0
  60. package/dist/languages/astgrep-backend/lang/php.js.map +1 -0
  61. package/dist/languages/astgrep-backend/lang/ruby.d.ts +37 -0
  62. package/dist/languages/astgrep-backend/lang/ruby.d.ts.map +1 -0
  63. package/dist/languages/astgrep-backend/lang/ruby.js +70 -0
  64. package/dist/languages/astgrep-backend/lang/ruby.js.map +1 -0
  65. package/dist/languages/astgrep-backend/lang/swift.d.ts +34 -0
  66. package/dist/languages/astgrep-backend/lang/swift.d.ts.map +1 -0
  67. package/dist/languages/astgrep-backend/lang/swift.js +86 -0
  68. package/dist/languages/astgrep-backend/lang/swift.js.map +1 -0
  69. package/dist/languages/astgrep-backend/languages.d.ts +55 -0
  70. package/dist/languages/astgrep-backend/languages.d.ts.map +1 -0
  71. package/dist/languages/astgrep-backend/languages.js +214 -0
  72. package/dist/languages/astgrep-backend/languages.js.map +1 -0
  73. package/dist/languages/astgrep-backend/napi.d.ts +71 -0
  74. package/dist/languages/astgrep-backend/napi.d.ts.map +1 -0
  75. package/dist/languages/astgrep-backend/napi.js +176 -0
  76. package/dist/languages/astgrep-backend/napi.js.map +1 -0
  77. package/dist/languages/astgrep-backend/syntax.d.ts +88 -0
  78. package/dist/languages/astgrep-backend/syntax.d.ts.map +1 -0
  79. package/dist/languages/astgrep-backend/syntax.js +180 -0
  80. package/dist/languages/astgrep-backend/syntax.js.map +1 -0
  81. package/dist/languages/index.d.ts +14 -0
  82. package/dist/languages/index.d.ts.map +1 -0
  83. package/dist/languages/index.js +37 -0
  84. package/dist/languages/index.js.map +1 -0
  85. package/dist/languages/javascript/index.d.ts +4 -0
  86. package/dist/languages/javascript/index.d.ts.map +1 -0
  87. package/dist/languages/javascript/index.js +7 -0
  88. package/dist/languages/javascript/index.js.map +1 -0
  89. package/dist/languages/jsx/index.d.ts +4 -0
  90. package/dist/languages/jsx/index.d.ts.map +1 -0
  91. package/dist/languages/jsx/index.js +7 -0
  92. package/dist/languages/jsx/index.js.map +1 -0
  93. package/dist/languages/prose/index.d.ts +53 -0
  94. package/dist/languages/prose/index.d.ts.map +1 -0
  95. package/dist/languages/prose/index.js +172 -0
  96. package/dist/languages/prose/index.js.map +1 -0
  97. package/dist/languages/prose/line-bytes.d.ts +31 -0
  98. package/dist/languages/prose/line-bytes.d.ts.map +1 -0
  99. package/dist/languages/prose/line-bytes.js +39 -0
  100. package/dist/languages/prose/line-bytes.js.map +1 -0
  101. package/dist/languages/python/create-adapter.d.ts +20 -0
  102. package/dist/languages/python/create-adapter.d.ts.map +1 -0
  103. package/dist/languages/python/create-adapter.js +9 -0
  104. package/dist/languages/python/create-adapter.js.map +1 -0
  105. package/dist/languages/python/index.d.ts +4 -0
  106. package/dist/languages/python/index.d.ts.map +1 -0
  107. package/dist/languages/python/index.js +6 -0
  108. package/dist/languages/python/index.js.map +1 -0
  109. package/dist/languages/python/profile.d.ts +36 -0
  110. package/dist/languages/python/profile.d.ts.map +1 -0
  111. package/dist/languages/python/profile.js +282 -0
  112. package/dist/languages/python/profile.js.map +1 -0
  113. package/dist/languages/python/signature.d.ts +53 -0
  114. package/dist/languages/python/signature.d.ts.map +1 -0
  115. package/dist/languages/python/signature.js +188 -0
  116. package/dist/languages/python/signature.js.map +1 -0
  117. package/dist/languages/python/table.d.ts +46 -0
  118. package/dist/languages/python/table.d.ts.map +1 -0
  119. package/dist/languages/python/table.js +88 -0
  120. package/dist/languages/python/table.js.map +1 -0
  121. package/dist/languages/shared/call-detection.d.ts +17 -0
  122. package/dist/languages/shared/call-detection.d.ts.map +1 -0
  123. package/dist/languages/shared/call-detection.js +86 -0
  124. package/dist/languages/shared/call-detection.js.map +1 -0
  125. package/dist/languages/shared/chunks.d.ts +28 -0
  126. package/dist/languages/shared/chunks.d.ts.map +1 -0
  127. package/dist/languages/shared/chunks.js +181 -0
  128. package/dist/languages/shared/chunks.js.map +1 -0
  129. package/dist/languages/shared/create-adapter.d.ts +11 -0
  130. package/dist/languages/shared/create-adapter.d.ts.map +1 -0
  131. package/dist/languages/shared/create-adapter.js +90 -0
  132. package/dist/languages/shared/create-adapter.js.map +1 -0
  133. package/dist/languages/shared/decisions.d.ts +45 -0
  134. package/dist/languages/shared/decisions.d.ts.map +1 -0
  135. package/dist/languages/shared/decisions.js +141 -0
  136. package/dist/languages/shared/decisions.js.map +1 -0
  137. package/dist/languages/shared/dialect.d.ts +18 -0
  138. package/dist/languages/shared/dialect.d.ts.map +1 -0
  139. package/dist/languages/shared/dialect.js +37 -0
  140. package/dist/languages/shared/dialect.js.map +1 -0
  141. package/dist/languages/shared/doc-binding.d.ts +26 -0
  142. package/dist/languages/shared/doc-binding.d.ts.map +1 -0
  143. package/dist/languages/shared/doc-binding.js +50 -0
  144. package/dist/languages/shared/doc-binding.js.map +1 -0
  145. package/dist/languages/shared/engine.d.ts +49 -0
  146. package/dist/languages/shared/engine.d.ts.map +1 -0
  147. package/dist/languages/shared/engine.js +317 -0
  148. package/dist/languages/shared/engine.js.map +1 -0
  149. package/dist/languages/shared/extract-symbols.d.ts +5 -0
  150. package/dist/languages/shared/extract-symbols.d.ts.map +1 -0
  151. package/dist/languages/shared/extract-symbols.js +31 -0
  152. package/dist/languages/shared/extract-symbols.js.map +1 -0
  153. package/dist/languages/shared/fingerprint.d.ts +7 -0
  154. package/dist/languages/shared/fingerprint.d.ts.map +1 -0
  155. package/dist/languages/shared/fingerprint.js +95 -0
  156. package/dist/languages/shared/fingerprint.js.map +1 -0
  157. package/dist/languages/shared/grammar-loader.d.ts +15 -0
  158. package/dist/languages/shared/grammar-loader.d.ts.map +1 -0
  159. package/dist/languages/shared/grammar-loader.js +48 -0
  160. package/dist/languages/shared/grammar-loader.js.map +1 -0
  161. package/dist/languages/shared/import-detection.d.ts +24 -0
  162. package/dist/languages/shared/import-detection.d.ts.map +1 -0
  163. package/dist/languages/shared/import-detection.js +138 -0
  164. package/dist/languages/shared/import-detection.js.map +1 -0
  165. package/dist/languages/shared/js-family-profile.d.ts +5 -0
  166. package/dist/languages/shared/js-family-profile.d.ts.map +1 -0
  167. package/dist/languages/shared/js-family-profile.js +179 -0
  168. package/dist/languages/shared/js-family-profile.js.map +1 -0
  169. package/dist/languages/shared/node-kinds.d.ts +78 -0
  170. package/dist/languages/shared/node-kinds.d.ts.map +1 -0
  171. package/dist/languages/shared/node-kinds.js +141 -0
  172. package/dist/languages/shared/node-kinds.js.map +1 -0
  173. package/dist/languages/shared/node-utils.d.ts +31 -0
  174. package/dist/languages/shared/node-utils.d.ts.map +1 -0
  175. package/dist/languages/shared/node-utils.js +89 -0
  176. package/dist/languages/shared/node-utils.js.map +1 -0
  177. package/dist/languages/shared/parse-diagnostics.d.ts +44 -0
  178. package/dist/languages/shared/parse-diagnostics.d.ts.map +1 -0
  179. package/dist/languages/shared/parse-diagnostics.js +64 -0
  180. package/dist/languages/shared/parse-diagnostics.js.map +1 -0
  181. package/dist/languages/shared/parse-limits.d.ts +24 -0
  182. package/dist/languages/shared/parse-limits.d.ts.map +1 -0
  183. package/dist/languages/shared/parse-limits.js +134 -0
  184. package/dist/languages/shared/parse-limits.js.map +1 -0
  185. package/dist/languages/shared/profile.d.ts +149 -0
  186. package/dist/languages/shared/profile.d.ts.map +1 -0
  187. package/dist/languages/shared/profile.js +9 -0
  188. package/dist/languages/shared/profile.js.map +1 -0
  189. package/dist/languages/shared/scope-model.d.ts +32 -0
  190. package/dist/languages/shared/scope-model.d.ts.map +1 -0
  191. package/dist/languages/shared/scope-model.js +2 -0
  192. package/dist/languages/shared/scope-model.js.map +1 -0
  193. package/dist/languages/shared/scope-naming.d.ts +20 -0
  194. package/dist/languages/shared/scope-naming.d.ts.map +1 -0
  195. package/dist/languages/shared/scope-naming.js +118 -0
  196. package/dist/languages/shared/scope-naming.js.map +1 -0
  197. package/dist/languages/shared/scope-signature.d.ts +14 -0
  198. package/dist/languages/shared/scope-signature.d.ts.map +1 -0
  199. package/dist/languages/shared/scope-signature.js +82 -0
  200. package/dist/languages/shared/scope-signature.js.map +1 -0
  201. package/dist/languages/shared/signature.d.ts +55 -0
  202. package/dist/languages/shared/signature.d.ts.map +1 -0
  203. package/dist/languages/shared/signature.js +147 -0
  204. package/dist/languages/shared/signature.js.map +1 -0
  205. package/dist/languages/shared/syntax.d.ts +115 -0
  206. package/dist/languages/shared/syntax.d.ts.map +1 -0
  207. package/dist/languages/shared/syntax.js +2 -0
  208. package/dist/languages/shared/syntax.js.map +1 -0
  209. package/dist/languages/shared/table-profile-decisions.d.ts +54 -0
  210. package/dist/languages/shared/table-profile-decisions.d.ts.map +1 -0
  211. package/dist/languages/shared/table-profile-decisions.js +245 -0
  212. package/dist/languages/shared/table-profile-decisions.js.map +1 -0
  213. package/dist/languages/shared/table-profile-module-facts.d.ts +29 -0
  214. package/dist/languages/shared/table-profile-module-facts.d.ts.map +1 -0
  215. package/dist/languages/shared/table-profile-module-facts.js +139 -0
  216. package/dist/languages/shared/table-profile-module-facts.js.map +1 -0
  217. package/dist/languages/shared/table-profile-queries.d.ts +27 -0
  218. package/dist/languages/shared/table-profile-queries.d.ts.map +1 -0
  219. package/dist/languages/shared/table-profile-queries.js +70 -0
  220. package/dist/languages/shared/table-profile-queries.js.map +1 -0
  221. package/dist/languages/shared/table-profile-scopes.d.ts +46 -0
  222. package/dist/languages/shared/table-profile-scopes.d.ts.map +1 -0
  223. package/dist/languages/shared/table-profile-scopes.js +180 -0
  224. package/dist/languages/shared/table-profile-scopes.js.map +1 -0
  225. package/dist/languages/shared/table-profile.d.ts +302 -0
  226. package/dist/languages/shared/table-profile.d.ts.map +1 -0
  227. package/dist/languages/shared/table-profile.js +125 -0
  228. package/dist/languages/shared/table-profile.js.map +1 -0
  229. package/dist/languages/shared/tree-sitter-types.d.ts +44 -0
  230. package/dist/languages/shared/tree-sitter-types.d.ts.map +1 -0
  231. package/dist/languages/shared/tree-sitter-types.js +2 -0
  232. package/dist/languages/shared/tree-sitter-types.js.map +1 -0
  233. package/dist/languages/structured-text/index.d.ts +48 -0
  234. package/dist/languages/structured-text/index.d.ts.map +1 -0
  235. package/dist/languages/structured-text/index.js +120 -0
  236. package/dist/languages/structured-text/index.js.map +1 -0
  237. package/dist/languages/tsx/index.d.ts +4 -0
  238. package/dist/languages/tsx/index.d.ts.map +1 -0
  239. package/dist/languages/tsx/index.js +7 -0
  240. package/dist/languages/tsx/index.js.map +1 -0
  241. package/dist/languages/typescript/index.d.ts +4 -0
  242. package/dist/languages/typescript/index.d.ts.map +1 -0
  243. package/dist/languages/typescript/index.js +7 -0
  244. package/dist/languages/typescript/index.js.map +1 -0
  245. package/dist/languages/vue/index.d.ts +21 -0
  246. package/dist/languages/vue/index.d.ts.map +1 -0
  247. package/dist/languages/vue/index.js +234 -0
  248. package/dist/languages/vue/index.js.map +1 -0
  249. package/dist/languages/vue/mapping.d.ts +11 -0
  250. package/dist/languages/vue/mapping.d.ts.map +1 -0
  251. package/dist/languages/vue/mapping.js +77 -0
  252. package/dist/languages/vue/mapping.js.map +1 -0
  253. package/dist/registry.d.ts +24 -0
  254. package/dist/registry.d.ts.map +1 -0
  255. package/dist/registry.js +42 -0
  256. package/dist/registry.js.map +1 -0
  257. package/dist/text/byte-offset-table.d.ts +27 -0
  258. package/dist/text/byte-offset-table.d.ts.map +1 -0
  259. package/dist/text/byte-offset-table.js +39 -0
  260. package/dist/text/byte-offset-table.js.map +1 -0
  261. package/package.json +125 -3
  262. package/src/boundaries/expression.ts +95 -0
  263. package/src/boundaries/extract.ts +307 -0
  264. package/src/boundaries/python.ts +181 -0
  265. package/src/index.ts +51 -0
  266. package/src/languages/__golden__/javascript-basic.json +32 -0
  267. package/src/languages/__golden__/tsx-basic.json +19 -0
  268. package/src/languages/__golden__/typescript-basic.json +37 -0
  269. package/src/languages/astgrep-backend/GRAMMARS.md +86 -0
  270. package/src/languages/astgrep-backend/README.md +112 -0
  271. package/src/languages/astgrep-backend/__golden__/bash-basic.sh +53 -0
  272. package/src/languages/astgrep-backend/__golden__/c-basic.c +64 -0
  273. package/src/languages/astgrep-backend/__golden__/cpp-basic.cpp +65 -0
  274. package/src/languages/astgrep-backend/__golden__/csharp-basic.cs +73 -0
  275. package/src/languages/astgrep-backend/__golden__/go-basic.go +93 -0
  276. package/src/languages/astgrep-backend/__golden__/java-basic.java +62 -0
  277. package/src/languages/astgrep-backend/__golden__/kotlin-basic.kt +58 -0
  278. package/src/languages/astgrep-backend/__golden__/php-basic.php +72 -0
  279. package/src/languages/astgrep-backend/__golden__/ruby-basic.rb +62 -0
  280. package/src/languages/astgrep-backend/__golden__/rust-basic.rs +82 -0
  281. package/src/languages/astgrep-backend/__golden__/swift-basic.swift +73 -0
  282. package/src/languages/astgrep-backend/adapter.ts +240 -0
  283. package/src/languages/astgrep-backend/index.ts +44 -0
  284. package/src/languages/astgrep-backend/lang/README.md +115 -0
  285. package/src/languages/astgrep-backend/lang/bash.ts +78 -0
  286. package/src/languages/astgrep-backend/lang/c.ts +119 -0
  287. package/src/languages/astgrep-backend/lang/cpp.ts +65 -0
  288. package/src/languages/astgrep-backend/lang/csharp.ts +125 -0
  289. package/src/languages/astgrep-backend/lang/index.ts +61 -0
  290. package/src/languages/astgrep-backend/lang/java.ts +115 -0
  291. package/src/languages/astgrep-backend/lang/kotlin.ts +136 -0
  292. package/src/languages/astgrep-backend/lang/php.ts +105 -0
  293. package/src/languages/astgrep-backend/lang/ruby.ts +105 -0
  294. package/src/languages/astgrep-backend/lang/swift.ts +118 -0
  295. package/src/languages/astgrep-backend/languages.ts +238 -0
  296. package/src/languages/astgrep-backend/napi.ts +261 -0
  297. package/src/languages/astgrep-backend/syntax.ts +242 -0
  298. package/src/languages/index.ts +53 -0
  299. package/src/languages/javascript/index.ts +9 -0
  300. package/src/languages/jsx/index.ts +9 -0
  301. package/src/languages/prose/index.ts +270 -0
  302. package/src/languages/prose/line-bytes.ts +52 -0
  303. package/src/languages/python/README.md +246 -0
  304. package/src/languages/python/__golden__/python-basic.json +44 -0
  305. package/src/languages/python/create-adapter.ts +29 -0
  306. package/src/languages/python/index.ts +8 -0
  307. package/src/languages/python/profile.ts +341 -0
  308. package/src/languages/python/signature.ts +183 -0
  309. package/src/languages/python/table.ts +135 -0
  310. package/src/languages/shared/__fixtures__/large-over-32kib.ts.txt +1207 -0
  311. package/src/languages/shared/call-detection.ts +112 -0
  312. package/src/languages/shared/chunks.ts +255 -0
  313. package/src/languages/shared/create-adapter.ts +136 -0
  314. package/src/languages/shared/decisions.ts +204 -0
  315. package/src/languages/shared/dialect.ts +55 -0
  316. package/src/languages/shared/doc-binding.ts +78 -0
  317. package/src/languages/shared/engine.ts +461 -0
  318. package/src/languages/shared/extract-symbols.ts +35 -0
  319. package/src/languages/shared/fingerprint.ts +99 -0
  320. package/src/languages/shared/grammar-loader.ts +67 -0
  321. package/src/languages/shared/import-detection.ts +154 -0
  322. package/src/languages/shared/js-family-profile.ts +246 -0
  323. package/src/languages/shared/node-kinds.ts +153 -0
  324. package/src/languages/shared/node-utils.ts +120 -0
  325. package/src/languages/shared/parse-diagnostics.ts +125 -0
  326. package/src/languages/shared/parse-limits.ts +147 -0
  327. package/src/languages/shared/profile.ts +184 -0
  328. package/src/languages/shared/scope-model.ts +43 -0
  329. package/src/languages/shared/scope-naming.ts +124 -0
  330. package/src/languages/shared/scope-signature.ts +108 -0
  331. package/src/languages/shared/signature.ts +149 -0
  332. package/src/languages/shared/syntax.ts +116 -0
  333. package/src/languages/shared/table-profile-decisions.ts +251 -0
  334. package/src/languages/shared/table-profile-module-facts.ts +177 -0
  335. package/src/languages/shared/table-profile-queries.ts +85 -0
  336. package/src/languages/shared/table-profile-scopes.ts +198 -0
  337. package/src/languages/shared/table-profile.ts +427 -0
  338. package/src/languages/shared/tree-sitter-types.ts +46 -0
  339. package/src/languages/structured-text/index.ts +192 -0
  340. package/src/languages/tsx/index.ts +9 -0
  341. package/src/languages/typescript/index.ts +9 -0
  342. package/src/languages/vue/index.ts +312 -0
  343. package/src/languages/vue/mapping.ts +93 -0
  344. package/src/registry.ts +61 -0
  345. package/src/text/byte-offset-table.ts +63 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * `LanguageAdapter` fuer strukturierte, verfasste Daten — JSON, YAML, TOML,
3
+ * XML (vision.md §1c, spec.md §7.1/§7.2, WP-217).
4
+ *
5
+ * DIE ENTSCHEIDUNG, DIE HIER GETROFFEN IST
6
+ *
7
+ * Bei der Selbstanalyse fielen 80 JSON-, 6 TOML-, 4 YAML- und 2 XML-Dateien
8
+ * unter `unsupported_language`. Dieser Grund war falsch: die Formate SIND
9
+ * unterstuetzt, sie haben nur keinen Graphen und keinen Kontrollfluss. Nach
10
+ * spec.md §7.2 gehoeren sie ausdruecklich in die Stufe `text`.
11
+ *
12
+ * Sie bekommen deshalb hier `text` — mit voller Suche und sicheren
13
+ * Textchunks. Eine `package.json`, eine `untangle.toml`, ein Manifest
14
+ * beantworten echte Fragen; sie aus dem Index zu halten waere ein Verlust.
15
+ *
16
+ * WAS SIE NICHT BEKOMMEN, UND WARUM DAS KEINE ABSTUFUNG IST
17
+ *
18
+ * - Keine Symbole und keine `symbolScopes`: ein Schluessel in einer
19
+ * `package.json` ist kein Symbol mit Signatur, Callern und Callees. Ein
20
+ * erfundenes Symbol waere schlimmer als keins.
21
+ * - Keine Komplexitaetszahlen: es gibt keine Entscheidungspunkte. Wer diese
22
+ * Dateien in einer Metrikauswertung uebergeht, benennt das mit dem Grund
23
+ * `no_metric_defined` (domain `skip-ledger.ts`) — nicht mit
24
+ * `unsupported_language`, denn verstanden sind sie.
25
+ * - Auch KEINE Prosa-Metriken: eine YAML-Datei hat keine Abschnittstiefe im
26
+ * Sinne von Ueberschriften und keine Verweisdichte im Sinne von
27
+ * Querverweisen. Die Prosa-Familie ist fuer Prosa.
28
+ *
29
+ * WIE GESCHNITTEN WIRD
30
+ *
31
+ * Nur an Grenzen, die im Format EXAKT und ohne Parser bestimmbar sind:
32
+ *
33
+ * - TOML: eine Zeile, die (nach Leerraum) mit `[` beginnt, eroeffnet eine
34
+ * neue Tabelle — das ist die Gliederung des Formats.
35
+ * - YAML: `---` trennt Dokumente in einem Strom.
36
+ *
37
+ * Fuer JSON und XML gibt es keine solche Grenze ohne echten Parser. Sie
38
+ * bekommen EINEN Bereich ueber die ganze Datei, den der Chunker bei Bedarf
39
+ * am Tokenbudget teilt. Das ist die ehrliche Antwort und ausdruecklich
40
+ * KEINE ueberschriftenbewusste Gliederung, wie Markdown sie bekommt — sie
41
+ * zu behaupten, wo das Format sie nicht hergibt, waere die Sorte
42
+ * Beschoenigung, die E4 verbietet.
43
+ */
44
+ import type {
45
+ AstRegion,
46
+ ComplexityFacts,
47
+ ExtractedSymbol,
48
+ HalsteadTokens,
49
+ LanguageAdapter,
50
+ ParsedAst,
51
+ ParseResult,
52
+ RawCall,
53
+ RawImport,
54
+ SourceFile,
55
+ SourceRange,
56
+ } from "@untangle-code/domain";
57
+ import { textFormatExtensions, textFormatExtensionOf } from "@untangle-code/domain";
58
+
59
+ import { buildLineByteIndex, rangeForLines, type LineByteIndex } from "../prose/line-bytes.js";
60
+
61
+ /** Sprachkennung dieses Adapters. Bewusst formatuebergreifend: die Behandlung ist dieselbe. */
62
+ export const STRUCTURED_TEXT_LANGUAGE_ID = "structured-text";
63
+
64
+ interface StructuredAstRoot {
65
+ readonly fileId: string;
66
+ readonly index: LineByteIndex;
67
+ readonly blocks: readonly SourceRange[];
68
+ }
69
+
70
+ const TOML_TABLE = /^\s*\[/;
71
+ const YAML_DOCUMENT_SEPARATOR = /^---\s*$/;
72
+
73
+ /** Zeilen, an denen ein neuer Block beginnt (1-basiert), aufsteigend, ohne Zeile 1. */
74
+ function blockStartLines(path: string, lines: readonly string[]): number[] {
75
+ const extension = textFormatExtensionOf(path);
76
+ const isToml = extension === ".toml";
77
+ const isYaml = extension === ".yaml" || extension === ".yml";
78
+ if (!isToml && !isYaml) return [];
79
+
80
+ const starts: number[] = [];
81
+ for (const [index, rawLine] of lines.entries()) {
82
+ if (index === 0) continue;
83
+ if (isToml && TOML_TABLE.test(rawLine)) starts.push(index + 1);
84
+ if (isYaml && YAML_DOCUMENT_SEPARATOR.test(rawLine)) starts.push(index + 1);
85
+ }
86
+ return starts;
87
+ }
88
+
89
+ function buildBlocks(path: string, content: string, index: LineByteIndex): SourceRange[] {
90
+ const lines = content.split("\n").map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line));
91
+ const totalLines = Math.max(index.lineCount, 1);
92
+ const starts = [1, ...blockStartLines(path, lines)];
93
+ return starts.map((startLine, position) => {
94
+ const next = starts[position + 1];
95
+ return rangeForLines(index, startLine, next !== undefined ? next - 1 : totalLines);
96
+ });
97
+ }
98
+
99
+ function rootOf(ast: ParsedAst): StructuredAstRoot {
100
+ return ast.root as StructuredAstRoot;
101
+ }
102
+
103
+ export function createStructuredTextAdapter(): LanguageAdapter {
104
+ return {
105
+ languageId: STRUCTURED_TEXT_LANGUAGE_ID,
106
+ extensions: textFormatExtensions("structured_data"),
107
+ supportLevel: "text",
108
+
109
+ parse(source: SourceFile): ParseResult {
110
+ const index = buildLineByteIndex(source.content);
111
+ const root: StructuredAstRoot = {
112
+ fileId: source.fileId,
113
+ index,
114
+ blocks: buildBlocks(source.path, source.content, index),
115
+ };
116
+ // Es wird nichts geparst, also kann nichts scheitern. `"complete"` ist
117
+ // hier eine Aussage ueber die Textzerlegung, nicht ueber eine
118
+ // Grammatik: eine ungueltige JSON-Datei wird trotzdem vollstaendig
119
+ // erfasst und durchsuchbar — sie bekommt nur keine Struktur.
120
+ return {
121
+ parseQuality: "complete",
122
+ ast: {
123
+ languageId: STRUCTURED_TEXT_LANGUAGE_ID,
124
+ parseQuality: "complete",
125
+ root,
126
+ diagnostics: [],
127
+ },
128
+ diagnostics: [],
129
+ errorNodeCount: 0,
130
+ missingNodeCount: 0,
131
+ };
132
+ },
133
+
134
+ extractChunks(ast: ParsedAst): AstRegion[] {
135
+ const root = rootOf(ast);
136
+ const children: AstRegion[] = root.blocks.map((range, ordinal) => ({
137
+ chunkKind: "configuration",
138
+ range,
139
+ scopeId: `${root.fileId}#block#${String(ordinal)}`,
140
+ splittable: false,
141
+ }));
142
+ return [
143
+ {
144
+ chunkKind: "module",
145
+ range: {
146
+ startLine: 1,
147
+ endLine: root.index.lineCount,
148
+ startByte: 0,
149
+ endByte: root.index.totalBytes,
150
+ },
151
+ scopeId: root.fileId,
152
+ // Ein einziger Block ueber die ganze Datei traegt keine
153
+ // Information; dann bleibt der Wurzelbereich kinderlos und der
154
+ // Chunker schneidet selbst am Tokenbudget.
155
+ splittable: children.length > 1,
156
+ ...(children.length > 1 ? { children } : {}),
157
+ },
158
+ ];
159
+ },
160
+
161
+ extractSymbols(_ast: ParsedAst): ExtractedSymbol[] {
162
+ return [];
163
+ },
164
+
165
+ extractImports(_ast: ParsedAst): RawImport[] {
166
+ return [];
167
+ },
168
+
169
+ extractCalls(_ast: ParsedAst): RawCall[] {
170
+ return [];
171
+ },
172
+
173
+ computeComplexity(ast: ParsedAst): ComplexityFacts {
174
+ return {
175
+ symbolScopes: [],
176
+ decisions: [],
177
+ nestingEvents: [],
178
+ operators: [],
179
+ operands: [],
180
+ nodeKinds: [],
181
+ comments: [],
182
+ identifiers: [],
183
+ literals: [],
184
+ parseDiagnostics: ast.diagnostics,
185
+ };
186
+ },
187
+
188
+ tokenizeForHalstead(_ast: ParsedAst): HalsteadTokens {
189
+ return { operators: [], operands: [] };
190
+ },
191
+ };
192
+ }
@@ -0,0 +1,9 @@
1
+ import type { LanguageAdapter } from "@untangle-code/domain";
2
+
3
+ import { createTreeSitterAdapter } from "../shared/create-adapter.js";
4
+ import { TSX_DIALECT } from "../shared/dialect.js";
5
+
6
+ /** TSX `LanguageAdapter` (`.tsx`), support level "deep" (spec.md §7.2). */
7
+ export function createTsxAdapter(): LanguageAdapter {
8
+ return createTreeSitterAdapter(TSX_DIALECT);
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { LanguageAdapter } from "@untangle-code/domain";
2
+
3
+ import { createTreeSitterAdapter } from "../shared/create-adapter.js";
4
+ import { TYPESCRIPT_DIALECT } from "../shared/dialect.js";
5
+
6
+ /** TypeScript `LanguageAdapter` (`.ts`, `.mts`, `.cts`), support level "deep" (spec.md §7.2). */
7
+ export function createTypeScriptAdapter(): LanguageAdapter {
8
+ return createTreeSitterAdapter(TYPESCRIPT_DIALECT);
9
+ }
@@ -0,0 +1,312 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ import type {
4
+ AstRegion,
5
+ ComplexityFacts,
6
+ LanguageAdapter,
7
+ ParseDiagnostic,
8
+ ParsedAst,
9
+ ParseResult,
10
+ SourceFile,
11
+ SourceRange,
12
+ } from "@untangle-code/domain";
13
+ import { AdapterParseError, sha256Hex } from "@untangle-code/domain";
14
+ import type { SFCBlock, SFCParseResult, SFCScriptBlock } from "@vue/compiler-sfc";
15
+ import type * as VueCompiler from "@vue/compiler-sfc";
16
+
17
+ import { buildByteOffsetTable } from "../../text/byte-offset-table.js";
18
+ import { createJavaScriptAdapter } from "../javascript/index.js";
19
+ import { createJsxAdapter } from "../jsx/index.js";
20
+ import { MAX_PARSE_SOURCE_BYTES } from "../shared/parse-limits.js";
21
+ import { createTsxAdapter } from "../tsx/index.js";
22
+ import { createTypeScriptAdapter } from "../typescript/index.js";
23
+
24
+ import { shiftVueRange, vueFacts, vueRegion, vueScopeId, vueSymbol } from "./mapping.js";
25
+
26
+ export { shiftVueRange, vueQualifiedName, vueScopeId } from "./mapping.js";
27
+
28
+ export interface VueScriptAst {
29
+ context: "script" | "setup";
30
+ /** Only dual-script SFCs need explicit context names to keep equal bindings distinct. */
31
+ qualifier: string;
32
+ adapter: LanguageAdapter;
33
+ ast: ParsedAst;
34
+ source: SourceFile;
35
+ /** Content range in the original SFC, not the surrounding script tags. */
36
+ range: SourceRange;
37
+ }
38
+
39
+ export interface VueAstRoot {
40
+ kind: "vue-sfc";
41
+ fileId: string;
42
+ range: SourceRange;
43
+ scripts: VueScriptAst[];
44
+ }
45
+
46
+ const require = createRequire(import.meta.url);
47
+ let parseSfc:
48
+ | ((
49
+ source: string,
50
+ options: { filename: string; sourceMap: false; ignoreEmpty: false },
51
+ ) => SFCParseResult)
52
+ | undefined;
53
+
54
+ function parseDescriptor(source: SourceFile): SFCParseResult {
55
+ // Loading the registry must not load Vue's compiler or any native grammar.
56
+ parseSfc ??= (require("@vue/compiler-sfc") as typeof VueCompiler).parse;
57
+ return parseSfc(source.content, { filename: source.path, sourceMap: false, ignoreEmpty: false });
58
+ }
59
+
60
+ function rootOf(ast: ParsedAst): VueAstRoot {
61
+ return ast.root as VueAstRoot;
62
+ }
63
+
64
+ function emptyFacts(diagnostics: ParseDiagnostic[]): ComplexityFacts {
65
+ return {
66
+ symbolScopes: [],
67
+ decisions: [],
68
+ nestingEvents: [],
69
+ operators: [],
70
+ operands: [],
71
+ nodeKinds: [],
72
+ comments: [],
73
+ identifiers: [],
74
+ literals: [],
75
+ parseDiagnostics: diagnostics,
76
+ };
77
+ }
78
+
79
+ function combinedFacts(ast: ParsedAst): ComplexityFacts {
80
+ const root = rootOf(ast);
81
+ const facts = emptyFacts(ast.diagnostics);
82
+ // A template-only component has no executable-code scope and no invented base complexity.
83
+ if (root.scripts.length === 0) return facts;
84
+ facts.symbolScopes.push({
85
+ symbolScopeId: root.fileId,
86
+ name: "",
87
+ qualifiedName: "",
88
+ kind: "file",
89
+ range: root.range,
90
+ executable: true,
91
+ });
92
+ for (const script of root.scripts) {
93
+ const part = vueFacts(script, root.fileId);
94
+ facts.symbolScopes.push(...part.symbolScopes);
95
+ facts.decisions.push(...part.decisions);
96
+ facts.nestingEvents.push(...part.nestingEvents);
97
+ facts.operators.push(...part.operators);
98
+ facts.operands.push(...part.operands);
99
+ facts.nodeKinds.push(...part.nodeKinds);
100
+ facts.comments.push(...part.comments);
101
+ facts.identifiers.push(...part.identifiers);
102
+ facts.literals.push(...part.literals);
103
+ }
104
+ return facts;
105
+ }
106
+
107
+ function blockRange(source: SourceFile, block: Pick<SFCBlock, "loc">): SourceRange {
108
+ const offsets = buildByteOffsetTable(source.content);
109
+ return {
110
+ startLine: block.loc.start.line,
111
+ endLine: block.loc.end.line,
112
+ startByte: offsets.toByteOffset(block.loc.start.offset),
113
+ endByte: offsets.toByteOffset(block.loc.end.offset),
114
+ };
115
+ }
116
+
117
+ function diagnostic(
118
+ message: string,
119
+ range: SourceRange,
120
+ kind: ParseDiagnostic["kind"] = "fallback",
121
+ ): ParseDiagnostic {
122
+ return { severity: "warning", kind, message, range };
123
+ }
124
+
125
+ function parseVue(source: SourceFile, adapters: ReadonlyMap<string, LanguageAdapter>): ParseResult {
126
+ const bytes = Buffer.byteLength(source.content, "utf8");
127
+ if (bytes > MAX_PARSE_SOURCE_BYTES) {
128
+ throw new AdapterParseError("file_too_large", "Vue SFC exceeds the parser source-byte limit.", {
129
+ measurements: { sizeBytes: bytes, limitBytes: MAX_PARSE_SOURCE_BYTES },
130
+ });
131
+ }
132
+ const parsed = parseDescriptor(source);
133
+ const range: SourceRange = {
134
+ startByte: 0,
135
+ endByte: bytes,
136
+ startLine: 1,
137
+ endLine: source.content.split("\n").length,
138
+ };
139
+ const diagnostics: ParseDiagnostic[] = parsed.errors.map((error) => ({
140
+ severity: "error",
141
+ kind: "error_node",
142
+ message: `Vue SFC: ${error.message}`,
143
+ range:
144
+ "loc" in error && error.loc !== undefined ? blockRange(source, { loc: error.loc }) : range,
145
+ }));
146
+ let errorNodeCount = parsed.errors.length;
147
+ let missingNodeCount = 0;
148
+ let incomplete = parsed.errors.length > 0;
149
+ const scripts: VueScriptAst[] = [];
150
+ const descriptor = parsed.descriptor;
151
+ const blocks: ["script" | "setup", SFCScriptBlock | null][] = [
152
+ ["script", descriptor.script],
153
+ ["setup", descriptor.scriptSetup],
154
+ ];
155
+ blocks.sort(
156
+ (left, right) =>
157
+ (left[1]?.loc.start.offset ?? Number.POSITIVE_INFINITY) -
158
+ (right[1]?.loc.start.offset ?? Number.POSITIVE_INFINITY),
159
+ );
160
+ const dual = descriptor.script !== null && descriptor.scriptSetup !== null;
161
+ if (dual && (descriptor.script?.lang ?? "js") !== (descriptor.scriptSetup?.lang ?? "js")) {
162
+ incomplete = true;
163
+ diagnostics.push(
164
+ diagnostic(
165
+ "Vue script and script setup must use the same language; cross-block compilation is not validated.",
166
+ range,
167
+ ),
168
+ );
169
+ }
170
+ for (const [context, block] of blocks) {
171
+ if (block === null) continue;
172
+ const partRange = blockRange(source, block);
173
+ const lang = block.lang ?? "js";
174
+ const adapter = adapters.get(lang);
175
+ if (block.src !== undefined || adapter === undefined) {
176
+ incomplete = true;
177
+ diagnostics.push(
178
+ diagnostic(
179
+ block.src !== undefined
180
+ ? `Vue ${context}: external script src is not analyzed; analyze its source file separately.`
181
+ : `Vue ${context}: unsupported script language "${lang}".`,
182
+ partRange,
183
+ ),
184
+ );
185
+ continue;
186
+ }
187
+ const scriptSource: SourceFile = {
188
+ ...source,
189
+ fileId: `${source.fileId}\u001fvue-${context}`,
190
+ languageId: adapter.languageId,
191
+ content: block.content,
192
+ contentHash: sha256Hex(block.content),
193
+ sizeBytes: Buffer.byteLength(block.content, "utf8"),
194
+ };
195
+ const part = adapter.parse(scriptSource);
196
+ const script = {
197
+ context,
198
+ qualifier: dual ? context : "",
199
+ adapter,
200
+ source: scriptSource,
201
+ range: partRange,
202
+ };
203
+ diagnostics.push(
204
+ ...part.diagnostics.map((item) => ({
205
+ ...item,
206
+ range: shiftVueRange(script, item.range),
207
+ })),
208
+ );
209
+ errorNodeCount += part.errorNodeCount;
210
+ missingNodeCount += part.missingNodeCount;
211
+ incomplete ||= part.parseQuality !== "complete";
212
+ if (part.ast !== null) scripts.push({ ...script, ast: part.ast });
213
+ }
214
+ if (blocks.every(([, block]) => block === null)) {
215
+ incomplete = true;
216
+ diagnostics.push(
217
+ diagnostic("Vue SFC contains no inline script; template logic is not analyzed.", range),
218
+ );
219
+ }
220
+ // Valid syntax is distinct from analysis scope: these warnings do not invent syntax errors.
221
+ const unmeasuredBlocks = [descriptor.template, ...descriptor.styles, ...descriptor.customBlocks];
222
+ for (const block of unmeasuredBlocks) {
223
+ if (block === null) continue;
224
+ diagnostics.push({
225
+ ...diagnostic(
226
+ `Vue analysis scope: inline script code only; ${block.type} block complexity and runtime bindings are not measured. The original block remains text-searchable.`,
227
+ blockRange(source, block),
228
+ "other",
229
+ ),
230
+ code: "analysis_scope_limited",
231
+ });
232
+ }
233
+ const parseQuality = incomplete ? "partial" : "complete";
234
+ const ast: ParsedAst = {
235
+ languageId: "vue",
236
+ parseQuality,
237
+ diagnostics,
238
+ root: { kind: "vue-sfc", fileId: source.fileId, range, scripts } satisfies VueAstRoot,
239
+ };
240
+ return { parseQuality, ast, diagnostics, errorNodeCount, missingNodeCount };
241
+ }
242
+
243
+ /** Vue SFC adapter: source-level inline scripts, never generated render/setup code. */
244
+ export function createVueAdapter(): LanguageAdapter {
245
+ const adapters = new Map([
246
+ ["js", createJavaScriptAdapter()],
247
+ ["javascript", createJavaScriptAdapter()],
248
+ ["ts", createTypeScriptAdapter()],
249
+ ["typescript", createTypeScriptAdapter()],
250
+ ["tsx", createTsxAdapter()],
251
+ ["jsx", createJsxAdapter()],
252
+ ]);
253
+ const cache = new WeakMap<ParsedAst, ComplexityFacts>();
254
+ const facts = (ast: ParsedAst): ComplexityFacts => {
255
+ const previous = cache.get(ast);
256
+ if (previous !== undefined) return previous;
257
+ const computed = combinedFacts(ast);
258
+ cache.set(ast, computed);
259
+ return computed;
260
+ };
261
+ return {
262
+ languageId: "vue",
263
+ extensions: [".vue"],
264
+ supportLevel: "structural",
265
+ parse: (source) => parseVue(source, adapters),
266
+ extractChunks(ast): AstRegion[] {
267
+ const root = rootOf(ast);
268
+ const children = root.scripts
269
+ .flatMap((script) =>
270
+ script.adapter
271
+ .extractChunks(script.ast)
272
+ .flatMap((region) => region.children ?? [])
273
+ .map((region) => vueRegion(script, region, root.fileId)),
274
+ )
275
+ .sort((left, right) => left.range.startByte - right.range.startByte);
276
+ return [
277
+ {
278
+ chunkKind: "module",
279
+ range: root.range,
280
+ scopeId: root.fileId,
281
+ splittable: children.length > 0,
282
+ children,
283
+ },
284
+ ];
285
+ },
286
+ extractSymbols: (ast) =>
287
+ rootOf(ast).scripts.flatMap((script) =>
288
+ script.adapter.extractSymbols(script.ast).map((symbol) => vueSymbol(script, symbol)),
289
+ ),
290
+ extractImports: (ast) =>
291
+ rootOf(ast).scripts.flatMap((script) =>
292
+ script.adapter
293
+ .extractImports(script.ast)
294
+ .map((item) => ({ ...item, range: shiftVueRange(script, item.range) })),
295
+ ),
296
+ extractCalls: (ast) => {
297
+ const root = rootOf(ast);
298
+ return root.scripts.flatMap((script) =>
299
+ script.adapter.extractCalls(script.ast).map((call) => ({
300
+ ...call,
301
+ callerScopeId: vueScopeId(script, call.callerScopeId, root.fileId),
302
+ range: shiftVueRange(script, call.range),
303
+ })),
304
+ );
305
+ },
306
+ computeComplexity: facts,
307
+ tokenizeForHalstead(ast) {
308
+ const { operators, operands } = facts(ast);
309
+ return { operators, operands };
310
+ },
311
+ };
312
+ }
@@ -0,0 +1,93 @@
1
+ import type {
2
+ AstRegion,
3
+ ComplexityFacts,
4
+ ExtractedSymbol,
5
+ SourceRange,
6
+ } from "@untangle-code/domain";
7
+
8
+ import type { VueScriptAst } from "./index.js";
9
+
10
+ /** Vue compiler locations use UTF-16; the block range is already converted to UTF-8. */
11
+ export function shiftVueRange(
12
+ script: Pick<VueScriptAst, "range">,
13
+ range: SourceRange,
14
+ ): SourceRange {
15
+ return {
16
+ startByte: script.range.startByte + range.startByte,
17
+ endByte: script.range.startByte + range.endByte,
18
+ startLine: script.range.startLine + range.startLine - 1,
19
+ endLine: script.range.startLine + range.endLine - 1,
20
+ };
21
+ }
22
+
23
+ export function vueQualifiedName(script: VueScriptAst, name: string): string {
24
+ return script.qualifier.length === 0 ? name : `${script.qualifier}.${name}`;
25
+ }
26
+
27
+ /** Both inline blocks share the enclosing file scope, but their child identities stay distinct. */
28
+ export function vueScopeId(script: VueScriptAst, scopeId: string, fileId: string): string {
29
+ return scopeId === script.source.fileId ? fileId : scopeId;
30
+ }
31
+
32
+ export function vueSymbol(script: VueScriptAst, symbol: ExtractedSymbol): ExtractedSymbol {
33
+ return {
34
+ ...symbol,
35
+ qualifiedName: vueQualifiedName(script, symbol.qualifiedName),
36
+ range: shiftVueRange(script, symbol.range),
37
+ ...(symbol.docRange !== undefined ? { docRange: shiftVueRange(script, symbol.docRange) } : {}),
38
+ ...(symbol.parentQualifiedName !== undefined
39
+ ? { parentQualifiedName: vueQualifiedName(script, symbol.parentQualifiedName) }
40
+ : {}),
41
+ };
42
+ }
43
+
44
+ export function vueRegion(script: VueScriptAst, region: AstRegion, fileId: string): AstRegion {
45
+ return {
46
+ ...region,
47
+ range: shiftVueRange(script, region.range),
48
+ scopeId: vueScopeId(script, region.scopeId, fileId),
49
+ ...(region.symbolFqn !== undefined
50
+ ? { symbolFqn: vueQualifiedName(script, region.symbolFqn) }
51
+ : {}),
52
+ ...(region.children !== undefined
53
+ ? { children: region.children.map((child) => vueRegion(script, child, fileId)) }
54
+ : {}),
55
+ };
56
+ }
57
+
58
+ export function vueFacts(script: VueScriptAst, fileId: string): ComplexityFacts {
59
+ const facts = script.adapter.computeComplexity(script.ast);
60
+ const scoped = <T extends { symbolScopeId: string }>(fact: T): T => ({
61
+ ...fact,
62
+ symbolScopeId: vueScopeId(script, fact.symbolScopeId, fileId),
63
+ });
64
+ const ranged = <T extends { range: SourceRange }>(fact: T): T => ({
65
+ ...fact,
66
+ range: shiftVueRange(script, fact.range),
67
+ });
68
+ return {
69
+ symbolScopes: facts.symbolScopes
70
+ .filter((scope) => scope.symbolScopeId !== script.source.fileId)
71
+ .map((scope) => ({
72
+ ...ranged(scoped(scope)),
73
+ qualifiedName: vueQualifiedName(script, scope.qualifiedName),
74
+ ...(scope.parentScopeId !== undefined
75
+ ? { parentScopeId: vueScopeId(script, scope.parentScopeId, fileId) }
76
+ : {}),
77
+ })),
78
+ decisions: facts.decisions.map((fact) => ({
79
+ ...ranged(scoped(fact)),
80
+ ...(fact.logicalGroupId !== undefined
81
+ ? { logicalGroupId: `${script.context}:${fact.logicalGroupId}` }
82
+ : {}),
83
+ })),
84
+ nestingEvents: facts.nestingEvents.map((fact) => ranged(scoped(fact))),
85
+ operators: facts.operators.map((fact) => ranged(scoped(fact))),
86
+ operands: facts.operands.map((fact) => ranged(scoped(fact))),
87
+ nodeKinds: facts.nodeKinds.map(scoped),
88
+ comments: facts.comments.map((range) => shiftVueRange(script, range)),
89
+ identifiers: facts.identifiers.map((fact) => ranged(scoped(fact))),
90
+ literals: facts.literals.map((fact) => ranged(scoped(fact))),
91
+ parseDiagnostics: facts.parseDiagnostics.map(ranged),
92
+ };
93
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * `ParserRegistry` (domain `ports.ts`) implementation: registration plus
3
+ * resolution by extension / language id (architecture.md §6.5).
4
+ *
5
+ * Registering an adapter here does NOT load its grammar — `createTreeSitterAdapter`
6
+ * (see `languages/shared/create-adapter.ts`) only touches the native
7
+ * `tree-sitter` module and the specific grammar module inside `parse()`,
8
+ * via `grammar-loader.ts`'s lazy, cached `require`. A CLI can therefore call
9
+ * `createParserRegistry()` and list/resolve adapters at startup without
10
+ * loading a single native grammar; the first grammar load happens on the
11
+ * first `parse()` call for that language, and only that language's grammar
12
+ * is ever touched if a workspace has, say, TypeScript files only.
13
+ */
14
+ import type { LanguageAdapter, ParserRegistry, SupportLevel } from "@untangle-code/domain";
15
+
16
+ export class LazyParserRegistry implements ParserRegistry {
17
+ private readonly adaptersByLanguageId = new Map<string, LanguageAdapter>();
18
+ private readonly adaptersByExtension = new Map<string, LanguageAdapter>();
19
+
20
+ register(adapter: LanguageAdapter): void {
21
+ this.adaptersByLanguageId.set(adapter.languageId, adapter);
22
+ for (const extension of adapter.extensions) {
23
+ this.adaptersByExtension.set(extension.toLowerCase(), adapter);
24
+ }
25
+ }
26
+
27
+ listAdapters(): LanguageAdapter[] {
28
+ return [...this.adaptersByLanguageId.values()];
29
+ }
30
+
31
+ getAdapterByLanguage(languageId: string): LanguageAdapter | null {
32
+ return this.adaptersByLanguageId.get(languageId) ?? null;
33
+ }
34
+
35
+ getAdapterForPath(path: string, _contentSample?: string): LanguageAdapter | null {
36
+ const extension = extensionOf(path);
37
+ if (extension === null) {
38
+ // Extensionless-file content probing (spec.md §6.1) has no MVP use
39
+ // case in this package — every language it supports (TS/JS/TSX/JSX)
40
+ // is always extension-identified. `_contentSample` is accepted (per
41
+ // the domain port signature) but unused; a future adapter that needs
42
+ // it (e.g. a shebang-sniffed shell/Python script) implements the
43
+ // probe itself.
44
+ return null;
45
+ }
46
+ return this.adaptersByExtension.get(extension) ?? null;
47
+ }
48
+
49
+ supportLevelOf(languageId: string): SupportLevel | null {
50
+ return this.adaptersByLanguageId.get(languageId)?.supportLevel ?? null;
51
+ }
52
+ }
53
+
54
+ function extensionOf(path: string): string | null {
55
+ const normalized = path.replace(/\\/g, "/");
56
+ const lastSlash = normalized.lastIndexOf("/");
57
+ const fileName = lastSlash === -1 ? normalized : normalized.slice(lastSlash + 1);
58
+ const lastDot = fileName.lastIndexOf(".");
59
+ if (lastDot <= 0) return null; // no dot, or a dotfile like ".gitignore" (no extension)
60
+ return fileName.slice(lastDot).toLowerCase();
61
+ }