@alloy-js/core 0.23.0-dev.0 → 0.23.0-dev.10

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 (316) hide show
  1. package/CHANGELOG.md +0 -22
  2. package/dist/devtools/index.html +68 -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 +55 -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/Prose.js +2 -2
  24. package/dist/src/components/Prose.js.map +1 -1
  25. package/dist/src/components/Scope.d.ts.map +1 -1
  26. package/dist/src/components/Scope.js +6 -1
  27. package/dist/src/components/Scope.js.map +1 -1
  28. package/dist/src/components/SourceDirectory.d.ts.map +1 -1
  29. package/dist/src/components/SourceDirectory.js +1 -2
  30. package/dist/src/components/SourceDirectory.js.map +1 -1
  31. package/dist/src/components/TemplateFile.d.ts.map +1 -1
  32. package/dist/src/components/TemplateFile.js +18 -3
  33. package/dist/src/components/TemplateFile.js.map +1 -1
  34. package/dist/src/components/index.d.ts +1 -0
  35. package/dist/src/components/index.d.ts.map +1 -1
  36. package/dist/src/components/index.js +1 -0
  37. package/dist/src/components/index.js.map +1 -1
  38. package/dist/src/content-slot.d.ts.map +1 -1
  39. package/dist/src/content-slot.js +7 -6
  40. package/dist/src/content-slot.js.map +1 -1
  41. package/dist/src/context.d.ts.map +1 -1
  42. package/dist/src/context.js +10 -3
  43. package/dist/src/context.js.map +1 -1
  44. package/dist/src/debug/cli.d.ts +6 -0
  45. package/dist/src/debug/cli.d.ts.map +1 -0
  46. package/dist/src/{debug.js → debug/cli.js} +78 -84
  47. package/dist/src/debug/cli.js.map +1 -0
  48. package/dist/src/debug/diagnostics.test.d.ts +2 -0
  49. package/dist/src/debug/diagnostics.test.d.ts.map +1 -0
  50. package/dist/src/debug/diagnostics.test.js +45 -0
  51. package/dist/src/debug/diagnostics.test.js.map +1 -0
  52. package/dist/src/debug/effects.d.ts +73 -0
  53. package/dist/src/debug/effects.d.ts.map +1 -0
  54. package/dist/src/debug/effects.js +228 -0
  55. package/dist/src/debug/effects.js.map +1 -0
  56. package/dist/src/debug/effects.test.d.ts +2 -0
  57. package/dist/src/debug/effects.test.d.ts.map +1 -0
  58. package/dist/src/debug/effects.test.js +84 -0
  59. package/dist/src/debug/effects.test.js.map +1 -0
  60. package/dist/src/debug/files.d.ts +14 -0
  61. package/dist/src/debug/files.d.ts.map +1 -0
  62. package/dist/src/debug/files.js +40 -0
  63. package/dist/src/debug/files.js.map +1 -0
  64. package/dist/src/debug/files.test.d.ts +2 -0
  65. package/dist/src/debug/files.test.d.ts.map +1 -0
  66. package/dist/src/debug/files.test.js +89 -0
  67. package/dist/src/debug/files.test.js.map +1 -0
  68. package/dist/src/debug/index.d.ts +61 -0
  69. package/dist/src/debug/index.d.ts.map +1 -0
  70. package/dist/src/debug/index.js +69 -0
  71. package/dist/src/debug/index.js.map +1 -0
  72. package/dist/src/debug/render.d.ts +57 -0
  73. package/dist/src/debug/render.d.ts.map +1 -0
  74. package/dist/src/debug/render.js +519 -0
  75. package/dist/src/debug/render.js.map +1 -0
  76. package/dist/src/debug/render.test.d.ts +2 -0
  77. package/dist/src/debug/render.test.d.ts.map +1 -0
  78. package/dist/src/debug/render.test.js +328 -0
  79. package/dist/src/debug/render.test.js.map +1 -0
  80. package/dist/src/debug/serialize.d.ts +9 -0
  81. package/dist/src/debug/serialize.d.ts.map +1 -0
  82. package/dist/src/debug/serialize.js +70 -0
  83. package/dist/src/debug/serialize.js.map +1 -0
  84. package/dist/src/debug/symbols.d.ts +15 -0
  85. package/dist/src/debug/symbols.d.ts.map +1 -0
  86. package/dist/src/debug/symbols.js +173 -0
  87. package/dist/src/debug/symbols.js.map +1 -0
  88. package/dist/src/debug/symbols.test.d.ts +2 -0
  89. package/dist/src/debug/symbols.test.d.ts.map +1 -0
  90. package/dist/src/debug/symbols.test.js +104 -0
  91. package/dist/src/debug/symbols.test.js.map +1 -0
  92. package/dist/src/debug/trace.d.ts +342 -0
  93. package/dist/src/debug/trace.d.ts.map +1 -0
  94. package/dist/src/debug/trace.js +443 -0
  95. package/dist/src/debug/trace.js.map +1 -0
  96. package/dist/src/devtools/devtools-protocol.d.ts +232 -0
  97. package/dist/src/devtools/devtools-protocol.d.ts.map +1 -0
  98. package/dist/src/devtools/devtools-protocol.js +2 -0
  99. package/dist/src/devtools/devtools-protocol.js.map +1 -0
  100. package/dist/src/devtools/devtools-server.browser.d.ts +28 -0
  101. package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -0
  102. package/dist/src/devtools/devtools-server.browser.js +36 -0
  103. package/dist/src/devtools/devtools-server.browser.js.map +1 -0
  104. package/dist/src/devtools/devtools-server.d.ts +72 -0
  105. package/dist/src/devtools/devtools-server.d.ts.map +1 -0
  106. package/dist/src/devtools/devtools-server.js +256 -0
  107. package/dist/src/devtools/devtools-server.js.map +1 -0
  108. package/dist/src/devtools/devtools-transport.d.ts +23 -0
  109. package/dist/src/devtools/devtools-transport.d.ts.map +1 -0
  110. package/dist/src/devtools/devtools-transport.js +114 -0
  111. package/dist/src/devtools/devtools-transport.js.map +1 -0
  112. package/dist/src/devtools-entry.browser.d.ts +4 -0
  113. package/dist/src/devtools-entry.browser.d.ts.map +1 -0
  114. package/dist/src/devtools-entry.browser.js +2 -0
  115. package/dist/src/devtools-entry.browser.js.map +1 -0
  116. package/dist/src/devtools-entry.d.ts +4 -0
  117. package/dist/src/devtools-entry.d.ts.map +1 -0
  118. package/dist/src/devtools-entry.js +2 -0
  119. package/dist/src/devtools-entry.js.map +1 -0
  120. package/dist/src/diagnostics.d.ts +34 -0
  121. package/dist/src/diagnostics.d.ts.map +1 -0
  122. package/dist/src/diagnostics.js +89 -0
  123. package/dist/src/diagnostics.js.map +1 -0
  124. package/dist/src/index.d.ts +3 -2
  125. package/dist/src/index.d.ts.map +1 -1
  126. package/dist/src/index.js +3 -2
  127. package/dist/src/index.js.map +1 -1
  128. package/dist/src/print-hook.d.ts +14 -0
  129. package/dist/src/print-hook.d.ts.map +1 -0
  130. package/dist/src/print-hook.js +10 -0
  131. package/dist/src/print-hook.js.map +1 -0
  132. package/dist/src/reactive-union-set.d.ts.map +1 -1
  133. package/dist/src/reactive-union-set.js +28 -3
  134. package/dist/src/reactive-union-set.js.map +1 -1
  135. package/dist/src/reactivity.d.ts +50 -8
  136. package/dist/src/reactivity.d.ts.map +1 -1
  137. package/dist/src/reactivity.js +225 -39
  138. package/dist/src/reactivity.js.map +1 -1
  139. package/dist/src/render-stack.d.ts +30 -0
  140. package/dist/src/render-stack.d.ts.map +1 -0
  141. package/dist/src/render-stack.js +251 -0
  142. package/dist/src/render-stack.js.map +1 -0
  143. package/dist/src/render.d.ts +9 -19
  144. package/dist/src/render.d.ts.map +1 -1
  145. package/dist/src/render.js +371 -159
  146. package/dist/src/render.js.map +1 -1
  147. package/dist/src/resource.d.ts.map +1 -1
  148. package/dist/src/resource.js +5 -0
  149. package/dist/src/resource.js.map +1 -1
  150. package/dist/src/runtime/component.d.ts +7 -1
  151. package/dist/src/runtime/component.d.ts.map +1 -1
  152. package/dist/src/runtime/component.js +4 -1
  153. package/dist/src/runtime/component.js.map +1 -1
  154. package/dist/src/scheduler.d.ts +8 -0
  155. package/dist/src/scheduler.d.ts.map +1 -1
  156. package/dist/src/scheduler.js +69 -3
  157. package/dist/src/scheduler.js.map +1 -1
  158. package/dist/src/symbols/basic-symbol.d.ts.map +1 -1
  159. package/dist/src/symbols/basic-symbol.js +6 -1
  160. package/dist/src/symbols/basic-symbol.js.map +1 -1
  161. package/dist/src/symbols/decl.d.ts.map +1 -1
  162. package/dist/src/symbols/decl.js +5 -1
  163. package/dist/src/symbols/decl.js.map +1 -1
  164. package/dist/src/symbols/output-scope.d.ts +2 -1
  165. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  166. package/dist/src/symbols/output-scope.js +13 -8
  167. package/dist/src/symbols/output-scope.js.map +1 -1
  168. package/dist/src/symbols/output-symbol.d.ts +1 -0
  169. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  170. package/dist/src/symbols/output-symbol.js +25 -8
  171. package/dist/src/symbols/output-symbol.js.map +1 -1
  172. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  173. package/dist/src/symbols/symbol-flow.js +24 -8
  174. package/dist/src/symbols/symbol-flow.js.map +1 -1
  175. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  176. package/dist/src/symbols/symbol-slot.js +15 -0
  177. package/dist/src/symbols/symbol-slot.js.map +1 -1
  178. package/dist/src/symbols/symbol-slot.test.d.ts +2 -0
  179. package/dist/src/symbols/symbol-slot.test.d.ts.map +1 -0
  180. package/dist/src/symbols/symbol-slot.test.js +35 -0
  181. package/dist/src/symbols/symbol-slot.test.js.map +1 -0
  182. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  183. package/dist/src/symbols/symbol-table.js +6 -5
  184. package/dist/src/symbols/symbol-table.js.map +1 -1
  185. package/dist/src/trace.d.ts +2 -0
  186. package/dist/src/trace.d.ts.map +1 -0
  187. package/dist/src/trace.js +2 -0
  188. package/dist/src/trace.js.map +1 -0
  189. package/dist/src/tracer.d.ts +2 -228
  190. package/dist/src/tracer.d.ts.map +1 -1
  191. package/dist/src/tracer.js +5 -298
  192. package/dist/src/tracer.js.map +1 -1
  193. package/dist/src/utils.d.ts.map +1 -1
  194. package/dist/src/utils.js +7 -5
  195. package/dist/src/utils.js.map +1 -1
  196. package/dist/test/components/append-file.test.d.ts.map +1 -1
  197. package/dist/test/components/append-file.test.js +18 -10
  198. package/dist/test/components/append-file.test.js.map +1 -1
  199. package/dist/test/components/template-file.test.d.ts.map +1 -1
  200. package/dist/test/components/template-file.test.js +6 -4
  201. package/dist/test/components/template-file.test.js.map +1 -1
  202. package/dist/test/lazy-isempty.test.d.ts +2 -0
  203. package/dist/test/lazy-isempty.test.d.ts.map +1 -0
  204. package/dist/test/lazy-isempty.test.js +89 -0
  205. package/dist/test/lazy-isempty.test.js.map +1 -0
  206. package/dist/test/reactive-union-set-disposers.test.d.ts +2 -0
  207. package/dist/test/reactive-union-set-disposers.test.d.ts.map +1 -0
  208. package/dist/test/reactive-union-set-disposers.test.js +98 -0
  209. package/dist/test/reactive-union-set-disposers.test.js.map +1 -0
  210. package/dist/test/reactivity/shallow-reactive.test.d.ts +2 -0
  211. package/dist/test/reactivity/shallow-reactive.test.d.ts.map +1 -0
  212. package/dist/test/reactivity/shallow-reactive.test.js +52 -0
  213. package/dist/test/reactivity/shallow-reactive.test.js.map +1 -0
  214. package/dist/test/rendering/basic.test.js +3 -0
  215. package/dist/test/rendering/basic.test.js.map +1 -1
  216. package/dist/test/rendering/print-render-stack.test.d.ts +2 -0
  217. package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -0
  218. package/dist/test/rendering/print-render-stack.test.js +207 -0
  219. package/dist/test/rendering/print-render-stack.test.js.map +1 -0
  220. package/dist/test/scheduler-extended.test.d.ts +2 -0
  221. package/dist/test/scheduler-extended.test.d.ts.map +1 -0
  222. package/dist/test/scheduler-extended.test.js +96 -0
  223. package/dist/test/scheduler-extended.test.js.map +1 -0
  224. package/dist/test/scheduler.test.d.ts +2 -0
  225. package/dist/test/scheduler.test.d.ts.map +1 -0
  226. package/dist/test/scheduler.test.js +46 -0
  227. package/dist/test/scheduler.test.js.map +1 -0
  228. package/dist/testing/create-test-wrapper.d.ts +1 -1
  229. package/dist/testing/create-test-wrapper.d.ts.map +1 -1
  230. package/dist/testing/create-test-wrapper.js +1 -1
  231. package/dist/testing/create-test-wrapper.js.map +1 -1
  232. package/dist/testing/devtools-utils.d.ts +26 -0
  233. package/dist/testing/devtools-utils.d.ts.map +1 -0
  234. package/dist/testing/devtools-utils.js +140 -0
  235. package/dist/testing/devtools-utils.js.map +1 -0
  236. package/dist/testing/extend-expect.d.ts.map +1 -1
  237. package/dist/testing/extend-expect.js +63 -1
  238. package/dist/testing/extend-expect.js.map +1 -1
  239. package/dist/testing/render.d.ts +2 -2
  240. package/dist/testing/render.d.ts.map +1 -1
  241. package/dist/testing/render.js +2 -2
  242. package/dist/testing/render.js.map +1 -1
  243. package/dist/tsconfig.tsbuildinfo +1 -1
  244. package/package.json +21 -7
  245. package/scripts/copy-devtools-ui.mjs +26 -0
  246. package/src/binder.ts +71 -16
  247. package/src/components/AccessExpression.test.tsx +132 -0
  248. package/src/components/AccessExpression.tsx +344 -0
  249. package/src/components/AppendFile.tsx +14 -9
  250. package/src/components/Block.tsx +1 -1
  251. package/src/components/Declaration.tsx +2 -1
  252. package/src/components/Prose.tsx +1 -1
  253. package/src/components/Scope.tsx +6 -1
  254. package/src/components/SourceDirectory.tsx +1 -2
  255. package/src/components/TemplateFile.tsx +18 -9
  256. package/src/components/index.tsx +1 -0
  257. package/src/content-slot.tsx +7 -7
  258. package/src/context.ts +17 -6
  259. package/src/{debug.ts → debug/cli.ts} +112 -127
  260. package/src/debug/diagnostics.test.tsx +55 -0
  261. package/src/debug/effects.test.tsx +89 -0
  262. package/src/debug/effects.ts +317 -0
  263. package/src/debug/files.test.tsx +96 -0
  264. package/src/debug/files.ts +40 -0
  265. package/src/debug/index.ts +128 -0
  266. package/src/debug/render.test.tsx +379 -0
  267. package/src/debug/render.ts +639 -0
  268. package/src/debug/serialize.ts +85 -0
  269. package/src/debug/symbols.test.tsx +106 -0
  270. package/src/debug/symbols.ts +239 -0
  271. package/src/debug/trace.ts +312 -0
  272. package/src/devtools/devtools-protocol.ts +312 -0
  273. package/src/devtools/devtools-server.browser.ts +71 -0
  274. package/src/devtools/devtools-server.ts +290 -0
  275. package/src/devtools/devtools-transport.ts +154 -0
  276. package/src/devtools-entry.browser.ts +52 -0
  277. package/src/devtools-entry.ts +54 -0
  278. package/src/diagnostics.ts +141 -0
  279. package/src/index.ts +2 -7
  280. package/src/print-hook.ts +22 -0
  281. package/src/reactive-union-set.ts +85 -44
  282. package/src/reactivity.ts +301 -59
  283. package/src/render-stack.ts +294 -0
  284. package/src/render.ts +470 -216
  285. package/src/resource.ts +28 -19
  286. package/src/runtime/component.ts +11 -0
  287. package/src/scheduler.ts +80 -4
  288. package/src/symbols/basic-symbol.ts +6 -1
  289. package/src/symbols/decl.ts +5 -1
  290. package/src/symbols/output-scope.ts +21 -13
  291. package/src/symbols/output-symbol.ts +34 -14
  292. package/src/symbols/symbol-flow.ts +76 -39
  293. package/src/symbols/symbol-slot.test.tsx +41 -0
  294. package/src/symbols/symbol-slot.tsx +47 -20
  295. package/src/symbols/symbol-table.ts +6 -10
  296. package/src/trace.ts +1 -0
  297. package/src/tracer.ts +13 -242
  298. package/src/utils.tsx +24 -17
  299. package/temp/api.json +4187 -1603
  300. package/test/components/append-file.test.tsx +36 -29
  301. package/test/components/template-file.test.tsx +11 -11
  302. package/test/lazy-isempty.test.tsx +106 -0
  303. package/test/reactive-union-set-disposers.test.tsx +112 -0
  304. package/test/reactivity/shallow-reactive.test.tsx +56 -0
  305. package/test/rendering/basic.test.tsx +4 -0
  306. package/test/rendering/print-render-stack.test.tsx +244 -0
  307. package/test/scheduler-extended.test.tsx +122 -0
  308. package/test/scheduler.test.tsx +50 -0
  309. package/testing/create-test-wrapper.tsx +1 -1
  310. package/testing/devtools-utils.ts +203 -0
  311. package/testing/extend-expect.ts +89 -0
  312. package/testing/render.ts +2 -2
  313. package/testing/vitest.d.ts +9 -0
  314. package/dist/src/debug.d.ts +0 -15
  315. package/dist/src/debug.d.ts.map +0 -1
  316. package/dist/src/debug.js.map +0 -1
