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

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 (506) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/dev/src/components/AccessExpression.test.js +1 -1
  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 +1 -1
  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 +1 -1
  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/components/block.test.js +1 -1
  88. package/dist/dev/test/components/block.test.js.map +1 -1
  89. package/dist/dev/test/components/copy-file.test.js +7 -7
  90. package/dist/dev/test/components/copy-file.test.js.map +1 -1
  91. package/dist/dev/test/components/update-file.test.js +1 -1
  92. package/dist/dev/test/components/update-file.test.js.map +1 -1
  93. package/dist/dev/test/components/wrap.test.js +1 -1
  94. package/dist/dev/test/components/wrap.test.js.map +1 -1
  95. package/dist/dev/test/control-flow/match.test.js +1 -1
  96. package/dist/dev/test/control-flow/match.test.js.map +1 -1
  97. package/dist/dev/test/control-flow/show.test.js +1 -1
  98. package/dist/dev/test/control-flow/show.test.js.map +1 -1
  99. package/dist/dev/test/lazy-isempty.test.js +6 -6
  100. package/dist/dev/test/lazy-isempty.test.js.map +1 -1
  101. package/dist/dev/test/node.test.js +80 -0
  102. package/dist/dev/test/node.test.js.map +1 -0
  103. package/dist/dev/test/output-e2e.test.js +194 -0
  104. package/dist/dev/test/output-e2e.test.js.map +1 -0
  105. package/dist/dev/test/reactivity/circular-reactives.test.js +1 -1
  106. package/dist/dev/test/reactivity/circular-reactives.test.js.map +1 -1
  107. package/dist/dev/test/reactivity/cleanup.test.js +1 -1
  108. package/dist/dev/test/reactivity/cleanup.test.js.map +1 -1
  109. package/dist/dev/test/rendering/memoization.test.js +6 -1
  110. package/dist/dev/test/rendering/memoization.test.js.map +1 -1
  111. package/dist/dev/test/rendering/render-output-diagnostics.test.js +102 -0
  112. package/dist/dev/test/rendering/render-output-diagnostics.test.js.map +1 -0
  113. package/dist/dev/test/runtime.test.js +385 -0
  114. package/dist/dev/test/runtime.test.js.map +1 -0
  115. package/dist/dev/test/tree-test-utils.js +16 -0
  116. package/dist/dev/test/tree-test-utils.js.map +1 -0
  117. package/dist/dev/test/utils.test.js +1 -1
  118. package/dist/dev/test/utils.test.js.map +1 -1
  119. package/dist/dev/testing/devtools-utils.js +1 -1
  120. package/dist/dev/testing/devtools-utils.js.map +1 -1
  121. package/dist/dev/testing/extend-expect.js +7 -33
  122. package/dist/dev/testing/extend-expect.js.map +1 -1
  123. package/dist/dev/testing/render.js +7 -17
  124. package/dist/dev/testing/render.js.map +1 -1
  125. package/dist/devtools/index.html +17 -17
  126. package/dist/src/components/AccessExpression.test.js +1 -1
  127. package/dist/src/components/AccessExpression.test.js.map +1 -1
  128. package/dist/src/components/Output.d.ts +1 -1
  129. package/dist/src/components/Output.d.ts.map +1 -1
  130. package/dist/src/components/Output.js +2 -1
  131. package/dist/src/components/Output.js.map +1 -1
  132. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  133. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  134. package/dist/src/components/SourceFile.d.ts +1 -1
  135. package/dist/src/components/SourceFile.d.ts.map +1 -1
  136. package/dist/src/components/SourceFile.js.map +1 -1
  137. package/dist/src/content-slot.test.js +1 -1
  138. package/dist/src/content-slot.test.js.map +1 -1
  139. package/dist/src/context/format-options.d.ts +1 -1
  140. package/dist/src/context/format-options.d.ts.map +1 -1
  141. package/dist/src/context.d.ts +9 -1
  142. package/dist/src/context.d.ts.map +1 -1
  143. package/dist/src/context.js +30 -3
  144. package/dist/src/context.js.map +1 -1
  145. package/dist/src/debug/diagnostics.test.js +1 -1
  146. package/dist/src/debug/diagnostics.test.js.map +1 -1
  147. package/dist/src/debug/effects.test.js +1 -1
  148. package/dist/src/debug/effects.test.js.map +1 -1
  149. package/dist/src/debug/file-streaming.d.ts +22 -0
  150. package/dist/src/debug/file-streaming.d.ts.map +1 -0
  151. package/dist/src/debug/file-streaming.js +103 -0
  152. package/dist/src/debug/file-streaming.js.map +1 -0
  153. package/dist/src/debug/files.test.js +4 -5
  154. package/dist/src/debug/files.test.js.map +1 -1
  155. package/dist/src/debug/index.d.ts +5 -7
  156. package/dist/src/debug/index.d.ts.map +1 -1
  157. package/dist/src/debug/index.js +4 -6
  158. package/dist/src/debug/index.js.map +1 -1
  159. package/dist/src/debug/message-format.test.js +16 -18
  160. package/dist/src/debug/message-format.test.js.map +1 -1
  161. package/dist/src/debug/render-tree-orphans.test.js +8 -18
  162. package/dist/src/debug/render-tree-orphans.test.js.map +1 -1
  163. package/dist/src/debug/render.d.ts +71 -21
  164. package/dist/src/debug/render.d.ts.map +1 -1
  165. package/dist/src/debug/render.js +529 -352
  166. package/dist/src/debug/render.js.map +1 -1
  167. package/dist/src/debug/render.test.js +137 -74
  168. package/dist/src/debug/render.test.js.map +1 -1
  169. package/dist/src/debug/trace-writer.d.ts +6 -1
  170. package/dist/src/debug/trace-writer.d.ts.map +1 -1
  171. package/dist/src/debug/trace-writer.js +127 -15
  172. package/dist/src/debug/trace-writer.js.map +1 -1
  173. package/dist/src/debug/trace.d.ts +0 -36
  174. package/dist/src/debug/trace.d.ts.map +1 -1
  175. package/dist/src/debug/trace.js +0 -36
  176. package/dist/src/debug/trace.js.map +1 -1
  177. package/dist/src/devtools/devtools-protocol.d.ts +34 -1
  178. package/dist/src/devtools/devtools-protocol.d.ts.map +1 -1
  179. package/dist/src/devtools/devtools-server.d.ts.map +1 -1
  180. package/dist/src/devtools/devtools-server.js +55 -32
  181. package/dist/src/devtools/devtools-server.js.map +1 -1
  182. package/dist/src/devtools-entry.browser.d.ts +1 -1
  183. package/dist/src/devtools-entry.browser.d.ts.map +1 -1
  184. package/dist/src/devtools-entry.browser.js.map +1 -1
  185. package/dist/src/devtools-entry.d.ts +1 -1
  186. package/dist/src/devtools-entry.d.ts.map +1 -1
  187. package/dist/src/devtools-entry.js.map +1 -1
  188. package/dist/src/diagnostics.d.ts +4 -0
  189. package/dist/src/diagnostics.d.ts.map +1 -1
  190. package/dist/src/diagnostics.js +19 -1
  191. package/dist/src/diagnostics.js.map +1 -1
  192. package/dist/src/index.d.ts +5 -2
  193. package/dist/src/index.d.ts.map +1 -1
  194. package/dist/src/index.js +5 -2
  195. package/dist/src/index.js.map +1 -1
  196. package/dist/src/jsx-runtime.d.ts +13 -4
  197. package/dist/src/jsx-runtime.d.ts.map +1 -1
  198. package/dist/src/jsx-runtime.js +14 -8
  199. package/dist/src/jsx-runtime.js.map +1 -1
  200. package/dist/src/output-types.d.ts +40 -0
  201. package/dist/src/output-types.d.ts.map +1 -0
  202. package/dist/src/output-types.js +2 -0
  203. package/dist/src/output-types.js.map +1 -0
  204. package/dist/src/reactivity.d.ts +49 -18
  205. package/dist/src/reactivity.d.ts.map +1 -1
  206. package/dist/src/reactivity.js +155 -13
  207. package/dist/src/reactivity.js.map +1 -1
  208. package/dist/src/render/get-string-width.d.ts +19 -0
  209. package/dist/src/render/get-string-width.d.ts.map +1 -0
  210. package/dist/src/render/get-string-width.js +61 -0
  211. package/dist/src/render/get-string-width.js.map +1 -0
  212. package/dist/src/render/index.d.ts +2 -0
  213. package/dist/src/render/index.d.ts.map +1 -0
  214. package/dist/src/render/index.js +2 -0
  215. package/dist/src/render/index.js.map +1 -0
  216. package/dist/src/render/node-context.d.ts +5 -0
  217. package/dist/src/render/node-context.d.ts.map +1 -0
  218. package/dist/src/render/node-context.js +7 -0
  219. package/dist/src/render/node-context.js.map +1 -0
  220. package/dist/src/render/node.d.ts +146 -0
  221. package/dist/src/render/node.d.ts.map +1 -0
  222. package/dist/src/render/node.js +386 -0
  223. package/dist/src/render/node.js.map +1 -0
  224. package/dist/src/render/printer-support.d.ts +50 -0
  225. package/dist/src/render/printer-support.d.ts.map +1 -0
  226. package/dist/src/render/printer-support.js +180 -0
  227. package/dist/src/render/printer-support.js.map +1 -0
  228. package/dist/src/render/printer.d.ts +35 -0
  229. package/dist/src/render/printer.d.ts.map +1 -0
  230. package/dist/src/render/printer.js +797 -0
  231. package/dist/src/render/printer.js.map +1 -0
  232. package/dist/src/render-error.d.ts +4 -0
  233. package/dist/src/render-error.d.ts.map +1 -0
  234. package/dist/src/render-error.js +79 -0
  235. package/dist/src/render-error.js.map +1 -0
  236. package/dist/src/render-output.d.ts +42 -0
  237. package/dist/src/render-output.d.ts.map +1 -0
  238. package/dist/src/render-output.js +209 -0
  239. package/dist/src/render-output.js.map +1 -0
  240. package/dist/src/runtime/component.d.ts +2 -2
  241. package/dist/src/runtime/component.d.ts.map +1 -1
  242. package/dist/src/runtime/create-intrinsic.d.ts +28 -0
  243. package/dist/src/runtime/create-intrinsic.d.ts.map +1 -0
  244. package/dist/src/runtime/create-intrinsic.js +53 -0
  245. package/dist/src/runtime/create-intrinsic.js.map +1 -0
  246. package/dist/src/runtime/fragment.d.ts +16 -0
  247. package/dist/src/runtime/fragment.d.ts.map +1 -0
  248. package/dist/src/runtime/fragment.js +21 -0
  249. package/dist/src/runtime/fragment.js.map +1 -0
  250. package/dist/src/runtime/index.d.ts +12 -0
  251. package/dist/src/runtime/index.d.ts.map +1 -0
  252. package/dist/src/runtime/index.js +13 -0
  253. package/dist/src/runtime/index.js.map +1 -0
  254. package/dist/src/runtime/insert.d.ts +29 -0
  255. package/dist/src/runtime/insert.d.ts.map +1 -0
  256. package/dist/src/runtime/insert.js +453 -0
  257. package/dist/src/runtime/insert.js.map +1 -0
  258. package/dist/src/runtime/intrinsic.d.ts +12 -29
  259. package/dist/src/runtime/intrinsic.d.ts.map +1 -1
  260. package/dist/src/runtime/intrinsic.js +1 -11
  261. package/dist/src/runtime/intrinsic.js.map +1 -1
  262. package/dist/src/scheduler.d.ts.map +1 -1
  263. package/dist/src/scheduler.js +38 -14
  264. package/dist/src/scheduler.js.map +1 -1
  265. package/dist/src/stc.d.ts.map +1 -1
  266. package/dist/src/stc.js +2 -0
  267. package/dist/src/stc.js.map +1 -1
  268. package/dist/src/sti.d.ts +7 -6
  269. package/dist/src/sti.d.ts.map +1 -1
  270. package/dist/src/sti.js +1 -1
  271. package/dist/src/sti.js.map +1 -1
  272. package/dist/src/symbols/symbol-slot.test.js +1 -1
  273. package/dist/src/symbols/symbol-slot.test.js.map +1 -1
  274. package/dist/src/test-render.d.ts +31 -0
  275. package/dist/src/test-render.d.ts.map +1 -0
  276. package/dist/src/test-render.js +78 -0
  277. package/dist/src/test-render.js.map +1 -0
  278. package/dist/src/utils.d.ts +1 -1
  279. package/dist/src/utils.d.ts.map +1 -1
  280. package/dist/src/utils.js +40 -28
  281. package/dist/src/utils.js.map +1 -1
  282. package/dist/src/write-output.d.ts +1 -1
  283. package/dist/src/write-output.d.ts.map +1 -1
  284. package/dist/test/babel-e2e.test.d.ts +13 -0
  285. package/dist/test/babel-e2e.test.d.ts.map +1 -0
  286. package/dist/test/babel-e2e.test.js +218 -0
  287. package/dist/test/babel-e2e.test.js.map +1 -0
  288. package/dist/test/components/block.test.js +1 -1
  289. package/dist/test/components/block.test.js.map +1 -1
  290. package/dist/test/components/copy-file.test.d.ts.map +1 -1
  291. package/dist/test/components/copy-file.test.js +1 -1
  292. package/dist/test/components/copy-file.test.js.map +1 -1
  293. package/dist/test/components/update-file.test.js +1 -1
  294. package/dist/test/components/update-file.test.js.map +1 -1
  295. package/dist/test/components/wrap.test.js +1 -1
  296. package/dist/test/components/wrap.test.js.map +1 -1
  297. package/dist/test/control-flow/match.test.js +1 -1
  298. package/dist/test/control-flow/match.test.js.map +1 -1
  299. package/dist/test/control-flow/show.test.js +1 -1
  300. package/dist/test/control-flow/show.test.js.map +1 -1
  301. package/dist/test/lazy-isempty.test.js +6 -6
  302. package/dist/test/lazy-isempty.test.js.map +1 -1
  303. package/dist/test/node.test.d.ts +2 -0
  304. package/dist/test/node.test.d.ts.map +1 -0
  305. package/dist/test/node.test.js +80 -0
  306. package/dist/test/node.test.js.map +1 -0
  307. package/dist/test/output-e2e.test.d.ts +13 -0
  308. package/dist/test/output-e2e.test.d.ts.map +1 -0
  309. package/dist/test/output-e2e.test.js +194 -0
  310. package/dist/test/output-e2e.test.js.map +1 -0
  311. package/dist/test/reactivity/circular-reactives.test.js +1 -1
  312. package/dist/test/reactivity/circular-reactives.test.js.map +1 -1
  313. package/dist/test/reactivity/cleanup.test.js +1 -1
  314. package/dist/test/reactivity/cleanup.test.js.map +1 -1
  315. package/dist/test/rendering/memoization.test.js +6 -1
  316. package/dist/test/rendering/memoization.test.js.map +1 -1
  317. package/dist/test/rendering/render-output-diagnostics.test.d.ts +2 -0
  318. package/dist/test/rendering/render-output-diagnostics.test.d.ts.map +1 -0
  319. package/dist/test/rendering/render-output-diagnostics.test.js +82 -0
  320. package/dist/test/rendering/render-output-diagnostics.test.js.map +1 -0
  321. package/dist/test/runtime.test.d.ts +11 -0
  322. package/dist/test/runtime.test.d.ts.map +1 -0
  323. package/dist/test/runtime.test.js +385 -0
  324. package/dist/test/runtime.test.js.map +1 -0
  325. package/dist/test/tree-test-utils.d.ts +3 -0
  326. package/dist/test/tree-test-utils.d.ts.map +1 -0
  327. package/dist/test/tree-test-utils.js +16 -0
  328. package/dist/test/tree-test-utils.js.map +1 -0
  329. package/dist/test/utils.test.js +1 -1
  330. package/dist/test/utils.test.js.map +1 -1
  331. package/dist/testing/devtools-utils.d.ts.map +1 -1
  332. package/dist/testing/devtools-utils.js +1 -1
  333. package/dist/testing/devtools-utils.js.map +1 -1
  334. package/dist/testing/extend-expect.d.ts.map +1 -1
  335. package/dist/testing/extend-expect.js +7 -33
  336. package/dist/testing/extend-expect.js.map +1 -1
  337. package/dist/testing/render.d.ts +7 -9
  338. package/dist/testing/render.d.ts.map +1 -1
  339. package/dist/testing/render.js +7 -17
  340. package/dist/testing/render.js.map +1 -1
  341. package/dist/tsconfig.tsbuildinfo +1 -1
  342. package/docs/api/components/Output.md +0 -3
  343. package/docs/api/components/SourceFile.md +0 -3
  344. package/docs/api/functions/createComment.md +18 -0
  345. package/docs/api/functions/createElement.md +19 -0
  346. package/docs/api/functions/createFragment.md +17 -0
  347. package/docs/api/functions/createTextNode.md +18 -0
  348. package/docs/api/functions/emitDiagnosticForTree.md +19 -0
  349. package/docs/api/functions/ensureIsEmpty.md +1 -1
  350. package/docs/api/functions/getContextForNode.md +18 -0
  351. package/docs/api/functions/getContextForRenderNode.md +4 -4
  352. package/docs/api/functions/getDiagnosticsForTree.md +7 -5
  353. package/docs/api/functions/getRegisteredDiagnosticsForTree.md +18 -0
  354. package/docs/api/functions/index.md +17 -12
  355. package/docs/api/functions/isCustomContext.md +4 -4
  356. package/docs/api/functions/notifyContentState.md +6 -0
  357. package/docs/api/functions/printTree.md +6 -16
  358. package/docs/api/functions/registerDiagnosticsForTree.md +19 -0
  359. package/docs/api/functions/render.md +1 -2
  360. package/docs/api/functions/renderAsync.md +1 -2
  361. package/docs/api/functions/renderTree.md +8 -5
  362. package/docs/api/functions/reportDiagnosticsForTree.md +18 -0
  363. package/docs/api/functions/runInContext.md +28 -0
  364. package/docs/api/functions/sourceFilesForTree.md +6 -16
  365. package/docs/api/index.md +3 -3
  366. package/docs/api/testing/functions/index.md +1 -1
  367. package/docs/api/testing/functions/renderToString.md +1 -1
  368. package/docs/api/types/AlloyNode.md +22 -0
  369. package/docs/api/types/Child.md +1 -1
  370. package/docs/api/types/CommentNode.md +15 -0
  371. package/docs/api/types/Context.md +13 -15
  372. package/docs/api/types/ElementNode.md +18 -0
  373. package/docs/api/types/FragmentNode.md +12 -0
  374. package/docs/api/types/Insertable.md +7 -0
  375. package/docs/api/types/NodeType.md +5 -0
  376. package/docs/api/types/OutputDirectory.md +0 -50
  377. package/docs/api/types/PrintTreeOptions.md +0 -1
  378. package/docs/api/types/RenderTreeOptions.md +7 -0
  379. package/docs/api/types/StiComponentCreator.md +4 -4
  380. package/docs/api/types/StiSignature.md +1 -1
  381. package/docs/api/types/TextNode.md +16 -0
  382. package/docs/api/types/index.md +10 -28
  383. package/docs/api/variables/COMMENT_NODE.md +5 -0
  384. package/docs/api/variables/ELEMENT_NODE.md +11 -0
  385. package/docs/api/variables/FRAGMENT_NODE.md +5 -0
  386. package/docs/api/variables/TEXT_NODE.md +5 -0
  387. package/docs/api/variables/index.md +4 -2
  388. package/docs/formatting.md +1 -1
  389. package/docs/rendering.md +4 -4
  390. package/package.json +6 -6
  391. package/src/components/AccessExpression.test.tsx +1 -1
  392. package/src/components/Output.tsx +2 -1
  393. package/src/components/SourceFile.tsx +1 -1
  394. package/src/content-slot.test.tsx +1 -1
  395. package/src/context/format-options.ts +1 -1
  396. package/src/context.ts +37 -4
  397. package/src/debug/diagnostics.test.tsx +1 -1
  398. package/src/debug/effects.test.tsx +1 -1
  399. package/src/debug/file-streaming.ts +115 -0
  400. package/src/debug/files.test.tsx +15 -11
  401. package/src/debug/index.ts +11 -11
  402. package/src/debug/message-format.test.tsx +32 -19
  403. package/src/debug/render-tree-orphans.test.tsx +10 -19
  404. package/src/debug/render.test.tsx +206 -78
  405. package/src/debug/render.ts +642 -495
  406. package/src/debug/trace-writer.ts +168 -14
  407. package/src/debug/trace.ts +0 -20
  408. package/src/devtools/devtools-protocol.ts +43 -0
  409. package/src/devtools/devtools-server.ts +57 -32
  410. package/src/devtools-entry.browser.ts +5 -0
  411. package/src/devtools-entry.ts +5 -0
  412. package/src/diagnostics.ts +31 -0
  413. package/src/index.ts +66 -2
  414. package/src/jsx-runtime.ts +16 -14
  415. package/src/output-types.ts +47 -0
  416. package/src/reactivity.ts +186 -40
  417. package/src/render/get-string-width.ts +201 -0
  418. package/src/render/index.ts +1 -0
  419. package/src/render/node-context.ts +14 -0
  420. package/src/render/node.ts +442 -0
  421. package/src/render/printer-support.ts +209 -0
  422. package/src/render/printer.ts +817 -0
  423. package/src/render-error.ts +98 -0
  424. package/src/render-output.ts +243 -0
  425. package/src/runtime/component.ts +2 -2
  426. package/src/runtime/create-intrinsic.ts +56 -0
  427. package/src/runtime/fragment.ts +22 -0
  428. package/src/runtime/index.ts +12 -0
  429. package/src/runtime/insert.ts +569 -0
  430. package/src/runtime/intrinsic.ts +14 -70
  431. package/src/scheduler.ts +40 -25
  432. package/src/stc.ts +3 -0
  433. package/src/sti.ts +17 -20
  434. package/src/symbols/symbol-slot.test.tsx +1 -1
  435. package/src/test-render.ts +103 -0
  436. package/src/utils.tsx +55 -37
  437. package/src/write-output.ts +1 -1
  438. package/temp/api-testing.json +390 -14
  439. package/temp/api.json +4320 -4144
  440. package/test/babel-e2e.test.ts +224 -0
  441. package/test/components/block.test.tsx +1 -1
  442. package/test/components/copy-file.test.tsx +2 -1
  443. package/test/components/update-file.test.tsx +1 -1
  444. package/test/components/wrap.test.tsx +1 -1
  445. package/test/control-flow/match.test.tsx +1 -1
  446. package/test/control-flow/show.test.tsx +1 -1
  447. package/test/lazy-isempty.test.tsx +6 -6
  448. package/test/node.test.ts +90 -0
  449. package/test/output-e2e.test.ts +198 -0
  450. package/test/reactivity/circular-reactives.test.tsx +1 -1
  451. package/test/reactivity/cleanup.test.tsx +1 -1
  452. package/test/rendering/memoization.test.tsx +6 -1
  453. package/test/rendering/render-output-diagnostics.test.tsx +120 -0
  454. package/test/runtime.test.ts +448 -0
  455. package/test/tree-test-utils.ts +23 -0
  456. package/test/utils.test.tsx +1 -1
  457. package/testing/devtools-utils.ts +2 -0
  458. package/testing/extend-expect.ts +8 -46
  459. package/testing/render.ts +17 -21
  460. package/dist/dev/src/print-hook.js +0 -10
  461. package/dist/dev/src/print-hook.js.map +0 -1
  462. package/dist/dev/src/render.js +0 -872
  463. package/dist/dev/src/render.js.map +0 -1
  464. package/dist/src/print-hook.d.ts +0 -14
  465. package/dist/src/print-hook.d.ts.map +0 -1
  466. package/dist/src/print-hook.js +0 -10
  467. package/dist/src/print-hook.js.map +0 -1
  468. package/dist/src/render.d.ts +0 -155
  469. package/dist/src/render.d.ts.map +0 -1
  470. package/dist/src/render.js +0 -872
  471. package/dist/src/render.js.map +0 -1
  472. package/docs/api/functions/createIntrinsic.md +0 -19
  473. package/docs/api/functions/createRenderTreeHook.md +0 -19
  474. package/docs/api/functions/getElementCache.md +0 -17
  475. package/docs/api/functions/isIntrinsicElement.md +0 -18
  476. package/docs/api/functions/isPrintHook.md +0 -18
  477. package/docs/api/types/AlignIntrinsicElement.md +0 -5
  478. package/docs/api/types/BrIntrinsicElement.md +0 -5
  479. package/docs/api/types/BreakParentIntrinsicElement.md +0 -5
  480. package/docs/api/types/DedentIntrinsicElement.md +0 -5
  481. package/docs/api/types/DedentToRootIntrinsicElement.md +0 -5
  482. package/docs/api/types/ElementCache.md +0 -5
  483. package/docs/api/types/ElementCacheKey.md +0 -5
  484. package/docs/api/types/FillIntrinsicElement.md +0 -5
  485. package/docs/api/types/GroupIntrinsicElement.md +0 -5
  486. package/docs/api/types/HardlineIntrinsicElement.md +0 -5
  487. package/docs/api/types/HbrIntrinsicElement.md +0 -5
  488. package/docs/api/types/IfBreakIntrinsicElement.md +0 -5
  489. package/docs/api/types/IndentIfBreakIntrinsicElement.md +0 -5
  490. package/docs/api/types/IndentIntrinsicElement.md +0 -5
  491. package/docs/api/types/IntrinsicElement.md +0 -5
  492. package/docs/api/types/IntrinsicElementBase.md +0 -9
  493. package/docs/api/types/LbrIntrinsicElement.md +0 -5
  494. package/docs/api/types/LineIntrinsicElement.md +0 -5
  495. package/docs/api/types/LineSuffixBoundaryIntrinsicElement.md +0 -5
  496. package/docs/api/types/LineSuffixIntrinsicElement.md +0 -5
  497. package/docs/api/types/LiterallineIntrinsicElement.md +0 -5
  498. package/docs/api/types/MarkAsRootIntrinsicElement.md +0 -5
  499. package/docs/api/types/PrintHook.md +0 -10
  500. package/docs/api/types/RenderedTextTree.md +0 -5
  501. package/docs/api/types/SbrIntrinsicElement.md +0 -5
  502. package/docs/api/types/SoftlineIntrinsicElement.md +0 -5
  503. package/docs/api/variables/intrinsicElementKey.md +0 -5
  504. package/docs/api/variables/printHookTag.md +0 -7
  505. package/src/print-hook.ts +0 -22
  506. package/src/render.ts +0 -1154
