@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,55 @@
1
+ import type { SupportLevel } from "@untangle-code/domain";
2
+
3
+ import type { GrammarSource } from "./grammar-loader.js";
4
+
5
+ /** Static, per-language configuration for the tree-sitter adapter factory. */
6
+ export interface Dialect {
7
+ languageId: string;
8
+ extensions: string[];
9
+ supportLevel: SupportLevel;
10
+ grammar: GrammarSource;
11
+ /** Whether the grammar has TypeScript type syntax (interfaces, type aliases, enums, type annotations, generics). */
12
+ hasTypes: boolean;
13
+ /** Class field/property-signature node type name, which differs between the JS and TS grammars. */
14
+ fieldDefinitionKind: "field_definition" | "public_field_definition";
15
+ }
16
+
17
+ export const TYPESCRIPT_DIALECT: Dialect = {
18
+ languageId: "typescript",
19
+ extensions: [".ts", ".mts", ".cts"],
20
+ supportLevel: "deep",
21
+ grammar: { moduleName: "tree-sitter-typescript", exportName: "typescript" },
22
+ hasTypes: true,
23
+ fieldDefinitionKind: "public_field_definition",
24
+ };
25
+
26
+ export const TSX_DIALECT: Dialect = {
27
+ languageId: "tsx",
28
+ extensions: [".tsx"],
29
+ supportLevel: "deep",
30
+ grammar: { moduleName: "tree-sitter-typescript", exportName: "tsx" },
31
+ hasTypes: true,
32
+ fieldDefinitionKind: "public_field_definition",
33
+ };
34
+
35
+ export const JAVASCRIPT_DIALECT: Dialect = {
36
+ languageId: "javascript",
37
+ extensions: [".js", ".mjs", ".cjs"],
38
+ supportLevel: "deep",
39
+ grammar: { moduleName: "tree-sitter-javascript" },
40
+ hasTypes: false,
41
+ fieldDefinitionKind: "field_definition",
42
+ };
43
+
44
+ export const JSX_DIALECT: Dialect = {
45
+ languageId: "jsx",
46
+ extensions: [".jsx"],
47
+ supportLevel: "deep",
48
+ // tree-sitter-javascript's single grammar already parses JSX syntax
49
+ // (verified empirically — see README "Grammatik-Wahl"); JSX gets its own
50
+ // languageId/extension per spec.md §7.2's MVP table row ("TSX/JSX"), not
51
+ // its own grammar.
52
+ grammar: { moduleName: "tree-sitter-javascript" },
53
+ hasTypes: false,
54
+ fieldDefinitionKind: "field_definition",
55
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Doc-comment binding (spec.md §8.3 step 2: "Doccomment, Annotationen und
3
+ * Dekoratoren an das folgende Symbol binden").
4
+ *
5
+ * Decorators are represented by the grammar as PRECEDING SIBLINGS of the
6
+ * member they decorate inside `class_body` (verified empirically — not as a
7
+ * nested field on the member node, despite `node-types.json` listing
8
+ * `decorator` as an optional field; that field shape applies to parameter
9
+ * decorators, e.g. `constructor(@Inject() dep: Dep)`, which nest inside
10
+ * `required_parameter` instead). A leading doc comment is, in turn, a
11
+ * preceding sibling of the (possibly decorator-preceded) member.
12
+ *
13
+ * For a symbol whose defining node is buried inside an expression (an arrow
14
+ * function assigned to a `const`, a function expression as an object
15
+ * property value, ...), the anchor for "preceding sibling" purposes is not
16
+ * the function node itself but its enclosing statement — see
17
+ * `resolveDocAnchor`.
18
+ */
19
+ import type { SourceRange } from "@untangle-code/domain";
20
+
21
+ import { COMMENT_TYPE, DECORATOR_TYPE } from "./node-kinds.js";
22
+ import type { FileTextContext } from "./node-utils.js";
23
+ import { rangeOf, unionRange } from "./node-utils.js";
24
+ import type { SyntaxNode } from "./syntax.js";
25
+
26
+ /** Climbs from a (possibly deeply nested) scope-defining node to its statement-level anchor. */
27
+ export function resolveDocAnchor(node: SyntaxNode): SyntaxNode {
28
+ let anchor = node;
29
+ const parent = node.parent;
30
+ if (parent !== null) {
31
+ if (parent.type === "variable_declarator") {
32
+ const declarationList = parent.parent;
33
+ if (
34
+ declarationList !== null &&
35
+ (declarationList.type === "lexical_declaration" ||
36
+ declarationList.type === "variable_declaration")
37
+ ) {
38
+ anchor = declarationList;
39
+ }
40
+ } else if (
41
+ parent.type === "assignment_expression" &&
42
+ parent.parent?.type === "expression_statement"
43
+ ) {
44
+ anchor = parent.parent;
45
+ }
46
+ }
47
+ if (anchor.parent !== null && anchor.parent.type === "export_statement") {
48
+ anchor = anchor.parent;
49
+ }
50
+ return anchor;
51
+ }
52
+
53
+ const MAX_BLANK_LINES_BETWEEN_DOC_AND_SYMBOL = 1;
54
+
55
+ /** Resolves the bound doc-comment range for a scope-defining node, if any (spec.md §8.3 step 2). */
56
+ export function resolveDocRange(node: SyntaxNode, ctx: FileTextContext): SourceRange | undefined {
57
+ const anchor = resolveDocAnchor(node);
58
+
59
+ let cursor = anchor.previousSibling;
60
+ let boundary = anchor;
61
+ // Skip immediately-preceding decorators (they travel with the symbol's own range, not the doc range,
62
+ // but a comment further back must still be considered "immediately preceding" through them).
63
+ while (cursor !== null && cursor.type === DECORATOR_TYPE) {
64
+ boundary = cursor;
65
+ cursor = cursor.previousSibling;
66
+ }
67
+
68
+ let docRange: SourceRange | undefined;
69
+ while (cursor !== null && cursor.type === COMMENT_TYPE) {
70
+ const gap = boundary.startPosition.row - cursor.endPosition.row;
71
+ if (gap > MAX_BLANK_LINES_BETWEEN_DOC_AND_SYMBOL) break;
72
+ const commentRange = rangeOf(cursor, ctx);
73
+ docRange = docRange === undefined ? commentRange : unionRange(commentRange, docRange);
74
+ boundary = cursor;
75
+ cursor = cursor.previousSibling;
76
+ }
77
+ return docRange;
78
+ }
@@ -0,0 +1,461 @@
1
+ /**
2
+ * The single unified AST walk. Every `LanguageAdapter` extraction method
3
+ * (`extractSymbols`, `extractImports`, `extractCalls`, `computeComplexity`,
4
+ * `tokenizeForHalstead`, `extractChunks`) is a thin projection over the ONE
5
+ * `AnalysisResult` this module computes — see `create-adapter.ts`, which
6
+ * memoizes it per `ParsedAst` (via `WeakMap`) so calling multiple extract
7
+ * methods on the same parse re-walks the tree only once.
8
+ *
9
+ * Building everything in one pass is not just a performance optimization:
10
+ * it is what GUARANTEES that a `symbolScopeId` produced for a
11
+ * `SymbolScopeFact` (from `computeComplexity`) is the exact same string as
12
+ * the `callerScopeId` on a `RawCall` (from `extractCalls`) for a call
13
+ * written inside that scope — both come from the same live scope-stack
14
+ * frame during the same walk, not from two independently-reimplemented
15
+ * scope-id algorithms that could drift apart.
16
+ *
17
+ * TRAVERSIERUNG (WP-95): der Walk laeuft ueber die CURSOR-API
18
+ * (`tree.walk()` / `gotoFirstChild` / `gotoNextSibling` / `gotoParent`),
19
+ * NICHT ueber `node.children`. Gemessen an diesem Repository (716 Dateien,
20
+ * 128.219 Zeilen) kostete der `.children`-Weg 25,6 s fuer den Walk gegen
21
+ * 3,6 s fuers Parsen: jeder `.children`-Zugriff baut ein JS-Array aus
22
+ * Knotenwrappern und ueberquert die Grenze zur nativen Bibliothek einmal je
23
+ * Knoten. Der Cursor haelt die Position nativ.
24
+ *
25
+ * WAS DER CURSOR NICHT HAT, und wie es hier ersetzt wird:
26
+ * - `node.parent` -> `parentTypeAt[depth]`, waehrend des Abstiegs gefuehrt.
27
+ * - `node.childCount === 0` -> ein probeweises `gotoFirstChild()`; schlaegt
28
+ * es fehl, ist der Knoten ein Blatt (sonst bringt `gotoParent()` zurueck).
29
+ * - `parent.childForFieldName(...)` fuer die Rolle eines Bezeichners ->
30
+ * `cursor.currentFieldName`, das denselben Feldnamen ohne Wrapper liefert.
31
+ *
32
+ * Ein `SyntaxNode`-Wrapper entsteht nur noch dort, wo ein Detektor ihn
33
+ * wirklich braucht (siehe `visitInnerNode`) — wer diese Vorsiebe aufweicht,
34
+ * baut die Grenzueberquerung je Knoten wieder ein.
35
+ */
36
+ import type {
37
+ ComplexityFacts,
38
+ IdentifierFact,
39
+ LiteralFact,
40
+ NodeKindFact,
41
+ RawCall,
42
+ RawImport,
43
+ SourceRange,
44
+ SymbolScopeFact,
45
+ TokenFact,
46
+ } from "@untangle-code/domain";
47
+
48
+ import { lambdaNesting } from "./decisions.js";
49
+ import { computeAstHash, computeTokenFingerprint } from "./fingerprint.js";
50
+ import type { FileTextContext } from "./node-utils.js";
51
+ import { commentRangeOfCursor, rangeOf, rangeOfCursor } from "./node-utils.js";
52
+ import type { LanguageProfile, ModuleFactSink } from "./profile.js";
53
+ import { isExecutableScopeKind } from "./profile.js";
54
+ import type { ScopeNode } from "./scope-model.js";
55
+ import type { SyntaxCursor, SyntaxNode } from "./syntax.js";
56
+
57
+ export interface AnalysisResult {
58
+ scopeTree: ScopeNode;
59
+ facts: ComplexityFacts;
60
+ imports: RawImport[];
61
+ calls: RawCall[];
62
+ }
63
+
64
+ interface MutableFacts {
65
+ symbolScopes: SymbolScopeFact[];
66
+ decisions: ComplexityFacts["decisions"];
67
+ nestingEvents: ComplexityFacts["nestingEvents"];
68
+ operators: TokenFact[];
69
+ operands: TokenFact[];
70
+ nodeKinds: NodeKindFact[];
71
+ comments: SourceRange[];
72
+ identifiers: IdentifierFact[];
73
+ literals: LiteralFact[];
74
+ imports: RawImport[];
75
+ calls: RawCall[];
76
+ }
77
+
78
+ /** Separates scope-id components (U+001F, unit separator) — avoids the classic "ab"+"c" == "a"+"bc" join ambiguity. */
79
+ const SCOPE_ID_SEPARATOR = "";
80
+
81
+ interface WorkingFrame {
82
+ scopeId: string;
83
+ qualifiedName: string;
84
+ executable: boolean;
85
+ scopeNode: ScopeNode;
86
+ childOrdinalCounters: Map<string, number>;
87
+ }
88
+
89
+ function toSymbolScopeFact(
90
+ frame: WorkingFrame,
91
+ parentScopeId: string | undefined,
92
+ ): SymbolScopeFact {
93
+ const { scopeNode } = frame;
94
+ return {
95
+ symbolScopeId: scopeNode.scopeId,
96
+ name: scopeNode.name,
97
+ qualifiedName: scopeNode.qualifiedName,
98
+ kind: scopeNode.kind,
99
+ range: scopeNode.range,
100
+ ...(parentScopeId !== undefined ? { parentScopeId } : {}),
101
+ executable: scopeNode.executable,
102
+ };
103
+ }
104
+
105
+ function openScope(
106
+ cursor: SyntaxCursor,
107
+ node: SyntaxNode,
108
+ parent: WorkingFrame,
109
+ profile: LanguageProfile,
110
+ ctx: FileTextContext,
111
+ fileId: string,
112
+ out: MutableFacts,
113
+ ): WorkingFrame | null {
114
+ if (profile.suppressesScope(node)) return null;
115
+
116
+ const kind = profile.scopeKindOf(node);
117
+ if (kind === null) return null;
118
+
119
+ const name = profile.scopeName(node);
120
+ // WP-237: Sprachen, die den Traeger als FELD statt als Elternknoten fuehren
121
+ // (Gos Methodenempfaenger), liefern ihn hier nach. Der SYMBOLNAME bleibt
122
+ // unveraendert `Run` — nur der qualifizierte Name wird `A.Run`, damit zwei
123
+ // gleichnamige Methoden auf verschiedenen Typen unterscheidbar bleiben.
124
+ const qualifier = profile.scopeQualifier?.(node);
125
+ const localName = qualifier === undefined ? name : `${qualifier}.${name}`;
126
+ const qualifiedName =
127
+ parent.qualifiedName.length > 0 ? `${parent.qualifiedName}.${localName}` : localName;
128
+ const counterKey = `${kind}:${qualifiedName}`;
129
+ const ordinal = parent.childOrdinalCounters.get(counterKey) ?? 0;
130
+ parent.childOrdinalCounters.set(counterKey, ordinal + 1);
131
+ const scopeId = [fileId, "scope", qualifiedName, kind, String(ordinal)].join(SCOPE_ID_SEPARATOR);
132
+
133
+ const signature = profile.scopeSignature(node, kind, name);
134
+ const docRange = profile.docRange(node, ctx);
135
+ const executable = isExecutableScopeKind(kind);
136
+ const visibility = profile.visibility(node, name);
137
+ const parentQualifiedName = parent.qualifiedName.length > 0 ? parent.qualifiedName : undefined;
138
+
139
+ const scopeNode: ScopeNode = {
140
+ scopeId,
141
+ kind,
142
+ name,
143
+ qualifiedName,
144
+ ...(parentQualifiedName !== undefined ? { parentQualifiedName } : {}),
145
+ range: rangeOf(node, ctx),
146
+ ...(docRange !== undefined ? { docRange } : {}),
147
+ ...(signature.raw !== undefined ? { signature: signature.raw } : {}),
148
+ normalizedSignature: signature.normalized,
149
+ exportedNames: profile.exportedNames(node, name),
150
+ ...(visibility !== undefined ? { visibility } : {}),
151
+ executable,
152
+ astHash: computeAstHash(cursor, profile),
153
+ tokenFingerprint: computeTokenFingerprint(cursor, profile),
154
+ node,
155
+ children: [],
156
+ };
157
+
158
+ const frame: WorkingFrame = {
159
+ scopeId,
160
+ qualifiedName,
161
+ executable,
162
+ scopeNode,
163
+ childOrdinalCounters: new Map(),
164
+ };
165
+ out.symbolScopes.push(toSymbolScopeFact(frame, parent.scopeId));
166
+ parent.scopeNode.children.push(scopeNode);
167
+ return frame;
168
+ }
169
+
170
+ /**
171
+ * Ein Blattknoten (kein Kind) wird eingeordnet. Der Cursor steht auf ihm; ein
172
+ * `SyntaxNode`-Wrapper wird NICHT gebaut — `nodeText`, `nodeType` und
173
+ * `currentFieldName` liefern alles Noetige, `parentType` kommt aus dem Abstieg.
174
+ *
175
+ * Die frueher hier stehende `predefined_type`-Pruefung ist ENTFALLEN, nicht
176
+ * vergessen: der einzige Aufrufer (`walkWithCursor`) siebt diesen Fall bereits
177
+ * vor dem Blatt-Zweig aus (ueber `profile.typeKeywordParentKinds`), die
178
+ * Pruefung war an dieser Stelle unerreichbar.
179
+ */
180
+ function classifyAndRecordLeaf(
181
+ cursor: SyntaxCursor,
182
+ nodeType: string,
183
+ parentType: string,
184
+ range: SourceRange,
185
+ frame: WorkingFrame,
186
+ profile: LanguageProfile,
187
+ out: MutableFacts,
188
+ ): void {
189
+ const scopeId = frame.scopeId;
190
+
191
+ if (profile.identifierLeafKinds.has(nodeType)) {
192
+ const text = cursor.nodeText;
193
+ out.identifiers.push({
194
+ name: text,
195
+ range,
196
+ symbolScopeId: scopeId,
197
+ role: profile.identifierRole(cursor.currentFieldName, parentType),
198
+ });
199
+ out.operands.push({ text, range, symbolScopeId: scopeId });
200
+ return;
201
+ }
202
+
203
+ if (profile.simpleLiteralLeafKinds.has(nodeType)) {
204
+ const text = cursor.nodeText;
205
+ out.literals.push({
206
+ raw: text,
207
+ literalKind: profile.simpleLiteralKind(nodeType),
208
+ range,
209
+ symbolScopeId: scopeId,
210
+ });
211
+ out.operands.push({ text, range, symbolScopeId: scopeId });
212
+ return;
213
+ }
214
+
215
+ if (profile.templateTextLeafKinds.has(nodeType)) {
216
+ const text = cursor.nodeText;
217
+ out.literals.push({ raw: text, literalKind: "template", range, symbolScopeId: scopeId });
218
+ out.operands.push({ text, range, symbolScopeId: scopeId });
219
+ return;
220
+ }
221
+
222
+ if (profile.ignoredPunctuationKinds.has(nodeType)) return;
223
+
224
+ out.operators.push({ text: cursor.nodeText, range, symbolScopeId: scopeId });
225
+ }
226
+
227
+ /**
228
+ * Alles, was ein innerer Knoten (mindestens ein Kind) beitraegt: Entscheidung,
229
+ * Nesting, Import, Aufruf, eigener Scope. Gibt den neu geoeffneten Scope-Rahmen
230
+ * zurueck, sonst `null`.
231
+ *
232
+ * HIER und nur hier entsteht ein `SyntaxNode`-Wrapper, und nur wenn das Profil
233
+ * fuer diese Knotenart ueberhaupt einen Detektor auf den Plan ruft
234
+ * (`profile.needsNode`). Fuer die grosse Mehrheit der inneren Knoten faellt die
235
+ * Grenzueberquerung damit ganz weg — beim tree-sitter-Backend spart das den
236
+ * Wrapper, beim ast-grep-Backend den weit teureren `children()`-Aufbau.
237
+ */
238
+ function visitInnerNode(
239
+ cursor: SyntaxCursor,
240
+ nodeType: string,
241
+ range: SourceRange,
242
+ frame: WorkingFrame,
243
+ profile: LanguageProfile,
244
+ ctx: FileTextContext,
245
+ fileId: string,
246
+ out: MutableFacts,
247
+ ): WorkingFrame | null {
248
+ // Kein Detektor zustaendig: kein Wrapper, kein Scope. Das Lambda-Nesting
249
+ // unten kann hier nicht verloren gehen — ein funktionsartiger Knoten oeffnet
250
+ // immer auch einen Scope, also ist `needsNode` dort wahr (in
251
+ // `js-family-profile.ts` wie in `table-profile.ts` durch Konstruktion).
252
+ if (!profile.needsNode(nodeType)) return null;
253
+
254
+ const node = cursor.currentNode;
255
+
256
+ // Decision / nesting facts.
257
+ const detected = profile.detectDecisionAndNesting(node);
258
+ if (detected.decision !== undefined) {
259
+ const fact = {
260
+ kind: detected.decision.kind,
261
+ range,
262
+ symbolScopeId: frame.scopeId,
263
+ countsForClassic: detected.decision.countsForClassic,
264
+ countsForExtended: detected.decision.countsForExtended,
265
+ ...(detected.decision.logicalGroupId !== undefined
266
+ ? { logicalGroupId: detected.decision.logicalGroupId }
267
+ : {}),
268
+ };
269
+ // `repeat` (Vorgabe 1) ist die flache n-stellige Alternative — siehe
270
+ // `DetectedDecision.repeat`. Jede Wiederholung ist eine EIGENE Tatsache
271
+ // mit demselben Bereich, kein Zaehler auf einer.
272
+ for (let index = 0; index < (detected.decision.repeat ?? 1); index += 1) {
273
+ out.decisions.push({ ...fact });
274
+ }
275
+ }
276
+ if (detected.nesting !== undefined) {
277
+ out.nestingEvents.push({
278
+ construct: detected.nesting.construct,
279
+ range,
280
+ symbolScopeId: frame.scopeId,
281
+ continuation: detected.nesting.continuation,
282
+ });
283
+ }
284
+
285
+ // Importe und Aufrufe (Aufrufe dem AKTUELLEN Scope zugerechnet, also dem Rufer).
286
+ const sink: ModuleFactSink = { imports: out.imports, calls: out.calls };
287
+ profile.collectModuleFacts(node, nodeType, frame.scopeId, ctx, sink);
288
+
289
+ const openedScope = openScope(cursor, node, frame, profile, ctx, fileId, out);
290
+
291
+ // A directly-nested function-like node (lambda/local function) inside an
292
+ // already-executable scope gets an extra lambda nesting event (spec.md
293
+ // §16.4: "lokale Funktionen/Lambdas verwenden einen dokumentierten
294
+ // Nesting-Kontext") in addition to becoming its own scope below. A node kind
295
+ // can be function-like only in a particular syntactic context, so a rejected
296
+ // scope must not leave behind a phantom lambda event.
297
+ if (openedScope !== null && frame.executable && profile.functionLikeKinds.has(nodeType)) {
298
+ const lambda = lambdaNesting();
299
+ out.nestingEvents.push({
300
+ construct: lambda.construct,
301
+ range,
302
+ symbolScopeId: frame.scopeId,
303
+ continuation: lambda.continuation,
304
+ });
305
+ }
306
+
307
+ return openedScope;
308
+ }
309
+
310
+ /**
311
+ * Der vereinheitlichte Walk, iterativ ueber einen Baumcursor.
312
+ *
313
+ * Der Cursor beginnt auf der Wurzel und endet wieder dort. Besuchsreihenfolge,
314
+ * `depth`-Zaehlung und die Reihenfolge JEDER Faktenliste sind identisch mit
315
+ * der frueheren Rekursion ueber `node.children` — die Gegenprobe
316
+ * (`diff-walk.mjs`, siehe README) faehrt beide Wege ueber dieses Repository
317
+ * und vergleicht Symbole, Regionen, Chunk-IDs und Metriken Datei fuer Datei.
318
+ *
319
+ * `frameAt`/`parentTypeAt` sind nach Tiefe indiziert und ersetzen zusammen den
320
+ * Aufrufstapel der Rekursion samt `node.parent`. Eintraege unterhalb der
321
+ * aktuellen Tiefe sind veraltet, werden aber vor jedem Lesen ueberschrieben.
322
+ */
323
+ function walkWithCursor(
324
+ cursor: SyntaxCursor,
325
+ rootType: string,
326
+ rootFrame: WorkingFrame,
327
+ profile: LanguageProfile,
328
+ ctx: FileTextContext,
329
+ fileId: string,
330
+ out: MutableFacts,
331
+ ): void {
332
+ if (!cursor.gotoFirstChild()) return;
333
+
334
+ const frameAt: WorkingFrame[] = [rootFrame, rootFrame];
335
+ const parentTypeAt: string[] = [rootType, rootType];
336
+ let depth = 1;
337
+
338
+ for (;;) {
339
+ const frame = frameAt[depth] as WorkingFrame;
340
+ const parentType = parentTypeAt[depth] as string;
341
+ const nodeType = cursor.nodeType;
342
+ const range = rangeOfCursor(cursor, ctx);
343
+ out.nodeKinds.push({ kind: nodeType, depth, symbolScopeId: frame.scopeId });
344
+
345
+ let descended = false;
346
+
347
+ if (profile.commentKinds.has(nodeType)) {
348
+ out.comments.push(commentRangeOfCursor(cursor, ctx));
349
+ } else if (profile.typeKeywordParentKinds.has(parentType)) {
350
+ // Ein Typschluessselwort-Blatt (z. B. das `string`/`number`/`void`-Kind
351
+ // von `predefined_type`): dieselben Namen wie Literale, aber Typsyntax,
352
+ // kein Wert. Weiter in `nodeKinds` gezaehlt (oben), nie als
353
+ // Operator/Operand/Literal/Bezeichner. Muss VOR dem Literalcontainer
354
+ // unten stehen: das Kind fuer das Typschluesselwort `string` hat den
355
+ // Knotentyp "string" — genau denselben wie ein echtes Zeichenkettenliteral.
356
+ } else if (profile.literalContainerKinds.has(nodeType)) {
357
+ const text = cursor.nodeText;
358
+ out.operands.push({ text, range, symbolScopeId: frame.scopeId });
359
+ out.literals.push({
360
+ raw: text,
361
+ literalKind: profile.containerLiteralKind(nodeType),
362
+ range,
363
+ symbolScopeId: frame.scopeId,
364
+ });
365
+ } else if (!cursor.gotoFirstChild()) {
366
+ // Der Cursor kennt kein `childCount`: der fehlgeschlagene Abstieg IST
367
+ // die Blattpruefung, und er hat die Position nicht veraendert.
368
+ classifyAndRecordLeaf(cursor, nodeType, parentType, range, frame, profile, out);
369
+ } else {
370
+ cursor.gotoParent(); // zurueck auf den inneren Knoten selbst
371
+ const childFrame = visitInnerNode(cursor, nodeType, range, frame, profile, ctx, fileId, out);
372
+ cursor.gotoFirstChild();
373
+ depth += 1;
374
+ frameAt[depth] = childFrame ?? frame;
375
+ parentTypeAt[depth] = nodeType;
376
+ descended = true;
377
+ }
378
+
379
+ if (descended) continue;
380
+
381
+ // Aufsteigen, bis ein Geschwisterknoten da ist. Tiefe 1 ohne Geschwister
382
+ // heisst: die Kinder der Wurzel sind abgearbeitet.
383
+ while (!cursor.gotoNextSibling()) {
384
+ if (depth === 1) return;
385
+ cursor.gotoParent();
386
+ depth -= 1;
387
+ }
388
+ }
389
+ }
390
+
391
+ /** Runs the single unified walk over a file's root node. */
392
+ export function analyzeTree(
393
+ root: SyntaxNode,
394
+ ctx: FileTextContext,
395
+ fileId: string,
396
+ profile: LanguageProfile,
397
+ ): AnalysisResult {
398
+ const out: MutableFacts = {
399
+ symbolScopes: [],
400
+ decisions: [],
401
+ nestingEvents: [],
402
+ operators: [],
403
+ operands: [],
404
+ nodeKinds: [],
405
+ comments: [],
406
+ identifiers: [],
407
+ literals: [],
408
+ imports: [],
409
+ calls: [],
410
+ };
411
+
412
+ // EIN Cursor fuer alles: er beginnt auf der Wurzel, und nur ein von der
413
+ // Wurzel her abgestiegener Cursor meldet Knotentypen verlaesslich (siehe
414
+ // `fingerprint.ts`, Punkt 2). Jede Hilfsfunktion, die ihn bewegt, gibt ihn
415
+ // an der Ausgangsposition zurueck.
416
+ const cursor = root.walk();
417
+
418
+ const fileScopeNode: ScopeNode = {
419
+ scopeId: fileId,
420
+ kind: "file",
421
+ name: "",
422
+ qualifiedName: "",
423
+ range: rangeOf(root, ctx),
424
+ normalizedSignature: "",
425
+ exportedNames: [],
426
+ executable: true,
427
+ astHash: computeAstHash(cursor, profile),
428
+ tokenFingerprint: computeTokenFingerprint(cursor, profile),
429
+ node: root,
430
+ children: [],
431
+ };
432
+ const rootFrame: WorkingFrame = {
433
+ scopeId: fileId,
434
+ qualifiedName: "",
435
+ executable: true,
436
+ scopeNode: fileScopeNode,
437
+ childOrdinalCounters: new Map(),
438
+ };
439
+ out.symbolScopes.push(toSymbolScopeFact(rootFrame, undefined));
440
+
441
+ walkWithCursor(cursor, root.type, rootFrame, profile, ctx, fileId, out);
442
+
443
+ const facts: ComplexityFacts = {
444
+ symbolScopes: out.symbolScopes,
445
+ decisions: out.decisions,
446
+ nestingEvents: out.nestingEvents,
447
+ operators: out.operators,
448
+ operands: out.operands,
449
+ nodeKinds: out.nodeKinds,
450
+ comments: out.comments,
451
+ identifiers: out.identifiers,
452
+ literals: out.literals,
453
+ // Leer AN DIESER STELLE mit Absicht: die Parse-Diagnosen entstehen in
454
+ // `parse()` und werden in `create-adapter.ts#getAnalysis` eingesetzt,
455
+ // bevor die Facts den Adapter verlassen. Wer diese Zeile als "sowieso
456
+ // immer leer" liest, hat den falschen Ausschnitt vor sich.
457
+ parseDiagnostics: [],
458
+ };
459
+
460
+ return { scopeTree: fileScopeNode, facts, imports: out.imports, calls: out.calls };
461
+ }
@@ -0,0 +1,35 @@
1
+ import type { ExtractedSymbol } from "@untangle-code/domain";
2
+
3
+ import type { ScopeNode } from "./scope-model.js";
4
+
5
+ function toExtractedSymbol(scope: ScopeNode): ExtractedSymbol {
6
+ return {
7
+ name: scope.name,
8
+ qualifiedName: scope.qualifiedName,
9
+ kind: scope.kind,
10
+ ...(scope.signature !== undefined ? { signature: scope.signature } : {}),
11
+ normalizedSignature: scope.normalizedSignature,
12
+ range: scope.range,
13
+ ...(scope.docRange !== undefined ? { docRange: scope.docRange } : {}),
14
+ ...(scope.parentQualifiedName !== undefined
15
+ ? { parentQualifiedName: scope.parentQualifiedName }
16
+ : {}),
17
+ exportedNames: scope.exportedNames,
18
+ ...(scope.visibility !== undefined ? { visibility: scope.visibility } : {}),
19
+ astHash: scope.astHash,
20
+ tokenFingerprint: scope.tokenFingerprint,
21
+ };
22
+ }
23
+
24
+ /** Flattens the scope tree (excluding the synthetic file-level root) into `ExtractedSymbol[]`, document order. */
25
+ export function extractedSymbolsOf(fileScope: ScopeNode): ExtractedSymbol[] {
26
+ const symbols: ExtractedSymbol[] = [];
27
+ const visit = (scope: ScopeNode): void => {
28
+ for (const child of scope.children) {
29
+ symbols.push(toExtractedSymbol(child));
30
+ visit(child);
31
+ }
32
+ };
33
+ visit(fileScope);
34
+ return symbols;
35
+ }