spark-sql-language-server 0.0.1-beta.6 → 0.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (740) hide show
  1. package/out/sparksql-server-worker.js +1 -1
  2. package/out/sparksql-server-worker.js.map +1 -1
  3. package/out-tsc/assets/built-in-functions.d.ts +2 -0
  4. package/out-tsc/assets/built-in-functions.d.ts.map +1 -0
  5. package/out-tsc/assets/built-in-functions.js +4 -2
  6. package/out-tsc/assets/built-in-functions.js.map +1 -1
  7. package/out-tsc/completion-parser.d.ts +11 -0
  8. package/out-tsc/completion-parser.d.ts.map +1 -0
  9. package/out-tsc/completion-parser.js +148 -0
  10. package/out-tsc/completion-parser.js.map +1 -0
  11. package/out-tsc/constants.d.ts +9 -0
  12. package/out-tsc/constants.d.ts.map +1 -0
  13. package/out-tsc/constants.js +12 -0
  14. package/out-tsc/constants.js.map +1 -0
  15. package/out-tsc/cursor.d.ts +10 -0
  16. package/out-tsc/cursor.d.ts.map +1 -0
  17. package/out-tsc/cursor.js +3 -0
  18. package/out-tsc/cursor.js.map +1 -1
  19. package/out-tsc/execute-command.d.ts +7 -0
  20. package/out-tsc/execute-command.d.ts.map +1 -0
  21. package/out-tsc/execute-command.js +78 -0
  22. package/out-tsc/execute-command.js.map +1 -0
  23. package/out-tsc/execute-commands.d.ts +1 -0
  24. package/out-tsc/execute-commands.d.ts.map +1 -0
  25. package/out-tsc/execute-commands.js +3 -4
  26. package/out-tsc/execute-commands.js.map +1 -1
  27. package/out-tsc/formatter/boundary-writer.d.ts +30 -0
  28. package/out-tsc/formatter/boundary-writer.d.ts.map +1 -0
  29. package/out-tsc/formatter/boundary-writer.js +47 -0
  30. package/out-tsc/formatter/boundary-writer.js.map +1 -0
  31. package/out-tsc/formatter/core/comment-helper.d.ts +11 -0
  32. package/out-tsc/formatter/core/comment-helper.d.ts.map +1 -0
  33. package/out-tsc/formatter/core/comment-helper.js +139 -0
  34. package/out-tsc/formatter/core/comment-helper.js.map +1 -0
  35. package/out-tsc/formatter/core/edit-collector.d.ts +110 -0
  36. package/out-tsc/formatter/core/edit-collector.d.ts.map +1 -0
  37. package/out-tsc/formatter/core/edit-collector.js +159 -0
  38. package/out-tsc/formatter/core/edit-collector.js.map +1 -0
  39. package/out-tsc/formatter/core/formatting-context.d.ts +183 -0
  40. package/out-tsc/formatter/core/formatting-context.d.ts.map +1 -0
  41. package/out-tsc/formatter/core/formatting-context.js +294 -0
  42. package/out-tsc/formatter/core/formatting-context.js.map +1 -0
  43. package/out-tsc/formatter/core/index.d.ts +25 -0
  44. package/out-tsc/formatter/core/index.d.ts.map +1 -0
  45. package/out-tsc/formatter/core/index.js +57 -0
  46. package/out-tsc/formatter/core/index.js.map +1 -0
  47. package/out-tsc/formatter/core/pipeline/formatting-pipeline.d.ts +116 -0
  48. package/out-tsc/formatter/core/pipeline/formatting-pipeline.d.ts.map +1 -0
  49. package/out-tsc/formatter/core/pipeline/formatting-pipeline.js +237 -0
  50. package/out-tsc/formatter/core/pipeline/formatting-pipeline.js.map +1 -0
  51. package/out-tsc/formatter/core/pipeline/index.d.ts +12 -0
  52. package/out-tsc/formatter/core/pipeline/index.d.ts.map +1 -0
  53. package/out-tsc/formatter/core/pipeline/index.js +19 -0
  54. package/out-tsc/formatter/core/pipeline/index.js.map +1 -0
  55. package/out-tsc/formatter/core/pipeline/statement-separation.d.ts +5 -0
  56. package/out-tsc/formatter/core/pipeline/statement-separation.d.ts.map +1 -0
  57. package/out-tsc/formatter/core/pipeline/statement-separation.js +149 -0
  58. package/out-tsc/formatter/core/pipeline/statement-separation.js.map +1 -0
  59. package/out-tsc/formatter/core/rules/index.d.ts +11 -0
  60. package/out-tsc/formatter/core/rules/index.d.ts.map +1 -0
  61. package/out-tsc/formatter/core/rules/index.js +29 -0
  62. package/out-tsc/formatter/core/rules/index.js.map +1 -0
  63. package/out-tsc/formatter/core/rules/newline-rules.d.ts +169 -0
  64. package/out-tsc/formatter/core/rules/newline-rules.d.ts.map +1 -0
  65. package/out-tsc/formatter/core/rules/newline-rules.js +246 -0
  66. package/out-tsc/formatter/core/rules/newline-rules.js.map +1 -0
  67. package/out-tsc/formatter/core/rules/spacing-rules.d.ts +150 -0
  68. package/out-tsc/formatter/core/rules/spacing-rules.d.ts.map +1 -0
  69. package/out-tsc/formatter/core/rules/spacing-rules.js +219 -0
  70. package/out-tsc/formatter/core/rules/spacing-rules.js.map +1 -0
  71. package/out-tsc/formatter/core/strategy-bridge.d.ts +56 -0
  72. package/out-tsc/formatter/core/strategy-bridge.d.ts.map +1 -0
  73. package/out-tsc/formatter/core/strategy-bridge.js +159 -0
  74. package/out-tsc/formatter/core/strategy-bridge.js.map +1 -0
  75. package/out-tsc/formatter/core/strategy-interface.d.ts +123 -0
  76. package/out-tsc/formatter/core/strategy-interface.d.ts.map +1 -0
  77. package/out-tsc/formatter/core/strategy-interface.js +83 -0
  78. package/out-tsc/formatter/core/strategy-interface.js.map +1 -0
  79. package/out-tsc/formatter/core/token-helper.d.ts +12 -0
  80. package/out-tsc/formatter/core/token-helper.d.ts.map +1 -0
  81. package/out-tsc/formatter/core/token-helper.js +79 -0
  82. package/out-tsc/formatter/core/token-helper.js.map +1 -0
  83. package/out-tsc/formatter/core/unicode-utils.d.ts +107 -0
  84. package/out-tsc/formatter/core/unicode-utils.d.ts.map +1 -0
  85. package/out-tsc/formatter/core/unicode-utils.js +181 -0
  86. package/out-tsc/formatter/core/unicode-utils.js.map +1 -0
  87. package/out-tsc/formatter/core/whitespace-writer.d.ts +20 -0
  88. package/out-tsc/formatter/core/whitespace-writer.d.ts.map +1 -0
  89. package/out-tsc/formatter/core/whitespace-writer.js +86 -0
  90. package/out-tsc/formatter/core/whitespace-writer.js.map +1 -0
  91. package/out-tsc/formatter/formatter-adapter.d.ts +56 -0
  92. package/out-tsc/formatter/formatter-adapter.d.ts.map +1 -0
  93. package/out-tsc/formatter/formatter-adapter.js +719 -0
  94. package/out-tsc/formatter/formatter-adapter.js.map +1 -0
  95. package/out-tsc/formatter/index.d.ts +16 -0
  96. package/out-tsc/formatter/index.d.ts.map +1 -0
  97. package/out-tsc/formatter/index.js +43 -0
  98. package/out-tsc/formatter/index.js.map +1 -0
  99. package/out-tsc/formatter/pipe-step-classifier.d.ts +9 -0
  100. package/out-tsc/formatter/pipe-step-classifier.d.ts.map +1 -0
  101. package/out-tsc/formatter/pipe-step-classifier.js +49 -0
  102. package/out-tsc/formatter/pipe-step-classifier.js.map +1 -0
  103. package/out-tsc/formatter/state.d.ts +10 -0
  104. package/out-tsc/formatter/state.d.ts.map +1 -0
  105. package/out-tsc/formatter/state.js +12 -0
  106. package/out-tsc/formatter/state.js.map +1 -0
  107. package/out-tsc/formatter/strategies/block.strategy.d.ts +191 -0
  108. package/out-tsc/formatter/strategies/block.strategy.d.ts.map +1 -0
  109. package/out-tsc/formatter/strategies/block.strategy.js +238 -0
  110. package/out-tsc/formatter/strategies/block.strategy.js.map +1 -0
  111. package/out-tsc/formatter/strategies/clause-head-body.strategy.d.ts +17 -0
  112. package/out-tsc/formatter/strategies/clause-head-body.strategy.d.ts.map +1 -0
  113. package/out-tsc/formatter/strategies/clause-head-body.strategy.js +13 -0
  114. package/out-tsc/formatter/strategies/clause-head-body.strategy.js.map +1 -0
  115. package/out-tsc/formatter/strategies/ddl/alter-table-extended.strategy.d.ts +68 -0
  116. package/out-tsc/formatter/strategies/ddl/alter-table-extended.strategy.d.ts.map +1 -0
  117. package/out-tsc/formatter/strategies/ddl/alter-table-extended.strategy.js +242 -0
  118. package/out-tsc/formatter/strategies/ddl/alter-table-extended.strategy.js.map +1 -0
  119. package/out-tsc/formatter/strategies/ddl/alter-table.strategy.d.ts +146 -0
  120. package/out-tsc/formatter/strategies/ddl/alter-table.strategy.d.ts.map +1 -0
  121. package/out-tsc/formatter/strategies/ddl/alter-table.strategy.js +578 -0
  122. package/out-tsc/formatter/strategies/ddl/alter-table.strategy.js.map +1 -0
  123. package/out-tsc/formatter/strategies/ddl/create-table.strategy.d.ts +103 -0
  124. package/out-tsc/formatter/strategies/ddl/create-table.strategy.d.ts.map +1 -0
  125. package/out-tsc/formatter/strategies/ddl/create-table.strategy.js +659 -0
  126. package/out-tsc/formatter/strategies/ddl/create-table.strategy.js.map +1 -0
  127. package/out-tsc/formatter/strategies/ddl/create-view-function.strategy.d.ts +64 -0
  128. package/out-tsc/formatter/strategies/ddl/create-view-function.strategy.d.ts.map +1 -0
  129. package/out-tsc/formatter/strategies/ddl/create-view-function.strategy.js +402 -0
  130. package/out-tsc/formatter/strategies/ddl/create-view-function.strategy.js.map +1 -0
  131. package/out-tsc/formatter/strategies/ddl/drop-utility.strategy.d.ts +119 -0
  132. package/out-tsc/formatter/strategies/ddl/drop-utility.strategy.d.ts.map +1 -0
  133. package/out-tsc/formatter/strategies/ddl/drop-utility.strategy.js +863 -0
  134. package/out-tsc/formatter/strategies/ddl/drop-utility.strategy.js.map +1 -0
  135. package/out-tsc/formatter/strategies/ddl/index.d.ts +17 -0
  136. package/out-tsc/formatter/strategies/ddl/index.d.ts.map +1 -0
  137. package/out-tsc/formatter/strategies/ddl/index.js +57 -0
  138. package/out-tsc/formatter/strategies/ddl/index.js.map +1 -0
  139. package/out-tsc/formatter/strategies/ddl/namespace-catalog.strategy.d.ts +26 -0
  140. package/out-tsc/formatter/strategies/ddl/namespace-catalog.strategy.d.ts.map +1 -0
  141. package/out-tsc/formatter/strategies/ddl/namespace-catalog.strategy.js +77 -0
  142. package/out-tsc/formatter/strategies/ddl/namespace-catalog.strategy.js.map +1 -0
  143. package/out-tsc/formatter/strategies/ddl/pipeline.strategy.d.ts +99 -0
  144. package/out-tsc/formatter/strategies/ddl/pipeline.strategy.d.ts.map +1 -0
  145. package/out-tsc/formatter/strategies/ddl/pipeline.strategy.js +385 -0
  146. package/out-tsc/formatter/strategies/ddl/pipeline.strategy.js.map +1 -0
  147. package/out-tsc/formatter/strategies/ddl/set-reset-config.strategy.d.ts +48 -0
  148. package/out-tsc/formatter/strategies/ddl/set-reset-config.strategy.d.ts.map +1 -0
  149. package/out-tsc/formatter/strategies/ddl/set-reset-config.strategy.js +145 -0
  150. package/out-tsc/formatter/strategies/ddl/set-reset-config.strategy.js.map +1 -0
  151. package/out-tsc/formatter/strategies/ddl/show-utility.strategy.d.ts +71 -0
  152. package/out-tsc/formatter/strategies/ddl/show-utility.strategy.d.ts.map +1 -0
  153. package/out-tsc/formatter/strategies/ddl/show-utility.strategy.js +196 -0
  154. package/out-tsc/formatter/strategies/ddl/show-utility.strategy.js.map +1 -0
  155. package/out-tsc/formatter/strategies/dml/index.d.ts +10 -0
  156. package/out-tsc/formatter/strategies/dml/index.d.ts.map +1 -0
  157. package/out-tsc/formatter/strategies/dml/index.js +35 -0
  158. package/out-tsc/formatter/strategies/dml/index.js.map +1 -0
  159. package/out-tsc/formatter/strategies/dml/insert-update-delete.strategy.d.ts +113 -0
  160. package/out-tsc/formatter/strategies/dml/insert-update-delete.strategy.d.ts.map +1 -0
  161. package/out-tsc/formatter/strategies/dml/insert-update-delete.strategy.js +438 -0
  162. package/out-tsc/formatter/strategies/dml/insert-update-delete.strategy.js.map +1 -0
  163. package/out-tsc/formatter/strategies/dml/select-clause.strategy.d.ts +76 -0
  164. package/out-tsc/formatter/strategies/dml/select-clause.strategy.d.ts.map +1 -0
  165. package/out-tsc/formatter/strategies/dml/select-clause.strategy.js +480 -0
  166. package/out-tsc/formatter/strategies/dml/select-clause.strategy.js.map +1 -0
  167. package/out-tsc/formatter/strategies/expression/function-call.strategy.d.ts +50 -0
  168. package/out-tsc/formatter/strategies/expression/function-call.strategy.d.ts.map +1 -0
  169. package/out-tsc/formatter/strategies/expression/function-call.strategy.js +319 -0
  170. package/out-tsc/formatter/strategies/expression/function-call.strategy.js.map +1 -0
  171. package/out-tsc/formatter/strategies/expression/index.d.ts +18 -0
  172. package/out-tsc/formatter/strategies/expression/index.d.ts.map +1 -0
  173. package/out-tsc/formatter/strategies/expression/index.js +51 -0
  174. package/out-tsc/formatter/strategies/expression/index.js.map +1 -0
  175. package/out-tsc/formatter/strategies/expression/logical-comparison.strategy.d.ts +55 -0
  176. package/out-tsc/formatter/strategies/expression/logical-comparison.strategy.d.ts.map +1 -0
  177. package/out-tsc/formatter/strategies/expression/logical-comparison.strategy.js +266 -0
  178. package/out-tsc/formatter/strategies/expression/logical-comparison.strategy.js.map +1 -0
  179. package/out-tsc/formatter/strategies/expression/subquery-parenthesis.strategy.d.ts +38 -0
  180. package/out-tsc/formatter/strategies/expression/subquery-parenthesis.strategy.d.ts.map +1 -0
  181. package/out-tsc/formatter/strategies/expression/subquery-parenthesis.strategy.js +397 -0
  182. package/out-tsc/formatter/strategies/expression/subquery-parenthesis.strategy.js.map +1 -0
  183. package/out-tsc/formatter/strategies/function-call.strategy.d.ts +80 -0
  184. package/out-tsc/formatter/strategies/function-call.strategy.d.ts.map +1 -0
  185. package/out-tsc/formatter/strategies/function-call.strategy.js +136 -0
  186. package/out-tsc/formatter/strategies/function-call.strategy.js.map +1 -0
  187. package/out-tsc/formatter/strategies/index.d.ts +87 -0
  188. package/out-tsc/formatter/strategies/index.d.ts.map +1 -0
  189. package/out-tsc/formatter/strategies/index.js +121 -0
  190. package/out-tsc/formatter/strategies/index.js.map +1 -0
  191. package/out-tsc/formatter/strategies/join.strategy.d.ts +31 -0
  192. package/out-tsc/formatter/strategies/join.strategy.d.ts.map +1 -0
  193. package/out-tsc/formatter/strategies/join.strategy.js +29 -0
  194. package/out-tsc/formatter/strategies/join.strategy.js.map +1 -0
  195. package/out-tsc/formatter/strategies/keyword.strategy.d.ts +82 -0
  196. package/out-tsc/formatter/strategies/keyword.strategy.d.ts.map +1 -0
  197. package/out-tsc/formatter/strategies/keyword.strategy.js +129 -0
  198. package/out-tsc/formatter/strategies/keyword.strategy.js.map +1 -0
  199. package/out-tsc/formatter/strategies/list.strategy.d.ts +159 -0
  200. package/out-tsc/formatter/strategies/list.strategy.d.ts.map +1 -0
  201. package/out-tsc/formatter/strategies/list.strategy.js +193 -0
  202. package/out-tsc/formatter/strategies/list.strategy.js.map +1 -0
  203. package/out-tsc/formatter/strategies/pipe-aggregate.strategy.d.ts +24 -0
  204. package/out-tsc/formatter/strategies/pipe-aggregate.strategy.d.ts.map +1 -0
  205. package/out-tsc/formatter/strategies/pipe-aggregate.strategy.js +47 -0
  206. package/out-tsc/formatter/strategies/pipe-aggregate.strategy.js.map +1 -0
  207. package/out-tsc/formatter/strategies/pipe-drop.strategy.d.ts +21 -0
  208. package/out-tsc/formatter/strategies/pipe-drop.strategy.d.ts.map +1 -0
  209. package/out-tsc/formatter/strategies/pipe-drop.strategy.js +52 -0
  210. package/out-tsc/formatter/strategies/pipe-drop.strategy.js.map +1 -0
  211. package/out-tsc/formatter/strategies/pipe-extend.strategy.d.ts +21 -0
  212. package/out-tsc/formatter/strategies/pipe-extend.strategy.d.ts.map +1 -0
  213. package/out-tsc/formatter/strategies/pipe-extend.strategy.js +45 -0
  214. package/out-tsc/formatter/strategies/pipe-extend.strategy.js.map +1 -0
  215. package/out-tsc/formatter/strategies/pipe-join.strategy.d.ts +22 -0
  216. package/out-tsc/formatter/strategies/pipe-join.strategy.d.ts.map +1 -0
  217. package/out-tsc/formatter/strategies/pipe-join.strategy.js +42 -0
  218. package/out-tsc/formatter/strategies/pipe-join.strategy.js.map +1 -0
  219. package/out-tsc/formatter/strategies/pipe-pivot.strategy.d.ts +7 -0
  220. package/out-tsc/formatter/strategies/pipe-pivot.strategy.d.ts.map +1 -0
  221. package/out-tsc/formatter/strategies/pipe-pivot.strategy.js +34 -0
  222. package/out-tsc/formatter/strategies/pipe-pivot.strategy.js.map +1 -0
  223. package/out-tsc/formatter/strategies/pipe-query-organization.strategy.d.ts +7 -0
  224. package/out-tsc/formatter/strategies/pipe-query-organization.strategy.d.ts.map +1 -0
  225. package/out-tsc/formatter/strategies/pipe-query-organization.strategy.js +14 -0
  226. package/out-tsc/formatter/strategies/pipe-query-organization.strategy.js.map +1 -0
  227. package/out-tsc/formatter/strategies/pipe-sample.strategy.d.ts +7 -0
  228. package/out-tsc/formatter/strategies/pipe-sample.strategy.d.ts.map +1 -0
  229. package/out-tsc/formatter/strategies/pipe-sample.strategy.js +18 -0
  230. package/out-tsc/formatter/strategies/pipe-sample.strategy.js.map +1 -0
  231. package/out-tsc/formatter/strategies/pipe-select.strategy.d.ts +22 -0
  232. package/out-tsc/formatter/strategies/pipe-select.strategy.d.ts.map +1 -0
  233. package/out-tsc/formatter/strategies/pipe-select.strategy.js +51 -0
  234. package/out-tsc/formatter/strategies/pipe-select.strategy.js.map +1 -0
  235. package/out-tsc/formatter/strategies/pipe-set-operation.strategy.d.ts +7 -0
  236. package/out-tsc/formatter/strategies/pipe-set-operation.strategy.d.ts.map +1 -0
  237. package/out-tsc/formatter/strategies/pipe-set-operation.strategy.js +30 -0
  238. package/out-tsc/formatter/strategies/pipe-set-operation.strategy.js.map +1 -0
  239. package/out-tsc/formatter/strategies/pipe-set.strategy.d.ts +21 -0
  240. package/out-tsc/formatter/strategies/pipe-set.strategy.d.ts.map +1 -0
  241. package/out-tsc/formatter/strategies/pipe-set.strategy.js +52 -0
  242. package/out-tsc/formatter/strategies/pipe-set.strategy.js.map +1 -0
  243. package/out-tsc/formatter/strategies/pipe-step.strategy.d.ts +25 -0
  244. package/out-tsc/formatter/strategies/pipe-step.strategy.d.ts.map +1 -0
  245. package/out-tsc/{lib/SparkSqlParserVisitor.js → formatter/strategies/pipe-step.strategy.js} +1 -1
  246. package/out-tsc/formatter/strategies/pipe-step.strategy.js.map +1 -0
  247. package/out-tsc/formatter/strategies/pipe-unpivot.strategy.d.ts +7 -0
  248. package/out-tsc/formatter/strategies/pipe-unpivot.strategy.d.ts.map +1 -0
  249. package/out-tsc/formatter/strategies/pipe-unpivot.strategy.js +33 -0
  250. package/out-tsc/formatter/strategies/pipe-unpivot.strategy.js.map +1 -0
  251. package/out-tsc/formatter/strategies/pipe-where.strategy.d.ts +21 -0
  252. package/out-tsc/formatter/strategies/pipe-where.strategy.d.ts.map +1 -0
  253. package/out-tsc/formatter/strategies/pipe-where.strategy.js +44 -0
  254. package/out-tsc/formatter/strategies/pipe-where.strategy.js.map +1 -0
  255. package/out-tsc/formatter/strategies/procedure/case-statement.strategy.d.ts +20 -0
  256. package/out-tsc/formatter/strategies/procedure/case-statement.strategy.d.ts.map +1 -0
  257. package/out-tsc/formatter/strategies/procedure/case-statement.strategy.js +132 -0
  258. package/out-tsc/formatter/strategies/procedure/case-statement.strategy.js.map +1 -0
  259. package/out-tsc/formatter/strategies/procedure/compound-statement.strategy.d.ts +43 -0
  260. package/out-tsc/formatter/strategies/procedure/compound-statement.strategy.d.ts.map +1 -0
  261. package/out-tsc/formatter/strategies/procedure/compound-statement.strategy.js +174 -0
  262. package/out-tsc/formatter/strategies/procedure/compound-statement.strategy.js.map +1 -0
  263. package/out-tsc/formatter/strategies/procedure/handler.strategy.d.ts +23 -0
  264. package/out-tsc/formatter/strategies/procedure/handler.strategy.d.ts.map +1 -0
  265. package/out-tsc/formatter/strategies/procedure/handler.strategy.js +81 -0
  266. package/out-tsc/formatter/strategies/procedure/handler.strategy.js.map +1 -0
  267. package/out-tsc/formatter/strategies/procedure/if-else.strategy.d.ts +19 -0
  268. package/out-tsc/formatter/strategies/procedure/if-else.strategy.d.ts.map +1 -0
  269. package/out-tsc/formatter/strategies/procedure/if-else.strategy.js +80 -0
  270. package/out-tsc/formatter/strategies/procedure/if-else.strategy.js.map +1 -0
  271. package/out-tsc/formatter/strategies/procedure/index.d.ts +27 -0
  272. package/out-tsc/formatter/strategies/procedure/index.d.ts.map +1 -0
  273. package/out-tsc/formatter/strategies/procedure/index.js +63 -0
  274. package/out-tsc/formatter/strategies/procedure/index.js.map +1 -0
  275. package/out-tsc/formatter/strategies/procedure/leave-iterate.strategy.d.ts +19 -0
  276. package/out-tsc/formatter/strategies/procedure/leave-iterate.strategy.d.ts.map +1 -0
  277. package/out-tsc/formatter/strategies/procedure/leave-iterate.strategy.js +54 -0
  278. package/out-tsc/formatter/strategies/procedure/leave-iterate.strategy.js.map +1 -0
  279. package/out-tsc/formatter/strategies/procedure/loop.strategy.d.ts +71 -0
  280. package/out-tsc/formatter/strategies/procedure/loop.strategy.d.ts.map +1 -0
  281. package/out-tsc/formatter/strategies/procedure/loop.strategy.js +216 -0
  282. package/out-tsc/formatter/strategies/procedure/loop.strategy.js.map +1 -0
  283. package/out-tsc/formatter/strategy-based-formatter.d.ts +329 -0
  284. package/out-tsc/formatter/strategy-based-formatter.d.ts.map +1 -0
  285. package/out-tsc/formatter/strategy-based-formatter.js +3808 -0
  286. package/out-tsc/formatter/strategy-based-formatter.js.map +1 -0
  287. package/out-tsc/formatter/strategy-dispatcher.d.ts +24 -0
  288. package/out-tsc/formatter/strategy-dispatcher.d.ts.map +1 -0
  289. package/out-tsc/formatter/strategy-dispatcher.js +19 -0
  290. package/out-tsc/formatter/strategy-dispatcher.js.map +1 -0
  291. package/out-tsc/formatter/types.d.ts +2 -0
  292. package/out-tsc/formatter/types.d.ts.map +1 -0
  293. package/out-tsc/{lib/SparkSqlParserListener.js → formatter/types.js} +1 -1
  294. package/out-tsc/formatter/types.js.map +1 -0
  295. package/out-tsc/formatter/visitor/ddl/alter-table.d.ts +48 -0
  296. package/out-tsc/formatter/visitor/ddl/alter-table.d.ts.map +1 -0
  297. package/out-tsc/formatter/visitor/ddl/alter-table.js +133 -0
  298. package/out-tsc/formatter/visitor/ddl/alter-table.js.map +1 -0
  299. package/out-tsc/formatter/visitor/ddl/create-table.d.ts +54 -0
  300. package/out-tsc/formatter/visitor/ddl/create-table.d.ts.map +1 -0
  301. package/out-tsc/formatter/visitor/ddl/create-table.js +142 -0
  302. package/out-tsc/formatter/visitor/ddl/create-table.js.map +1 -0
  303. package/out-tsc/formatter/visitor/ddl/create-view.d.ts +27 -0
  304. package/out-tsc/formatter/visitor/ddl/create-view.d.ts.map +1 -0
  305. package/out-tsc/formatter/visitor/ddl/create-view.js +61 -0
  306. package/out-tsc/formatter/visitor/ddl/create-view.js.map +1 -0
  307. package/out-tsc/formatter/visitor/ddl/drop.d.ts +30 -0
  308. package/out-tsc/formatter/visitor/ddl/drop.d.ts.map +1 -0
  309. package/out-tsc/formatter/visitor/ddl/drop.js +69 -0
  310. package/out-tsc/formatter/visitor/ddl/drop.js.map +1 -0
  311. package/out-tsc/formatter/visitor/ddl/index.d.ts +10 -0
  312. package/out-tsc/formatter/visitor/ddl/index.d.ts.map +1 -0
  313. package/out-tsc/formatter/visitor/ddl/index.js +26 -0
  314. package/out-tsc/formatter/visitor/ddl/index.js.map +1 -0
  315. package/out-tsc/formatter/visitor/dml/delete.d.ts +26 -0
  316. package/out-tsc/formatter/visitor/dml/delete.d.ts.map +1 -0
  317. package/out-tsc/formatter/visitor/dml/delete.js +38 -0
  318. package/out-tsc/formatter/visitor/dml/delete.js.map +1 -0
  319. package/out-tsc/formatter/visitor/dml/index.d.ts +10 -0
  320. package/out-tsc/formatter/visitor/dml/index.d.ts.map +1 -0
  321. package/out-tsc/formatter/visitor/dml/index.js +26 -0
  322. package/out-tsc/formatter/visitor/dml/index.js.map +1 -0
  323. package/out-tsc/formatter/visitor/dml/insert.d.ts +42 -0
  324. package/out-tsc/formatter/visitor/dml/insert.d.ts.map +1 -0
  325. package/out-tsc/formatter/visitor/dml/insert.js +112 -0
  326. package/out-tsc/formatter/visitor/dml/insert.js.map +1 -0
  327. package/out-tsc/formatter/visitor/dml/merge.d.ts +40 -0
  328. package/out-tsc/formatter/visitor/dml/merge.d.ts.map +1 -0
  329. package/out-tsc/formatter/visitor/dml/merge.js +67 -0
  330. package/out-tsc/formatter/visitor/dml/merge.js.map +1 -0
  331. package/out-tsc/formatter/visitor/dml/update.d.ts +33 -0
  332. package/out-tsc/formatter/visitor/dml/update.d.ts.map +1 -0
  333. package/out-tsc/formatter/visitor/dml/update.js +49 -0
  334. package/out-tsc/formatter/visitor/dml/update.js.map +1 -0
  335. package/out-tsc/formatter/visitor/expression/arithmetic.d.ts +20 -0
  336. package/out-tsc/formatter/visitor/expression/arithmetic.d.ts.map +1 -0
  337. package/out-tsc/formatter/visitor/expression/arithmetic.js +44 -0
  338. package/out-tsc/formatter/visitor/expression/arithmetic.js.map +1 -0
  339. package/out-tsc/formatter/visitor/expression/case-when.d.ts +41 -0
  340. package/out-tsc/formatter/visitor/expression/case-when.d.ts.map +1 -0
  341. package/out-tsc/formatter/visitor/expression/case-when.js +94 -0
  342. package/out-tsc/formatter/visitor/expression/case-when.js.map +1 -0
  343. package/out-tsc/formatter/visitor/expression/comparison.d.ts +20 -0
  344. package/out-tsc/formatter/visitor/expression/comparison.d.ts.map +1 -0
  345. package/out-tsc/formatter/visitor/expression/comparison.js +26 -0
  346. package/out-tsc/formatter/visitor/expression/comparison.js.map +1 -0
  347. package/out-tsc/formatter/visitor/expression/function-call.d.ts +20 -0
  348. package/out-tsc/formatter/visitor/expression/function-call.d.ts.map +1 -0
  349. package/out-tsc/formatter/visitor/expression/function-call.js +33 -0
  350. package/out-tsc/formatter/visitor/expression/function-call.js.map +1 -0
  351. package/out-tsc/formatter/visitor/expression/index.d.ts +11 -0
  352. package/out-tsc/formatter/visitor/expression/index.d.ts.map +1 -0
  353. package/out-tsc/formatter/visitor/expression/index.js +27 -0
  354. package/out-tsc/formatter/visitor/expression/index.js.map +1 -0
  355. package/out-tsc/formatter/visitor/expression/logical.d.ts +26 -0
  356. package/out-tsc/formatter/visitor/expression/logical.d.ts.map +1 -0
  357. package/out-tsc/formatter/visitor/expression/logical.js +46 -0
  358. package/out-tsc/formatter/visitor/expression/logical.js.map +1 -0
  359. package/out-tsc/formatter/visitor/formatter-core.d.ts +79 -0
  360. package/out-tsc/formatter/visitor/formatter-core.d.ts.map +1 -0
  361. package/out-tsc/formatter/visitor/formatter-core.js +211 -0
  362. package/out-tsc/formatter/visitor/formatter-core.js.map +1 -0
  363. package/out-tsc/formatter/visitor/index.d.ts +21 -0
  364. package/out-tsc/formatter/visitor/index.d.ts.map +1 -0
  365. package/out-tsc/formatter/visitor/index.js +26 -0
  366. package/out-tsc/formatter/visitor/index.js.map +1 -0
  367. package/out-tsc/formatter/visitor/management/cache.d.ts +26 -0
  368. package/out-tsc/formatter/visitor/management/cache.d.ts.map +1 -0
  369. package/out-tsc/formatter/visitor/management/cache.js +58 -0
  370. package/out-tsc/formatter/visitor/management/cache.js.map +1 -0
  371. package/out-tsc/formatter/visitor/management/index.d.ts +8 -0
  372. package/out-tsc/formatter/visitor/management/index.d.ts.map +1 -0
  373. package/out-tsc/formatter/visitor/management/index.js +24 -0
  374. package/out-tsc/formatter/visitor/management/index.js.map +1 -0
  375. package/out-tsc/formatter/visitor/management/refresh.d.ts +26 -0
  376. package/out-tsc/formatter/visitor/management/refresh.d.ts.map +1 -0
  377. package/out-tsc/formatter/visitor/management/refresh.js +55 -0
  378. package/out-tsc/formatter/visitor/management/refresh.js.map +1 -0
  379. package/out-tsc/formatter/visitor/pipeline/delta-live-tables.d.ts +31 -0
  380. package/out-tsc/formatter/visitor/pipeline/delta-live-tables.d.ts.map +1 -0
  381. package/out-tsc/formatter/visitor/pipeline/delta-live-tables.js +46 -0
  382. package/out-tsc/formatter/visitor/pipeline/delta-live-tables.js.map +1 -0
  383. package/out-tsc/formatter/visitor/pipeline/index.d.ts +7 -0
  384. package/out-tsc/formatter/visitor/pipeline/index.d.ts.map +1 -0
  385. package/out-tsc/formatter/visitor/pipeline/index.js +23 -0
  386. package/out-tsc/formatter/visitor/pipeline/index.js.map +1 -0
  387. package/out-tsc/formatter/visitor/query/cte.d.ts +34 -0
  388. package/out-tsc/formatter/visitor/query/cte.d.ts.map +1 -0
  389. package/out-tsc/formatter/visitor/query/cte.js +54 -0
  390. package/out-tsc/formatter/visitor/query/cte.js.map +1 -0
  391. package/out-tsc/formatter/visitor/query/index.d.ts +11 -0
  392. package/out-tsc/formatter/visitor/query/index.d.ts.map +1 -0
  393. package/out-tsc/formatter/visitor/query/index.js +27 -0
  394. package/out-tsc/formatter/visitor/query/index.js.map +1 -0
  395. package/out-tsc/formatter/visitor/query/query-organization.d.ts +25 -0
  396. package/out-tsc/formatter/visitor/query/query-organization.d.ts.map +1 -0
  397. package/out-tsc/formatter/visitor/query/query-organization.js +75 -0
  398. package/out-tsc/formatter/visitor/query/query-organization.js.map +1 -0
  399. package/out-tsc/formatter/visitor/query/query.d.ts +22 -0
  400. package/out-tsc/formatter/visitor/query/query.d.ts.map +1 -0
  401. package/out-tsc/formatter/visitor/query/query.js +30 -0
  402. package/out-tsc/formatter/visitor/query/query.js.map +1 -0
  403. package/out-tsc/formatter/visitor/query/select-clause.d.ts +17 -0
  404. package/out-tsc/formatter/visitor/query/select-clause.d.ts.map +1 -0
  405. package/out-tsc/formatter/visitor/query/select-clause.js +35 -0
  406. package/out-tsc/formatter/visitor/query/select-clause.js.map +1 -0
  407. package/out-tsc/formatter/visitor/query/set-operation.d.ts +25 -0
  408. package/out-tsc/formatter/visitor/query/set-operation.d.ts.map +1 -0
  409. package/out-tsc/formatter/visitor/query/set-operation.js +52 -0
  410. package/out-tsc/formatter/visitor/query/set-operation.js.map +1 -0
  411. package/out-tsc/formatter/visitor/statements/index.d.ts +7 -0
  412. package/out-tsc/formatter/visitor/statements/index.d.ts.map +1 -0
  413. package/out-tsc/formatter/visitor/statements/index.js +23 -0
  414. package/out-tsc/formatter/visitor/statements/index.js.map +1 -0
  415. package/out-tsc/formatter/visitor/statements/program.d.ts +33 -0
  416. package/out-tsc/formatter/visitor/statements/program.d.ts.map +1 -0
  417. package/out-tsc/formatter/visitor/statements/program.js +69 -0
  418. package/out-tsc/formatter/visitor/statements/program.js.map +1 -0
  419. package/out-tsc/formatter/visitor/types/complex-types.d.ts +24 -0
  420. package/out-tsc/formatter/visitor/types/complex-types.d.ts.map +1 -0
  421. package/out-tsc/formatter/visitor/types/complex-types.js +47 -0
  422. package/out-tsc/formatter/visitor/types/complex-types.js.map +1 -0
  423. package/out-tsc/formatter/visitor/types/index.d.ts +8 -0
  424. package/out-tsc/formatter/visitor/types/index.d.ts.map +1 -0
  425. package/out-tsc/formatter/visitor/types/index.js +24 -0
  426. package/out-tsc/formatter/visitor/types/index.js.map +1 -0
  427. package/out-tsc/formatter/visitor/types/primitive-types.d.ts +22 -0
  428. package/out-tsc/formatter/visitor/types/primitive-types.d.ts.map +1 -0
  429. package/out-tsc/formatter/visitor/types/primitive-types.js +37 -0
  430. package/out-tsc/formatter/visitor/types/primitive-types.js.map +1 -0
  431. package/out-tsc/formatter/visitor/utils/context-helpers.d.ts +32 -0
  432. package/out-tsc/formatter/visitor/utils/context-helpers.d.ts.map +1 -0
  433. package/out-tsc/formatter/visitor/utils/context-helpers.js +98 -0
  434. package/out-tsc/formatter/visitor/utils/context-helpers.js.map +1 -0
  435. package/out-tsc/formatter/visitor/utils/index.d.ts +11 -0
  436. package/out-tsc/formatter/visitor/utils/index.d.ts.map +1 -0
  437. package/out-tsc/formatter/visitor/utils/index.js +45 -0
  438. package/out-tsc/formatter/visitor/utils/index.js.map +1 -0
  439. package/out-tsc/formatter/visitor/utils/keyword-formatting.d.ts +57 -0
  440. package/out-tsc/formatter/visitor/utils/keyword-formatting.d.ts.map +1 -0
  441. package/out-tsc/formatter/visitor/utils/keyword-formatting.js +87 -0
  442. package/out-tsc/formatter/visitor/utils/keyword-formatting.js.map +1 -0
  443. package/out-tsc/formatter/visitor/utils/parenthesis-formatting.d.ts +53 -0
  444. package/out-tsc/formatter/visitor/utils/parenthesis-formatting.d.ts.map +1 -0
  445. package/out-tsc/formatter/visitor/utils/parenthesis-formatting.js +88 -0
  446. package/out-tsc/formatter/visitor/utils/parenthesis-formatting.js.map +1 -0
  447. package/out-tsc/formatter/visitor/utils/space-compression.d.ts +55 -0
  448. package/out-tsc/formatter/visitor/utils/space-compression.d.ts.map +1 -0
  449. package/out-tsc/formatter/visitor/utils/space-compression.js +71 -0
  450. package/out-tsc/formatter/visitor/utils/space-compression.js.map +1 -0
  451. package/out-tsc/formatter/visitor/utils/token-helpers.d.ts +64 -0
  452. package/out-tsc/formatter/visitor/utils/token-helpers.d.ts.map +1 -0
  453. package/out-tsc/formatter/visitor/utils/token-helpers.js +249 -0
  454. package/out-tsc/formatter/visitor/utils/token-helpers.js.map +1 -0
  455. package/out-tsc/index.d.ts +2 -1
  456. package/out-tsc/index.d.ts.map +1 -0
  457. package/out-tsc/index.js +3 -1
  458. package/out-tsc/index.js.map +1 -1
  459. package/out-tsc/lib/SparkSQLLexer.d.ts +557 -0
  460. package/out-tsc/lib/SparkSQLLexer.d.ts.map +1 -0
  461. package/out-tsc/lib/SparkSQLLexer.js +3676 -0
  462. package/out-tsc/lib/SparkSQLLexer.js.map +1 -0
  463. package/out-tsc/lib/SparkSQLParser.d.ts +7884 -0
  464. package/out-tsc/lib/SparkSQLParser.d.ts.map +1 -0
  465. package/out-tsc/lib/SparkSQLParser.js +45848 -0
  466. package/out-tsc/lib/SparkSQLParser.js.map +1 -0
  467. package/out-tsc/lib/SparkSQLParserListener.d.ts +5855 -0
  468. package/out-tsc/lib/SparkSQLParserListener.d.ts.map +1 -0
  469. package/out-tsc/lib/SparkSQLParserListener.js +4 -0
  470. package/out-tsc/lib/SparkSQLParserListener.js.map +1 -0
  471. package/out-tsc/lib/SparkSQLParserVisitor.d.ts +3674 -0
  472. package/out-tsc/lib/SparkSQLParserVisitor.d.ts.map +1 -0
  473. package/out-tsc/lib/SparkSQLParserVisitor.js +4 -0
  474. package/out-tsc/lib/SparkSQLParserVisitor.js.map +1 -0
  475. package/out-tsc/lineage.typing.d.ts +64 -0
  476. package/out-tsc/lineage.typing.d.ts.map +1 -0
  477. package/out-tsc/lineage.typing.js +3 -0
  478. package/out-tsc/lineage.typing.js.map +1 -0
  479. package/out-tsc/listeners/parse-error.listener.d.ts +3 -2
  480. package/out-tsc/listeners/parse-error.listener.d.ts.map +1 -0
  481. package/out-tsc/listeners/parse-error.listener.js +4 -4
  482. package/out-tsc/listeners/parse-error.listener.js.map +1 -1
  483. package/out-tsc/listeners/schema.listener.d.ts +32 -39
  484. package/out-tsc/listeners/schema.listener.d.ts.map +1 -0
  485. package/out-tsc/listeners/schema.listener.js +58 -100
  486. package/out-tsc/listeners/schema.listener.js.map +1 -1
  487. package/out-tsc/listeners/statement.listener.d.ts +263 -5
  488. package/out-tsc/listeners/statement.listener.d.ts.map +1 -0
  489. package/out-tsc/listeners/statement.listener.js +836 -11
  490. package/out-tsc/listeners/statement.listener.js.map +1 -1
  491. package/out-tsc/listeners/structure.listener.d.ts +70 -0
  492. package/out-tsc/listeners/structure.listener.d.ts.map +1 -0
  493. package/out-tsc/listeners/structure.listener.js +211 -0
  494. package/out-tsc/listeners/structure.listener.js.map +1 -0
  495. package/out-tsc/listeners/tokens-collector.listener.d.ts +27 -0
  496. package/out-tsc/listeners/tokens-collector.listener.d.ts.map +1 -0
  497. package/out-tsc/listeners/tokens-collector.listener.js +102 -0
  498. package/out-tsc/listeners/tokens-collector.listener.js.map +1 -0
  499. package/out-tsc/lsp-server.d.ts +79 -8
  500. package/out-tsc/lsp-server.d.ts.map +1 -0
  501. package/out-tsc/lsp-server.js +672 -237
  502. package/out-tsc/lsp-server.js.map +1 -1
  503. package/out-tsc/metadata.typing.d.ts +1 -0
  504. package/out-tsc/metadata.typing.d.ts.map +1 -0
  505. package/out-tsc/monaco-config.d.ts +219 -0
  506. package/out-tsc/monaco-config.d.ts.map +1 -0
  507. package/out-tsc/monaco-config.js +1032 -0
  508. package/out-tsc/monaco-config.js.map +1 -0
  509. package/out-tsc/parsing-warehouse.d.ts +8 -3
  510. package/out-tsc/parsing-warehouse.d.ts.map +1 -0
  511. package/out-tsc/parsing-warehouse.js +62 -6
  512. package/out-tsc/parsing-warehouse.js.map +1 -1
  513. package/out-tsc/protocol-translation.d.ts +12 -5
  514. package/out-tsc/protocol-translation.d.ts.map +1 -0
  515. package/out-tsc/protocol-translation.js +72 -19
  516. package/out-tsc/protocol-translation.js.map +1 -1
  517. package/out-tsc/public-apis.d.ts +1 -0
  518. package/out-tsc/public-apis.d.ts.map +1 -0
  519. package/out-tsc/schema-registry.d.ts +10 -7
  520. package/out-tsc/schema-registry.d.ts.map +1 -0
  521. package/out-tsc/schema-registry.js +87 -106
  522. package/out-tsc/schema-registry.js.map +1 -1
  523. package/out-tsc/server-worker.d.ts +1 -0
  524. package/out-tsc/server-worker.d.ts.map +1 -0
  525. package/out-tsc/server-worker.js +159 -44
  526. package/out-tsc/server-worker.js.map +1 -1
  527. package/out-tsc/tests/folding/block-comment-folding.test.d.ts +7 -0
  528. package/out-tsc/tests/folding/block-comment-folding.test.d.ts.map +1 -0
  529. package/out-tsc/tests/folding/block-comment-folding.test.js +268 -0
  530. package/out-tsc/tests/folding/block-comment-folding.test.js.map +1 -0
  531. package/out-tsc/tests/folding/caching.test.d.ts +11 -0
  532. package/out-tsc/tests/folding/caching.test.d.ts.map +1 -0
  533. package/out-tsc/tests/folding/caching.test.js +141 -0
  534. package/out-tsc/tests/folding/caching.test.js.map +1 -0
  535. package/out-tsc/tests/folding/cte-dependency-chain.test.d.ts +15 -0
  536. package/out-tsc/tests/folding/cte-dependency-chain.test.d.ts.map +1 -0
  537. package/out-tsc/tests/folding/cte-dependency-chain.test.js +323 -0
  538. package/out-tsc/tests/folding/cte-dependency-chain.test.js.map +1 -0
  539. package/out-tsc/tests/folding/debug-format-flow.test.d.ts +2 -0
  540. package/out-tsc/tests/folding/debug-format-flow.test.d.ts.map +1 -0
  541. package/out-tsc/tests/folding/debug-format-flow.test.js +114 -0
  542. package/out-tsc/tests/folding/debug-format-flow.test.js.map +1 -0
  543. package/out-tsc/tests/folding/debug-formatted.test.d.ts +2 -0
  544. package/out-tsc/tests/folding/debug-formatted.test.d.ts.map +1 -0
  545. package/out-tsc/tests/folding/debug-formatted.test.js +175 -0
  546. package/out-tsc/tests/folding/debug-formatted.test.js.map +1 -0
  547. package/out-tsc/tests/folding/deduplication.test.d.ts +10 -0
  548. package/out-tsc/tests/folding/deduplication.test.d.ts.map +1 -0
  549. package/out-tsc/tests/folding/deduplication.test.js +206 -0
  550. package/out-tsc/tests/folding/deduplication.test.js.map +1 -0
  551. package/out-tsc/tests/folding/edge-cases.test.d.ts +8 -0
  552. package/out-tsc/tests/folding/edge-cases.test.d.ts.map +1 -0
  553. package/out-tsc/tests/folding/edge-cases.test.js +319 -0
  554. package/out-tsc/tests/folding/edge-cases.test.js.map +1 -0
  555. package/out-tsc/tests/folding/folding-level-config.test.d.ts +11 -0
  556. package/out-tsc/tests/folding/folding-level-config.test.d.ts.map +1 -0
  557. package/out-tsc/tests/folding/folding-level-config.test.js +313 -0
  558. package/out-tsc/tests/folding/folding-level-config.test.js.map +1 -0
  559. package/out-tsc/tests/folding/folding-statistics.test.d.ts +13 -0
  560. package/out-tsc/tests/folding/folding-statistics.test.d.ts.map +1 -0
  561. package/out-tsc/tests/folding/folding-statistics.test.js +144 -0
  562. package/out-tsc/tests/folding/folding-statistics.test.js.map +1 -0
  563. package/out-tsc/tests/folding/index.d.ts +8 -0
  564. package/out-tsc/tests/folding/index.d.ts.map +1 -0
  565. package/out-tsc/tests/folding/index.js +24 -0
  566. package/out-tsc/tests/folding/index.js.map +1 -0
  567. package/out-tsc/tests/folding/join-folding.test.d.ts +11 -0
  568. package/out-tsc/tests/folding/join-folding.test.d.ts.map +1 -0
  569. package/out-tsc/tests/folding/join-folding.test.js +167 -0
  570. package/out-tsc/tests/folding/join-folding.test.js.map +1 -0
  571. package/out-tsc/tests/folding/kind-classification.test.d.ts +11 -0
  572. package/out-tsc/tests/folding/kind-classification.test.d.ts.map +1 -0
  573. package/out-tsc/tests/folding/kind-classification.test.js +270 -0
  574. package/out-tsc/tests/folding/kind-classification.test.js.map +1 -0
  575. package/out-tsc/tests/folding/level1-statement.test.d.ts +8 -0
  576. package/out-tsc/tests/folding/level1-statement.test.d.ts.map +1 -0
  577. package/out-tsc/tests/folding/level1-statement.test.js +278 -0
  578. package/out-tsc/tests/folding/level1-statement.test.js.map +1 -0
  579. package/out-tsc/tests/folding/level2-query-block.test.d.ts +8 -0
  580. package/out-tsc/tests/folding/level2-query-block.test.d.ts.map +1 -0
  581. package/out-tsc/tests/folding/level2-query-block.test.js +374 -0
  582. package/out-tsc/tests/folding/level2-query-block.test.js.map +1 -0
  583. package/out-tsc/tests/folding/level3-expression.test.d.ts +8 -0
  584. package/out-tsc/tests/folding/level3-expression.test.d.ts.map +1 -0
  585. package/out-tsc/tests/folding/level3-expression.test.js +361 -0
  586. package/out-tsc/tests/folding/level3-expression.test.js.map +1 -0
  587. package/out-tsc/tests/folding/level4-structure.test.d.ts +8 -0
  588. package/out-tsc/tests/folding/level4-structure.test.d.ts.map +1 -0
  589. package/out-tsc/tests/folding/level4-structure.test.js +270 -0
  590. package/out-tsc/tests/folding/level4-structure.test.js.map +1 -0
  591. package/out-tsc/tests/folding/line-comment-folding.test.d.ts +13 -0
  592. package/out-tsc/tests/folding/line-comment-folding.test.d.ts.map +1 -0
  593. package/out-tsc/tests/folding/line-comment-folding.test.js +215 -0
  594. package/out-tsc/tests/folding/line-comment-folding.test.js.map +1 -0
  595. package/out-tsc/tests/folding/nested-folding.test.d.ts +8 -0
  596. package/out-tsc/tests/folding/nested-folding.test.d.ts.map +1 -0
  597. package/out-tsc/tests/folding/nested-folding.test.js +386 -0
  598. package/out-tsc/tests/folding/nested-folding.test.js.map +1 -0
  599. package/out-tsc/tests/folding/performance-benchmark.test.d.ts +11 -0
  600. package/out-tsc/tests/folding/performance-benchmark.test.d.ts.map +1 -0
  601. package/out-tsc/tests/folding/performance-benchmark.test.js +256 -0
  602. package/out-tsc/tests/folding/performance-benchmark.test.js.map +1 -0
  603. package/out-tsc/tests/folding/region-marker-folding.test.d.ts +11 -0
  604. package/out-tsc/tests/folding/region-marker-folding.test.d.ts.map +1 -0
  605. package/out-tsc/tests/folding/region-marker-folding.test.js +245 -0
  606. package/out-tsc/tests/folding/region-marker-folding.test.js.map +1 -0
  607. package/out-tsc/tests/folding/select-columns-folding.test.d.ts +10 -0
  608. package/out-tsc/tests/folding/select-columns-folding.test.d.ts.map +1 -0
  609. package/out-tsc/tests/folding/select-columns-folding.test.js +139 -0
  610. package/out-tsc/tests/folding/select-columns-folding.test.js.map +1 -0
  611. package/out-tsc/tests/folding/test-utils.d.ts +73 -0
  612. package/out-tsc/tests/folding/test-utils.d.ts.map +1 -0
  613. package/out-tsc/tests/folding/test-utils.js +98 -0
  614. package/out-tsc/tests/folding/test-utils.js.map +1 -0
  615. package/out-tsc/tests/folding/values-folding.test.d.ts +10 -0
  616. package/out-tsc/tests/folding/values-folding.test.d.ts.map +1 -0
  617. package/out-tsc/tests/folding/values-folding.test.js +102 -0
  618. package/out-tsc/tests/folding/values-folding.test.js.map +1 -0
  619. package/out-tsc/tests/format/ddl/datatype-constraint.test.d.ts +5 -0
  620. package/out-tsc/tests/format/ddl/datatype-constraint.test.d.ts.map +1 -0
  621. package/out-tsc/tests/format/ddl/datatype-constraint.test.js +132 -0
  622. package/out-tsc/tests/format/ddl/datatype-constraint.test.js.map +1 -0
  623. package/out-tsc/tests/format/ddl/index.test.d.ts +5 -0
  624. package/out-tsc/tests/format/ddl/index.test.d.ts.map +1 -0
  625. package/out-tsc/tests/format/ddl/index.test.js +74 -0
  626. package/out-tsc/tests/format/ddl/index.test.js.map +1 -0
  627. package/out-tsc/tests/format/ddl/materialized-view.test.d.ts +5 -0
  628. package/out-tsc/tests/format/ddl/materialized-view.test.d.ts.map +1 -0
  629. package/out-tsc/tests/format/ddl/materialized-view.test.js +92 -0
  630. package/out-tsc/tests/format/ddl/materialized-view.test.js.map +1 -0
  631. package/out-tsc/tests/format/ddl/partition.test.d.ts +5 -0
  632. package/out-tsc/tests/format/ddl/partition.test.d.ts.map +1 -0
  633. package/out-tsc/tests/format/ddl/partition.test.js +109 -0
  634. package/out-tsc/tests/format/ddl/partition.test.js.map +1 -0
  635. package/out-tsc/tests/format/ddl/variable.test.d.ts +5 -0
  636. package/out-tsc/tests/format/ddl/variable.test.d.ts.map +1 -0
  637. package/out-tsc/tests/format/ddl/variable.test.js +58 -0
  638. package/out-tsc/tests/format/ddl/variable.test.js.map +1 -0
  639. package/out-tsc/tests/format/dml/select.test.d.ts +5 -0
  640. package/out-tsc/tests/format/dml/select.test.d.ts.map +1 -0
  641. package/out-tsc/tests/format/dml/select.test.js +114 -0
  642. package/out-tsc/tests/format/dml/select.test.js.map +1 -0
  643. package/out-tsc/tests/format/dml/subquery.test.d.ts +5 -0
  644. package/out-tsc/tests/format/dml/subquery.test.d.ts.map +1 -0
  645. package/out-tsc/tests/format/dml/subquery.test.js +221 -0
  646. package/out-tsc/tests/format/dml/subquery.test.js.map +1 -0
  647. package/out-tsc/tests/format/dql/comment.test.d.ts +7 -0
  648. package/out-tsc/tests/format/dql/comment.test.d.ts.map +1 -0
  649. package/out-tsc/tests/format/dql/comment.test.js +279 -0
  650. package/out-tsc/tests/format/dql/comment.test.js.map +1 -0
  651. package/out-tsc/tests/format/dql/cte.test.d.ts +7 -0
  652. package/out-tsc/tests/format/dql/cte.test.d.ts.map +1 -0
  653. package/out-tsc/tests/format/dql/cte.test.js +31 -0
  654. package/out-tsc/tests/format/dql/cte.test.js.map +1 -0
  655. package/out-tsc/tests/format/dql/dql-detail.test.d.ts +5 -0
  656. package/out-tsc/tests/format/dql/dql-detail.test.d.ts.map +1 -0
  657. package/out-tsc/tests/format/dql/dql-detail.test.js +191 -0
  658. package/out-tsc/tests/format/dql/dql-detail.test.js.map +1 -0
  659. package/out-tsc/tests/format/dql/lateral-view.test.d.ts +7 -0
  660. package/out-tsc/tests/format/dql/lateral-view.test.d.ts.map +1 -0
  661. package/out-tsc/tests/format/dql/lateral-view.test.js +34 -0
  662. package/out-tsc/tests/format/dql/lateral-view.test.js.map +1 -0
  663. package/out-tsc/tests/format/dql/pivot.test.d.ts +7 -0
  664. package/out-tsc/tests/format/dql/pivot.test.d.ts.map +1 -0
  665. package/out-tsc/tests/format/dql/pivot.test.js +56 -0
  666. package/out-tsc/tests/format/dql/pivot.test.js.map +1 -0
  667. package/out-tsc/tests/format/dql/window.test.d.ts +7 -0
  668. package/out-tsc/tests/format/dql/window.test.d.ts.map +1 -0
  669. package/out-tsc/tests/format/dql/window.test.js +89 -0
  670. package/out-tsc/tests/format/dql/window.test.js.map +1 -0
  671. package/out-tsc/tests/format/expression/expression.test.d.ts +5 -0
  672. package/out-tsc/tests/format/expression/expression.test.d.ts.map +1 -0
  673. package/out-tsc/tests/format/expression/expression.test.js +203 -0
  674. package/out-tsc/tests/format/expression/expression.test.js.map +1 -0
  675. package/out-tsc/tests/format/pipe/pipe-operator.test.d.ts +5 -0
  676. package/out-tsc/tests/format/pipe/pipe-operator.test.d.ts.map +1 -0
  677. package/out-tsc/tests/format/pipe/pipe-operator.test.js +290 -0
  678. package/out-tsc/tests/format/pipe/pipe-operator.test.js.map +1 -0
  679. package/out-tsc/tests/format/procedure/compound-statement.test.d.ts +16 -0
  680. package/out-tsc/tests/format/procedure/compound-statement.test.d.ts.map +1 -0
  681. package/out-tsc/tests/format/procedure/compound-statement.test.js +254 -0
  682. package/out-tsc/tests/format/procedure/compound-statement.test.js.map +1 -0
  683. package/out-tsc/tests/format/resource/resource.test.d.ts +5 -0
  684. package/out-tsc/tests/format/resource/resource.test.d.ts.map +1 -0
  685. package/out-tsc/tests/format/resource/resource.test.js +69 -0
  686. package/out-tsc/tests/format/resource/resource.test.js.map +1 -0
  687. package/out-tsc/tests/format/test-utils.d.ts +40 -0
  688. package/out-tsc/tests/format/test-utils.d.ts.map +1 -0
  689. package/out-tsc/tests/format/test-utils.js +53 -0
  690. package/out-tsc/tests/format/test-utils.js.map +1 -0
  691. package/out-tsc/tests/lsp-server.test.d.ts +2 -0
  692. package/out-tsc/tests/lsp-server.test.d.ts.map +1 -0
  693. package/out-tsc/tests/lsp-server.test.js +1525 -0
  694. package/out-tsc/tests/lsp-server.test.js.map +1 -0
  695. package/out-tsc/tests/spark-sql-inputs.test.d.ts +17 -0
  696. package/out-tsc/tests/spark-sql-inputs.test.d.ts.map +1 -0
  697. package/out-tsc/tests/spark-sql-inputs.test.js +570 -0
  698. package/out-tsc/tests/spark-sql-inputs.test.js.map +1 -0
  699. package/out-tsc/tests/validation.test.d.ts +2 -0
  700. package/out-tsc/tests/validation.test.d.ts.map +1 -0
  701. package/out-tsc/tests/validation.test.js +115 -0
  702. package/out-tsc/tests/validation.test.js.map +1 -0
  703. package/out-tsc/typings.d.ts +115 -1
  704. package/out-tsc/typings.d.ts.map +1 -0
  705. package/out-tsc/typings.js +28 -0
  706. package/out-tsc/typings.js.map +1 -1
  707. package/out-tsc/utils.d.ts +1 -0
  708. package/out-tsc/utils.d.ts.map +1 -0
  709. package/out-tsc/utils.js +4 -5
  710. package/out-tsc/utils.js.map +1 -1
  711. package/out-tsc/visitors/completion.visitor.d.ts +85 -0
  712. package/out-tsc/visitors/completion.visitor.d.ts.map +1 -0
  713. package/out-tsc/visitors/completion.visitor.js +379 -0
  714. package/out-tsc/visitors/completion.visitor.js.map +1 -0
  715. package/out-tsc/visitors/lineage.visitor.d.ts +34 -0
  716. package/out-tsc/visitors/lineage.visitor.d.ts.map +1 -0
  717. package/out-tsc/visitors/lineage.visitor.js +181 -0
  718. package/out-tsc/visitors/lineage.visitor.js.map +1 -0
  719. package/out-tsc/visitors/space-replacer-format.visitor.d.ts +1641 -0
  720. package/out-tsc/visitors/space-replacer-format.visitor.d.ts.map +1 -0
  721. package/out-tsc/visitors/space-replacer-format.visitor.js +7529 -0
  722. package/out-tsc/visitors/space-replacer-format.visitor.js.map +1 -0
  723. package/out-tsc/visitors/sparksql-relation.visitor.d.ts +154 -0
  724. package/out-tsc/visitors/sparksql-relation.visitor.d.ts.map +1 -0
  725. package/out-tsc/visitors/sparksql-relation.visitor.js +749 -0
  726. package/out-tsc/visitors/sparksql-relation.visitor.js.map +1 -0
  727. package/package.json +36 -9
  728. package/out-tsc/constant.d.ts +0 -3
  729. package/out-tsc/constant.js +0 -7
  730. package/out-tsc/constant.js.map +0 -1
  731. package/out-tsc/lib/SparkSqlLexer.d.ts +0 -421
  732. package/out-tsc/lib/SparkSqlLexer.js +0 -2750
  733. package/out-tsc/lib/SparkSqlLexer.js.map +0 -1
  734. package/out-tsc/lib/SparkSqlParser.d.ts +0 -6203
  735. package/out-tsc/lib/SparkSqlParser.js +0 -34733
  736. package/out-tsc/lib/SparkSqlParser.js.map +0 -1
  737. package/out-tsc/lib/SparkSqlParserListener.d.ts +0 -1158
  738. package/out-tsc/lib/SparkSqlParserListener.js.map +0 -1
  739. package/out-tsc/lib/SparkSqlParserVisitor.d.ts +0 -773
  740. package/out-tsc/lib/SparkSqlParserVisitor.js.map +0 -1