@@ -0,0 +1,224 @@
1
+ /**
2
+ * End-to-end test: compile real JSX through the Alloy babel preset with
3
+ * then execute the compiled output against the new runtime.
4
+ *
5
+ * Validates that:
6
+ * - The preset routes runtime imports to `@alloy-js/core/jsx-runtime`.
7
+ * - The compiled output (using `_$createIntrinsic` / `_$createComponent`
8
+ * / `_$memo` / `_$mergeProps`) executes correctly under the new
9
+ * runtime semantics (component thunks invoked via `runInContext`,
10
+ * intrinsics returning AlloyNodes eagerly).
11
+ */
12
+
13
+ // @ts-expect-error — @babel/core has no bundled types in this workspace
14
+ import { transformSync } from "@babel/core";
15
+ // @ts-expect-error — preset has no types
16
+ import alloyPreset from "@alloy-js/babel-preset";
17
+ // @ts-expect-error — preset-typescript has no types
18
+ import typescriptPreset from "@babel/preset-typescript";
19
+ import { describe, expect, it } from "vitest";
20
+ import { type AlloyNode } from "../src/render/index.js";
21
+ import { createElement } from "../src/render/node.js";
22
+ import { insert } from "../src/runtime/index.js";
23
+ import { flushJobs } from "../src/scheduler.js";
24
+ import { textContent } from "./tree-test-utils.js";
25
+
26
+ function compile(src: string): string {
27
+ const result = transformSync(src, {
28
+ filename: "test.tsx",
29
+ presets: [typescriptPreset, [alloyPreset]],
30
+ });
31
+ if (!result?.code) throw new Error("compile failed");
32
+ return result.code;
33
+ }
34
+
35
+ /**
36
+ * Build a function that evaluates the compiled module body with our
37
+ * jsx-runtime exports injected, and returns the named export.
38
+ */
39
+ async function evalCompiled(src: string, exportName: string): Promise<unknown> {
40
+ const code = compile(src);
41
+ // Replace the auto-imports with a destructure from a passed-in runtime.
42
+ const runtimeStub = `const __rt = arguments[0]; const __core = arguments[1];`;
43
+ // Strip all `import { ... } from "@alloy-js/core/jsx-runtime";` lines
44
+ // and replace them with destructuring from __rt.
45
+ const importRegex =
46
+ /import\s*\{\s*([^}]+)\s*\}\s*from\s*"@alloy-js\/core\/jsx-runtime";?/g;
47
+ const destructures: string[] = [];
48
+ let body = code.replace(importRegex, (_match, names: string) => {
49
+ // Convert `foo as _$foo` (import alias) → `foo: _$foo` (destructure alias).
50
+ const destructureNames = names.replace(/(\w+)\s+as\s+(\w+)/g, "$1: $2");
51
+ destructures.push(`const {${destructureNames}} = __rt;`);
52
+ return "";
53
+ });
54
+ // Bare @alloy-js/core imports (Show, Switch, Match, For, …) come from
55
+ // the second runtime argument.
56
+ const coreImportRegex =
57
+ /import\s*\{\s*([^}]+)\s*\}\s*from\s*"@alloy-js\/core";?/g;
58
+ body = body.replace(coreImportRegex, (_match, names: string) => {
59
+ const destructureNames = names.replace(/(\w+)\s+as\s+(\w+)/g, "$1: $2");
60
+ // Built-ins live in the runtime module; everything
61
+ // else comes from core. Split the names by what the runtime
62
+ // re-exports.
63
+ destructures.push(`const {${destructureNames}} = { ...__core, ...__rt };`);
64
+ return "";
65
+ });
66
+ // The compiled module uses ESM `export { App }`. Convert to a return.
67
+ body = body.replace(
68
+ /export\s*\{\s*([^}]+)\s*\}\s*;?/g,
69
+ (_, names: string) => {
70
+ const list = names.split(",").map((s) => s.trim());
71
+ return `return { ${list.join(",")} };`;
72
+ },
73
+ );
74
+ // import.meta.url isn't available; stub it.
75
+ body = body.replace(/import\.meta\.url/g, '"test://test.tsx"');
76
+
77
+ const wrapped = `${runtimeStub}\n${destructures.join("\n")}\n${body}`;
78
+ const fn = new Function(wrapped);
79
+ const runtime = await import("../src/runtime/index.js");
80
+ const core = await import("../src/index.js");
81
+ return fn(runtime, core)[exportName];
82
+ }
83
+
84
+ function renderToString(thunk: unknown): string {
85
+ const parent = createElement("group");
86
+ insert(parent, thunk);
87
+ flushJobs();
88
+ return textContent(parent);
89
+ }
90
+
91
+ function printNode(node: AlloyNode): string {
92
+ flushJobs();
93
+ return textContent(node);
94
+ }
95
+
96
+ describe("babel preset — end-to-end", () => {
97
+ it("compiles intrinsics and produces AlloyNode output", async () => {
98
+ const src = `
99
+ const App = () => <group>hello, world</group>;
100
+ export { App };
101
+ `;
102
+ const App = (await evalCompiled(src, "App")) as () => unknown;
103
+ // App is a plain function (no createComponent wrapper at the top).
104
+ const node = App() as AlloyNode;
105
+ expect(printNode(node)).toBe("hello, world");
106
+ });
107
+
108
+ it("compiles component invocations and threads props correctly", async () => {
109
+ const src = `
110
+ const Greet = (props) => <group>hello, {props.name}!</group>;
111
+ const App = () => <indent><Greet name="world" /></indent>;
112
+ export { App };
113
+ `;
114
+ const App = (await evalCompiled(src, "App")) as () => unknown;
115
+ const node = App() as AlloyNode;
116
+ expect(printNode(node)).toBe("hello, world!");
117
+ });
118
+
119
+ it("compiles fragments and arrays of children", async () => {
120
+ const src = `
121
+ const App = () => <><group>a</group>{"-"}<group>b</group></>;
122
+ export { App };
123
+ `;
124
+ const App = (await evalCompiled(src, "App")) as () => unknown;
125
+ // Top-level fragment: App() returns an array (Children) per plugin
126
+ // output. Insert into a parent and print.
127
+ expect(renderToString(App())).toBe("a-b");
128
+ });
129
+
130
+ it("compiles nested components composing through intrinsics", async () => {
131
+ const src = `
132
+ const Inner = (props) => <group>[{props.value}]</group>;
133
+ const Mid = (props) => <indent><Inner value={props.value} /></indent>;
134
+ const App = () => <group><Mid value="x" /></group>;
135
+ export { App };
136
+ `;
137
+ const App = (await evalCompiled(src, "App")) as () => unknown;
138
+ expect(printNode(App() as AlloyNode)).toBe("[x]");
139
+ });
140
+
141
+ it("Show built-in works with alloy preset", async () => {
142
+ const src = `
143
+ import { Show } from "@alloy-js/core";
144
+ const App = (props) => <group><Show when={props.cond} fallback="no">yes</Show></group>;
145
+ export { App };
146
+ `;
147
+ const App = (await evalCompiled(src, "App")) as (props: any) => unknown;
148
+ expect(printNode(App({ cond: true }) as AlloyNode)).toBe("yes");
149
+ expect(printNode(App({ cond: false }) as AlloyNode)).toBe("no");
150
+ });
151
+
152
+ it("Switch/Match built-ins work with alloy preset", async () => {
153
+ const src = `
154
+ import { Switch, Match } from "@alloy-js/core";
155
+ const App = (props) => (
156
+ <group>
157
+ <Switch>
158
+ <Match when={props.kind === "a"}>A!</Match>
159
+ <Match when={props.kind === "b"}>B!</Match>
160
+ <Match else>other</Match>
161
+ </Switch>
162
+ </group>
163
+ );
164
+ export { App };
165
+ `;
166
+ const App = (await evalCompiled(src, "App")) as (props: any) => unknown;
167
+ expect(printNode(App({ kind: "a" }) as AlloyNode)).toBe("A!");
168
+ expect(printNode(App({ kind: "b" }) as AlloyNode)).toBe("B!");
169
+ expect(printNode(App({ kind: "c" }) as AlloyNode)).toBe("other");
170
+ });
171
+
172
+ it("For built-in works with alloy preset", async () => {
173
+ const src = `
174
+ import { For } from "@alloy-js/core";
175
+ const App = (props) => (
176
+ <group>
177
+ <For each={props.items}>{(item) => <group>[{item}]</group>}</For>
178
+ </group>
179
+ );
180
+ export { App };
181
+ `;
182
+ const App = (await evalCompiled(src, "App")) as (props: any) => unknown;
183
+ expect(printNode(App({ items: ["a", "b", "c"] }) as AlloyNode)).toBe(
184
+ "[a][b][c]",
185
+ );
186
+ });
187
+
188
+ it("For with joiner with alloy preset", async () => {
189
+ const src = `
190
+ import { For } from "@alloy-js/core";
191
+ const App = (props) => (
192
+ <group>
193
+ <For each={props.items} joiner=",">{(item) => <group>{item}</group>}</For>
194
+ </group>
195
+ );
196
+ export { App };
197
+ `;
198
+ const App = (await evalCompiled(src, "App")) as (props: any) => unknown;
199
+ expect(printNode(App({ items: ["x", "y", "z"] }) as AlloyNode)).toBe(
200
+ "x,y,z",
201
+ );
202
+ expect(printNode(App({ items: [] }) as AlloyNode)).toBe("");
203
+ });
204
+
205
+ it("Context.Provider value flows to descendants with alloy preset", async () => {
206
+ const src = `
207
+ import { createContext, useContext } from "@alloy-js/core";
208
+ const Ctx = createContext();
209
+ const Reader = () => {
210
+ const v = useContext(Ctx);
211
+ return <group>v={v}</group>;
212
+ };
213
+ const App = () => (
214
+ <Ctx.Provider value="hello">
215
+ <group><Reader /></group>
216
+ </Ctx.Provider>
217
+ );
218
+ export { App };
219
+ `;
220
+ const App = (await evalCompiled(src, "App")) as () => unknown;
221
+ // Top-level Component yields a thunk; route through insert into a parent.
222
+ expect(renderToString(App())).toBe("v=hello");
223
+ });
224
+ });
@@ -1,7 +1,7 @@
1
1
  import { ref } from "@vue/reactivity";
