@alloy-js/core 0.24.0-dev.2 → 0.24.0-dev.7

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 (656) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/dev/src/components/AccessExpression.test.js +30 -38
  3. package/dist/dev/src/components/AccessExpression.test.js.map +1 -1
  4. package/dist/dev/src/components/Output.js +3 -2
  5. package/dist/dev/src/components/Output.js.map +1 -1
  6. package/dist/dev/src/components/SourceFile.js.map +1 -1
  7. package/dist/dev/src/content-slot.test.js +16 -18
  8. package/dist/dev/src/content-slot.test.js.map +1 -1
  9. package/dist/dev/src/context.js +30 -3
  10. package/dist/dev/src/context.js.map +1 -1
  11. package/dist/dev/src/debug/diagnostics.test.js +1 -1
  12. package/dist/dev/src/debug/diagnostics.test.js.map +1 -1
  13. package/dist/dev/src/debug/effects.test.js +1 -1
  14. package/dist/dev/src/debug/effects.test.js.map +1 -1
  15. package/dist/dev/src/debug/file-streaming.js +103 -0
  16. package/dist/dev/src/debug/file-streaming.js.map +1 -0
  17. package/dist/dev/src/debug/files.test.js +4 -5
  18. package/dist/dev/src/debug/files.test.js.map +1 -1
  19. package/dist/dev/src/debug/index.js +4 -6
  20. package/dist/dev/src/debug/index.js.map +1 -1
  21. package/dist/dev/src/debug/message-format.test.js +50 -52
  22. package/dist/dev/src/debug/message-format.test.js.map +1 -1
  23. package/dist/dev/src/debug/render-tree-orphans.test.js +13 -23
  24. package/dist/dev/src/debug/render-tree-orphans.test.js.map +1 -1
  25. package/dist/dev/src/debug/render.js +529 -352
  26. package/dist/dev/src/debug/render.js.map +1 -1
  27. package/dist/dev/src/debug/render.test.js +171 -92
  28. package/dist/dev/src/debug/render.test.js.map +1 -1
  29. package/dist/dev/src/debug/trace-writer.js +127 -15
  30. package/dist/dev/src/debug/trace-writer.js.map +1 -1
  31. package/dist/dev/src/debug/trace.js +0 -36
  32. package/dist/dev/src/debug/trace.js.map +1 -1
  33. package/dist/dev/src/devtools/devtools-server.js +55 -32
  34. package/dist/dev/src/devtools/devtools-server.js.map +1 -1
  35. package/dist/dev/src/devtools-entry.browser.js.map +1 -1
  36. package/dist/dev/src/devtools-entry.js.map +1 -1
  37. package/dist/dev/src/diagnostics.js +19 -1
  38. package/dist/dev/src/diagnostics.js.map +1 -1
  39. package/dist/dev/src/index.js +5 -2
  40. package/dist/dev/src/index.js.map +1 -1
  41. package/dist/dev/src/jsx-runtime.js +14 -8
  42. package/dist/dev/src/jsx-runtime.js.map +1 -1
  43. package/dist/dev/src/output-types.js +2 -0
  44. package/dist/dev/src/output-types.js.map +1 -0
  45. package/dist/dev/src/reactivity.js +155 -13
  46. package/dist/dev/src/reactivity.js.map +1 -1
  47. package/dist/dev/src/render/get-string-width.js +61 -0
  48. package/dist/dev/src/render/get-string-width.js.map +1 -0
  49. package/dist/dev/src/render/index.js +2 -0
  50. package/dist/dev/src/render/index.js.map +1 -0
  51. package/dist/dev/src/render/node-context.js +7 -0
  52. package/dist/dev/src/render/node-context.js.map +1 -0
  53. package/dist/dev/src/render/node.js +386 -0
  54. package/dist/dev/src/render/node.js.map +1 -0
  55. package/dist/dev/src/render/printer-support.js +180 -0
  56. package/dist/dev/src/render/printer-support.js.map +1 -0
  57. package/dist/dev/src/render/printer.js +797 -0
  58. package/dist/dev/src/render/printer.js.map +1 -0
  59. package/dist/dev/src/render-error.js +79 -0
  60. package/dist/dev/src/render-error.js.map +1 -0
  61. package/dist/dev/src/render-output.js +209 -0
  62. package/dist/dev/src/render-output.js.map +1 -0
  63. package/dist/dev/src/runtime/create-intrinsic.js +53 -0
  64. package/dist/dev/src/runtime/create-intrinsic.js.map +1 -0
  65. package/dist/dev/src/runtime/fragment.js +21 -0
  66. package/dist/dev/src/runtime/fragment.js.map +1 -0
  67. package/dist/dev/src/runtime/index.js +13 -0
  68. package/dist/dev/src/runtime/index.js.map +1 -0
  69. package/dist/dev/src/runtime/insert.js +453 -0
  70. package/dist/dev/src/runtime/insert.js.map +1 -0
  71. package/dist/dev/src/runtime/intrinsic.js +1 -11
  72. package/dist/dev/src/runtime/intrinsic.js.map +1 -1
  73. package/dist/dev/src/scheduler.js +38 -14
  74. package/dist/dev/src/scheduler.js.map +1 -1
  75. package/dist/dev/src/stc.js +2 -0
  76. package/dist/dev/src/stc.js.map +1 -1
  77. package/dist/dev/src/sti.js +1 -1
  78. package/dist/dev/src/sti.js.map +1 -1
  79. package/dist/dev/src/symbols/symbol-slot.test.js +5 -5
  80. package/dist/dev/src/symbols/symbol-slot.test.js.map +1 -1
  81. package/dist/dev/src/test-render.js +78 -0
  82. package/dist/dev/src/test-render.js.map +1 -0
  83. package/dist/dev/src/utils.js +47 -35
  84. package/dist/dev/src/utils.js.map +1 -1
  85. package/dist/dev/test/babel-e2e.test.js +218 -0
  86. package/dist/dev/test/babel-e2e.test.js.map +1 -0
  87. package/dist/dev/test/children.test.js +9 -11
  88. package/dist/dev/test/children.test.js.map +1 -1
  89. package/dist/dev/test/components/append-file.test.js +26 -27
  90. package/dist/dev/test/components/append-file.test.js.map +1 -1
  91. package/dist/dev/test/components/block.test.js +9 -11
  92. package/dist/dev/test/components/block.test.js.map +1 -1
  93. package/dist/dev/test/components/copy-file.test.js +1 -2
  94. package/dist/dev/test/components/copy-file.test.js.map +1 -1
  95. package/dist/dev/test/components/declaration.test.js +2 -2
  96. package/dist/dev/test/components/declaration.test.js.map +1 -1
  97. package/dist/dev/test/components/list.test.js +41 -43
  98. package/dist/dev/test/components/list.test.js.map +1 -1
  99. package/dist/dev/test/components/prose.test.js +4 -5
  100. package/dist/dev/test/components/prose.test.js.map +1 -1
  101. package/dist/dev/test/components/reference-or-content.test.js +32 -33
  102. package/dist/dev/test/components/reference-or-content.test.js.map +1 -1
  103. package/dist/dev/test/components/source-file.test.js +8 -7
  104. package/dist/dev/test/components/source-file.test.js.map +1 -1
  105. package/dist/dev/test/components/template-file.test.js +16 -17
  106. package/dist/dev/test/components/template-file.test.js.map +1 -1
  107. package/dist/dev/test/components/update-file.test.js +11 -12
  108. package/dist/dev/test/components/update-file.test.js.map +1 -1
  109. package/dist/dev/test/components/wrap.test.js +6 -8
  110. package/dist/dev/test/components/wrap.test.js.map +1 -1
  111. package/dist/dev/test/control-flow/for.test.js +58 -42
  112. package/dist/dev/test/control-flow/for.test.js.map +1 -1
  113. package/dist/dev/test/control-flow/match.test.js +15 -17
  114. package/dist/dev/test/control-flow/match.test.js.map +1 -1
  115. package/dist/dev/test/control-flow/show.test.js +5 -8
  116. package/dist/dev/test/control-flow/show.test.js.map +1 -1
  117. package/dist/dev/test/lazy-isempty.test.js +29 -31
  118. package/dist/dev/test/lazy-isempty.test.js.map +1 -1
  119. package/dist/dev/test/name-policy.test.js +2 -3
  120. package/dist/dev/test/name-policy.test.js.map +1 -1
  121. package/dist/dev/test/node.test.js +80 -0
  122. package/dist/dev/test/node.test.js.map +1 -0
  123. package/dist/dev/test/output-e2e.test.js +194 -0
  124. package/dist/dev/test/output-e2e.test.js.map +1 -0
  125. package/dist/dev/test/reactivity/circular-reactives.test.js +9 -9
  126. package/dist/dev/test/reactivity/circular-reactives.test.js.map +1 -1
  127. package/dist/dev/test/reactivity/cleanup.test.js +5 -6
  128. package/dist/dev/test/reactivity/cleanup.test.js.map +1 -1
  129. package/dist/dev/test/reactivity/ref-rendering.test.js +15 -15
  130. package/dist/dev/test/reactivity/ref-rendering.test.js.map +1 -1
  131. package/dist/dev/test/reactivity/test.test.js +18 -18
  132. package/dist/dev/test/reactivity/test.test.js.map +1 -1
  133. package/dist/dev/test/rendering/basic.test.js +18 -19
  134. package/dist/dev/test/rendering/basic.test.js.map +1 -1
  135. package/dist/dev/test/rendering/code.test.js +2 -3
  136. package/dist/dev/test/rendering/code.test.js.map +1 -1
  137. package/dist/dev/test/rendering/formatting.test.js +115 -121
  138. package/dist/dev/test/rendering/formatting.test.js.map +1 -1
  139. package/dist/dev/test/rendering/indent.test.js +23 -24
  140. package/dist/dev/test/rendering/indent.test.js.map +1 -1
  141. package/dist/dev/test/rendering/memoization.test.js +9 -5
  142. package/dist/dev/test/rendering/memoization.test.js.map +1 -1
  143. package/dist/dev/test/rendering/print-render-stack.test.js +20 -21
  144. package/dist/dev/test/rendering/print-render-stack.test.js.map +1 -1
  145. package/dist/dev/test/rendering/refkeys.test.js +1 -2
  146. package/dist/dev/test/rendering/refkeys.test.js.map +1 -1
  147. package/dist/dev/test/rendering/render-output-diagnostics.test.js +102 -0
  148. package/dist/dev/test/rendering/render-output-diagnostics.test.js.map +1 -0
  149. package/dist/dev/test/runtime.test.js +385 -0
  150. package/dist/dev/test/runtime.test.js.map +1 -0
  151. package/dist/dev/test/stc.test.js +0 -1
  152. package/dist/dev/test/stc.test.js.map +1 -1
  153. package/dist/dev/test/tree-test-utils.js +16 -0
  154. package/dist/dev/test/tree-test-utils.js.map +1 -0
  155. package/dist/dev/test/utils.test.js +34 -33
  156. package/dist/dev/test/utils.test.js.map +1 -1
  157. package/dist/dev/test/vitest.setup.js +2 -0
  158. package/dist/dev/test/vitest.setup.js.map +1 -0
  159. package/dist/dev/testing/devtools-utils.js +1 -1
  160. package/dist/dev/testing/devtools-utils.js.map +1 -1
  161. package/dist/dev/testing/extend-expect.js +30 -34
  162. package/dist/dev/testing/extend-expect.js.map +1 -1
  163. package/dist/dev/testing/render.js +7 -17
  164. package/dist/dev/testing/render.js.map +1 -1
  165. package/dist/devtools/index.html +17 -17
  166. package/dist/src/components/AccessExpression.test.d.ts +1 -1
  167. package/dist/src/components/AccessExpression.test.d.ts.map +1 -1
  168. package/dist/src/components/AccessExpression.test.js +5 -13
  169. package/dist/src/components/AccessExpression.test.js.map +1 -1
  170. package/dist/src/components/Output.d.ts +1 -1
  171. package/dist/src/components/Output.d.ts.map +1 -1
  172. package/dist/src/components/Output.js +2 -1
  173. package/dist/src/components/Output.js.map +1 -1
  174. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  175. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  176. package/dist/src/components/SourceFile.d.ts +1 -1
  177. package/dist/src/components/SourceFile.d.ts.map +1 -1
  178. package/dist/src/components/SourceFile.js.map +1 -1
  179. package/dist/src/content-slot.test.d.ts +1 -1
  180. package/dist/src/content-slot.test.d.ts.map +1 -1
  181. package/dist/src/content-slot.test.js +8 -10
  182. package/dist/src/content-slot.test.js.map +1 -1
  183. package/dist/src/context/format-options.d.ts +1 -1
  184. package/dist/src/context/format-options.d.ts.map +1 -1
  185. package/dist/src/context.d.ts +9 -1
  186. package/dist/src/context.d.ts.map +1 -1
  187. package/dist/src/context.js +30 -3
  188. package/dist/src/context.js.map +1 -1
  189. package/dist/src/debug/diagnostics.test.js +1 -1
  190. package/dist/src/debug/diagnostics.test.js.map +1 -1
  191. package/dist/src/debug/effects.test.js +1 -1
  192. package/dist/src/debug/effects.test.js.map +1 -1
  193. package/dist/src/debug/file-streaming.d.ts +22 -0
  194. package/dist/src/debug/file-streaming.d.ts.map +1 -0
  195. package/dist/src/debug/file-streaming.js +103 -0
  196. package/dist/src/debug/file-streaming.js.map +1 -0
  197. package/dist/src/debug/files.test.js +4 -5
  198. package/dist/src/debug/files.test.js.map +1 -1
  199. package/dist/src/debug/index.d.ts +5 -7
  200. package/dist/src/debug/index.d.ts.map +1 -1
  201. package/dist/src/debug/index.js +4 -6
  202. package/dist/src/debug/index.js.map +1 -1
  203. package/dist/src/debug/message-format.test.js +16 -18
  204. package/dist/src/debug/message-format.test.js.map +1 -1
  205. package/dist/src/debug/render-tree-orphans.test.js +8 -18
  206. package/dist/src/debug/render-tree-orphans.test.js.map +1 -1
  207. package/dist/src/debug/render.d.ts +71 -21
  208. package/dist/src/debug/render.d.ts.map +1 -1
  209. package/dist/src/debug/render.js +529 -352
  210. package/dist/src/debug/render.js.map +1 -1
  211. package/dist/src/debug/render.test.js +137 -74
  212. package/dist/src/debug/render.test.js.map +1 -1
  213. package/dist/src/debug/trace-writer.d.ts +6 -1
  214. package/dist/src/debug/trace-writer.d.ts.map +1 -1
  215. package/dist/src/debug/trace-writer.js +127 -15
  216. package/dist/src/debug/trace-writer.js.map +1 -1
  217. package/dist/src/debug/trace.d.ts +0 -36
  218. package/dist/src/debug/trace.d.ts.map +1 -1
  219. package/dist/src/debug/trace.js +0 -36
  220. package/dist/src/debug/trace.js.map +1 -1
  221. package/dist/src/devtools/devtools-protocol.d.ts +34 -1
  222. package/dist/src/devtools/devtools-protocol.d.ts.map +1 -1
  223. package/dist/src/devtools/devtools-server.d.ts.map +1 -1
  224. package/dist/src/devtools/devtools-server.js +55 -32
  225. package/dist/src/devtools/devtools-server.js.map +1 -1
  226. package/dist/src/devtools-entry.browser.d.ts +1 -1
  227. package/dist/src/devtools-entry.browser.d.ts.map +1 -1
  228. package/dist/src/devtools-entry.browser.js.map +1 -1
  229. package/dist/src/devtools-entry.d.ts +1 -1
  230. package/dist/src/devtools-entry.d.ts.map +1 -1
  231. package/dist/src/devtools-entry.js.map +1 -1
  232. package/dist/src/diagnostics.d.ts +4 -0
  233. package/dist/src/diagnostics.d.ts.map +1 -1
  234. package/dist/src/diagnostics.js +19 -1
  235. package/dist/src/diagnostics.js.map +1 -1
  236. package/dist/src/index.d.ts +5 -2
  237. package/dist/src/index.d.ts.map +1 -1
  238. package/dist/src/index.js +5 -2
  239. package/dist/src/index.js.map +1 -1
  240. package/dist/src/jsx-runtime.d.ts +13 -4
  241. package/dist/src/jsx-runtime.d.ts.map +1 -1
  242. package/dist/src/jsx-runtime.js +14 -8
  243. package/dist/src/jsx-runtime.js.map +1 -1
  244. package/dist/src/output-types.d.ts +40 -0
  245. package/dist/src/output-types.d.ts.map +1 -0
  246. package/dist/src/output-types.js +2 -0
  247. package/dist/src/output-types.js.map +1 -0
  248. package/dist/src/reactivity.d.ts +49 -18
  249. package/dist/src/reactivity.d.ts.map +1 -1
  250. package/dist/src/reactivity.js +155 -13
  251. package/dist/src/reactivity.js.map +1 -1
  252. package/dist/src/render/get-string-width.d.ts +19 -0
  253. package/dist/src/render/get-string-width.d.ts.map +1 -0
  254. package/dist/src/render/get-string-width.js +61 -0
  255. package/dist/src/render/get-string-width.js.map +1 -0
  256. package/dist/src/render/index.d.ts +2 -0
  257. package/dist/src/render/index.d.ts.map +1 -0
  258. package/dist/src/render/index.js +2 -0
  259. package/dist/src/render/index.js.map +1 -0
  260. package/dist/src/render/node-context.d.ts +5 -0
  261. package/dist/src/render/node-context.d.ts.map +1 -0
  262. package/dist/src/render/node-context.js +7 -0
  263. package/dist/src/render/node-context.js.map +1 -0
  264. package/dist/src/render/node.d.ts +146 -0
  265. package/dist/src/render/node.d.ts.map +1 -0
  266. package/dist/src/render/node.js +386 -0
  267. package/dist/src/render/node.js.map +1 -0
  268. package/dist/src/render/printer-support.d.ts +50 -0
  269. package/dist/src/render/printer-support.d.ts.map +1 -0
  270. package/dist/src/render/printer-support.js +180 -0
  271. package/dist/src/render/printer-support.js.map +1 -0
  272. package/dist/src/render/printer.d.ts +35 -0
  273. package/dist/src/render/printer.d.ts.map +1 -0
  274. package/dist/src/render/printer.js +797 -0
  275. package/dist/src/render/printer.js.map +1 -0
  276. package/dist/src/render-error.d.ts +4 -0
  277. package/dist/src/render-error.d.ts.map +1 -0
  278. package/dist/src/render-error.js +79 -0
  279. package/dist/src/render-error.js.map +1 -0
  280. package/dist/src/render-output.d.ts +42 -0
  281. package/dist/src/render-output.d.ts.map +1 -0
  282. package/dist/src/render-output.js +209 -0
  283. package/dist/src/render-output.js.map +1 -0
  284. package/dist/src/runtime/component.d.ts +2 -2
  285. package/dist/src/runtime/component.d.ts.map +1 -1
  286. package/dist/src/runtime/create-intrinsic.d.ts +28 -0
  287. package/dist/src/runtime/create-intrinsic.d.ts.map +1 -0
  288. package/dist/src/runtime/create-intrinsic.js +53 -0
  289. package/dist/src/runtime/create-intrinsic.js.map +1 -0
  290. package/dist/src/runtime/fragment.d.ts +16 -0
  291. package/dist/src/runtime/fragment.d.ts.map +1 -0
  292. package/dist/src/runtime/fragment.js +21 -0
  293. package/dist/src/runtime/fragment.js.map +1 -0
  294. package/dist/src/runtime/index.d.ts +12 -0
  295. package/dist/src/runtime/index.d.ts.map +1 -0
  296. package/dist/src/runtime/index.js +13 -0
  297. package/dist/src/runtime/index.js.map +1 -0
  298. package/dist/src/runtime/insert.d.ts +29 -0
  299. package/dist/src/runtime/insert.d.ts.map +1 -0
  300. package/dist/src/runtime/insert.js +453 -0
  301. package/dist/src/runtime/insert.js.map +1 -0
  302. package/dist/src/runtime/intrinsic.d.ts +12 -29
  303. package/dist/src/runtime/intrinsic.d.ts.map +1 -1
  304. package/dist/src/runtime/intrinsic.js +1 -11
  305. package/dist/src/runtime/intrinsic.js.map +1 -1
  306. package/dist/src/scheduler.d.ts.map +1 -1
  307. package/dist/src/scheduler.js +38 -14
  308. package/dist/src/scheduler.js.map +1 -1
  309. package/dist/src/stc.d.ts.map +1 -1
  310. package/dist/src/stc.js +2 -0
  311. package/dist/src/stc.js.map +1 -1
  312. package/dist/src/sti.d.ts +7 -6
  313. package/dist/src/sti.d.ts.map +1 -1
  314. package/dist/src/sti.js +1 -1
  315. package/dist/src/sti.js.map +1 -1
  316. package/dist/src/symbols/symbol-slot.test.js +5 -5
  317. package/dist/src/symbols/symbol-slot.test.js.map +1 -1
  318. package/dist/src/test-render.d.ts +31 -0
  319. package/dist/src/test-render.d.ts.map +1 -0
  320. package/dist/src/test-render.js +78 -0
  321. package/dist/src/test-render.js.map +1 -0
  322. package/dist/src/utils.d.ts +1 -1
  323. package/dist/src/utils.d.ts.map +1 -1
  324. package/dist/src/utils.js +40 -28
  325. package/dist/src/utils.js.map +1 -1
  326. package/dist/src/write-output.d.ts +1 -1
  327. package/dist/src/write-output.d.ts.map +1 -1
  328. package/dist/test/babel-e2e.test.d.ts +13 -0
  329. package/dist/test/babel-e2e.test.d.ts.map +1 -0
  330. package/dist/test/babel-e2e.test.js +218 -0
  331. package/dist/test/babel-e2e.test.js.map +1 -0
  332. package/dist/test/children.test.js +5 -7
  333. package/dist/test/children.test.js.map +1 -1
  334. package/dist/test/components/append-file.test.d.ts +1 -1
  335. package/dist/test/components/append-file.test.d.ts.map +1 -1
  336. package/dist/test/components/append-file.test.js +0 -1
  337. package/dist/test/components/append-file.test.js.map +1 -1
  338. package/dist/test/components/block.test.d.ts +1 -1
  339. package/dist/test/components/block.test.d.ts.map +1 -1
  340. package/dist/test/components/block.test.js +4 -6
  341. package/dist/test/components/block.test.js.map +1 -1
  342. package/dist/test/components/copy-file.test.d.ts +1 -1
  343. package/dist/test/components/copy-file.test.d.ts.map +1 -1
  344. package/dist/test/components/copy-file.test.js +1 -2
  345. package/dist/test/components/copy-file.test.js.map +1 -1
  346. package/dist/test/components/declaration.test.js +2 -2
  347. package/dist/test/components/declaration.test.js.map +1 -1
  348. package/dist/test/components/list.test.d.ts +1 -1
  349. package/dist/test/components/list.test.d.ts.map +1 -1
  350. package/dist/test/components/list.test.js +20 -22
  351. package/dist/test/components/list.test.js.map +1 -1
  352. package/dist/test/components/prose.test.d.ts +1 -1
  353. package/dist/test/components/prose.test.d.ts.map +1 -1
  354. package/dist/test/components/prose.test.js +0 -1
  355. package/dist/test/components/prose.test.js.map +1 -1
  356. package/dist/test/components/reference-or-content.test.js +8 -9
  357. package/dist/test/components/reference-or-content.test.js.map +1 -1
  358. package/dist/test/components/source-file.test.d.ts +1 -1
  359. package/dist/test/components/source-file.test.d.ts.map +1 -1
  360. package/dist/test/components/source-file.test.js +5 -4
  361. package/dist/test/components/source-file.test.js.map +1 -1
  362. package/dist/test/components/template-file.test.d.ts +1 -1
  363. package/dist/test/components/template-file.test.d.ts.map +1 -1
  364. package/dist/test/components/template-file.test.js +0 -1
  365. package/dist/test/components/template-file.test.js.map +1 -1
  366. package/dist/test/components/update-file.test.d.ts +1 -1
  367. package/dist/test/components/update-file.test.d.ts.map +1 -1
  368. package/dist/test/components/update-file.test.js +1 -2
  369. package/dist/test/components/update-file.test.js.map +1 -1
  370. package/dist/test/components/wrap.test.d.ts +1 -1
  371. package/dist/test/components/wrap.test.d.ts.map +1 -1
  372. package/dist/test/components/wrap.test.js +3 -5
  373. package/dist/test/components/wrap.test.js.map +1 -1
  374. package/dist/test/control-flow/for.test.d.ts +1 -1
  375. package/dist/test/control-flow/for.test.d.ts.map +1 -1
  376. package/dist/test/control-flow/for.test.js +40 -24
  377. package/dist/test/control-flow/for.test.js.map +1 -1
  378. package/dist/test/control-flow/match.test.d.ts +1 -1
  379. package/dist/test/control-flow/match.test.d.ts.map +1 -1
  380. package/dist/test/control-flow/match.test.js +4 -6
  381. package/dist/test/control-flow/match.test.js.map +1 -1
  382. package/dist/test/control-flow/show.test.d.ts +1 -1
  383. package/dist/test/control-flow/show.test.d.ts.map +1 -1
  384. package/dist/test/control-flow/show.test.js +3 -6
  385. package/dist/test/control-flow/show.test.js.map +1 -1
  386. package/dist/test/lazy-isempty.test.d.ts +1 -1
  387. package/dist/test/lazy-isempty.test.d.ts.map +1 -1
  388. package/dist/test/lazy-isempty.test.js +16 -18
  389. package/dist/test/lazy-isempty.test.js.map +1 -1
  390. package/dist/test/name-policy.test.d.ts +1 -1
  391. package/dist/test/name-policy.test.d.ts.map +1 -1
  392. package/dist/test/name-policy.test.js +0 -1
  393. package/dist/test/name-policy.test.js.map +1 -1
  394. package/dist/test/node.test.d.ts +2 -0
  395. package/dist/test/node.test.d.ts.map +1 -0
  396. package/dist/test/node.test.js +80 -0
  397. package/dist/test/node.test.js.map +1 -0
  398. package/dist/test/output-e2e.test.d.ts +13 -0
  399. package/dist/test/output-e2e.test.d.ts.map +1 -0
  400. package/dist/test/output-e2e.test.js +194 -0
  401. package/dist/test/output-e2e.test.js.map +1 -0
  402. package/dist/test/reactivity/circular-reactives.test.js +6 -6
  403. package/dist/test/reactivity/circular-reactives.test.js.map +1 -1
  404. package/dist/test/reactivity/cleanup.test.js +2 -3
  405. package/dist/test/reactivity/cleanup.test.js.map +1 -1
  406. package/dist/test/reactivity/ref-rendering.test.js +15 -15
  407. package/dist/test/reactivity/ref-rendering.test.js.map +1 -1
  408. package/dist/test/reactivity/test.test.js +15 -15
  409. package/dist/test/reactivity/test.test.js.map +1 -1
  410. package/dist/test/rendering/basic.test.d.ts +1 -1
  411. package/dist/test/rendering/basic.test.d.ts.map +1 -1
  412. package/dist/test/rendering/basic.test.js +0 -1
  413. package/dist/test/rendering/basic.test.js.map +1 -1
  414. package/dist/test/rendering/code.test.d.ts +1 -1
  415. package/dist/test/rendering/code.test.d.ts.map +1 -1
  416. package/dist/test/rendering/code.test.js +0 -1
  417. package/dist/test/rendering/code.test.js.map +1 -1
  418. package/dist/test/rendering/formatting.test.d.ts +1 -1
  419. package/dist/test/rendering/formatting.test.d.ts.map +1 -1
  420. package/dist/test/rendering/formatting.test.js +17 -23
  421. package/dist/test/rendering/formatting.test.js.map +1 -1
  422. package/dist/test/rendering/indent.test.d.ts +1 -1
  423. package/dist/test/rendering/indent.test.d.ts.map +1 -1
  424. package/dist/test/rendering/indent.test.js +0 -1
  425. package/dist/test/rendering/indent.test.js.map +1 -1
  426. package/dist/test/rendering/memoization.test.js +7 -3
  427. package/dist/test/rendering/memoization.test.js.map +1 -1
  428. package/dist/test/rendering/print-render-stack.test.d.ts +1 -1
  429. package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -1
  430. package/dist/test/rendering/print-render-stack.test.js +0 -1
  431. package/dist/test/rendering/print-render-stack.test.js.map +1 -1
  432. package/dist/test/rendering/refkeys.test.d.ts +1 -1
  433. package/dist/test/rendering/refkeys.test.d.ts.map +1 -1
  434. package/dist/test/rendering/refkeys.test.js +0 -1
  435. package/dist/test/rendering/refkeys.test.js.map +1 -1
  436. package/dist/test/rendering/render-output-diagnostics.test.d.ts +2 -0
  437. package/dist/test/rendering/render-output-diagnostics.test.d.ts.map +1 -0
  438. package/dist/test/rendering/render-output-diagnostics.test.js +82 -0
  439. package/dist/test/rendering/render-output-diagnostics.test.js.map +1 -0
  440. package/dist/test/runtime.test.d.ts +11 -0
  441. package/dist/test/runtime.test.d.ts.map +1 -0
  442. package/dist/test/runtime.test.js +385 -0
  443. package/dist/test/runtime.test.js.map +1 -0
  444. package/dist/test/stc.test.d.ts +1 -1
  445. package/dist/test/stc.test.d.ts.map +1 -1
  446. package/dist/test/stc.test.js +0 -1
  447. package/dist/test/stc.test.js.map +1 -1
  448. package/dist/test/tree-test-utils.d.ts +3 -0
  449. package/dist/test/tree-test-utils.d.ts.map +1 -0
  450. package/dist/test/tree-test-utils.js +16 -0
  451. package/dist/test/tree-test-utils.js.map +1 -0
  452. package/dist/test/utils.test.d.ts +1 -1
  453. package/dist/test/utils.test.d.ts.map +1 -1
  454. package/dist/test/utils.test.js +12 -11
  455. package/dist/test/utils.test.js.map +1 -1
  456. package/dist/test/vitest.setup.d.ts +2 -0
  457. package/dist/test/vitest.setup.d.ts.map +1 -0
  458. package/dist/test/vitest.setup.js +2 -0
  459. package/dist/test/vitest.setup.js.map +1 -0
  460. package/dist/testing/devtools-utils.d.ts.map +1 -1
  461. package/dist/testing/devtools-utils.js +1 -1
  462. package/dist/testing/devtools-utils.js.map +1 -1
  463. package/dist/testing/extend-expect.d.ts.map +1 -1
  464. package/dist/testing/extend-expect.js +30 -34
  465. package/dist/testing/extend-expect.js.map +1 -1
  466. package/dist/testing/render.d.ts +7 -9
  467. package/dist/testing/render.d.ts.map +1 -1
  468. package/dist/testing/render.js +7 -17
  469. package/dist/testing/render.js.map +1 -1
  470. package/dist/tsconfig.tsbuildinfo +1 -1
  471. package/docs/api/components/Output.md +0 -3
  472. package/docs/api/components/SourceFile.md +0 -3
  473. package/docs/api/functions/createComment.md +18 -0
  474. package/docs/api/functions/createElement.md +19 -0
  475. package/docs/api/functions/createFragment.md +17 -0
  476. package/docs/api/functions/createTextNode.md +18 -0
  477. package/docs/api/functions/emitDiagnosticForTree.md +19 -0
  478. package/docs/api/functions/ensureIsEmpty.md +1 -1
  479. package/docs/api/functions/getContextForNode.md +18 -0
  480. package/docs/api/functions/getContextForRenderNode.md +4 -4
  481. package/docs/api/functions/getDiagnosticsForTree.md +7 -5
  482. package/docs/api/functions/getRegisteredDiagnosticsForTree.md +18 -0
  483. package/docs/api/functions/index.md +17 -12
  484. package/docs/api/functions/isCustomContext.md +4 -4
  485. package/docs/api/functions/notifyContentState.md +6 -0
  486. package/docs/api/functions/printTree.md +6 -16
  487. package/docs/api/functions/registerDiagnosticsForTree.md +19 -0
  488. package/docs/api/functions/render.md +1 -2
  489. package/docs/api/functions/renderAsync.md +1 -2
  490. package/docs/api/functions/renderTree.md +8 -5
  491. package/docs/api/functions/reportDiagnosticsForTree.md +18 -0
  492. package/docs/api/functions/runInContext.md +28 -0
  493. package/docs/api/functions/sourceFilesForTree.md +6 -16
  494. package/docs/api/index.md +3 -3
  495. package/docs/api/testing/functions/index.md +1 -1
  496. package/docs/api/testing/functions/renderToString.md +1 -1
  497. package/docs/api/types/AlloyNode.md +22 -0
  498. package/docs/api/types/Child.md +1 -1
  499. package/docs/api/types/CommentNode.md +15 -0
  500. package/docs/api/types/Context.md +13 -15
  501. package/docs/api/types/ElementNode.md +18 -0
  502. package/docs/api/types/FragmentNode.md +12 -0
  503. package/docs/api/types/Insertable.md +7 -0
  504. package/docs/api/types/NodeType.md +5 -0
  505. package/docs/api/types/OutputDirectory.md +0 -50
  506. package/docs/api/types/PrintTreeOptions.md +0 -1
  507. package/docs/api/types/RenderTreeOptions.md +7 -0
  508. package/docs/api/types/StiComponentCreator.md +4 -4
  509. package/docs/api/types/StiSignature.md +1 -1
  510. package/docs/api/types/TextNode.md +16 -0
  511. package/docs/api/types/index.md +10 -28
  512. package/docs/api/variables/COMMENT_NODE.md +5 -0
  513. package/docs/api/variables/ELEMENT_NODE.md +11 -0
  514. package/docs/api/variables/FRAGMENT_NODE.md +5 -0
  515. package/docs/api/variables/TEXT_NODE.md +5 -0
  516. package/docs/api/variables/index.md +4 -2
  517. package/docs/formatting.md +1 -1
  518. package/docs/rendering.md +4 -4
  519. package/package.json +6 -6
  520. package/src/components/AccessExpression.test.tsx +5 -13
  521. package/src/components/Output.tsx +2 -1
  522. package/src/components/SourceFile.tsx +1 -1
  523. package/src/content-slot.test.tsx +8 -10
  524. package/src/context/format-options.ts +1 -1
  525. package/src/context.ts +37 -4
  526. package/src/debug/diagnostics.test.tsx +1 -1
  527. package/src/debug/effects.test.tsx +1 -1
  528. package/src/debug/file-streaming.ts +115 -0
  529. package/src/debug/files.test.tsx +15 -11
  530. package/src/debug/index.ts +11 -11
  531. package/src/debug/message-format.test.tsx +32 -19
  532. package/src/debug/render-tree-orphans.test.tsx +10 -19
  533. package/src/debug/render.test.tsx +206 -78
  534. package/src/debug/render.ts +642 -495
  535. package/src/debug/trace-writer.ts +168 -14
  536. package/src/debug/trace.ts +0 -20
  537. package/src/devtools/devtools-protocol.ts +43 -0
  538. package/src/devtools/devtools-server.ts +57 -32
  539. package/src/devtools-entry.browser.ts +5 -0
  540. package/src/devtools-entry.ts +5 -0
  541. package/src/diagnostics.ts +31 -0
  542. package/src/index.ts +66 -2
  543. package/src/jsx-runtime.ts +16 -14
  544. package/src/output-types.ts +47 -0
  545. package/src/reactivity.ts +186 -40
  546. package/src/render/get-string-width.ts +201 -0
  547. package/src/render/index.ts +1 -0
  548. package/src/render/node-context.ts +14 -0
  549. package/src/render/node.ts +442 -0
  550. package/src/render/printer-support.ts +209 -0
  551. package/src/render/printer.ts +817 -0
  552. package/src/render-error.ts +98 -0
  553. package/src/render-output.ts +243 -0
  554. package/src/runtime/component.ts +2 -2
  555. package/src/runtime/create-intrinsic.ts +56 -0
  556. package/src/runtime/fragment.ts +22 -0
  557. package/src/runtime/index.ts +12 -0
  558. package/src/runtime/insert.ts +569 -0
  559. package/src/runtime/intrinsic.ts +14 -70
  560. package/src/scheduler.ts +40 -25
  561. package/src/stc.ts +3 -0
  562. package/src/sti.ts +17 -20
  563. package/src/symbols/symbol-slot.test.tsx +5 -5
  564. package/src/test-render.ts +103 -0
  565. package/src/utils.tsx +55 -37
  566. package/src/write-output.ts +1 -1
  567. package/temp/api-testing.json +390 -14
  568. package/temp/api.json +4320 -4144
  569. package/test/babel-e2e.test.ts +224 -0
  570. package/test/children.test.tsx +4 -7
  571. package/test/components/append-file.test.tsx +0 -1
  572. package/test/components/block.test.tsx +4 -6
  573. package/test/components/copy-file.test.tsx +2 -2
  574. package/test/components/declaration.test.tsx +2 -2
  575. package/test/components/list.test.tsx +20 -29
  576. package/test/components/prose.test.tsx +0 -1
  577. package/test/components/reference-or-content.test.tsx +8 -9
  578. package/test/components/source-file.test.tsx +4 -4
  579. package/test/components/template-file.test.tsx +0 -1
  580. package/test/components/update-file.test.tsx +1 -2
  581. package/test/components/wrap.test.tsx +3 -5
  582. package/test/control-flow/for.test.tsx +39 -31
  583. package/test/control-flow/match.test.tsx +4 -6
  584. package/test/control-flow/show.test.tsx +3 -6
  585. package/test/lazy-isempty.test.tsx +17 -19
  586. package/test/name-policy.test.tsx +0 -1
  587. package/test/node.test.ts +90 -0
  588. package/test/output-e2e.test.ts +198 -0
  589. package/test/reactivity/circular-reactives.test.tsx +6 -6
  590. package/test/reactivity/cleanup.test.tsx +2 -3
  591. package/test/reactivity/ref-rendering.test.tsx +15 -15
  592. package/test/reactivity/test.test.tsx +14 -14
  593. package/test/rendering/basic.test.tsx +0 -1
  594. package/test/rendering/code.test.tsx +0 -1
  595. package/test/rendering/formatting.test.tsx +21 -29
  596. package/test/rendering/indent.test.tsx +0 -1
  597. package/test/rendering/memoization.test.tsx +7 -3
  598. package/test/rendering/print-render-stack.test.tsx +0 -1
  599. package/test/rendering/refkeys.test.tsx +0 -1
  600. package/test/rendering/render-output-diagnostics.test.tsx +120 -0
  601. package/test/runtime.test.ts +448 -0
  602. package/test/stc.test.tsx +0 -1
  603. package/test/tree-test-utils.ts +23 -0
  604. package/test/utils.test.tsx +10 -9
  605. package/test/vitest.setup.ts +1 -0
  606. package/testing/devtools-utils.ts +2 -0
  607. package/testing/extend-expect.ts +32 -47
  608. package/testing/render.ts +17 -21
  609. package/vitest.config.ts +3 -0
  610. package/dist/dev/src/print-hook.js +0 -10
  611. package/dist/dev/src/print-hook.js.map +0 -1
  612. package/dist/dev/src/render.js +0 -872
  613. package/dist/dev/src/render.js.map +0 -1
  614. package/dist/src/print-hook.d.ts +0 -14
  615. package/dist/src/print-hook.d.ts.map +0 -1
  616. package/dist/src/print-hook.js +0 -10
  617. package/dist/src/print-hook.js.map +0 -1
  618. package/dist/src/render.d.ts +0 -155
  619. package/dist/src/render.d.ts.map +0 -1
  620. package/dist/src/render.js +0 -872
  621. package/dist/src/render.js.map +0 -1
  622. package/docs/api/functions/createIntrinsic.md +0 -19
  623. package/docs/api/functions/createRenderTreeHook.md +0 -19
  624. package/docs/api/functions/getElementCache.md +0 -17
  625. package/docs/api/functions/isIntrinsicElement.md +0 -18
  626. package/docs/api/functions/isPrintHook.md +0 -18
  627. package/docs/api/types/AlignIntrinsicElement.md +0 -5
  628. package/docs/api/types/BrIntrinsicElement.md +0 -5
  629. package/docs/api/types/BreakParentIntrinsicElement.md +0 -5
  630. package/docs/api/types/DedentIntrinsicElement.md +0 -5
  631. package/docs/api/types/DedentToRootIntrinsicElement.md +0 -5
  632. package/docs/api/types/ElementCache.md +0 -5
  633. package/docs/api/types/ElementCacheKey.md +0 -5
  634. package/docs/api/types/FillIntrinsicElement.md +0 -5
  635. package/docs/api/types/GroupIntrinsicElement.md +0 -5
  636. package/docs/api/types/HardlineIntrinsicElement.md +0 -5
  637. package/docs/api/types/HbrIntrinsicElement.md +0 -5
  638. package/docs/api/types/IfBreakIntrinsicElement.md +0 -5
  639. package/docs/api/types/IndentIfBreakIntrinsicElement.md +0 -5
  640. package/docs/api/types/IndentIntrinsicElement.md +0 -5
  641. package/docs/api/types/IntrinsicElement.md +0 -5
  642. package/docs/api/types/IntrinsicElementBase.md +0 -9
  643. package/docs/api/types/LbrIntrinsicElement.md +0 -5
  644. package/docs/api/types/LineIntrinsicElement.md +0 -5
  645. package/docs/api/types/LineSuffixBoundaryIntrinsicElement.md +0 -5
  646. package/docs/api/types/LineSuffixIntrinsicElement.md +0 -5
  647. package/docs/api/types/LiterallineIntrinsicElement.md +0 -5
  648. package/docs/api/types/MarkAsRootIntrinsicElement.md +0 -5
  649. package/docs/api/types/PrintHook.md +0 -10
  650. package/docs/api/types/RenderedTextTree.md +0 -5
  651. package/docs/api/types/SbrIntrinsicElement.md +0 -5
  652. package/docs/api/types/SoftlineIntrinsicElement.md +0 -5
  653. package/docs/api/variables/intrinsicElementKey.md +0 -5
  654. package/docs/api/variables/printHookTag.md +0 -7
  655. package/src/print-hook.ts +0 -22
  656. package/src/render.ts +0 -1154
