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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,242 @@
1
+ /**
2
+ * Der backend-neutrale Baumvertrag (`shared/syntax.ts`), nachgebaut ueber
3
+ * `SgNode`.
4
+ *
5
+ * WARUM DAS HIER TEURER IST ALS DER ANDERE WEG, und warum wir es trotzdem so
6
+ * bauen: ast-grep hat KEINE Cursor-API. Es gibt kein Gegenstueck zu
7
+ * `gotoFirstChild`/`gotoNextSibling`/`gotoParent`; jeder Abstieg geht ueber
8
+ * `children()`, und jedes `children()` baut ein frisches JS-Array aus
9
+ * Knotenwrappern. Gemessen an diesem Repositorium (721 Dateien, 1.143.212
10
+ * Knoten): tree-sitter-Cursor 1.703.642 Knoten/s gegen ast-grep 455.329
11
+ * Knoten/s — Faktor 3,74, Mehrkosten 1,61 us je Knoten. Das ist das Niveau des
12
+ * `.children`-Weges, den WP-95 abgeschafft hat.
13
+ *
14
+ * Deshalb: die JS/TS-Familie bleibt bei tree-sitter, und dieser Cursor ist der
15
+ * Weg fuer Sprachen, die es sonst GAR NICHT gaebe. Fuer sie ist der Aufpreis
16
+ * kein Rueckschritt — er ist der Eintrittspreis.
17
+ *
18
+ * WAS DIESER CURSOR TROTZDEM RICHTIG MACHT:
19
+ * - Er ist ITERATIV. Ein Baum kann zehntausende Ebenen tief sein (eine lange
20
+ * `a || b || c`-Kette genuegt); ein rekursiver Walk zerbricht daran mit
21
+ * `RangeError: Maximum call stack size exceeded`, nachgemessen an 50.000
22
+ * Gliedern.
23
+ * - Er materialisiert die Kindliste je Ebene EINMAL, nicht je Zugriff.
24
+ * - Er merkt sich den Bereich (`range()`) des aktuellen Knotens, weil
25
+ * `rangeOfCursor` vier Werte daraus liest und ast-grep bei jedem Aufruf ein
26
+ * verschachteltes Objekt neu baut.
27
+ *
28
+ * WAS ER NICHT KANN — und was der Adapter deshalb ehrlich sagen muss:
29
+ * - `nodeIsMissing` gibt es bei ast-grep nicht. Hier steht eine HEURISTIK:
30
+ * ein Blatt der Breite null. An diesem Repositorium war sie exakt (3 von 3
31
+ * MISSING-Knoten), sie bleibt aber eine Heuristik. `create-adapter.ts`
32
+ * schreibt das in JEDE davon erzeugte Diagnose.
33
+ * - `currentFieldName` gibt es nicht als Rueckrichtung. Wir fragen die
34
+ * Felder ab, die das Sprachprofil nennt, und vergleichen ueber `id()` —
35
+ * prozesslokal gueltig, nie in Ergebnisdaten (siehe `napi.ts`).
36
+ */
37
+ import type { SyntaxCursor, SyntaxNode, SyntaxPoint } from "../shared/syntax.js";
38
+
39
+ import type { SgNode, SgPos } from "./napi.js";
40
+
41
+ function pointOf(pos: SgPos): SyntaxPoint {
42
+ return { row: pos.line, column: pos.column };
43
+ }
44
+
45
+ /** Ein `SgNode` in der Form, die `shared/` erwartet. */
46
+ export class AstGrepSyntaxNode implements SyntaxNode {
47
+ constructor(
48
+ /** Der rohe ast-grep-Knoten. Nur `syntax.ts` fasst ihn an. */
49
+ readonly sg: SgNode,
50
+ private readonly fieldNames: readonly string[],
51
+ ) {}
52
+
53
+ get type(): string {
54
+ return this.sg.kind();
55
+ }
56
+
57
+ get text(): string {
58
+ return this.sg.text();
59
+ }
60
+
61
+ get isNamed(): boolean {
62
+ return this.sg.isNamed();
63
+ }
64
+
65
+ get startIndex(): number {
66
+ return this.sg.range().start.index;
67
+ }
68
+
69
+ get endIndex(): number {
70
+ return this.sg.range().end.index;
71
+ }
72
+
73
+ get startPosition(): SyntaxPoint {
74
+ return pointOf(this.sg.range().start);
75
+ }
76
+
77
+ get endPosition(): SyntaxPoint {
78
+ return pointOf(this.sg.range().end);
79
+ }
80
+
81
+ get parent(): SyntaxNode | null {
82
+ const parent = this.sg.parent();
83
+ return parent === null ? null : new AstGrepSyntaxNode(parent, this.fieldNames);
84
+ }
85
+
86
+ get previousSibling(): SyntaxNode | null {
87
+ // Geprueft: ast-grep `prev()` liefert auch ANONYME Geschwister (das
88
+ // vorangehende `{` einer Blockklammer ebenso wie einen Kommentar). Waere
89
+ // es nur das vorherige benannte Geschwister, verschoebe sich die
90
+ // Doc-Bindung stillschweigend.
91
+ const previous = this.sg.prev();
92
+ return previous === null ? null : new AstGrepSyntaxNode(previous, this.fieldNames);
93
+ }
94
+
95
+ get children(): readonly SyntaxNode[] {
96
+ return this.sg.children().map((child) => new AstGrepSyntaxNode(child, this.fieldNames));
97
+ }
98
+
99
+ get namedChildCount(): number {
100
+ return this.sg.namedChildren().length;
101
+ }
102
+
103
+ namedChild(index: number): SyntaxNode | null {
104
+ const child = this.sg.namedChildren()[index];
105
+ return child === undefined ? null : new AstGrepSyntaxNode(child, this.fieldNames);
106
+ }
107
+
108
+ childForFieldName(fieldName: string): SyntaxNode | null {
109
+ // Ein unbekannter Feldname liefert bei ast-grep `null` (geprueft), wirft
110
+ // also nicht — ein Profil darf nach Feldern fragen, die es in dieser
111
+ // Grammatik nicht gibt.
112
+ const field = this.sg.field(fieldName);
113
+ return field === null ? null : new AstGrepSyntaxNode(field, this.fieldNames);
114
+ }
115
+
116
+ walk(): SyntaxCursor {
117
+ return new AstGrepCursor(this.sg, this.fieldNames);
118
+ }
119
+ }
120
+
121
+ /** Eine Ebene des Abstiegs: die Geschwisterliste und die Stelle darin. */
122
+ interface CursorLevel {
123
+ siblings: SgNode[];
124
+ index: number;
125
+ }
126
+
127
+ export class AstGrepCursor implements SyntaxCursor {
128
+ private readonly levels: CursorLevel[] = [];
129
+ private rangeCacheNode: SgNode | null = null;
130
+ private rangeCacheValue: { start: SgPos; end: SgPos } | null = null;
131
+
132
+ constructor(
133
+ private readonly rootNode: SgNode,
134
+ private readonly fieldNames: readonly string[],
135
+ ) {}
136
+
137
+ private get node(): SgNode {
138
+ const level = this.levels[this.levels.length - 1];
139
+ if (level === undefined) return this.rootNode;
140
+ return level.siblings[level.index] as SgNode;
141
+ }
142
+
143
+ private get range(): { start: SgPos; end: SgPos } {
144
+ const node = this.node;
145
+ if (this.rangeCacheNode === node && this.rangeCacheValue !== null) return this.rangeCacheValue;
146
+ const value = node.range();
147
+ this.rangeCacheNode = node;
148
+ this.rangeCacheValue = value;
149
+ return value;
150
+ }
151
+
152
+ get nodeType(): string {
153
+ return this.node.kind();
154
+ }
155
+
156
+ get nodeText(): string {
157
+ return this.node.text();
158
+ }
159
+
160
+ get nodeIsMissing(): boolean {
161
+ // HEURISTIK, kein Messwert: ast-grep kennt `ts_node_is_missing` nicht.
162
+ // Ein von der Fehlerkorrektur eingefuegter Knoten hat die Breite null und
163
+ // keine Kinder; die Wurzel ist ausgenommen (eine leere Datei ist kein
164
+ // fehlender Knoten).
165
+ if (this.levels.length === 0) return false;
166
+ const range = this.range;
167
+ return range.start.index === range.end.index && this.node.isLeaf();
168
+ }
169
+
170
+ get currentFieldName(): string | undefined {
171
+ const parent = this.parentNode();
172
+ if (parent === null) return undefined;
173
+ const nodeId = this.node.id();
174
+ for (const fieldName of this.fieldNames) {
175
+ const field = parent.field(fieldName);
176
+ if (field !== null && field.id() === nodeId) return fieldName;
177
+ }
178
+ return undefined;
179
+ }
180
+
181
+ /** Der Elternknoten der aktuellen Position, oder `null` auf der Wurzel. */
182
+ private parentNode(): SgNode | null {
183
+ if (this.levels.length === 0) return null;
184
+ if (this.levels.length === 1) return this.rootNode;
185
+ const level = this.levels[this.levels.length - 2] as CursorLevel;
186
+ return level.siblings[level.index] as SgNode;
187
+ }
188
+
189
+ get currentNode(): SyntaxNode {
190
+ return new AstGrepSyntaxNode(this.node, this.fieldNames);
191
+ }
192
+
193
+ get startPosition(): SyntaxPoint {
194
+ return pointOf(this.range.start);
195
+ }
196
+
197
+ get endPosition(): SyntaxPoint {
198
+ return pointOf(this.range.end);
199
+ }
200
+
201
+ get startIndex(): number {
202
+ return this.range.start.index;
203
+ }
204
+
205
+ get endIndex(): number {
206
+ return this.range.end.index;
207
+ }
208
+
209
+ gotoParent(): boolean {
210
+ if (this.levels.length === 0) return false;
211
+ this.levels.pop();
212
+ return true;
213
+ }
214
+
215
+ gotoFirstChild(): boolean {
216
+ const children = this.node.children();
217
+ if (children.length === 0) return false;
218
+ this.levels.push({ siblings: children, index: 0 });
219
+ return true;
220
+ }
221
+
222
+ gotoLastChild(): boolean {
223
+ const children = this.node.children();
224
+ if (children.length === 0) return false;
225
+ this.levels.push({ siblings: children, index: children.length - 1 });
226
+ return true;
227
+ }
228
+
229
+ gotoNextSibling(): boolean {
230
+ const level = this.levels[this.levels.length - 1];
231
+ if (level === undefined || level.index + 1 >= level.siblings.length) return false;
232
+ level.index += 1;
233
+ return true;
234
+ }
235
+
236
+ gotoPreviousSibling(): boolean {
237
+ const level = this.levels[this.levels.length - 1];
238
+ if (level === undefined || level.index === 0) return false;
239
+ level.index -= 1;
240
+ return true;
241
+ }
242
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Central builtin-language registration point.
3
+ *
4
+ * Dateibesitz (BUILD_PLAN §4): every path under `packages/parser-registry/`
5
+ * belongs to WP-06, EXCEPT `src/languages/python/**` and "the registration
6
+ * line" in this file, both owned by WP-09 (a later wave). WP-09 adds its
7
+ * import and ONE `registry.register(createPythonAdapter());` line below,
8
+ * without touching any line above it — that is the whole contract for
9
+ * adding a language without editing existing files/lines.
10
+ */
11
+ import type { LazyParserRegistry } from "../registry.js";
12
+
13
+ import {
14
+ createBreadthAdapters,
15
+ createGoAdapter,
16
+ createRustAdapter,
17
+ } from "./astgrep-backend/index.js";
18
+ import { createJavaScriptAdapter } from "./javascript/index.js";
19
+ import { createJsxAdapter } from "./jsx/index.js";
20
+ import { createProseAdapter } from "./prose/index.js";
21
+ import { createPythonAdapter } from "./python/index.js";
22
+ import { createStructuredTextAdapter } from "./structured-text/index.js";
23
+ import { createTsxAdapter } from "./tsx/index.js";
24
+ import { createTypeScriptAdapter } from "./typescript/index.js";
25
+ import { createVueAdapter } from "./vue/index.js";
26
+
27
+ /** Registers every builtin language adapter. Registration is cheap and lazy — see `registry.ts`'s doc comment. */
28
+ export function registerBuiltinLanguages(registry: LazyParserRegistry): void {
29
+ registry.register(createTypeScriptAdapter());
30
+ registry.register(createJavaScriptAdapter());
31
+ registry.register(createTsxAdapter());
32
+ registry.register(createJsxAdapter());
33
+ registry.register(createVueAdapter());
34
+ registry.register(createPythonAdapter());
35
+ // WP-110/WP-217: Prosa und strukturierte Daten sind Stufe `text`, nicht
36
+ // `unsupported_language` (vision.md §1c, spec.md §7.2). Beide Adapter
37
+ // laden keine Grammatik und kosten bei der Registrierung nichts.
38
+ registry.register(createProseAdapter());
39
+ registry.register(createStructuredTextAdapter());
40
+ // WP-220: Go und Rust laufen ueber das ast-grep-Backend
41
+ // (`languages/astgrep-backend/README.md` sagt, warum GENAU diese Sprachen
42
+ // dort laufen und die JS/TS-Familie nicht). Die Anmeldung kostet nichts:
43
+ // weder `@ast-grep/napi` noch eine Grammatik wird dabei geladen — das
44
+ // passiert erst beim ersten Parse einer dieser Sprachen.
45
+ registry.register(createGoAdapter());
46
+ registry.register(createRustAdapter());
47
+ // WP-86: neun weitere Sprachen ueber DASSELBE Backend und DIESELBE
48
+ // Tabellenform — Java, C#, Ruby, PHP, Kotlin, C, C++, Swift, Bash. Auch sie
49
+ // laden beim Registrieren nichts.
50
+ for (const adapter of createBreadthAdapters()) {
51
+ registry.register(adapter);
52
+ }
53
+ }
@@ -0,0 +1,9 @@
1
+ import type { LanguageAdapter } from "@untangle-code/domain";
2
+
3
+ import { createTreeSitterAdapter } from "../shared/create-adapter.js";
4
+ import { JAVASCRIPT_DIALECT } from "../shared/dialect.js";
5
+
6
+ /** JavaScript `LanguageAdapter` (`.js`, `.mjs`, `.cjs`), support level "deep" (spec.md §7.2). */
7
+ export function createJavaScriptAdapter(): LanguageAdapter {
8
+ return createTreeSitterAdapter(JAVASCRIPT_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 { JSX_DIALECT } from "../shared/dialect.js";
5
+
6
+ /** JSX `LanguageAdapter` (`.jsx`), support level "deep" (spec.md §7.2). */
7
+ export function createJsxAdapter(): LanguageAdapter {
8
+ return createTreeSitterAdapter(JSX_DIALECT);
9
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Prosa-`LanguageAdapter` (vision.md §1c, WP-110/WP-217).
3
+ *
4
+ * WAS ER LOEST
5
+ *
6
+ * Vor ihm kannte `getAdapterForPath("spec.md")` nur `null`. Jede Stelle, die
7
+ * das fragt — `untangle complexity`, der Watcher, der Selbstanalyse-Report —
8
+ * schrieb daraufhin `unsupported_language` ins Skip-Ledger. Bei der ersten
9
+ * Selbstanalyse dieses Repositories waren das allein 35 Markdown-Dateien,
10
+ * bei 654 KB Markdown gegen 2.006 KB TypeScript. vision.md §1c sagt genau
11
+ * das Gegenteil: Prosa ist erstklassiger Inhalt, und `text` ist kein
12
+ * abgeschwaechtes `deep`.
13
+ *
14
+ * WAS ER LIEFERT — UND WAS BEWUSST NICHT
15
+ *
16
+ * - `extractChunks` liefert ueberschriftenbewusste Abschnitte mit
17
+ * Breadcrumb. Die Gliederung ist NICHT neu gebaut: es ist dieselbe
18
+ * `outlineMarkdown()`, die `@untangle-code/context-artifacts` schon fuer
19
+ * konfigurierte Markdown-Artefakte benutzt hat (WP-110 hat sie nach
20
+ * domain gehoben). Damit bekommt eine gewoehnliche `.md`-Datei im Chunker
21
+ * die AST-Strategie statt `line_fallback` — statt willkuerlicher
22
+ * Zeilenfenster also dieselben semantischen Einheiten wie eine
23
+ * konfigurierte.
24
+ * - `extractSymbols` liefert je Abschnitt ein Symbol der Art `"section"`.
25
+ * Das ist die Zuordnung, ueber die der Chunker `symbolId`/`symbolFqn` an
26
+ * jeden Abschnitt und an jedes Fragment eines zu grossen Abschnitts
27
+ * haengt (spec.md §8.5).
28
+ * - `extractImports` liefert relative Dateiverweise. Ein Verweis von
29
+ * `vision.md` auf `spec.md` IST eine Kante im Dateigraphen; sie zu
30
+ * verschweigen waere derselbe Verlust wie ein verschwiegener Import.
31
+ * - `extractCalls` liefert NICHTS. Prosa hat keine Aufrufe.
32
+ * - `computeComplexity` liefert LEERE Facts: keine `symbolScopes`, keine
33
+ * `decisions`. Das ist der Kern von WP-217 und keine Nachlaessigkeit —
34
+ * zyklomatische Komplexitaet ueber ein Dokument ist keine schlechte Zahl,
35
+ * sondern gar keine. Wer Prosa messen will, nimmt die Prosa-Metriken aus
36
+ * `@untangle-code/complexity` (`computeProseMetrics`), die als eigene
37
+ * Metrikfamilie (`ProseNumberV1`) gefuehrt werden und deshalb strukturell
38
+ * nie in eine Code-Summe geraten koennen.
39
+ * - `tokenizeForHalstead` liefert NICHTS: Halstead zaehlt Operatoren und
40
+ * Operanden; in Prosa gibt es beides nicht.
41
+ *
42
+ * `parse()` kann nicht scheitern. Markdown hat keine Syntaxfehler — jeder
43
+ * Text ist gueltiges Markdown —, deshalb ist `parseQuality` immer
44
+ * `"complete"` und `ast` nie `null`. Das ist eine Aussage ueber das Format,
45
+ * keine Beschoenigung.
46
+ */
47
+ import type {
48
+ AstRegion,
49
+ ComplexityFacts,
50
+ ExtractedSymbol,
51
+ HalsteadTokens,
52
+ LanguageAdapter,
53
+ MarkdownSectionV1,
54
+ ParsedAst,
55
+ ParseResult,
56
+ RawCall,
57
+ RawImport,
58
+ SourceFile,
59
+ SourceRange,
60
+ } from "@untangle-code/domain";
61
+ import {
62
+ classifyLinkTarget,
63
+ findMarkdownLinks,
64
+ outlineMarkdown,
65
+ sha256Hex,
66
+ textFormatExtensions,
67
+ } from "@untangle-code/domain";
68
+
69
+ import { buildLineByteIndex, rangeForLines, type LineByteIndex } from "./line-bytes.js";
70
+
71
+ /** Sprachkennung dieses Adapters; identisch mit der Scanner-Klassifikation fuer `.md`. */
72
+ export const PROSE_LANGUAGE_ID = "markdown";
73
+
74
+ /** Symbolart eines Prosa-Abschnitts. Ein Abschnitt ist keine Funktion und heisst auch nicht so. */
75
+ export const PROSE_SYMBOL_KIND = "section";
76
+
77
+ /** Name des Abschnitts vor der ersten Ueberschrift. */
78
+ const PREAMBLE_NAME = "(Vorspann)";
79
+
80
+ /** Der in `ParsedAst.root` abgelegte Nutzinhalt; nur dieser Adapter sieht hinein. */
81
+ interface ProseAstRoot {
82
+ readonly fileId: string;
83
+ readonly lines: readonly string[];
84
+ readonly index: LineByteIndex;
85
+ readonly sections: readonly ProseSection[];
86
+ }
87
+
88
+ interface ProseSection extends MarkdownSectionV1 {
89
+ /** Eindeutiger Name innerhalb des Dokuments (siehe `uniqueName`). */
90
+ readonly qualifiedName: string;
91
+ readonly range: SourceRange;
92
+ }
93
+
94
+ /**
95
+ * Physische Zeilen ohne Zeilenende. Ein abschliessendes `\r` faellt weg,
96
+ * damit die Ueberschriften- und Verweiserkennung nicht daran scheitert.
97
+ */
98
+ function splitLines(content: string): string[] {
99
+ return content.split("\n").map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line));
100
+ }
101
+
102
+ /**
103
+ * Zwei Abschnitte koennen denselben Breadcrumb tragen (zweimal dieselbe
104
+ * Ueberschrift unter demselben Elternteil). Der Chunker schluesselt Symbole
105
+ * ueber `qualifiedName` in einer `Map`; ohne Vereindeutigung wuerde der
106
+ * zweite Abschnitt den ersten ueberschreiben und beide dieselbe `symbolId`
107
+ * bekommen. Angehaengt wird deshalb eine laufende Nummer — sichtbar, nicht
108
+ * still.
109
+ */
110
+ function uniqueName(breadcrumb: string, seen: Map<string, number>): string {
111
+ const base = breadcrumb === "" ? PREAMBLE_NAME : breadcrumb;
112
+ const count = (seen.get(base) ?? 0) + 1;
113
+ seen.set(base, count);
114
+ return count === 1 ? base : `${base} (${String(count)})`;
115
+ }
116
+
117
+ function buildSections(lines: readonly string[], index: LineByteIndex): ProseSection[] {
118
+ const seen = new Map<string, number>();
119
+ return outlineMarkdown(lines).map((section) => ({
120
+ ...section,
121
+ qualifiedName: uniqueName(section.breadcrumb, seen),
122
+ range: rangeForLines(index, section.startLine, section.endLine),
123
+ }));
124
+ }
125
+
126
+ function rootOf(ast: ParsedAst): ProseAstRoot {
127
+ return ast.root as ProseAstRoot;
128
+ }
129
+
130
+ function sectionContent(root: ProseAstRoot, section: ProseSection): string {
131
+ return root.lines.slice(section.startLine - 1, section.endLine).join("\n");
132
+ }
133
+
134
+ function headingTextOf(section: ProseSection): string {
135
+ return section.level === 0 ? PREAMBLE_NAME : `${"#".repeat(section.level)} ${section.title}`;
136
+ }
137
+
138
+ function symbolOf(root: ProseAstRoot, section: ProseSection): ExtractedSymbol {
139
+ return {
140
+ name: section.level === 0 ? PREAMBLE_NAME : section.title,
141
+ qualifiedName: section.qualifiedName,
142
+ kind: PROSE_SYMBOL_KIND,
143
+ signature: headingTextOf(section),
144
+ // Die "Signatur" eines Abschnitts ist seine Ueberschriftenebene plus
145
+ // Pfad: was ihn im Dokument identifiziert, unabhaengig von seiner Zeile.
146
+ normalizedSignature: `h${String(section.level)} ${section.qualifiedName}`,
147
+ range: section.range,
148
+ exportedNames: [],
149
+ // Formhash: Ebene und Pfad — aendert sich, wenn der Abschnitt umbenannt
150
+ // oder verschoben wird, nicht wenn sein Text sich aendert.
151
+ astHash: sha256Hex(`prose-section ${String(section.level)} ${section.qualifiedName}`),
152
+ // Inhaltshash: der Rohtext des Abschnitts.
153
+ tokenFingerprint: sha256Hex(sectionContent(root, section)),
154
+ };
155
+ }
156
+
157
+ export function createProseAdapter(): LanguageAdapter {
158
+ return {
159
+ languageId: PROSE_LANGUAGE_ID,
160
+ extensions: textFormatExtensions("prose"),
161
+ supportLevel: "text",
162
+
163
+ parse(source: SourceFile): ParseResult {
164
+ const lines = splitLines(source.content);
165
+ const index = buildLineByteIndex(source.content);
166
+ const root: ProseAstRoot = {
167
+ fileId: source.fileId,
168
+ lines,
169
+ index,
170
+ sections: buildSections(lines, index),
171
+ };
172
+ const ast: ParsedAst = {
173
+ languageId: PROSE_LANGUAGE_ID,
174
+ parseQuality: "complete",
175
+ root,
176
+ diagnostics: [],
177
+ };
178
+ return {
179
+ parseQuality: "complete",
180
+ ast,
181
+ diagnostics: [],
182
+ errorNodeCount: 0,
183
+ missingNodeCount: 0,
184
+ };
185
+ },
186
+
187
+ extractChunks(ast: ParsedAst): AstRegion[] {
188
+ const root = rootOf(ast);
189
+ const children: AstRegion[] = root.sections.map((section) => ({
190
+ // Der Vorspann vor der ersten Ueberschrift ist genau das, was
191
+ // `file_preamble` beschreibt; alles Weitere ist ein Prosa-Abschnitt.
192
+ chunkKind: section.level === 0 ? "file_preamble" : "prose_section",
193
+ range: section.range,
194
+ scopeId: `${root.fileId}#${section.qualifiedName}`,
195
+ symbolFqn: section.qualifiedName,
196
+ headerText:
197
+ section.level === 0
198
+ ? PREAMBLE_NAME
199
+ : `${"#".repeat(section.level)} ${section.breadcrumb}`,
200
+ // Ein Abschnitt hat keine feineren AST-Grenzen; ist er zu gross,
201
+ // teilt der Chunker ihn an Tokengrenzen in `symbol_fragment`s, die
202
+ // seine `symbolId` erben (spec.md §8.5).
203
+ splittable: false,
204
+ }));
205
+ return [
206
+ {
207
+ chunkKind: "module",
208
+ range: {
209
+ startLine: 1,
210
+ endLine: root.index.lineCount,
211
+ startByte: 0,
212
+ endByte: root.index.totalBytes,
213
+ },
214
+ scopeId: root.fileId,
215
+ splittable: children.length > 0,
216
+ ...(children.length > 0 ? { children } : {}),
217
+ },
218
+ ];
219
+ },
220
+
221
+ extractSymbols(ast: ParsedAst): ExtractedSymbol[] {
222
+ const root = rootOf(ast);
223
+ return root.sections.map((section) => symbolOf(root, section));
224
+ },
225
+
226
+ extractImports(ast: ParsedAst): RawImport[] {
227
+ const root = rootOf(ast);
228
+ const imports: RawImport[] = [];
229
+ for (const link of findMarkdownLinks(root.lines)) {
230
+ if (classifyLinkTarget(link.target) !== "relative_file") continue;
231
+ imports.push({
232
+ specifier: link.target,
233
+ importKind: "import",
234
+ range: rangeForLines(root.index, link.line, link.line),
235
+ });
236
+ }
237
+ return imports;
238
+ },
239
+
240
+ extractCalls(_ast: ParsedAst): RawCall[] {
241
+ // Prosa hat keine Aufrufe. Eine leere Liste ist hier die vollstaendige
242
+ // Antwort, keine Abstufung.
243
+ return [];
244
+ },
245
+
246
+ computeComplexity(ast: ParsedAst): ComplexityFacts {
247
+ // KEINE `symbolScopes` und KEINE `decisions` — siehe Kopfkommentar.
248
+ // Stuende hier je Abschnitt ein Scope, rechnete jede
249
+ // Code-Metrik-Pipeline anschliessend `cyclomatic = 1` je Ueberschrift
250
+ // und addierte das zur Summe des Repositories. Genau das verhindert
251
+ // diese leere Antwort.
252
+ return {
253
+ symbolScopes: [],
254
+ decisions: [],
255
+ nestingEvents: [],
256
+ operators: [],
257
+ operands: [],
258
+ nodeKinds: [],
259
+ comments: [],
260
+ identifiers: [],
261
+ literals: [],
262
+ parseDiagnostics: ast.diagnostics,
263
+ };
264
+ },
265
+
266
+ tokenizeForHalstead(_ast: ParsedAst): HalsteadTokens {
267
+ return { operators: [], operands: [] };
268
+ },
269
+ };
270
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Zeilenanfaenge als UTF-8-Byte-Versaetze.
3
+ *
4
+ * `SourceRange` (domain `types/common.ts`) ist auf BYTES normativ; die
5
+ * Prosa-Gliederung arbeitet in ZEILEN. Diese Tabelle ist die Uebersetzung.
6
+ * Geschnitten wird ausschliesslich unmittelbar nach `\n` (0x0A) — ein
7
+ * Einzelbyte, nie ein UTF-8-Folgebyte —, damit jede erzeugte Grenze eine
8
+ * gueltige Zeichengrenze ist.
9
+ */
10
+
11
+ export interface LineByteIndex {
12
+ /** Byte-Versatz jedes Zeilenanfangs, plus ein Schlusswaechter = Dateigroesse. */
13
+ readonly lineStarts: readonly number[];
14
+ /** Anzahl physischer Zeilen. */
15
+ readonly lineCount: number;
16
+ readonly totalBytes: number;
17
+ }
18
+
19
+ export function buildLineByteIndex(content: string): LineByteIndex {
20
+ const buffer = Buffer.from(content, "utf8");
21
+ const lineStarts: number[] = [0];
22
+ for (let i = 0; i < buffer.length; i += 1) {
23
+ if (buffer[i] === 0x0a) lineStarts.push(i + 1);
24
+ }
25
+ const lineCount = lineStarts.length;
26
+ lineStarts.push(buffer.length);
27
+ return { lineStarts, lineCount, totalBytes: buffer.length };
28
+ }
29
+
30
+ /** Byte-Versatz des Anfangs der 1-basierten Zeile `line`, geklemmt. */
31
+ export function lineStartByte(index: LineByteIndex, line: number): number {
32
+ const clamped = Math.min(Math.max(line, 1), index.lineStarts.length);
33
+ return index.lineStarts[clamped - 1] ?? index.totalBytes;
34
+ }
35
+
36
+ /**
37
+ * `SourceRange` fuer die 1-basierte inklusive Zeilenspanne. `endByte` ist der
38
+ * Anfang der Zeile NACH `endLine`, also sind zwei benachbarte Spannen
39
+ * lueckenlos und ueberlappungsfrei.
40
+ */
41
+ export function rangeForLines(
42
+ index: LineByteIndex,
43
+ startLine: number,
44
+ endLine: number,
45
+ ): { startLine: number; endLine: number; startByte: number; endByte: number } {
46
+ return {
47
+ startLine,
48
+ endLine,
49
+ startByte: lineStartByte(index, startLine),
50
+ endByte: lineStartByte(index, endLine + 1),
51
+ };
52
+ }