@@ -0,0 +1,294 @@
1
+ import pc from "picocolors";
2
+ import { contextsByKey } from "./context.js";
3
+ import { SourceDirectoryContext } from "./context/source-directory.js";
4
+ import { SourceFileContext } from "./context/source-file.js";
5
+ import { Context, getContext } from "./reactivity.js";
6
+ import { Component, Props, SourceLocation } from "./runtime/component.js";
7
+
8
+ // Store render stack for error diagnostics
9
+ const renderStack: Array<{
10
+ component: Component<any>;
11
+ props: Props;
12
+ context: Context | null;
13
+ source?: SourceLocation;
14
+ }> = [];
15
+
16
+ export interface RenderStackSnapshotEntry {
17
+ component: Component<any>;
18
+ props: Props;
19
+ context: Context | null;
20
+ source?: SourceLocation;
21
+ displayName: string;
22
+ }
23
+
24
+ export function pushStack(
25
+ component: Component<any>,
26
+ props: Props,
27
+ source?: SourceLocation,
28
+ ) {
29
+ renderStack.push({ component, props, context: getContext(), source });
30
+ }
31
+
32
+ export function popStack() {
33
+ renderStack.pop();
34
+ }
35
+
36
+ export function currentComponentName(): string | undefined {
37
+ const entry = renderStack[renderStack.length - 1];
38
+ return entry?.component.name || undefined;
39
+ }
40
+
41
+ export function clearRenderStack() {
42
+ renderStack.length = 0;
43
+ }
44
+
45
+ /**
46
+ * Get the current rendering path from the render stack context.
47
+ * Prefers SourceFileContext over SourceDirectoryContext.
48
+ */
49
+ export function getCurrentRenderPath(): string | undefined {
50
+ let currentPath: string | undefined;
51
+ for (let i = renderStack.length - 1; i >= 0; i--) {
52
+ const { context } = renderStack[i];
53
+ // Prefer SourceFileContext over SourceDirectoryContext
54
+ if (context?.context?.[SourceFileContext.id]) {
55
+ const fileContext = context.context[
56
+ SourceFileContext.id
57
+ ] as SourceFileContext;
58
+ return fileContext.path;
59
+ }
60
+ if (!currentPath && context?.context?.[SourceDirectoryContext.id]) {
61
+ const dirContext = context.context[
62
+ SourceDirectoryContext.id
63
+ ] as SourceDirectoryContext;
64
+ currentPath = dirContext.path;
65
+ // Don't break - keep looking for a SourceFileContext
66
+ }
67
+ }
68
+ return currentPath;
69
+ }
70
+
71
+ export function getRenderStackSnapshot(): RenderStackSnapshotEntry[] {
72
+ return renderStack.map((entry) => ({
73
+ component: entry.component,
74
+ props: entry.props,
75
+ context: entry.context,
76
+ source: entry.source,
77
+ displayName: getComponentDisplayName(entry.component, entry.props),
78
+ }));
79
+ }
80
+
81
+ // Helper functions
82
+ function getComponentDisplayName(
83
+ component: Component<any>,
84
+ props: Props,
85
+ ): string {
86
+ // Check if this is a Provider and if we can find its context name
87
+ if (component.name === "Provider") {
88
+ // Try to find the context this provider is associated with
89
+ for (const ctx of contextsByKey.values()) {
90
+ if (ctx.Provider === component && ctx.name) {
91
+ return ctx.name;
92
+ }
93
+ }
94
+ }
95
+ return component.name;
96
+ }
97
+
98
+ function inspectProps(props: Props) {
99
+ const entries = Object.entries(props)
100
+ .filter(([key]) => key !== "children") // Exclude children prop
101
+ .map(([key, value]) => {
102
+ const formattedValue = formatValue(value);
103
+ return `${pc.dim(key)}: ${formattedValue}`;
104
+ });
105
+
106
+ return entries.length > 0 ? entries.join(pc.dim(", ")) : "";
107
+ }
108
+
109
+ function formatValue(value: unknown): string {
110
+ switch (typeof value) {
111
+ case "string":
112
+ return pc.blue(`"${value}"`);
113
+ case "number":
114
+ case "boolean":
115
+ return pc.blue(String(value));
116
+ case "undefined":
117
+ return pc.gray("undefined");
118
+ case "object":
119
+ return value ? pc.gray("{...}") : pc.gray("null");
120
+ case "function":
121
+ return pc.gray("function");
122
+ default:
123
+ return pc.gray(String(value));
124
+ }
125
+ }
126
+
127
+ function formatSourceLocation(source: SourceLocation): string {
128
+ const cwd = process.cwd();
129
+ let filePath = source.fileName;
130
+
131
+ // Convert to relative path if under cwd
132
+ if (filePath.startsWith(cwd)) {
133
+ filePath = filePath.slice(cwd.length + 1); // +1 to remove leading slash
134
+ }
135
+
136
+ return `${filePath}:${source.lineNumber}:${source.columnNumber}`;
137
+ }
138
+
139
+ /**
140
+ * Print the current render stack to the console for debugging.
141
+ *
142
+ * This differs from debug.component.stack in that this uses a purpose-built
143
+ * stack rather than walking the context chain. When this is called, the context
144
+ * chain has been restored. In the future this can probably be unified nicely.
145
+ *
146
+ * @param error - Optional error to print the stack trace from
147
+ */
148
+ export function printRenderStack(error?: unknown) {
149
+ // Find the nearest SourceFileContext or SourceDirectoryContext from the render stack
150
+ let currentPath: string | undefined;
151
+ for (let i = renderStack.length - 1; i >= 0; i--) {
152
+ const { context } = renderStack[i];
153
+ // Prefer SourceFileContext over SourceDirectoryContext
154
+ if (context?.context?.[SourceFileContext.id]) {
155
+ const fileContext = context.context[
156
+ SourceFileContext.id
157
+ ] as SourceFileContext;
158
+ currentPath = fileContext.path;
159
+ break;
160
+ }
161
+ if (!currentPath && context?.context?.[SourceDirectoryContext.id]) {
162
+ const dirContext = context.context[
163
+ SourceDirectoryContext.id
164
+ ] as SourceDirectoryContext;
165
+ currentPath = dirContext.path;
166
+ // Don't break - keep looking for a SourceFileContext
167
+ }
168
+ }
169
+
170
+ if (currentPath) {
171
+ // eslint-disable-next-line no-console
172
+ console.error(pc.red(`Error rendering in file ${currentPath}`));
173
+ } else {
174
+ // eslint-disable-next-line no-console
175
+ console.error(pc.red("Error rendering:"));
176
+ }
177
+
178
+ // Print the error message and stack if provided
179
+ if (error) {
180
+ if (error instanceof Error) {
181
+ // eslint-disable-next-line no-console
182
+ console.error(pc.red(` ${error.message}`));
183
+ if (error.stack) {
184
+ // Print stack lines (skip the first line which is the error message)
185
+ const stackLines = error.stack.split("\n").slice(1);
186
+ for (const line of stackLines) {
187
+ // eslint-disable-next-line no-console
188
+ console.error(pc.gray(line));
189
+ }
190
+ }
191
+ } else {
192
+ // eslint-disable-next-line no-console
193
+ console.error(pc.red(` ${String(error)}`));
194
+ }
195
+ // eslint-disable-next-line no-console
196
+ console.error(); // Empty line before component stack
197
+ }
198
+
199
+ // First pass: determine which providers should be nested vs standalone
200
+ // A provider should be nested under its parent if it's from a different file
201
+ // (i.e., it's part of the component's implementation, not user-provided)
202
+ const nestedProviderIndices = new Set<number>();
203
+
204
+ for (let i = renderStack.length - 1; i >= 0; i--) {
205
+ const { component, source } = renderStack[i];
206
+
207
+ // Skip anonymous components and providers
208
+ if (!component.name || component.name === "Provider") {
209
+ continue;
210
+ }
211
+
212
+ // Look for providers that come immediately after this component
213
+ for (let j = i + 1; j < renderStack.length; j++) {
214
+ const providerEntry = renderStack[j];
215
+ if (!providerEntry.component.name) continue;
216
+ if (providerEntry.component.name !== "Provider") break;
217
+
218
+ // Nest provider if it's from a different file (component-internal)
219
+ const shouldNest =
220
+ !source ||
221
+ !providerEntry.source ||
222
+ source.fileName !== providerEntry.source.fileName;
223
+
224
+ if (shouldNest) {
225
+ nestedProviderIndices.add(j);
226
+ } else {
227
+ // Stop looking - this provider and all after should be standalone
228
+ break;
229
+ }
230
+ }
231
+ }
232
+
233
+ // Second pass: print stack entries in order, nesting providers where appropriate
234
+ for (let i = renderStack.length - 1; i >= 0; i--) {
235
+ const { component, props, source } = renderStack[i];
236
+
237
+ // Skip anonymous components
238
+ if (!component.name) {
239
+ continue;
240
+ }
241
+
242
+ // Skip providers that will be nested under their parent
243
+ if (nestedProviderIndices.has(i)) {
244
+ continue;
245
+ }
246
+
247
+ const displayName = getComponentDisplayName(component, props);
248
+ const sourceStr =
249
+ source ? pc.gray(` (${formatSourceLocation(source)})`) : "";
250
+
251
+ // eslint-disable-next-line no-console
252
+ console.error(` ${pc.cyan("at")} ${pc.bold(displayName)}${sourceStr}`);
253
+
254
+ // Print props on next line if there are any
255
+ const propsStr = inspectProps(props);
256
+ if (propsStr) {
257
+ // eslint-disable-next-line no-console
258
+ console.error(` ${propsStr}`);
259
+ }
260
+
261
+ // For non-Provider components, print any nested providers
262
+ if (component.name !== "Provider") {
263
+ for (let j = i + 1; j < renderStack.length; j++) {
264
+ if (!nestedProviderIndices.has(j)) break;
265
+
266
+ const providerEntry = renderStack[j];
267
+ if (!providerEntry.component.name) continue;
268
+
269
+ const providerName = getComponentDisplayName(
270
+ providerEntry.component,
271
+ providerEntry.props,
272
+ );
273
+ const providerSourceStr =
274
+ providerEntry.source ?
275
+ pc.gray(` (${formatSourceLocation(providerEntry.source)})`)
276
+ : "";
277
+
278
+ // eslint-disable-next-line no-console
279
+ console.error(
280
+ ` ${pc.magenta("provides")} ${pc.bold(providerName)}${providerSourceStr}`,
281
+ );
282
+
283
+ const providerPropsStr = inspectProps(providerEntry.props);
284
+ if (providerPropsStr) {
285
+ // eslint-disable-next-line no-console
286
+ console.error(` ${providerPropsStr}`);
287
+ }
288
+ }
289
+ }
290
+ }
291
+
292
+ // Clear the stack after printing to avoid stale data on subsequent render errors
293
+ clearRenderStack();
294
+ }