@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
package/src/render.ts DELETED
@@ -1,1154 +0,0 @@
1
- import { isRef } from "@vue/reactivity";
2
- import { Doc, doc } from "prettier";
3
- import prettier from "prettier/doc.js";
4
- import { useContext } from "./context.js";
5
- import { SourceFileContext } from "./context/source-file.js";
6
- import {
7
- debug,
8
- getRenderNodeId,
9
- isDevtoolsConnected,
10
- isDevtoolsEnabled,
11
- type RenderTreeNodeInfo,
12
- } from "./debug/index.js";
13
- import {
14
- beginTransaction,
15
- closeTrace,
16
- commitTransaction,
17
- notifyDiagnosticsReport,
18
- } from "./debug/trace-writer.js";
19
- import { isTraceEnabled } from "./debug/trace.js";
20
- import {
21
- attachDiagnosticsCollector,
22
- DiagnosticsCollector,
23
- emitDiagnostic,
24
- reportDiagnostics,
25
- } from "./diagnostics.js";
26
- import {
27
- isPrintHook,
28
- printHookTag,
29
- type PrintHook,
30
- type RenderedTextTree,
31
- } from "./print-hook.js";
32
- import {
33
- Context,
34
- CustomContext,
35
- effect,
36
- getContext,
37
- getElementCache,
38
- isCustomContext,
39
- onCleanup,
40
- ref,
41
- root,
42
- untrack,
43
- } from "./reactivity.js";
44
- import { isRefkeyable, toRefkey } from "./refkey.js";
45
- import {
46
- getRenderStackSnapshot,
47
- popStack,
48
- printRenderStack,
49
- pushStack,
50
- } from "./render-stack.js";
51
- import {
52
- Child,
53
- Children,
54
- isComponentCreator,
55
- isRenderableObject,
56
- RENDERABLE,
57
- } from "./runtime/component.js";
58
- import { IntrinsicElement, isIntrinsicElement } from "./runtime/intrinsic.js";
59
- import { flushJobs, flushJobsAsync, waitForSignal } from "./scheduler.js";
60
-
61
- const notifiedErrors = new WeakSet<object>();
62
-
63
- // ─────────────────────────────────────────────────────────────────────────────
64
- // Deferred file printing: mark files dirty during render, print once at end
65
- // ─────────────────────────────────────────────────────────────────────────────
66
- interface DirtyFileEntry {
67
- renderNode: RenderedTextTree;
68
- printOptions: {
69
- printWidth?: number;
70
- tabWidth?: number;
71
- useTabs?: boolean;
72
- insertFinalNewLine?: boolean;
73
- };
74
- path: string;
75
- filetype: string;
76
- }
77
- const dirtyFiles = new Map<string, DirtyFileEntry>();
78
- const lastFlushTimeByFile = new Map<string, number>();
79
- const DEVTOOLS_FLUSH_INTERVAL_MS = 1000;
80
-
81
- function flushDirtyFile(path: string): void {
82
- const entry = dirtyFiles.get(path);
83
- if (!entry) return;
84
- dirtyFiles.delete(path);
85
- const contents = printTree(entry.renderNode, {
86
- ...entry.printOptions,
87
- insertFinalNewLine: entry.printOptions.insertFinalNewLine ?? true,
88
- noFlush: true,
89
- });
90
- debug.files.updated({ path: entry.path, filetype: entry.filetype, contents });
91
- }
92
-
93
- function flushDirtyFiles(): void {
94
- for (const path of [...dirtyFiles.keys()]) {
95
- flushDirtyFile(path);
96
- }
97
- }
98
-
99
- let lastRenderError: {
100
- error: { name: string; message: string; stack?: string };
101
- componentStack: Array<{
102
- name: string;
103
- props?: Record<string, unknown> | undefined;
104
- propsSerialized?: string;
105
- renderNodeId?: number;
106
- source?: RenderTreeNodeInfo["source"];
107
- }>;
108
- } | null = null;
109
-
110
- function normalizeRenderError(error: unknown): {
111
- name: string;
112
- message: string;
113
- stack?: string;
114
- } {
115
- if (error instanceof Error) {
116
- return {
117
- name: error.name || error.constructor?.name || "Error",
118
- message: error.message || "",
119
- stack: error.stack,
120
- };
121
- }
122
- if (error && typeof error === "object") {
123
- const anyError = error as {
124
- name?: string;
125
- message?: string;
126
- stack?: string;
127
- };
128
- return {
129
- name: anyError.name || "Error",
130
- message: anyError.message || String(error),
131
- stack: anyError.stack,
132
- };
133
- }
134
- return {
135
- name: "Error",
136
- message: String(error),
137
- };
138
- }
139
-
140
- function notifyRenderError(error: unknown) {
141
- if (error && typeof error === "object") {
142
- if (notifiedErrors.has(error)) return;
143
- notifiedErrors.add(error);
144
- }
145
- if (lastRenderError) return;
146
-
147
- const { name, message, stack } = normalizeRenderError(error);
148
- const componentStack = getRenderStackSnapshot().map((entry) => {
149
- const renderNode = entry.context?.meta?.renderNode as
150
- | RenderedTextTree
151
- | undefined;
152
- const renderNodeId = renderNode ? getRenderNodeId(renderNode) : undefined;
153
- return {
154
- name: entry.displayName,
155
- props: entry.props as Record<string, unknown> | undefined,
156
- renderNodeId,
157
- source: entry.source,
158
- };
159
- });
160
-
161
- // Output to console
162
- printRenderStack(error);
163
-
164
- // Send to devtools if enabled
165
- debug.render.error({ name, message, stack }, componentStack);
166
-
167
- // Store for diagnostics
168
- lastRenderError = { error: { name, message, stack }, componentStack };
169
- const lastEntry = componentStack.at(-1);
170
- emitDiagnostic({
171
- severity: "error",
172
- message: `${name}: ${message}`,
173
- source: lastEntry?.source,
174
- });
175
- }
176
-
177
- function reportLastRenderError() {
178
- // Error already reported in notifyRenderError via debug.renderError
179
- lastRenderError = null;
180
- }
181
-
182
- const {
183
- builders: {
184
- align,
185
- breakParent,
186
- dedent,
187
- dedentToRoot,
188
- fill,
189
- group,
190
- hardline,
191
- indent,
192
- indentIfBreak,
193
- line,
194
- lineSuffix,
195
- lineSuffixBoundary,
196
- literalline,
197
- markAsRoot,
198
- softline,
199
- ifBreak,
200
- },
201
- } = prettier;
202
-
203
- /**
204
- * Turning components into source text involves three different trees produced
205
- * sequentially:
206
- *
207
- * 1. Component tree, built by the nesting of components
208
- * 2. Rendered text tree, produced by *rendering* the component tree
209
- * 3. Document tree, produced by *printing* the rendered text tree
210
- *
211
- * Finally, the document tree is converted to text via `prettier`. Let's look at
212
- * each of these trees and the conversions in detail.
213
- *
214
- * # Component tree
215
- *
216
- * The component tree is built by JSX or STC templates. The nodes in this tree
217
- * are defined by the type `Child` and are one of the following
218
- *
219
- * ## Primitive values
220
- *
221
- * Strings in the tree are placed into the rendered text tree as-is. Numbers are
222
- * converted to strings. Falsy primitive values and booleans are converted to
223
- * empty strings (and may cause a line break to be ignored, see below).
224
- *
225
- * ## Nullary functions
226
- *
227
- * Nullary functions represent computed or reactive values in the component
228
- * tree, such as expressions placed into a JSX template with curly brackets.
229
- * Nullary functions return `Children` which are then recursively rendered.
230
- * Nullary functions are invoked in an effect which will update the rendered
231
- * text tree when any reactive dependencies change.
232
- *
233
- * ## Component creators
234
- *
235
- * Component creators are a special kind of nullary function which instantiate
236
- * components in order to get their children which are then recursively
237
- * rendered. Component creators have some special rendering behavior, such as
238
- * tracking the stack of rendered components. Like other nullary functions,
239
- * component creators are invoked in an effect which will update the rendered
240
- * text tree when any reactive dependencies change.
241
- *
242
- * ## Refs
243
- *
244
- * Refs are wrapped in a nullary function and rendered in an effect which will
245
- * update the rendered text tree when the ref's value changes. This is
246
- * essentially a syntactic convenience, allowing JSX templates to contain
247
- * `\{ someRef \}` instead of `\{ someRef.value \}`.
248
- *
249
- * ## Refkey
250
- *
251
- * Refkeys are replaced with a component creator for the Reference component
252
- * associated with the current source file. This allows creating references by
253
- * placing them directly in the component tree e.g. `{ someRefkey }`.
254
- *
255
- * ## CustomContext
256
- *
257
- * CustomContext is a special kind of component which allows rendering children
258
- * within a custom reactive context. This enables components to manually manage
259
- * the lifetime of their reactive contexts.
260
- *
261
- * ## IntrinsicElement
262
- *
263
- * Various intrinsic elements exist to control formatting. These elements
264
- * provide Print Hooks that are called during Printing.
265
- *
266
- * # Rendered Text Tree
267
- *
268
- * This tree is a nested array structure containing the rendered output of all
269
- * the components in the component tree. This structure is updated reactively
270
- * when reactive dependencies change. The nodes in this tree are predominantly
271
- * strings, but can also be Print Hooks.
272
- *
273
- * This tree is built by the `renderTree` function.
274
- *
275
- * # Document Tree
276
- *
277
- * This tree is constructed by calling `printTree` on the rendered text tree.
278
- * The rendered text tree is walked and the appropriate Prettier builders are
279
- * called to produce a document tree. The result is then passed to Prettier's
280
- * `printDocToString` function to produce the final source text.
281
- */
282
-
283
- export interface OutputDirectory {
284
- kind: "directory";
285
- /** Full path from the output root, e.g. `"generated-client/src"`. Do not prepend parent directory paths when walking the tree. */
286
- path: string;
287
- contents: (OutputDirectory | OutputFile)[];
288
- }
289
-
290
- export interface OutputFileBase {
291
- kind: "file";
292
- /** Full path from the output root, e.g. `"generated-client/src/models.ext"`. Do not prepend parent directory paths when walking the tree. */
293
- path: string;
294
- }
295
-
296
- export interface CopyOutputFile extends OutputFileBase {
297
- sourcePath: string;
298
- }
299
-
300
- export interface ContentOutputFile extends OutputFileBase {
301
- contents: string;
302
- filetype: string;
303
- }
304
-
305
- export type OutputFile = ContentOutputFile | CopyOutputFile;
306
-
307
- const nodesToContext = new WeakMap<RenderedTextTree, Context>();
308
- const diagnosticsByTree = new WeakMap<RenderedTextTree, DiagnosticsCollector>();
309
-
310
- export function getContextForRenderNode(node: RenderedTextTree) {
311
- return nodesToContext.get(node);
312
- }
313
-
314
- export function getDiagnosticsForTree(tree: RenderedTextTree) {
315
- return diagnosticsByTree.get(tree)?.getDiagnostics() ?? [];
316
- }
317
-
318
- function reportDiagnosticsForTree(tree: RenderedTextTree) {
319
- const diagnostics = diagnosticsByTree.get(tree);
320
- if (!diagnostics) return;
321
- const entries = diagnostics.getDiagnostics();
322
- if (entries.length === 0) return;
323
- reportDiagnostics(diagnostics);
324
- notifyDiagnosticsReport(entries);
325
- }
326
-
327
- // Re-export from print-hook.ts to maintain backwards compatibility
328
- export {
329
- isPrintHook,
330
- printHookTag,
331
- type PrintHook,
332
- type RenderedTextTree,
333
- } from "./print-hook.js";
334
-
335
- export function createRenderTreeHook(
336
- subtree: RenderedTextTree,
337
- hooks: Omit<PrintHook, typeof printHookTag | "subtree">,
338
- ): PrintHook {
339
- return {
340
- [printHookTag]: true,
341
- subtree,
342
- ...hooks,
343
- };
344
- }
345
-
346
- /**
347
- * Render a component tree to source directories and files. Will ensure that
348
- * all non-async scheduled jobs are completed before returning. If async jobs
349
- * are found, an error will be thrown. Use `renderAsync` when asynchronous
350
- * jobs are expected.
351
- */
352
- export function render(
353
- children: Children,
354
- options?: PrintTreeOptions,
355
- ): OutputDirectory {
356
- const tree = renderTree(children);
357
- flushJobs();
358
- const output = sourceFilesForTree(tree, options);
359
- flushDirtyFiles();
360
- reportDiagnosticsForTree(tree);
361
- reportLastRenderError();
362
- debug.render.complete();
363
- // Only close the trace DB when devtools is NOT running. When devtools is
364
- // active the DB must remain open for post-render reactive updates.
365
- if (isTraceEnabled() && !isDevtoolsEnabled()) closeTrace();
366
- if (isDevtoolsEnabled()) {
367
- void waitForSignal();
368
- }
369
- return output;
370
- }
371
-
372
- /**
373
- * Render a component tree to source directories and files. Will ensure that all
374
- * scheduled jobs are completed before returning.
375
- */
376
- export async function renderAsync(
377
- children: Children,
378
- options?: PrintTreeOptions,
379
- ): Promise<OutputDirectory> {
380
- await debug.prepare();
381
- const tree = renderTree(children);
382
- // Ensure all reactive updates are flushed before printing.
383
- await flushJobsAsync();
384
- const output = sourceFilesForTree(tree, options);
385
- flushDirtyFiles();
386
- reportDiagnosticsForTree(tree);
387
- reportLastRenderError();
388
- debug.render.complete();
389
- // Only close the trace DB when devtools is NOT running. When devtools is
390
- // active the DB must remain open for post-render reactive updates.
391
- if (isTraceEnabled() && !isDevtoolsEnabled()) closeTrace();
392
-
393
- return output;
394
- }
395
-
396
- /**
397
- * Convert a rendered text tree to source directories and files. Will ensure
398
- * that all scheduled jobs are completed before returning.
399
- */
400
- export function sourceFilesForTree(
401
- tree: RenderedTextTree,
402
- options?: PrintTreeOptions,
403
- ): OutputDirectory {
404
- let rootDirectory: OutputDirectory | undefined = undefined;
405
-
406
- collectSourceFiles(undefined, tree);
407
-
408
- if (!rootDirectory) {
409
- emitDiagnostic({
410
- severity: "error",
411
- message:
412
- "No root directory found. Make sure you are using the output component.",
413
- });
414
- return { kind: "directory", path: "", contents: [] };
415
- }
416
-
417
- return rootDirectory;
418
-
419
- function collectSourceFiles(
420
- currentDirectory: OutputDirectory | undefined,
421
- root: RenderedTextTree,
422
- ) {
423
- if (!Array.isArray(root)) {
424
- return;
425
- }
426
- const context = getContextForRenderNode(root);
427
-
428
- if (!context) {
429
- return recurse(currentDirectory);
430
- }
431
-
432
- if (context.meta?.directory) {
433
- const directory: OutputDirectory = {
434
- kind: "directory",
435
- path: context.meta?.directory.path,
436
- contents: [],
437
- };
438
-
439
- if (currentDirectory) {
440
- currentDirectory.contents.push(directory);
441
- } else {
442
- rootDirectory = directory;
443
- }
444
- recurse(directory);
445
- } else if (context.meta?.sourceFile) {
446
- if (!currentDirectory) {
447
- // This shouldn't happen if you're using the Output component.
448
- throw new Error(
449
- "Source file doesn't have parent directory. Make sure you have used the Output component.",
450
- );
451
- }
452
-
453
- const sourceFile: ContentOutputFile = {
454
- kind: "file",
455
- path: context.meta?.sourceFile.path,
456
- filetype: context.meta?.sourceFile.filetype,
457
- contents: printTree(root, {
458
- printWidth:
459
- options?.printWidth ?? context.meta?.printOptions?.printWidth,
460
- tabWidth: options?.tabWidth ?? context.meta?.printOptions?.tabWidth,
461
- useTabs: options?.useTabs ?? context.meta?.printOptions?.useTabs,
462
- insertFinalNewLine:
463
- options?.insertFinalNewLine ??
464
- context.meta?.printOptions?.insertFinalNewLine ??
465
- true,
466
- }),
467
- };
468
-
469
- currentDirectory.contents.push(sourceFile);
470
- } else if (context.meta?.copyFile) {
471
- if (!currentDirectory) {
472
- // This shouldn't happen if you're using the Output component.
473
- throw new Error(
474
- "Copy file doesn't have parent directory. Make sure you have used the Output component.",
475
- );
476
- }
477
-
478
- const sourceFile: CopyOutputFile = {
479
- kind: "file",
480
- path: context.meta?.copyFile.path,
481
- sourcePath: context.meta?.copyFile.sourcePath,
482
- };
483
-
484
- currentDirectory.contents.push(sourceFile);
485
- } else {
486
- recurse(currentDirectory);
487
- }
488
-
489
- function recurse(cwd: OutputDirectory | undefined) {
490
- for (const child of root) {
491
- collectSourceFiles(cwd, child as RenderedTextTree);
492
- }
493
- }
494
- }
495
- }
496
- export function renderTree(children: Children) {
497
- const rootElem: RenderedTextTree = [];
498
- const diagnostics = new DiagnosticsCollector();
499
- lastRenderError = null;
500
- debug.effect.reset();
501
- debug.symbols.reset();
502
- debug.files.reset();
503
- dirtyFiles.clear();
504
- lastFlushTimeByFile.clear();
505
- debug.render.initialize(rootElem);
506
- if (isTraceEnabled()) beginTransaction();
507
- try {
508
- root(() => {
509
- attachDiagnosticsCollector(diagnostics);
510
- renderWorker(rootElem, children);
511
- });
512
- } catch (e) {
513
- if (isTraceEnabled()) commitTransaction();
514
- flushDirtyFiles();
515
- notifyRenderError(e);
516
- reportLastRenderError();
517
- throw e;
518
- }
519
- if (isTraceEnabled()) commitTransaction();
520
-
521
- diagnosticsByTree.set(rootElem, diagnostics);
522
-
523
- return rootElem;
524
- }
525
-
526
- function renderWorker(node: RenderedTextTree, children: Children) {
527
- if (lastRenderError) return;
528
- if (!getContext()) {
529
- throw new Error(
530
- "Cannot render without a context. Make sure you are using the Output component.",
531
- );
532
- }
533
-
534
- if (Array.isArray(node)) {
535
- nodesToContext.set(node, getContext()!);
536
- }
537
-
538
- if (Array.isArray(children)) {
539
- for (const child of (children as any).flat(Infinity)) {
540
- appendChild(node, child);
541
- if (lastRenderError) break;
542
- }
543
- } else {
544
- appendChild(node, children);
545
- }
546
- }
547
-
548
- function contentAdded() {
549
- const context: Context = getContext()!;
550
- context.childrenWithContent++;
551
- }
552
-
553
- export function notifyContentState() {
554
- untrack(() => {
555
- const startContext = getContext()!;
556
-
557
- if (startContext.childrenWithContent === 0) {
558
- if (startContext._lastEmpty) {
559
- // it was already empty, no work to do.
560
- return;
561
- }
562
-
563
- startContext._lastEmpty = true;
564
- if (startContext.isEmpty) {
565
- startContext.isEmpty.value = true;
566
- }
567
-
568
- // otherwise we need to decrement the content counts up the tree.
569
- let current = startContext.owner;
570
- while (current) {
571
- if (current.childrenWithContent === 0) {
572
- break;
573
- }
574
- current.childrenWithContent--;
575
- if (current.childrenWithContent > 0) {
576
- // This isn't the last content so we have no work to do
577
- break;
578
- }
579
- current._lastEmpty = true;
580
- if (current.isEmpty) {
581
- current.isEmpty.value = true;
582
- }
583
- current = current.owner;
584
- }
585
- } else {
586
- if (!startContext._lastEmpty) {
587
- // it was already non-empty, no work to do.
588
- return;
589
- }
590
-
591
- startContext._lastEmpty = false;
592
- if (startContext.isEmpty) {
593
- startContext.isEmpty.value = false;
594
- }
595
-
596
- // otherwise we need to increment the content counts up the tree.
597
- let current = startContext.owner;
598
- while (current) {
599
- current.childrenWithContent++;
600
- if (current.childrenWithContent > 1) {
601
- // This isn't the first content so we have no work to do
602
- break;
603
- }
604
-
605
- current._lastEmpty = false;
606
- if (current.isEmpty) {
607
- current.isEmpty.value = false;
608
- }
609
-
610
- current = current.owner;
611
- }
612
- }
613
- });
614
- }
615
-
616
- function appendChild(node: RenderedTextTree, rawChild: Child) {
617
- if (lastRenderError) return;
618
- const child = normalizeChild(rawChild);
619
-
620
- if (typeof child === "string") {
621
- if (child !== "") {
622
- contentAdded();
623
- debug.render.appendTextNode(node, node.length, child);
624
- }
625
- node.push(child);
626
- } else {
627
- const cache = getElementCache();
628
- if (cache.has(child as any)) {
629
- const cachedNode = cache.get(child as any)!;
630
- // recordSubtreeAdded detects cached nodes automatically and re-adds their children
631
- if (isCustomContext(child)) {
632
- debug.render.appendCustomContext(node, cachedNode);
633
- } else {
634
- debug.render.appendFragmentChild(node, cachedNode);
635
- }
636
- node.push(cachedNode);
637
- return;
638
- }
639
- if (isCustomContext(child)) {
640
- const newNode: RenderedTextTree = [];
641
- debug.render.appendCustomContext(node, newNode);
642
- child.useCustomContext((children) => {
643
- renderWorker(newNode, children);
644
- node.push(newNode);
645
- cache.set(child, newNode);
646
- notifyContentState();
647
- notifyFileUpdateForNode(node);
648
- });
649
- } else if (isIntrinsicElement(child)) {
650
- // don't need a new context here because intrinsics are never reactive
651
- const intrinsic = child as IntrinsicElement;
652
- const newNode: RenderedTextTree = [];
653
-
654
- function formatHookWithChildren(command: (doc: Doc) => Doc) {
655
- const hook = createRenderTreeHook(newNode, {
656
- print(tree, print) {
657
- return command(print(tree));
658
- },
659
- });
660
- debug.render.appendPrintHook(
661
- node,
662
- node.length,
663
- hook,
664
- intrinsic.name,
665
- newNode,
666
- );
667
- node.push(hook);
668
- renderWorker(newNode, (child as any).props.children);
669
- notifyFileUpdateForNode(node);
670
- }
671
-
672
- function formatHook(command: Doc) {
673
- const hook = createRenderTreeHook(newNode, {
674
- print() {
675
- return command;
676
- },
677
- });
678
- debug.render.appendPrintHook(node, node.length, hook, intrinsic.name);
679
- node.push(hook);
680
- return hook;
681
- }
682
-
683
- switch (child.name) {
684
- case "indent":
685
- return formatHookWithChildren(indent);
686
- case "indentIfBreak":
687
- {
688
- const hook = createRenderTreeHook(newNode, {
689
- print(tree, print) {
690
- return indentIfBreak(print(tree), {
691
- groupId: child.props.groupId,
692
- negate: child.props.negate,
693
- });
694
- },
695
- });
696
- debug.render.appendPrintHook(
697
- node,
698
- node.length,
699
- hook,
700
- intrinsic.name,
701
- newNode,
702
- );
703
- node.push(hook);
704
- }
705
- renderWorker(newNode, child.props.children);
706
- notifyFileUpdateForNode(node);
707
- return;
708
- case "fill":
709
- return formatHookWithChildren(fill as any);
710
- case "group":
711
- {
712
- const hook = createRenderTreeHook(newNode, {
713
- print(tree, print) {
714
- return group(print(tree), {
715
- id: child.props.id,
716
- shouldBreak: child.props.shouldBreak,
717
- });
718
- },
719
- });
720
- debug.render.appendPrintHook(
721
- node,
722
- node.length,
723
- hook,
724
- intrinsic.name,
725
- newNode,
726
- );
727
- node.push(hook);
728
- }
729
- renderWorker(newNode, child.props.children);
730
- notifyFileUpdateForNode(node);
731
- return;
732
- case "line":
733
- case "br":
734
- return formatHook(line);
735
- case "hbr":
736
- case "hardline":
737
- return formatHook(hardline);
738
- case "sbr":
739
- case "softline":
740
- return formatHook(softline);
741
- case "literalline":
742
- case "lbr":
743
- return formatHook(literalline);
744
- case "align":
745
- {
746
- const hook = createRenderTreeHook(newNode, {
747
- print(tree, print) {
748
- return align(
749
- (child.props as any).width ?? (child.props as any).string!,
750
- print(tree),
751
- );
752
- },
753
- });
754
- debug.render.appendPrintHook(
755
- node,
756
- node.length,
757
- hook,
758
- intrinsic.name,
759
- newNode,
760
- );
761
- node.push(hook);
762
- }
763
- renderWorker(newNode, (child as any).props.children);
764
- notifyFileUpdateForNode(node);
765
- return;
766
- case "lineSuffix":
767
- return formatHookWithChildren(lineSuffix);
768
- case "lineSuffixBoundary":
769
- return formatHook(lineSuffixBoundary);
770
- case "breakParent":
771
- return formatHook(breakParent);
772
- case "dedent":
773
- return formatHookWithChildren(dedent);
774
- case "dedentToRoot":
775
- return formatHookWithChildren(dedentToRoot);
776
- case "markAsRoot":
777
- return formatHookWithChildren(markAsRoot);
778
- case "ifBreak":
779
- {
780
- const hook = createRenderTreeHook(newNode, {
781
- print(tree, print) {
782
- return ifBreak(
783
- print((tree as RenderedTextTree[])[0]),
784
- print((tree as RenderedTextTree[])[1]),
785
- );
786
- },
787
- });
788
- debug.render.appendPrintHook(
789
- node,
790
- node.length,
791
- hook,
792
- intrinsic.name,
793
- newNode,
794
- );
795
- node.push(hook);
796
- }
797
- newNode.push([], []);
798
- debug.render.appendFragmentChild(
799
- newNode,
800
- newNode[0] as RenderedTextTree,
801
- );
802
- debug.render.appendFragmentChild(
803
- newNode,
804
- newNode[1] as RenderedTextTree,
805
- );
806
- renderWorker(
807
- newNode[0] as RenderedTextTree[],
808
- (child as any).props.children,
809
- );
810
- renderWorker(
811
- newNode[1] as RenderedTextTree[],
812
- (child as any).props.flatContents,
813
- );
814
- notifyFileUpdateForNode(node);
815
- return;
816
- default:
817
- throw new Error("Unknown intrinsic element");
818
- }
819
- } else if (isComponentCreator(child)) {
820
- const index = node.length;
821
- const rerenderToken =
822
- isDevtoolsEnabled() ? ref(0, { isInfrastructure: true }) : undefined;
823
- const breakNext =
824
- isDevtoolsEnabled() ?
825
- ref(false, { isInfrastructure: true })
826
- : undefined;
827
- // todo: remove this effect (only needed for context, not needed for anything else)
828
- effect(
829
- () => {
830
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
831
- rerenderToken?.value;
832
- const context = getContext();
833
- context!.childrenWithContent = 0;
834
-
835
- if (context) context.componentOwner = child;
836
- const existing = node[index];
837
- const componentRoot: RenderedTextTree =
838
- Array.isArray(existing) ? existing : [];
839
- context!.meta ??= {};
840
- context!.meta.renderNode = componentRoot;
841
- const propsSource = (child.props ?? undefined) as
842
- | Record<string, unknown>
843
- | undefined;
844
- const debugSession = debug.render.beginComponent({
845
- parent: node,
846
- index,
847
- node: componentRoot,
848
- component: child,
849
- propsSource,
850
- source: child.source,
851
- isExisting: Array.isArray(existing),
852
- actions: {
853
- rerender:
854
- rerenderToken ?
855
- () => {
856
- lastRenderError = null;
857
- rerenderToken.value++;
858
- }
859
- : () => {},
860
- rerenderAndBreak:
861
- breakNext && rerenderToken ?
862
- () => {
863
- lastRenderError = null;
864
- breakNext.value = true;
865
- rerenderToken.value++;
866
- }
867
- : () => {},
868
- },
869
- });
870
- if (Array.isArray(existing)) {
871
- componentRoot.length = 0;
872
- }
873
-
874
- pushStack(child.component, child.props, child.source);
875
- let renderFailed = false;
876
- let childResult: Children | undefined;
877
- try {
878
- childResult = untrack(() => {
879
- const shouldBreak = breakNext?.value ?? false;
880
- if (shouldBreak) {
881
- breakNext!.value = false;
882
- // eslint-disable-next-line no-debugger
883
- debugger;
884
- }
885
- return child();
886
- });
887
- } catch (error) {
888
- notifyRenderError(error);
889
- renderFailed = true;
890
- throw error;
891
- }
892
- try {
893
- if (context?.meta?.directory) {
894
- debugSession.recordDirectory(context.meta.directory.path);
895
- }
896
- if (context?.meta?.sourceFile) {
897
- context.meta.renderNode = componentRoot;
898
- debugSession.recordFile(
899
- context.meta.sourceFile.path,
900
- context.meta.sourceFile.filetype,
901
- );
902
- context.meta.sourceFileReady = false;
903
- }
904
- if (!renderFailed) {
905
- renderWorker(componentRoot, childResult);
906
- }
907
- } finally {
908
- popStack();
909
- }
910
- if (renderFailed) {
911
- node[index] = componentRoot;
912
- cache.set(child, componentRoot);
913
- notifyFileUpdateForNode(node);
914
- notifyContentState();
915
- onCleanup(() => debugSession.dispose());
916
- return;
917
- }
918
- if (context?.meta?.sourceFile) {
919
- context.meta.sourceFileReady = true;
920
- notifyFileUpdateForNode(componentRoot);
921
- }
922
- node[index] = componentRoot;
923
- cache.set(child, componentRoot);
924
- notifyContentState();
925
- onCleanup(() => debugSession.dispose());
926
- },
927
- undefined,
928
- {
929
- debug: {
930
- name: `render:${child.component.name || "Anonymous"}`,
931
- type: "render",
932
- },
933
- },
934
- );
935
- } else if (typeof child === "function") {
936
- const index = node.length;
937
- effect(
938
- () => {
939
- let res: Child | Children | undefined;
940
- let renderFailed = false;
941
- try {
942
- res = child();
943
- while (typeof res === "function" && !isComponentCreator(res)) {
944
- res = res();
945
- }
946
- } catch (error) {
947
- notifyRenderError(error);
948
- renderFailed = true;
949
- throw error;
950
- }
951
- const context = getContext();
952
- context!.childrenWithContent = 0;
953
-
954
- const existing = node[index];
955
- const memoNode: RenderedTextTree =
956
- Array.isArray(existing) ? existing : [];
957
-
958
- debug.render.prepareMemoNode(node, memoNode, Array.isArray(existing));
959
- if (Array.isArray(existing)) {
960
- memoNode.length = 0;
961
- }
962
-
963
- if (!renderFailed) {
964
- renderWorker(memoNode, res);
965
- }
966
- node[index] = memoNode;
967
- cache.set(child, memoNode);
968
- notifyFileUpdateForNode(node);
969
- notifyContentState();
970
- return memoNode;
971
- },
972
- undefined,
973
- {
974
- debug: {
975
- name: `render:memo:${child.name || "anonymous"}`,
976
- type: "render",
977
- },
978
- },
979
- );
980
- } else {
981
- throw new Error("Unexpected child type");
982
- }
983
- }
984
- }
985
-
986
- function findSourceFileContext(node: RenderedTextTree) {
987
- let context: Context | null | undefined =
988
- getContextForRenderNode(node) ?? null;
989
- while (context) {
990
- if (context.meta?.sourceFile) return context;
991
- context = context.owner;
992
- }
993
- return undefined;
994
- }
995
-
996
- function notifyFileUpdateForNode(node: RenderedTextTree) {
997
- // Only track when devtools or trace are actually enabled
998
- if (!isDevtoolsEnabled() && !isTraceEnabled()) return;
999
- const context = findSourceFileContext(node);
1000
- if (!context?.meta?.sourceFile) return;
1001
- if (context.meta.sourceFileReady === false) return;
1002
- const sourceFile = context.meta.sourceFile;
1003
- const renderNode: RenderedTextTree =
1004
- (context.meta.renderNode as RenderedTextTree | undefined) ?? node;
1005
-
1006
- // Mark this file as dirty — defer the expensive printTree to end of render
1007
- dirtyFiles.set(sourceFile.path, {
1008
- renderNode,
1009
- printOptions: {
1010
- printWidth: context.meta?.printOptions?.printWidth,
1011
- tabWidth: context.meta?.printOptions?.tabWidth,
1012
- useTabs: context.meta?.printOptions?.useTabs,
1013
- insertFinalNewLine: context.meta?.printOptions?.insertFinalNewLine,
1014
- },
1015
- path: sourceFile.path,
1016
- filetype: sourceFile.filetype,
1017
- });
1018
-
1019
- // When a devtools client is connected, throttle file flushing to ~1s per file
1020
- // so the user can watch content build up during rendering.
1021
- if (isDevtoolsConnected()) {
1022
- const now = Date.now();
1023
- const lastFlush = lastFlushTimeByFile.get(sourceFile.path) ?? 0;
1024
- if (now - lastFlush >= DEVTOOLS_FLUSH_INTERVAL_MS) {
1025
- lastFlushTimeByFile.set(sourceFile.path, now);
1026
- flushDirtyFile(sourceFile.path);
1027
- }
1028
- }
1029
- }
1030
-
1031
- type NormalizedChildren = NormalizedChild | NormalizedChildren[];
1032
- type NormalizedChild =
1033
- | string
1034
- | (() => Child | Children)
1035
- | CustomContext
1036
- | IntrinsicElement;
1037
-
1038
- function normalizeChild(child: Child): NormalizedChildren {
1039
- if (Array.isArray(child)) {
1040
- return child.map(normalizeChild);
1041
- } else if (typeof child === "string" || typeof child === "function") {
1042
- return child as NormalizedChild;
1043
- } else if (
1044
- typeof child === "undefined" ||
1045
- child === null ||
1046
- typeof child === "boolean"
1047
- ) {
1048
- return "";
1049
- } else if (isRef(child)) {
1050
- return () => child.value as () => Child;
1051
- } else if (isRefkeyable(child)) {
1052
- const refkey = toRefkey(child);
1053
- return () => {
1054
- const sfContext = useContext(SourceFileContext);
1055
- if (!sfContext || !sfContext.reference) {
1056
- throw new Error("Can only emit references inside of source files");
1057
- }
1058
-
1059
- return sfContext.reference({ refkey });
1060
- };
1061
- } else if (isRenderableObject(child)) {
1062
- // For custom renderable objects, we will just normalize them to a bound function.
1063
- return child[RENDERABLE].bind(child);
1064
- } else if (isCustomContext(child)) {
1065
- return child;
1066
- } else if (isIntrinsicElement(child)) {
1067
- return child;
1068
- } else {
1069
- return String(child);
1070
- }
1071
- }
1072
-
1073
- export interface PrintTreeOptions {
1074
- /**
1075
- * The number of characters the printer will wrap on. Defaults to 100
1076
- * characters.
1077
- */
1078
- printWidth?: number;
1079
-
1080
- /**
1081
- * Whether to use tabs instead of spaces for indentation. Defaults to false.
1082
- */
1083
- useTabs?: boolean;
1084
-
1085
- /**
1086
- * The number of spaces to use for indentation. Defaults to 2 spaces.
1087
- */
1088
- tabWidth?: number;
1089
-
1090
- /**
1091
- * If files should end with a final new line.
1092
- * @default true
1093
- */
1094
- insertFinalNewLine?: boolean;
1095
-
1096
- /**
1097
- * Skip flushing scheduled jobs before printing.
1098
- * @default false
1099
- */
1100
- noFlush?: boolean;
1101
- }
1102
-
1103
- const defaultPrintTreeOptions: PrintTreeOptions = {
1104
- printWidth: 80,
1105
- tabWidth: 2,
1106
- };
1107
-
1108
- /**
1109
- * Convert a rendered text tree to a string. Will ensure that the scheduler is
1110
- * empty before printing.
1111
- */
1112
- export function printTree(tree: RenderedTextTree, options?: PrintTreeOptions) {
1113
- options = {
1114
- ...defaultPrintTreeOptions,
1115
- ...Object.fromEntries(
1116
- Object.entries(options ?? {}).filter(([_, v]) => v !== undefined),
1117
- ),
1118
- };
1119
-
1120
- if (!options.noFlush) {
1121
- // make sure queue is empty
1122
- flushJobs();
1123
- }
1124
-
1125
- const d = printTreeWorker(tree);
1126
- const result = doc.printer.printDocToString(
1127
- d,
1128
- options as doc.printer.Options,
1129
- ).formatted;
1130
-
1131
- return options.insertFinalNewLine && !result.endsWith("\n") ?
1132
- `${result}\n`
1133
- : result;
1134
- }
1135
-
1136
- function printTreeWorker(tree: RenderedTextTree): Doc {
1137
- const doc: Doc = [];
1138
- for (const node of tree) {
1139
- if (typeof node === "string") {
1140
- const normalizedNode = node
1141
- .split(/\r?\n/)
1142
- .flatMap((line, index, array) =>
1143
- index < array.length - 1 ? [line, hardline] : [line],
1144
- );
1145
- doc.push(normalizedNode);
1146
- } else if (isPrintHook(node)) {
1147
- doc.push(node.print!(node.subtree, printTreeWorker));
1148
- } else {
1149
- doc.push(printTreeWorker(node));
1150
- }
1151
- }
1152
-
1153
- return doc;
1154
- }