@alloy-js/core 0.23.0-dev.1 → 0.23.0-dev.11

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 (337) hide show
  1. package/CHANGELOG.md +0 -22
  2. package/dist/devtools/index.html +80 -0
  3. package/dist/src/binder.d.ts +2 -0
  4. package/dist/src/binder.d.ts.map +1 -1
  5. package/dist/src/binder.js +60 -12
  6. package/dist/src/binder.js.map +1 -1
  7. package/dist/src/components/AccessExpression.d.ts +78 -0
  8. package/dist/src/components/AccessExpression.d.ts.map +1 -0
  9. package/dist/src/components/AccessExpression.js +218 -0
  10. package/dist/src/components/AccessExpression.js.map +1 -0
  11. package/dist/src/components/AccessExpression.test.d.ts +2 -0
  12. package/dist/src/components/AccessExpression.test.d.ts.map +1 -0
  13. package/dist/src/components/AccessExpression.test.js +137 -0
  14. package/dist/src/components/AccessExpression.test.js.map +1 -0
  15. package/dist/src/components/AppendFile.d.ts.map +1 -1
  16. package/dist/src/components/AppendFile.js +14 -3
  17. package/dist/src/components/AppendFile.js.map +1 -1
  18. package/dist/src/components/Block.js +1 -1
  19. package/dist/src/components/Block.js.map +1 -1
  20. package/dist/src/components/Declaration.d.ts.map +1 -1
  21. package/dist/src/components/Declaration.js +2 -1
  22. package/dist/src/components/Declaration.js.map +1 -1
  23. package/dist/src/components/For.d.ts.map +1 -1
  24. package/dist/src/components/For.js +1 -1
  25. package/dist/src/components/For.js.map +1 -1
  26. package/dist/src/components/List.d.ts.map +1 -1
  27. package/dist/src/components/List.js +1 -1
  28. package/dist/src/components/List.js.map +1 -1
  29. package/dist/src/components/Prose.js +2 -2
  30. package/dist/src/components/Prose.js.map +1 -1
  31. package/dist/src/components/Scope.d.ts.map +1 -1
  32. package/dist/src/components/Scope.js +6 -1
  33. package/dist/src/components/Scope.js.map +1 -1
  34. package/dist/src/components/SourceDirectory.d.ts.map +1 -1
  35. package/dist/src/components/SourceDirectory.js +1 -2
  36. package/dist/src/components/SourceDirectory.js.map +1 -1
  37. package/dist/src/components/Switch.d.ts.map +1 -1
  38. package/dist/src/components/Switch.js +1 -1
  39. package/dist/src/components/Switch.js.map +1 -1
  40. package/dist/src/components/TemplateFile.d.ts.map +1 -1
  41. package/dist/src/components/TemplateFile.js +18 -3
  42. package/dist/src/components/TemplateFile.js.map +1 -1
  43. package/dist/src/components/index.d.ts +1 -0
  44. package/dist/src/components/index.d.ts.map +1 -1
  45. package/dist/src/components/index.js +1 -0
  46. package/dist/src/components/index.js.map +1 -1
  47. package/dist/src/content-slot.d.ts.map +1 -1
  48. package/dist/src/content-slot.js +7 -6
  49. package/dist/src/content-slot.js.map +1 -1
  50. package/dist/src/context.d.ts.map +1 -1
  51. package/dist/src/context.js +10 -3
  52. package/dist/src/context.js.map +1 -1
  53. package/dist/src/debug/cli.d.ts +6 -0
  54. package/dist/src/debug/cli.d.ts.map +1 -0
  55. package/dist/src/{debug.js → debug/cli.js} +79 -82
  56. package/dist/src/debug/cli.js.map +1 -0
  57. package/dist/src/debug/diagnostics.test.d.ts +2 -0
  58. package/dist/src/debug/diagnostics.test.d.ts.map +1 -0
  59. package/dist/src/debug/diagnostics.test.js +46 -0
  60. package/dist/src/debug/diagnostics.test.js.map +1 -0
  61. package/dist/src/debug/effects.d.ts +81 -0
  62. package/dist/src/debug/effects.d.ts.map +1 -0
  63. package/dist/src/debug/effects.js +358 -0
  64. package/dist/src/debug/effects.js.map +1 -0
  65. package/dist/src/debug/effects.test.d.ts +2 -0
  66. package/dist/src/debug/effects.test.d.ts.map +1 -0
  67. package/dist/src/debug/effects.test.js +256 -0
  68. package/dist/src/debug/effects.test.js.map +1 -0
  69. package/dist/src/debug/files.d.ts +14 -0
  70. package/dist/src/debug/files.d.ts.map +1 -0
  71. package/dist/src/debug/files.js +29 -0
  72. package/dist/src/debug/files.js.map +1 -0
  73. package/dist/src/debug/files.test.d.ts +2 -0
  74. package/dist/src/debug/files.test.d.ts.map +1 -0
  75. package/dist/src/debug/files.test.js +66 -0
  76. package/dist/src/debug/files.test.js.map +1 -0
  77. package/dist/src/debug/index.d.ts +63 -0
  78. package/dist/src/debug/index.d.ts.map +1 -0
  79. package/dist/src/debug/index.js +71 -0
  80. package/dist/src/debug/index.js.map +1 -0
  81. package/dist/src/debug/message-format.test.d.ts +2 -0
  82. package/dist/src/debug/message-format.test.d.ts.map +1 -0
  83. package/dist/src/debug/message-format.test.js +700 -0
  84. package/dist/src/debug/message-format.test.js.map +1 -0
  85. package/dist/src/debug/render-tree-orphans.test.d.ts +2 -0
  86. package/dist/src/debug/render-tree-orphans.test.d.ts.map +1 -0
  87. package/dist/src/debug/render-tree-orphans.test.js +297 -0
  88. package/dist/src/debug/render-tree-orphans.test.js.map +1 -0
  89. package/dist/src/debug/render.d.ts +57 -0
  90. package/dist/src/debug/render.d.ts.map +1 -0
  91. package/dist/src/debug/render.js +472 -0
  92. package/dist/src/debug/render.js.map +1 -0
  93. package/dist/src/debug/render.test.d.ts +2 -0
  94. package/dist/src/debug/render.test.d.ts.map +1 -0
  95. package/dist/src/debug/render.test.js +291 -0
  96. package/dist/src/debug/render.test.js.map +1 -0
  97. package/dist/src/debug/serialize.d.ts +9 -0
  98. package/dist/src/debug/serialize.d.ts.map +1 -0
  99. package/dist/src/debug/serialize.js +70 -0
  100. package/dist/src/debug/serialize.js.map +1 -0
  101. package/dist/src/debug/symbols.d.ts +16 -0
  102. package/dist/src/debug/symbols.d.ts.map +1 -0
  103. package/dist/src/debug/symbols.js +196 -0
  104. package/dist/src/debug/symbols.js.map +1 -0
  105. package/dist/src/debug/symbols.test.d.ts +2 -0
  106. package/dist/src/debug/symbols.test.d.ts.map +1 -0
  107. package/dist/src/debug/symbols.test.js +93 -0
  108. package/dist/src/debug/symbols.test.js.map +1 -0
  109. package/dist/src/debug/trace-writer.d.ts +55 -0
  110. package/dist/src/debug/trace-writer.d.ts.map +1 -0
  111. package/dist/src/debug/trace-writer.js +658 -0
  112. package/dist/src/debug/trace-writer.js.map +1 -0
  113. package/dist/src/debug/trace.d.ts +342 -0
  114. package/dist/src/debug/trace.d.ts.map +1 -0
  115. package/dist/src/debug/trace.js +446 -0
  116. package/dist/src/debug/trace.js.map +1 -0
  117. package/dist/src/devtools/devtools-protocol.d.ts +389 -0
  118. package/dist/src/devtools/devtools-protocol.d.ts.map +1 -0
  119. package/dist/src/devtools/devtools-protocol.js +2 -0
  120. package/dist/src/devtools/devtools-protocol.js.map +1 -0
  121. package/dist/src/devtools/devtools-server.browser.d.ts +23 -0
  122. package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -0
  123. package/dist/src/devtools/devtools-server.browser.js +33 -0
  124. package/dist/src/devtools/devtools-server.browser.js.map +1 -0
  125. package/dist/src/devtools/devtools-server.d.ts +66 -0
  126. package/dist/src/devtools/devtools-server.d.ts.map +1 -0
  127. package/dist/src/devtools/devtools-server.js +444 -0
  128. package/dist/src/devtools/devtools-server.js.map +1 -0
  129. package/dist/src/devtools/devtools-transport.d.ts +23 -0
  130. package/dist/src/devtools/devtools-transport.d.ts.map +1 -0
  131. package/dist/src/devtools/devtools-transport.js +114 -0
  132. package/dist/src/devtools/devtools-transport.js.map +1 -0
  133. package/dist/src/devtools-entry.browser.d.ts +4 -0
  134. package/dist/src/devtools-entry.browser.d.ts.map +1 -0
  135. package/dist/src/devtools-entry.browser.js +2 -0
  136. package/dist/src/devtools-entry.browser.js.map +1 -0
  137. package/dist/src/devtools-entry.d.ts +4 -0
  138. package/dist/src/devtools-entry.d.ts.map +1 -0
  139. package/dist/src/devtools-entry.js +2 -0
  140. package/dist/src/devtools-entry.js.map +1 -0
  141. package/dist/src/diagnostics.d.ts +34 -0
  142. package/dist/src/diagnostics.d.ts.map +1 -0
  143. package/dist/src/diagnostics.js +89 -0
  144. package/dist/src/diagnostics.js.map +1 -0
  145. package/dist/src/index.d.ts +3 -2
  146. package/dist/src/index.d.ts.map +1 -1
  147. package/dist/src/index.js +3 -2
  148. package/dist/src/index.js.map +1 -1
  149. package/dist/src/print-hook.d.ts +14 -0
  150. package/dist/src/print-hook.d.ts.map +1 -0
  151. package/dist/src/print-hook.js +10 -0
  152. package/dist/src/print-hook.js.map +1 -0
  153. package/dist/src/reactive-union-set.d.ts.map +1 -1
  154. package/dist/src/reactive-union-set.js +28 -3
  155. package/dist/src/reactive-union-set.js.map +1 -1
  156. package/dist/src/reactivity.d.ts +60 -7
  157. package/dist/src/reactivity.d.ts.map +1 -1
  158. package/dist/src/reactivity.js +308 -39
  159. package/dist/src/reactivity.js.map +1 -1
  160. package/dist/src/render-stack.d.ts +18 -1
  161. package/dist/src/render-stack.d.ts.map +1 -1
  162. package/dist/src/render-stack.js +61 -1
  163. package/dist/src/render-stack.js.map +1 -1
  164. package/dist/src/render.d.ts +8 -15
  165. package/dist/src/render.d.ts.map +1 -1
  166. package/dist/src/render.js +424 -109
  167. package/dist/src/render.js.map +1 -1
  168. package/dist/src/resource.d.ts.map +1 -1
  169. package/dist/src/resource.js +5 -0
  170. package/dist/src/resource.js.map +1 -1
  171. package/dist/src/scheduler.d.ts +13 -0
  172. package/dist/src/scheduler.d.ts.map +1 -1
  173. package/dist/src/scheduler.js +150 -13
  174. package/dist/src/scheduler.js.map +1 -1
  175. package/dist/src/symbols/basic-symbol.d.ts.map +1 -1
  176. package/dist/src/symbols/basic-symbol.js +6 -1
  177. package/dist/src/symbols/basic-symbol.js.map +1 -1
  178. package/dist/src/symbols/decl.d.ts.map +1 -1
  179. package/dist/src/symbols/decl.js +5 -1
  180. package/dist/src/symbols/decl.js.map +1 -1
  181. package/dist/src/symbols/output-scope.d.ts +2 -1
  182. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  183. package/dist/src/symbols/output-scope.js +13 -8
  184. package/dist/src/symbols/output-scope.js.map +1 -1
  185. package/dist/src/symbols/output-symbol.d.ts +1 -0
  186. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  187. package/dist/src/symbols/output-symbol.js +25 -8
  188. package/dist/src/symbols/output-symbol.js.map +1 -1
  189. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  190. package/dist/src/symbols/symbol-flow.js +24 -8
  191. package/dist/src/symbols/symbol-flow.js.map +1 -1
  192. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  193. package/dist/src/symbols/symbol-slot.js +15 -0
  194. package/dist/src/symbols/symbol-slot.js.map +1 -1
  195. package/dist/src/symbols/symbol-slot.test.d.ts +2 -0
  196. package/dist/src/symbols/symbol-slot.test.d.ts.map +1 -0
  197. package/dist/src/symbols/symbol-slot.test.js +35 -0
  198. package/dist/src/symbols/symbol-slot.test.js.map +1 -0
  199. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  200. package/dist/src/symbols/symbol-table.js +6 -5
  201. package/dist/src/symbols/symbol-table.js.map +1 -1
  202. package/dist/src/trace.d.ts +2 -0
  203. package/dist/src/trace.d.ts.map +1 -0
  204. package/dist/src/trace.js +2 -0
  205. package/dist/src/trace.js.map +1 -0
  206. package/dist/src/tracer.d.ts +2 -228
  207. package/dist/src/tracer.d.ts.map +1 -1
  208. package/dist/src/tracer.js +5 -298
  209. package/dist/src/tracer.js.map +1 -1
  210. package/dist/src/utils.d.ts.map +1 -1
  211. package/dist/src/utils.js +17 -9
  212. package/dist/src/utils.js.map +1 -1
  213. package/dist/test/components/append-file.test.d.ts.map +1 -1
  214. package/dist/test/components/append-file.test.js +18 -10
  215. package/dist/test/components/append-file.test.js.map +1 -1
  216. package/dist/test/components/template-file.test.d.ts.map +1 -1
  217. package/dist/test/components/template-file.test.js +6 -4
  218. package/dist/test/components/template-file.test.js.map +1 -1
  219. package/dist/test/lazy-isempty.test.d.ts +2 -0
  220. package/dist/test/lazy-isempty.test.d.ts.map +1 -0
  221. package/dist/test/lazy-isempty.test.js +89 -0
  222. package/dist/test/lazy-isempty.test.js.map +1 -0
  223. package/dist/test/reactive-union-set-disposers.test.d.ts +2 -0
  224. package/dist/test/reactive-union-set-disposers.test.d.ts.map +1 -0
  225. package/dist/test/reactive-union-set-disposers.test.js +98 -0
  226. package/dist/test/reactive-union-set-disposers.test.js.map +1 -0
  227. package/dist/test/reactivity/shallow-reactive.test.d.ts +2 -0
  228. package/dist/test/reactivity/shallow-reactive.test.d.ts.map +1 -0
  229. package/dist/test/reactivity/shallow-reactive.test.js +52 -0
  230. package/dist/test/reactivity/shallow-reactive.test.js.map +1 -0
  231. package/dist/test/rendering/basic.test.js +3 -0
  232. package/dist/test/rendering/basic.test.js.map +1 -1
  233. package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -1
  234. package/dist/test/rendering/print-render-stack.test.js +91 -98
  235. package/dist/test/rendering/print-render-stack.test.js.map +1 -1
  236. package/dist/test/scheduler-extended.test.d.ts +2 -0
  237. package/dist/test/scheduler-extended.test.d.ts.map +1 -0
  238. package/dist/test/scheduler-extended.test.js +96 -0
  239. package/dist/test/scheduler-extended.test.js.map +1 -0
  240. package/dist/test/scheduler.test.d.ts +2 -0
  241. package/dist/test/scheduler.test.d.ts.map +1 -0
  242. package/dist/test/scheduler.test.js +46 -0
  243. package/dist/test/scheduler.test.js.map +1 -0
  244. package/dist/testing/create-test-wrapper.d.ts +1 -1
  245. package/dist/testing/create-test-wrapper.d.ts.map +1 -1
  246. package/dist/testing/create-test-wrapper.js +1 -1
  247. package/dist/testing/create-test-wrapper.js.map +1 -1
  248. package/dist/testing/devtools-utils.d.ts +35 -0
  249. package/dist/testing/devtools-utils.d.ts.map +1 -0
  250. package/dist/testing/devtools-utils.js +162 -0
  251. package/dist/testing/devtools-utils.js.map +1 -0
  252. package/dist/testing/extend-expect.d.ts.map +1 -1
  253. package/dist/testing/extend-expect.js +63 -1
  254. package/dist/testing/extend-expect.js.map +1 -1
  255. package/dist/testing/render.d.ts +2 -2
  256. package/dist/testing/render.d.ts.map +1 -1
  257. package/dist/testing/render.js +2 -2
  258. package/dist/testing/render.js.map +1 -1
  259. package/dist/tsconfig.tsbuildinfo +1 -1
  260. package/package.json +21 -7
  261. package/scripts/copy-devtools-ui.mjs +26 -0
  262. package/src/binder.ts +117 -53
  263. package/src/components/AccessExpression.test.tsx +132 -0
  264. package/src/components/AccessExpression.tsx +344 -0
  265. package/src/components/AppendFile.tsx +14 -9
  266. package/src/components/Block.tsx +1 -1
  267. package/src/components/Declaration.tsx +2 -1
  268. package/src/components/For.tsx +14 -10
  269. package/src/components/List.tsx +7 -4
  270. package/src/components/Prose.tsx +1 -1
  271. package/src/components/Scope.tsx +6 -1
  272. package/src/components/SourceDirectory.tsx +1 -2
  273. package/src/components/Switch.tsx +11 -7
  274. package/src/components/TemplateFile.tsx +18 -9
  275. package/src/components/index.tsx +1 -0
  276. package/src/content-slot.tsx +7 -7
  277. package/src/context.ts +17 -6
  278. package/src/{debug.ts → debug/cli.ts} +114 -125
  279. package/src/debug/diagnostics.test.tsx +56 -0
  280. package/src/debug/effects.test.tsx +301 -0
  281. package/src/debug/effects.ts +531 -0
  282. package/src/debug/files.test.tsx +76 -0
  283. package/src/debug/files.ts +40 -0
  284. package/src/debug/index.ts +132 -0
  285. package/src/debug/message-format.test.tsx +759 -0
  286. package/src/debug/render-tree-orphans.test.tsx +344 -0
  287. package/src/debug/render.test.tsx +357 -0
  288. package/src/debug/render.ts +698 -0
  289. package/src/debug/serialize.ts +85 -0
  290. package/src/debug/symbols.test.tsx +105 -0
  291. package/src/debug/symbols.ts +322 -0
  292. package/src/debug/trace-writer.ts +969 -0
  293. package/src/debug/trace.ts +309 -0
  294. package/src/devtools/devtools-protocol.ts +497 -0
  295. package/src/devtools/devtools-server.browser.ts +62 -0
  296. package/src/devtools/devtools-server.ts +468 -0
  297. package/src/devtools/devtools-transport.ts +154 -0
  298. package/src/devtools-entry.browser.ts +48 -0
  299. package/src/devtools-entry.ts +48 -0
  300. package/src/diagnostics.ts +150 -0
  301. package/src/index.ts +2 -7
  302. package/src/print-hook.ts +22 -0
  303. package/src/reactive-union-set.ts +85 -44
  304. package/src/reactivity.ts +396 -58
  305. package/src/render-stack.ts +73 -1
  306. package/src/render.ts +544 -161
  307. package/src/resource.ts +28 -19
  308. package/src/scheduler.ts +209 -14
  309. package/src/symbols/basic-symbol.ts +6 -1
  310. package/src/symbols/decl.ts +5 -1
  311. package/src/symbols/output-scope.ts +21 -13
  312. package/src/symbols/output-symbol.ts +34 -14
  313. package/src/symbols/symbol-flow.ts +76 -39
  314. package/src/symbols/symbol-slot.test.tsx +41 -0
  315. package/src/symbols/symbol-slot.tsx +47 -20
  316. package/src/symbols/symbol-table.ts +6 -10
  317. package/src/trace.ts +1 -0
  318. package/src/tracer.ts +13 -242
  319. package/src/utils.tsx +31 -21
  320. package/temp/api.json +5700 -3015
  321. package/test/components/append-file.test.tsx +36 -29
  322. package/test/components/template-file.test.tsx +11 -11
  323. package/test/lazy-isempty.test.tsx +106 -0
  324. package/test/reactive-union-set-disposers.test.tsx +112 -0
  325. package/test/reactivity/shallow-reactive.test.tsx +56 -0
  326. package/test/rendering/basic.test.tsx +4 -0
  327. package/test/rendering/print-render-stack.test.tsx +52 -43
  328. package/test/scheduler-extended.test.tsx +122 -0
  329. package/test/scheduler.test.tsx +50 -0
  330. package/testing/create-test-wrapper.tsx +1 -1
  331. package/testing/devtools-utils.ts +245 -0
  332. package/testing/extend-expect.ts +89 -0
  333. package/testing/render.ts +2 -2
  334. package/testing/vitest.d.ts +9 -0
  335. package/dist/src/debug.d.ts +0 -14
  336. package/dist/src/debug.d.ts.map +0 -1
  337. package/dist/src/debug.js.map +0 -1