2
2
  import { expect, it } from "vitest";
3
3
  import { Block } from "../../src/components/Block.jsx";
4
- import { printTree, renderTree } from "../../src/render.js";
4
+ import { printTree, renderTree } from "../../src/test-render.js";
5
5
  import "../../testing/extend-expect.js";
6
6
  it("renders properly with no children", () => {
7
7
  const template = (
@@ -4,7 +4,8 @@ import { join } from "path";
4
4
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
5
  import { CopyFile } from "../../src/components/CopyFile.jsx";
6
6
  import { SourceDirectory } from "../../src/components/SourceDirectory.jsx";
7
- import { CopyOutputFile, render } from "../../src/render.js";
7
+ import type { CopyOutputFile } from "../../src/output-types.js";
8
+ import { render } from "../../src/render-output.js";
8
9
  import { writeOutput } from "../../src/write-output.js";
9
10
  import "../../testing/extend-expect.js";
10
11
 
@@ -3,7 +3,7 @@ import { tmpdir } from "os";
3
3
  import { join } from "pathe";
4
4
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
5
  import { UpdateFile } from "../../src/components/UpdateFile.jsx";
6
- import { render } from "../../src/render.js";
6
+ import { render } from "../../src/render-output.js";
7
7
  import "../../testing/extend-expect.js";
8
8
  import { d } from "../../testing/render.js";
9
9
 
@@ -1,7 +1,7 @@
1
1
  import { ref } from "@vue/reactivity";
2
2
  import { expect, it } from "vitest";
3
3
  import { Wrap } from "../../src/components/Wrap.jsx";
4
- import { printTree, renderTree } from "../../src/render.js";
4
+ import { printTree, renderTree } from "../../src/test-render.js";
5
5
  import "../../testing/extend-expect.js";
6
6
 
7
7
  function Wrapper(props: any) {
@@ -2,7 +2,7 @@ import "@alloy-js/core/testing";
2
2
  import { ref } from "@vue/reactivity";
3
3
  import { expect, it } from "vitest";
4
4
  import { Match, Switch } from "../../src/components/Switch.jsx";
5
- import { printTree, renderTree } from "../../src/render.js";
5
+ import { printTree, renderTree } from "../../src/test-render.js";
6
6
 
7
7
  it("selects the true branch", () => {
8
8
  const template = (
@@ -2,7 +2,7 @@ import "@alloy-js/core/testing";
2
2
  import { ref } from "@vue/reactivity";
3
3
  import { expect, it } from "vitest";
4
4
  import { Show } from "../../src/components/Show.jsx";
5
- import { printTree, renderTree } from "../../src/render.js";
5
+ import { printTree, renderTree } from "../../src/test-render.js";
6
6
 
7
7
  it("selects the true branch", () => {
8
8
  const template = <Show when={true}>true</Show>;
@@ -3,10 +3,10 @@ import { describe, expect, it } from "vitest";
3
3
  import { Show } from "../src/components/Show.jsx";
4
4
  import { createContentSlot } from "../src/content-slot.jsx";
5
5
  import { Context, ensureIsEmpty, getContext } from "../src/reactivity.js";
6
- import { printTree, renderTree } from "../src/render.js";
6
+ import { printTree, renderTree } from "../src/test-render.js";
7
7
  import "../testing/extend-expect.js";
8
8
 
9
- describe("lazy isEmpty / _lastEmpty", () => {
9
+ describe("lazy isEmpty", () => {
10
10
  it("context starts without isEmpty ref allocated", () => {
11
11
  let ctx: Context | null = null;
12
12
 
@@ -20,7 +20,7 @@ describe("lazy isEmpty / _lastEmpty", () => {
20
20
  // The isEmpty ref should NOT be allocated unless someone observes it.
21
21
  expect(ctx).not.toBeNull();
22
22
  expect(ctx!.isEmpty).toBeUndefined();
23
- expect(ctx!._lastEmpty).toBe(false);
23
+ expect(ctx!.childrenWithContent).toBe(1);
24
24
  });
25
25
 
26
26
  it("ensureIsEmpty lazily allocates the isEmpty ref", () => {
@@ -39,7 +39,7 @@ describe("lazy isEmpty / _lastEmpty", () => {
39
39
  expect(isEmptyRef).toBe(ctx!.isEmpty);
40
40
  });
41
41
 
42
- it("_lastEmpty is true for empty component, false for non-empty", () => {
42
+ it("tracks content count for empty and non-empty components", () => {
43
43
  let emptyCtx: Context | null = null;
44
44
  let fullCtx: Context | null = null;
45
45
 
@@ -60,8 +60,8 @@ describe("lazy isEmpty / _lastEmpty", () => {
60
60
  </>,
61
61
  );
62
62
 
63
- expect(emptyCtx!._lastEmpty).toBe(true);
64
- expect(fullCtx!._lastEmpty).toBe(false);
63
+ expect(emptyCtx!.childrenWithContent).toBe(0);
64
+ expect(fullCtx!.childrenWithContent).toBe(1);
65
65
  });
66
66
 
67
67
  it("ContentSlot triggers ensureIsEmpty and tracks reactively", () => {
@@ -0,0 +1,90 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ createElement,
4
+ createFragment,
5
+ createTextNode,
6
+ } from "../src/render/index.js";
7
+ import { textContent } from "./tree-test-utils.js";
8
+
9
+ describe("Node tree", () => {
10
+ it("append/prepend/before/after build linked list correctly", () => {
11
+ const root = createElement("group");
12
+ const b = createTextNode("B");
13
+ const c = createTextNode("C");
14
+ root.append(b, c);
15
+ const a = createTextNode("A");
16
+ root.prepend(a);
17
+ const d = createTextNode("D");
18
+ c.after(d);
19
+ const between = createTextNode("X");
20
+ c.before(between);
21
+
22
+ expect(textContent(root)).toBe("ABXCD");
23
+ expect(root.firstChild).toBe(a);
24
+ expect(root.lastChild).toBe(d);
25
+ expect(a.nextSibling).toBe(b);
26
+ expect(d.previousSibling).toBe(c);
27
+ });
28
+
29
+ it("replaceWith / remove maintain links", () => {
30
+ const root = createElement("group");
31
+ const a = createTextNode("A");
32
+ const b = createTextNode("B");
33
+ const c = createTextNode("C");
34
+ root.append(a, b, c);
35
+ const x = createTextNode("X");
36
+ const y = createTextNode("Y");
37
+ b.replaceWith(x, y);
38
+ expect(textContent(root)).toBe("AXYC");
39
+ expect(b.parentNode).toBeNull();
40
+ a.remove();
41
+ expect(textContent(root)).toBe("XYC");
42
+ expect(root.firstChild).toBe(x);
43
+ });
44
+
45
+ it("Fragment splices children on insert and self-empties", () => {
46
+ const root = createElement("group");
47
+ const f = createFragment();
48
+ f.append("hello", " ", "world");
49
+ expect(f.firstChild).not.toBeNull();
50
+ root.append(f);
51
+ expect(f.firstChild).toBeNull();
52
+ expect(f.parentNode).toBeNull();
53
+ expect(textContent(root)).toBe("hello world");
54
+ });
55
+
56
+ it("indent element preserves nested text in tree order", () => {
57
+ const root = createElement("group");
58
+ const indent = createElement("indent");
59
+ indent.append("first\nsecond\nthird");
60
+ root.append("top\n", indent);
61
+ expect(textContent(root)).toBe("top\nfirst\nsecond\nthird");
62
+ expect(root.lastChild).toBe(indent);
63
+ });
64
+
65
+ it("moveBefore atomically relocates without disconnecting subtree", () => {
66
+ const root = createElement("group");
67
+ const a = createElement("group");
68
+ const b = createElement("group");
69
+ a.append("A-content");
70
+ b.append("B-content");
71
+ root.append(a, b);
72
+ expect(textContent(root)).toBe("A-contentB-content");
73
+ // Move a after b.
74
+ root.moveBefore(a, null);
75
+ expect(textContent(root)).toBe("B-contentA-content");
76
+ // Subtree of `a` is untouched.
77
+ expect(a.firstChild).not.toBeNull();
78
+ });
79
+
80
+ it("moveBefore is a no-op when already at target position", () => {
81
+ const root = createElement("group");
82
+ const a = createTextNode("A");
83
+ const b = createTextNode("B");
84
+ root.append(a, b);
85
+ const aPrev = a.previousSibling;
86
+ root.moveBefore(a, b);
87
+ expect(a.previousSibling).toBe(aPrev);
88
+ expect(textContent(root)).toBe("AB");
89
+ });
90
+ });
@@ -0,0 +1,198 @@
1
+ /**
2
+ * End-to-end test of the entry point: compile JSX through the babel
3
+ * preset (alloy preset), evaluate against the runtime, and run through
4
+ * `renderAsync` to produce an `OutputDirectory`.
5
+ *
6
+ * Validates:
7
+ * - Output → SourceDirectory → SourceFile composition.
8
+ * - File contents are produced via Alloy's direct printer.
9
+ * - Nested directories accumulate paths correctly.
10
+ * - `For` works under the runtime emitting multiple files.
11
+ */
12
+
13
+ // @ts-expect-error — @babel/core has no bundled types in this workspace
14
+ import { transformSync } from "@babel/core";
15
+ // @ts-expect-error — preset has no types
16
+ import alloyPreset from "@alloy-js/babel-preset";
17
+ // @ts-expect-error — preset-typescript has no types
18
+ import typescriptPreset from "@babel/preset-typescript";
19
+ import { beforeAll, describe, expect, it } from "vitest";
20
+ import type {
21
+ ContentOutputFile,
22
+ OutputDirectory,
23
+ } from "../src/output-types.js";
24
+
25
+ // Prime the runtime + core module imports once. Without this, the first
26
+ // test in the suite pays the full module-init cost of `@alloy-js/core`
27
+ // inside its 5s timeout window, which is flaky on slower machines.
28
+ let runtimeMod: any;
29
+ let coreMod: any;
30
+ beforeAll(async () => {
31
+ runtimeMod = await import("../src/runtime/index.js");
32
+ coreMod = await import("../src/index.js");
33
+ });
34
+
35
+ function compile(src: string): string {
36
+ const result = transformSync(src, {
37
+ filename: "test.tsx",
38
+ presets: [typescriptPreset, [alloyPreset]],
39
+ });
40
+ if (!result?.code) throw new Error("compile failed");
41
+ return result.code;
42
+ }
43
+
44
+ async function evalCompiled(src: string, exportName: string): Promise<unknown> {
45
+ const code = compile(src);
46
+ const runtimeStub = `const __rt = arguments[0]; const __core = arguments[1];`;
47
+ const importRegex =
48
+ /import\s*\{\s*([^}]+)\s*\}\s*from\s*"@alloy-js\/core\/jsx-runtime";?/g;
49
+ const destructures: string[] = [];
50
+ let body = code.replace(importRegex, (_match, names: string) => {
51
+ const dn = names.replace(/(\w+)\s+as\s+(\w+)/g, "$1: $2");
52
+ destructures.push(`const {${dn}} = __rt;`);
53
+ return "";
54
+ });
55
+ const coreImportRegex =
56
+ /import\s*\{\s*([^}]+)\s*\}\s*from\s*"@alloy-js\/core";?/g;
57
+ body = body.replace(coreImportRegex, (_match, names: string) => {
58
+ const dn = names.replace(/(\w+)\s+as\s+(\w+)/g, "$1: $2");
59
+ destructures.push(`const {${dn}} = { ...__core, ...__rt };`);
60
+ return "";
61
+ });
62
+ body = body.replace(
63
+ /export\s*\{\s*([^}]+)\s*\}\s*;?/g,
64
+ (_, names: string) => {
65
+ const list = names.split(",").map((s) => s.trim());
66
+ return `return { ${list.join(",")} };`;
67
+ },
68
+ );
69
+ body = body.replace(/import\.meta\.url/g, '"test://test.tsx"');
70
+ const wrapped = `${runtimeStub}\n${destructures.join("\n")}\n${body}`;
71
+ const fn = new Function(wrapped);
72
+ return fn(runtimeMod, coreMod)[exportName];
73
+ }
74
+
75
+ function findFile(
76
+ dir: OutputDirectory,
77
+ path: string,
78
+ ): ContentOutputFile | undefined {
79
+ for (const c of dir.contents) {
80
+ if (c.kind === "file" && "contents" in c && c.path === path) return c;
81
+ if (c.kind === "directory") {
82
+ const found = findFile(c, path);
83
+ if (found) return found;
84
+ }
85
+ }
86
+ return undefined;
87
+ }
88
+
89
+ describe("renderAsync — end-to-end output structure", () => {
90
+ it("produces a single SourceFile under Output > SourceDirectory", async () => {
91
+ const src = `
92
+ import { Output, SourceDirectory, SourceFile } from "@alloy-js/core";
93
+ const App = () => (
94
+ <Output>
95
+ <SourceDirectory path="src">
96
+ <SourceFile path="hello.txt" filetype="text/plain">
97
+ <group>hello, world</group>
98
+ </SourceFile>
99
+ </SourceDirectory>
100
+ </Output>
101
+ );
102
+ export { App };
103
+ `;
104
+ const App = (await evalCompiled(src, "App")) as () => unknown;
105
+ const { renderAsync } = runtimeMod;
106
+ // App() returns a ComponentCreator (top-level <Output>); pass the
107
+ // thunk directly as Children — renderAsync's insert handles it.
108
+ const out = await renderAsync(App() as any);
109
+ const f = findFile(out, "src/hello.txt");
110
+ expect(f).toBeDefined();
111
+ expect(f!.contents).toBe("hello, world\n");
112
+ expect(f!.filetype).toBe("text/plain");
113
+ });
114
+
115
+ it("nested SourceDirectory paths accumulate", async () => {
116
+ const src = `
117
+ import { Output, SourceDirectory, SourceFile } from "@alloy-js/core";
118
+ const App = () => (
119
+ <Output>
120
+ <SourceDirectory path="src">
121
+ <SourceDirectory path="lib">
122
+ <SourceFile path="x.txt" filetype="text/plain">x</SourceFile>
123
+ </SourceDirectory>
124
+ </SourceDirectory>
125
+ </Output>
126
+ );
127
+ export { App };
128
+ `;
129
+ const App = (await evalCompiled(src, "App")) as () => unknown;
130
+ const { renderAsync } = runtimeMod;
131
+ const out = await renderAsync(App() as any);
132
+ expect(findFile(out, "src/lib/x.txt")?.contents).toBe("x\n");
133
+ });
134
+
135
+ it("For emits multiple files", async () => {
136
+ const src = `
137
+ import { For, Output, SourceDirectory, SourceFile } from "@alloy-js/core";
138
+ const App = (props) => (
139
+ <Output>
140
+ <SourceDirectory path="src">
141
+ <For each={props.specs}>
142
+ {(spec) => (
143
+ <SourceFile path={spec.path} filetype="text/plain">
144
+ <group>{spec.body}</group>
145
+ </SourceFile>
146
+ )}
147
+ </For>
148
+ </SourceDirectory>
149
+ </Output>
150
+ );
151
+ export { App };
152
+ `;
153
+ const App = (await evalCompiled(src, "App")) as (props: any) => unknown;
154
+ const { renderAsync } = runtimeMod;
155
+ const specs = [
156
+ { path: "a.txt", body: "alpha" },
157
+ { path: "b.txt", body: "beta" },
158
+ { path: "c.txt", body: "gamma" },
159
+ ];
160
+ const out = await renderAsync(App({ specs }) as any);
161
+ expect(findFile(out, "src/a.txt")?.contents).toBe("alpha\n");
162
+ expect(findFile(out, "src/b.txt")?.contents).toBe("beta\n");
163
+ expect(findFile(out, "src/c.txt")?.contents).toBe("gamma\n");
164
+ });
165
+
166
+ it("direct printer formatting — group breaks at printWidth", async () => {
167
+ const src = `
168
+ import { Output, SourceDirectory, SourceFile } from "@alloy-js/core";
169
+ const App = () => (
170
+ <Output>
171
+ <SourceDirectory path=".">
172
+ <SourceFile path="t.txt" filetype="text/plain">
173
+ <group>
174
+ {"["}
175
+ <indent>
176
+ <line />
177
+ {"aaaaaaaaaaaaaaaaaaaa,"}
178
+ <line />
179
+ {"bbbbbbbbbbbbbbbbbbbb"}
180
+ </indent>
181
+ <line />
182
+ {"]"}
183
+ </group>
184
+ </SourceFile>
185
+ </SourceDirectory>
186
+ </Output>
187
+ );
188
+ export { App };
189
+ `;
190
+ const App = (await evalCompiled(src, "App")) as () => unknown;
191
+ const { renderAsync } = runtimeMod;
192
+ const out = await renderAsync(App() as any, { printWidth: 30 });
193
+ const f = findFile(out, "t.txt");
194
+ expect(f!.contents).toBe(
195
+ "[\n aaaaaaaaaaaaaaaaaaaa,\n bbbbbbbbbbbbbbbbbbbb\n]\n",
196
+ );
197
+ });
198
+ });
@@ -1,7 +1,7 @@
1
1
  import { shallowReactive } from "@vue/reactivity";
2
2
  import { expect, it } from "vitest";
3
3
  import { For } from "../../src/index.js";
4
- import { printTree, renderTree } from "../../src/render.js";
4
+ import { printTree, renderTree } from "../../src/test-render.js";
5
5
  import { d } from "../../testing/render.js";
6
6
 
7
7
  it("it should work with circular reactives", () => {
@@ -1,9 +1,9 @@
1
1
  import { ref } from "@vue/reactivity";
2
2
  import { describe, expect, it } from "vitest";
3
3
  import { effect, memo, onCleanup } from "../../src/reactivity.js";
4
- import { renderTree } from "../../src/render.js";
5
4
  import type { Children } from "../../src/runtime/component.js";
6
5
  import { flushJobs } from "../../src/scheduler.js";
6
+ import { renderTree } from "../../src/test-render.js";
7
7
 
8
8
  describe("memo cleanup", () => {
9
9
  it("cleans up when memo value is recomputed", () => {
@@ -1,8 +1,8 @@
1
1
  import { ref } from "@vue/reactivity";
2
2
  import { expect, it } from "vitest";
3
3
  import { memo } from "../../src/reactivity.js";
4
- import { renderTree } from "../../src/render.js";
5
4
  import { flushJobs } from "../../src/scheduler.js";
5
+ import { renderTree } from "../../src/test-render.js";
6
6
 
7
7
  it("memoizes child components", () => {
8
8
  let renderCount = 0;
@@ -28,5 +28,10 @@ it("memoizes child components", () => {
28
28
  renderTree(template);
29
29
  doThing.value = true;
30
30
  flushJobs();
31
+ // Without element-cache (legacy), each component creator is invoked on
32
+ // every reactive re-evaluation, except when the same ComponentCreator
33
+ // instance reappears at a slot — reconcileArray keeps the existing
34
+ // subtree intact. child1 is invoked once initially and reused on the
35
+ // memo re-fire; child2 is invoked once when added.
31
36
  expect(renderCount).toBe(2);
32
37
  });