@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,341 @@
1
+ /**
2
+ * Die Python-Regeln, die KEINE Tabelle ausdrueckt.
3
+ *
4
+ * Alles Uebrige — Entscheidungen, Nesting, Kommentare, Halstead-Token,
5
+ * Aufrufe, Scopes — kommt aus `table.ts` durch den gemeinsamen Motor
6
+ * (`shared/table-profile.ts`, `shared/engine.ts`). Hier steht nur, was
7
+ * Python anders macht als jede andere Sprache dieses Projekts:
8
+ *
9
+ * 1. DOCSTRINGS. Python bindet die Beschreibung nicht an einen Kommentar VOR
10
+ * der Definition, sondern an die erste Anweisung IM Rumpf.
11
+ * 2. SICHTBARKEIT. Es gibt keinen Modifikator; sie steht in der
12
+ * Namenskonvention (`_x` geschuetzt, `__x` privat, `__x__` oeffentlich).
13
+ * 3. `__all__`. Was eine Datei exportiert, steht in einer Zuweisung auf
14
+ * Modulebene — also je DATEI, nicht je Knoten. Deshalb wird dieses Profil
15
+ * je Parse gebaut (`AstGrepAdapterHooks.profileForFile`) und nicht einmal
16
+ * je Adapter.
17
+ * 4. METHODE ODER FUNKTION. `def` ist beides; welches, sagt erst der
18
+ * umgebende Knoten. Eine Tabelle bildet Knotenart auf Scope-Art ab und
19
+ * kann das nicht.
20
+ * 5. IMPORTE. Eine Anweisung fuehrt mehrere Ziele mit je eigenem Alias
21
+ * (`from a import b as c, d`) — `ImportRules` kennt genau eines.
22
+ * 6. SIGNATUREN. Die Normalform folgt `signature.ts` (Vorgabewerte fallen
23
+ * weg, Annotationen bleiben) und nicht der Rohtextregel der Tabelle.
24
+ * 7. ZEICHENKETTEN. Ein `string` ist hier KEIN geschlossener Container
25
+ * (siehe `table.ts`); seine Textblaetter muessen deshalb ausdruecklich
26
+ * als Zeichenkettenliterale gelten.
27
+ */
28
+ import type { LiteralFact, RawImport, SourceFile, SourceRange } from "@untangle-code/domain";
29
+
30
+ import type { DecisionDetectionResult } from "../shared/decisions.js";
31
+ import type { FileTextContext } from "../shared/node-utils.js";
32
+ import { rangeOf } from "../shared/node-utils.js";
33
+ import type { LanguageProfile, ModuleFactSink, ScopeSignature } from "../shared/profile.js";
34
+ import type { ScopeNode } from "../shared/scope-model.js";
35
+ import type { SyntaxNode } from "../shared/syntax.js";
36
+
37
+ import { normalizeHeaderText, normalizeParameterList, normalizeReturnType } from "./signature.js";
38
+ import { PYTHON_STRING_LEAF_KINDS } from "./table.js";
39
+
40
+ const INIT_FILE_RE = /(^|\/)__init__\.pyi?$/;
41
+ const STRING_LEAF_KINDS: ReadonlySet<string> = new Set(PYTHON_STRING_LEAF_KINDS);
42
+
43
+ /** Knotenarten, die einen eigenen Namensraum aufmachen — die Grenze fuer "steht in einer Klasse". */
44
+ const SCOPE_OPENING_KINDS: ReadonlySet<string> = new Set([
45
+ "function_definition",
46
+ "class_definition",
47
+ "lambda",
48
+ ]);
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // 2. Sichtbarkeit aus der Namenskonvention (PEP 8)
52
+ // ---------------------------------------------------------------------------
53
+
54
+ /**
55
+ * `__x__` ist das oeffentliche Protokoll (`__init__`, `__len__`) und bekommt
56
+ * deshalb GAR KEINE Angabe — nicht "public": das Feld ist optional, und
57
+ * "keine Angabe" ist die ehrliche Aussage ueber eine Sprache ohne
58
+ * Sichtbarkeitsmodifikatoren.
59
+ */
60
+ function pythonVisibility(name: string): string | undefined {
61
+ if (name.startsWith("__") && name.endsWith("__") && name.length > 4) return undefined;
62
+ if (name.startsWith("__")) return "private";
63
+ if (name.startsWith("_")) return "protected";
64
+ return undefined;
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // 1. Docstrings
69
+ // ---------------------------------------------------------------------------
70
+
71
+ /** Der Text eines Zeichenkettenknotens ohne Anfuehrungszeichen (auch dreifache). */
72
+ function stringLiteralText(node: SyntaxNode): string | null {
73
+ if (node.type !== "string") return null;
74
+ for (const child of node.children) {
75
+ if (child.type === "string_content") return child.text;
76
+ }
77
+ return "";
78
+ }
79
+
80
+ /**
81
+ * Der Docstring eines Scopes: die erste Anweisung des Rumpfes, wenn sie aus
82
+ * nichts als einem Zeichenkettenliteral besteht. Alles andere ist Code, und
83
+ * ein Stueck Code als Beschreibung auszugeben waere eine Erfindung.
84
+ */
85
+ function docstringRange(
86
+ node: SyntaxNode,
87
+ ctx: FileTextContext,
88
+ bodyField: string,
89
+ ): SourceRange | undefined {
90
+ const body = node.childForFieldName(bodyField);
91
+ if (body === null) return undefined;
92
+ const first = body.namedChild(0);
93
+ if (first === null || first.type !== "expression_statement") return undefined;
94
+ const expression = first.namedChild(0);
95
+ if (expression === null || stringLiteralText(expression) === null) return undefined;
96
+ return rangeOf(expression, ctx);
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // 3. `__all__`
101
+ // ---------------------------------------------------------------------------
102
+
103
+ /**
104
+ * Die Namen aus `__all__ = [...]` auf Modulebene, oder `null`, wenn die Datei
105
+ * keines hat. `null` und nicht "leere Menge": ohne `__all__` gilt die
106
+ * Unterstrich-Konvention, mit leerem `__all__` exportiert die Datei nichts.
107
+ * Die beiden Faelle zu vermengen hiesse, jede Datei ohne `__all__` fuer
108
+ * exportlos zu erklaeren.
109
+ */
110
+ function findDunderAll(root: SyntaxNode): ReadonlySet<string> | null {
111
+ for (const statement of root.children) {
112
+ if (statement.type !== "expression_statement") continue;
113
+ const assignment = statement.namedChild(0);
114
+ if (assignment === null || assignment.type !== "assignment") continue;
115
+ const left = assignment.childForFieldName("left");
116
+ if (left === null || left.type !== "identifier" || left.text !== "__all__") continue;
117
+ const right = assignment.childForFieldName("right");
118
+ if (
119
+ right === null ||
120
+ (right.type !== "list" && right.type !== "tuple" && right.type !== "set")
121
+ ) {
122
+ continue;
123
+ }
124
+ const names = new Set<string>();
125
+ for (const element of right.children) {
126
+ const text = stringLiteralText(element);
127
+ if (text !== null) names.add(text);
128
+ }
129
+ return names;
130
+ }
131
+ return null;
132
+ }
133
+
134
+ /** Steht dieser Knoten unmittelbar auf Modulebene (auch unter einem Dekorator)? */
135
+ function isTopLevel(node: SyntaxNode): boolean {
136
+ const parent = node.parent;
137
+ if (parent === null) return false;
138
+ if (parent.type === "module") return true;
139
+ return parent.type === "decorated_definition" && parent.parent?.type === "module";
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------
143
+ // 4. Methode oder Funktion
144
+ // ---------------------------------------------------------------------------
145
+
146
+ /** Der naechste umschliessende Knoten, der selbst einen Namensraum oeffnet. */
147
+ function enclosingScopeKind(node: SyntaxNode): string | null {
148
+ let current = node.parent;
149
+ while (current !== null) {
150
+ if (SCOPE_OPENING_KINDS.has(current.type)) return current.type;
151
+ current = current.parent;
152
+ }
153
+ return null;
154
+ }
155
+
156
+ // ---------------------------------------------------------------------------
157
+ // 5. Importe
158
+ // ---------------------------------------------------------------------------
159
+
160
+ /** Ziel und Alias eines einzelnen Importeintrags (`os.path as osp`, `helper`). */
161
+ function importEntryOf(node: SyntaxNode): { path: string; alias?: string } | null {
162
+ if (node.type === "dotted_name") return { path: node.text };
163
+ if (node.type !== "aliased_import") return null;
164
+ const path = node.childForFieldName("name");
165
+ const alias = node.childForFieldName("alias");
166
+ if (path === null) return null;
167
+ return { path: path.text, ...(alias === null ? {} : { alias: alias.text }) };
168
+ }
169
+
170
+ /**
171
+ * `import a, b as c` — jedes Ziel ist ein eigener Import mit eigenem Pfad.
172
+ * `from m import a, b as c` — EIN Pfad (`m`) mit mehreren gebundenen Namen.
173
+ * Zwei Formen, deshalb zwei Zweige und keine gemeinsame Schleife, die beide
174
+ * halb falsch bedient.
175
+ */
176
+ function collectPythonImports(
177
+ node: SyntaxNode,
178
+ ctx: FileTextContext,
179
+ sink: ModuleFactSink,
180
+ isInitFile: boolean,
181
+ ): void {
182
+ const range = rangeOf(node, ctx);
183
+ // spec.md §6.2: was ein Paketkopf (`__init__.py`) auf oberster Ebene
184
+ // hereinholt, reicht er weiter — das ist ein Re-Export, kein Verbrauch.
185
+ const importKind: RawImport["importKind"] =
186
+ isInitFile && isTopLevel(node) ? "re_export" : "import";
187
+
188
+ if (node.type === "import_statement") {
189
+ for (const child of node.children) {
190
+ const entry = importEntryOf(child);
191
+ if (entry === null) continue;
192
+ sink.imports.push({
193
+ specifier: entry.path,
194
+ importKind,
195
+ range,
196
+ ...(entry.alias === undefined ? {} : { importedNames: [entry.alias] }),
197
+ });
198
+ }
199
+ return;
200
+ }
201
+
202
+ const moduleNode = node.childForFieldName("module_name");
203
+ if (moduleNode === null) return;
204
+ const importedNames: string[] = [];
205
+ // Die gebundenen Namen stehen NACH dem Schluesselwort `import`; davor steht
206
+ // der Modulpfad, der genauso aussieht. Ohne diese Schranke stuende
207
+ // `collections` bei `from collections import x` als importierter Name da.
208
+ let afterKeyword = false;
209
+ for (const child of node.children) {
210
+ if (child.type === "import") {
211
+ afterKeyword = true;
212
+ continue;
213
+ }
214
+ if (!afterKeyword) continue;
215
+ // `from m import *` bindet unbekannt viele Namen. KEINEN zu nennen ist
216
+ // die einzige ehrliche Antwort (domain `analysis.ts`: ein fehlendes Feld
217
+ // heisst "unbekannt").
218
+ const entry = importEntryOf(child);
219
+ if (entry !== null) importedNames.push(entry.alias ?? entry.path);
220
+ }
221
+ sink.imports.push({
222
+ specifier: moduleNode.text,
223
+ importKind,
224
+ range,
225
+ ...(importedNames.length > 0 ? { importedNames } : {}),
226
+ });
227
+ }
228
+
229
+ // ---------------------------------------------------------------------------
230
+ // 6. Signaturen
231
+ // ---------------------------------------------------------------------------
232
+
233
+ function headerBeforeBody(node: SyntaxNode, bodyField: string): string {
234
+ const body = node.childForFieldName(bodyField);
235
+ if (body === null) return node.text.split("\n")[0]?.trim() ?? node.text;
236
+ return node.text.slice(0, Math.max(0, body.startIndex - node.startIndex)).trimEnd();
237
+ }
238
+
239
+ function pythonSignature(node: SyntaxNode, name: string, bodyField: string): ScopeSignature {
240
+ if (node.type === "class_definition") {
241
+ const raw = headerBeforeBody(node, bodyField);
242
+ return { raw, normalized: normalizeHeaderText(raw) };
243
+ }
244
+
245
+ const parameters = node.childForFieldName("parameters");
246
+ // `lambda_parameters` traegt KEINE Klammern; `parameters` traegt sie. Beide
247
+ // muessen als `(...)` in die Normalform, sonst zerfaellt die Aufteilung.
248
+ const parametersText =
249
+ parameters === null
250
+ ? "()"
251
+ : parameters.text.trim().startsWith("(")
252
+ ? parameters.text
253
+ : `(${parameters.text})`;
254
+ const returnType = node.childForFieldName("return_type");
255
+ // `async` ist ein anonymes Kind, kein Feld — und es gehoert zur
256
+ // Aufrufschnittstelle: eine Koroutine ist nicht dasselbe wie eine Funktion.
257
+ const isAsync = node.children.some((child) => child.type === "async");
258
+ const head = `${isAsync ? "async " : ""}${name}`;
259
+ const raw = `${head}${parametersText}${returnType === null ? "" : ` -> ${returnType.text}`}`;
260
+ const normalized = `${head}${normalizeParameterList(parametersText)}${normalizeReturnType(
261
+ returnType?.text,
262
+ )}`;
263
+ return { raw, normalized };
264
+ }
265
+
266
+ // ---------------------------------------------------------------------------
267
+
268
+ /**
269
+ * Baut das Python-Profil ueber dem Tabellenprofil — EINMAL JE DATEI, weil
270
+ * `__all__` und `__init__.py` Dateieigenschaften sind.
271
+ */
272
+ export function createPythonProfile(
273
+ base: LanguageProfile,
274
+ root: SyntaxNode,
275
+ file: SourceFile,
276
+ ): LanguageProfile {
277
+ const dunderAll = findDunderAll(root);
278
+ const isInitFile = INIT_FILE_RE.test(file.path.replace(/\\/g, "/"));
279
+ const bodyField = "body";
280
+
281
+ return {
282
+ ...base,
283
+
284
+ // 7. Zeichenkettenblaetter (siehe `table.ts`: `string` ist kein Container).
285
+ simpleLiteralLeafKinds: new Set([...base.simpleLiteralLeafKinds, ...STRING_LEAF_KINDS]),
286
+ simpleLiteralKind(kind: string): LiteralFact["literalKind"] {
287
+ return STRING_LEAF_KINDS.has(kind) ? "string" : base.simpleLiteralKind(kind);
288
+ },
289
+
290
+ // Der Dekorator gehoert zum Symbol: `@app.route(...)` steht ueber der
291
+ // Funktion und beschreibt sie. `chunks.ts` weitet den Bereich darauf aus.
292
+ exportWrapperKinds: new Set(["decorated_definition"]),
293
+
294
+ // 4. `def` ist Funktion, Methode oder Konstruktor.
295
+ scopeKindOf(node: SyntaxNode): ScopeNode["kind"] | null {
296
+ const kind = base.scopeKindOf(node);
297
+ if (kind !== "function" || node.type !== "function_definition") return kind;
298
+ if (enclosingScopeKind(node) !== "class_definition") return "function";
299
+ return base.scopeName(node) === "__init__" ? "constructor" : "method";
300
+ },
301
+
302
+ scopeSignature(node: SyntaxNode, _kind: ScopeNode["kind"], name: string): ScopeSignature {
303
+ return pythonSignature(node, name, bodyField);
304
+ },
305
+
306
+ docRange: (node, ctx) => docstringRange(node, ctx, bodyField),
307
+
308
+ visibility: (_node, name) => pythonVisibility(name),
309
+
310
+ // 3. `__all__` schlaegt die Unterstrich-Konvention. Beides gilt nur fuer
311
+ // Namen auf Modulebene: eine Methode wird nicht aus der Datei exportiert.
312
+ exportedNames(node: SyntaxNode, name: string): string[] {
313
+ if (!isTopLevel(node)) return [];
314
+ if (dunderAll !== null) return dunderAll.has(name) ? [name] : [];
315
+ return name.startsWith("_") ? [] : [name];
316
+ },
317
+
318
+ detectDecisionAndNesting(node: SyntaxNode): DecisionDetectionResult {
319
+ const detected = base.detectDecisionAndNesting(node);
320
+ // `union_pattern` ist FLACH: `case 1 | 2 | 3` ist EIN Knoten mit drei
321
+ // Zweigen, waehrend Rusts `or_pattern` fuer dasselbe zwei verschachtelte
322
+ // Knoten baut. Ohne diese Zahl kostete `1 | 2 | 3` so viel wie `1 | 2`.
323
+ if (node.type !== "union_pattern" || detected.decision === undefined) return detected;
324
+ const alternatives = node.namedChildCount;
325
+ if (alternatives <= 1) return detected;
326
+ return { ...detected, decision: { ...detected.decision, repeat: alternatives - 1 } };
327
+ },
328
+
329
+ collectModuleFacts(node, kind, callerScopeId, ctx, sink): void {
330
+ if (
331
+ kind === "import_statement" ||
332
+ kind === "import_from_statement" ||
333
+ kind === "future_import_statement"
334
+ ) {
335
+ collectPythonImports(node, ctx, sink, isInitFile);
336
+ return;
337
+ }
338
+ base.collectModuleFacts(node, kind, callerScopeId, ctx, sink);
339
+ },
340
+ };
341
+ }
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Signature text normalization for Python (spec.md §5.5).
3
+ *
4
+ * `normalizedSignature` feeds `buildSymbolId` and MUST be stable across
5
+ * formatting-only edits. Rules (documented WP-09 decision — Python has no
6
+ * `tree-sitter-python` grammar to reuse `languages/shared/signature.ts`'s
7
+ * `<`/`>`-as-bracket assumption from, which is wrong for Python anyway:
8
+ * `<`/`>` are ONLY comparison operators here, never generic brackets):
9
+ *
10
+ * 1. **Whitespace**: any run of spaces/tabs/newlines collapses to a single
11
+ * space; spacing around `,`, `:` (annotation colon) and `=` (only for
12
+ * an ANNOTATED parameter's default, per PEP 8 — `x: int = 1`, not
13
+ * `x=1`) is canonicalized.
14
+ * 2. **Default values** (`= <expr>`) are STRIPPED from the identity
15
+ * signature, exactly like the TS/JS adapters: a default value is a
16
+ * call-site convenience, not a change to the parameter's name,
17
+ * position, or `*`/`**` role — keeping it would change a symbol's id on
18
+ * a body-only-feeling edit (`def f(a=1)` -> `def f(a=2)` should not look
19
+ * like a new symbol). Unlike TypeScript, Python has no separate
20
+ * "optional marker" syntax (`?`) that would otherwise carry the
21
+ * "caller may omit this" information forward — that information is
22
+ * simply not part of the normalized identity for Python, a documented
23
+ * (not accidental) asymmetry with the TS/JS adapters.
24
+ * 3. **Type annotations** (`: <type>`) are kept verbatim (modulo whitespace
25
+ * rules) — they are part of the observable call contract.
26
+ * 4. **`*args` / `**kwargs` / bare `*` (keyword-only marker) / `/`
27
+ * (positional-only marker, PEP 570)**: their `*`/`**`/`/` marker is kept
28
+ * exactly as written (it changes the call contract), only a following
29
+ * default (impossible for `*args`/`**kwargs`/markers, but harmless to
30
+ * guard) or its annotation spacing is normalized.
31
+ * 5. **Return type** (`-> <type>`) is kept verbatim (modulo whitespace),
32
+ * canonicalized to always have exactly one space on each side of `->`.
33
+ *
34
+ * Known limitation (documented, not a defect, mirroring the TS/JS
35
+ * adapters' own documented limitation): default-value stripping uses a
36
+ * bracket-DEPTH scanner over `( [ {` (never `<`/`>` — see above), not a
37
+ * full expression parser. A default expression containing an unbalanced
38
+ * string literal with a comma/`=` inside is not specially protected either
39
+ * (rare enough in default-value position to accept as a scoping decision).
40
+ */
41
+
42
+ const OPEN_BRACKETS = new Set(["(", "[", "{"]);
43
+ const CLOSE_BRACKETS = new Set([")", "]", "}"]);
44
+
45
+ /** Collapses whitespace runs to single spaces and trims. */
46
+ export function normalizeSpacing(text: string): string {
47
+ return text.replace(/\s+/g, " ").trim();
48
+ }
49
+
50
+ /** Splits `content` on top-level `,` (depth 0 w.r.t. `( [ {`). */
51
+ export function splitTopLevelComma(content: string): string[] {
52
+ const parts: string[] = [];
53
+ let depth = 0;
54
+ let current = "";
55
+ let inString: string | null = null;
56
+ for (let i = 0; i < content.length; i += 1) {
57
+ const ch = content[i] as string;
58
+ if (inString !== null) {
59
+ current += ch;
60
+ if (ch === "\\") {
61
+ i += 1;
62
+ if (i < content.length) current += content[i];
63
+ } else if (ch === inString) {
64
+ inString = null;
65
+ }
66
+ continue;
67
+ }
68
+ if (ch === '"' || ch === "'") {
69
+ inString = ch;
70
+ current += ch;
71
+ continue;
72
+ }
73
+ if (OPEN_BRACKETS.has(ch)) depth += 1;
74
+ else if (CLOSE_BRACKETS.has(ch)) depth = Math.max(0, depth - 1);
75
+ if (ch === "," && depth === 0) {
76
+ parts.push(current);
77
+ current = "";
78
+ } else {
79
+ current += ch;
80
+ }
81
+ }
82
+ parts.push(current);
83
+ return parts;
84
+ }
85
+
86
+ /** Index of the top-level `=` introducing a default value, or -1. Excludes `==`, `!=`, `<=`, `>=`, `:=`. */
87
+ function findTopLevelDefaultEquals(text: string): number {
88
+ let depth = 0;
89
+ let inString: string | null = null;
90
+ for (let i = 0; i < text.length; i += 1) {
91
+ const ch = text[i] as string;
92
+ if (inString !== null) {
93
+ if (ch === "\\") i += 1;
94
+ else if (ch === inString) inString = null;
95
+ continue;
96
+ }
97
+ if (ch === '"' || ch === "'") {
98
+ inString = ch;
99
+ continue;
100
+ }
101
+ if (OPEN_BRACKETS.has(ch)) {
102
+ depth += 1;
103
+ continue;
104
+ }
105
+ if (CLOSE_BRACKETS.has(ch)) {
106
+ depth = Math.max(0, depth - 1);
107
+ continue;
108
+ }
109
+ if (ch === "=" && depth === 0) {
110
+ const prev = i > 0 ? text[i - 1] : "";
111
+ const next = i + 1 < text.length ? text[i + 1] : "";
112
+ const isCompoundOperator =
113
+ next === "=" ||
114
+ prev === "=" ||
115
+ prev === "!" ||
116
+ prev === "<" ||
117
+ prev === ">" ||
118
+ prev === ":";
119
+ if (!isCompoundOperator) return i;
120
+ }
121
+ }
122
+ return -1;
123
+ }
124
+
125
+ /** Strips one parameter entry's default value (`= <expr>`), keeping any annotation before it. */
126
+ export function stripDefaultValue(entry: string): string {
127
+ const eqIndex = findTopLevelDefaultEquals(entry);
128
+ return eqIndex === -1 ? entry : entry.slice(0, eqIndex).trimEnd();
129
+ }
130
+
131
+ /** Canonicalizes one parameter entry's internal spacing: `a :int=1` -> `a: int`. */
132
+ function normalizeParamEntry(entry: string): string {
133
+ const stripped = stripDefaultValue(entry);
134
+ const colonIndex = topLevelColonIndex(stripped);
135
+ if (colonIndex === -1) return normalizeSpacing(stripped);
136
+ const name = normalizeSpacing(stripped.slice(0, colonIndex));
137
+ const annotation = normalizeSpacing(stripped.slice(colonIndex + 1));
138
+ return `${name}: ${annotation}`;
139
+ }
140
+
141
+ function topLevelColonIndex(text: string): number {
142
+ let depth = 0;
143
+ let inString: string | null = null;
144
+ for (let i = 0; i < text.length; i += 1) {
145
+ const ch = text[i] as string;
146
+ if (inString !== null) {
147
+ if (ch === "\\") i += 1;
148
+ else if (ch === inString) inString = null;
149
+ continue;
150
+ }
151
+ if (ch === '"' || ch === "'") {
152
+ inString = ch;
153
+ continue;
154
+ }
155
+ if (OPEN_BRACKETS.has(ch)) depth += 1;
156
+ else if (CLOSE_BRACKETS.has(ch)) depth = Math.max(0, depth - 1);
157
+ else if (ch === ":" && depth === 0) return i;
158
+ }
159
+ return -1;
160
+ }
161
+
162
+ /** Normalizes a parameter-list text INCLUDING its outer parens, e.g. `( a:int=1, *, b = 2 )` -> `(a: int, *, b)`. */
163
+ export function normalizeParameterList(paramsText: string): string {
164
+ const trimmed = paramsText.trim();
165
+ const hasParens = trimmed.startsWith("(") && trimmed.endsWith(")");
166
+ const inner = hasParens ? trimmed.slice(1, -1) : trimmed;
167
+ const entries = splitTopLevelComma(inner)
168
+ .map((entry) => entry.trim())
169
+ .filter((entry) => entry.length > 0);
170
+ const normalizedEntries = entries.map(normalizeParamEntry);
171
+ return `(${normalizedEntries.join(", ")})`;
172
+ }
173
+
174
+ /** Normalizes a `-> ReturnType` suffix (or `""` when absent). */
175
+ export function normalizeReturnType(returnTypeRaw: string | undefined): string {
176
+ if (returnTypeRaw === undefined || returnTypeRaw.trim().length === 0) return "";
177
+ return ` -> ${normalizeSpacing(returnTypeRaw)}`;
178
+ }
179
+
180
+ /** Normalizes a class/def header text with no parameter list (e.g. a bare `class Foo:`). */
181
+ export function normalizeHeaderText(headerText: string): string {
182
+ return normalizeSpacing(headerText.replace(/:\s*$/, ""));
183
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Die Sprachtabelle fuer Python — die zwoelfte Sprache des ast-grep-Backends.
3
+ *
4
+ * WAS HIER GESCHAH (WP-239): bis Welle 7 stand an dieser Stelle ein
5
+ * HANDGESCHRIEBENER Tokenizer, Parser und AST-Motor ueber 5.604 Zeilen. Sie
6
+ * entstanden nicht aus einer fachlichen Notwendigkeit, sondern weil eine zu
7
+ * enge Auftragsgrenze einem Agenten verbot, `package.json` anzufassen
8
+ * (dokumentiert in `docs/PARITY.md`). Die Grammatik, die es dafuer braucht,
9
+ * gibt es fertig und MIT-lizenziert: `@ast-grep/lang-python`.
10
+ *
11
+ * WAS DIE ABLOESUNG NEBENBEI BEHOBEN HAT — nicht durch eine Korrektur,
12
+ * sondern weil die Klasse von Fehlern verschwindet:
13
+ *
14
+ * - WP-238: `with a() as x, b() as y:` liess im handgeschriebenen Parser die
15
+ * GANZE Datei mit `parseQuality: "failed"` durchfallen. Die Grammatik legt
16
+ * dafuer `with_clause > with_item*` an; es gibt nichts zu erkennen.
17
+ * - WP-115: verschachtelte Ausdruecke in f-String-Formatangaben
18
+ * (`f"{x:{w}.{p}}"`) gingen im Teil-Parse verloren. Hier sind sie
19
+ * gewoehnliche `interpolation`/`format_expression`-Knoten im Baum —
20
+ * deshalb steht `string` NICHT unter `stringContainerKinds` (siehe dort).
21
+ * - WP-226: ein nachgestellter Kommentar vor dem Zeilenende verschluckte im
22
+ * Tokenizer das NEWLINE. Ein `comment` ist hier ein Geschwister wie jedes
23
+ * andere.
24
+ *
25
+ * WAS DIE TABELLE NICHT LEISTET, steht in `profile.ts` daneben: Docstrings,
26
+ * Sichtbarkeit aus der Namenskonvention, `__all__`, die Unterscheidung
27
+ * Funktion/Methode/Konstruktor und die Importformen sind Python-Regeln, die
28
+ * KEINE Tabelle ausdrueckt. Sie stehen als Verfeinerung ueber diesem Profil,
29
+ * nicht als Sonderfaelle im gemeinsamen Motor.
30
+ *
31
+ * DIE KNOTENARTEN SIND NACHGESEHEN, NICHT GERATEN: jede Zeichenkette hier
32
+ * stammt aus einem echten Baum, den `adapters.test.ts` mit demselben
33
+ * Quelltext wieder erzeugt.
34
+ */
35
+ import type { AstGrepLanguageSource } from "../astgrep-backend/index.js";
36
+ import type { LanguageKindTable } from "../shared/table-profile.js";
37
+ import { DEFAULT_PUNCTUATION } from "../shared/table-profile.js";
38
+
39
+ /** Woher die Grammatik kommt. MIT-lizenziert, siehe `THIRD_PARTY_LICENSES.md`. */
40
+ export const PYTHON_SOURCE: AstGrepLanguageSource = {
41
+ languageName: "python",
42
+ moduleName: "@ast-grep/lang-python",
43
+ };
44
+
45
+ /**
46
+ * Zeichenkettenblaetter. Sie stehen NICHT unter `numberLeafKinds` und
47
+ * Verwandten, weil `simpleLiteralKind` daraus "number"/"boolean"/"null"
48
+ * ableitet; `profile.ts` haengt sie an und beantwortet sie mit "string".
49
+ */
50
+ export const PYTHON_STRING_LEAF_KINDS: readonly string[] = ["string_content", "escape_sequence"];
51
+
52
+ export const PYTHON_TABLE: LanguageKindTable = {
53
+ languageId: "python",
54
+ extensions: [".py", ".pyi"],
55
+ supportLevel: "deep",
56
+ commentKinds: ["comment"],
57
+
58
+ /**
59
+ * ABSICHTLICH LEER. Ein `string` waere in jeder anderen Sprache ein
60
+ * Container, dessen Teilbaum EIN Operand ist. In Python ist er das nicht:
61
+ * ein f-String traegt `interpolation`-Knoten mit vollwertigen Ausdruecken,
62
+ * und ein Aufruf darin ist ein Aufruf. Wer `string` hier eintraegt, macht
63
+ * WP-115 zum zweiten Mal — nur diesmal ohne Diagnose, weil der Walk gar
64
+ * nicht erst hineinsieht.
65
+ */
66
+ stringContainerKinds: [],
67
+
68
+ identifierLeafKinds: ["identifier"],
69
+ numberLeafKinds: ["integer", "float"],
70
+ booleanLeafKinds: ["true", "false"],
71
+ nullLeafKinds: ["none"],
72
+
73
+ // `string_start`/`string_end` tragen das Praefix und die Anfuehrungszeichen;
74
+ // sie sind Struktur, kein Operator. Ohne sie stuende `f"` als "Operator" in
75
+ // jeder Halstead-Rechnung.
76
+ punctuationKinds: [...DEFAULT_PUNCTUATION, "string_start", "string_end"],
77
+
78
+ scopes: [
79
+ { kinds: ["function_definition"], scopeKind: "function" },
80
+ { kinds: ["class_definition"], scopeKind: "class" },
81
+ // Ein `lambda` ist eine Ausfuehrungseinheit wie eine `def`: spec.md §16.1
82
+ // zaehlt Lambdas mit, und §16.4 verlangt fuer sie ein eigenes
83
+ // Nesting-Ereignis im umgebenden Scope. Beides haengt daran, dass es hier
84
+ // steht.
85
+ { kinds: ["lambda"], scopeKind: "function" },
86
+ ],
87
+
88
+ decisions: {
89
+ // `if_clause` ist BEIDES: der Filter einer Komprehension
90
+ // (`[x for x in a if p(x)]`) und der Waechter eines `case`. Beide sind
91
+ // eine echte Verzweigung, beide zaehlen — und beide heissen so.
92
+ ifKinds: ["if_statement", "if_clause"],
93
+ elseIfKinds: ["elif_clause"],
94
+ // `for_in_clause` ist die `for`-Klausel einer Komprehension. Sie ist eine
95
+ // Schleife, auch wenn sie keine Anweisung ist.
96
+ loopKinds: ["for_statement", "while_statement", "for_in_clause"],
97
+ catchKinds: ["except_clause", "except_group_clause"],
98
+ ternaryKinds: ["conditional_expression"],
99
+ switchKinds: ["match_statement"],
100
+ caseKinds: ["case_clause"],
101
+ // `case _:` zaehlt in Python MIT: anders als ein C-`default` ist `_` ein
102
+ // gewoehnliches Muster in der Reihenfolge, und ein `match` bricht ohne
103
+ // Treffer einfach ab. Deshalb steht hier KEIN `caseExcludeChildKinds`.
104
+ patternAlternativeKinds: ["union_pattern"],
105
+ binaryKinds: ["boolean_operator"],
106
+ operatorField: "operator",
107
+ logicalAndOperators: ["and"],
108
+ logicalOrOperators: ["or"],
109
+ jumpKinds: ["return_statement", "raise_statement", "break_statement", "continue_statement"],
110
+ blockKinds: ["block"],
111
+ consequenceField: "consequence",
112
+ // `elif_clause` UND `else_clause` stehen beide im Feld `alternative`.
113
+ // Genau deshalb ist ein `if` mit `elif` kein Waechter (`guard`), sondern
114
+ // ein `if` — was `adapters.test.ts` festhaelt.
115
+ alternativeField: "alternative",
116
+ },
117
+
118
+ // Die Importe wertet `profile.ts` aus: Python fuehrt in EINER Anweisung
119
+ // mehrere Ziele mit je eigenem Alias, und das druecken `ImportRules` nicht
120
+ // aus. Die Arten stehen hier, damit das Vorsieb (`needsNode`) sie kennt.
121
+ imports: {
122
+ kinds: ["import_statement", "import_from_statement", "future_import_statement"],
123
+ },
124
+
125
+ calls: {
126
+ kinds: ["call"],
127
+ functionField: "function",
128
+ argumentsField: "arguments",
129
+ memberKinds: ["attribute"],
130
+ },
131
+
132
+ declarationParentKinds: ["function_definition", "class_definition"],
133
+
134
+ bodyField: "body",
135
+ };