@@ -1,15 +1,122 @@
1
- import { isRef, ref } from "@vue/reactivity";
1
+ import { isRef } from "@vue/reactivity";
2
2
  import { doc } from "prettier";
3
3
  import prettier from "prettier/doc.js";
4
4
  import { useContext } from "./context.js";
5
5
  import { SourceFileContext } from "./context/source-file.js";
6
- import { effect, getContext, getElementCache, isCustomContext, root, untrack } from "./reactivity.js";
6
+ import { debug, getRenderNodeId, isDevtoolsConnected, isDevtoolsEnabled } from "./debug/index.js";
7
+ import { beginTransaction, closeTrace, commitTransaction, notifyDiagnosticsReport } from "./debug/trace-writer.js";
8
+ import { isTraceEnabled } from "./debug/trace.js";
9
+ import { attachDiagnosticsCollector, DiagnosticsCollector, emitDiagnostic, reportDiagnostics } from "./diagnostics.js";
10
+ import { isPrintHook, printHookTag } from "./print-hook.js";
11
+ import { effect, getContext, getElementCache, isCustomContext, onCleanup, ref, root, untrack } from "./reactivity.js";
7
12
  import { isRefkeyable, toRefkey } from "./refkey.js";
8
- import { popStack, printRenderStack, pushStack } from "./render-stack.js";
13
+ import { getRenderStackSnapshot, popStack, printRenderStack, pushStack } from "./render-stack.js";
9
14
  import { isComponentCreator, isRenderableObject, RENDERABLE } from "./runtime/component.js";