@@ -0,0 +1,3808 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StrategyBasedFormatter = void 0;
4
+ const ParserRuleContext_1 = require("antlr4ts/ParserRuleContext");
5
+ const tree_1 = require("antlr4ts/tree");
6
+ const core_1 = require("./core");
7
+ const strategies_1 = require("./strategies");
8
+ const block_strategy_1 = require("./strategies/block.strategy");
9
+ const SparkSQLLexer_1 = require("../lib/SparkSQLLexer");
10
+ const SparkSQLParser_1 = require("../lib/SparkSQLParser");
11
+ const typings_1 = require("../typings");
12
+ /**
13
+ * Strategy-based SQL Formatter
14
+ *
15
+ * Uses a registry of strategies to format different SQL statement types.
16
+ */
17
+ class StrategyBasedFormatter extends tree_1.AbstractParseTreeVisitor {
18
+ constructor(tokens, config) {
19
+ super();
20
+ this.tokens = tokens;
21
+ this.config = config;
22
+ this.textEdits = [];
23
+ this.formattingErrors = [];
24
+ this.editCollector = new core_1.EditCollector();
25
+ this.blockStrategy = new block_strategy_1.BlockStrategy();
26
+ // Legacy flags for compatibility during transition
27
+ this.inPipeOperatorRightSide = false;
28
+ this.inPipeSubquery = false;
29
+ this.inWindowClause = false;
30
+ this.inUnpivotLongContent = false;
31
+ this.newline = '\n';
32
+ this.context = new core_1.FormattingContext(config.tabSize);
33
+ this.maxParenthesisLength = config.maxParenthesisLength ?? typings_1.DEFAULT_MAX_PARENTHESIS_LENGTH;
34
+ this.strategies = [...strategies_1.allStrategies];
35
+ // Create bridge with visitor reference
36
+ this.bridge = new core_1.StrategyFormattingBridge({
37
+ tokens: this.tokens,
38
+ context: this.context,
39
+ collector: this.editCollector,
40
+ visitor: {
41
+ visit: ctx => this.visit(ctx),
42
+ visitChildren: ctx => this.visitChildren(ctx)
43
+ }
44
+ });
45
+ }
46
+ /**
47
+ * Get formatted text edits
48
+ */
49
+ getTextEdits() {
50
+ return this.textEdits;
51
+ }
52
+ /**
53
+ * Process the parse tree and collect edits
54
+ */
55
+ format(ctx) {
56
+ this.textEdits = [];
57
+ this.formattingErrors = [];
58
+ this.editCollector.clear();
59
+ // Visit the tree
60
+ this.visit(ctx);
61
+ // Post-processing: normalize keyword spacing
62
+ this.normalizeAllKeywordSpacing();
63
+ // Post-processing: compress consecutive spaces
64
+ this.compressConsecutiveSpaces();
65
+ // Post-processing: clean parentheses spaces and comma spaces
66
+ this.cleanParenthesesSpaces();
67
+ // Collect all edits
68
+ this.textEdits = this.editCollector.getEdits();
69
+ return this.textEdits;
70
+ }
71
+ defaultResult() {
72
+ return;
73
+ }
74
+ // ==================== Strategy Dispatch ====================
75
+ /**
76
+ * Try to format using registered strategies, fallback to default behavior
77
+ */
78
+ tryFormatWithStrategy(ctx) {
79
+ for (const strategy of this.strategies) {
80
+ if (strategy.canHandle(ctx)) {
81
+ try {
82
+ strategy.format(ctx, this.bridge);
83
+ return true;
84
+ }
85
+ catch (error) {
86
+ // Log error but continue
87
+ const errorMessage = error instanceof Error ? error.message : String(error);
88
+ this.formattingErrors.push({
89
+ message: `Strategy ${strategy.id} failed: ${errorMessage}`,
90
+ line: ctx.start.line - 1
91
+ });
92
+ }
93
+ }
94
+ }
95
+ return false;
96
+ }
97
+ // ==================== Program & Statements ====================
98
+ visitProgram(ctx) {
99
+ const statements = ctx.statements();
100
+ if (statements) {
101
+ this.visit(statements);
102
+ }
103
+ this.compressConsecutiveSpaces();
104
+ }
105
+ visitStatements(ctx) {
106
+ const stmtForFoldings = ctx.statementForFolding();
107
+ stmtForFoldings.forEach((sff, index) => {
108
+ if (index > 0) {
109
+ // Handle statement separation
110
+ const prevStmt = stmtForFoldings[index - 1];
111
+ const prevStmtEnd = prevStmt._stop?.stopIndex ?? 0;
112
+ const currStmtStart = sff._start?.startIndex ?? 0;
113
+ const commentsBetween = this.findCommentTokensBetween(prevStmtEnd + 1, currStmtStart);
114
+ if (commentsBetween.length > 0) {
115
+ const firstComment = commentsBetween[0];
116
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(firstComment.startIndex);
117
+ if (prevToken) {
118
+ const prevEndPos = this.getTokenEndPosition(prevToken);
119
+ this.addTextEdit({
120
+ range: {
121
+ start: prevEndPos,
122
+ end: { line: firstComment.line - 1, character: firstComment.charPositionInLine }
123
+ },
124
+ newText: this.newline
125
+ });
126
+ }
127
+ }
128
+ else {
129
+ const prevStmt = stmtForFoldings[index - 1];
130
+ if (prevStmt._stop) {
131
+ const prevStmtEndIndex = prevStmt._stop.stopIndex;
132
+ const currStmtStartIndex = sff._start?.startIndex ?? 0;
133
+ const allTokens = this.tokens.getTokens();
134
+ let semicolonToken;
135
+ for (const token of allTokens) {
136
+ if (token.startIndex > prevStmtEndIndex && token.startIndex < currStmtStartIndex) {
137
+ if (token.channel === 0 && token.text === ';') {
138
+ semicolonToken = token;
139
+ break;
140
+ }
141
+ }
142
+ }
143
+ if (semicolonToken) {
144
+ const semicolonEndPos = this.getTokenEndPosition(semicolonToken);
145
+ const currStmtRange = { start: { line: sff.start.line - 1, character: sff.start.charPositionInLine } };
146
+ this.addTextEdit({
147
+ range: { start: semicolonEndPos, end: currStmtRange.start },
148
+ newText: this.newline.repeat(2)
149
+ });
150
+ }
151
+ }
152
+ }
153
+ }
154
+ try {
155
+ this.visit(sff);
156
+ }
157
+ catch (error) {
158
+ const errorMessage = error instanceof Error ? error.message : String(error);
159
+ this.formattingErrors.push({
160
+ message: `Statement formatting failed: ${errorMessage}`,
161
+ line: sff.start.line - 1
162
+ });
163
+ }
164
+ });
165
+ ctx.statementEnd().forEach(stmtEnd => this.visit(stmtEnd));
166
+ }
167
+ visitStatementEnd(ctx) {
168
+ const semicolon = ctx.SEMICOLON();
169
+ if (semicolon) {
170
+ // Clean whitespace before semicolon
171
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(semicolon.symbol.startIndex);
172
+ if (prevToken) {
173
+ const prevEndPos = this.getTokenEndPosition(prevToken);
174
+ this.addTextEdit({
175
+ range: {
176
+ start: prevEndPos,
177
+ end: { line: semicolon.symbol.line - 1, character: semicolon.symbol.charPositionInLine }
178
+ },
179
+ newText: ''
180
+ });
181
+ }
182
+ // Clean whitespace after semicolon (before comment on same line)
183
+ const allTokens = this.tokens.getTokens();
184
+ const semicolonIdx = allTokens.indexOf(semicolon.symbol);
185
+ const semicolonEndPos = this.getTokenEndPosition(semicolon.symbol);
186
+ for (let i = semicolonIdx + 1; i < allTokens.length; i++) {
187
+ const token = allTokens[i];
188
+ // Skip EOF
189
+ if (token.type === 0)
190
+ break;
191
+ // Skip only whitespace tokens - comments (channel 1) should be preserved
192
+ if (token.channel === 1 && token.text?.trim() === '')
193
+ continue;
194
+ // Found next meaningful token on same line (comment or other)
195
+ if (token.line === semicolon.symbol.line) {
196
+ const nextTokenStartPos = {
197
+ line: token.line - 1,
198
+ character: token.charPositionInLine
199
+ };
200
+ // Only add edit if there's actual whitespace to clean
201
+ if (semicolonEndPos.character < nextTokenStartPos.character) {
202
+ this.addTextEdit({
203
+ range: {
204
+ start: semicolonEndPos,
205
+ end: nextTokenStartPos
206
+ },
207
+ newText: ' '
208
+ });
209
+ }
210
+ break;
211
+ }
212
+ // Token on different line - stop looking
213
+ break;
214
+ }
215
+ }
216
+ }
217
+ visitStatementForFolding(ctx) {
218
+ // Delegate to the inner statement, setResetStatement, or compoundStatement
219
+ const stmt = ctx.statement();
220
+ const setResetStmt = ctx.setResetStatement();
221
+ const compoundStmt = ctx.compoundStatement();
222
+ if (stmt) {
223
+ this.visit(stmt);
224
+ }
225
+ else if (setResetStmt) {
226
+ this.visit(setResetStmt);
227
+ }
228
+ else if (compoundStmt) {
229
+ this.visit(compoundStmt);
230
+ }
231
+ }
232
+ // ==================== DDL Statements ====================
233
+ visitCreateTable(ctx) {
234
+ if (!this.tryFormatWithStrategy(ctx)) {
235
+ super.visitChildren(ctx);
236
+ }
237
+ }
238
+ visitCreateTableLike(ctx) {
239
+ if (!this.tryFormatWithStrategy(ctx)) {
240
+ super.visitChildren(ctx);
241
+ }
242
+ }
243
+ visitCreateTableHeader(ctx) {
244
+ if (!this.tryFormatWithStrategy(ctx)) {
245
+ super.visitChildren(ctx);
246
+ }
247
+ }
248
+ visitCreateTableClauses(ctx) {
249
+ if (!this.tryFormatWithStrategy(ctx)) {
250
+ super.visitChildren(ctx);
251
+ }
252
+ }
253
+ visitTableProvider(ctx) {
254
+ if (!this.tryFormatWithStrategy(ctx)) {
255
+ super.visitChildren(ctx);
256
+ }
257
+ }
258
+ visitTableElementList(ctx) {
259
+ if (!this.tryFormatWithStrategy(ctx)) {
260
+ super.visitChildren(ctx);
261
+ }
262
+ }
263
+ visitColDefinition(ctx) {
264
+ if (!this.tryFormatWithStrategy(ctx)) {
265
+ super.visitChildren(ctx);
266
+ }
267
+ }
268
+ visitReplaceTable(ctx) {
269
+ if (!this.tryFormatWithStrategy(ctx)) {
270
+ super.visitChildren(ctx);
271
+ }
272
+ }
273
+ visitReplaceTableHeader(ctx) {
274
+ if (!this.tryFormatWithStrategy(ctx)) {
275
+ super.visitChildren(ctx);
276
+ }
277
+ }
278
+ visitCreatePipelineDataset(ctx) {
279
+ if (!this.tryFormatWithStrategy(ctx)) {
280
+ super.visitChildren(ctx);
281
+ }
282
+ }
283
+ visitCreatePipelineDatasetHeader(ctx) {
284
+ if (!this.tryFormatWithStrategy(ctx)) {
285
+ super.visitChildren(ctx);
286
+ }
287
+ }
288
+ visitCreatePipelineInsertIntoFlow(ctx) {
289
+ if (!this.tryFormatWithStrategy(ctx)) {
290
+ super.visitChildren(ctx);
291
+ }
292
+ }
293
+ visitCreatePipelineFlowHeader(ctx) {
294
+ if (!this.tryFormatWithStrategy(ctx)) {
295
+ super.visitChildren(ctx);
296
+ }
297
+ }
298
+ visitPartitionFieldList(ctx) {
299
+ if (!this.tryFormatWithStrategy(ctx)) {
300
+ super.visitChildren(ctx);
301
+ }
302
+ }
303
+ visitPropertyList(ctx) {
304
+ if (!this.tryFormatWithStrategy(ctx)) {
305
+ super.visitChildren(ctx);
306
+ }
307
+ }
308
+ visitExpressionPropertyList(ctx) {
309
+ if (!this.tryFormatWithStrategy(ctx)) {
310
+ super.visitChildren(ctx);
311
+ }
312
+ }
313
+ visitPropertyWithKeyAndEquals(ctx) {
314
+ if (!this.tryFormatWithStrategy(ctx)) {
315
+ super.visitChildren(ctx);
316
+ }
317
+ }
318
+ visitExpressionPropertyWithKeyAndEquals(ctx) {
319
+ if (!this.tryFormatWithStrategy(ctx)) {
320
+ super.visitChildren(ctx);
321
+ }
322
+ }
323
+ visitCreateView(ctx) {
324
+ if (!this.tryFormatWithStrategy(ctx)) {
325
+ super.visitChildren(ctx);
326
+ }
327
+ }
328
+ visitCreateMetricView(ctx) {
329
+ if (!this.tryFormatWithStrategy(ctx)) {
330
+ super.visitChildren(ctx);
331
+ }
332
+ }
333
+ visitCreateTempViewUsing(ctx) {
334
+ if (!this.tryFormatWithStrategy(ctx)) {
335
+ super.visitChildren(ctx);
336
+ }
337
+ }
338
+ visitCreateFunction(ctx) {
339
+ if (!this.tryFormatWithStrategy(ctx)) {
340
+ super.visitChildren(ctx);
341
+ }
342
+ }
343
+ visitResource(ctx) {
344
+ if (!this.tryFormatWithStrategy(ctx)) {
345
+ super.visitChildren(ctx);
346
+ }
347
+ }
348
+ // ==================== ALTER TABLE ====================
349
+ visitAddTableColumns(ctx) {
350
+ if (!this.tryFormatWithStrategy(ctx)) {
351
+ super.visitChildren(ctx);
352
+ }
353
+ }
354
+ visitRenameTableColumn(ctx) {
355
+ if (!this.tryFormatWithStrategy(ctx)) {
356
+ super.visitChildren(ctx);
357
+ }
358
+ }
359
+ visitDropTableColumns(ctx) {
360
+ if (!this.tryFormatWithStrategy(ctx)) {
361
+ super.visitChildren(ctx);
362
+ }
363
+ }
364
+ visitRenameTable(ctx) {
365
+ if (!this.tryFormatWithStrategy(ctx)) {
366
+ super.visitChildren(ctx);
367
+ }
368
+ }
369
+ visitSetTableProperties(ctx) {
370
+ if (!this.tryFormatWithStrategy(ctx)) {
371
+ super.visitChildren(ctx);
372
+ }
373
+ }
374
+ visitUnsetTableProperties(ctx) {
375
+ if (!this.tryFormatWithStrategy(ctx)) {
376
+ super.visitChildren(ctx);
377
+ }
378
+ }
379
+ visitAlterTableAlterColumn(ctx) {
380
+ if (!this.tryFormatWithStrategy(ctx)) {
381
+ super.visitChildren(ctx);
382
+ }
383
+ }
384
+ visitAlterColumnAction(ctx) {
385
+ if (!this.tryFormatWithStrategy(ctx)) {
386
+ super.visitChildren(ctx);
387
+ }
388
+ }
389
+ visitHiveChangeColumn(ctx) {
390
+ if (!this.tryFormatWithStrategy(ctx)) {
391
+ super.visitChildren(ctx);
392
+ }
393
+ }
394
+ visitAlterViewQuery(ctx) {
395
+ if (!this.tryFormatWithStrategy(ctx)) {
396
+ super.visitChildren(ctx);
397
+ }
398
+ }
399
+ visitSetTableLocation(ctx) {
400
+ if (!this.tryFormatWithStrategy(ctx)) {
401
+ super.visitChildren(ctx);
402
+ }
403
+ }
404
+ // ==================== PARTITION Statements ====================
405
+ visitAddTablePartition(ctx) {
406
+ if (!this.tryFormatWithStrategy(ctx)) {
407
+ super.visitChildren(ctx);
408
+ }
409
+ }
410
+ visitDropTablePartitions(ctx) {
411
+ if (!this.tryFormatWithStrategy(ctx)) {
412
+ super.visitChildren(ctx);
413
+ }
414
+ }
415
+ visitRenameTablePartition(ctx) {
416
+ if (!this.tryFormatWithStrategy(ctx)) {
417
+ super.visitChildren(ctx);
418
+ }
419
+ }
420
+ // ==================== DROP Statements ====================
421
+ visitDropTable(ctx) {
422
+ if (!this.tryFormatWithStrategy(ctx)) {
423
+ super.visitChildren(ctx);
424
+ }
425
+ }
426
+ visitDropView(ctx) {
427
+ if (!this.tryFormatWithStrategy(ctx)) {
428
+ super.visitChildren(ctx);
429
+ }
430
+ }
431
+ visitDropFunction(ctx) {
432
+ if (!this.tryFormatWithStrategy(ctx)) {
433
+ super.visitChildren(ctx);
434
+ }
435
+ }
436
+ visitDropNamespace(ctx) {
437
+ if (!this.tryFormatWithStrategy(ctx)) {
438
+ super.visitChildren(ctx);
439
+ }
440
+ }
441
+ // ==================== RESOURCE Management Statements ====================
442
+ visitManageResource(ctx) {
443
+ if (!this.tryFormatWithStrategy(ctx)) {
444
+ super.visitChildren(ctx);
445
+ }
446
+ }
447
+ // ==================== SET/RESET Statements ====================
448
+ visitSetVariable(ctx) {
449
+ if (!this.tryFormatWithStrategy(ctx)) {
450
+ super.visitChildren(ctx);
451
+ }
452
+ }
453
+ // ==================== INDEX Statements ====================
454
+ visitCreateIndex(ctx) {
455
+ if (!this.tryFormatWithStrategy(ctx)) {
456
+ super.visitChildren(ctx);
457
+ }
458
+ }
459
+ visitDropIndex(ctx) {
460
+ if (!this.tryFormatWithStrategy(ctx)) {
461
+ super.visitChildren(ctx);
462
+ }
463
+ }
464
+ // ==================== DML Statements ====================
465
+ visitQuery(ctx) {
466
+ if (ctx.ctes()) {
467
+ this.updateBeforeNextTokenByContext(ctx.ctes(), this.newlineIndent);
468
+ }
469
+ super.visitChildren(ctx);
470
+ }
471
+ // ==================== CTE (Common Table Expression) ====================
472
+ visitCtes(ctx) {
473
+ // Ensure single space after WITH keyword
474
+ const withNode = ctx.WITH();
475
+ if (withNode) {
476
+ this.updateBeforeNextTokenByNode(withNode, ' ');
477
+ }
478
+ // Handle RECURSIVE keyword if present
479
+ const recursiveNode = ctx.RECURSIVE();
480
+ if (recursiveNode) {
481
+ this.updateAfterPreviousTokenByNode(recursiveNode, ' ');
482
+ this.updateBeforeNextTokenByNode(recursiveNode, ' ');
483
+ }
484
+ // Format commas between CTEs - each namedQuery on new line after comma
485
+ const namedQueries = ctx.namedQuery();
486
+ for (let i = 1; i < namedQueries.length; i++) {
487
+ this.updateAfterPreviousTokenByContext(namedQueries[i], this.newlineIndent);
488
+ }
489
+ super.visitChildren(ctx);
490
+ }
491
+ visitNamedQuery(ctx) {
492
+ // Format AS keyword
493
+ this.normalizeKeywordSpacing(ctx.AS());
494
+ // Format the parentheses and query content
495
+ const leftParen = ctx.LEFT_PAREN();
496
+ const rightParen = ctx.RIGHT_PAREN();
497
+ if (leftParen && rightParen) {
498
+ // Content on new line with indent after left parenthesis
499
+ this.addIndent();
500
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
501
+ // Visit children with added indent
502
+ super.visitChildren(ctx);
503
+ // Check if this CTE is part of a DML statement with INSERT
504
+ let parent = ctx.parent;
505
+ let isInDmlStatement = false;
506
+ while (parent) {
507
+ if (parent.constructor.name === 'DmlStatementContext') {
508
+ isInDmlStatement = true;
509
+ break;
510
+ }
511
+ parent = parent.parent;
512
+ }
513
+ // Reduce indent before right parenthesis (so it aligns with WITH)
514
+ this.minusIndent();
515
+ // Right parenthesis on new line without extra indent (aligned with WITH)
516
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
517
+ if (isInDmlStatement) {
518
+ // For CTE followed by INSERT - keep INSERT on same line
519
+ this.updateBeforeNextTokenByNode(rightParen, ' ');
520
+ }
521
+ }
522
+ else {
523
+ super.visitChildren(ctx);
524
+ }
525
+ }
526
+ visitRegularQuerySpecification(ctx) {
527
+ // Legacy visitor doesn't add indent here - each clause handles its own indentation
528
+ super.visitChildren(ctx);
529
+ }
530
+ visitSelectClause(ctx) {
531
+ // Ensure setQuantifier (DISTINCT/ALL) stays on same line as SELECT
532
+ const setQuantifier = ctx.setQuantifier();
533
+ if (setQuantifier) {
534
+ const selectToken = ctx.SELECT();
535
+ if (selectToken) {
536
+ this.updateBeforeNextTokenByNode(selectToken, ' ');
537
+ }
538
+ }
539
+ if (!this.tryFormatWithStrategy(ctx)) {
540
+ super.visitChildren(ctx);
541
+ }
542
+ }
543
+ visitFromClause(ctx) {
544
+ if (!this.tryFormatWithStrategy(ctx)) {
545
+ const fromToken = ctx.FROM();
546
+ const relations = ctx.relation();
547
+ const lateralViews = ctx.lateralView();
548
+ // Add newline before FROM
549
+ if (fromToken) {
550
+ this.updateAfterPreviousTokenByNode(fromToken, this.newlineIndent);
551
+ }
552
+ // Add indent for FROM body (but not for VALUES - that handles its own indent)
553
+ let addedIndent = false;
554
+ if (relations.length > 0) {
555
+ // Check if first relation is an InlineTable (VALUES clause)
556
+ const firstRelationPrimary = relations[0].relationPrimary();
557
+ const isFromValues = firstRelationPrimary?.constructor.name === 'InlineTableDefault2Context';
558
+ if (!isFromValues) {
559
+ this.addIndent();
560
+ addedIndent = true;
561
+ // First relation on new line with indent
562
+ this.updateAfterPreviousTokenByContext(relations[0], this.newlineIndent);
563
+ }
564
+ // For FROM VALUES, visitInlineTable handles all formatting including indent
565
+ }
566
+ // Format commas in FROM clause
567
+ const commas = ctx.COMMA();
568
+ for (const comma of commas) {
569
+ this.updateAfterPreviousTokenByNode(comma, '');
570
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
571
+ }
572
+ // Visit relations
573
+ for (const relation of relations) {
574
+ this.visit(relation);
575
+ }
576
+ // Visit LATERAL VIEW with proper indent (one level more than FROM body)
577
+ if (lateralViews.length > 0 && addedIndent) {
578
+ // LATERAL VIEW should have one more level of indent
579
+ // But we already have FROM body indent, so LATERAL VIEW just needs newline
580
+ for (const lateralView of lateralViews) {
581
+ this.visit(lateralView);
582
+ }
583
+ }
584
+ else {
585
+ for (const lateralView of lateralViews) {
586
+ this.visit(lateralView);
587
+ }
588
+ }
589
+ // Visit PIVOT and UNPIVOT
590
+ const pivotClause = ctx.pivotClause();
591
+ if (pivotClause) {
592
+ this.visit(pivotClause);
593
+ }
594
+ const unpivotClause = ctx.unpivotClause();
595
+ if (unpivotClause) {
596
+ this.visit(unpivotClause);
597
+ }
598
+ if (addedIndent) {
599
+ this.minusIndent();
600
+ }
601
+ }
602
+ }
603
+ visitWhereClause(ctx) {
604
+ if (!this.tryFormatWithStrategy(ctx)) {
605
+ const whereToken = ctx.WHERE();
606
+ const booleanExpr = ctx.booleanExpression();
607
+ // Add newline before WHERE (except in pipe context where `|> WHERE` is on same line)
608
+ if (whereToken && !this.inPipeOperatorRightSide) {
609
+ this.updateAfterPreviousTokenByNode(whereToken, this.newlineIndent);
610
+ }
611
+ // Add indent for WHERE body and newline before expression
612
+ // In pipe context, this is handled by PipeWhereStrategy
613
+ if (booleanExpr && !this.inPipeOperatorRightSide) {
614
+ this.addIndent();
615
+ this.updateAfterPreviousTokenByContext(booleanExpr, this.newlineIndent);
616
+ }
617
+ super.visitChildren(ctx);
618
+ if (booleanExpr && !this.inPipeOperatorRightSide) {
619
+ this.minusIndent();
620
+ }
621
+ }
622
+ }
623
+ visitAggregationClause(ctx) {
624
+ if (!this.tryFormatWithStrategy(ctx)) {
625
+ const groupToken = ctx.GROUP();
626
+ const byToken = ctx.BY();
627
+ const expressions = ctx.namedExpression();
628
+ const groupByClauses = ctx.groupByClause();
629
+ // In pipe context, GROUP BY formatting is handled by PipeAggregateStrategy
630
+ if (!this.inPipeOperatorRightSide) {
631
+ // Add newline before GROUP BY
632
+ if (groupToken) {
633
+ this.updateAfterPreviousTokenByNode(groupToken, this.newlineIndent);
634
+ }
635
+ if (byToken) {
636
+ this.updateBeforeNextTokenByNode(byToken, ' ');
637
+ this.updateAfterPreviousTokenByNode(byToken, ' ');
638
+ }
639
+ }
640
+ // Add indent for GROUP BY body (except in pipe context)
641
+ if (!this.inPipeOperatorRightSide) {
642
+ this.addIndent();
643
+ }
644
+ // Get first expression and put it on new line with indent
645
+ // In pipe context, use pipe-specific indent
646
+ const groupByBodyIndent = this.inPipeOperatorRightSide ? this.context.getPipeContentIndent() : this.newlineIndent;
647
+ if (groupByClauses.length > 0) {
648
+ this.updateAfterPreviousTokenByContext(groupByClauses[0], groupByBodyIndent);
649
+ }
650
+ else if (expressions.length > 0) {
651
+ this.updateAfterPreviousTokenByContext(expressions[0], groupByBodyIndent);
652
+ }
653
+ // Format commas
654
+ const commas = ctx.COMMA();
655
+ for (const comma of commas) {
656
+ this.updateAfterPreviousTokenByNode(comma, '');
657
+ this.updateBeforeNextTokenByNode(comma, groupByBodyIndent);
658
+ }
659
+ // Handle WITH ROLLUP / WITH CUBE - on separate line
660
+ const withToken = ctx.WITH();
661
+ if (withToken) {
662
+ this.updateAfterPreviousTokenByNode(withToken, this.newlineIndent);
663
+ this.updateBeforeNextTokenByNode(withToken, ' ');
664
+ }
665
+ const rollupToken = ctx.ROLLUP();
666
+ if (rollupToken) {
667
+ this.updateAfterPreviousTokenByNode(rollupToken, ' ');
668
+ }
669
+ const cubeToken = ctx.CUBE();
670
+ if (cubeToken) {
671
+ this.updateAfterPreviousTokenByNode(cubeToken, ' ');
672
+ }
673
+ // Note: GROUPING SETS is handled in visitGroupingAnalytics
674
+ super.visitChildren(ctx);
675
+ if (!this.inPipeOperatorRightSide) {
676
+ this.minusIndent();
677
+ }
678
+ }
679
+ }
680
+ visitHavingClause(ctx) {
681
+ if (!this.tryFormatWithStrategy(ctx)) {
682
+ const havingToken = ctx.HAVING();
683
+ const booleanExpr = ctx.booleanExpression();
684
+ // Add newline before HAVING
685
+ if (havingToken) {
686
+ this.updateAfterPreviousTokenByNode(havingToken, this.newlineIndent);
687
+ }
688
+ // Add indent for HAVING body and newline before expression
689
+ if (booleanExpr) {
690
+ this.addIndent();
691
+ this.updateAfterPreviousTokenByContext(booleanExpr, this.newlineIndent);
692
+ }
693
+ super.visitChildren(ctx);
694
+ if (booleanExpr) {
695
+ this.minusIndent();
696
+ }
697
+ }
698
+ }
699
+ visitQueryOrganization(ctx) {
700
+ if (!this.tryFormatWithStrategy(ctx)) {
701
+ // In pipe context, ORDER BY / LIMIT should stay on same line as |>\n // Pipe content indent: 5 spaces from `|>` position
702
+ const pipeContentIndent = this.inPipeOperatorRightSide ? this.context.getPipeContentIndent() : this.newlineIndent;
703
+ // For keywords like ORDER BY, use 3 spaces indent
704
+ const _pipeClauseIndent = this.inPipeOperatorRightSide ? `\n${this.indent} ` : this.newlineIndent;
705
+ // Handle ORDER BY
706
+ if (ctx.ORDER()) {
707
+ // In pipe context: `|> ORDER BY` on same line, content indent 5 spaces
708
+ if (!this.inPipeOperatorRightSide) {
709
+ this.updateAfterPreviousTokenByNode(ctx.ORDER(), this.newlineIndent);
710
+ }
711
+ const byTokens = ctx.BY();
712
+ for (const by of byTokens) {
713
+ this.updateBeforeNextTokenByNode(by, ' ');
714
+ this.updateAfterPreviousTokenByNode(by, ' ');
715
+ }
716
+ // Add indent and newline before first expression
717
+ if (!this.inPipeOperatorRightSide) {
718
+ this.addIndent();
719
+ }
720
+ const expressions = ctx.sortItem();
721
+ if (expressions.length > 0) {
722
+ this.updateAfterPreviousTokenByContext(expressions[0], pipeContentIndent);
723
+ }
724
+ }
725
+ // Handle CLUSTER BY
726
+ if (ctx.CLUSTER()) {
727
+ if (!this.inPipeOperatorRightSide) {
728
+ this.updateAfterPreviousTokenByNode(ctx.CLUSTER(), this.newlineIndent);
729
+ }
730
+ const byTokens = ctx.BY();
731
+ for (const by of byTokens) {
732
+ this.updateBeforeNextTokenByNode(by, ' ');
733
+ this.updateAfterPreviousTokenByNode(by, ' ');
734
+ }
735
+ if (!this.inPipeOperatorRightSide) {
736
+ this.addIndent();
737
+ }
738
+ const expressions = ctx.expression();
739
+ if (expressions.length > 0) {
740
+ this.updateAfterPreviousTokenByContext(expressions[0], pipeContentIndent);
741
+ }
742
+ }
743
+ // Handle DISTRIBUTE BY
744
+ if (ctx.DISTRIBUTE()) {
745
+ if (!this.inPipeOperatorRightSide) {
746
+ this.updateAfterPreviousTokenByNode(ctx.DISTRIBUTE(), this.newlineIndent);
747
+ }
748
+ const byTokens = ctx.BY();
749
+ for (const by of byTokens) {
750
+ this.updateBeforeNextTokenByNode(by, ' ');
751
+ this.updateAfterPreviousTokenByNode(by, ' ');
752
+ }
753
+ if (!this.inPipeOperatorRightSide) {
754
+ this.addIndent();
755
+ }
756
+ const expressions = ctx.expression();
757
+ if (expressions.length > 0) {
758
+ this.updateAfterPreviousTokenByContext(expressions[0], pipeContentIndent);
759
+ }
760
+ }
761
+ // Handle SORT BY
762
+ if (ctx.SORT()) {
763
+ if (!this.inPipeOperatorRightSide) {
764
+ this.updateAfterPreviousTokenByNode(ctx.SORT(), this.newlineIndent);
765
+ }
766
+ const byTokens = ctx.BY();
767
+ for (const by of byTokens) {
768
+ this.updateBeforeNextTokenByNode(by, ' ');
769
+ this.updateAfterPreviousTokenByNode(by, ' ');
770
+ }
771
+ if (!this.inPipeOperatorRightSide) {
772
+ this.addIndent();
773
+ }
774
+ const expressions = ctx.sortItem();
775
+ if (expressions.length > 0) {
776
+ this.updateAfterPreviousTokenByContext(expressions[0], pipeContentIndent);
777
+ }
778
+ }
779
+ // Handle LIMIT - in pipe context, stays on same line as |>
780
+ if (ctx.LIMIT() && !this.inPipeOperatorRightSide) {
781
+ this.updateAfterPreviousTokenByNode(ctx.LIMIT(), this.newlineIndent);
782
+ }
783
+ // Handle OFFSET
784
+ if (ctx.OFFSET() && !this.inPipeOperatorRightSide) {
785
+ this.updateAfterPreviousTokenByNode(ctx.OFFSET(), this.newlineIndent);
786
+ }
787
+ super.visitChildren(ctx);
788
+ // Minus indent after processing (except in pipe context)
789
+ if (!this.inPipeOperatorRightSide && (ctx.ORDER() || ctx.CLUSTER() || ctx.DISTRIBUTE() || ctx.SORT())) {
790
+ this.minusIndent();
791
+ }
792
+ }
793
+ }
794
+ visitSortItem(ctx) {
795
+ // Format ASC/DESC - space before
796
+ if (ctx.ASC()) {
797
+ this.updateAfterPreviousTokenByNode(ctx.ASC(), ' ');
798
+ }
799
+ if (ctx.DESC()) {
800
+ this.updateAfterPreviousTokenByNode(ctx.DESC(), ' ');
801
+ }
802
+ // Format NULLS FIRST/LAST - space before NULLS
803
+ if (ctx.NULLS()) {
804
+ this.updateAfterPreviousTokenByNode(ctx.NULLS(), ' ');
805
+ }
806
+ super.visitChildren(ctx);
807
+ }
808
+ // ==================== Window Clause ====================
809
+ visitWindowClause(ctx) {
810
+ // In pipe context, WINDOW formatting is handled by PipeSelectStrategy
811
+ if (!this.inPipeOperatorRightSide) {
812
+ // WINDOW on new line with indent
813
+ this.updateAfterPreviousTokenByContext(ctx, this.newlineIndent);
814
+ }
815
+ // 判断是否为多窗口
816
+ const namedWindows = ctx.namedWindow();
817
+ const _isMultipleWindows = namedWindows.length > 1;
818
+ // 检查每个窗口是否为简单窗口(无窗口帧、无多参数)
819
+ const windowIsSimple = [];
820
+ for (const nw of namedWindows) {
821
+ const windowSpec = nw.windowSpec();
822
+ if (windowSpec instanceof SparkSQLParser_1.WindowDefContext) {
823
+ const hasWindowFrame = windowSpec.windowFrame();
824
+ const partitionExprs = windowSpec._partition || [];
825
+ const sortItems = windowSpec.sortItem();
826
+ const hasMultiplePartitionExprs = windowSpec.PARTITION() && partitionExprs.length > 1;
827
+ const hasMultipleSortItems = windowSpec.ORDER() && sortItems.length > 1;
828
+ // 简单窗口:无窗口帧、无多参数
829
+ windowIsSimple.push(!hasWindowFrame && !hasMultiplePartitionExprs && !hasMultipleSortItems);
830
+ }
831
+ else {
832
+ windowIsSimple.push(true); // WindowRef 视为简单
833
+ }
834
+ }
835
+ // 短句判断:单窗口且简单窗口
836
+ const isShortForm = namedWindows.length === 1 && windowIsSimple[0];
837
+ if (isShortForm) {
838
+ // 短句格式:WINDOW w AS (PARTITION BY dept ORDER BY date)
839
+ // 不添加缩进,不换行
840
+ this.inWindowClause = false; // 标记不在需要换行的 WINDOW 子句中
841
+ // 标记每个窗口定义是在 WINDOW 子句中
842
+ for (const nw of namedWindows) {
843
+ const windowSpec = nw.windowSpec();
844
+ if (windowSpec) {
845
+ windowSpec._isInWindowClause = true;
846
+ }
847
+ }
848
+ super.visitChildren(ctx);
849
+ }
850
+ else {
851
+ // 长句格式
852
+ // WINDOW 后换行
853
+ const windowToken = ctx.WINDOW();
854
+ if (windowToken) {
855
+ this.updateBeforeNextTokenByNode(windowToken, this.newlineIndent);
856
+ }
857
+ this.addIndent();
858
+ // Format commas between window definitions - each window on separate line
859
+ const commas = ctx.COMMA();
860
+ for (let i = 0; i < commas.length; i++) {
861
+ const comma = commas[i];
862
+ this.updateAfterPreviousTokenByNode(comma, '');
863
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
864
+ }
865
+ // 存储每个窗口是否简单的信息,供 visitWindowDef 使用
866
+ ctx._windowIsSimple = windowIsSimple;
867
+ ctx._currentWindowIndex = 0;
868
+ this.inWindowClause = true; // 标记在需要换行的 WINDOW 子句中
869
+ super.visitChildren(ctx);
870
+ this.minusIndent();
871
+ }
872
+ }
873
+ visitNamedWindow(ctx) {
874
+ // Format AS keyword - space before and after
875
+ this.normalizeKeywordSpacing(ctx.AS());
876
+ // 长句格式时,窗口名需要缩进 2 空格
877
+ if (this.inWindowClause) {
878
+ // 窗口名(identifier)前换行缩进
879
+ const identifier = ctx.errorCapturingIdentifier();
880
+ if (identifier) {
881
+ this.updateAfterPreviousTokenByContext(identifier, this.newlineIndent);
882
+ }
883
+ }
884
+ // 标记这是 WINDOW 子句中的窗口定义(而不是 OVER 子句)
885
+ const windowSpec = ctx.windowSpec();
886
+ if (windowSpec) {
887
+ windowSpec._isInWindowClause = true;
888
+ }
889
+ // 检查父级 WindowClauseContext 中是否有窗口简单性信息
890
+ const parentCtx = ctx.parent;
891
+ if (parentCtx && parentCtx._windowIsSimple && parentCtx._currentWindowIndex !== undefined) {
892
+ const idx = parentCtx._currentWindowIndex;
893
+ // 将当前窗口的简单性信息传递给 windowDef
894
+ if (windowSpec) {
895
+ windowSpec._isSimpleInMultiWindow = parentCtx._windowIsSimple[idx];
896
+ }
897
+ parentCtx._currentWindowIndex++;
898
+ }
899
+ super.visitChildren(ctx);
900
+ }
901
+ visitWindowDef(ctx) {
902
+ const leftParen = ctx.LEFT_PAREN();
903
+ const rightParen = ctx.RIGHT_PAREN();
904
+ // Check if this is an empty window spec or has content
905
+ const hasPartition = ctx.PARTITION();
906
+ const hasDistribute = ctx.DISTRIBUTE();
907
+ const hasOrder = ctx.ORDER();
908
+ const hasSort = ctx.SORT();
909
+ const hasWindowFrame = ctx.windowFrame();
910
+ const hasContent = hasPartition || hasDistribute || hasOrder || hasSort || hasWindowFrame;
911
+ // In pipe context or for WINDOW clause definitions, use compact single-line format
912
+ // Example: WINDOW w as (partition by cate order by val)
913
+ const useCompactFormat = this.inPipeOperatorRightSide;
914
+ // 检查是否为简单窗口(用于 WINDOW 子句短句格式)
915
+ const partitionExprs = ctx._partition || [];
916
+ const sortItems = ctx.sortItem();
917
+ const hasMultiplePartitionExprs = ctx.PARTITION() && partitionExprs.length > 1;
918
+ const hasMultipleSortItems = ctx.ORDER() && sortItems.length > 1;
919
+ const isSimpleWindow = !hasWindowFrame && !hasMultiplePartitionExprs && !hasMultipleSortItems;
920
+ // 检查是否在多窗口场景下是简单窗口
921
+ const isSimpleInMultiWindow = ctx._isSimpleInMultiWindow;
922
+ // 短句格式判断:
923
+ // 只有在 WINDOW 子句中才能使用短句格式
924
+ // OVER 子句不使用短句格式
925
+ // 1. 在 WINDOW 子句中且不在长句格式(inWindowClause=false 表示单窗口简单场景)
926
+ // 2. 或者在多窗口场景下当前窗口是简单窗口
927
+ const isInWindowClause = this.inWindowClause || ctx._isInWindowClause;
928
+ const useShortFormat = isInWindowClause && !useCompactFormat && isSimpleWindow && hasContent && isSimpleInMultiWindow !== false;
929
+ if (useShortFormat && leftParen && rightParen) {
930
+ // 短句格式:WINDOW w AS (PARTITION BY dept ORDER BY date)
931
+ // 括号内容保持单行,紧凑格式
932
+ this.updateBeforeNextTokenByNode(leftParen, '');
933
+ this.updateAfterPreviousTokenByNode(rightParen, '');
934
+ // Handle keywords with proper spacing
935
+ if (ctx.PARTITION()) {
936
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.PARTITION().symbol.startIndex);
937
+ if (prevToken && prevToken.text !== '(') {
938
+ this.updateAfterPreviousTokenByNode(ctx.PARTITION(), ' ');
939
+ }
940
+ const byTokens = ctx.BY();
941
+ for (const by of byTokens) {
942
+ this.updateAfterPreviousTokenByNode(by, ' ');
943
+ }
944
+ }
945
+ if (ctx.DISTRIBUTE()) {
946
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.DISTRIBUTE().symbol.startIndex);
947
+ if (prevToken && prevToken.text !== '(') {
948
+ this.updateAfterPreviousTokenByNode(ctx.DISTRIBUTE(), ' ');
949
+ }
950
+ const byTokens = ctx.BY();
951
+ for (const by of byTokens) {
952
+ this.updateAfterPreviousTokenByNode(by, ' ');
953
+ }
954
+ }
955
+ if (ctx.ORDER()) {
956
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.ORDER().symbol.startIndex);
957
+ if (prevToken && prevToken.text !== '(') {
958
+ this.updateAfterPreviousTokenByNode(ctx.ORDER(), ' ');
959
+ }
960
+ const byTokens = ctx.BY();
961
+ for (const by of byTokens) {
962
+ this.updateAfterPreviousTokenByNode(by, ' ');
963
+ }
964
+ }
965
+ if (ctx.SORT()) {
966
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.SORT().symbol.startIndex);
967
+ if (prevToken && prevToken.text !== '(') {
968
+ this.updateAfterPreviousTokenByNode(ctx.SORT(), ' ');
969
+ }
970
+ const byTokens = ctx.BY();
971
+ for (const by of byTokens) {
972
+ this.updateAfterPreviousTokenByNode(by, ' ');
973
+ }
974
+ }
975
+ super.visitChildren(ctx);
976
+ }
977
+ else if (useCompactFormat && leftParen && rightParen) {
978
+ // Compact format for pipe context - single line
979
+ this.updateBeforeNextTokenByNode(leftParen, '');
980
+ this.updateAfterPreviousTokenByNode(rightParen, '');
981
+ // Handle keywords with proper spacing
982
+ // For PARTITION/ORDER etc, check if they are right after left paren
983
+ if (ctx.PARTITION()) {
984
+ // Check if PARTITION is right after left paren
985
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.PARTITION().symbol.startIndex);
986
+ if (prevToken && prevToken.text === '(') {
987
+ // No space needed - it's right after left paren
988
+ }
989
+ else {
990
+ this.updateAfterPreviousTokenByNode(ctx.PARTITION(), ' ');
991
+ }
992
+ const byTokens = ctx.BY();
993
+ for (const by of byTokens) {
994
+ this.updateBeforeNextTokenByNode(by, ' ');
995
+ this.updateAfterPreviousTokenByNode(by, ' ');
996
+ }
997
+ }
998
+ if (ctx.DISTRIBUTE()) {
999
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.DISTRIBUTE().symbol.startIndex);
1000
+ if (prevToken && prevToken.text !== '(') {
1001
+ this.updateAfterPreviousTokenByNode(ctx.DISTRIBUTE(), ' ');
1002
+ }
1003
+ const byTokens = ctx.BY();
1004
+ for (const by of byTokens) {
1005
+ this.updateBeforeNextTokenByNode(by, ' ');
1006
+ this.updateAfterPreviousTokenByNode(by, ' ');
1007
+ }
1008
+ }
1009
+ if (ctx.ORDER()) {
1010
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.ORDER().symbol.startIndex);
1011
+ if (prevToken && prevToken.text !== '(') {
1012
+ this.updateAfterPreviousTokenByNode(ctx.ORDER(), ' ');
1013
+ }
1014
+ const byTokens = ctx.BY();
1015
+ for (const by of byTokens) {
1016
+ this.updateBeforeNextTokenByNode(by, ' ');
1017
+ this.updateAfterPreviousTokenByNode(by, ' ');
1018
+ }
1019
+ }
1020
+ if (ctx.SORT()) {
1021
+ const prevToken = this.getPreviousNonHiddenTokenByStartIndex(ctx.SORT().symbol.startIndex);
1022
+ if (prevToken && prevToken.text !== '(') {
1023
+ this.updateAfterPreviousTokenByNode(ctx.SORT(), ' ');
1024
+ }
1025
+ const byTokens = ctx.BY();
1026
+ for (const by of byTokens) {
1027
+ this.updateBeforeNextTokenByNode(by, ' ');
1028
+ this.updateAfterPreviousTokenByNode(by, ' ');
1029
+ }
1030
+ }
1031
+ super.visitChildren(ctx);
1032
+ }
1033
+ else if (hasOrder && !hasPartition && !hasDistribute && !hasWindowFrame && leftParen && rightParen) {
1034
+ // Simple OVER clause - use hanging indent format with ORDER BY on new line
1035
+ // Format: OVER (
1036
+ // ORDER BY
1037
+ // col
1038
+ // )
1039
+ this.updateBeforeNextTokenByNode(leftParen, '');
1040
+ // Add indent for content (total 4 spaces for PARTITION BY / ORDER BY)
1041
+ this.addIndent();
1042
+ // ORDER BY on new line with indent
1043
+ const orderToken = ctx.ORDER();
1044
+ if (orderToken) {
1045
+ this.updateAfterPreviousTokenByNode(orderToken, this.newlineIndent);
1046
+ }
1047
+ // Space around BY keywords
1048
+ const byTokens = ctx.BY();
1049
+ for (const by of byTokens) {
1050
+ this.updateAfterPreviousTokenByNode(by, ' ');
1051
+ }
1052
+ // ORDER BY 后的 sortItem 需要换行,缩进 6 空格 (4 + 2)
1053
+ const sortItems = ctx.sortItem();
1054
+ const hasMultipleSortItems = sortItems.length > 1;
1055
+ if (sortItems.length > 0) {
1056
+ // 添加额外缩进,使 sortItem 缩进 6 空格
1057
+ this.addIndent();
1058
+ // 在第一个 BY 后换行
1059
+ if (byTokens.length > 0) {
1060
+ this.updateBeforeNextTokenByNode(byTokens[0], this.newlineIndent);
1061
+ }
1062
+ // 多参数时处理逗号换行
1063
+ if (hasMultipleSortItems) {
1064
+ const commas = ctx.COMMA();
1065
+ for (const comma of commas) {
1066
+ this.updateAfterPreviousTokenByNode(comma, '');
1067
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1068
+ }
1069
+ }
1070
+ }
1071
+ super.visitChildren(ctx);
1072
+ // 减去 sortItem 的额外缩进
1073
+ if (sortItems.length > 0) {
1074
+ this.minusIndent();
1075
+ }
1076
+ // Minus indent before right paren
1077
+ this.minusIndent();
1078
+ // Right paren on new line with 2-space indent
1079
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
1080
+ }
1081
+ else if (hasContent && leftParen && rightParen) {
1082
+ // Complex window spec - format with hanging indent
1083
+ // Left paren stays on same line
1084
+ this.updateBeforeNextTokenByNode(leftParen, '');
1085
+ // Add indent for window spec content (content at 4 spaces)
1086
+ this.addIndent();
1087
+ // Handle PARTITION BY / DISTRIBUTE BY
1088
+ // PARTITION BY 多参数时,表达式换行缩进 6 空格
1089
+ // 注意:使用 _partition 数组获取 PARTITION BY 后的表达式数量
1090
+ const partitionExprs = ctx._partition || [];
1091
+ const hasMultiplePartitionExprs = ctx.PARTITION() && partitionExprs.length > 1;
1092
+ // 收集所有 BY tokens
1093
+ const allByTokens = ctx.BY();
1094
+ let byIndex = 0;
1095
+ if (ctx.PARTITION()) {
1096
+ this.updateAfterPreviousTokenByNode(ctx.PARTITION(), this.newlineIndent);
1097
+ // PARTITION BY 的 BY token
1098
+ if (allByTokens.length > byIndex) {
1099
+ const partitionBy = allByTokens[byIndex];
1100
+ byIndex++;
1101
+ // BY 前面加空格(保持 PARTITION BY 在同一行)
1102
+ this.updateAfterPreviousTokenByNode(partitionBy, ' ');
1103
+ if (hasMultiplePartitionExprs) {
1104
+ // 先添加额外缩进使表达式缩进 6 空格
1105
+ this.addIndent();
1106
+ // 多参数时,BY 后换行(此时 newlineIndent 已经是 6 空格)
1107
+ this.updateBeforeNextTokenByNode(partitionBy, this.newlineIndent);
1108
+ // 处理逗号换行
1109
+ const commas = ctx.COMMA();
1110
+ for (const comma of commas) {
1111
+ this.updateAfterPreviousTokenByNode(comma, '');
1112
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1113
+ }
1114
+ }
1115
+ else {
1116
+ // 单参数时,BY 后空格
1117
+ this.updateBeforeNextTokenByNode(partitionBy, ' ');
1118
+ }
1119
+ }
1120
+ }
1121
+ if (ctx.DISTRIBUTE()) {
1122
+ this.updateAfterPreviousTokenByNode(ctx.DISTRIBUTE(), this.newlineIndent);
1123
+ if (allByTokens.length > byIndex) {
1124
+ const distributeBy = allByTokens[byIndex];
1125
+ byIndex++;
1126
+ this.updateAfterPreviousTokenByNode(distributeBy, ' ');
1127
+ this.updateBeforeNextTokenByNode(distributeBy, ' ');
1128
+ }
1129
+ }
1130
+ // Handle ORDER BY / SORT BY
1131
+ // ORDER BY 多参数时,sortItem 换行缩进 6 空格
1132
+ const sortItems = ctx.sortItem();
1133
+ const hasMultipleSortItems = ctx.ORDER() && sortItems.length > 1;
1134
+ let hasOrderBy = false;
1135
+ if (ctx.ORDER()) {
1136
+ hasOrderBy = true;
1137
+ // 先减去 PARTITION BY 多参数的额外缩进(如果有)
1138
+ if (hasMultiplePartitionExprs) {
1139
+ this.minusIndent();
1140
+ }
1141
+ this.updateAfterPreviousTokenByNode(ctx.ORDER(), this.newlineIndent);
1142
+ // ORDER BY 的 BY token
1143
+ if (allByTokens.length > byIndex) {
1144
+ const orderBy = allByTokens[byIndex];
1145
+ byIndex++;
1146
+ // BY 前面加空格(保持 ORDER BY 在同一行)
1147
+ this.updateAfterPreviousTokenByNode(orderBy, ' ');
1148
+ // sortItem 换行,缩进 6 空格
1149
+ if (sortItems.length > 0) {
1150
+ // 先添加额外缩进使后续 sortItem 缩进 6 空格
1151
+ this.addIndent();
1152
+ // 在 BY 后换行
1153
+ this.updateBeforeNextTokenByNode(orderBy, this.newlineIndent);
1154
+ // 多参数时处理逗号换行
1155
+ if (hasMultipleSortItems) {
1156
+ const commas = ctx.COMMA();
1157
+ // 只处理 ORDER BY 相关的逗号(排除 PARTITION BY 的逗号)
1158
+ const partitionCommaCount = hasMultiplePartitionExprs ? partitionExprs.length - 1 : 0;
1159
+ for (let i = partitionCommaCount; i < commas.length; i++) {
1160
+ const comma = commas[i];
1161
+ this.updateAfterPreviousTokenByNode(comma, '');
1162
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1163
+ }
1164
+ }
1165
+ }
1166
+ else {
1167
+ // 没有 sortItem 时,BY 后空格
1168
+ this.updateBeforeNextTokenByNode(orderBy, ' ');
1169
+ }
1170
+ }
1171
+ }
1172
+ if (ctx.SORT()) {
1173
+ // 先减去 PARTITION BY 多参数的额外缩进(如果有)
1174
+ if (hasMultiplePartitionExprs && !hasOrderBy) {
1175
+ this.minusIndent();
1176
+ }
1177
+ this.updateAfterPreviousTokenByNode(ctx.SORT(), this.newlineIndent);
1178
+ // SORT BY 的 BY token
1179
+ if (allByTokens.length > byIndex) {
1180
+ const sortBy = allByTokens[byIndex];
1181
+ byIndex++;
1182
+ this.updateAfterPreviousTokenByNode(sortBy, ' ');
1183
+ this.updateBeforeNextTokenByNode(sortBy, ' ');
1184
+ }
1185
+ }
1186
+ // 窗口帧 ROWS/RANGE BETWEEN 需要独立成行,缩进 4 空格
1187
+ // 注意:如果前面有 ORDER BY sortItem,需要先减去 sortItem 的额外缩进
1188
+ if (hasOrderBy && sortItems.length > 0) {
1189
+ this.minusIndent();
1190
+ }
1191
+ super.visitChildren(ctx);
1192
+ // 减去 PARTITION BY 多参数的额外缩进(如果没有 ORDER BY)
1193
+ if (hasMultiplePartitionExprs && !ctx.ORDER() && !ctx.SORT()) {
1194
+ this.minusIndent();
1195
+ }
1196
+ // Minus indent before right paren
1197
+ this.minusIndent();
1198
+ // Right paren on new line with 2-space indent
1199
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
1200
+ }
1201
+ else {
1202
+ // Empty or simple window ref - compact format
1203
+ if (leftParen) {
1204
+ this.updateBeforeNextTokenByNode(leftParen, '');
1205
+ }
1206
+ if (rightParen) {
1207
+ this.updateAfterPreviousTokenByNode(rightParen, '');
1208
+ }
1209
+ super.visitChildren(ctx);
1210
+ }
1211
+ }
1212
+ visitWindowFrame(ctx) {
1213
+ // ROWS or RANGE - 独立成行,缩进 4 空格(与 PARTITION BY 同级)
1214
+ if (ctx.ROWS()) {
1215
+ this.updateAfterPreviousTokenByNode(ctx.ROWS(), this.newlineIndent);
1216
+ this.updateBeforeNextTokenByNode(ctx.ROWS(), '');
1217
+ }
1218
+ if (ctx.RANGE()) {
1219
+ this.updateAfterPreviousTokenByNode(ctx.RANGE(), this.newlineIndent);
1220
+ this.updateBeforeNextTokenByNode(ctx.RANGE(), '');
1221
+ }
1222
+ // BETWEEN keyword - space after
1223
+ if (ctx.BETWEEN()) {
1224
+ this.updateAfterPreviousTokenByNode(ctx.BETWEEN(), ' ');
1225
+ }
1226
+ // AND keyword - space before and after
1227
+ if (ctx.AND()) {
1228
+ this.updateAfterPreviousTokenByNode(ctx.AND(), ' ');
1229
+ this.updateBeforeNextTokenByNode(ctx.AND(), ' ');
1230
+ }
1231
+ super.visitChildren(ctx);
1232
+ }
1233
+ visitFrameBound(ctx) {
1234
+ // UNBOUNDED - space after
1235
+ if (ctx.UNBOUNDED()) {
1236
+ this.updateAfterPreviousTokenByNode(ctx.UNBOUNDED(), ' ');
1237
+ this.updateBeforeNextTokenByNode(ctx.UNBOUNDED(), ' ');
1238
+ }
1239
+ // CURRENT - space after
1240
+ if (ctx.CURRENT()) {
1241
+ this.updateAfterPreviousTokenByNode(ctx.CURRENT(), ' ');
1242
+ this.updateBeforeNextTokenByNode(ctx.CURRENT(), ' ');
1243
+ }
1244
+ // PRECEDING / FOLLOWING - space before
1245
+ if (ctx.PRECEDING()) {
1246
+ this.updateAfterPreviousTokenByNode(ctx.PRECEDING(), ' ');
1247
+ }
1248
+ if (ctx.FOLLOWING()) {
1249
+ this.updateAfterPreviousTokenByNode(ctx.FOLLOWING(), ' ');
1250
+ }
1251
+ super.visitChildren(ctx);
1252
+ }
1253
+ // ==================== Grouping Analytics ====================
1254
+ visitGroupingAnalytics(ctx) {
1255
+ // ROLLUP, CUBE - put on new line after GROUP BY
1256
+ if (ctx.ROLLUP()) {
1257
+ this.updateAfterPreviousTokenByNode(ctx.ROLLUP(), this.newlineIndent);
1258
+ this.updateBeforeNextTokenByNode(ctx.ROLLUP(), ' ');
1259
+ }
1260
+ if (ctx.CUBE()) {
1261
+ this.updateAfterPreviousTokenByNode(ctx.CUBE(), this.newlineIndent);
1262
+ this.updateBeforeNextTokenByNode(ctx.CUBE(), ' ');
1263
+ }
1264
+ // GROUPING SETS - put GROUPING on new line after GROUP BY
1265
+ if (ctx.GROUPING()) {
1266
+ this.updateAfterPreviousTokenByNode(ctx.GROUPING(), this.newlineIndent);
1267
+ this.updateBeforeNextTokenByNode(ctx.GROUPING(), ' ');
1268
+ }
1269
+ if (ctx.SETS()) {
1270
+ this.updateAfterPreviousTokenByNode(ctx.SETS(), ' ');
1271
+ this.updateBeforeNextTokenByNode(ctx.SETS(), ' ');
1272
+ }
1273
+ const leftParen = ctx.LEFT_PAREN();
1274
+ const rightParen = ctx.RIGHT_PAREN();
1275
+ // Get grouping sets or grouping elements
1276
+ const _groupingSets = ctx.groupingSet();
1277
+ const _groupingElements = ctx.groupingElement();
1278
+ if (leftParen && rightParen) {
1279
+ // Check content length to determine format
1280
+ const contentLength = ctx.stop.stopIndex - ctx.start.startIndex;
1281
+ const isLongContent = contentLength > this.maxParenthesisLength;
1282
+ if (isLongContent) {
1283
+ // Long content: each item on separate line
1284
+ this.updateBeforeNextTokenByNode(leftParen, '');
1285
+ this.addIndent();
1286
+ // Format commas
1287
+ const commas = ctx.COMMA();
1288
+ for (const comma of commas) {
1289
+ this.updateAfterPreviousTokenByNode(comma, '');
1290
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1291
+ }
1292
+ this.updateBeforeNextTokenByNode(rightParen, this.newlineIndent);
1293
+ super.visitChildren(ctx);
1294
+ this.minusIndent();
1295
+ }
1296
+ else {
1297
+ // Short content: compact format on same line - no space inside parens
1298
+ this.updateBeforeNextTokenByNode(leftParen, '');
1299
+ this.updateAfterPreviousTokenByNode(rightParen, '');
1300
+ super.visitChildren(ctx);
1301
+ }
1302
+ }
1303
+ else {
1304
+ super.visitChildren(ctx);
1305
+ }
1306
+ }
1307
+ visitGroupingSet(ctx) {
1308
+ const leftParen = ctx.LEFT_PAREN();
1309
+ const rightParen = ctx.RIGHT_PAREN();
1310
+ if (leftParen && rightParen) {
1311
+ // Compact parentheses format - no extra spaces inside
1312
+ this.updateBeforeNextTokenByNode(leftParen, '');
1313
+ this.updateAfterPreviousTokenByNode(rightParen, '');
1314
+ // Format commas - space after, no space before
1315
+ const commas = ctx.COMMA();
1316
+ for (const comma of commas) {
1317
+ this.updateAfterPreviousTokenByNode(comma, '');
1318
+ this.updateBeforeNextTokenByNode(comma, ' ');
1319
+ }
1320
+ }
1321
+ super.visitChildren(ctx);
1322
+ }
1323
+ // ==================== PIVOT/UNPIVOT ====================
1324
+ visitPivotClause(ctx) {
1325
+ const leftParen = ctx.LEFT_PAREN();
1326
+ const rightParen = ctx.RIGHT_PAREN();
1327
+ const namedExprSeq = ctx.namedExpressionSeq();
1328
+ // Count aggregation expressions
1329
+ const namedExpressions = namedExprSeq?.namedExpression() || [];
1330
+ const hasMultipleAggregations = namedExpressions.length > 1;
1331
+ // Check content length to determine format
1332
+ const PIVOT_MAX_LENGTH = 80;
1333
+ const contentLength = ctx.stop.stopIndex - ctx.start.startIndex;
1334
+ const isLongContent = contentLength > PIVOT_MAX_LENGTH;
1335
+ if (hasMultipleAggregations || isLongContent) {
1336
+ // Multiple aggregations or long content: PIVOT on separate line with extra indent
1337
+ // Format:
1338
+ // FROM
1339
+ // t
1340
+ // PIVOT (
1341
+ // SUM(amount) FOR year IN (
1342
+ // 2020,
1343
+ // 2021
1344
+ // )
1345
+ // );
1346
+ // Or with multiple aggregations:
1347
+ // PIVOT (
1348
+ // SUM(a),
1349
+ // SUM(b) FOR year IN (
1350
+ // 2020,
1351
+ // 2021
1352
+ // )
1353
+ // );
1354
+ this.addIndent();
1355
+ this.updateAfterPreviousTokenByNode(ctx.PIVOT(), this.newlineIndent);
1356
+ // Left paren after PIVOT - space before, newline + indent after
1357
+ if (leftParen && leftParen.length > 0) {
1358
+ this.updateAfterPreviousTokenByNode(leftParen[0], ' ');
1359
+ this.addIndent();
1360
+ this.updateBeforeNextTokenByNode(leftParen[0], this.newlineIndent);
1361
+ }
1362
+ // Format multiple aggregations - each on new line
1363
+ if (hasMultipleAggregations && namedExprSeq) {
1364
+ const commas = namedExprSeq.COMMA();
1365
+ for (const comma of commas) {
1366
+ this.updateAfterPreviousTokenByNode(comma, '');
1367
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1368
+ }
1369
+ }
1370
+ // Format FOR keyword - space before and after
1371
+ if (ctx.FOR()) {
1372
+ this.updateAfterPreviousTokenByNode(ctx.FOR(), ' ');
1373
+ this.updateBeforeNextTokenByNode(ctx.FOR(), ' ');
1374
+ }
1375
+ // Format IN keyword - space before and after
1376
+ if (ctx.IN()) {
1377
+ this.updateAfterPreviousTokenByNode(ctx.IN(), ' ');
1378
+ this.updateBeforeNextTokenByNode(ctx.IN(), ' ');
1379
+ }
1380
+ // IN clause left paren - space before, newline + indent after
1381
+ if (leftParen && leftParen.length > 1) {
1382
+ this.updateAfterPreviousTokenByNode(leftParen[1], ' ');
1383
+ this.addIndent();
1384
+ this.updateBeforeNextTokenByNode(leftParen[1], this.newlineIndent);
1385
+ }
1386
+ // Format pivot values - each on new line
1387
+ const pivotCommas = ctx.COMMA();
1388
+ for (const comma of pivotCommas) {
1389
+ this.updateAfterPreviousTokenByNode(comma, '');
1390
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1391
+ }
1392
+ // Right paren for IN clause - need to use direct edit for proper indent
1393
+ if (rightParen && rightParen.length > 0) {
1394
+ // IN right paren should align with 'SUM(amount) FOR year IN ('
1395
+ // First minusIndent to go back to that level
1396
+ this.minusIndent();
1397
+ const inClosingIndent = this.newlineIndent;
1398
+ this.bridge.collector.addEdit({
1399
+ range: {
1400
+ start: {
1401
+ line: rightParen[0].symbol.line - 1,
1402
+ character: rightParen[0].symbol.charPositionInLine
1403
+ },
1404
+ end: {
1405
+ line: rightParen[0].symbol.line - 1,
1406
+ character: rightParen[0].symbol.charPositionInLine
1407
+ }
1408
+ },
1409
+ newText: inClosingIndent
1410
+ }, { level: 10, source: 'pivot-in-right-paren' });
1411
+ }
1412
+ // Right paren for PIVOT main - need to use direct edit for proper indent
1413
+ if (rightParen && rightParen.length > 1) {
1414
+ // PIVOT right paren should align with 'PIVOT ('
1415
+ this.minusIndent();
1416
+ const pivotClosingIndent = this.newlineIndent;
1417
+ this.bridge.collector.addEdit({
1418
+ range: {
1419
+ start: {
1420
+ line: rightParen[1].symbol.line - 1,
1421
+ character: rightParen[1].symbol.charPositionInLine
1422
+ },
1423
+ end: {
1424
+ line: rightParen[1].symbol.line - 1,
1425
+ character: rightParen[1].symbol.charPositionInLine
1426
+ }
1427
+ },
1428
+ newText: pivotClosingIndent
1429
+ }, { level: 10, source: 'pivot-right-paren' });
1430
+ }
1431
+ else if (rightParen && rightParen.length === 1) {
1432
+ // Only one right paren (shouldn't happen but handle gracefully)
1433
+ this.minusIndent();
1434
+ const pivotClosingIndent = this.newlineIndent;
1435
+ this.bridge.collector.addEdit({
1436
+ range: {
1437
+ start: {
1438
+ line: rightParen[0].symbol.line - 1,
1439
+ character: rightParen[0].symbol.charPositionInLine
1440
+ },
1441
+ end: {
1442
+ line: rightParen[0].symbol.line - 1,
1443
+ character: rightParen[0].symbol.charPositionInLine
1444
+ }
1445
+ },
1446
+ newText: pivotClosingIndent
1447
+ }, { level: 10, source: 'pivot-right-paren' });
1448
+ }
1449
+ super.visitChildren(ctx);
1450
+ this.minusIndent(); // PIVOT indent
1451
+ }
1452
+ else {
1453
+ // Single aggregation, short content: PIVOT on same line as table
1454
+ // Format: FROM t PIVOT (SUM(amount) FOR year IN (2020, 2021, 2022))
1455
+ this.updateAfterPreviousTokenByNode(ctx.PIVOT(), ' ');
1456
+ // Left paren after PIVOT - ensure space before, no space after
1457
+ // Note: leftParen[0] is the main PIVOT parenthesis
1458
+ // We need to handle the space between PIVOT and (
1459
+ // updateAfterPreviousTokenByNode handles the space before leftParen[0]
1460
+ // We don't need to call updateBeforeNextTokenByNode(leftParen[0]) because
1461
+ // it would affect content after the paren
1462
+ // Format FOR keyword
1463
+ if (ctx.FOR()) {
1464
+ this.updateAfterPreviousTokenByNode(ctx.FOR(), ' ');
1465
+ this.updateBeforeNextTokenByNode(ctx.FOR(), ' ');
1466
+ }
1467
+ // Format IN keyword
1468
+ if (ctx.IN()) {
1469
+ this.updateAfterPreviousTokenByNode(ctx.IN(), ' ');
1470
+ this.updateBeforeNextTokenByNode(ctx.IN(), ' ');
1471
+ }
1472
+ // IN clause parentheses - leftParen[1] is the IN parenthesis
1473
+ // Ensure space before IN (
1474
+ if (leftParen && leftParen.length > 1) {
1475
+ this.updateAfterPreviousTokenByNode(leftParen[1], ' ');
1476
+ }
1477
+ // Right parens - no extra space
1478
+ if (rightParen && rightParen.length > 0) {
1479
+ this.updateAfterPreviousTokenByNode(rightParen[0], '');
1480
+ }
1481
+ if (rightParen && rightParen.length > 1) {
1482
+ this.updateAfterPreviousTokenByNode(rightParen[1], '');
1483
+ }
1484
+ // Format pivot values - compact (comma space)
1485
+ const pivotCommas = ctx.COMMA();
1486
+ for (const comma of pivotCommas) {
1487
+ this.updateAfterPreviousTokenByNode(comma, '');
1488
+ this.updateBeforeNextTokenByNode(comma, ' ');
1489
+ }
1490
+ // Skip strategy formatting for namedExpressionSeq in PIVOT - visit children directly
1491
+ // This prevents unwanted newlines inside short PIVOT clauses
1492
+ const children = ctx.children;
1493
+ if (children) {
1494
+ for (const child of children) {
1495
+ if (child instanceof ParserRuleContext_1.ParserRuleContext) {
1496
+ // Skip namedExpressionSeq - it's already formatted above
1497
+ if (child.constructor.name !== 'NamedExpressionSeqContext') {
1498
+ this.visit(child);
1499
+ }
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ visitUnpivotClause(ctx) {
1506
+ const leftParen = ctx.LEFT_PAREN();
1507
+ const rightParen = ctx.RIGHT_PAREN();
1508
+ const nullClause = ctx.unpivotNullClause();
1509
+ // Check content length to determine format
1510
+ const UNPIVOT_MAX_LENGTH = 80;
1511
+ const contentLength = ctx.stop.stopIndex - ctx.start.startIndex;
1512
+ const isLongContent = contentLength > UNPIVOT_MAX_LENGTH;
1513
+ if (isLongContent) {
1514
+ // Long content: UNPIVOT on separate line with extra indent
1515
+ // Format:
1516
+ // FROM t
1517
+ // UNPIVOT INCLUDE NULLS (
1518
+ // val FOR col IN (
1519
+ // a,
1520
+ // b,
1521
+ // c
1522
+ // )
1523
+ // )
1524
+ this.addIndent();
1525
+ this.updateAfterPreviousTokenByNode(ctx.UNPIVOT(), this.newlineIndent);
1526
+ // INCLUDE/EXCLUDE NULLS from nullClause
1527
+ if (nullClause) {
1528
+ if (nullClause.INCLUDE()) {
1529
+ this.updateAfterPreviousTokenByNode(nullClause.INCLUDE(), ' ');
1530
+ this.updateBeforeNextTokenByNode(nullClause.INCLUDE(), ' ');
1531
+ }
1532
+ if (nullClause.EXCLUDE()) {
1533
+ this.updateAfterPreviousTokenByNode(nullClause.EXCLUDE(), ' ');
1534
+ this.updateBeforeNextTokenByNode(nullClause.EXCLUDE(), ' ');
1535
+ }
1536
+ if (nullClause.NULLS()) {
1537
+ this.updateAfterPreviousTokenByNode(nullClause.NULLS(), ' ');
1538
+ this.updateBeforeNextTokenByNode(nullClause.NULLS(), ' ');
1539
+ }
1540
+ }
1541
+ // Left paren - space before, newline + indent after
1542
+ if (leftParen) {
1543
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
1544
+ // Add indent BEFORE newline so content inside has proper indent
1545
+ this.addIndent();
1546
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
1547
+ }
1548
+ else {
1549
+ // No left paren, but still need indent for content
1550
+ this.addIndent();
1551
+ }
1552
+ // Set flag for IN clause formatting
1553
+ this.inUnpivotLongContent = true;
1554
+ // Visit children to handle IN clause
1555
+ const operator = ctx.unpivotOperator();
1556
+ if (operator) {
1557
+ this.visit(operator);
1558
+ }
1559
+ // Reset flag
1560
+ this.inUnpivotLongContent = false;
1561
+ // Right paren on new line - should have same indent as UNPIVOT line
1562
+ if (rightParen) {
1563
+ // UNPIVOT right paren should be at indent level 2 (4 spaces)
1564
+ // Current level is 3 (after IN clause minusIndent), need to go to level 2
1565
+ this.minusIndent();
1566
+ const closingIndent = this.newlineIndent;
1567
+ // Use direct edit since previous edit might conflict
1568
+ this.bridge.collector.addEdit({
1569
+ range: {
1570
+ start: {
1571
+ line: rightParen.symbol.line - 1,
1572
+ character: rightParen.symbol.charPositionInLine
1573
+ },
1574
+ end: {
1575
+ line: rightParen.symbol.line - 1,
1576
+ character: rightParen.symbol.charPositionInLine
1577
+ }
1578
+ },
1579
+ newText: closingIndent
1580
+ }, { level: 10, source: 'unpivot-right-paren' });
1581
+ }
1582
+ else {
1583
+ this.minusIndent();
1584
+ }
1585
+ this.minusIndent(); // UNPIVOT indent
1586
+ }
1587
+ else {
1588
+ // Short content: UNPIVOT on same line as table
1589
+ this.updateAfterPreviousTokenByNode(ctx.UNPIVOT(), ' ');
1590
+ // INCLUDE/EXCLUDE NULLS from nullClause
1591
+ if (nullClause) {
1592
+ if (nullClause.INCLUDE()) {
1593
+ this.updateAfterPreviousTokenByNode(nullClause.INCLUDE(), ' ');
1594
+ this.updateBeforeNextTokenByNode(nullClause.INCLUDE(), ' ');
1595
+ }
1596
+ if (nullClause.EXCLUDE()) {
1597
+ this.updateAfterPreviousTokenByNode(nullClause.EXCLUDE(), ' ');
1598
+ this.updateBeforeNextTokenByNode(nullClause.EXCLUDE(), ' ');
1599
+ }
1600
+ if (nullClause.NULLS()) {
1601
+ this.updateAfterPreviousTokenByNode(nullClause.NULLS(), ' ');
1602
+ this.updateBeforeNextTokenByNode(nullClause.NULLS(), ' ');
1603
+ }
1604
+ }
1605
+ // Left paren - space before, no space after
1606
+ if (leftParen) {
1607
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
1608
+ }
1609
+ // Right paren - no extra space
1610
+ if (rightParen) {
1611
+ this.updateAfterPreviousTokenByNode(rightParen, '');
1612
+ }
1613
+ super.visitChildren(ctx);
1614
+ }
1615
+ }
1616
+ visitUnpivotSingleValueColumnClause(ctx) {
1617
+ // Format: val FOR col IN (a, b, c)
1618
+ const inToken = ctx.IN();
1619
+ const leftParen = ctx.LEFT_PAREN();
1620
+ const rightParen = ctx.RIGHT_PAREN();
1621
+ const commas = ctx.COMMA();
1622
+ if (this.inUnpivotLongContent) {
1623
+ // Format IN clause with newlines
1624
+ // val FOR col IN (
1625
+ // a,
1626
+ // b,
1627
+ // c
1628
+ // )
1629
+ if (inToken) {
1630
+ this.updateAfterPreviousTokenByNode(inToken, ' ');
1631
+ this.updateBeforeNextTokenByNode(inToken, ' ');
1632
+ }
1633
+ if (leftParen) {
1634
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
1635
+ // Add indent before newline+indent for elements
1636
+ this.addIndent();
1637
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
1638
+ }
1639
+ // Commas - each element on new line with current indent
1640
+ for (const comma of commas) {
1641
+ this.updateAfterPreviousTokenByNode(comma, '');
1642
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
1643
+ }
1644
+ if (rightParen) {
1645
+ // IN clause right paren should align with 'val FOR col IN ('
1646
+ // First minusIndent to go back to that level
1647
+ this.minusIndent();
1648
+ // Now save the indent for IN closing paren
1649
+ const inClosingIndent = this.newlineIndent;
1650
+ // Use direct edit to insert before the right paren
1651
+ this.bridge.collector.addEdit({
1652
+ range: {
1653
+ start: {
1654
+ line: rightParen.symbol.line - 1,
1655
+ character: rightParen.symbol.charPositionInLine
1656
+ },
1657
+ end: {
1658
+ line: rightParen.symbol.line - 1,
1659
+ character: rightParen.symbol.charPositionInLine
1660
+ }
1661
+ },
1662
+ newText: inClosingIndent
1663
+ }, { level: 10, source: 'unpivot-in-right-paren' });
1664
+ }
1665
+ // Visit children to format column names
1666
+ super.visitChildren(ctx);
1667
+ }
1668
+ else {
1669
+ // Compact format
1670
+ if (inToken) {
1671
+ this.updateAfterPreviousTokenByNode(inToken, ' ');
1672
+ this.updateBeforeNextTokenByNode(inToken, ' ');
1673
+ }
1674
+ if (leftParen) {
1675
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
1676
+ }
1677
+ if (rightParen) {
1678
+ this.updateAfterPreviousTokenByNode(rightParen, '');
1679
+ }
1680
+ for (const comma of commas) {
1681
+ this.updateAfterPreviousTokenByNode(comma, '');
1682
+ this.updateBeforeNextTokenByNode(comma, ' ');
1683
+ }
1684
+ super.visitChildren(ctx);
1685
+ }
1686
+ }
1687
+ visitUnpivotMultiValueColumnClause(ctx) {
1688
+ // Similar handling for multi value column clause
1689
+ super.visitChildren(ctx);
1690
+ }
1691
+ // ==================== Table Definition ====================
1692
+ visitCreateFileFormat(ctx) {
1693
+ // STORED AS or STORED BY
1694
+ const storedNode = ctx.STORED();
1695
+ const asNode = ctx.AS();
1696
+ const byNode = ctx.BY();
1697
+ if (storedNode) {
1698
+ this.updateAfterPreviousTokenByNode(storedNode, this.newlineIndent);
1699
+ this.updateBeforeNextTokenByNode(storedNode, ' ');
1700
+ }
1701
+ if (asNode) {
1702
+ this.updateAfterPreviousTokenByNode(asNode, ' ');
1703
+ this.updateBeforeNextTokenByNode(asNode, ' ');
1704
+ }
1705
+ if (byNode) {
1706
+ this.updateAfterPreviousTokenByNode(byNode, ' ');
1707
+ this.updateBeforeNextTokenByNode(byNode, ' ');
1708
+ }
1709
+ // Check for INPUTFORMAT/OUTPUTFORMAT (tableFileFormat)
1710
+ const fileFormat = ctx.fileFormat();
1711
+ if (fileFormat && fileFormat instanceof SparkSQLParser_1.TableFileFormatContext) {
1712
+ const inputFormat = fileFormat.INPUTFORMAT();
1713
+ const outputFormat = fileFormat.OUTPUTFORMAT();
1714
+ const stringLits = fileFormat.stringLit();
1715
+ // Check if line is too long - use stop/start position for accurate length
1716
+ const contentLength = ctx.stop.stopIndex - ctx.start.startIndex;
1717
+ const isLongContent = contentLength > this.maxParenthesisLength;
1718
+ if (isLongContent) {
1719
+ // Long content format:
1720
+ // STORED AS INPUTFORMAT
1721
+ // 'string'
1722
+ // OUTPUTFORMAT
1723
+ // 'string'
1724
+ // INPUTFORMAT stays on same line as STORED AS
1725
+ if (inputFormat) {
1726
+ this.updateAfterPreviousTokenByNode(inputFormat, ' ');
1727
+ this.updateBeforeNextTokenByNode(inputFormat, ' ');
1728
+ }
1729
+ // String value on new line with indent
1730
+ if (stringLits.length > 0) {
1731
+ this.addIndent();
1732
+ this.updateAfterPreviousTokenByContext(stringLits[0], this.newlineIndent);
1733
+ this.minusIndent();
1734
+ }
1735
+ // OUTPUTFORMAT on new line (no extra indent)
1736
+ if (outputFormat) {
1737
+ this.updateAfterPreviousTokenByNode(outputFormat, this.newlineIndent);
1738
+ this.updateBeforeNextTokenByNode(outputFormat, ' ');
1739
+ }
1740
+ // String value on new line with indent
1741
+ if (stringLits.length > 1) {
1742
+ this.addIndent();
1743
+ this.updateAfterPreviousTokenByContext(stringLits[1], this.newlineIndent);
1744
+ this.minusIndent();
1745
+ }
1746
+ }
1747
+ else {
1748
+ // Short content: all on same line with spaces
1749
+ if (inputFormat) {
1750
+ this.updateAfterPreviousTokenByNode(inputFormat, ' ');
1751
+ this.updateBeforeNextTokenByNode(inputFormat, ' ');
1752
+ }
1753
+ if (outputFormat) {
1754
+ this.updateAfterPreviousTokenByNode(outputFormat, ' ');
1755
+ this.updateBeforeNextTokenByNode(outputFormat, ' ');
1756
+ }
1757
+ }
1758
+ }
1759
+ super.visitChildren(ctx);
1760
+ }
1761
+ visitBucketSpec(ctx) {
1762
+ // CLUSTERED BY
1763
+ const clusteredNode = ctx.CLUSTERED();
1764
+ const byTokens = ctx.BY();
1765
+ if (clusteredNode) {
1766
+ this.updateAfterPreviousTokenByNode(clusteredNode, ' ');
1767
+ this.updateBeforeNextTokenByNode(clusteredNode, ' ');
1768
+ }
1769
+ if (byTokens.length > 0) {
1770
+ this.updateAfterPreviousTokenByNode(byTokens[0], ' ');
1771
+ this.updateBeforeNextTokenByNode(byTokens[0], ' ');
1772
+ }
1773
+ // SORTED BY (optional)
1774
+ const sortedNode = ctx.SORTED();
1775
+ if (sortedNode && byTokens.length > 1) {
1776
+ this.updateAfterPreviousTokenByNode(sortedNode, ' ');
1777
+ this.updateBeforeNextTokenByNode(sortedNode, ' ');
1778
+ this.updateAfterPreviousTokenByNode(byTokens[1], ' ');
1779
+ this.updateBeforeNextTokenByNode(byTokens[1], ' ');
1780
+ }
1781
+ // INTO n BUCKETS
1782
+ const intoNode = ctx.INTO();
1783
+ const bucketsNode = ctx.BUCKETS();
1784
+ if (intoNode) {
1785
+ this.updateAfterPreviousTokenByNode(intoNode, ' ');
1786
+ this.updateBeforeNextTokenByNode(intoNode, ' ');
1787
+ }
1788
+ if (bucketsNode) {
1789
+ this.updateAfterPreviousTokenByNode(bucketsNode, ' ');
1790
+ }
1791
+ super.visitChildren(ctx);
1792
+ }
1793
+ visitSample(ctx) {
1794
+ const tablesample = ctx.TABLESAMPLE();
1795
+ const repeatable = ctx.REPEATABLE();
1796
+ const leftParens = ctx.LEFT_PAREN();
1797
+ const rightParens = ctx.RIGHT_PAREN();
1798
+ // TABLESAMPLE - space after
1799
+ if (tablesample) {
1800
+ this.updateAfterPreviousTokenByNode(tablesample, ' ');
1801
+ this.updateBeforeNextTokenByNode(tablesample, ' ');
1802
+ }
1803
+ // Parentheses - compact format
1804
+ for (const leftParen of leftParens) {
1805
+ this.updateBeforeNextTokenByNode(leftParen, '');
1806
+ this.updateAfterPreviousTokenByNode(leftParen, '');
1807
+ }
1808
+ for (const rightParen of rightParens) {
1809
+ this.updateAfterPreviousTokenByNode(rightParen, '');
1810
+ }
1811
+ // REPEATABLE - space before and after
1812
+ if (repeatable) {
1813
+ this.updateAfterPreviousTokenByNode(repeatable, ' ');
1814
+ this.updateBeforeNextTokenByNode(repeatable, ' ');
1815
+ }
1816
+ super.visitChildren(ctx);
1817
+ }
1818
+ // ==================== CASE WHEN Expression ====================
1819
+ visitSearchedCase(ctx) {
1820
+ const _caseNode = ctx.CASE();
1821
+ const endNode = ctx.END();
1822
+ const elseNode = ctx.ELSE();
1823
+ const whenClauses = ctx.whenClause();
1824
+ const elseExpr = ctx.expression();
1825
+ // 增加 CASE 内部缩进(WHEN/ELSE 使用)
1826
+ this.addIndent();
1827
+ // 手动处理每个 WHEN 子句
1828
+ for (let i = 0; i < whenClauses.length; i++) {
1829
+ const whenClause = whenClauses[i];
1830
+ const thenNode = whenClause.THEN();
1831
+ const expressions = whenClause.expression();
1832
+ // 每个 WHEN 前换行(包括第一个),这样 CASE 后自动换行
1833
+ this.updateAfterPreviousTokenByContext(whenClause, this.newlineIndent);
1834
+ // 检查 THEN 后是否是嵌套 CASE WHEN
1835
+ const resultExpr = expressions && expressions.length > 1 ? expressions[1] : null;
1836
+ const isNestedCase = resultExpr && this.isCaseWhenExpression(resultExpr);
1837
+ if (isNestedCase) {
1838
+ // 嵌套 CASE 特殊格式:WHEN 条件换行
1839
+ // 先增加缩进用于条件表达式
1840
+ this.addIndent();
1841
+ const whenNode = whenClause.WHEN();
1842
+ if (whenNode) {
1843
+ // WHEN 后换行 + 缩进(此时缩进已增加)
1844
+ this.updateBeforeNextTokenByNode(whenNode, this.newlineIndent);
1845
+ }
1846
+ // 访问条件表达式
1847
+ if (expressions && expressions.length > 0) {
1848
+ this.visit(expressions[0]);
1849
+ }
1850
+ // 减少缩进(回到 CASE 内部缩进)
1851
+ this.minusIndent();
1852
+ // THEN 独占一行
1853
+ if (thenNode) {
1854
+ // THEN 前换行(使用当前 CASE 内部缩进)
1855
+ this.updateAfterPreviousTokenByNode(thenNode, this.newlineIndent);
1856
+ // THEN 后换行:先增加缩进,再设置
1857
+ this.addIndent();
1858
+ this.updateBeforeNextTokenByNode(thenNode, this.newlineIndent);
1859
+ }
1860
+ // 访问嵌套 CASE 结果表达式
1861
+ if (expressions && expressions.length > 1) {
1862
+ this.visit(expressions[1]);
1863
+ }
1864
+ // 减少缩进(THEN 后增加的)
1865
+ if (thenNode) {
1866
+ this.minusIndent();
1867
+ }
1868
+ }
1869
+ else {
1870
+ // 普通格式:WHEN 条件不换行
1871
+ const whenNode = whenClause.WHEN();
1872
+ if (whenNode) {
1873
+ // WHEN 后空格
1874
+ this.updateBeforeNextTokenByNode(whenNode, ' ');
1875
+ }
1876
+ // 访问条件表达式
1877
+ if (expressions && expressions.length > 0) {
1878
+ this.visit(expressions[0]);
1879
+ }
1880
+ // THEN 前后空格
1881
+ if (thenNode) {
1882
+ this.updateBeforeNextTokenByNode(thenNode, ' ');
1883
+ // THEN 后空格
1884
+ this.updateAfterPreviousTokenByNode(thenNode, ' ');
1885
+ }
1886
+ // 访问结果表达式
1887
+ if (expressions && expressions.length > 1) {
1888
+ this.visit(expressions[1]);
1889
+ }
1890
+ }
1891
+ }
1892
+ // ELSE 前换行
1893
+ if (elseNode) {
1894
+ this.updateAfterPreviousTokenByNode(elseNode, this.newlineIndent);
1895
+ }
1896
+ // 访问 ELSE 后的表达式
1897
+ if (elseExpr) {
1898
+ this.visit(elseExpr);
1899
+ }
1900
+ // 减少 CASE 内部缩进
1901
+ this.minusIndent();
1902
+ // END 前换行(恢复到 CASE 同级缩进)
1903
+ if (endNode) {
1904
+ this.updateAfterPreviousTokenByNode(endNode, this.newlineIndent);
1905
+ }
1906
+ }
1907
+ /**
1908
+ * 检查表达式是否是 CASE WHEN 表达式
1909
+ */
1910
+ isCaseWhenExpression(ctx) {
1911
+ // 检查当前节点类型
1912
+ const className = ctx.constructor.name;
1913
+ if (className === 'SearchedCaseContext' || className === 'SimpleCaseContext') {
1914
+ return true;
1915
+ }
1916
+ // 递归检查子节点(因为 CASE WHEN 可能在括号内或其他表达式中)
1917
+ if (ctx.childCount > 0) {
1918
+ for (let i = 0; i < ctx.childCount; i++) {
1919
+ const child = ctx.getChild(i);
1920
+ if (child instanceof ParserRuleContext_1.ParserRuleContext) {
1921
+ if (this.isCaseWhenExpression(child)) {
1922
+ return true;
1923
+ }
1924
+ }
1925
+ }
1926
+ }
1927
+ return false;
1928
+ }
1929
+ visitSimpleCase(ctx) {
1930
+ const caseNode = ctx.CASE();
1931
+ const endNode = ctx.END();
1932
+ const elseNode = ctx.ELSE();
1933
+ const whenClauses = ctx.whenClause();
1934
+ const expressions = ctx.expression();
1935
+ // CASE 后空格(保留 case 值表达式在同一行)
1936
+ if (caseNode) {
1937
+ this.updateBeforeNextTokenByNode(caseNode, ' ');
1938
+ }
1939
+ // 访问 case 值表达式(第一个表达式)
1940
+ if (expressions && expressions.length > 0) {
1941
+ this.visit(expressions[0]);
1942
+ }
1943
+ // 增加 CASE 内部缩进(WHEN/ELSE 使用)
1944
+ this.addIndent();
1945
+ // 手动处理每个 WHEN 子句
1946
+ for (const whenClause of whenClauses) {
1947
+ const thenNode = whenClause.THEN();
1948
+ const whenExprs = whenClause.expression();
1949
+ // 每个 WHEN 前换行
1950
+ this.updateAfterPreviousTokenByContext(whenClause, this.newlineIndent);
1951
+ // 检查 THEN 后是否是嵌套 CASE WHEN
1952
+ const resultExpr = whenExprs && whenExprs.length > 1 ? whenExprs[1] : null;
1953
+ const isNestedCase = resultExpr && this.isCaseWhenExpression(resultExpr);
1954
+ if (isNestedCase) {
1955
+ // 嵌套 CASE 特殊格式:WHEN 值换行
1956
+ // 先增加缩进用于 WHEN 值表达式
1957
+ this.addIndent();
1958
+ const whenNode = whenClause.WHEN();
1959
+ if (whenNode) {
1960
+ // WHEN 后换行 + 缩进(此时缩进已增加)
1961
+ this.updateBeforeNextTokenByNode(whenNode, this.newlineIndent);
1962
+ }
1963
+ // 访问 WHEN 值表达式
1964
+ if (whenExprs && whenExprs.length > 0) {
1965
+ this.visit(whenExprs[0]);
1966
+ }
1967
+ // 减少缩进(回到 CASE 内部缩进)
1968
+ this.minusIndent();
1969
+ // THEN 独占一行
1970
+ if (thenNode) {
1971
+ // THEN 前换行(使用当前 CASE 内部缩进)
1972
+ this.updateAfterPreviousTokenByNode(thenNode, this.newlineIndent);
1973
+ // THEN 后换行:先增加缩进,再设置
1974
+ this.addIndent();
1975
+ this.updateBeforeNextTokenByNode(thenNode, this.newlineIndent);
1976
+ }
1977
+ // 访问嵌套 CASE 结果表达式
1978
+ if (whenExprs && whenExprs.length > 1) {
1979
+ this.visit(whenExprs[1]);
1980
+ }
1981
+ // 减少缩进(THEN 后增加的)
1982
+ if (thenNode) {
1983
+ this.minusIndent();
1984
+ }
1985
+ }
1986
+ else {
1987
+ // 普通格式:WHEN 值不换行
1988
+ const whenNode = whenClause.WHEN();
1989
+ if (whenNode) {
1990
+ // WHEN 后空格
1991
+ this.updateBeforeNextTokenByNode(whenNode, ' ');
1992
+ }
1993
+ // 访问 WHEN 值表达式
1994
+ if (whenExprs && whenExprs.length > 0) {
1995
+ this.visit(whenExprs[0]);
1996
+ }
1997
+ // THEN 前后空格
1998
+ if (thenNode) {
1999
+ this.updateBeforeNextTokenByNode(thenNode, ' ');
2000
+ // THEN 后空格
2001
+ this.updateAfterPreviousTokenByNode(thenNode, ' ');
2002
+ }
2003
+ // 访问结果表达式
2004
+ if (whenExprs && whenExprs.length > 1) {
2005
+ this.visit(whenExprs[1]);
2006
+ }
2007
+ }
2008
+ }
2009
+ // ELSE 前换行
2010
+ if (elseNode) {
2011
+ this.updateAfterPreviousTokenByNode(elseNode, this.newlineIndent);
2012
+ }
2013
+ // 访问 ELSE 后的表达式
2014
+ if (expressions && expressions.length > 1) {
2015
+ this.visit(expressions[1]);
2016
+ }
2017
+ // 减少 CASE 内部缩进
2018
+ this.minusIndent();
2019
+ // END 前换行(恢复到 CASE 同级缩进)
2020
+ if (endNode) {
2021
+ this.updateAfterPreviousTokenByNode(endNode, this.newlineIndent);
2022
+ }
2023
+ }
2024
+ visitWhenClause(_ctx) {
2025
+ // WHEN/THEN 的空格在 visitSearchedCase/visitSimpleCase 中处理
2026
+ // 这里不调用 super.visitChildren(ctx),因为子节点已经在上层处理过了
2027
+ }
2028
+ visitSetOperation(ctx) {
2029
+ // UNION, INTERSECT, EXCEPT, SETMINUS should be on their own line
2030
+ const unionNode = ctx.UNION();
2031
+ const intersectNode = ctx.INTERSECT();
2032
+ const exceptNode = ctx.EXCEPT();
2033
+ const setminusNode = ctx.SETMINUS();
2034
+ const operatorNode = unionNode || intersectNode || exceptNode || setminusNode;
2035
+ if (operatorNode) {
2036
+ // Operator keyword on new line
2037
+ this.updateAfterPreviousTokenByNode(operatorNode, this.newlineIndent);
2038
+ }
2039
+ // Handle setQuantifier (ALL/DISTINCT) - it should stay on same line as operator
2040
+ const setQuantifier = ctx.setQuantifier();
2041
+ if (setQuantifier) {
2042
+ // Space before ALL/DISTINCT
2043
+ this.updateAfterPreviousTokenByContext(setQuantifier, ' ');
2044
+ // Newline after ALL/DISTINCT, before right query
2045
+ this.updateBeforeNextTokenByContext(setQuantifier, this.newlineIndent);
2046
+ }
2047
+ // Right query should start on new line after UNION ALL / UNION / etc.
2048
+ // Only add newline if there's no setQuantifier (otherwise it's handled above)
2049
+ const rightQuery = ctx._right;
2050
+ if (rightQuery && !setQuantifier) {
2051
+ this.updateAfterPreviousTokenByContext(rightQuery, this.newlineIndent);
2052
+ }
2053
+ super.visitChildren(ctx);
2054
+ }
2055
+ visitSetQuantifier(ctx) {
2056
+ if (!this.tryFormatWithStrategy(ctx)) {
2057
+ super.visitChildren(ctx);
2058
+ }
2059
+ }
2060
+ visitNamedExpressionSeq(ctx) {
2061
+ if (!this.tryFormatWithStrategy(ctx)) {
2062
+ super.visitChildren(ctx);
2063
+ }
2064
+ }
2065
+ visitNamedExpression(ctx) {
2066
+ // Format AS keyword - ensure space before and after
2067
+ this.normalizeKeywordSpacing(ctx.AS());
2068
+ if (!this.tryFormatWithStrategy(ctx)) {
2069
+ super.visitChildren(ctx);
2070
+ }
2071
+ }
2072
+ // ==================== Column Type ====================
2073
+ visitColType(ctx) {
2074
+ // Single space between column name (identifier) and data type
2075
+ const dataType = ctx.dataType();
2076
+ if (dataType) {
2077
+ this.updateAfterPreviousTokenByContext(dataType, ' ');
2078
+ }
2079
+ // Handle COMMENT when there's no dataType - add space after column identifier
2080
+ const commentSpec = ctx.commentSpec();
2081
+ const identifier = ctx.errorCapturingIdentifier();
2082
+ if (!dataType && commentSpec && identifier) {
2083
+ // Add space after column identifier before COMMENT
2084
+ this.updateAfterPreviousTokenByContext(identifier, ' ');
2085
+ }
2086
+ // Handle NOT NULL
2087
+ const errorCapturingNot = ctx.errorCapturingNot();
2088
+ const nullNode = ctx.NULL();
2089
+ if (errorCapturingNot && nullNode) {
2090
+ this.updateAfterPreviousTokenByContext(errorCapturingNot, ' ');
2091
+ this.updateBeforeNextTokenByContext(errorCapturingNot, ' ');
2092
+ }
2093
+ super.visitChildren(ctx);
2094
+ }
2095
+ // ==================== JOIN ====================
2096
+ visitJoinRelation(ctx) {
2097
+ const bridge = this.getJoinFormattingBridge();
2098
+ const target = {
2099
+ joinContext: ctx,
2100
+ naturalKeyword: ctx.NATURAL() || undefined,
2101
+ joinKeyword: ctx.JOIN(),
2102
+ lateralKeyword: ctx.LATERAL() || undefined
2103
+ };
2104
+ if (this.inPipeOperatorRightSide) {
2105
+ strategies_1.coreStrategies.join.formatJoinEntry(target, bridge, { separatorBeforeJoin: ' ' });
2106
+ super.visitChildren(ctx);
2107
+ return;
2108
+ }
2109
+ // Check if there is ON clause (not USING - USING should stay on same line)
2110
+ const joinCriteria = ctx.joinCriteria();
2111
+ const hasOnClause = joinCriteria && joinCriteria.ON();
2112
+ // Check if NATURAL JOIN (no ON clause needed)
2113
+ const isNaturalJoin = ctx.NATURAL() !== null && ctx.NATURAL() !== undefined;
2114
+ // Check if CROSS JOIN (no ON clause needed)
2115
+ const joinType = ctx.joinType();
2116
+ const isCrossJoin = joinType && joinType.CROSS() !== null && joinType.CROSS() !== undefined;
2117
+ // Check if this JOIN is right after a closing parenthesis (inside parentheses)
2118
+ let isAfterClosingParen = false;
2119
+ if (isCrossJoin || isNaturalJoin) {
2120
+ const joinKeyword = ctx.JOIN();
2121
+ if (joinKeyword) {
2122
+ const _prevToken = this.getPreviousNonHiddenTokenByStartIndex(joinKeyword.symbol.startIndex);
2123
+ // Check if previous token is ) or the token before JOIN keyword is )
2124
+ // For CROSS JOIN, need to check before CROSS keyword
2125
+ const crossKeyword = joinType?.CROSS();
2126
+ const naturalKeyword = ctx.NATURAL();
2127
+ const checkToken = crossKeyword || naturalKeyword || joinKeyword;
2128
+ if (checkToken) {
2129
+ const tokenBeforeJoin = this.getPreviousNonHiddenTokenByStartIndex(checkToken.symbol.startIndex);
2130
+ isAfterClosingParen = tokenBeforeJoin?.text === ')';
2131
+ }
2132
+ }
2133
+ }
2134
+ if (hasOnClause) {
2135
+ // Has ON: JOIN should be on new line with extra indent
2136
+ // Rule: JOIN relative to table name +1 indent level (total 2 levels, 4 spaces)
2137
+ this.addIndent();
2138
+ strategies_1.coreStrategies.join.formatJoinEntry(target, bridge, { separatorBeforeJoin: this.newlineIndent });
2139
+ super.visitChildren(ctx);
2140
+ this.minusIndent();
2141
+ }
2142
+ else if (isAfterClosingParen) {
2143
+ // JOIN after closing parenthesis inside parentheses: should be on new line with indent
2144
+ this.addIndent();
2145
+ strategies_1.coreStrategies.join.formatJoinEntry(target, bridge, { separatorBeforeJoin: this.newlineIndent });
2146
+ super.visitChildren(ctx);
2147
+ this.minusIndent();
2148
+ }
2149
+ else if (isNaturalJoin || isCrossJoin) {
2150
+ // NATURAL or CROSS JOIN: stays on same line as previous table
2151
+ // Rule 6: No ON, JOIN does not break line
2152
+ strategies_1.coreStrategies.join.formatJoinEntry(target, bridge, { separatorBeforeJoin: ' ' });
2153
+ super.visitChildren(ctx);
2154
+ }
2155
+ else {
2156
+ // Other JOINs without ON (may have USING or no criteria)
2157
+ // Check for USING - stays on same line
2158
+ const hasUsingClause = joinCriteria && joinCriteria.USING();
2159
+ if (hasUsingClause) {
2160
+ strategies_1.coreStrategies.join.formatJoinEntry(target, bridge, { separatorBeforeJoin: ' ' });
2161
+ super.visitChildren(ctx);
2162
+ }
2163
+ else {
2164
+ // No criteria at all - check if this is expected or error
2165
+ // For now, treat as no line break
2166
+ strategies_1.coreStrategies.join.formatJoinEntry(target, bridge, { separatorBeforeJoin: ' ' });
2167
+ super.visitChildren(ctx);
2168
+ }
2169
+ }
2170
+ }
2171
+ visitJoinType(ctx) {
2172
+ if (ctx.LEFT())
2173
+ this.updateBeforeNextTokenByNode(ctx.LEFT(), ' ');
2174
+ if (ctx.RIGHT())
2175
+ this.updateBeforeNextTokenByNode(ctx.RIGHT(), ' ');
2176
+ if (ctx.FULL())
2177
+ this.updateBeforeNextTokenByNode(ctx.FULL(), ' ');
2178
+ if (ctx.OUTER()) {
2179
+ this.updateAfterPreviousTokenByNode(ctx.OUTER(), ' ');
2180
+ this.updateBeforeNextTokenByNode(ctx.OUTER(), ' ');
2181
+ }
2182
+ if (ctx.INNER())
2183
+ this.updateBeforeNextTokenByNode(ctx.INNER(), ' ');
2184
+ if (ctx.CROSS())
2185
+ this.updateBeforeNextTokenByNode(ctx.CROSS(), ' ');
2186
+ if (ctx.SEMI()) {
2187
+ this.updateAfterPreviousTokenByNode(ctx.SEMI(), ' ');
2188
+ this.updateBeforeNextTokenByNode(ctx.SEMI(), ' ');
2189
+ }
2190
+ if (ctx.ANTI()) {
2191
+ this.updateAfterPreviousTokenByNode(ctx.ANTI(), ' ');
2192
+ this.updateBeforeNextTokenByNode(ctx.ANTI(), ' ');
2193
+ }
2194
+ super.visitChildren(ctx);
2195
+ }
2196
+ visitJoinCriteria(ctx) {
2197
+ const bridge = this.getJoinFormattingBridge();
2198
+ const target = {
2199
+ criteriaContext: ctx,
2200
+ usingKeyword: ctx.USING() || undefined,
2201
+ onKeyword: ctx.ON() || undefined,
2202
+ bodyStart: (ctx.booleanExpression() || ctx.identifierList()) ?? undefined
2203
+ };
2204
+ if (this.inPipeOperatorRightSide) {
2205
+ // In pipe context: ON should be on new line with pipe content indent
2206
+ if (ctx.ON()) {
2207
+ strategies_1.coreStrategies.join.formatJoinCriteriaEntry(target, bridge, {
2208
+ separatorBeforeCriteriaKeyword: this.context.getPipeContentIndent(),
2209
+ separatorAfterCriteriaKeyword: ' '
2210
+ });
2211
+ }
2212
+ else {
2213
+ // USING clause: stays on same line
2214
+ strategies_1.coreStrategies.join.formatJoinCriteriaEntry(target, bridge, {
2215
+ separatorBeforeCriteriaKeyword: ' ',
2216
+ separatorAfterCriteriaKeyword: ''
2217
+ });
2218
+ }
2219
+ super.visitChildren(ctx);
2220
+ return;
2221
+ }
2222
+ // ON clause: should be on new line with extra indent (relative to JOIN)
2223
+ // Rule: ON relative to JOIN +1 indent level (total 3 levels, 6 spaces)
2224
+ if (ctx.ON()) {
2225
+ this.addIndent();
2226
+ // Check if the ON clause starts with a parenthesized expression
2227
+ const booleanExpr = ctx.booleanExpression();
2228
+ const startsWithParen = booleanExpr && this.expressionStartsWithParen(booleanExpr);
2229
+ if (startsWithParen) {
2230
+ // ON (condition): keep space after ON, let ParenthesisStrategy handle the paren
2231
+ strategies_1.coreStrategies.join.formatJoinCriteriaEntry(target, bridge, {
2232
+ separatorBeforeCriteriaKeyword: this.newlineIndent,
2233
+ separatorAfterCriteriaKeyword: ' '
2234
+ });
2235
+ }
2236
+ else {
2237
+ // Normal ON clause: space after ON
2238
+ strategies_1.coreStrategies.join.formatJoinCriteriaEntry(target, bridge, {
2239
+ separatorBeforeCriteriaKeyword: this.newlineIndent,
2240
+ separatorAfterCriteriaKeyword: ' '
2241
+ });
2242
+ }
2243
+ super.visitChildren(ctx);
2244
+ this.minusIndent();
2245
+ }
2246
+ else {
2247
+ // USING clause: stays on same line as JOIN
2248
+ // Rule 6: No ON, does not break line
2249
+ strategies_1.coreStrategies.join.formatJoinCriteriaEntry(target, bridge, {
2250
+ separatorBeforeCriteriaKeyword: ' ',
2251
+ separatorAfterCriteriaKeyword: ''
2252
+ });
2253
+ super.visitChildren(ctx);
2254
+ }
2255
+ }
2256
+ expressionStartsWithParen(expr) {
2257
+ // Check if expression starts with a parenthesis
2258
+ const text = expr.text || '';
2259
+ return text.trimStart().startsWith('(');
2260
+ }
2261
+ visitLateralView(ctx) {
2262
+ if (this.inPipeOperatorRightSide) {
2263
+ super.visitChildren(ctx);
2264
+ return;
2265
+ }
2266
+ // LATERAL VIEW on new line with one level indent (relative to FROM)
2267
+ // Get the previous token (should be the end of relation or previous lateral view)
2268
+ const lateralToken = ctx.LATERAL();
2269
+ if (lateralToken) {
2270
+ // Find the previous non-hidden token
2271
+ const prevToken = this.getPreviousNonHiddenToken(lateralToken.symbol.tokenIndex);
2272
+ if (prevToken) {
2273
+ // Insert newline + indent between previous token and LATERAL
2274
+ const prevEndPos = this.getTokenEndPosition(prevToken);
2275
+ // Use high priority to ensure this edit is not overridden
2276
+ this.bridge.collector.addEdit({
2277
+ range: {
2278
+ start: prevEndPos,
2279
+ end: { line: lateralToken.symbol.line - 1, character: lateralToken.symbol.charPositionInLine }
2280
+ },
2281
+ newText: this.newlineIndent
2282
+ }, { level: 10, source: 'lateralView' });
2283
+ }
2284
+ }
2285
+ const viewToken = ctx.VIEW();
2286
+ const outerToken = ctx.OUTER();
2287
+ if (lateralToken && viewToken) {
2288
+ // Skip updateAfterPreviousTokenByNode(lateralToken) - already handled by newline+indent above
2289
+ this.updateBeforeNextTokenByNode(viewToken, ' ');
2290
+ this.updateAfterPreviousTokenByNode(viewToken, ' ');
2291
+ }
2292
+ if (outerToken) {
2293
+ this.updateAfterPreviousTokenByNode(outerToken, ' ');
2294
+ this.updateBeforeNextTokenByNode(outerToken, ' ');
2295
+ }
2296
+ const leftParen = ctx.LEFT_PAREN();
2297
+ const rightParen = ctx.RIGHT_PAREN();
2298
+ if (leftParen && rightParen) {
2299
+ this.updateAfterPreviousTokenByNode(leftParen, '');
2300
+ this.updateBeforeNextTokenByNode(leftParen, '');
2301
+ this.updateAfterPreviousTokenByNode(rightParen, '');
2302
+ const leftParenIndex = leftParen.symbol.tokenIndex;
2303
+ const rightParenIndex = rightParen.symbol.tokenIndex;
2304
+ const commas = ctx.COMMA();
2305
+ for (const comma of commas) {
2306
+ const commaIndex = comma.symbol.tokenIndex;
2307
+ if (commaIndex > leftParenIndex && commaIndex < rightParenIndex) {
2308
+ this.updateAfterPreviousTokenByNode(comma, '');
2309
+ this.updateBeforeNextTokenByNode(comma, ' ');
2310
+ }
2311
+ }
2312
+ }
2313
+ super.visitChildren(ctx);
2314
+ }
2315
+ // ==================== INSERT/UPDATE/DELETE/MERGE ====================
2316
+ visitSingleInsertQuery(ctx) {
2317
+ if (!this.tryFormatWithStrategy(ctx)) {
2318
+ super.visitChildren(ctx);
2319
+ }
2320
+ }
2321
+ visitInsertIntoTable(ctx) {
2322
+ if (!this.tryFormatWithStrategy(ctx)) {
2323
+ super.visitChildren(ctx);
2324
+ }
2325
+ }
2326
+ visitInsertOverwriteTable(ctx) {
2327
+ if (!this.tryFormatWithStrategy(ctx)) {
2328
+ super.visitChildren(ctx);
2329
+ }
2330
+ }
2331
+ visitInsertOverwriteHiveDir(ctx) {
2332
+ if (!this.tryFormatWithStrategy(ctx)) {
2333
+ super.visitChildren(ctx);
2334
+ }
2335
+ }
2336
+ visitInsertOverwriteDir(ctx) {
2337
+ if (!this.tryFormatWithStrategy(ctx)) {
2338
+ super.visitChildren(ctx);
2339
+ }
2340
+ }
2341
+ visitDeleteFromTable(ctx) {
2342
+ if (!this.tryFormatWithStrategy(ctx)) {
2343
+ super.visitChildren(ctx);
2344
+ }
2345
+ }
2346
+ visitUpdateTable(ctx) {
2347
+ if (!this.tryFormatWithStrategy(ctx)) {
2348
+ super.visitChildren(ctx);
2349
+ }
2350
+ }
2351
+ visitSetClause(ctx) {
2352
+ if (!this.tryFormatWithStrategy(ctx)) {
2353
+ super.visitChildren(ctx);
2354
+ }
2355
+ }
2356
+ visitMergeIntoTable(ctx) {
2357
+ if (!this.tryFormatWithStrategy(ctx)) {
2358
+ super.visitChildren(ctx);
2359
+ }
2360
+ }
2361
+ visitMatchedClause(ctx) {
2362
+ if (!this.tryFormatWithStrategy(ctx)) {
2363
+ super.visitChildren(ctx);
2364
+ }
2365
+ }
2366
+ visitNotMatchedClause(ctx) {
2367
+ if (!this.tryFormatWithStrategy(ctx)) {
2368
+ super.visitChildren(ctx);
2369
+ }
2370
+ }
2371
+ visitNotMatchedBySourceClause(ctx) {
2372
+ if (!this.tryFormatWithStrategy(ctx)) {
2373
+ super.visitChildren(ctx);
2374
+ }
2375
+ }
2376
+ // ==================== Utility Statements ====================
2377
+ visitExplain(ctx) {
2378
+ const explainNode = ctx.EXPLAIN();
2379
+ const modeNode = ctx.LOGICAL() || ctx.FORMATTED() || ctx.EXTENDED() || ctx.CODEGEN() || ctx.COST();
2380
+ if (modeNode) {
2381
+ this.updateBeforeNextTokenByNode(explainNode, ' ');
2382
+ this.updateBeforeNextTokenByNode(modeNode, this.newline);
2383
+ }
2384
+ else {
2385
+ this.updateBeforeNextTokenByNode(explainNode, this.newline);
2386
+ }
2387
+ super.visitChildren(ctx);
2388
+ }
2389
+ visitCall(ctx) {
2390
+ const callKeyword = ctx.CALL();
2391
+ this.updateBeforeNextTokenByNode(callKeyword, ' ');
2392
+ const leftParen = ctx.LEFT_PAREN();
2393
+ const rightParen = ctx.RIGHT_PAREN();
2394
+ if (leftParen && rightParen) {
2395
+ this.updateAfterPreviousTokenByNode(leftParen, '');
2396
+ const args = ctx.functionArgument();
2397
+ const argsLength = args.map(a => a.text).join(', ').length;
2398
+ if (argsLength > this.maxParenthesisLength) {
2399
+ this.addIndent();
2400
+ if (args.length > 0) {
2401
+ this.updateAfterPreviousTokenByContext(args[0], this.newlineIndent);
2402
+ }
2403
+ const commas = ctx.COMMA();
2404
+ for (const comma of commas) {
2405
+ this.updateAfterPreviousTokenByNode(comma, '');
2406
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
2407
+ }
2408
+ this.minusIndent();
2409
+ this.updateAfterPreviousTokenByNode(rightParen, this.newline);
2410
+ }
2411
+ else {
2412
+ const commas = ctx.COMMA();
2413
+ for (const comma of commas) {
2414
+ this.updateAfterPreviousTokenByNode(comma, '');
2415
+ this.updateBeforeNextTokenByNode(comma, ' ');
2416
+ }
2417
+ }
2418
+ }
2419
+ super.visitChildren(ctx);
2420
+ }
2421
+ visitExecuteImmediate(ctx) {
2422
+ const executeNode = ctx.EXECUTE();
2423
+ const immediateNode = ctx.IMMEDIATE();
2424
+ this.updateBeforeNextTokenByNode(executeNode, ' ');
2425
+ this.updateBeforeNextTokenByNode(immediateNode, ' ');
2426
+ const intoNode = ctx.INTO();
2427
+ if (intoNode) {
2428
+ this.updateAfterPreviousTokenByNode(intoNode, this.newline);
2429
+ this.updateBeforeNextTokenByNode(intoNode, ' ');
2430
+ }
2431
+ const targetVariable = ctx.multipartIdentifierList();
2432
+ if (targetVariable) {
2433
+ const commas = targetVariable.COMMA();
2434
+ for (const comma of commas) {
2435
+ this.updateAfterPreviousTokenByNode(comma, '');
2436
+ this.updateBeforeNextTokenByNode(comma, ' ');
2437
+ }
2438
+ }
2439
+ const usingClause = ctx.executeImmediateUsing();
2440
+ if (usingClause) {
2441
+ this.visitExecuteImmediateUsing(usingClause);
2442
+ }
2443
+ super.visitChildren(ctx);
2444
+ }
2445
+ visitExecuteImmediateUsing(ctx) {
2446
+ const usingNode = ctx.USING();
2447
+ this.updateAfterPreviousTokenByNode(usingNode, this.newline);
2448
+ const leftParen = ctx.LEFT_PAREN();
2449
+ const rightParen = ctx.RIGHT_PAREN();
2450
+ if (leftParen && rightParen) {
2451
+ const paramsSeq = ctx.namedExpressionSeq();
2452
+ const params = paramsSeq.namedExpression();
2453
+ const paramsLength = params.map(p => p.text).join(', ').length;
2454
+ if (paramsLength > this.maxParenthesisLength) {
2455
+ this.addIndent();
2456
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
2457
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
2458
+ this.minusIndent();
2459
+ }
2460
+ else {
2461
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
2462
+ this.updateBeforeNextTokenByNode(leftParen, '');
2463
+ this.updateAfterPreviousTokenByNode(rightParen, '');
2464
+ }
2465
+ }
2466
+ else {
2467
+ this.updateBeforeNextTokenByNode(usingNode, ' ');
2468
+ }
2469
+ super.visitChildren(ctx);
2470
+ }
2471
+ visitCommentNamespace(ctx) {
2472
+ if (!this.tryFormatWithStrategy(ctx)) {
2473
+ super.visitChildren(ctx);
2474
+ }
2475
+ }
2476
+ visitCommentTable(ctx) {
2477
+ if (!this.tryFormatWithStrategy(ctx)) {
2478
+ super.visitChildren(ctx);
2479
+ }
2480
+ }
2481
+ visitDescribeFunction(ctx) {
2482
+ if (!this.tryFormatWithStrategy(ctx)) {
2483
+ super.visitChildren(ctx);
2484
+ }
2485
+ }
2486
+ visitDescribeProcedure(ctx) {
2487
+ if (!this.tryFormatWithStrategy(ctx)) {
2488
+ super.visitChildren(ctx);
2489
+ }
2490
+ }
2491
+ visitDescribeNamespace(ctx) {
2492
+ if (!this.tryFormatWithStrategy(ctx)) {
2493
+ super.visitChildren(ctx);
2494
+ }
2495
+ }
2496
+ visitDescribeRelation(ctx) {
2497
+ if (!this.tryFormatWithStrategy(ctx)) {
2498
+ super.visitChildren(ctx);
2499
+ }
2500
+ }
2501
+ visitDescribeQuery(ctx) {
2502
+ if (!this.tryFormatWithStrategy(ctx)) {
2503
+ super.visitChildren(ctx);
2504
+ }
2505
+ }
2506
+ visitAnalyze(ctx) {
2507
+ if (!this.tryFormatWithStrategy(ctx)) {
2508
+ super.visitChildren(ctx);
2509
+ }
2510
+ }
2511
+ visitAnalyzeTables(ctx) {
2512
+ if (!this.tryFormatWithStrategy(ctx)) {
2513
+ super.visitChildren(ctx);
2514
+ }
2515
+ }
2516
+ visitRepairTable(ctx) {
2517
+ if (!this.tryFormatWithStrategy(ctx)) {
2518
+ super.visitChildren(ctx);
2519
+ }
2520
+ }
2521
+ visitTruncateTable(ctx) {
2522
+ if (!this.tryFormatWithStrategy(ctx)) {
2523
+ super.visitChildren(ctx);
2524
+ }
2525
+ }
2526
+ visitCacheTable(ctx) {
2527
+ if (!this.tryFormatWithStrategy(ctx)) {
2528
+ super.visitChildren(ctx);
2529
+ }
2530
+ }
2531
+ visitUncacheTable(ctx) {
2532
+ if (!this.tryFormatWithStrategy(ctx)) {
2533
+ super.visitChildren(ctx);
2534
+ }
2535
+ }
2536
+ visitClearCache(ctx) {
2537
+ if (!this.tryFormatWithStrategy(ctx)) {
2538
+ super.visitChildren(ctx);
2539
+ }
2540
+ }
2541
+ visitRefreshTable(ctx) {
2542
+ if (!this.tryFormatWithStrategy(ctx)) {
2543
+ super.visitChildren(ctx);
2544
+ }
2545
+ }
2546
+ visitRefreshFunction(ctx) {
2547
+ if (!this.tryFormatWithStrategy(ctx)) {
2548
+ super.visitChildren(ctx);
2549
+ }
2550
+ }
2551
+ visitLoadData(ctx) {
2552
+ if (!this.tryFormatWithStrategy(ctx)) {
2553
+ super.visitChildren(ctx);
2554
+ }
2555
+ }
2556
+ // ==================== Expression ====================
2557
+ visitFunctionCall(ctx) {
2558
+ if (!this.tryFormatWithStrategy(ctx)) {
2559
+ super.visitChildren(ctx);
2560
+ }
2561
+ }
2562
+ visitCast(ctx) {
2563
+ if (!this.tryFormatWithStrategy(ctx)) {
2564
+ super.visitChildren(ctx);
2565
+ }
2566
+ }
2567
+ visitTrim(ctx) {
2568
+ if (!this.tryFormatWithStrategy(ctx)) {
2569
+ super.visitChildren(ctx);
2570
+ }
2571
+ }
2572
+ visitAny_value(ctx) {
2573
+ if (!this.tryFormatWithStrategy(ctx)) {
2574
+ super.visitChildren(ctx);
2575
+ }
2576
+ }
2577
+ visitFirst(ctx) {
2578
+ if (!this.tryFormatWithStrategy(ctx)) {
2579
+ super.visitChildren(ctx);
2580
+ }
2581
+ }
2582
+ visitLast(ctx) {
2583
+ if (!this.tryFormatWithStrategy(ctx)) {
2584
+ super.visitChildren(ctx);
2585
+ }
2586
+ }
2587
+ visitTimestampadd(ctx) {
2588
+ if (!this.tryFormatWithStrategy(ctx)) {
2589
+ super.visitChildren(ctx);
2590
+ }
2591
+ }
2592
+ visitTimestampdiff(ctx) {
2593
+ if (!this.tryFormatWithStrategy(ctx)) {
2594
+ super.visitChildren(ctx);
2595
+ }
2596
+ }
2597
+ visitPosition(ctx) {
2598
+ if (!this.tryFormatWithStrategy(ctx)) {
2599
+ super.visitChildren(ctx);
2600
+ }
2601
+ }
2602
+ visitStruct(ctx) {
2603
+ if (!this.tryFormatWithStrategy(ctx)) {
2604
+ super.visitChildren(ctx);
2605
+ }
2606
+ }
2607
+ visitLogicalBinary(ctx) {
2608
+ // In pipe context, use pipe-specific indent for AND/OR
2609
+ const indentForAndOr = this.inPipeOperatorRightSide ? this.context.getPipeContentIndent() : this.newlineIndent;
2610
+ // Format AND/OR on new line with indent
2611
+ if (ctx.AND()) {
2612
+ this.updateAfterPreviousTokenByNode(ctx.AND(), indentForAndOr);
2613
+ this.updateBeforeNextTokenByNode(ctx.AND(), ' ');
2614
+ }
2615
+ if (ctx.OR()) {
2616
+ this.updateAfterPreviousTokenByNode(ctx.OR(), indentForAndOr);
2617
+ this.updateBeforeNextTokenByNode(ctx.OR(), ' ');
2618
+ }
2619
+ super.visitChildren(ctx);
2620
+ }
2621
+ visitLogicalNot(ctx) {
2622
+ // Space after NOT (but NOT before - that's handled by parent context like WHERE)
2623
+ if (ctx.NOT()) {
2624
+ this.updateBeforeNextTokenByNode(ctx.NOT(), ' ');
2625
+ }
2626
+ if (ctx.BANG()) {
2627
+ this.updateBeforeNextTokenByNode(ctx.BANG(), ' ');
2628
+ }
2629
+ super.visitChildren(ctx);
2630
+ }
2631
+ visitComparison(ctx) {
2632
+ if (!this.tryFormatWithStrategy(ctx)) {
2633
+ super.visitChildren(ctx);
2634
+ }
2635
+ }
2636
+ visitPredicate(ctx) {
2637
+ if (!this.tryFormatWithStrategy(ctx)) {
2638
+ super.visitChildren(ctx);
2639
+ }
2640
+ }
2641
+ visitCollateClause(ctx) {
2642
+ if (!this.tryFormatWithStrategy(ctx)) {
2643
+ super.visitChildren(ctx);
2644
+ }
2645
+ }
2646
+ visitCollate(ctx) {
2647
+ if (!this.tryFormatWithStrategy(ctx)) {
2648
+ super.visitChildren(ctx);
2649
+ }
2650
+ }
2651
+ visitArithmeticBinary(ctx) {
2652
+ if (!this.tryFormatWithStrategy(ctx)) {
2653
+ super.visitChildren(ctx);
2654
+ }
2655
+ }
2656
+ visitIntervalValue(ctx) {
2657
+ // Add space before interval value if preceded by INTERVAL keyword
2658
+ const prevToken = this.getPreviousNonHiddenToken(ctx.start.tokenIndex);
2659
+ if (prevToken?.type === SparkSQLLexer_1.SparkSQLLexer.INTERVAL) {
2660
+ this.updateAfterPreviousTokenByContext(ctx, ' ');
2661
+ }
2662
+ // Handle MINUS sign with spaces
2663
+ const minus = ctx.MINUS();
2664
+ if (minus) {
2665
+ this.updateAfterPreviousTokenByNode(minus, ' ');
2666
+ this.updateBeforeNextTokenByNode(minus, ' ');
2667
+ }
2668
+ // Add space after the value before the unit
2669
+ const integerValue = ctx.INTEGER_VALUE();
2670
+ const decimalValue = ctx.DECIMAL_VALUE();
2671
+ const stringLit = ctx.stringLit();
2672
+ if (integerValue) {
2673
+ this.updateBeforeNextTokenByNode(integerValue, ' ');
2674
+ }
2675
+ else if (decimalValue) {
2676
+ this.updateBeforeNextTokenByNode(decimalValue, ' ');
2677
+ }
2678
+ else if (stringLit && !minus) {
2679
+ this.updateBeforeNextTokenByContext(stringLit, ' ');
2680
+ }
2681
+ super.visitChildren(ctx);
2682
+ }
2683
+ visitSubqueryExpression(ctx) {
2684
+ if (!this.tryFormatWithStrategy(ctx)) {
2685
+ super.visitChildren(ctx);
2686
+ }
2687
+ }
2688
+ visitSubquery(ctx) {
2689
+ if (!this.tryFormatWithStrategy(ctx)) {
2690
+ super.visitChildren(ctx);
2691
+ }
2692
+ }
2693
+ visitParenthesizedExpression(ctx) {
2694
+ // Check if this parenthesized expression is inside an InlineTable (VALUES clause)
2695
+ // For InlineTable, preserve space between VALUES keyword and left paren
2696
+ // The space was already added by visitInlineTable, so skip strategy formatting
2697
+ let isInInlineTable = false;
2698
+ let parent = ctx.parent;
2699
+ while (parent) {
2700
+ if (parent.constructor.name === 'InlineTableContext') {
2701
+ isInInlineTable = true;
2702
+ break;
2703
+ }
2704
+ parent = parent.parent;
2705
+ }
2706
+ if (isInInlineTable) {
2707
+ // Don't use strategy - it would override the space after VALUES
2708
+ // Just format the right paren, but NOT the left paren
2709
+ const rightParen = ctx.RIGHT_PAREN();
2710
+ if (rightParen) {
2711
+ this.updateAfterPreviousTokenByNode(rightParen, '');
2712
+ }
2713
+ super.visitChildren(ctx);
2714
+ }
2715
+ else if (!this.tryFormatWithStrategy(ctx)) {
2716
+ super.visitChildren(ctx);
2717
+ }
2718
+ }
2719
+ visitExists(ctx) {
2720
+ if (!this.tryFormatWithStrategy(ctx)) {
2721
+ super.visitChildren(ctx);
2722
+ }
2723
+ }
2724
+ // ==================== Inline Table ====================
2725
+ visitInlineTableDefault2(ctx) {
2726
+ // InlineTable in FROM clause - visit inlineTable child directly
2727
+ // This ensures InlineTable sees InlineTableDefault2Context as its parent
2728
+ const inlineTable = ctx.inlineTable();
2729
+ if (inlineTable) {
2730
+ // Mark that this is FROM VALUES context
2731
+ inlineTable.__isFromValues = true;
2732
+ }
2733
+ super.visitChildren(ctx);
2734
+ }
2735
+ visitInlineTable(ctx) {
2736
+ // VALUES clause formatting
2737
+ const valuesToken = ctx.VALUES();
2738
+ const _expressions = ctx.expression();
2739
+ const tableAlias = ctx.tableAlias();
2740
+ if (!valuesToken) {
2741
+ super.visitChildren(ctx);
2742
+ return;
2743
+ }
2744
+ // Check if this is inside an INSERT statement or CREATE VIEW AS VALUES
2745
+ let parent = ctx.parent;
2746
+ let isInsideInsert = false;
2747
+ let isAfterCreateViewAs = false;
2748
+ let isInsideFromClause = false;
2749
+ // First check for FROM clause context
2750
+ let p = ctx.parent;
2751
+ while (p) {
2752
+ if (p.constructor.name === 'FromClauseContext') {
2753
+ isInsideFromClause = true;
2754
+ break;
2755
+ }
2756
+ if (p.constructor.name === 'InlineTableDefault2Context') {
2757
+ isInsideFromClause = true;
2758
+ break;
2759
+ }
2760
+ p = p.parent;
2761
+ }
2762
+ // Then check for INSERT or CREATE VIEW AS VALUES
2763
+ parent = ctx.parent;
2764
+ while (parent) {
2765
+ if (parent.constructor.name === 'SingleInsertQueryContext') {
2766
+ isInsideInsert = true;
2767
+ break;
2768
+ }
2769
+ // Only set isAfterCreateViewAs if VALUES is directly after AS (not in FROM clause)
2770
+ if (parent.constructor.name === 'CreateViewContext' && !isInsideFromClause) {
2771
+ isAfterCreateViewAs = true;
2772
+ break;
2773
+ }
2774
+ parent = parent.parent;
2775
+ }
2776
+ if (isInsideInsert) {
2777
+ // Inside INSERT - VALUES on new line with 2-space indent
2778
+ this.updateAfterPreviousTokenByNode(valuesToken, '\n ');
2779
+ const expressions = ctx.expression();
2780
+ const _commas = ctx.COMMA();
2781
+ if (expressions.length > 1) {
2782
+ // Multiple tuples - each on separate line with additional indent
2783
+ this.addIndent();
2784
+ // Mark inlineTable as long content for visitRowConstructor
2785
+ ctx.__isLongContent = true;
2786
+ // VALUES 后换行,所有元组在独立行
2787
+ this.updateBeforeNextTokenByNode(valuesToken, this.newlineIndent);
2788
+ // 在每个后续元组前添加换行+缩进
2789
+ for (let i = 1; i < expressions.length; i++) {
2790
+ const expr = expressions[i];
2791
+ // 使用 updateAfterPreviousTokenByContext 在元组前设置换行
2792
+ this.updateAfterPreviousTokenByContext(expr, this.newlineIndent);
2793
+ }
2794
+ super.visitChildren(ctx);
2795
+ this.minusIndent();
2796
+ }
2797
+ else {
2798
+ // Single tuple - on same line as VALUES
2799
+ this.updateBeforeNextTokenByNode(valuesToken, ' ');
2800
+ super.visitChildren(ctx);
2801
+ }
2802
+ }
2803
+ else if (isAfterCreateViewAs) {
2804
+ // Inside CREATE VIEW AS VALUES - VALUES on new line
2805
+ // The newline after AS is already handled by CreateViewStrategy
2806
+ // Only need to add space after VALUES keyword
2807
+ this.updateBeforeNextTokenByNode(valuesToken, ' ');
2808
+ const commas = ctx.COMMA();
2809
+ for (const comma of commas) {
2810
+ this.updateAfterPreviousTokenByNode(comma, '');
2811
+ this.updateBeforeNextTokenByNode(comma, ' ');
2812
+ }
2813
+ super.visitChildren(ctx);
2814
+ }
2815
+ else {
2816
+ // Not inside INSERT or CREATE VIEW AS VALUES
2817
+ // Check if this is a VALUES statement as pipe start (TABLE statement)
2818
+ // This is the case when VALUES appears at the start of a pipe expression
2819
+ let isPipeStart = false;
2820
+ let p = ctx.parent;
2821
+ while (p) {
2822
+ if (p.constructor.name === 'TableStatementContext' || p.constructor.name === 'OperatorPipeStatementContext') {
2823
+ isPipeStart = true;
2824
+ break;
2825
+ }
2826
+ // VALUES in InlineTableDefault1Context can be pipe start
2827
+ if (p.constructor.name === 'InlineTableDefault1Context') {
2828
+ isPipeStart = true;
2829
+ break;
2830
+ }
2831
+ p = p.parent;
2832
+ }
2833
+ // Check if content is long enough to require multiline formatting
2834
+ // For InlineTable, use ctx.text.length to match Legacy behavior (compressed text length)
2835
+ const contentLength = ctx.text.length;
2836
+ const isLongContent = contentLength > this.maxParenthesisLength || isPipeStart;
2837
+ const expressions = ctx.expression();
2838
+ if (isLongContent) {
2839
+ // Long content - use multiline format with each tuple on separate line
2840
+ // Add indent first so newlineIndent has proper indent for VALUES
2841
+ this.addIndent();
2842
+ // For pipe start, VALUES is the first token, set newline after it
2843
+ // For FROM VALUES, set newline before VALUES
2844
+ if (isPipeStart) {
2845
+ // VALUES is first token - set newline after VALUES
2846
+ this.updateBeforeNextTokenByNode(valuesToken, this.newlineIndent);
2847
+ }
2848
+ else {
2849
+ // VALUES is after FROM - set newline before VALUES
2850
+ this.updateAfterPreviousTokenByNode(valuesToken, this.newlineIndent);
2851
+ }
2852
+ // First tuple on new line after VALUES (same indent as VALUES content)
2853
+ // Format tuple-level commas: comma stays at end of line, next tuple on new line
2854
+ const commas = ctx.COMMA();
2855
+ for (let i = 0; i < commas.length; i++) {
2856
+ const comma = commas[i];
2857
+ this.updateAfterPreviousTokenByNode(comma, '');
2858
+ // Next tuple on new line
2859
+ if (expressions.length > i + 1) {
2860
+ this.updateAfterPreviousTokenByContext(expressions[i + 1], this.newlineIndent);
2861
+ }
2862
+ }
2863
+ // Mark inlineTable as long content for visitRowConstructor
2864
+ ctx.__isLongContent = true;
2865
+ super.visitChildren(ctx);
2866
+ this.minusIndent(); // Remove VALUES indent
2867
+ }
2868
+ else {
2869
+ // Short content - compact format
2870
+ // VALUES on new line with indent after FROM
2871
+ this.addIndent();
2872
+ this.updateAfterPreviousTokenByNode(valuesToken, this.newlineIndent);
2873
+ this.updateBeforeNextTokenByNode(valuesToken, ' ');
2874
+ // Legacy uses formatInlineCommaNodes for tuple-level commas
2875
+ const commas = ctx.COMMA();
2876
+ for (const comma of commas) {
2877
+ this.updateAfterPreviousTokenByNode(comma, '');
2878
+ this.updateBeforeNextTokenByNode(comma, ' ');
2879
+ }
2880
+ super.visitChildren(ctx);
2881
+ this.minusIndent();
2882
+ }
2883
+ }
2884
+ // Handle table alias with AS keyword - AS should never have newline before it
2885
+ if (tableAlias) {
2886
+ this.normalizeKeywordSpacing(tableAlias.AS());
2887
+ }
2888
+ }
2889
+ visitRowConstructor(ctx) {
2890
+ const leftParen = ctx.LEFT_PAREN();
2891
+ const rightParen = ctx.RIGHT_PAREN();
2892
+ if (leftParen && rightParen) {
2893
+ // Check if this row constructor is inside an inlineTable (VALUES clause)
2894
+ let inlineTableCtx = null;
2895
+ let p = ctx.parent;
2896
+ while (p) {
2897
+ if (p.constructor.name === 'InlineTableContext') {
2898
+ inlineTableCtx = p;
2899
+ break;
2900
+ }
2901
+ p = p.parent;
2902
+ }
2903
+ const isInInlineTable = inlineTableCtx !== null;
2904
+ const isLongContent = inlineTableCtx?.__isLongContent;
2905
+ const contentLength = ctx.text.length;
2906
+ const commas = ctx.COMMA();
2907
+ // For RowConstructor inside InlineTable with long content:
2908
+ // Keep tuple compact, don't modify space before left paren
2909
+ // (space/newline was already set by visitInlineTable)
2910
+ if (isInInlineTable && isLongContent) {
2911
+ // Compact format: only handle inside parens
2912
+ this.updateAfterPreviousTokenByNode(rightParen, '');
2913
+ // Internal commas: compact
2914
+ for (const comma of commas) {
2915
+ this.updateAfterPreviousTokenByNode(comma, '');
2916
+ this.updateBeforeNextTokenByNode(comma, ' ');
2917
+ }
2918
+ super.visitChildren(ctx);
2919
+ }
2920
+ else {
2921
+ this.formatParenthesizedContent(leftParen, rightParen, commas, contentLength, {
2922
+ forceCompact: true,
2923
+ spaceBeforeLeftParen: isInInlineTable,
2924
+ visitChildren: () => super.visitChildren(ctx)
2925
+ });
2926
+ }
2927
+ }
2928
+ else {
2929
+ super.visitChildren(ctx);
2930
+ }
2931
+ }
2932
+ // ==================== Aliased Query/Relation (FROM 后子查询) ====================
2933
+ /**
2934
+ * Format aliased query (FROM 后的括号子查询)
2935
+ * 规则:左括号换行,内容缩进 2 空格,右括号与 FROM 对齐
2936
+ *
2937
+ * 例如:
2938
+ * FROM
2939
+ * (
2940
+ * SELECT ...
2941
+ * ) AS alias
2942
+ */
2943
+ visitAliasedQuery(ctx) {
2944
+ const leftParen = ctx.LEFT_PAREN();
2945
+ const rightParen = ctx.RIGHT_PAREN();
2946
+ const query = ctx.query();
2947
+ const tableAlias = ctx.tableAlias();
2948
+ if (!leftParen || !rightParen) {
2949
+ super.visitChildren(ctx);
2950
+ return;
2951
+ }
2952
+ // 左括号换行
2953
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
2954
+ // 增加缩进(子查询内容缩进 2 空格)
2955
+ this.addIndent();
2956
+ // 子查询内容换行
2957
+ if (query) {
2958
+ this.updateAfterPreviousTokenByContext(query, this.newlineIndent);
2959
+ }
2960
+ // 访问子查询
2961
+ if (query) {
2962
+ this.visit(query);
2963
+ }
2964
+ // 减少缩进
2965
+ this.minusIndent();
2966
+ // 右括号换行(与 FROM 对齐)
2967
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
2968
+ // 处理别名 - 与右括号同行
2969
+ if (tableAlias) {
2970
+ const asNode = tableAlias.AS();
2971
+ if (asNode) {
2972
+ this.updateAfterPreviousTokenByNode(asNode, ' ');
2973
+ this.updateBeforeNextTokenByNode(asNode, ' ');
2974
+ }
2975
+ this.visit(tableAlias);
2976
+ }
2977
+ // 处理 sample 和 watermarkClause
2978
+ const sample = ctx.sample();
2979
+ if (sample) {
2980
+ this.visit(sample);
2981
+ }
2982
+ const watermarkClause = ctx.watermarkClause();
2983
+ if (watermarkClause) {
2984
+ this.visit(watermarkClause);
2985
+ }
2986
+ }
2987
+ /**
2988
+ * Format aliased relation (FROM 后的括号关系)
2989
+ * 规则:左括号换行,内容缩进 2 空格,右括号与 FROM 对齐
2990
+ */
2991
+ visitAliasedRelation(ctx) {
2992
+ const leftParen = ctx.LEFT_PAREN();
2993
+ const rightParen = ctx.RIGHT_PAREN();
2994
+ const relation = ctx.relation();
2995
+ const tableAlias = ctx.tableAlias();
2996
+ if (!leftParen || !rightParen) {
2997
+ super.visitChildren(ctx);
2998
+ return;
2999
+ }
3000
+ // 左括号换行
3001
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
3002
+ // 增加缩进(括号内容缩进 2 空格)
3003
+ this.addIndent();
3004
+ // 关系内容换行
3005
+ if (relation) {
3006
+ this.updateAfterPreviousTokenByContext(relation, this.newlineIndent);
3007
+ }
3008
+ // 访问关系
3009
+ if (relation) {
3010
+ this.visit(relation);
3011
+ }
3012
+ // 减少缩进
3013
+ this.minusIndent();
3014
+ // 右括号换行(与 FROM 对齐)
3015
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
3016
+ // 处理别名 - 与右括号同行
3017
+ if (tableAlias) {
3018
+ const asNode = tableAlias.AS();
3019
+ if (asNode) {
3020
+ this.updateAfterPreviousTokenByNode(asNode, ' ');
3021
+ this.updateBeforeNextTokenByNode(asNode, ' ');
3022
+ }
3023
+ this.visit(tableAlias);
3024
+ }
3025
+ // 处理 sample 和 watermarkClause
3026
+ const sample = ctx.sample();
3027
+ if (sample) {
3028
+ this.visit(sample);
3029
+ }
3030
+ const watermarkClause = ctx.watermarkClause();
3031
+ if (watermarkClause) {
3032
+ this.visit(watermarkClause);
3033
+ }
3034
+ }
3035
+ visitTableAlias(ctx) {
3036
+ const strictIdentifier = ctx.strictIdentifier();
3037
+ if (strictIdentifier) {
3038
+ this.updateAfterPreviousTokenByContext(strictIdentifier, ' ');
3039
+ }
3040
+ const identifierList = ctx.identifierList();
3041
+ if (identifierList) {
3042
+ const leftParen = identifierList.LEFT_PAREN();
3043
+ if (leftParen) {
3044
+ this.updateAfterPreviousTokenByNode(leftParen, '');
3045
+ }
3046
+ }
3047
+ super.visitChildren(ctx);
3048
+ }
3049
+ visitIdentifierList(ctx) {
3050
+ const leftParen = ctx.LEFT_PAREN();
3051
+ const rightParen = ctx.RIGHT_PAREN();
3052
+ if (leftParen && rightParen) {
3053
+ const isInsideTableAlias = ctx.parent?.constructor?.name === 'TableAliasContext';
3054
+ const identifierSeq = ctx.identifierSeq();
3055
+ const commas = identifierSeq?.COMMA() || [];
3056
+ const contentLength = ctx.stop.stopIndex - ctx.start.startIndex;
3057
+ if (contentLength > this.maxParenthesisLength) {
3058
+ this.addIndent();
3059
+ this.updateBeforeNextTokenByNode(leftParen, this.newlineIndent);
3060
+ this.updateAfterPreviousTokenByNode(rightParen, this.newlineIndent);
3061
+ this.minusIndent();
3062
+ for (const comma of commas) {
3063
+ this.updateAfterPreviousTokenByNode(comma, '');
3064
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
3065
+ }
3066
+ }
3067
+ else {
3068
+ if (!isInsideTableAlias) {
3069
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
3070
+ }
3071
+ this.updateBeforeNextTokenByNode(leftParen, '');
3072
+ this.updateAfterPreviousTokenByNode(rightParen, '');
3073
+ for (const comma of commas) {
3074
+ this.updateAfterPreviousTokenByNode(comma, '');
3075
+ this.updateBeforeNextTokenByNode(comma, ' ');
3076
+ }
3077
+ }
3078
+ }
3079
+ super.visitChildren(ctx);
3080
+ }
3081
+ visitIdentifierSeq(ctx) {
3082
+ if (ctx.parent?.constructor?.name === 'IdentifierListContext') {
3083
+ super.visitChildren(ctx);
3084
+ return;
3085
+ }
3086
+ const commas = ctx.COMMA();
3087
+ for (const comma of commas) {
3088
+ this.updateAfterPreviousTokenByNode(comma, '');
3089
+ this.updateBeforeNextTokenByNode(comma, ' ');
3090
+ }
3091
+ super.visitChildren(ctx);
3092
+ }
3093
+ // ==================== Partition ====================
3094
+ visitPartitionSpec(ctx) {
3095
+ const partitionNode = ctx.PARTITION();
3096
+ const leftParen = ctx.LEFT_PAREN();
3097
+ const rightParen = ctx.RIGHT_PAREN();
3098
+ if (partitionNode && leftParen && rightParen) {
3099
+ this.updateBeforeNextTokenByNode(partitionNode, ' ');
3100
+ this.updateBeforeNextTokenByNode(leftParen, '');
3101
+ this.updateAfterPreviousTokenByNode(rightParen, '');
3102
+ const commas = ctx.COMMA();
3103
+ for (const comma of commas) {
3104
+ this.updateAfterPreviousTokenByNode(comma, '');
3105
+ this.updateBeforeNextTokenByNode(comma, ' ');
3106
+ }
3107
+ }
3108
+ super.visitChildren(ctx);
3109
+ }
3110
+ visitPartitionVal(ctx) {
3111
+ const eqNode = ctx.EQ();
3112
+ if (eqNode) {
3113
+ this.updateAfterPreviousTokenByNode(eqNode, ' ');
3114
+ this.updateBeforeNextTokenByNode(eqNode, ' ');
3115
+ }
3116
+ super.visitChildren(ctx);
3117
+ }
3118
+ // ==================== Table ====================
3119
+ visitTable(ctx) {
3120
+ const tableToken = ctx.TABLE();
3121
+ if (tableToken) {
3122
+ this.updateBeforeNextTokenByNode(tableToken, ' ');
3123
+ }
3124
+ super.visitChildren(ctx);
3125
+ }
3126
+ visitTableName(ctx) {
3127
+ const tableAlias = ctx.tableAlias();
3128
+ if (tableAlias) {
3129
+ this.normalizeKeywordSpacing(tableAlias.AS());
3130
+ }
3131
+ super.visitChildren(ctx);
3132
+ }
3133
+ // ==================== Pipe Operator ====================
3134
+ visitOperatorPipeStatement(ctx) {
3135
+ const operatorPipeNode = ctx.OPERATOR_PIPE();
3136
+ const pipeNode = ctx.PIPE();
3137
+ const operatorNode = operatorPipeNode || pipeNode;
3138
+ if (operatorNode) {
3139
+ // `|> KEYWORD` should be on the same line (no newline before KEYWORD)
3140
+ // Just ensure space before and after `|>`
3141
+ this.updateAfterPreviousTokenByNode(operatorNode, '\n');
3142
+ this.updateBeforeNextTokenByNode(operatorNode, ' ');
3143
+ }
3144
+ super.visitChildren(ctx);
3145
+ }
3146
+ visitOperatorPipeRightSide(ctx) {
3147
+ // Save state
3148
+ const savedInPipeOperatorRightSide = this.inPipeOperatorRightSide;
3149
+ this.inPipeOperatorRightSide = true;
3150
+ // Sync state to FormattingContext so strategies can check via bridge.context.inPipeOperatorRightSide
3151
+ this.context.enterPipeContext();
3152
+ // Get pipe step kind and apply appropriate strategy
3153
+ const stepKind = this.getPipeStepKind(ctx);
3154
+ const formatting = {
3155
+ savedIndentNumber: this.context.currentIndentLevel,
3156
+ savedIndentString: ' ',
3157
+ previousInPipeOperatorRightSide: savedInPipeOperatorRightSide,
3158
+ newline: this.newline,
3159
+ newlineIndent: this.newlineIndent
3160
+ };
3161
+ switch (stepKind) {
3162
+ case 'pipe.select':
3163
+ strategies_1.coreStrategies.pipeSelect.apply(ctx, this.getPipeStepBridge(), formatting);
3164
+ break;
3165
+ case 'pipe.where':
3166
+ strategies_1.coreStrategies.pipeWhere.apply(ctx, this.getPipeStepBridge(), formatting);
3167
+ break;
3168
+ case 'pipe.set':
3169
+ strategies_1.coreStrategies.pipeSet.apply(ctx, this.getPipeStepBridge(), formatting);
3170
+ break;
3171
+ case 'pipe.drop':
3172
+ strategies_1.coreStrategies.pipeDrop.apply(ctx, this.getPipeStepBridge(), formatting);
3173
+ break;
3174
+ case 'pipe.extend':
3175
+ strategies_1.coreStrategies.pipeExtend.apply(ctx, this.getPipeStepBridge(), formatting);
3176
+ break;
3177
+ case 'pipe.join':
3178
+ strategies_1.coreStrategies.pipeJoin.apply(ctx, this.getPipeStepBridge(), formatting);
3179
+ break;
3180
+ case 'pipe.aggregate':
3181
+ strategies_1.coreStrategies.pipeAggregate.apply(ctx, this.getPipeStepBridge(), formatting);
3182
+ break;
3183
+ case 'pipe.setOperation':
3184
+ strategies_1.coreStrategies.pipeSetOperation.apply(ctx, this.getPipeStepBridge(), formatting);
3185
+ break;
3186
+ case 'pipe.queryOrganization':
3187
+ strategies_1.coreStrategies.pipeQueryOrganization.apply(ctx, this.getPipeStepBridge(), formatting);
3188
+ break;
3189
+ case 'pipe.sample':
3190
+ strategies_1.coreStrategies.pipeSample.apply(ctx, this.getPipeStepBridge(), formatting);
3191
+ break;
3192
+ case 'pipe.pivot':
3193
+ strategies_1.coreStrategies.pipePivot.apply(ctx, this.getPipeStepBridge(), formatting);
3194
+ break;
3195
+ case 'pipe.unpivot':
3196
+ strategies_1.coreStrategies.pipeUnpivot.apply(ctx, this.getPipeStepBridge(), formatting);
3197
+ break;
3198
+ default:
3199
+ super.visitChildren(ctx);
3200
+ }
3201
+ // Restore state
3202
+ this.inPipeOperatorRightSide = savedInPipeOperatorRightSide;
3203
+ this.context.exitPipeContext();
3204
+ }
3205
+ // ==================== Helper Methods ====================
3206
+ get indent() {
3207
+ return this.context.indent;
3208
+ }
3209
+ get newlineIndent() {
3210
+ return this.context.newlineIndent;
3211
+ }
3212
+ addIndent() {
3213
+ this.context.addIndent();
3214
+ }
3215
+ minusIndent() {
3216
+ this.context.minusIndent();
3217
+ }
3218
+ addTextEdit(edit) {
3219
+ this.editCollector.addEdit(edit);
3220
+ }
3221
+ updateAfterPreviousTokenByContext(ctx, newText) {
3222
+ this.bridge.updateAfterPreviousTokenByContext(ctx, newText);
3223
+ }
3224
+ updateAfterPreviousTokenByNode(node, newText) {
3225
+ this.bridge.updateAfterPreviousTokenByNode(node, newText);
3226
+ }
3227
+ updateBeforeNextTokenByNode(node, newText) {
3228
+ this.bridge.updateBeforeNextTokenByNode(node, newText);
3229
+ }
3230
+ updateBeforeNextTokenByContext(ctx, newText) {
3231
+ this.bridge.updateBeforeNextTokenByContext(ctx, newText);
3232
+ }
3233
+ getPreviousNonHiddenToken(tokenIndex) {
3234
+ return this.bridge.getPreviousNonHiddenToken(tokenIndex);
3235
+ }
3236
+ getPreviousNonHiddenTokenByStartIndex(startIndex) {
3237
+ return this.bridge.getPreviousNonHiddenTokenByStartIndex(startIndex);
3238
+ }
3239
+ getNextNonHiddenToken(tokenIndex) {
3240
+ return this.bridge.getNextNonHiddenToken(tokenIndex);
3241
+ }
3242
+ getTokenEndPosition(token) {
3243
+ return this.bridge.getTokenEndPosition(token);
3244
+ }
3245
+ findCommentTokensBetween(startIndex, endIndex) {
3246
+ return this.bridge.findCommentTokensBetween(startIndex, endIndex);
3247
+ }
3248
+ /**
3249
+ * Normalize keyword spacing - ensure single space before and after
3250
+ * Used for keywords like AS, VALUES, TABLE, etc.
3251
+ */
3252
+ normalizeKeywordSpacing(node) {
3253
+ if (!node) {
3254
+ return;
3255
+ }
3256
+ this.updateAfterPreviousTokenByNode(node, ' ');
3257
+ this.updateBeforeNextTokenByNode(node, ' ');
3258
+ }
3259
+ /**
3260
+ * Normalize multiple keywords at once
3261
+ */
3262
+ normalizeKeywordsSpacing(...nodes) {
3263
+ for (const node of nodes) {
3264
+ this.normalizeKeywordSpacing(node);
3265
+ }
3266
+ }
3267
+ // ==================== Legacy Helper Methods Migration ====================
3268
+ /**
3269
+ * Add space after a node (shorthand for common pattern)
3270
+ */
3271
+ addSpaceAfterNode(node) {
3272
+ if (node) {
3273
+ this.updateBeforeNextTokenByNode(node, ' ');
3274
+ }
3275
+ }
3276
+ /**
3277
+ * Add space after a context (shorthand for common pattern)
3278
+ */
3279
+ addSpaceAfterContext(ctx) {
3280
+ if (ctx) {
3281
+ this.updateBeforeNextTokenByContext(ctx, ' ');
3282
+ }
3283
+ }
3284
+ /**
3285
+ * Add space after multiple nodes (batch operation)
3286
+ */
3287
+ addSpaceAfterNodes(...nodes) {
3288
+ for (const node of nodes) {
3289
+ if (node) {
3290
+ this.updateBeforeNextTokenByNode(node, ' ');
3291
+ }
3292
+ }
3293
+ }
3294
+ /**
3295
+ * Add newline before a node
3296
+ */
3297
+ addNewlineBeforeNode(node) {
3298
+ if (node) {
3299
+ this.updateAfterPreviousTokenByNode(node, this.newline);
3300
+ }
3301
+ }
3302
+ /**
3303
+ * Add newline after a node
3304
+ */
3305
+ addNewlineAfterNode(node) {
3306
+ if (node) {
3307
+ this.updateBeforeNextTokenByNode(node, this.newline);
3308
+ }
3309
+ }
3310
+ /**
3311
+ * Add newline with indent before a node
3312
+ */
3313
+ addNewlineIndentBeforeNode(node) {
3314
+ if (node) {
3315
+ this.updateAfterPreviousTokenByNode(node, this.newlineIndent);
3316
+ }
3317
+ }
3318
+ /**
3319
+ * Add newline before a context
3320
+ */
3321
+ addNewlineBeforeContext(ctx) {
3322
+ if (ctx) {
3323
+ this.updateAfterPreviousTokenByContext(ctx, this.newline);
3324
+ }
3325
+ }
3326
+ /**
3327
+ * Add newline with indent before a context
3328
+ */
3329
+ addNewlineIndentBeforeContext(ctx) {
3330
+ if (ctx) {
3331
+ this.updateAfterPreviousTokenByContext(ctx, this.newlineIndent);
3332
+ }
3333
+ }
3334
+ /**
3335
+ * Add indent and put node on new line with indent
3336
+ */
3337
+ indentAfterNode(node) {
3338
+ if (!node) {
3339
+ return;
3340
+ }
3341
+ this.addIndent();
3342
+ this.updateBeforeNextTokenByNode(node, this.newlineIndent);
3343
+ this.minusIndent();
3344
+ }
3345
+ /**
3346
+ * Format compact parentheses (no newlines inside)
3347
+ */
3348
+ formatCompactParentheses(leftParen, rightParen, options) {
3349
+ if (!leftParen || !rightParen) {
3350
+ return;
3351
+ }
3352
+ const spaceBeforeLeftParen = options?.spaceBeforeLeftParen ?? false;
3353
+ if (spaceBeforeLeftParen) {
3354
+ this.updateAfterPreviousTokenByNode(leftParen, ' ');
3355
+ }
3356
+ this.updateBeforeNextTokenByNode(leftParen, '');
3357
+ this.updateAfterPreviousTokenByNode(rightParen, '');
3358
+ if (options?.commas) {
3359
+ this.formatInlineCommaNodes(options.commas);
3360
+ }
3361
+ }
3362
+ /**
3363
+ * Format inline comma nodes - comma stays at end with space after
3364
+ */
3365
+ formatInlineCommaNodes(commas) {
3366
+ for (const comma of commas) {
3367
+ this.updateAfterPreviousTokenByNode(comma, '');
3368
+ this.updateBeforeNextTokenByNode(comma, ' ');
3369
+ }
3370
+ }
3371
+ /**
3372
+ * Get bridge for BlockStrategy formatting
3373
+ */
3374
+ getBlockFormattingBridge() {
3375
+ return {
3376
+ updateAfterPreviousTokenByNode: (node, newText) => this.updateAfterPreviousTokenByNode(node, newText),
3377
+ updateBeforeNextTokenByNode: (node, newText) => this.updateBeforeNextTokenByNode(node, newText),
3378
+ updateAfterPreviousTokenByContext: (ctx, newText) => this.updateAfterPreviousTokenByContext(ctx, newText)
3379
+ };
3380
+ }
3381
+ /**
3382
+ * Format parenthesized content with automatic line length detection
3383
+ */
3384
+ formatParenthesizedContent(leftParen, rightParen, commas, contentLength, options) {
3385
+ if (!leftParen || !rightParen) {
3386
+ options?.visitChildren?.();
3387
+ return;
3388
+ }
3389
+ const opts = options || {};
3390
+ const useMultiline = opts.forceMultiline || (!opts.forceCompact && contentLength > this.maxParenthesisLength);
3391
+ const bridge = this.getBlockFormattingBridge();
3392
+ if (useMultiline) {
3393
+ if (opts.addIndentBeforeFormat) {
3394
+ this.addIndent();
3395
+ }
3396
+ this.addIndent();
3397
+ this.blockStrategy.formatMultilineBlock({ leftParen, rightParen }, bridge, {
3398
+ spaceBeforeLeftParen: opts.spaceBeforeLeftParen,
3399
+ separatorAfterLeftParen: this.newlineIndent,
3400
+ separatorBeforeRightParen: this.newlineIndent
3401
+ });
3402
+ for (const comma of commas) {
3403
+ this.updateAfterPreviousTokenByNode(comma, '');
3404
+ this.updateBeforeNextTokenByNode(comma, this.newlineIndent);
3405
+ }
3406
+ opts.visitChildren?.();
3407
+ this.minusIndent();
3408
+ this.addNewlineIndentBeforeNode(rightParen);
3409
+ if (opts.addIndentBeforeFormat) {
3410
+ this.minusIndent();
3411
+ }
3412
+ }
3413
+ else {
3414
+ this.blockStrategy.formatCompactBlock({ leftParen, rightParen }, bridge, {
3415
+ spaceBeforeLeftParen: opts.spaceBeforeLeftParen,
3416
+ separatorAfterLeftParen: '',
3417
+ separatorBeforeRightParen: ''
3418
+ });
3419
+ this.formatInlineCommaNodes(commas);
3420
+ opts.visitChildren?.();
3421
+ }
3422
+ }
3423
+ /**
3424
+ * Post-process: normalize keyword spacing in final output
3425
+ * This catches any keywords that weren't handled by visitor methods
3426
+ */
3427
+ normalizeAllKeywordSpacing() {
3428
+ // Keywords that need space before and after (when not at line start)
3429
+ const keywordsNeedingSpace = [
3430
+ 'AS',
3431
+ 'VALUES',
3432
+ 'TABLE',
3433
+ 'VIEW',
3434
+ 'INDEX',
3435
+ 'FUNCTION',
3436
+ 'INNER',
3437
+ 'LEFT',
3438
+ 'RIGHT',
3439
+ 'FULL',
3440
+ 'OUTER',
3441
+ 'CROSS',
3442
+ 'NATURAL',
3443
+ 'UNION',
3444
+ 'INTERSECT',
3445
+ 'EXCEPT',
3446
+ 'JOIN',
3447
+ 'ON',
3448
+ 'AND',
3449
+ 'OR',
3450
+ 'NOT',
3451
+ 'ORDER',
3452
+ 'GROUP',
3453
+ 'BY',
3454
+ 'HAVING',
3455
+ 'LIMIT',
3456
+ 'OFFSET',
3457
+ 'WHERE',
3458
+ 'FROM',
3459
+ 'SELECT',
3460
+ 'INSERT',
3461
+ 'UPDATE',
3462
+ 'DELETE',
3463
+ 'CREATE',
3464
+ 'ALTER',
3465
+ 'DROP',
3466
+ 'SET',
3467
+ 'INTO',
3468
+ 'OVERWRITE'
3469
+ ];
3470
+ const allTokens = this.tokens.getTokens();
3471
+ for (let i = 0; i < allTokens.length; i++) {
3472
+ const token = allTokens[i];
3473
+ const tokenText = token.text?.toUpperCase();
3474
+ if (token.channel !== 0)
3475
+ continue;
3476
+ if (!tokenText || !keywordsNeedingSpace.includes(tokenText))
3477
+ continue;
3478
+ // Skip if no edits were made near this token (it was already handled by visitor)
3479
+ const tokenLine = token.line - 1;
3480
+ const tokenStart = token.charPositionInLine;
3481
+ const tokenEnd = tokenStart + (token.text?.length || 0);
3482
+ // Check if there's already an edit for this token's surrounding whitespace
3483
+ if (this.editCollector.hasOverlappingEdit(tokenLine, tokenStart - 1, tokenLine, tokenEnd + 1)) {
3484
+ continue;
3485
+ }
3486
+ // Ensure space before keyword (unless at line start or after newline)
3487
+ if (i > 0) {
3488
+ const prevToken = allTokens[i - 1];
3489
+ if (prevToken.channel === 1 && prevToken.text && !prevToken.text.includes('\n')) {
3490
+ // Previous is whitespace on same line - ensure single space
3491
+ if (!prevToken.text.endsWith(' ')) {
3492
+ const prevStartChar = prevToken.charPositionInLine;
3493
+ const prevEndChar = prevStartChar + prevToken.text.length;
3494
+ if (!this.editCollector.hasOverlappingEdit(prevToken.line - 1, prevStartChar, prevToken.line - 1, prevEndChar)) {
3495
+ this.editCollector.addEdit({
3496
+ range: {
3497
+ start: { line: prevToken.line - 1, character: prevStartChar },
3498
+ end: { line: prevToken.line - 1, character: prevEndChar }
3499
+ },
3500
+ newText: `${prevToken.text} `
3501
+ });
3502
+ }
3503
+ }
3504
+ }
3505
+ }
3506
+ // Ensure space after keyword
3507
+ if (i + 1 < allTokens.length) {
3508
+ const nextToken = allTokens[i + 1];
3509
+ if (nextToken.channel === 1 && nextToken.text && !nextToken.text.includes('\n')) {
3510
+ // Next is whitespace on same line - ensure single space
3511
+ if (!nextToken.text.startsWith(' ')) {
3512
+ const nextStartChar = nextToken.charPositionInLine;
3513
+ const nextEndChar = nextStartChar + nextToken.text.length;
3514
+ if (!this.editCollector.hasOverlappingEdit(nextToken.line - 1, nextStartChar, nextToken.line - 1, nextEndChar)) {
3515
+ this.editCollector.addEdit({
3516
+ range: {
3517
+ start: { line: nextToken.line - 1, character: nextStartChar },
3518
+ end: { line: nextToken.line - 1, character: nextEndChar }
3519
+ },
3520
+ newText: ` ${nextToken.text}`
3521
+ });
3522
+ }
3523
+ }
3524
+ }
3525
+ }
3526
+ }
3527
+ }
3528
+ compressConsecutiveSpaces() {
3529
+ const allTokens = this.tokens.getTokens();
3530
+ for (const token of allTokens) {
3531
+ // Skip non-whitespace tokens (channel 1 is HIDDEN/whitespace)
3532
+ if (token.channel !== 1)
3533
+ continue;
3534
+ // Skip comment tokens (they are also on HIDDEN channel but should not be modified)
3535
+ if (token.type === SparkSQLLexer_1.SparkSQLLexer.SIMPLE_COMMENT || token.type === SparkSQLLexer_1.SparkSQLLexer.BRACKETED_COMMENT) {
3536
+ continue;
3537
+ }
3538
+ const text = token.text;
3539
+ if (!text)
3540
+ continue;
3541
+ const startLine = token.line - 1;
3542
+ const startChar = token.charPositionInLine;
3543
+ const endChar = startChar + text.length;
3544
+ if (this.editCollector.hasOverlappingEdit(startLine, startChar, startLine, endChar))
3545
+ continue;
3546
+ // Rule 1: Compress multiple spaces to single space (no newlines)
3547
+ if (!text.includes('\n') && !text.includes('\r') && text.includes(' ')) {
3548
+ this.editCollector.addEdit({
3549
+ range: {
3550
+ start: { line: startLine, character: startChar },
3551
+ end: { line: startLine, character: endChar }
3552
+ },
3553
+ newText: ' '
3554
+ });
3555
+ continue;
3556
+ }
3557
+ // Rule 3: Replace multiple newlines with single space between tokens
3558
+ // (newlines between keywords should become space)
3559
+ // This is handled by checking for consecutive newlines
3560
+ if ((text.includes('\n') || text.includes('\r')) && !text.includes(' ')) {
3561
+ // Count newlines
3562
+ const newlineCount = (text.match(/\n/g) || []).length + (text.match(/\r/g) || []).length;
3563
+ if (newlineCount > 1) {
3564
+ // Multiple newlines - replace with single space
3565
+ this.editCollector.addEdit({
3566
+ range: {
3567
+ start: { line: startLine, character: startChar },
3568
+ end: { line: startLine, character: endChar }
3569
+ },
3570
+ newText: ' '
3571
+ });
3572
+ }
3573
+ }
3574
+ }
3575
+ }
3576
+ /**
3577
+ * Clean up extra spaces inside parentheses: ( a, b ) -> (a, b)
3578
+ * Clean up comma spacing: a , b -> a, b
3579
+ * Called after main formatting is done
3580
+ */
3581
+ cleanParenthesesSpaces() {
3582
+ const allTokens = this.tokens.getTokens();
3583
+ // Find all parentheses pairs and clean spaces inside
3584
+ for (let i = 0; i < allTokens.length; i++) {
3585
+ const token = allTokens[i];
3586
+ // Check for left paren - ensure no space after
3587
+ if (token.text === '(' && token.channel === 0) {
3588
+ // Check if next token is whitespace with leading space
3589
+ if (i + 1 < allTokens.length) {
3590
+ const nextToken = allTokens[i + 1];
3591
+ // Only process if next token is whitespace on same line
3592
+ if (nextToken.channel === 1 &&
3593
+ nextToken.text &&
3594
+ nextToken.text.includes(' ') &&
3595
+ nextToken.line === token.line) {
3596
+ // Check if this is IN ( or EXISTS ( - skip cleaning as it should be "IN (\n SELECT"
3597
+ // Check if previous token is IN or EXISTS
3598
+ let skipCleaning = false;
3599
+ if (i > 0) {
3600
+ const prevToken = allTokens[i - 1];
3601
+ if (prevToken.channel === 0 &&
3602
+ (prevToken.text?.toUpperCase() === 'IN' || prevToken.text?.toUpperCase() === 'EXISTS')) {
3603
+ skipCleaning = true;
3604
+ }
3605
+ }
3606
+ if (!skipCleaning) {
3607
+ // Remove the space part after (
3608
+ const nextStartChar = nextToken.charPositionInLine;
3609
+ const nextEndChar = nextStartChar + nextToken.text.length;
3610
+ if (!this.editCollector.hasOverlappingEdit(nextToken.line - 1, nextStartChar, nextToken.line - 1, nextEndChar)) {
3611
+ // Keep only the non-space parts (like newlines)
3612
+ const nonSpacePart = nextToken.text.replace(/^ +/, '');
3613
+ this.editCollector.addEdit({
3614
+ range: {
3615
+ start: { line: nextToken.line - 1, character: nextStartChar },
3616
+ end: { line: nextToken.line - 1, character: nextEndChar }
3617
+ },
3618
+ newText: nonSpacePart
3619
+ });
3620
+ }
3621
+ }
3622
+ }
3623
+ }
3624
+ }
3625
+ // Check for right paren - ensure no space before
3626
+ if (token.text === ')' && token.channel === 0) {
3627
+ // Check if previous token is whitespace with trailing space
3628
+ if (i > 0) {
3629
+ const prevToken = allTokens[i - 1];
3630
+ // Only process if prev token is whitespace on same line
3631
+ if (prevToken.channel === 1 &&
3632
+ prevToken.text &&
3633
+ prevToken.text.includes(' ') &&
3634
+ prevToken.line === token.line) {
3635
+ // Remove the space part before )
3636
+ const prevStartChar = prevToken.charPositionInLine;
3637
+ const prevEndChar = prevStartChar + prevToken.text.length;
3638
+ if (!this.editCollector.hasOverlappingEdit(prevToken.line - 1, prevStartChar, prevToken.line - 1, prevEndChar)) {
3639
+ // Keep only the non-space parts (like newlines)
3640
+ const nonSpacePart = prevToken.text.replace(/ +$/, '');
3641
+ this.editCollector.addEdit({
3642
+ range: {
3643
+ start: { line: prevToken.line - 1, character: prevStartChar },
3644
+ end: { line: prevToken.line - 1, character: prevEndChar }
3645
+ },
3646
+ newText: nonSpacePart
3647
+ });
3648
+ }
3649
+ }
3650
+ }
3651
+ }
3652
+ // Clean space before comma
3653
+ if (token.text === ',' && token.channel === 0) {
3654
+ // Check if previous token is whitespace with space
3655
+ if (i > 0) {
3656
+ const prevToken = allTokens[i - 1];
3657
+ if (prevToken.channel === 1 &&
3658
+ prevToken.text &&
3659
+ prevToken.text.includes(' ') &&
3660
+ prevToken.line === token.line) {
3661
+ // Remove space before comma
3662
+ const prevStartChar = prevToken.charPositionInLine;
3663
+ const prevEndChar = prevStartChar + prevToken.text.length;
3664
+ if (!this.editCollector.hasOverlappingEdit(prevToken.line - 1, prevStartChar, prevToken.line - 1, prevEndChar)) {
3665
+ const nonSpacePart = prevToken.text.replace(/ +$/, '');
3666
+ this.editCollector.addEdit({
3667
+ range: {
3668
+ start: { line: prevToken.line - 1, character: prevStartChar },
3669
+ end: { line: prevToken.line - 1, character: prevEndChar }
3670
+ },
3671
+ newText: nonSpacePart
3672
+ });
3673
+ }
3674
+ }
3675
+ }
3676
+ }
3677
+ }
3678
+ }
3679
+ getJoinFormattingBridge() {
3680
+ return {
3681
+ updateAfterPreviousTokenByContext: (ctx, newText) => this.updateAfterPreviousTokenByContext(ctx, newText),
3682
+ updateAfterPreviousTokenByNode: (node, newText) => this.updateAfterPreviousTokenByNode(node, newText),
3683
+ updateBeforeNextTokenByNode: (node, newText) => this.updateBeforeNextTokenByNode(node, newText)
3684
+ };
3685
+ }
3686
+ getPipeStepBridge() {
3687
+ return {
3688
+ visit: (ctx) => this.visit(ctx),
3689
+ visitNode: (ctx) => this.visit(ctx),
3690
+ visitChildren: (ctx) => super.visitChildren(ctx),
3691
+ updateAfterPreviousTokenByContext: (ctx, newText) => this.updateAfterPreviousTokenByContext(ctx, newText),
3692
+ updateBeforeNextTokenByContext: (ctx, newText) => this.updateBeforeNextTokenByContext(ctx, newText),
3693
+ updateAfterPreviousTokenByNode: (node, newText) => this.updateAfterPreviousTokenByNode(node, newText),
3694
+ updateBeforeNextTokenByNode: (node, newText) => this.updateBeforeNextTokenByNode(node, newText),
3695
+ restorePipeFormattingState: (formatting) => {
3696
+ this.inPipeOperatorRightSide = formatting.previousInPipeOperatorRightSide;
3697
+ }
3698
+ };
3699
+ }
3700
+ getPipeStepKind(ctx) {
3701
+ if (ctx.selectClause())
3702
+ return 'pipe.select';
3703
+ if (ctx.whereClause())
3704
+ return 'pipe.where';
3705
+ if (ctx.SET())
3706
+ return 'pipe.set';
3707
+ if (ctx.DROP())
3708
+ return 'pipe.drop';
3709
+ if (ctx.EXTEND())
3710
+ return 'pipe.extend';
3711
+ if (ctx.joinRelation())
3712
+ return 'pipe.join';
3713
+ if (ctx.aggregationClause())
3714
+ return 'pipe.aggregate';
3715
+ if (ctx.queryOrganization())
3716
+ return 'pipe.queryOrganization';
3717
+ if (ctx.sample())
3718
+ return 'pipe.sample';
3719
+ if (ctx.pivotClause())
3720
+ return 'pipe.pivot';
3721
+ if (ctx.unpivotClause())
3722
+ return 'pipe.unpivot';
3723
+ return 'pipe.unknown';
3724
+ }
3725
+ // ==================== Compound Statement (Stored Procedures) ====================
3726
+ visitSingleCompoundStatement(ctx) {
3727
+ if (!this.tryFormatWithStrategy(ctx)) {
3728
+ super.visitChildren(ctx);
3729
+ }
3730
+ }
3731
+ visitBeginEndCompoundBlock(ctx) {
3732
+ if (!this.tryFormatWithStrategy(ctx)) {
3733
+ super.visitChildren(ctx);
3734
+ }
3735
+ }
3736
+ visitCompoundBody(ctx) {
3737
+ if (!this.tryFormatWithStrategy(ctx)) {
3738
+ super.visitChildren(ctx);
3739
+ }
3740
+ }
3741
+ visitCompoundStatement(ctx) {
3742
+ if (!this.tryFormatWithStrategy(ctx)) {
3743
+ super.visitChildren(ctx);
3744
+ }
3745
+ }
3746
+ visitIfElseStatement(ctx) {
3747
+ if (!this.tryFormatWithStrategy(ctx)) {
3748
+ super.visitChildren(ctx);
3749
+ }
3750
+ }
3751
+ visitWhileStatement(ctx) {
3752
+ if (!this.tryFormatWithStrategy(ctx)) {
3753
+ super.visitChildren(ctx);
3754
+ }
3755
+ }
3756
+ visitLoopStatement(ctx) {
3757
+ if (!this.tryFormatWithStrategy(ctx)) {
3758
+ super.visitChildren(ctx);
3759
+ }
3760
+ }
3761
+ visitRepeatStatement(ctx) {
3762
+ if (!this.tryFormatWithStrategy(ctx)) {
3763
+ super.visitChildren(ctx);
3764
+ }
3765
+ }
3766
+ visitForStatement(ctx) {
3767
+ if (!this.tryFormatWithStrategy(ctx)) {
3768
+ super.visitChildren(ctx);
3769
+ }
3770
+ }
3771
+ visitCaseStatement(ctx) {
3772
+ if (!this.tryFormatWithStrategy(ctx)) {
3773
+ super.visitChildren(ctx);
3774
+ }
3775
+ }
3776
+ visitSearchedCaseStatement(ctx) {
3777
+ if (!this.tryFormatWithStrategy(ctx)) {
3778
+ super.visitChildren(ctx);
3779
+ }
3780
+ }
3781
+ visitSimpleCaseStatement(ctx) {
3782
+ if (!this.tryFormatWithStrategy(ctx)) {
3783
+ super.visitChildren(ctx);
3784
+ }
3785
+ }
3786
+ visitLeaveStatement(ctx) {
3787
+ if (!this.tryFormatWithStrategy(ctx)) {
3788
+ super.visitChildren(ctx);
3789
+ }
3790
+ }
3791
+ visitIterateStatement(ctx) {
3792
+ if (!this.tryFormatWithStrategy(ctx)) {
3793
+ super.visitChildren(ctx);
3794
+ }
3795
+ }
3796
+ visitDeclareConditionStatement(ctx) {
3797
+ if (!this.tryFormatWithStrategy(ctx)) {
3798
+ super.visitChildren(ctx);
3799
+ }
3800
+ }
3801
+ visitDeclareHandlerStatement(ctx) {
3802
+ if (!this.tryFormatWithStrategy(ctx)) {
3803
+ super.visitChildren(ctx);
3804
+ }
3805
+ }
3806
+ }
3807
+ exports.StrategyBasedFormatter = StrategyBasedFormatter;
3808
+ //# sourceMappingURL=strategy-based-formatter.js.map