@alloy-js/core 0.23.0-dev.1 → 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 (310) 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} +79 -82
  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 +18 -1
  140. package/dist/src/render-stack.d.ts.map +1 -1
  141. package/dist/src/render-stack.js +61 -1
  142. package/dist/src/render-stack.js.map +1 -1
  143. package/dist/src/render.d.ts +8 -15
  144. package/dist/src/render.d.ts.map +1 -1
  145. package/dist/src/render.js +370 -109
  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/scheduler.d.ts +8 -0
  151. package/dist/src/scheduler.d.ts.map +1 -1
  152. package/dist/src/scheduler.js +69 -3
  153. package/dist/src/scheduler.js.map +1 -1
  154. package/dist/src/symbols/basic-symbol.d.ts.map +1 -1
  155. package/dist/src/symbols/basic-symbol.js +6 -1
  156. package/dist/src/symbols/basic-symbol.js.map +1 -1
  157. package/dist/src/symbols/decl.d.ts.map +1 -1
  158. package/dist/src/symbols/decl.js +5 -1
  159. package/dist/src/symbols/decl.js.map +1 -1
  160. package/dist/src/symbols/output-scope.d.ts +2 -1
  161. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  162. package/dist/src/symbols/output-scope.js +13 -8
  163. package/dist/src/symbols/output-scope.js.map +1 -1
  164. package/dist/src/symbols/output-symbol.d.ts +1 -0
  165. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  166. package/dist/src/symbols/output-symbol.js +25 -8
  167. package/dist/src/symbols/output-symbol.js.map +1 -1
  168. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  169. package/dist/src/symbols/symbol-flow.js +24 -8
  170. package/dist/src/symbols/symbol-flow.js.map +1 -1
  171. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  172. package/dist/src/symbols/symbol-slot.js +15 -0
  173. package/dist/src/symbols/symbol-slot.js.map +1 -1
  174. package/dist/src/symbols/symbol-slot.test.d.ts +2 -0
  175. package/dist/src/symbols/symbol-slot.test.d.ts.map +1 -0
  176. package/dist/src/symbols/symbol-slot.test.js +35 -0
  177. package/dist/src/symbols/symbol-slot.test.js.map +1 -0
  178. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  179. package/dist/src/symbols/symbol-table.js +6 -5
  180. package/dist/src/symbols/symbol-table.js.map +1 -1
  181. package/dist/src/trace.d.ts +2 -0
  182. package/dist/src/trace.d.ts.map +1 -0
  183. package/dist/src/trace.js +2 -0
  184. package/dist/src/trace.js.map +1 -0
  185. package/dist/src/tracer.d.ts +2 -228
  186. package/dist/src/tracer.d.ts.map +1 -1
  187. package/dist/src/tracer.js +5 -298
  188. package/dist/src/tracer.js.map +1 -1
  189. package/dist/src/utils.d.ts.map +1 -1
  190. package/dist/src/utils.js +7 -5
  191. package/dist/src/utils.js.map +1 -1
  192. package/dist/test/components/append-file.test.d.ts.map +1 -1
  193. package/dist/test/components/append-file.test.js +18 -10
  194. package/dist/test/components/append-file.test.js.map +1 -1
  195. package/dist/test/components/template-file.test.d.ts.map +1 -1
  196. package/dist/test/components/template-file.test.js +6 -4
  197. package/dist/test/components/template-file.test.js.map +1 -1
  198. package/dist/test/lazy-isempty.test.d.ts +2 -0
  199. package/dist/test/lazy-isempty.test.d.ts.map +1 -0
  200. package/dist/test/lazy-isempty.test.js +89 -0
  201. package/dist/test/lazy-isempty.test.js.map +1 -0
  202. package/dist/test/reactive-union-set-disposers.test.d.ts +2 -0
  203. package/dist/test/reactive-union-set-disposers.test.d.ts.map +1 -0
  204. package/dist/test/reactive-union-set-disposers.test.js +98 -0
  205. package/dist/test/reactive-union-set-disposers.test.js.map +1 -0
  206. package/dist/test/reactivity/shallow-reactive.test.d.ts +2 -0
  207. package/dist/test/reactivity/shallow-reactive.test.d.ts.map +1 -0
  208. package/dist/test/reactivity/shallow-reactive.test.js +52 -0
  209. package/dist/test/reactivity/shallow-reactive.test.js.map +1 -0
  210. package/dist/test/rendering/basic.test.js +3 -0
  211. package/dist/test/rendering/basic.test.js.map +1 -1
  212. package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -1
  213. package/dist/test/rendering/print-render-stack.test.js +91 -98
  214. package/dist/test/rendering/print-render-stack.test.js.map +1 -1
  215. package/dist/test/scheduler-extended.test.d.ts +2 -0
  216. package/dist/test/scheduler-extended.test.d.ts.map +1 -0
  217. package/dist/test/scheduler-extended.test.js +96 -0
  218. package/dist/test/scheduler-extended.test.js.map +1 -0
  219. package/dist/test/scheduler.test.d.ts +2 -0
  220. package/dist/test/scheduler.test.d.ts.map +1 -0
  221. package/dist/test/scheduler.test.js +46 -0
  222. package/dist/test/scheduler.test.js.map +1 -0
  223. package/dist/testing/create-test-wrapper.d.ts +1 -1
  224. package/dist/testing/create-test-wrapper.d.ts.map +1 -1
  225. package/dist/testing/create-test-wrapper.js +1 -1
  226. package/dist/testing/create-test-wrapper.js.map +1 -1
  227. package/dist/testing/devtools-utils.d.ts +26 -0
  228. package/dist/testing/devtools-utils.d.ts.map +1 -0
  229. package/dist/testing/devtools-utils.js +140 -0
  230. package/dist/testing/devtools-utils.js.map +1 -0
  231. package/dist/testing/extend-expect.d.ts.map +1 -1
  232. package/dist/testing/extend-expect.js +63 -1
  233. package/dist/testing/extend-expect.js.map +1 -1
  234. package/dist/testing/render.d.ts +2 -2
  235. package/dist/testing/render.d.ts.map +1 -1
  236. package/dist/testing/render.js +2 -2
  237. package/dist/testing/render.js.map +1 -1
  238. package/dist/tsconfig.tsbuildinfo +1 -1
  239. package/package.json +21 -7
  240. package/scripts/copy-devtools-ui.mjs +26 -0
  241. package/src/binder.ts +71 -16
  242. package/src/components/AccessExpression.test.tsx +132 -0
  243. package/src/components/AccessExpression.tsx +344 -0
  244. package/src/components/AppendFile.tsx +14 -9
  245. package/src/components/Block.tsx +1 -1
  246. package/src/components/Declaration.tsx +2 -1
  247. package/src/components/Prose.tsx +1 -1
  248. package/src/components/Scope.tsx +6 -1
  249. package/src/components/SourceDirectory.tsx +1 -2
  250. package/src/components/TemplateFile.tsx +18 -9
  251. package/src/components/index.tsx +1 -0
  252. package/src/content-slot.tsx +7 -7
  253. package/src/context.ts +17 -6
  254. package/src/{debug.ts → debug/cli.ts} +114 -125
  255. package/src/debug/diagnostics.test.tsx +55 -0
  256. package/src/debug/effects.test.tsx +89 -0
  257. package/src/debug/effects.ts +317 -0
  258. package/src/debug/files.test.tsx +96 -0
  259. package/src/debug/files.ts +40 -0
  260. package/src/debug/index.ts +128 -0
  261. package/src/debug/render.test.tsx +379 -0
  262. package/src/debug/render.ts +639 -0
  263. package/src/debug/serialize.ts +85 -0
  264. package/src/debug/symbols.test.tsx +106 -0
  265. package/src/debug/symbols.ts +239 -0
  266. package/src/debug/trace.ts +312 -0
  267. package/src/devtools/devtools-protocol.ts +312 -0
  268. package/src/devtools/devtools-server.browser.ts +71 -0
  269. package/src/devtools/devtools-server.ts +290 -0
  270. package/src/devtools/devtools-transport.ts +154 -0
  271. package/src/devtools-entry.browser.ts +52 -0
  272. package/src/devtools-entry.ts +54 -0
  273. package/src/diagnostics.ts +141 -0
  274. package/src/index.ts +2 -7
  275. package/src/print-hook.ts +22 -0
  276. package/src/reactive-union-set.ts +85 -44
  277. package/src/reactivity.ts +301 -59
  278. package/src/render-stack.ts +73 -1
  279. package/src/render.ts +470 -161
  280. package/src/resource.ts +28 -19
  281. package/src/scheduler.ts +80 -4
  282. package/src/symbols/basic-symbol.ts +6 -1
  283. package/src/symbols/decl.ts +5 -1
  284. package/src/symbols/output-scope.ts +21 -13
  285. package/src/symbols/output-symbol.ts +34 -14
  286. package/src/symbols/symbol-flow.ts +76 -39
  287. package/src/symbols/symbol-slot.test.tsx +41 -0
  288. package/src/symbols/symbol-slot.tsx +47 -20
  289. package/src/symbols/symbol-table.ts +6 -10
  290. package/src/trace.ts +1 -0
  291. package/src/tracer.ts +13 -242
  292. package/src/utils.tsx +24 -17
  293. package/temp/api.json +5658 -3095
  294. package/test/components/append-file.test.tsx +36 -29
  295. package/test/components/template-file.test.tsx +11 -11
  296. package/test/lazy-isempty.test.tsx +106 -0
  297. package/test/reactive-union-set-disposers.test.tsx +112 -0
  298. package/test/reactivity/shallow-reactive.test.tsx +56 -0
  299. package/test/rendering/basic.test.tsx +4 -0
  300. package/test/rendering/print-render-stack.test.tsx +52 -43
  301. package/test/scheduler-extended.test.tsx +122 -0
  302. package/test/scheduler.test.tsx +50 -0
  303. package/testing/create-test-wrapper.tsx +1 -1
  304. package/testing/devtools-utils.ts +203 -0
  305. package/testing/extend-expect.ts +89 -0
  306. package/testing/render.ts +2 -2
  307. package/testing/vitest.d.ts +9 -0
  308. package/dist/src/debug.d.ts +0 -14
  309. package/dist/src/debug.d.ts.map +0 -1
  310. package/dist/src/debug.js.map +0 -1