@@ -0,0 +1,817 @@
1
+ /**
2
+ * Direct AlloyNode tree printer.
3
+ *
4
+ * The printer walks the DOM-like AlloyNode tree directly, dispatching on
5
+ * element `localName` and node type. Work items on the command stack carry
6
+ * AlloyNode references or small synthetic frames for constructs that have no
7
+ * node counterpart, such as fill continuation state, `ifBreak` alternate
8
+ * branches, and split text segments.
9
+ *
10
+ * Correctness invariants:
11
+ *
12
+ * - `fits` is continuation-aware (passes `restCommands`).
13
+ * - `breakParent` propagation runs as a prepass over the AlloyNode
14
+ * tree, including into `lineSuffix` content and both branches of
15
+ * `ifBreak` (matching Prettier's `traverseDoc`). Hardline / hbr /
16
+ * literalline / lbr / breakParent / TextNode-with-newline all
17
+ * trigger the propagation.
18
+ * - `lineSuffix` collects deferred `{ind, mode, frame}` commands.
19
+ * - `groupModeMap` carries forward-ref semantics: in `fits`,
20
+ * unknown groupId behaves as flat; during printing, unknown
21
+ * groupId yields no branch on `if-break` / `indent-if-break`.
22
+ * - `fill` uses `mustBeFlat=true` and a separate
23
+ * `firstAndSecondContentFits` measurement; comments are skipped
24
+ * when collecting the parts list.
25
+ * - `trim` rolls back trailing spaces / tabs from the `out` buffer.
26
+ * - String width is Prettier's CJK / east-asian / emoji-aware
27
+ * `getStringWidth` (vendored in `get-string-width.ts`).
28
+ */
29
+
30
+ import {
31
+ AlloyNode,
32
+ COMMENT_NODE,
33
+ ElementNode,
34
+ FRAGMENT_NODE,
35
+ TEXT_NODE,
36
+ TextNode,
37
+ } from "./node.js";
38
+ import {
39
+ CURSOR_PLACEHOLDER,
40
+ getStringWidth,
41
+ Indent,
42
+ joinOut,
43
+ makeAlign,
44
+ makeIndent,
45
+ Mode,
46
+ MODE_BREAK,
47
+ MODE_FLAT,
48
+ PrintNodeOptions,
49
+ rootIndent,
50
+ textHasNewline,
51
+ textWidth,
52
+ trimOut,
53
+ } from "./printer-support.js";
54
+
55
+ // #region Frame types
56
+
57
+ const SYNTH = Symbol("alloy:synthetic-frame");
58
+
59
+ type SynthFrame = {
60
+ [k in typeof SYNTH]: true;
61
+ } &
62
+ // Fill remaining state: re-print `node` but starting at `offset`.
63
+ (| { kind: "fill"; node: ElementNode; offset: number }
64
+ // Synthesize an inline list of nodes (used for fill's
65
+ // [content, whitespace, secondContent] measurement and for
66
+ // text-node newline expansion). Items are popped right-to-left.
67
+ | { kind: "list"; items: Frame[] }
68
+ // Synthesize a `line` with the given attributes (used for
69
+ // `line-suffix-boundary` flushing a hardline-without-break).
70
+ | { kind: "line"; hard?: boolean; soft?: boolean; literal?: boolean }
71
+ // Synthesize an `indent` wrapping the given AlloyNode contents
72
+ // (used by `indent-if-break` negate path).
73
+ | { kind: "indent"; node: ElementNode }
74
+ );
75
+
76
+ type Frame = AlloyNode | string | SynthFrame;
77
+
78
+ interface Cmd {
79
+ ind: Indent;
80
+ mode: Mode;
81
+ frame: Frame;
82
+ }
83
+
84
+ // #endregion
85
+
86
+ // #region Group broken predicate
87
+
88
+ /**
89
+ * O(1) replacement for Prettier's `propagateBreaks` prepass — the
90
+ * `_breakCount` field on `ElementNode` is maintained eagerly during
91
+ * insertion (see `propagateBreakDelta` in `node.ts`), so deciding
92
+ * whether a `group` is broken is just a field read plus the
93
+ * `shouldBreak` data flag.
94
+ */
95
+ function isGroupBroken(el: ElementNode): boolean {
96
+ if (el._breakCount > 0) return true;
97
+ const data = el.data as { shouldBreak?: boolean } | undefined;
98
+ return data?.shouldBreak === true;
99
+ }
100
+
101
+ // #endregion
102
+
103
+ // #region fits
104
+
105
+ function fits(
106
+ next: Cmd,
107
+ restCommands: Cmd[],
108
+ width: number,
109
+ hasLineSuffix: boolean,
110
+ groupModeMap: Record<symbol, Mode>,
111
+ mustBeFlat: boolean,
112
+ ): boolean {
113
+ if (width === Number.POSITIVE_INFINITY) return true;
114
+ let restIdx = restCommands.length;
115
+ const cmds: Cmd[] = [next];
116
+ const out: (string | symbol)[] = [];
117
+ const dummyInd = next.ind;
118
+ while (width >= 0) {
119
+ if (cmds.length === 0) {
120
+ if (restIdx === 0) return true;
121
+ cmds.push(restCommands[--restIdx]);
122
+ continue;
123
+ }
124
+ const cmd = cmds.pop()!;
125
+ const mode = cmd.mode;
126
+ const frame = cmd.frame;
127
+
128
+ if (typeof frame === "string") {
129
+ out.push(frame);
130
+ width -= getStringWidth(frame);
131
+ continue;
132
+ }
133
+
134
+ if (isSynth(frame)) {
135
+ switch (frame.kind) {
136
+ case "fill": {
137
+ const parts = collectChildren(frame.node);
138
+ for (let i = parts.length - 1; i >= frame.offset; i--) {
139
+ cmds.push({ ind: cmd.ind, mode, frame: parts[i] });
140
+ }
141
+ break;
142
+ }
143
+ case "list": {
144
+ for (let i = frame.items.length - 1; i >= 0; i--) {
145
+ cmds.push({ ind: cmd.ind, mode, frame: frame.items[i] });
146
+ }
147
+ break;
148
+ }
149
+ case "line": {
150
+ if (mode === MODE_BREAK || frame.hard) return true;
151
+ if (!frame.soft) {
152
+ out.push(" ");
153
+ width--;
154
+ }
155
+ break;
156
+ }
157
+ case "indent": {
158
+ // Synthesized indent wrapper — same effect on width as
159
+ // descending into the wrapped node's children.
160
+ for (
161
+ let c = frame.node.lastChild;
162
+ c !== null;
163
+ c = c.previousSibling
164
+ ) {
165
+ if (c.nodeType === COMMENT_NODE) continue;
166
+ cmds.push({ ind: cmd.ind, mode, frame: c });
167
+ }
168
+ break;
169
+ }
170
+ }
171
+ continue;
172
+ }
173
+
174
+ // AlloyNode
175
+ const node = frame as AlloyNode;
176
+ const nt = node.nodeType;
177
+ if (nt === TEXT_NODE) {
178
+ const tn = node as TextNode;
179
+ const text = tn.data;
180
+ if (text === "") continue;
181
+ if (!textHasNewline(tn)) {
182
+ out.push(text);
183
+ width -= textWidth(tn);
184
+ continue;
185
+ }
186
+ // Multi-line text: on the first newline encountered (in MODE_FLAT
187
+ // we treat it as forcing break — fits returns true if mode is
188
+ // BREAK, since reaching a hard line means content fits in the
189
+ // remaining buffer).
190
+ // Push reversed segments.
191
+ const items = expandMultilineText(text);
192
+ for (let i = items.length - 1; i >= 0; i--) {
193
+ cmds.push({ ind: cmd.ind, mode, frame: items[i] });
194
+ }
195
+ continue;
196
+ }
197
+ if (nt === COMMENT_NODE) continue;
198
+ if (nt === FRAGMENT_NODE) {
199
+ for (let c = node.lastChild; c !== null; c = c.previousSibling) {
200
+ if (c.nodeType === COMMENT_NODE) continue;
201
+ cmds.push({ ind: cmd.ind, mode, frame: c });
202
+ }
203
+ continue;
204
+ }
205
+ // ELEMENT_NODE
206
+ const el = node as ElementNode;
207
+ const ln = el.localName;
208
+ switch (ln) {
209
+ case "line":
210
+ case "br":
211
+ if (mode === MODE_BREAK) return true;
212
+ out.push(" ");
213
+ width--;
214
+ break;
215
+ case "softline":
216
+ case "sbr":
217
+ if (mode === MODE_BREAK) return true;
218
+ break;
219
+ case "hardline":
220
+ case "hbr":
221
+ case "literalline":
222
+ case "lbr":
223
+ return true;
224
+ case "breakParent":
225
+ break;
226
+ case "trim":
227
+ width += trimOut(out);
228
+ break;
229
+ case "lineSuffix":
230
+ hasLineSuffix = true;
231
+ break;
232
+ case "lineSuffixBoundary":
233
+ if (hasLineSuffix) return false;
234
+ break;
235
+ case "cursor":
236
+ // Width-neutral marker.
237
+ break;
238
+ case "group": {
239
+ const broken = isGroupBroken(el);
240
+ if (mustBeFlat && broken) return false;
241
+ const groupMode: Mode = broken ? MODE_BREAK : mode;
242
+ // alloy doesn't use expandedStates — descend into children.
243
+ for (let c = el.lastChild; c !== null; c = c.previousSibling) {
244
+ if (c.nodeType === COMMENT_NODE) continue;
245
+ cmds.push({ ind: cmd.ind, mode: groupMode, frame: c });
246
+ }
247
+ break;
248
+ }
249
+ case "ifBreak": {
250
+ const data = el.data as
251
+ | { flatNode?: ElementNode; flatText?: string; groupId?: symbol }
252
+ | undefined;
253
+ const groupMode: Mode =
254
+ data?.groupId ? groupModeMap[data.groupId] || MODE_FLAT : mode;
255
+ if (groupMode === MODE_BREAK) {
256
+ for (let c = el.lastChild; c !== null; c = c.previousSibling) {
257
+ if (c.nodeType === COMMENT_NODE) continue;
258
+ cmds.push({ ind: cmd.ind, mode, frame: c });
259
+ }
260
+ } else {
261
+ if (data?.flatNode !== undefined) {
262
+ cmds.push({ ind: cmd.ind, mode, frame: data.flatNode });
263
+ } else if (data?.flatText !== undefined && data.flatText !== "") {
264
+ cmds.push({ ind: cmd.ind, mode, frame: data.flatText });
265
+ }
266
+ }
267
+ break;
268
+ }
269
+ case "indentIfBreak": {
270
+ const data = el.data as
271
+ | { groupId?: symbol; negate?: boolean }
272
+ | undefined;
273
+ const groupMode: Mode =
274
+ data?.groupId ? groupModeMap[data.groupId] || MODE_FLAT : mode;
275
+ // For width measurement, indent vs no-indent doesn't matter (no
276
+ // newlines emitted in the candidate group while measuring flat,
277
+ // and on hardline we return true). Just descend.
278
+ for (let c = el.lastChild; c !== null; c = c.previousSibling) {
279
+ if (c.nodeType === COMMENT_NODE) continue;
280
+ cmds.push({ ind: cmd.ind, mode, frame: c });
281
+ }
282
+ // Suppress unused warning in case the linter complains.
283
+ void groupMode;
284
+ break;
285
+ }
286
+ case "fill":
287
+ case "indent":
288
+ case "align":
289
+ case "dedent":
290
+ case "dedentToRoot":
291
+ case "markAsRoot":
292
+ case "label":
293
+ default:
294
+ // Transparent for fits: descend into children.
295
+ for (let c = el.lastChild; c !== null; c = c.previousSibling) {
296
+ if (c.nodeType === COMMENT_NODE) continue;
297
+ cmds.push({ ind: cmd.ind, mode, frame: c });
298
+ }
299
+ break;
300
+ }
301
+ }
302
+ void dummyInd;
303
+ return false;
304
+ }
305
+
306
+ // #endregion
307
+
308
+ // #region Helpers
309
+
310
+ function isSynth(f: Frame): f is SynthFrame {
311
+ return typeof f === "object" && f !== null && (f as any)[SYNTH] === true;
312
+ }
313
+
314
+ /**
315
+ * Collect the non-comment children of an element into an array
316
+ * (in order). Used for `fill` part indexing — `fill` requires random
317
+ * access on the parts list (offset, length), which a linked list
318
+ * doesn't provide cheaply. Cached per ElementNode to amortize across
319
+ * the multiple fits-measurements `fill` performs.
320
+ */
321
+ const fillPartsCache = new WeakMap<ElementNode, AlloyNode[]>();
322
+
323
+ function collectChildren(el: ElementNode): AlloyNode[] {
324
+ const cached = fillPartsCache.get(el);
325
+ if (cached !== undefined) return cached;
326
+ const out: AlloyNode[] = [];
327
+ for (let c = el.firstChild; c !== null; c = c.nextSibling) {
328
+ if (c.nodeType === COMMENT_NODE) continue;
329
+ out.push(c);
330
+ }
331
+ fillPartsCache.set(el, out);
332
+ return out;
333
+ }
334
+
335
+ /**
336
+ * Expand a TextNode's `data` containing newlines into a flat list of
337
+ * frames matching `convertText` in `to-doc.ts` — segment strings
338
+ * separated by synthetic hardlines. Empty segments are dropped, just
339
+ * like Prettier's `[hardline, "x", hardline, "y"]` (no empty strings).
340
+ */
341
+ function expandMultilineText(text: string): Frame[] {
342
+ const parts = text.split(/\r?\n/);
343
+ const out: Frame[] = [];
344
+ const synthHardline: SynthFrame = { [SYNTH]: true, kind: "line", hard: true };
345
+ for (let i = 0; i < parts.length; i++) {
346
+ if (i > 0) out.push(synthHardline);
347
+ if (parts[i] !== "") out.push(parts[i]);
348
+ }
349
+ return out;
350
+ }
351
+
352
+ // #endregion
353
+
354
+ // #region Main entry point
355
+
356
+ export interface PrintNodeResult {
357
+ formatted: string;
358
+ }
359
+
360
+ export function printNodeToString(
361
+ root: AlloyNode,
362
+ options: PrintNodeOptions,
363
+ ): PrintNodeResult {
364
+ // Group "broken" status is maintained eagerly during render via
365
+ // `propagateBreakDelta` in node.ts (which keeps `el._breakCount`
366
+ // accurate). The `isGroupBroken` helper below reads it in O(1) so we
367
+ // no longer need the per-print `propagateBreaks` walk over the tree.
368
+
369
+ const groupModeMap: Record<symbol, Mode> = {};
370
+ const width = options.printWidth;
371
+ const newLine = "\n";
372
+ let pos = 0;
373
+ const cmds: Cmd[] = [{ ind: rootIndent(), mode: MODE_BREAK, frame: root }];
374
+ const out: (string | symbol)[] = [];
375
+ let shouldRemeasure = false;
376
+ const lineSuffix: Cmd[] = [];
377
+
378
+ while (cmds.length > 0) {
379
+ const cmd = cmds.pop()!;
380
+ const ind = cmd.ind;
381
+ const mode = cmd.mode;
382
+ const frame = cmd.frame;
383
+
384
+ // ---- string ----
385
+ if (typeof frame === "string") {
386
+ out.push(frame);
387
+ if (cmds.length > 0) pos += getStringWidth(frame);
388
+ continue;
389
+ }
390
+
391
+ // ---- synthetic ----
392
+ if (isSynth(frame)) {
393
+ switch (frame.kind) {
394
+ case "fill":
395
+ handleFill(frame.node, frame.offset, ind, mode);
396
+ break;
397
+ case "list": {
398
+ for (let i = frame.items.length - 1; i >= 0; i--) {
399
+ cmds.push({ ind, mode, frame: frame.items[i] });
400
+ }
401
+ break;
402
+ }
403
+ case "line":
404
+ handleLine(!!frame.hard, !!frame.soft, !!frame.literal, ind, mode);
405
+ break;
406
+ case "indent":
407
+ cmds.push({
408
+ ind: makeIndent(ind, options),
409
+ mode,
410
+ frame: {
411
+ [SYNTH]: true,
412
+ kind: "list",
413
+ items: collectChildren(frame.node),
414
+ },
415
+ });
416
+ break;
417
+ }
418
+ // After-pop line-suffix flush check.
419
+ if (cmds.length === 0 && lineSuffix.length > 0) {
420
+ cmds.push(...lineSuffix.reverse());
421
+ lineSuffix.length = 0;
422
+ }
423
+ continue;
424
+ }
425
+
426
+ // ---- AlloyNode ----
427
+ const node = frame as AlloyNode;
428
+ const nt = node.nodeType;
429
+
430
+ if (nt === TEXT_NODE) {
431
+ const tn = node as TextNode;
432
+ const text = tn.data;
433
+ if (text === "") {
434
+ // empty text: nothing
435
+ } else if (!textHasNewline(tn)) {
436
+ out.push(text);
437
+ if (cmds.length > 0) pos += textWidth(tn);
438
+ } else {
439
+ // multiline: expand into segments + synthetic hardlines.
440
+ const items = expandMultilineText(text);
441
+ for (let i = items.length - 1; i >= 0; i--) {
442
+ cmds.push({ ind, mode, frame: items[i] });
443
+ }
444
+ }
445
+ } else if (nt === COMMENT_NODE) {
446
+ // skip
447
+ } else if (nt === FRAGMENT_NODE) {
448
+ for (let c = node.lastChild; c !== null; c = c.previousSibling) {
449
+ if (c.nodeType === COMMENT_NODE) continue;
450
+ cmds.push({ ind, mode, frame: c });
451
+ }
452
+ } else {
453
+ // ELEMENT_NODE
454
+ const el = node as ElementNode;
455
+ handleElement(el, ind, mode);
456
+ }
457
+
458
+ if (cmds.length === 0 && lineSuffix.length > 0) {
459
+ cmds.push(...lineSuffix.reverse());
460
+ lineSuffix.length = 0;
461
+ }
462
+ }
463
+
464
+ return { formatted: joinOut(out) };
465
+
466
+ // #region Closures
467
+
468
+ function pushChildrenReversed(
469
+ el: ElementNode,
470
+ ind: Indent,
471
+ mode: Mode,
472
+ ): void {
473
+ for (let c = el.lastChild; c !== null; c = c.previousSibling) {
474
+ if (c.nodeType === COMMENT_NODE) continue;
475
+ cmds.push({ ind, mode, frame: c });
476
+ }
477
+ }
478
+
479
+ function handleElement(el: ElementNode, ind: Indent, mode: Mode): void {
480
+ const ln = el.localName;
481
+ switch (ln) {
482
+ case "line":
483
+ case "br":
484
+ handleLine(false, false, false, ind, mode);
485
+ return;
486
+ case "softline":
487
+ case "sbr":
488
+ handleLine(false, true, false, ind, mode);
489
+ return;
490
+ case "hardline":
491
+ case "hbr":
492
+ handleLine(true, false, false, ind, mode);
493
+ return;
494
+ case "literalline":
495
+ case "lbr":
496
+ handleLine(true, false, true, ind, mode);
497
+ return;
498
+ case "breakParent":
499
+ return;
500
+ case "trim":
501
+ pos -= trimOut(out);
502
+ return;
503
+ case "cursor":
504
+ out.push(CURSOR_PLACEHOLDER);
505
+ return;
506
+ case "indent":
507
+ pushChildrenReversed(el, makeIndent(ind, options), mode);
508
+ return;
509
+ case "dedent":
510
+ pushChildrenReversed(el, makeAlign(ind, -1, options), mode);
511
+ return;
512
+ case "dedentToRoot":
513
+ pushChildrenReversed(
514
+ el,
515
+ makeAlign(ind, Number.NEGATIVE_INFINITY, options),
516
+ mode,
517
+ );
518
+ return;
519
+ case "markAsRoot":
520
+ pushChildrenReversed(
521
+ el,
522
+ makeAlign(ind, { type: "root" }, options),
523
+ mode,
524
+ );
525
+ return;
526
+ case "align": {
527
+ const data = el.data as
528
+ | {
529
+ count?: number | string;
530
+ width?: number | string;
531
+ string?: string;
532
+ }
533
+ | undefined;
534
+ const widthOrString = data?.count ?? data?.width ?? data?.string ?? 0;
535
+ pushChildrenReversed(el, makeAlign(ind, widthOrString, options), mode);
536
+ return;
537
+ }
538
+ case "label":
539
+ pushChildrenReversed(el, ind, mode);
540
+ return;
541
+ case "lineSuffix": {
542
+ // Defer contents as a single list frame; capture current ind and mode.
543
+ lineSuffix.push({
544
+ ind,
545
+ mode,
546
+ frame: {
547
+ [SYNTH]: true,
548
+ kind: "list",
549
+ items: collectChildren(el),
550
+ },
551
+ });
552
+ return;
553
+ }
554
+ case "lineSuffixBoundary":
555
+ if (lineSuffix.length > 0) {
556
+ // Synthesize hardlineWithoutBreakParent.
557
+ cmds.push({
558
+ ind,
559
+ mode,
560
+ frame: { [SYNTH]: true, kind: "line", hard: true },
561
+ });
562
+ }
563
+ return;
564
+ case "group":
565
+ handleGroup(el, ind, mode);
566
+ return;
567
+ case "ifBreak":
568
+ handleIfBreak(el, ind, mode);
569
+ return;
570
+ case "indentIfBreak":
571
+ handleIndentIfBreak(el, ind, mode);
572
+ return;
573
+ case "fill":
574
+ handleFillElement(el, ind, mode);
575
+ return;
576
+ default:
577
+ // Unknown: transparent container.
578
+ pushChildrenReversed(el, ind, mode);
579
+ return;
580
+ }
581
+ }
582
+
583
+ function handleGroup(el: ElementNode, ind: Indent, mode: Mode): void {
584
+ const data = el.data as { shouldBreak?: boolean; id?: symbol } | undefined;
585
+ const broken = isGroupBroken(el);
586
+ const groupId = data?.id;
587
+
588
+ switch (mode) {
589
+ case MODE_FLAT: {
590
+ if (!shouldRemeasure) {
591
+ // Stay flat (or step into break if shouldBreak).
592
+ const m: Mode = broken ? MODE_BREAK : MODE_FLAT;
593
+ pushChildrenReversedAtMode(el, ind, m);
594
+ break;
595
+ }
596
+ }
597
+ // fallthrough
598
+ // eslint-disable-next-line no-fallthrough
599
+ case MODE_BREAK: {
600
+ shouldRemeasure = false;
601
+ // Build a "candidate" cmd that pushes the group's children flat.
602
+ // We measure via fits using a synthetic single frame: the
603
+ // element itself with mode=FLAT. But fits descends into children
604
+ // since group dispatches to them. To match prettier semantics
605
+ // exactly (fits treats group as: if mustBeFlat&&broken→false,
606
+ // else descend into contents at groupMode), passing the group
607
+ // itself works.
608
+ const next: Cmd = { ind, mode: MODE_FLAT, frame: el };
609
+ const rem = width - pos;
610
+ const hasLS = lineSuffix.length > 0;
611
+ if (!broken && fits(next, cmds, rem, hasLS, groupModeMap, false)) {
612
+ // Push children flat.
613
+ pushChildrenReversedAtMode(el, ind, MODE_FLAT);
614
+ } else {
615
+ // Push children broken.
616
+ pushChildrenReversedAtMode(el, ind, MODE_BREAK);
617
+ }
618
+ break;
619
+ }
620
+ }
621
+ if (groupId) {
622
+ groupModeMap[groupId] =
623
+ cmds.length > 0 ? cmds[cmds.length - 1].mode : mode;
624
+ }
625
+ }
626
+
627
+ function pushChildrenReversedAtMode(
628
+ el: ElementNode,
629
+ ind: Indent,
630
+ mode: Mode,
631
+ ): void {
632
+ for (let c = el.lastChild; c !== null; c = c.previousSibling) {
633
+ if (c.nodeType === COMMENT_NODE) continue;
634
+ cmds.push({ ind, mode, frame: c });
635
+ }
636
+ }
637
+
638
+ function handleIfBreak(el: ElementNode, ind: Indent, mode: Mode): void {
639
+ const data = el.data as
640
+ | { flatNode?: ElementNode; flatText?: string; groupId?: symbol }
641
+ | undefined;
642
+ const groupMode: Mode | undefined =
643
+ data?.groupId ? groupModeMap[data.groupId] : mode;
644
+ if (groupMode === MODE_BREAK) {
645
+ // Push children (the breakContents).
646
+ pushChildrenReversed(el, ind, mode);
647
+ } else if (groupMode === MODE_FLAT) {
648
+ if (data?.flatNode !== undefined) {
649
+ cmds.push({ ind, mode, frame: data.flatNode });
650
+ } else if (data?.flatText !== undefined && data.flatText !== "") {
651
+ cmds.push({ ind, mode, frame: data.flatText });
652
+ }
653
+ }
654
+ // groupMode === undefined: emit nothing (matches prettier).
655
+ }
656
+
657
+ function handleIndentIfBreak(el: ElementNode, ind: Indent, mode: Mode): void {
658
+ const data = el.data as { groupId?: symbol; negate?: boolean } | undefined;
659
+ const groupMode: Mode | undefined =
660
+ data?.groupId ? groupModeMap[data.groupId] : mode;
661
+ const negate = !!data?.negate;
662
+ if (groupMode === MODE_BREAK) {
663
+ if (negate) {
664
+ // breakContents = original children (no indent).
665
+ pushChildrenReversed(el, ind, mode);
666
+ } else {
667
+ // breakContents = indent(children).
668
+ pushChildrenReversed(el, makeIndent(ind, options), mode);
669
+ }
670
+ } else if (groupMode === MODE_FLAT) {
671
+ if (negate) {
672
+ // flatContents = indent(children).
673
+ pushChildrenReversed(el, makeIndent(ind, options), mode);
674
+ } else {
675
+ // flatContents = original children.
676
+ pushChildrenReversed(el, ind, mode);
677
+ }
678
+ }
679
+ }
680
+
681
+ function handleFillElement(el: ElementNode, ind: Indent, mode: Mode): void {
682
+ handleFill(el, 0, ind, mode);
683
+ }
684
+
685
+ function handleFill(
686
+ el: ElementNode,
687
+ offset: number,
688
+ indArg?: Indent,
689
+ modeArg?: Mode,
690
+ ): void {
691
+ const ind = indArg ?? rootIndent();
692
+ const mode = modeArg ?? MODE_BREAK;
693
+ const parts = collectChildren(el);
694
+ const rem = width - pos;
695
+ const length = parts.length - offset;
696
+ if (length === 0) return;
697
+ const content = parts[offset + 0];
698
+ const whitespace = parts[offset + 1];
699
+ const contentFlatCmd: Cmd = { ind, mode: MODE_FLAT, frame: content };
700
+ const contentBreakCmd: Cmd = { ind, mode: MODE_BREAK, frame: content };
701
+ const contentFits = fits(
702
+ contentFlatCmd,
703
+ [],
704
+ rem,
705
+ lineSuffix.length > 0,
706
+ groupModeMap,
707
+ true,
708
+ );
709
+ if (length === 1) {
710
+ if (contentFits) cmds.push(contentFlatCmd);
711
+ else cmds.push(contentBreakCmd);
712
+ return;
713
+ }
714
+ const whitespaceFlatCmd: Cmd = {
715
+ ind,
716
+ mode: MODE_FLAT,
717
+ frame: whitespace,
718
+ };
719
+ const whitespaceBreakCmd: Cmd = {
720
+ ind,
721
+ mode: MODE_BREAK,
722
+ frame: whitespace,
723
+ };
724
+ if (length === 2) {
725
+ if (contentFits) cmds.push(whitespaceFlatCmd, contentFlatCmd);
726
+ else cmds.push(whitespaceBreakCmd, contentBreakCmd);
727
+ return;
728
+ }
729
+ const secondContent = parts[offset + 2];
730
+ const remainingCmd: Cmd = {
731
+ ind,
732
+ mode,
733
+ frame: { [SYNTH]: true, kind: "fill", node: el, offset: offset + 2 },
734
+ };
735
+ const firstAndSecondListFrame: SynthFrame = {
736
+ [SYNTH]: true,
737
+ kind: "list",
738
+ items: [content, whitespace, secondContent],
739
+ };
740
+ const firstAndSecondContentFits = fits(
741
+ { ind, mode: MODE_FLAT, frame: firstAndSecondListFrame },
742
+ [],
743
+ rem,
744
+ lineSuffix.length > 0,
745
+ groupModeMap,
746
+ true,
747
+ );
748
+ if (firstAndSecondContentFits) {
749
+ cmds.push(remainingCmd, whitespaceFlatCmd, contentFlatCmd);
750
+ } else if (contentFits) {
751
+ cmds.push(remainingCmd, whitespaceBreakCmd, contentFlatCmd);
752
+ } else {
753
+ cmds.push(remainingCmd, whitespaceBreakCmd, contentBreakCmd);
754
+ }
755
+ }
756
+
757
+ function handleLine(
758
+ hard: boolean,
759
+ soft: boolean,
760
+ literal: boolean,
761
+ ind: Indent,
762
+ mode: Mode,
763
+ ): void {
764
+ switch (mode) {
765
+ case MODE_FLAT:
766
+ if (!hard) {
767
+ if (!soft) {
768
+ out.push(" ");
769
+ pos += 1;
770
+ }
771
+ break;
772
+ } else {
773
+ shouldRemeasure = true;
774
+ }
775
+ // fallthrough
776
+ // eslint-disable-next-line no-fallthrough
777
+ case MODE_BREAK:
778
+ if (lineSuffix.length > 0) {
779
+ // Re-push the line as a synthetic frame and then the suffix.
780
+ cmds.push({
781
+ ind,
782
+ mode,
783
+ frame: {
784
+ [SYNTH]: true,
785
+ kind: "line",
786
+ hard,
787
+ soft,
788
+ literal,
789
+ },
790
+ });
791
+ for (let i = lineSuffix.length - 1; i >= 0; i--) {
792
+ cmds.push(lineSuffix[i]);
793
+ }
794
+ lineSuffix.length = 0;
795
+ break;
796
+ }
797
+ if (literal) {
798
+ if (ind.root) {
799
+ out.push(newLine, ind.root.value);
800
+ pos = ind.root.length;
801
+ } else {
802
+ out.push(newLine);
803
+ pos = 0;
804
+ }
805
+ } else {
806
+ pos -= trimOut(out);
807
+ out.push(newLine + ind.value);
808
+ pos = ind.length;
809
+ }
810
+ break;
811
+ }
812
+ }
813
+
814
+ // #endregion
815
+ }
816
+
817
+ // #endregion