@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,184 @@
1
+ /**
2
+ * Das SPRACHPROFIL: alles, was der vereinheitlichte Walk (`engine.ts`) ueber
3
+ * eine konkrete Sprache wissen muss — als Tabelle plus eine Handvoll Haken,
4
+ * nicht als verdrahtete Zeichenketten im Motor.
5
+ *
6
+ * WARUM (WP-220): bis Welle 6 stand die JS/TS-Familie fest im Motor. `engine.ts`
7
+ * nannte 48 verschiedene Knotenarten woertlich, `fingerprint.ts` kannte
8
+ * `"comment"` als Konstante, `chunks.ts` kannte `export_statement`. Solange es
9
+ * genau ein Backend und genau eine Sprachfamilie gab, war das billig und
10
+ * ehrlich. Mit dem zweiten Backend (`languages/astgrep-backend/`) waere daraus ein
11
+ * ZWEITER Motor neben dem ersten geworden — und damit das Gegenteil der These
12
+ * aus vision.md §1b, die wir belegen wollen: gleiche Leistung mit WENIGER
13
+ * Komplexitaet. Deshalb erst die Verallgemeinerung, dann das Backend.
14
+ *
15
+ * ZWEI ARTEN, EIN PROFIL ZU BAUEN:
16
+ *
17
+ * 1. `js-family-profile.ts` — die handgeschriebene Fassung fuer
18
+ * TypeScript/JavaScript/TSX/JSX. Sie reicht die vorhandenen Detektoren
19
+ * (`decisions.ts`, `import-detection.ts`, `call-detection.ts`,
20
+ * `scope-naming.ts`, `scope-signature.ts`, `doc-binding.ts`) unveraendert
21
+ * durch. Ihr Verhalten ist Zeile fuer Zeile das von vorher; die
22
+ * Golden-Tests dieses Pakets sind der Beleg.
23
+ *
24
+ * 2. `table-profile.ts` — die tabellengetriebene Fassung fuer jede weitere
25
+ * Sprache. Sie kennt keine Sprache, nur Rollen: welche Knotenart ist ein
26
+ * Kommentar, welche oeffnet einen Scope, welche traegt eine Entscheidung.
27
+ * Eine neue Sprache kostet damit eine Tabelle, keinen Motor.
28
+ *
29
+ * WAS HIER NICHT HINEINGEHOERT: alles Backendspezifische. Ein Profil sagt,
30
+ * WAS eine Knotenart bedeutet, nie, WIE der Baum entsteht. Das Backend steht
31
+ * in `create-adapter.ts` (tree-sitter) bzw. `languages/astgrep-backend/create-adapter.ts`.
32
+ */
33
+ import type {
34
+ LiteralFact,
35
+ RawCall,
36
+ RawImport,
37
+ SourceRange,
38
+ SupportLevel,
39
+ } from "@untangle-code/domain";
40
+
41
+ import type { DecisionDetectionResult } from "./decisions.js";
42
+ import type { FileTextContext } from "./node-utils.js";
43
+ import type { ScopeNode } from "./scope-model.js";
44
+ import type { SyntaxNode } from "./syntax.js";
45
+
46
+ /** Die Fakten, die ein Knoten ausserhalb von Entscheidungen beitragen kann. */
47
+ export interface ModuleFactSink {
48
+ imports: RawImport[];
49
+ calls: RawCall[];
50
+ }
51
+
52
+ /** Roh- und Normalform der Kopfzeile eines Symbols (siehe `signature.ts`). */
53
+ export interface ScopeSignature {
54
+ raw?: string;
55
+ normalized: string;
56
+ }
57
+
58
+ /**
59
+ * Ein Sprachprofil. Jede Eigenschaft wird vom Walk GENAU EINMAL je Knoten
60
+ * gelesen; die Mengen sind deshalb `Set`s und keine Arrays.
61
+ */
62
+ export interface LanguageProfile {
63
+ readonly languageId: string;
64
+ readonly extensions: readonly string[];
65
+ readonly supportLevel: SupportLevel;
66
+
67
+ // -- Knotenrollen ---------------------------------------------------------
68
+
69
+ /** Kommentarknoten: nie Operator, nie Operand, nie Teil eines Fingerabdrucks. */
70
+ readonly commentKinds: ReadonlySet<string>;
71
+ /**
72
+ * Knoten, deren ganzer Teilbaum als EIN Operand/Literal zaehlt (der Walk
73
+ * steigt nicht hinein). In der JS/TS-Familie `string` und `regex`.
74
+ */
75
+ readonly literalContainerKinds: ReadonlySet<string>;
76
+ /** Blattknoten, die ein Bezeichnervorkommen sind. */
77
+ readonly identifierLeafKinds: ReadonlySet<string>;
78
+ /** Blattknoten, die ein einfaches Literal sind. */
79
+ readonly simpleLiteralLeafKinds: ReadonlySet<string>;
80
+ /** Statische Textteile in einer Zeichenkettenschablone. */
81
+ readonly templateTextLeafKinds: ReadonlySet<string>;
82
+ /** Satzzeichenblaetter, die weder Operator noch Operand sind. */
83
+ readonly ignoredPunctuationKinds: ReadonlySet<string>;
84
+ /**
85
+ * Elternknotenarten, deren Blaetter reine Typsyntax sind (TS
86
+ * `predefined_type`): gezaehlt in `nodeKinds`, aber nie als Token.
87
+ */
88
+ readonly typeKeywordParentKinds: ReadonlySet<string>;
89
+ /** Funktionsartige Knoten — sie erzeugen zusaetzlich ein Lambda-Nesting. */
90
+ readonly functionLikeKinds: ReadonlySet<string>;
91
+
92
+ /** Literalart eines Container-Literals (`literalContainerKinds`). */
93
+ containerLiteralKind(kind: string): LiteralFact["literalKind"];
94
+ /** Literalart eines einfachen Literalblatts (`simpleLiteralLeafKinds`). */
95
+ simpleLiteralKind(kind: string): LiteralFact["literalKind"];
96
+ /** Deklaration oder Verweis? `fieldName` ist der Feldname im Elternknoten. */
97
+ identifierRole(fieldName: string | undefined, parentKind: string): "declaration" | "reference";
98
+
99
+ // -- Vorsieb --------------------------------------------------------------
100
+
101
+ /**
102
+ * Braucht ein innerer Knoten dieser Art ueberhaupt einen Knotenwrapper?
103
+ *
104
+ * Das ist das Vorsieb aus WP-95: fuer die grosse Mehrheit der inneren Knoten
105
+ * (Ausdruecke, Bloecke, Anweisungslisten) faellt die Grenzueberquerung
106
+ * vollstaendig weg. Wer hier `true` zurueckgibt, bezahlt je Knoten — beim
107
+ * ast-grep-Backend deutlich mehr als bei tree-sitter.
108
+ */
109
+ needsNode(kind: string): boolean;
110
+
111
+ // -- Scopes ---------------------------------------------------------------
112
+
113
+ /** Welche Art von Scope oeffnet dieser Knoten — oder keinen (`null`)? */
114
+ scopeKindOf(node: SyntaxNode): ScopeNode["kind"] | null;
115
+ /**
116
+ * Unterdrueckt einen sonst geoeffneten Scope (JS: ein Feld, dessen Wert
117
+ * selbst eine Funktion ist — die Funktion bekommt den Scope, nicht das Feld).
118
+ */
119
+ suppressesScope(node: SyntaxNode): boolean;
120
+ scopeName(node: SyntaxNode): string;
121
+ /**
122
+ * Ein Namensteil, der VOR den Scope-Namen gehoert, aber nicht aus einem
123
+ * Elternscope stammt (WP-237).
124
+ *
125
+ * Gos Methoden haengen nicht in ihrem Typ, sondern tragen ihn als Feld:
126
+ * `func (a *A) Run()` ist ein Geschwister von `type A struct{}`, kein Kind.
127
+ * Ohne diesen Zusatz heissen `(*A).Run` und `(*B).Run` beide `Run`, und der
128
+ * Symbolgraph haelt zwei verschiedene Methoden fuer dieselbe — eine
129
+ * Impact-Analyse auf einer Go-Codebasis waere damit schlicht falsch.
130
+ *
131
+ * Rueckgabe `undefined` heisst: dieser Knoten braucht keinen Zusatz.
132
+ */
133
+ scopeQualifier?(node: SyntaxNode): string | undefined;
134
+ scopeSignature(node: SyntaxNode, kind: ScopeNode["kind"], name: string): ScopeSignature;
135
+ docRange(node: SyntaxNode, ctx: FileTextContext): SourceRange | undefined;
136
+ visibility(node: SyntaxNode, name: string): string | undefined;
137
+ exportedNames(node: SyntaxNode, name: string): string[];
138
+
139
+ // -- Fakten ---------------------------------------------------------------
140
+
141
+ detectDecisionAndNesting(node: SyntaxNode): DecisionDetectionResult;
142
+ /**
143
+ * Importe und Aufrufe dieses Knotens. Schreibt DIREKT in `sink`, statt ein
144
+ * Ergebnisobjekt zu bauen: der Haken laeuft im Walk, und ein Objekt je
145
+ * Aufrufknoten waere reiner Muell fuer den Sammler.
146
+ */
147
+ collectModuleFacts(
148
+ node: SyntaxNode,
149
+ kind: string,
150
+ callerScopeId: string,
151
+ ctx: FileTextContext,
152
+ sink: ModuleFactSink,
153
+ ): void;
154
+
155
+ // -- Regionen (`chunks.ts`) -----------------------------------------------
156
+
157
+ /**
158
+ * Huellknoten, deren Bytes zum Symbol gehoeren (JS/TS: `export_statement`).
159
+ * Leer, wenn die Sprache keine solche Huelle kennt.
160
+ */
161
+ readonly exportWrapperKinds: ReadonlySet<string>;
162
+ /**
163
+ * Zusaetzliche Kindregionen eines Klassen-artigen Scopes, die selbst keinen
164
+ * Scope oeffnen, aber Inhalt tragen (JS/TS: `static { ... }`). Ohne sie
165
+ * fielen ihre Bytes durch den Mitgliederlauf — spec.md §8.4 verbietet das.
166
+ */
167
+ memberRegions(node: SyntaxNode, parentScopeId: string, ctx: FileTextContext): MemberRegion[];
168
+ }
169
+
170
+ /** Eine Region ohne Symbol, wie sie `memberRegions` liefert. */
171
+ export interface MemberRegion {
172
+ range: SourceRange;
173
+ scopeId: string;
174
+ headerText: string;
175
+ }
176
+
177
+ /**
178
+ * Ausfuehrungseinheiten (spec.md §16.1) — bei jeder Sprache dieselben drei
179
+ * Arten. Der Dateirahmen ist gesondert ausfuehrbar (`engine.ts`); er kommt hier
180
+ * nie an, weil `scopeKindOf` niemals `"file"` liefert.
181
+ */
182
+ export function isExecutableScopeKind(kind: ScopeNode["kind"]): boolean {
183
+ return kind === "function" || kind === "method" || kind === "constructor";
184
+ }
@@ -0,0 +1,43 @@
1
+ import type { SourceRange } from "@untangle-code/domain";
2
+
3
+ import type { SyntaxNode } from "./syntax.js";
4
+
5
+ /**
6
+ * Internal (package-private) representation of one symbol scope, built once
7
+ * per parse by `engine.ts#analyze` and then projected into the public
8
+ * `ExtractedSymbol[]` / `SymbolScopeFact[]` / `AstRegion[]` shapes by
9
+ * `extractSymbols.ts`, `complexity.ts` and `chunks.ts` respectively. Keeping
10
+ * ONE tree as the single source of truth guarantees `scopeId`s line up
11
+ * exactly across `extractSymbols`, `computeComplexity` and `extractCalls`,
12
+ * since all three are projections of the same walk.
13
+ */
14
+ export interface ScopeNode {
15
+ scopeId: string;
16
+ /** Adapter-internal kind: superset of ExtractedSymbol.kind plus "file". */
17
+ kind:
18
+ | "file"
19
+ | "function"
20
+ | "method"
21
+ | "constructor"
22
+ | "class"
23
+ | "interface"
24
+ | "type"
25
+ | "enum"
26
+ | "namespace"
27
+ | "property";
28
+ name: string;
29
+ qualifiedName: string;
30
+ parentQualifiedName?: string;
31
+ range: SourceRange;
32
+ docRange?: SourceRange;
33
+ signature?: string;
34
+ normalizedSignature: string;
35
+ exportedNames: string[];
36
+ visibility?: string;
37
+ executable: boolean;
38
+ astHash: string;
39
+ tokenFingerprint: string;
40
+ /** The tree-sitter node whose range/body IS this scope (used only within this package). */
41
+ node: SyntaxNode;
42
+ children: ScopeNode[];
43
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Name/signature/visibility derivation for one scope-opening node.
3
+ *
4
+ * A scope-opening node (function/method/class/interface/type/enum/property,
5
+ * see `node-kinds.ts#SCOPE_OPENING_TYPES`) is either self-naming (its own
6
+ * `name` field) or anonymous, in which case the name is borrowed from the
7
+ * enclosing syntactic context — `const x = () => {}`, `{ key: () => {} }`,
8
+ * `x.y = function () {}`, `export default function () {}`, or a class field
9
+ * initialized with an arrow function (spec.md §8.3 step 3: "Top-Level-Symbole
10
+ * bestimmen").
11
+ */
12
+ import { CLASS_TYPES, FIELD_TYPES, FUNCTION_LIKE_TYPES, METHOD_TYPE } from "./node-kinds.js";
13
+ import { unquote } from "./node-utils.js";
14
+ import type { SyntaxNode } from "./syntax.js";
15
+
16
+ const ANONYMOUS_NAME = "<anonymous>";
17
+
18
+ /** Derives the declared or contextually-borrowed name of a scope-opening node. */
19
+ export function resolveScopeName(node: SyntaxNode): string {
20
+ const ownName = node.childForFieldName("name");
21
+ if (ownName !== null) {
22
+ return ownName.type === "computed_property_name" ? ownName.text : unquote(ownName.text);
23
+ }
24
+
25
+ if (FIELD_TYPES.has(node.type)) {
26
+ const property = node.childForFieldName("property");
27
+ if (property !== null) return unquote(property.text);
28
+ }
29
+
30
+ if (
31
+ FUNCTION_LIKE_TYPES.has(node.type) ||
32
+ node.type === METHOD_TYPE ||
33
+ CLASS_TYPES.has(node.type)
34
+ ) {
35
+ const parent = node.parent;
36
+ if (parent === null) return ANONYMOUS_NAME;
37
+
38
+ switch (parent.type) {
39
+ case "variable_declarator": {
40
+ const declaratorName = parent.childForFieldName("name");
41
+ return declaratorName !== null && declaratorName.type === "identifier"
42
+ ? declaratorName.text
43
+ : ANONYMOUS_NAME;
44
+ }
45
+ case "pair":
46
+ case "pair_pattern": {
47
+ const key = parent.childForFieldName("key");
48
+ return key !== null ? unquote(key.text) : ANONYMOUS_NAME;
49
+ }
50
+ case "assignment_expression": {
51
+ const left = parent.childForFieldName("left");
52
+ if (left === null) return ANONYMOUS_NAME;
53
+ if (left.type === "identifier") return left.text;
54
+ if (left.type === "member_expression") {
55
+ const property = left.childForFieldName("property");
56
+ return property !== null ? property.text : ANONYMOUS_NAME;
57
+ }
58
+ return ANONYMOUS_NAME;
59
+ }
60
+ case "field_definition":
61
+ case "public_field_definition": {
62
+ const property = parent.childForFieldName("property");
63
+ return property !== null ? unquote(property.text) : ANONYMOUS_NAME;
64
+ }
65
+ case "export_statement":
66
+ return "default";
67
+ default:
68
+ return ANONYMOUS_NAME;
69
+ }
70
+ }
71
+
72
+ return ANONYMOUS_NAME;
73
+ }
74
+
75
+ /**
76
+ * True when a field's initializer is itself a function-like node: in that
77
+ * case the FIELD does not get its own scope — the function value does,
78
+ * borrowing the field's property name (avoids a redundant doubled
79
+ * `Class.field.field` qualified name for `class C { handler = () => {} }`).
80
+ */
81
+ export function fieldDelegatesToFunctionValue(node: SyntaxNode): boolean {
82
+ if (!FIELD_TYPES.has(node.type)) return false;
83
+ const value = node.childForFieldName("value");
84
+ return value !== null && (FUNCTION_LIKE_TYPES.has(value.type) || value.type === "class");
85
+ }
86
+
87
+ const VISIBILITY_MODIFIER_TYPE = "accessibility_modifier";
88
+
89
+ /** `public`/`private`/`protected` if explicit, `"private"` for a `#name`, else `undefined` (implicit public). */
90
+ export function resolveVisibility(node: SyntaxNode, name: string): string | undefined {
91
+ const modifier = node.children.find((child) => child.type === VISIBILITY_MODIFIER_TYPE);
92
+ if (modifier !== undefined) return modifier.text;
93
+ if (name.startsWith("#")) return "private";
94
+ return undefined;
95
+ }
96
+
97
+ /**
98
+ * Names this declaration exports, per spec.md §8.3 step 2/§14 (best-effort:
99
+ * only direct `export` / `export default` wrapping the declaration itself is
100
+ * recognized — a later `export { name }` clause elsewhere in the file is a
101
+ * documented simplification, see README "Entscheidungen").
102
+ */
103
+ export function resolveExportedNames(node: SyntaxNode, name: string): string[] {
104
+ let current: SyntaxNode | null = node;
105
+ // Walk up through wrapping declarator/declaration nodes that carry no name of their own.
106
+ while (current !== null) {
107
+ const parent: SyntaxNode | null = current.parent;
108
+ if (parent === null) return [];
109
+ if (parent.type === "export_statement") {
110
+ const hasDefault = parent.children.some((child) => child.type === "default");
111
+ return [hasDefault ? "default" : name];
112
+ }
113
+ if (
114
+ parent.type === "variable_declarator" ||
115
+ parent.type === "lexical_declaration" ||
116
+ parent.type === "variable_declaration"
117
+ ) {
118
+ current = parent;
119
+ continue;
120
+ }
121
+ return [];
122
+ }
123
+ return [];
124
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Signature text composition per scope kind (see `signature.ts` for the
3
+ * normalization primitives this builds on, and its doc comment for the
4
+ * normative whitespace/defaults/optional-marker/type-annotation rules).
5
+ */
6
+ import { FUNCTION_LIKE_TYPES, METHOD_TYPE } from "./node-kinds.js";
7
+ import {
8
+ normalizeHeaderText,
9
+ normalizeParameterList,
10
+ normalizeReturnType,
11
+ normalizeTypeParameterList,
12
+ } from "./signature.js";
13
+ import type { SyntaxNode } from "./syntax.js";
14
+
15
+ const MODIFIER_ORDER = [
16
+ "accessibility_modifier",
17
+ "static",
18
+ "abstract",
19
+ "override_modifier",
20
+ "readonly",
21
+ "declare",
22
+ "async",
23
+ ] as const;
24
+
25
+ function collectModifiers(node: SyntaxNode): string[] {
26
+ const found: string[] = [];
27
+ for (const modifierType of MODIFIER_ORDER) {
28
+ const child = node.children.find((c) => c.type === modifierType);
29
+ if (child !== undefined) found.push(child.text);
30
+ }
31
+ return found;
32
+ }
33
+
34
+ function isGenerator(node: SyntaxNode): boolean {
35
+ return node.children.some((child) => child.type === "*");
36
+ }
37
+
38
+ function accessorKeyword(node: SyntaxNode): "get" | "set" | undefined {
39
+ const hasGet = node.children.some((child) => child.type === "get");
40
+ const hasSet = node.children.some((child) => child.type === "set");
41
+ return hasGet ? "get" : hasSet ? "set" : undefined;
42
+ }
43
+
44
+ interface FunctionSignature {
45
+ raw: string;
46
+ normalized: string;
47
+ }
48
+
49
+ /** Builds the signature for a function/arrow/method-shaped scope node. */
50
+ export function buildFunctionSignature(node: SyntaxNode, name: string): FunctionSignature {
51
+ const typeParamsNode = node.childForFieldName("type_parameters");
52
+ const parametersNode = node.childForFieldName("parameters");
53
+ const returnTypeNode = node.childForFieldName("return_type");
54
+
55
+ const modifiers = collectModifiers(node);
56
+ const accessor = accessorKeyword(node);
57
+ const generatorMarker = isGenerator(node) ? "*" : "";
58
+
59
+ const headParts = [...modifiers];
60
+ if (accessor !== undefined) headParts.push(accessor);
61
+ const head =
62
+ headParts.length > 0
63
+ ? `${headParts.join(" ")} ${generatorMarker}${name}`
64
+ : `${generatorMarker}${name}`;
65
+
66
+ const rawTypeParams = typeParamsNode?.text;
67
+ const rawParams =
68
+ parametersNode?.text ??
69
+ (node.childForFieldName("parameter")?.text !== undefined
70
+ ? `(${node.childForFieldName("parameter")?.text})`
71
+ : "()");
72
+ const rawReturnType = returnTypeNode?.text;
73
+
74
+ const raw = `${head}${rawTypeParams ?? ""}${rawParams}${rawReturnType !== undefined ? rawReturnType : ""}`;
75
+
76
+ const normalizedTypeParams = normalizeTypeParameterList(rawTypeParams);
77
+ const normalizedParams = normalizeParameterList(rawParams);
78
+ const normalizedReturnType = normalizeReturnType(rawReturnType);
79
+ const normalized = `${head}${normalizedTypeParams}${normalizedParams}${normalizedReturnType}`;
80
+
81
+ return { raw, normalized };
82
+ }
83
+
84
+ /** Builds the signature for a class/interface/enum/type-alias/namespace scope node. */
85
+ export function buildHeaderSignature(node: SyntaxNode): FunctionSignature {
86
+ const bodyNode = node.childForFieldName("body");
87
+ const raw =
88
+ bodyNode !== null
89
+ ? node.text.slice(0, bodyNode.startIndex - node.startIndex).trimEnd()
90
+ : node.text.replace(/;\s*$/, "");
91
+ return { raw, normalized: normalizeHeaderText(raw) };
92
+ }
93
+
94
+ /** Builds the signature for a class field / property scope node. */
95
+ export function buildPropertySignature(node: SyntaxNode, name: string): FunctionSignature {
96
+ const typeNode = node.childForFieldName("type");
97
+ const modifiers = collectModifiers(node);
98
+ const head = modifiers.length > 0 ? `${modifiers.join(" ")} ${name}` : name;
99
+ const rawType = typeNode?.text;
100
+ const raw = `${head}${rawType ?? ""}`;
101
+ const normalized =
102
+ rawType !== undefined ? `${head}${normalizeReturnType(rawType)}` : normalizeHeaderText(head);
103
+ return { raw, normalized };
104
+ }
105
+
106
+ export function isFunctionLikeScope(nodeType: string): boolean {
107
+ return FUNCTION_LIKE_TYPES.has(nodeType) || nodeType === METHOD_TYPE;
108
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Signature text normalization for the JS/TS grammar family.
3
+ *
4
+ * Normative requirement (WP-06 task, spec.md §5.5): `normalizedSignature`
5
+ * feeds `buildSymbolId`, so it MUST be stable across:
6
+ *
7
+ * 1. Whitespace — any run of spaces/tabs/newlines collapses to a single
8
+ * space; spacing around `,`, `:`, `(`, `)`, `<`, `>`, `?:` is
9
+ * canonicalized rather than preserved verbatim.
10
+ * 2. Default values — `= <expr>` parameter/type-parameter initializers are
11
+ * STRIPPED. Rationale: giving a parameter a default value is (mostly) a
12
+ * call-site convenience, not a new overload; keeping it in the identity
13
+ * signature would needlessly change a symbol's id on a body-only-feeling
14
+ * edit. The optional marker (see next point) already captures "callers
15
+ * may omit this argument".
16
+ * 3. Optional markers — TypeScript's trailing `?` on a parameter name is
17
+ * KEPT and canonicalized to sit directly against the following `:`
18
+ * (`a ?:string` and `a?: string` both become `a?: string`) because it
19
+ * changes the call contract independent of any default value.
20
+ * 4. Type annotations — kept verbatim (modulo the same whitespace rules)
21
+ * because they are part of the observable contract.
22
+ *
23
+ * Known limitation (documented, not a defect): default-value stripping and
24
+ * top-level-comma splitting use a bracket-DEPTH scanner, not a full
25
+ * expression parser. A `<` used as a less-than operator inside a default
26
+ * expression (e.g. `(a = b < c ? 1 : 2)`) is misread as a generic open
27
+ * bracket and can throw off depth tracking for the rest of that one
28
+ * parameter. This is vanishingly rare in default-value position and is
29
+ * accepted as a WP-06 scoping decision (see README "Entscheidungen").
30
+ */
31
+
32
+ const OPEN_BRACKETS = new Set(["(", "[", "{", "<"]);
33
+ const CLOSE_BRACKETS = new Set([")", "]", "}", ">"]);
34
+
35
+ /** Collapses whitespace and canonicalizes spacing around common punctuation. */
36
+ export function normalizeSpacing(text: string): string {
37
+ return text
38
+ .replace(/\s+/g, " ")
39
+ .replace(/\s*\?\s*:/g, "?:")
40
+ .replace(/\s*:\s*/g, ": ")
41
+ .replace(/\s*,\s*/g, ", ")
42
+ .replace(/\(\s+/g, "(")
43
+ .replace(/\s+\)/g, ")")
44
+ .replace(/<\s+/g, "<")
45
+ .replace(/\s+>/g, ">")
46
+ .replace(/\.\.\.\s+/g, "...")
47
+ .replace(/\s{2,}/g, " ")
48
+ .trim();
49
+ }
50
+
51
+ /**
52
+ * Splits `content` on top-level occurrences of `separator` (depth 0 with
53
+ * respect to `(`, `[`, `{`, `<`/`>`). Used to split parameter lists and
54
+ * type-parameter lists without being confused by nested generics/objects.
55
+ */
56
+ export function splitTopLevel(content: string, separator: string): string[] {
57
+ const parts: string[] = [];
58
+ let depth = 0;
59
+ let current = "";
60
+ for (const ch of content) {
61
+ if (OPEN_BRACKETS.has(ch)) depth += 1;
62
+ else if (CLOSE_BRACKETS.has(ch)) depth = Math.max(0, depth - 1);
63
+ if (ch === separator && depth === 0) {
64
+ parts.push(current);
65
+ current = "";
66
+ } else {
67
+ current += ch;
68
+ }
69
+ }
70
+ parts.push(current);
71
+ return parts;
72
+ }
73
+
74
+ /**
75
+ * Index of the top-level `=` that introduces a default value, or -1.
76
+ * Excludes `=>`, `==`, `===`, `!=`, `!==`, `<=`, `>=`.
77
+ */
78
+ function findTopLevelDefaultEquals(text: string): number {
79
+ let depth = 0;
80
+ for (let i = 0; i < text.length; i += 1) {
81
+ const ch = text[i] as string;
82
+ if (OPEN_BRACKETS.has(ch)) {
83
+ depth += 1;
84
+ continue;
85
+ }
86
+ if (CLOSE_BRACKETS.has(ch)) {
87
+ depth = Math.max(0, depth - 1);
88
+ continue;
89
+ }
90
+ if (ch === "=" && depth === 0) {
91
+ const prev = i > 0 ? text[i - 1] : "";
92
+ const next = i + 1 < text.length ? text[i + 1] : "";
93
+ const isCompoundOperator =
94
+ next === "=" || next === ">" || prev === "!" || prev === "<" || prev === ">";
95
+ if (!isCompoundOperator) return i;
96
+ }
97
+ }
98
+ return -1;
99
+ }
100
+
101
+ /** Strips a single parameter's/type-parameter's default value (`= <expr>`), keeping any `?`/type annotation before it. */
102
+ export function stripDefaultValue(entry: string): string {
103
+ const eqIndex = findTopLevelDefaultEquals(entry);
104
+ return eqIndex === -1 ? entry : entry.slice(0, eqIndex).trimEnd();
105
+ }
106
+
107
+ /**
108
+ * Normalizes a formal-parameter-list text (including its outer parens),
109
+ * e.g. `(a: number = 1, b ?: string)` -> `(a: number, b?: string)`.
110
+ */
111
+ export function normalizeParameterList(paramsText: string): string {
112
+ const trimmed = paramsText.trim();
113
+ const hasParens = trimmed.startsWith("(") && trimmed.endsWith(")");
114
+ const inner = hasParens ? trimmed.slice(1, -1) : trimmed;
115
+ const entries = splitTopLevel(inner, ",")
116
+ .map((entry) => entry.trim())
117
+ .filter((entry) => entry.length > 0);
118
+ const normalizedEntries = entries.map((entry) => normalizeSpacing(stripDefaultValue(entry)));
119
+ return `(${normalizedEntries.join(", ")})`;
120
+ }
121
+
122
+ /**
123
+ * Normalizes a type-parameter list text (including its outer `<>`), e.g.
124
+ * `<T extends object = {}, U>` -> `<T extends object, U>`.
125
+ */
126
+ export function normalizeTypeParameterList(typeParamsText: string | undefined): string {
127
+ if (typeParamsText === undefined || typeParamsText.trim().length === 0) return "";
128
+ const trimmed = typeParamsText.trim();
129
+ const hasBrackets = trimmed.startsWith("<") && trimmed.endsWith(">");
130
+ const inner = hasBrackets ? trimmed.slice(1, -1) : trimmed;
131
+ const entries = splitTopLevel(inner, ",")
132
+ .map((entry) => entry.trim())
133
+ .filter((entry) => entry.length > 0);
134
+ if (entries.length === 0) return "";
135
+ const normalizedEntries = entries.map((entry) => normalizeSpacing(stripDefaultValue(entry)));
136
+ return `<${normalizedEntries.join(", ")}>`;
137
+ }
138
+
139
+ /** Normalizes a return-type annotation text (e.g. ` : Promise<void> ` -> `: Promise<void>`). */
140
+ export function normalizeReturnType(returnTypeText: string | undefined): string {
141
+ if (returnTypeText === undefined || returnTypeText.trim().length === 0) return "";
142
+ const normalized = normalizeSpacing(returnTypeText);
143
+ return normalized.startsWith(":") ? normalized : `: ${normalized}`;
144
+ }
145
+
146
+ /** Normalizes an arbitrary header text (class/interface/type/enum declarations). */
147
+ export function normalizeHeaderText(headerText: string): string {
148
+ return normalizeSpacing(headerText.replace(/;\s*$/, ""));
149
+ }