10
15
  import { isIntrinsicElement } from "./runtime/intrinsic.js";
11
- import { flushJobs, flushJobsAsync } from "./scheduler.js";
12
- import { trace, TracePhase } from "./tracer.js";
16
+ import { flushJobs, flushJobsAsync, waitForSignal } from "./scheduler.js";
17
+ const notifiedErrors = new WeakSet();
18
+
19
+ // ─────────────────────────────────────────────────────────────────────────────
20
+ // Deferred file printing: mark files dirty during render, print once at end
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+
23
+ const dirtyFiles = new Map();
24
+ const lastFlushTimeByFile = new Map();
25
+ const DEVTOOLS_FLUSH_INTERVAL_MS = 1000;
26
+ function flushDirtyFile(path) {
27
+ const entry = dirtyFiles.get(path);
28
+ if (!entry) return;
29
+ dirtyFiles.delete(path);
30
+ const contents = printTree(entry.renderNode, {
31
+ ...entry.printOptions,
32
+ insertFinalNewLine: entry.printOptions.insertFinalNewLine ?? true,
33
+ noFlush: true
34
+ });
35
+ debug.files.updated({
36
+ path: entry.path,
37
+ filetype: entry.filetype,
38
+ contents
39
+ });
40
+ }
41
+ function flushDirtyFiles() {
42
+ for (const path of [...dirtyFiles.keys()]) {
43
+ flushDirtyFile(path);
44
+ }
45
+ }
46
+ let lastRenderError = null;
47
+ function normalizeRenderError(error) {
48
+ if (error instanceof Error) {
49
+ return {
50
+ name: error.name || error.constructor?.name || "Error",
51
+ message: error.message || "",
52
+ stack: error.stack
53
+ };
54
+ }
55
+ if (error && typeof error === "object") {
56
+ const anyError = error;
57
+ return {
58
+ name: anyError.name || "Error",
59
+ message: anyError.message || String(error),
60
+ stack: anyError.stack
61
+ };
62
+ }
63
+ return {
64
+ name: "Error",
65
+ message: String(error)
66
+ };
67
+ }
68
+ function notifyRenderError(error) {
69
+ if (error && typeof error === "object") {
70
+ if (notifiedErrors.has(error)) return;
71
+ notifiedErrors.add(error);
72
+ }
73
+ if (lastRenderError) return;
74
+ const {
75
+ name,
76
+ message,
77
+ stack
78
+ } = normalizeRenderError(error);
79
+ const componentStack = getRenderStackSnapshot().map(entry => {
80
+ const renderNode = entry.context?.meta?.renderNode;
81
+ const renderNodeId = renderNode ? getRenderNodeId(renderNode) : undefined;
82
+ return {
83
+ name: entry.displayName,
84
+ props: entry.props,
85
+ renderNodeId,
86
+ source: entry.source
87
+ };
88
+ });
89
+
90
+ // Output to console
91
+ printRenderStack(error);
92
+
93
+ // Send to devtools if enabled
94
+ debug.render.error({
95
+ name,
96
+ message,
97
+ stack
98
+ }, componentStack);
99
+
100
+ // Store for diagnostics
101
+ lastRenderError = {
102
+ error: {
103
+ name,
104
+ message,
105
+ stack
106
+ },
107
+ componentStack
108
+ };
109
+ const lastEntry = componentStack.at(-1);
110
+ emitDiagnostic({
111
+ severity: "error",
112
+ message: `${name}: ${message}`,
113
+ source: lastEntry?.source
114
+ });
115
+ }
116
+ function reportLastRenderError() {
117
+ // Error already reported in notifyRenderError via debug.renderError
118
+ lastRenderError = null;
119
+ }
13
120
  const {
14
121
  builders: {
15
122
  align,
@@ -112,10 +219,24 @@ const {
112
219
  */
113
220
 
114
221
  const nodesToContext = new WeakMap();
222
+ const diagnosticsByTree = new WeakMap();
115
223
  export function getContextForRenderNode(node) {
116
224
  return nodesToContext.get(node);
117
225
  }
118
- export const printHookTag = Symbol();
226
+ export function getDiagnosticsForTree(tree) {
227
+ return diagnosticsByTree.get(tree)?.getDiagnostics() ?? [];
228
+ }
229
+ function reportDiagnosticsForTree(tree) {
230
+ const diagnostics = diagnosticsByTree.get(tree);
231
+ if (!diagnostics) return;
232
+ const entries = diagnostics.getDiagnostics();
233
+ if (entries.length === 0) return;
234
+ reportDiagnostics(diagnostics);
235
+ notifyDiagnosticsReport(entries);
236
+ }
237
+
238
+ // Re-export from print-hook.ts to maintain backwards compatibility
239
+ export { isPrintHook, printHookTag } from "./print-hook.js";
119
240
  export function createRenderTreeHook(subtree, hooks) {
120
241
  return {
121
242
  [printHookTag]: true,
@@ -123,9 +244,7 @@ export function createRenderTreeHook(subtree, hooks) {
123
244
  ...hooks
124
245
  };
125
246
  }
126
- export function isPrintHook(type) {
127
- return typeof type === "object" && type !== null && printHookTag in type;
128
- }
247
+
129
248
  /**
130
249
  * Render a component tree to source directories and files. Will ensure that
131
250
  * all non-async scheduled jobs are completed before returning. If async jobs
@@ -135,7 +254,18 @@ export function isPrintHook(type) {
135
254
  export function render(children, options) {
136
255
  const tree = renderTree(children);
137
256
  flushJobs();
138
- return sourceFilesForTree(tree, options);
257
+ const output = sourceFilesForTree(tree, options);
258
+ flushDirtyFiles();
259
+ reportDiagnosticsForTree(tree);
260
+ reportLastRenderError();
261
+ debug.render.complete();
262
+ // Only close the trace DB when devtools is NOT running. When devtools is
263
+ // active the DB must remain open for post-render reactive updates.
264
+ if (isTraceEnabled() && !isDevtoolsEnabled()) closeTrace();
265
+ if (isDevtoolsEnabled()) {
266
+ void waitForSignal();
267
+ }
268
+ return output;
139
269
  }
140
270
 
141
271
  /**
@@ -143,20 +273,19 @@ export function render(children, options) {
143
273
  * scheduled jobs are completed before returning.
144
274
  */
145
275
  export async function renderAsync(children, options) {
276
+ await debug.prepare();
146
277
  const tree = renderTree(children);
147
- return sourceFilesForTreeAsync(tree, options);
148
- }
149
-
150
- /**
151
- * Convert a rendered text tree to source directories and files. Will ensure that
152
- * all scheduled jobs are completed, including async ones.
153
- */
154
- export async function sourceFilesForTreeAsync(tree, options) {
155
- // if we await here, we ensure all reactive updates are flushed.
156
- // sourceFilesForTree will flush again, but won't find anything, because tree
157
- // printing won't schedule anything.
278
+ // Ensure all reactive updates are flushed before printing.
158
279
  await flushJobsAsync();
159
- return sourceFilesForTree(tree, options);
280
+ const output = sourceFilesForTree(tree, options);
281
+ flushDirtyFiles();
282
+ reportDiagnosticsForTree(tree);
283
+ reportLastRenderError();
284
+ debug.render.complete();
285
+ // Only close the trace DB when devtools is NOT running. When devtools is
286
+ // active the DB must remain open for post-render reactive updates.
287
+ if (isTraceEnabled() && !isDevtoolsEnabled()) closeTrace();
288
+ return output;
160
289
  }
161
290
 
162
291
  /**
@@ -167,7 +296,15 @@ export function sourceFilesForTree(tree, options) {
167
296
  let rootDirectory = undefined;
168
297
  collectSourceFiles(undefined, tree);
169
298
  if (!rootDirectory) {
170
- throw new Error("No root directory found. Make sure you are using the Output component.");
299
+ emitDiagnostic({
300
+ severity: "error",
301
+ message: "No root directory found. Make sure you are using the output component."
302
+ });
303
+ return {
304
+ kind: "directory",
305
+ path: "",
306
+ contents: []
307
+ };
171
308
  }
172
309
  return rootDirectory;
173
310
  function collectSourceFiles(currentDirectory, root) {
@@ -230,27 +367,43 @@ export function sourceFilesForTree(tree, options) {
230
367
  }
231
368
  export function renderTree(children) {
232
369
  const rootElem = [];
370
+ const diagnostics = new DiagnosticsCollector();
371
+ lastRenderError = null;
372
+ debug.effect.reset();
373
+ debug.symbols.reset();
374
+ debug.files.reset();
375
+ dirtyFiles.clear();
376
+ lastFlushTimeByFile.clear();
377
+ debug.render.initialize(rootElem);
378
+ if (isTraceEnabled()) beginTransaction();
233
379
  try {
234
380
  root(() => {
381
+ attachDiagnosticsCollector(diagnostics);
235
382
  renderWorker(rootElem, children);
236
383
  });
237
384
  } catch (e) {
238
- printRenderStack();
385
+ if (isTraceEnabled()) commitTransaction();
386
+ flushDirtyFiles();
387
+ notifyRenderError(e);
388
+ reportLastRenderError();
239
389
  throw e;
240
390
  }
391
+ if (isTraceEnabled()) commitTransaction();
392
+ diagnosticsByTree.set(rootElem, diagnostics);
241
393
  return rootElem;
242
394
  }
243
395
  function renderWorker(node, children) {
396
+ if (lastRenderError) return;
244
397
  if (!getContext()) {
245
398
  throw new Error("Cannot render without a context. Make sure you are using the Output component.");
246
399
  }
247
- trace(TracePhase.render.worker, () => dumpChildren(children));
248
400
  if (Array.isArray(node)) {
249
401
  nodesToContext.set(node, getContext());
250
402
  }
251
403
  if (Array.isArray(children)) {
252
404
  for (const child of children.flat(Infinity)) {
253
405
  appendChild(node, child);
406
+ if (lastRenderError) break;
254
407
  }
255
408
  } else {
256
409
  appendChild(node, children);
@@ -264,10 +417,11 @@ export function notifyContentState() {
264
417
  untrack(() => {
265
418
  const startContext = getContext();
266
419
  if (startContext.childrenWithContent === 0) {
267
- if (startContext.isEmpty.value === true) {
420
+ if (startContext._lastEmpty) {
268
421
  // it was already empty, no work to do.
269
422
  return;
270
423
  }
424
+ startContext._lastEmpty = true;
271
425
  if (startContext.isEmpty) {
272
426
  startContext.isEmpty.value = true;
273
427
  }
@@ -279,17 +433,23 @@ export function notifyContentState() {
279
433
  break;
280
434
  }
281
435
  current.childrenWithContent--;
436
+ if (current.childrenWithContent > 0) {
437
+ // This isn't the last content so we have no work to do
438
+ break;
439
+ }
440
+ current._lastEmpty = true;
282
441
  if (current.isEmpty) {
283
442
  current.isEmpty.value = true;
284
443
  }
285
444
  current = current.owner;
286
445
  }
287
446
  } else {
288
- if (startContext.isEmpty.value === false) {
447
+ if (!startContext._lastEmpty) {
289
448
  // it was already non-empty, no work to do.
290
449
  return;
291
450
  }
292
- if (startContext.isEmpty && startContext.isEmpty.value) {
451
+ startContext._lastEmpty = false;
452
+ if (startContext.isEmpty) {
293
453
  startContext.isEmpty.value = false;
294
454
  }
295
455
 
@@ -301,7 +461,8 @@ export function notifyContentState() {
301
461
  // This isn't the first content so we have no work to do
302
462
  break;
303
463
  }
304
- if (current.isEmpty && current.isEmpty.value) {
464
+ current._lastEmpty = false;
465
+ if (current.isEmpty) {
305
466
  current.isEmpty.value = false;
306
467
  }
307
468
  current = current.owner;
@@ -310,74 +471,98 @@ export function notifyContentState() {
310
471
  });
311
472
  }
312
473
  function appendChild(node, rawChild) {
313
- trace(TracePhase.render.appendChild, () => debugPrintChild(rawChild));
474
+ if (lastRenderError) return;
314
475
  const child = normalizeChild(rawChild);
315
476
  if (typeof child === "string") {
316
477
  if (child !== "") {
317
478
  contentAdded();
479
+ debug.render.appendTextNode(node, node.length, child);
318
480
  }
319
481
  node.push(child);
320
482
  } else {
321
483
  const cache = getElementCache();
322
484
  if (cache.has(child)) {
323
- trace(TracePhase.render.appendChild, () => "Cached: " + debugPrintChild(child));
324
- node.push(cache.get(child));
485
+ const cachedNode = cache.get(child);
486
+ // recordSubtreeAdded detects cached nodes automatically and re-adds their children
487
+ if (isCustomContext(child)) {
488
+ debug.render.appendCustomContext(node, cachedNode);
489
+ } else {
490
+ debug.render.appendFragmentChild(node, cachedNode);
491
+ }
492
+ node.push(cachedNode);
325
493
  return;
326
494
  }
327
495
  if (isCustomContext(child)) {
328
- trace(TracePhase.render.appendChild, () => "CustomContext: " + debugPrintChild(child));
496
+ const newNode = [];
497
+ debug.render.appendCustomContext(node, newNode);
329
498
  child.useCustomContext(children => {
330
- const newNode = [];
331
499
  renderWorker(newNode, children);
332
500
  node.push(newNode);
333
501
  cache.set(child, newNode);
334
502
  notifyContentState();
503
+ notifyFileUpdateForNode(node);
335
504
  });
336
505
  } else if (isIntrinsicElement(child)) {
337
- trace(TracePhase.render.appendChild, () => "IntrinsicElement: " + debugPrintChild(child));
338
506
  // don't need a new context here because intrinsics are never reactive
507
+ const intrinsic = child;
339
508
  const newNode = [];
340
509
  function formatHookWithChildren(command) {
341
- node.push(createRenderTreeHook(newNode, {
510
+ const hook = createRenderTreeHook(newNode, {
342
511
  print(tree, print) {
343
512
  return command(print(tree));
344
513
  }
345
- }));
514
+ });
515
+ debug.render.appendPrintHook(node, node.length, hook, intrinsic.name, newNode);
516
+ node.push(hook);
346
517
  renderWorker(newNode, child.props.children);
518
+ notifyFileUpdateForNode(node);
347
519
  }
348
520
  function formatHook(command) {
349
- return node.push(createRenderTreeHook(newNode, {
521
+ const hook = createRenderTreeHook(newNode, {
350
522
  print() {
351
523
  return command;
352
524
  }
353
- }));
525
+ });
526
+ debug.render.appendPrintHook(node, node.length, hook, intrinsic.name);
527
+ node.push(hook);
528
+ return hook;
354
529
  }
355
530
  switch (child.name) {
356
531
  case "indent":
357
532
  return formatHookWithChildren(indent);
358
533
  case "indentIfBreak":
359
- node.push(createRenderTreeHook(newNode, {
360
- print(tree, print) {
361
- return indentIfBreak(print(tree), {
362
- groupId: child.props.groupId,
363
- negate: child.props.negate
364
- });
365
- }
366
- }));
534
+ {
535
+ const hook = createRenderTreeHook(newNode, {
536
+ print(tree, print) {
537
+ return indentIfBreak(print(tree), {
538
+ groupId: child.props.groupId,
539
+ negate: child.props.negate
540
+ });
541
+ }
542
+ });
543
+ debug.render.appendPrintHook(node, node.length, hook, intrinsic.name, newNode);
544
+ node.push(hook);
545
+ }
367
546
  renderWorker(newNode, child.props.children);
547
+ notifyFileUpdateForNode(node);
368
548
  return;
369
549
  case "fill":
370
550
  return formatHookWithChildren(fill);
371
551
  case "group":
372
- node.push(createRenderTreeHook(newNode, {
373
- print(tree, print) {
374
- return group(print(tree), {
375
- id: child.props.id,
376
- shouldBreak: child.props.shouldBreak
377
- });
378
- }
379
- }));
552
+ {
553
+ const hook = createRenderTreeHook(newNode, {
554
+ print(tree, print) {
555
+ return group(print(tree), {
556
+ id: child.props.id,
557
+ shouldBreak: child.props.shouldBreak
558
+ });
559
+ }
560
+ });
561
+ debug.render.appendPrintHook(node, node.length, hook, intrinsic.name, newNode);
562
+ node.push(hook);
563
+ }
380
564
  renderWorker(newNode, child.props.children);
565
+ notifyFileUpdateForNode(node);
381
566
  return;
382
567
  case "line":
383
568
  case "br":
@@ -392,12 +577,17 @@ function appendChild(node, rawChild) {
392
577
  case "lbr":
393
578
  return formatHook(literalline);
394
579
  case "align":
395
- node.push(createRenderTreeHook(newNode, {
396
- print(tree, print) {
397
- return align(child.props.width ?? child.props.string, print(tree));
398
- }
399
- }));
580
+ {
581
+ const hook = createRenderTreeHook(newNode, {
582
+ print(tree, print) {
583
+ return align(child.props.width ?? child.props.string, print(tree));
584
+ }
585
+ });
586
+ debug.render.appendPrintHook(node, node.length, hook, intrinsic.name, newNode);
587
+ node.push(hook);
588
+ }
400
589
  renderWorker(newNode, child.props.children);
590
+ notifyFileUpdateForNode(node);
401
591
  return;
402
592
  case "lineSuffix":
403
593
  return formatHookWithChildren(lineSuffix);
@@ -412,59 +602,206 @@ function appendChild(node, rawChild) {
412
602
  case "markAsRoot":
413
603
  return formatHookWithChildren(markAsRoot);
414
604
  case "ifBreak":
415
- node.push(createRenderTreeHook(newNode, {
416
- print(tree, print) {
417
- return ifBreak(print(tree[0]), print(tree[1]));
418
- }
419
- }));
605
+ {
606
+ const hook = createRenderTreeHook(newNode, {
607
+ print(tree, print) {
608
+ return ifBreak(print(tree[0]), print(tree[1]));
609
+ }
610
+ });
611
+ debug.render.appendPrintHook(node, node.length, hook, intrinsic.name, newNode);
612
+ node.push(hook);
613
+ }
420
614
  newNode.push([], []);
615
+ debug.render.appendFragmentChild(newNode, newNode[0]);
616
+ debug.render.appendFragmentChild(newNode, newNode[1]);
421
617
  renderWorker(newNode[0], child.props.children);
422
618
  renderWorker(newNode[1], child.props.flatContents);
619
+ notifyFileUpdateForNode(node);
423
620
  return;
424
621
  default:
425
622
  throw new Error("Unknown intrinsic element");
426
623
  }
427
624
  } else if (isComponentCreator(child)) {
625
+ const index = node.length;
626
+ const rerenderToken = isDevtoolsEnabled() ? ref(0, {
627
+ isInfrastructure: true
628
+ }) : undefined;
629
+ const breakNext = isDevtoolsEnabled() ? ref(false, {
630
+ isInfrastructure: true
631
+ }) : undefined;
428
632
  // todo: remove this effect (only needed for context, not needed for anything else)
429
633
  effect(() => {
430
- trace(TracePhase.render.appendChild, () => "Component: " + debugPrintChild(child));
634
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
635
+ rerenderToken?.value;
431
636
  const context = getContext();
432
637
  context.childrenWithContent = 0;
433
- context.isEmpty ??= ref(true);
434
638
  if (context) context.componentOwner = child;
435
- const componentRoot = [];
639
+ const existing = node[index];
640
+ const componentRoot = Array.isArray(existing) ? existing : [];
641
+ context.meta ??= {};
642
+ context.meta.renderNode = componentRoot;
643
+ const propsSource = child.props ?? undefined;
644
+ const debugSession = debug.render.beginComponent({
645
+ parent: node,
646
+ index,
647
+ node: componentRoot,
648
+ component: child,
649
+ propsSource,
650
+ source: child.source,
651
+ isExisting: Array.isArray(existing),
652
+ actions: {
653
+ rerender: rerenderToken ? () => {
654
+ lastRenderError = null;
655
+ rerenderToken.value++;
656
+ } : () => {},
657
+ rerenderAndBreak: breakNext && rerenderToken ? () => {
658
+ lastRenderError = null;
659
+ breakNext.value = true;
660
+ rerenderToken.value++;
661
+ } : () => {}
662
+ }
663
+ });
664
+ if (Array.isArray(existing)) {
665
+ componentRoot.length = 0;
666
+ }
436
667
  pushStack(child.component, child.props, child.source);
437
- renderWorker(componentRoot, untrack(child));
438
- popStack();
439
- node.push(componentRoot);
668
+ let renderFailed = false;
669
+ let childResult;
670
+ try {
671
+ childResult = untrack(() => {
672
+ const shouldBreak = breakNext?.value ?? false;
673
+ if (shouldBreak) {
674
+ breakNext.value = false;
675
+ // eslint-disable-next-line no-debugger
676
+ debugger;
677
+ }
678
+ return child();
679
+ });
680
+ } catch (error) {
681
+ notifyRenderError(error);
682
+ renderFailed = true;
683
+ throw error;
684
+ }
685
+ try {
686
+ if (context?.meta?.directory) {
687
+ debugSession.recordDirectory(context.meta.directory.path);
688
+ }
689
+ if (context?.meta?.sourceFile) {
690
+ context.meta.renderNode = componentRoot;
691
+ debugSession.recordFile(context.meta.sourceFile.path, context.meta.sourceFile.filetype);
692
+ context.meta.sourceFileReady = false;
693
+ }
694
+ if (!renderFailed) {
695
+ renderWorker(componentRoot, childResult);
696
+ }
697
+ } finally {
698
+ popStack();
699
+ }
700
+ if (renderFailed) {
701
+ node[index] = componentRoot;
702
+ cache.set(child, componentRoot);
703
+ notifyFileUpdateForNode(node);
704
+ notifyContentState();
705
+ onCleanup(() => debugSession.dispose());
706
+ return;
707
+ }
708
+ if (context?.meta?.sourceFile) {
709
+ context.meta.sourceFileReady = true;
710
+ notifyFileUpdateForNode(componentRoot);
711
+ }
712
+ node[index] = componentRoot;
440
713
  cache.set(child, componentRoot);
441
714
  notifyContentState();
442
- trace(TracePhase.render.appendChild, () => "Component done: " + debugPrintChild(child) + ", empty: " + context.isEmpty.value);
715
+ onCleanup(() => debugSession.dispose());
716
+ }, undefined, {
717
+ debug: {
718
+ name: `render:${child.component.name || "Anonymous"}`,
719
+ type: "render"
720
+ }
443
721
  });
444
722
  } else if (typeof child === "function") {
445
- trace(TracePhase.render.appendChild, () => "Memo: " + child.toString());
446
723
  const index = node.length;
447
724
  effect(() => {
448
- trace(TracePhase.render.renderEffect, () => "");
449
- let res = child();
450
- while (typeof res === "function" && !isComponentCreator(res)) {
451
- res = res();
725
+ let res;
726
+ let renderFailed = false;
727
+ try {
728
+ res = child();
729
+ while (typeof res === "function" && !isComponentCreator(res)) {
730
+ res = res();
731
+ }
732
+ } catch (error) {
733
+ notifyRenderError(error);
734
+ renderFailed = true;
735
+ throw error;
452
736
  }
453
737
  const context = getContext();
454
738
  context.childrenWithContent = 0;
455
- context.isEmpty ??= ref(true);
456
- const newNodes = [];
457
- renderWorker(newNodes, res);
458
- node[index] = newNodes;
459
- cache.set(child, newNodes);
739
+ const existing = node[index];
740
+ const memoNode = Array.isArray(existing) ? existing : [];
741
+ debug.render.prepareMemoNode(node, memoNode, Array.isArray(existing));
742
+ if (Array.isArray(existing)) {
743
+ memoNode.length = 0;
744
+ }
745
+ if (!renderFailed) {
746
+ renderWorker(memoNode, res);
747
+ }
748
+ node[index] = memoNode;
749
+ cache.set(child, memoNode);
750
+ notifyFileUpdateForNode(node);
460
751
  notifyContentState();
461
- return newNodes;
752
+ return memoNode;
753
+ }, undefined, {
754
+ debug: {
755
+ name: `render:memo:${child.name || "anonymous"}`,
756
+ type: "render"
757
+ }
462
758
  });
463
759
  } else {
464
760
  throw new Error("Unexpected child type");
465
761
  }
466
762
  }
467
763
  }
764
+ function findSourceFileContext(node) {
765
+ let context = getContextForRenderNode(node) ?? null;
766
+ while (context) {
767
+ if (context.meta?.sourceFile) return context;
768
+ context = context.owner;
769
+ }
770
+ return undefined;
771
+ }
772
+ function notifyFileUpdateForNode(node) {
773
+ // Only track when devtools or trace are actually enabled
774
+ if (!isDevtoolsEnabled() && !isTraceEnabled()) return;
775
+ const context = findSourceFileContext(node);
776
+ if (!context?.meta?.sourceFile) return;
777
+ if (context.meta.sourceFileReady === false) return;
778
+ const sourceFile = context.meta.sourceFile;
779
+ const renderNode = context.meta.renderNode ?? node;
780
+
781
+ // Mark this file as dirty — defer the expensive printTree to end of render
782
+ dirtyFiles.set(sourceFile.path, {
783
+ renderNode,
784
+ printOptions: {
785
+ printWidth: context.meta?.printOptions?.printWidth,
786
+ tabWidth: context.meta?.printOptions?.tabWidth,
787
+ useTabs: context.meta?.printOptions?.useTabs,
788
+ insertFinalNewLine: context.meta?.printOptions?.insertFinalNewLine
789
+ },
790
+ path: sourceFile.path,
791
+ filetype: sourceFile.filetype
792
+ });
793
+
794
+ // When a devtools client is connected, throttle file flushing to ~1s per file
795
+ // so the user can watch content build up during rendering.
796
+ if (isDevtoolsConnected()) {
797
+ const now = Date.now();
798
+ const lastFlush = lastFlushTimeByFile.get(sourceFile.path) ?? 0;
799
+ if (now - lastFlush >= DEVTOOLS_FLUSH_INTERVAL_MS) {
800
+ lastFlushTimeByFile.set(sourceFile.path, now);
801
+ flushDirtyFile(sourceFile.path);
802
+ }
803
+ }
804
+ }
468
805
  function normalizeChild(child) {
469
806
  if (Array.isArray(child)) {
470
807
  return child.map(normalizeChild);
@@ -496,29 +833,6 @@ function normalizeChild(child) {
496
833
  return String(child);
497
834
  }
498
835
  }
499
- function dumpChildren(children) {
500
- if (Array.isArray(children)) {
501
- return `[ ${children.map(debugPrintChild).join(", ")} ]`;
502
- }
503
- return debugPrintChild(children);
504
- }
505
- function debugPrintChild(child) {
506
- if (isComponentCreator(child)) {
507
- return "<" + child.component.name + ">";
508
- } else if (typeof child === "function") {
509
- return "$memo";
510
- } else if (isRef(child)) {
511
- return "$ref";
512
- } else if (isIntrinsicElement(child)) {
513
- return `<${child.name}>`;
514
- } else if (isRenderableObject(child)) {
515
- return `CustomChildElement(${JSON.stringify(child)})`;
516
- } else if (isRefkeyable(child)) {
517
- return `refkey`;
518
- } else {
519
- return JSON.stringify(child);
520
- }
521
- }
522
836
  const defaultPrintTreeOptions = {
523
837
  printWidth: 80,
524
838
  tabWidth: 2
@@ -533,9 +847,10 @@ export function printTree(tree, options) {
533
847
  ...defaultPrintTreeOptions,
534
848
  ...Object.fromEntries(Object.entries(options ?? {}).filter(([_, v]) => v !== undefined))
535
849
  };
536
-
537
- // make sure queue is empty
538
- flushJobs();
850
+ if (!options.noFlush) {
851
+ // make sure queue is empty
852
+ flushJobs();
853
+ }
539
854
  const d = printTreeWorker(tree);
540
855
  const result = doc.printer.printDocToString(d, options).formatted;
541
856
  return options.insertFinalNewLine && !result.endsWith("\n") ? `${result}\n` : result;