@@ -1,127 +1,16 @@
1
- import { isReactive } from "@vue/reactivity";
2
1
  import Table from "cli-table3";
3
2
  import pc from "picocolors";
4
- import { contextsByKey } from "./context.js";
5
- import { Context, getContext } from "./reactivity.js";
3
+ import { contextsByKey } from "../context.js";
4
+ import { getContext, untrack } from "../reactivity.js";
5
+ import { isReactiveTarget } from "./effects.js";
6
6
 
7
- interface DebugInterface {
8
- component: {
9
- stack(): void;
10
- tree(): void;
11
- watch(): void;
12
- render(): void;
13
- context(): void;
14
- };
15
- }
16
-
17
- const debug: DebugInterface = {
18
- component: {
19
- stack: debugStack,
20
- tree() {
21
- //eslint-disable-next-line no-console
22
- console.log("tree");
23
- },
24
- watch() {
25
- //eslint-disable-next-line no-console
26
- console.log("watch");
27
- },
28
- render() {
29
- //eslint-disable-next-line no-console
30
- console.log("render");
31
- },
32
- context: debugContext,
33
- },
34
- };
35
-
36
- function debugStack() {
37
- let currentContext = getContext();
38
- let foundContexts: Context[] = [];
39
- while (currentContext !== null) {
40
- if (
41
- currentContext.context &&
42
- Object.getOwnPropertySymbols(currentContext.context)[0]
43
- ) {
44
- foundContexts.push(currentContext);
45
- }
46
-
47
- if (
48
- currentContext.componentOwner &&
49
- currentContext.componentOwner.component.name !== "Provider"
50
- ) {
51
- process.stdout.write(
52
- style.component.name(currentContext.componentOwner.component.name) +
53
- "\n",
54
- );
55
- const table = kvTable();
56
- const props = currentContext.componentOwner.props;
57
-
58
- table.push([
59
- { hAlign: "right", content: "props" },
60
- props && Object.keys(props).length > 0 ?
61
- dumpValue(props)
62
- : pc.gray("(none)"),
63
- ]);
64
-
65
- table.push([
66
- { hAlign: "right", content: "contexts" },
67
- foundContexts.length > 0 ?
68
- foundContexts.map((c) => printContext(c, true)).join("\n")
69
- : pc.gray("(none)"),
70
- ]);
71
-
72
- process.stdout.write(table.toString() + "\n\n");
73
- foundContexts = [];
74
- }
75
-
76
- currentContext = currentContext.owner;
77
- }
78
- }
79
-
80
- function debugContext() {
81
- let currentContext = getContext();
82
- while (currentContext !== null) {
83
- //eslint-disable-next-line no-console
84
- console.log(printContext(currentContext));
85
- currentContext = currentContext.owner;
86
- }
87
- }
88
- function printContext(context: Context, omitOwner: boolean = false) {
89
- if (!context.context) return "";
90
- const key = Object.getOwnPropertySymbols(context.context)[0];
91
- if (!key) return "";
92
- const contextDefinition = contextsByKey.get(key);
93
- const contextName = contextDefinition?.name ?? "unknown context";
94
- const value = context.context[key];
95
-
96
- let output = style.context.name(contextName);
97
- if (!omitOwner) {
98
- const owner = findContextOwner(context);
99
- output += " provided by " + style.component.name(owner);
100
- }
101
-
102
- output += "\n" + dumpValue(value) + "\n";
103
-
104
- return output;
105
- }
106
-
107
- function findContextOwner(context: Context) {
108
- let currentContext: Context | null = context;
109
- while (
110
- currentContext &&
111
- (currentContext.componentOwner === undefined ||
112
- currentContext.componentOwner.component.name === "Provider")
113
- ) {
114
- currentContext = currentContext.owner;
7
+ function reactiveTag(value: unknown) {
8
+ if (isReactiveTarget(value)) {
9
+ return " " + pc.greenBright(`reactive`) + " ";
115
10
  }
116
-
117
- return currentContext?.componentOwner?.component.name ?? "unknown";
118
- }
119
- declare global {
120
- var debug: DebugInterface;
11
+ return "";
121
12
  }
122
13
 
123
- globalThis.debug = debug;
124
-
125
14
  const style = {
126
15
  value: {
127
16
  primitive(value: string | number | boolean | null | undefined) {
@@ -151,13 +40,6 @@ const style = {
151
40
  },
152
41
  };
153
42
 
154
- function reactiveTag(value: unknown) {
155
- if (isReactive(value)) {
156
- return " " + pc.greenBright(`reactive`) + " ";
157
- }
158
- return "";
159
- }
160
-
161
43
  function dumpValue(value: unknown, level = 0) {
162
44
  switch (typeof value) {
163
45
  case "boolean":
@@ -209,3 +91,110 @@ function kvTable(sep = " ") {
209
91
  style: { "padding-left": 0, "padding-right": 0 },
210
92
  });
211
93
  }
94
+
95
+ function printContext(
96
+ context: ReturnType<typeof getContext>,
97
+ omitOwner = false,
98
+ ) {
99
+ if (!context?.context) return "";
100
+ const key = Object.getOwnPropertySymbols(context.context)[0];
101
+ if (!key) return "";
102
+ const contextDefinition = contextsByKey.get(key);
103
+ const contextName = contextDefinition?.name ?? "unknown context";
104
+ const value = context.context[key];
105
+
106
+ let output = style.context.name(contextName);
107
+ if (!omitOwner) {
108
+ const owner = findContextOwner(context);
109
+ output += " provided by " + style.component.name(owner);
110
+ }
111
+
112
+ output += "\n" + dumpValue(value) + "\n";
113
+
114
+ return output;
115
+ }
116
+
117
+ function findContextOwner(context: ReturnType<typeof getContext>) {
118
+ let currentContext = context;
119
+ while (
120
+ currentContext &&
121
+ (currentContext.componentOwner === undefined ||
122
+ currentContext.componentOwner.component.name === "Provider")
123
+ ) {
124
+ currentContext = currentContext.owner;
125
+ }
126
+
127
+ return currentContext?.componentOwner?.component.name ?? "unknown";
128
+ }
129
+
130
+ export function debugStack() {
131
+ untrack(() => {
132
+ let currentContext = getContext();
133
+ let foundContexts: (typeof currentContext)[] = [];
134
+ while (currentContext !== null) {
135
+ if (
136
+ currentContext.context &&
137
+ Object.getOwnPropertySymbols(currentContext.context)[0]
138
+ ) {
139
+ foundContexts.push(currentContext);
140
+ }
141
+
142
+ if (
143
+ currentContext.componentOwner &&
144
+ currentContext.componentOwner.component.name !== "Provider"
145
+ ) {
146
+ process.stdout.write(
147
+ style.component.name(currentContext.componentOwner.component.name) +
148
+ "\n",
149
+ );
150
+ const table = kvTable();
151
+ const props = currentContext.componentOwner.props;
152
+
153
+ table.push([
154
+ { hAlign: "right", content: "props" },
155
+ props && Object.keys(props).length > 0 ?
156
+ dumpValue(props)
157
+ : pc.gray("(none)"),
158
+ ]);
159
+
160
+ table.push([
161
+ { hAlign: "right", content: "contexts" },
162
+ foundContexts.length > 0 ?
163
+ foundContexts.map((c) => printContext(c, true)).join("\n")
164
+ : pc.gray("(none)"),
165
+ ]);
166
+
167
+ process.stdout.write(table.toString() + "\n\n");
168
+ foundContexts = [];
169
+ }
170
+
171
+ currentContext = currentContext.owner;
172
+ }
173
+ });
174
+ }
175
+
176
+ export function debugContext() {
177
+ untrack(() => {
178
+ let currentContext = getContext();
179
+ while (currentContext !== null) {
180
+ // eslint-disable-next-line no-console
181
+ console.log(printContext(currentContext));
182
+ currentContext = currentContext.owner;
183
+ }
184
+ });
185
+ }
186
+
187
+ export function debugTree() {
188
+ // eslint-disable-next-line no-console
189
+ console.log("tree");
190
+ }
191
+
192
+ export function debugWatch() {
193
+ // eslint-disable-next-line no-console
194
+ console.log("watch");
195
+ }
196
+
197
+ export function debugRender() {
198
+ // eslint-disable-next-line no-console
199
+ console.log("render");
200
+ }
@@ -0,0 +1,55 @@
1
+ import { afterEach, beforeEach, expect, it } from "vitest";
2
+ import WebSocket from "ws";
3
+ import {
4
+ createMessageCollector,
5
+ type DevtoolsMessage,
6
+ } from "../../testing/devtools-utils.js";
7
+ import { Output } from "../components/Output.jsx";
8
+ import {
9
+ enableDevtools,
10
+ resetDevtoolsServerForTests,
11
+ } from "../devtools/devtools-server.js";
12
+ import { DiagnosticsCollector } from "../diagnostics.js";
13
+ import { renderAsync } from "../render.js";
14
+
15
+ let socket: WebSocket | undefined;
16
+
17
+ beforeEach(async () => {
18
+ const server = await enableDevtools({ port: 0 });
19
+ socket = new WebSocket(`ws://127.0.0.1:${server.port}`);
20
+
21
+ await new Promise<void>((resolve, reject) => {
22
+ socket?.once("open", resolve);
23
+ socket?.once("error", reject);
24
+ });
25
+ });
26
+
27
+ afterEach(async () => {
28
+ if (socket) {
29
+ socket.close();
30
+ socket = undefined;
31
+ }
32
+
33
+ await resetDevtoolsServerForTests();
34
+ });
35
+
36
+ it("emits diagnostics:report messages", async () => {
37
+ const collector = createMessageCollector(socket!);
38
+ const diagnostics = new DiagnosticsCollector();
39
+
40
+ diagnostics.emit({ message: "Test diagnostic", severity: "warning" });
41
+
42
+ await renderAsync(<Output>{"ok"}</Output>);
43
+
44
+ const messages = await collector.waitForRender();
45
+ const diagnosticsMessages = messages.filter(
46
+ (m: DevtoolsMessage) => m.type === "diagnostics:report",
47
+ );
48
+
49
+ collector.stop();
50
+
51
+ expect(diagnosticsMessages[0]).toMatchObject({
52
+ type: "diagnostics:report",
53
+ diagnostics: expect.any(Array),
54
+ });
55
+ });
@@ -0,0 +1,89 @@
1
+ import { afterEach, beforeEach, expect, it } from "vitest";
2
+ import WebSocket from "ws";
3
+ import {
4
+ createMessageCollector,
5
+ filterEffectsMessages,
6
+ } from "../../testing/devtools-utils.js";
7
+ import { Output } from "../components/Output.jsx";
8
+ import {
9
+ enableDevtools,
10
+ resetDevtoolsServerForTests,
11
+ } from "../devtools/devtools-server.js";
12
+ import { effect, ref } from "../reactivity.js";
13
+ import { renderAsync } from "../render.js";
14
+ import { debug } from "./index.js";
15
+
16
+ let socket: WebSocket | undefined;
17
+
18
+ beforeEach(async () => {
19
+ debug.effect.reset();
20
+
21
+ const server = await enableDevtools({ port: 0 });
22
+ socket = new WebSocket(`ws://127.0.0.1:${server.port}`);
23
+ await new Promise<void>((resolve, reject) => {
24
+ socket?.once("open", resolve);
25
+ socket?.once("error", reject);
26
+ });
27
+ });
28
+
29
+ afterEach(async () => {
30
+ if (socket) {
31
+ socket.close();
32
+ socket = undefined;
33
+ }
34
+
35
+ await resetDevtoolsServerForTests();
36
+ debug.effect.reset();
37
+ });
38
+
39
+ it("emits effect, ref, edge, and update messages", async () => {
40
+ const collector = createMessageCollector(socket!);
41
+ const r1 = ref(0);
42
+
43
+ // Create an effect that reads r1.
44
+ let observed = 0;
45
+ effect(() => {
46
+ observed = r1.value;
47
+ });
48
+
49
+ // Mutate r1 to trigger the effect.
50
+ r1.value = 42;
51
+
52
+ await renderAsync(<Output>{"ok"}</Output>);
53
+
54
+ const messages = await collector.waitForRender();
55
+ const effectsMessages = filterEffectsMessages(messages);
56
+ collector.stop();
57
+
58
+ // Check that core message types are present
59
+ const byType = (type: string) =>
60
+ effectsMessages.filter((m: any) => m.type === type);
61
+ expect(byType("effect:refAdded").length).toBeGreaterThanOrEqual(1);
62
+ expect(byType("effect:effectAdded").length).toBeGreaterThanOrEqual(1);
63
+ expect(byType("effect:track").length).toBeGreaterThanOrEqual(1);
64
+ expect(byType("effect:trigger").length).toBeGreaterThanOrEqual(1);
65
+ expect(byType("effect:effectUpdated").length).toBeGreaterThanOrEqual(1);
66
+
67
+ // Verify message shapes
68
+ expect(byType("effect:refAdded")[0]).toMatchObject({
69
+ ref: expect.objectContaining({ id: expect.any(Number), kind: "ref" }),
70
+ });
71
+ expect(byType("effect:effectAdded")[0]).toMatchObject({
72
+ effect: expect.objectContaining({ id: expect.any(Number) }),
73
+ });
74
+ expect(byType("effect:track")[0]).toMatchObject({
75
+ edge: expect.objectContaining({
76
+ type: "track",
77
+ effectId: expect.any(Number),
78
+ refId: expect.any(Number),
79
+ }),
80
+ });
81
+ expect(byType("effect:trigger")[0]).toMatchObject({
82
+ edge: expect.objectContaining({
83
+ effectId: expect.any(Number),
84
+ refId: expect.any(Number),
85
+ }),
86
+ });
87
+
88
+ expect(observed).toBe(42);
89
+ });
@@ -0,0 +1,317 @@
1
+ import { isReactive, isRef } from "@vue/reactivity";
2
+ import {
3
+ emitDevtoolsMessage,
4
+ isDevtoolsEnabled,
5
+ TracePhase,
6
+ traceType,
7
+ } from "./trace.js";
8
+
9
+ // ─────────────────────────────────────────────────────────────────────────────
10
+ // Effects debug
11
+ // ─────────────────────────────────────────────────────────────────────────────
12
+
13
+ export interface SourceLocation {
14
+ fileName?: string;
15
+ lineNumber?: number;
16
+ columnNumber?: number;
17
+ stack?: string;
18
+ }
19
+
20
+ export interface EffectDebugInfo {
21
+ id: number;
22
+ name?: string;
23
+ type?: string;
24
+ createdAt?: SourceLocation;
25
+ lastTriggeredByRefId?: number;
26
+ lastTriggeredAt?: SourceLocation;
27
+ }
28
+
29
+ export interface RefDebugInfo {
30
+ id: number;
31
+ kind?: string;
32
+ createdAt?: SourceLocation;
33
+ createdByEffectId?: number;
34
+ }
35
+
36
+ export interface EffectEdgeDebugInfo {
37
+ id: number;
38
+ type: "track" | "trigger" | "triggered-by";
39
+ effectId: number;
40
+ refId?: number;
41
+ targetId?: number;
42
+ targetKind?: "ref" | "target";
43
+ targetLabel?: string;
44
+ targetKey?: string | number;
45
+ location?: SourceLocation;
46
+ }
47
+
48
+ const effects = new Map<number, EffectDebugInfo>();
49
+ const refs = new Map<number, RefDebugInfo>();
50
+ let effectIdCounter = 1;
51
+ let edgeEventIdCounter = 1;
52
+ let nonRefTargetIdCounter = 1;
53
+ const nonRefTargetIds = new WeakMap<object, number>();
54
+ const primitiveTargetIds = new Map<unknown, number>();
55
+
56
+ const STACK_LINE = /\s*at\s+(?:.+?\s+\()?(.+?):(\d+):(\d+)\)?$/;
57
+ const STACK_SKIP = [
58
+ "node:internal",
59
+ "/node_modules/",
60
+ "\\node_modules\\",
61
+ "/@vue/",
62
+ "\\@vue\\",
63
+ "/@alloy-js/",
64
+ "\\@alloy-js\\",
65
+ "/packages/core/src/reactivity",
66
+ "/packages/core/src/devtools/effects-debug",
67
+ "/packages/core/dist/src/reactivity",
68
+ "\\packages\\core\\dist\\src\\reactivity",
69
+ "/packages/core/dist/src/devtools/effects-debug",
70
+ "\\packages\\core\\dist\\src\\devtools\\effects-debug",
71
+ "captureSourceLocation",
72
+ ];
73
+
74
+ const VUE_REACTIVITY_MARKERS = [
75
+ "@vue/reactivity",
76
+ "reactivity.esm",
77
+ "reactivity.cjs",
78
+ "reactivity.global",
79
+ "/@vue/",
80
+ "\\@vue\\",
81
+ ];
82
+
83
+ function isVueReactivityLine(line: string) {
84
+ return VUE_REACTIVITY_MARKERS.some((marker) => line.includes(marker));
85
+ }
86
+
87
+ function parseStackLine(
88
+ line: string,
89
+ stack?: string,
90
+ ): SourceLocation | undefined {
91
+ const match = STACK_LINE.exec(line);
92
+ if (!match) return undefined;
93
+ const [, fileName, lineNumber, columnNumber] = match;
94
+ return {
95
+ fileName,
96
+ lineNumber: Number(lineNumber),
97
+ columnNumber: Number(columnNumber),
98
+ stack,
99
+ };
100
+ }
101
+
102
+ export function captureSourceLocation(
103
+ skipReactives = true,
104
+ ): SourceLocation | undefined {
105
+ if (!isDevtoolsEnabled()) return undefined;
106
+ const stack = new Error().stack;
107
+ if (!stack) {
108
+ return { stack: "" };
109
+ }
110
+ const lines = stack.split("\n").slice(1);
111
+ for (const line of lines) {
112
+ if (STACK_SKIP.some((skip) => line.includes(skip))) continue;
113
+ const parsed = parseStackLine(line, stack);
114
+ if (parsed) return parsed;
115
+ }
116
+
117
+ if (skipReactives) {
118
+ for (const line of lines) {
119
+ if (STACK_SKIP.some((skip) => line.includes(skip))) continue;
120
+ if (isVueReactivityLine(line)) continue;
121
+ const parsed = parseStackLine(line, stack);
122
+ if (parsed) return parsed;
123
+ }
124
+ }
125
+
126
+ return { stack };
127
+ }
128
+
129
+ function getNonRefTargetId(target: unknown): number {
130
+ if (typeof target === "object" && target !== null) {
131
+ const existing = nonRefTargetIds.get(target);
132
+ if (existing) return existing;
133
+ const id = nonRefTargetIdCounter++;
134
+ nonRefTargetIds.set(target, id);
135
+ return id;
136
+ }
137
+ if (typeof target === "function") {
138
+ const existing = nonRefTargetIds.get(target as object);
139
+ if (existing) return existing;
140
+ const id = nonRefTargetIdCounter++;
141
+ nonRefTargetIds.set(target as object, id);
142
+ return id;
143
+ }
144
+ const existing = primitiveTargetIds.get(target);
145
+ if (existing) return existing;
146
+ const id = nonRefTargetIdCounter++;
147
+ primitiveTargetIds.set(target, id);
148
+ return id;
149
+ }
150
+
151
+ function formatNonRefTargetLabel(target: unknown): string {
152
+ if (Array.isArray(target)) return "[]";
153
+ try {
154
+ return String(target);
155
+ } catch {
156
+ return "[Unserializable]";
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Sanitize a Map/object key to ensure it's serializable.
162
+ */
163
+ function sanitizeTargetKey(key: unknown): string | number | undefined {
164
+ if (key === undefined) return undefined;
165
+ if (typeof key === "string" || typeof key === "number") return key;
166
+ if (typeof key === "symbol") return key.toString();
167
+ if (typeof key === "object" || typeof key === "function") return "Object";
168
+ return String(key);
169
+ }
170
+
171
+ function buildEffectTargetInfo(input: {
172
+ target: unknown;
173
+ refId?: number;
174
+ }): Pick<
175
+ EffectEdgeDebugInfo,
176
+ "refId" | "targetId" | "targetKind" | "targetLabel"
177
+ > {
178
+ if (input.refId !== undefined) {
179
+ return {
180
+ refId: input.refId,
181
+ targetId: input.refId,
182
+ targetKind: "ref",
183
+ };
184
+ }
185
+
186
+ const targetId = getNonRefTargetId(input.target);
187
+ return {
188
+ targetId,
189
+ targetKind: "target",
190
+ targetLabel: formatNonRefTargetLabel(input.target),
191
+ };
192
+ }
193
+
194
+ function emitEffect(message: { type: string; [key: string]: unknown }) {
195
+ emitDevtoolsMessage(message);
196
+ }
197
+
198
+ export function update(input: Partial<EffectDebugInfo> & { id: number }) {
199
+ if (!isDevtoolsEnabled()) return;
200
+ const existing = effects.get(input.id);
201
+ if (!existing) return;
202
+ const next: EffectDebugInfo = { ...existing, ...input };
203
+ effects.set(input.id, next);
204
+ emitEffect({
205
+ type: traceType(TracePhase.effect.effectUpdated),
206
+ effect: next,
207
+ });
208
+ }
209
+
210
+ export function register(input: {
211
+ name?: string;
212
+ type?: string;
213
+ createdAt?: SourceLocation;
214
+ contextId?: number;
215
+ ownerContextId?: number | null;
216
+ }): number {
217
+ if (!isDevtoolsEnabled()) return -1;
218
+ const id = effectIdCounter++;
219
+ const info: EffectDebugInfo = {
220
+ id,
221
+ name: input.name,
222
+ type: input.type,
223
+ createdAt: input.createdAt ?? captureSourceLocation(),
224
+ };
225
+ effects.set(id, info);
226
+ emitEffect({ type: traceType(TracePhase.effect.effectAdded), effect: info });
227
+ return id;
228
+ }
229
+
230
+ export function registerRef(input: {
231
+ id: number;
232
+ kind?: string;
233
+ createdAt?: SourceLocation;
234
+ createdByEffectId?: number;
235
+ isInfrastructure?: boolean;
236
+ }) {
237
+ if (!isDevtoolsEnabled()) return;
238
+ if (refs.has(input.id)) return;
239
+ const info: RefDebugInfo = {
240
+ id: input.id,
241
+ kind: input.kind,
242
+ createdAt: input.createdAt ?? captureSourceLocation(),
243
+ createdByEffectId: input.createdByEffectId,
244
+ };
245
+ refs.set(input.id, info);
246
+ emitEffect({ type: traceType(TracePhase.effect.refAdded), ref: info });
247
+ }
248
+
249
+ export function ensureRef(input: { id: number; kind?: string }) {
250
+ if (!isDevtoolsEnabled()) return;
251
+ if (refs.has(input.id)) return;
252
+ registerRef({ id: input.id, kind: input.kind });
253
+ }
254
+
255
+ export function track(input: {
256
+ effectId: number;
257
+ target: unknown;
258
+ refId?: number;
259
+ targetKey?: unknown;
260
+ location?: SourceLocation;
261
+ }) {
262
+ if (!isDevtoolsEnabled()) return;
263
+ const edge: EffectEdgeDebugInfo = {
264
+ id: edgeEventIdCounter++,
265
+ type: "track",
266
+ effectId: input.effectId,
267
+ ...buildEffectTargetInfo({ target: input.target, refId: input.refId }),
268
+ targetKey: sanitizeTargetKey(input.targetKey),
269
+ location: input.location ?? captureSourceLocation(),
270
+ };
271
+ emitEffect({ type: traceType(TracePhase.effect.track), edge });
272
+ }
273
+
274
+ export function trigger(input: {
275
+ effectId: number;
276
+ target: unknown;
277
+ refId?: number;
278
+ targetKey?: unknown;
279
+ location?: SourceLocation;
280
+ kind?: "trigger" | "triggered-by";
281
+ causedBy?: number;
282
+ }) {
283
+ if (!isDevtoolsEnabled()) return;
284
+ const edge: EffectEdgeDebugInfo = {
285
+ id: edgeEventIdCounter++,
286
+ type: input.kind ?? "triggered-by",
287
+ effectId: input.effectId,
288
+ ...buildEffectTargetInfo({ target: input.target, refId: input.refId }),
289
+ targetKey: sanitizeTargetKey(input.targetKey),
290
+ location: input.location ?? captureSourceLocation(),
291
+ };
292
+ emitEffect({ type: traceType(TracePhase.effect.trigger), edge });
293
+
294
+ update({
295
+ id: input.effectId,
296
+ ...(input.refId !== undefined ? { lastTriggeredByRefId: input.refId } : {}),
297
+ lastTriggeredAt: input.location ?? captureSourceLocation(),
298
+ });
299
+ }
300
+
301
+ export function reset() {
302
+ effects.clear();
303
+ refs.clear();
304
+ primitiveTargetIds.clear();
305
+ effectIdCounter = 1;
306
+ edgeEventIdCounter = 1;
307
+ nonRefTargetIdCounter = 1;
308
+ }
309
+
310
+ // Utilities used by other debug sections
311
+ export function isRefTarget(value: unknown) {
312
+ return isRef(value);
313
+ }
314
+
315
+ export function isReactiveTarget(value: unknown) {
316
+ return isReactive(value);
317
+ }