@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
package/src/resource.ts CHANGED
@@ -101,26 +101,35 @@ export function createResource<T, U>(
101
101
  }),
102
102
  );
103
103
  } else {
104
- effect(() => {
105
- let input: T;
106
- if (isRef(getter)) {
107
- input = getter.value;
108
- } else {
109
- input = getter();
110
- }
111
- const promise = (fetcher as (input: T) => Promise<U>)(input);
112
- trackPromise(promise);
113
- promise.then(
114
- (result) => {
115
- resource.data = result;
116
- resource.loading = false;
117
- },
118
- (error) => {
119
- resource.error = error;
120
- resource.loading = false;
104
+ effect(
105
+ () => {
106
+ let input: T;
107
+ if (isRef(getter)) {
108
+ input = getter.value;
109
+ } else {
110
+ input = getter();
111
+ }
112
+ const promise = (fetcher as (input: T) => Promise<U>)(input);
113
+ trackPromise(promise);
114
+ promise.then(
115
+ (result) => {
116
+ resource.data = result;
117
+ resource.loading = false;
118
+ },
119
+ (error) => {
120
+ resource.error = error;
121
+ resource.loading = false;
122
+ },
123
+ );
124
+ },
125
+ undefined,
126
+ {
127
+ debug: {
128
+ name: "resource:fetch",
129
+ type: "resource",
121
130
  },
122
- );
123
- });
131
+ },
132
+ );
124
133
  }
125
134
 
126
135
  return resource;
package/src/scheduler.ts CHANGED
@@ -1,17 +1,44 @@
1
1
  import { ReactiveEffect } from "@vue/reactivity";
2
+ import { debug } from "./debug/index.js";
2
3
 
3
4
  export interface QueueJob {
4
5
  run(): void;
5
6
  }
6
7
  const immediateQueue = new Set<QueueJob>();
7
8
  const queue = new Set<QueueJob>();
9
+ function isJobActive(job: QueueJob): boolean {
10
+ // ReactiveEffect uses bit 0 (flags & 1) as the ACTIVE flag.
11
+ // Skip effects that were stopped after being queued.
12
+ const flags = (job as any).flags;
13
+ return flags === undefined || (flags & 1) !== 0;
14
+ }
8
15
  const pendingPromises = new Set<Promise<any>>();
16
+ let waitForSignalPromise: Promise<void> | null = null;
17
+ let resolveWaitForSignal: (() => void) | null = null;
18
+ let jobSignalPromise: Promise<void> | null = null;
19
+ let resolveJobSignal: (() => void) | null = null;
20
+
21
+ // Maps effect debug IDs to the ref that most recently triggered them
22
+ const lastTriggerRef = new Map<number, number>();
23
+
24
+ /**
25
+ * Record which ref triggered an effect re-run.
26
+ * Called from the onTrigger debug hook before the effect is scheduled.
27
+ */
28
+ export function setLastTriggerRef(effectDebugId: number, refId: number): void {
29
+ lastTriggerRef.set(effectDebugId, refId);
30
+ }
9
31
 
10
32
  export function scheduler(immediate = false) {
33
+ if (!immediate) return defaultScheduler;
11
34
  return function (this: ReactiveEffect) {
12
- queueJob(this, immediate);
35
+ queueJob(this, true);
13
36
  };
14
37
  }
38
+
39
+ const defaultScheduler = function (this: ReactiveEffect) {
40
+ queueJob(this, false);
41
+ };
15
42
  export function queueJob(job: QueueJob | (() => void), immediate = false) {
16
43
  // if we have an immediate job, we don't need to queue the normal job.
17
44
  // the set is serving an important purpose here in deduping the effects we run
@@ -19,12 +46,17 @@ export function queueJob(job: QueueJob | (() => void), immediate = false) {
19
46
  if (typeof job === "function") {
20
47
  job = { run: job };
21
48
  }
22
-
23
49
  if (immediate) {
24
50
  immediateQueue.add(job);
25
51
  } else {
26
52
  queue.add(job);
27
53
  }
54
+
55
+ if (resolveJobSignal) {
56
+ resolveJobSignal();
57
+ resolveJobSignal = null;
58
+ jobSignalPromise = null;
59
+ }
28
60
  }
29
61
 
30
62
  /**
@@ -42,6 +74,7 @@ export function flushJobs() {
42
74
  // First, run all synchronous jobs
43
75
  let job;
44
76
  while ((job = takeJob()) !== null) {
77
+ if (!isJobActive(job)) continue;
45
78
  job.run();
46
79
  }
47
80
 
@@ -51,6 +84,33 @@ export function flushJobs() {
51
84
  "Asynchronous jobs were found but render was called synchronously. Use `renderAsync` instead.",
52
85
  );
53
86
  }
87
+
88
+ debug.render.flushJobsComplete();
89
+ }
90
+
91
+ export function waitForSignal(): Promise<void> {
92
+ if (!waitForSignalPromise) {
93
+ waitForSignalPromise = new Promise<void>((resolve) => {
94
+ resolveWaitForSignal = resolve;
95
+ });
96
+ pendingPromises.add(waitForSignalPromise);
97
+ }
98
+ return waitForSignalPromise;
99
+ }
100
+
101
+ export function signalSchedulerWait() {
102
+ if (resolveWaitForSignal) {
103
+ resolveWaitForSignal();
104
+ resolveWaitForSignal = null;
105
+ }
106
+ if (waitForSignalPromise) {
107
+ pendingPromises.delete(waitForSignalPromise);
108
+ }
109
+ waitForSignalPromise = null;
110
+ }
111
+
112
+ export function isWaitingForSignal() {
113
+ return waitForSignalPromise !== null;
54
114
  }
55
115
 
56
116
  export async function flushJobsAsync() {
@@ -59,6 +119,7 @@ export async function flushJobsAsync() {
59
119
  // First, run all synchronous jobs
60
120
  let job;
61
121
  while ((job = takeJob()) !== null) {
122
+ if (!isJobActive(job)) continue;
62
123
  job.run();
63
124
  }
64
125
 
@@ -67,9 +128,24 @@ export async function flushJobsAsync() {
67
128
  break;
68
129
  }
69
130
 
70
- // Wait for all current promises to complete
71
- await Promise.allSettled(Array.from(pendingPromises));
131
+ if (!jobSignalPromise) {
132
+ jobSignalPromise = new Promise<void>((resolve) => {
133
+ resolveJobSignal = resolve;
134
+ });
135
+ }
136
+
137
+ // Wait for either pending promises to complete or new jobs to arrive
138
+ await Promise.race([
139
+ Promise.allSettled(Array.from(pendingPromises)),
140
+ jobSignalPromise,
141
+ ]);
142
+
143
+ // Clear the job signal after each iteration so we create a new one next time
144
+ jobSignalPromise = null;
145
+ resolveJobSignal = null;
72
146
  }
147
+
148
+ debug.render.flushJobsComplete();
73
149
  }
74
150
 
75
151
  function takeJob() {
@@ -1,3 +1,4 @@
1
+ import { createSymbol } from "../binder.js";
1
2
  import { OutputSymbol } from "./output-symbol.js";
2
3
 
3
4
  /**
@@ -16,7 +17,11 @@ export class BasicSymbol extends OutputSymbol {
16
17
 
17
18
  copy() {
18
19
  const options = this.getCopyOptions();
19
- const copiedSymbol = new BasicSymbol(this.name, undefined, options);
20
+ const binder = this.binder;
21
+ const copiedSymbol = createSymbol(BasicSymbol, this.name, undefined, {
22
+ ...options,
23
+ binder,
24
+ });
20
25
  this.initializeCopy(copiedSymbol);
21
26
 
22
27
  return copiedSymbol;
@@ -1,4 +1,5 @@
1
1
  import { toRef } from "@vue/reactivity";
2
+ import { createSymbol } from "../binder.js";
2
3
  import { useScope } from "../context/scope.js";
3
4
  import { Namekey } from "../refkey.js";
4
5
  import { createComponent } from "../runtime/component.js";
@@ -18,7 +19,10 @@ export function decl(namekey: Namekey) {
18
19
  `Cannot declare symbol in non-basic scope: ${currentScope.constructor.name}. Use a language-specific 'decl' function instead.`,
19
20
  );
20
21
  }
21
- const symbol = new BasicSymbol(namekey, currentScope.symbols);
22
+ const binder = currentScope.binder;
23
+ const symbol = createSymbol(BasicSymbol, namekey, currentScope.symbols, {
24
+ binder,
25
+ });
22
26
 
23
27
  return toRef(symbol, "name");
24
28
  }, {});
@@ -1,8 +1,6 @@
1
1
  import {
2
- effect,
3
2
  reactive,
4
3
  ReactiveFlags,
5
- shallowReactive,
6
4
  track,
7
5
  TrackOpTypes,
8
6
  trigger,
@@ -11,8 +9,7 @@ import {
11
9
  import type { Binder } from "../binder.js";
12
10
  import { useBinder } from "../context/binder.js";
13
11
  import { inspect } from "../inspect.js";
14
- import { untrack } from "../reactivity.js";
15
- import { formatScope, trace, traceEffect, TracePhase } from "../tracer.js";
12
+ import { effect, shallowReactive, untrack } from "../reactivity.js";
16
13
  import { OutputDeclarationSpace, OutputSpace } from "./output-space.js";
17
14
  import { OutputSymbol } from "./output-symbol.js";
18
15
 
@@ -154,7 +151,7 @@ export abstract class OutputScope {
154
151
  return this.#binder;
155
152
  }
156
153
 
157
- [ReactiveFlags.SKIP] = this;
154
+ [ReactiveFlags.SKIP] = true;
158
155
 
159
156
  constructor(
160
157
  name: string,
@@ -167,9 +164,20 @@ export abstract class OutputScope {
167
164
  this.#binder = options.binder ?? useBinder();
168
165
  this.#children = shallowReactive(new Set());
169
166
  this.#parent = parentScope;
170
- effect(() => {
171
- this.#setOwnerSymbol(options.ownerSymbol?.movedTo ?? options.ownerSymbol);
172
- });
167
+ effect(
168
+ () => {
169
+ this.#setOwnerSymbol(
170
+ options.ownerSymbol?.movedTo ?? options.ownerSymbol,
171
+ );
172
+ },
173
+ undefined,
174
+ {
175
+ debug: {
176
+ name: "outputScope:ownerSymbol",
177
+ type: "symbol",
178
+ },
179
+ },
180
+ );
173
181
 
174
182
  if (this.#parent) {
175
183
  this.#parent.children.add(this);
@@ -184,12 +192,8 @@ export abstract class OutputScope {
184
192
  ]),
185
193
  );
186
194
 
195
+ // Notify binder so resolution tracking works even without createScope
187
196
  this.#binder?.notifyScopeCreated(this);
188
-
189
- trace(TracePhase.scope.create, () => `${formatScope(this)}`);
190
- traceEffect(TracePhase.scope.update, () => {
191
- return `${formatScope(this)}`;
192
- });
193
197
  }
194
198
 
195
199
  /**
@@ -215,6 +219,10 @@ export abstract class OutputScope {
215
219
  return this.#ownerSymbol;
216
220
  }
217
221
 
222
+ get debugInfo(): Record<string, unknown> {
223
+ return {};
224
+ }
225
+
218
226
  #setOwnerSymbol(value: OutputSymbol | undefined) {
219
227
  const old = this.#ownerSymbol;
220
228
  this.#ownerSymbol = value;
@@ -3,7 +3,6 @@ import {
3
3
  reactive,
4
4
  ReactiveFlags,
5
5
  Ref,
6
- shallowReactive,
7
6
  track,
8
7
  TrackOpTypes,
9
8
  trigger,
@@ -12,17 +11,19 @@ import {
12
11
  } from "@vue/reactivity";
13
12
  import type { Binder } from "../binder.js";
14
13
  import { useBinder } from "../context/binder.js";
14
+ import { debug, TracePhase } from "../debug/index.js";
15
15
  import { inspect } from "../inspect.js";
16
16
  import { NamePolicyGetter } from "../name-policy.js";
17
- import { untrack } from "../reactivity.js";
18
- import { Namekey, type Refkey } from "../refkey.js";
17
+ import { shallowReactive, untrack } from "../reactivity.js";
19
18
  import {
20
- formatSymbol,
21
- formatSymbolName,
22
- trace,
23
- traceEffect,
24
- TracePhase,
25
- } from "../tracer.js";
19
+ isMemberRefkey,
20
+ isNamekey,
21
+ isSymbolRefkey,
22
+ Namekey,
23
+ toRefkey,
24
+ type Refkey,
25
+ } from "../refkey.js";
26
+ import { formatSymbolName } from "../tracer.js";
26
27
  import {
27
28
  OutputDeclarationSpace,
28
29
  OutputMemberSpace,
@@ -459,6 +460,10 @@ export abstract class OutputSymbol {
459
460
  return this.#isTyped;
460
461
  }
461
462
 
463
+ get debugInfo(): Record<string, unknown> {
464
+ return {};
465
+ }
466
+
462
467
  #namePolicy: NamePolicyGetter | undefined;
463
468
  get namePolicy() {
464
469
  return this.#namePolicy;
@@ -552,10 +557,7 @@ export abstract class OutputSymbol {
552
557
  ]),
553
558
  );
554
559
 
555
- trace(TracePhase.symbol.create, () => `${formatSymbol(this)}`);
556
- traceEffect(TracePhase.symbol.update, () => {
557
- return `${formatSymbol(this)}`;
558
- });
560
+ // Notify binder so resolution tracking works even without createSymbol
559
561
  this.#binder?.notifySymbolCreated(this);
560
562
  }
561
563
 
@@ -570,7 +572,7 @@ export abstract class OutputSymbol {
570
572
  }
571
573
 
572
574
  delete() {
573
- trace(TracePhase.symbol.delete, () => `${formatSymbolName(this)}`);
575
+ debug.trace(TracePhase.symbol.delete, () => `${formatSymbolName(this)}`);
574
576
  if (this.#spaces) {
575
577
  this.#spaces.forEach((space) => space.delete(this));
576
578
  }
@@ -677,3 +679,21 @@ export abstract class OutputSymbol {
677
679
  return untrack(() => `${this.constructor.name} "${this.name}"[${this.id}]`);
678
680
  }
679
681
  }
682
+
683
+ function _formatRefkey(refkey: Refkey): string {
684
+ if (isNamekey(refkey)) {
685
+ return `name:${refkey.name}`;
686
+ }
687
+ if (isMemberRefkey(refkey)) {
688
+ const base = _formatRefkey(toRefkey(refkey.base));
689
+ const member =
690
+ typeof refkey.member === "string" ?
691
+ refkey.member
692
+ : _formatRefkey(toRefkey(refkey.member));
693
+ return `member:${base}.${member}`;
694
+ }
695
+ if (isSymbolRefkey(refkey)) {
696
+ return `key:${refkey.key}`;
697
+ }
698
+ return "refkey";
699
+ }
@@ -1,9 +1,16 @@
1
- import { isRef, Ref, shallowReactive } from "@vue/reactivity";
2
- import { Context, effect, getContext, onCleanup } from "../reactivity.js";
1
+ import { isRef, Ref } from "@vue/reactivity";
2
+ import {
3
+ Context,
4
+ effect,
5
+ getContext,
6
+ onCleanup,
7
+ shallowReactive,
8
+ } from "../reactivity.js";
3
9
 
4
10
  import { MemberContext } from "../context/member-scope.js";
5
11
  import { ScopeContext } from "../context/scope.js";
6
- import { formatSymbolName, trace, TracePhase } from "../tracer.js";
12
+ import { debug, TracePhase } from "../debug/index.js";
13
+ import { formatSymbolName } from "../tracer.js";
7
14
  import { OutputSymbol } from "./output-symbol.js";
8
15
 
9
16
  export interface TakeSymbolCallback {
@@ -19,16 +26,25 @@ export function takeSymbols(cb?: (symbol: OutputSymbol) => void) {
19
26
  context.takesSymbols = true;
20
27
  context.takenSymbols = shallowReactive(new Set<OutputSymbol>());
21
28
  if (cb) {
22
- effect<Set<OutputSymbol>>((oldSymbols) => {
23
- for (const symbol of context.takenSymbols!) {
24
- if (oldSymbols && oldSymbols.has(symbol)) {
25
- continue;
29
+ effect<Set<OutputSymbol>>(
30
+ (oldSymbols) => {
31
+ for (const symbol of context.takenSymbols!) {
32
+ if (oldSymbols && oldSymbols.has(symbol)) {
33
+ continue;
34
+ }
35
+ cb(symbol);
26
36
  }
27
- cb(symbol);
28
- }
29
37
 
30
- return new Set(context.takenSymbols!);
31
- });
38
+ return new Set(context.takenSymbols!);
39
+ },
40
+ undefined,
41
+ {
42
+ debug: {
43
+ name: "symbolFlow:takeSymbols",
44
+ type: "symbol",
45
+ },
46
+ },
47
+ );
32
48
  }
33
49
  return context.takenSymbols;
34
50
  }
@@ -37,9 +53,9 @@ export function emitSymbol(
37
53
  symbol: OutputSymbol | Ref<OutputSymbol | undefined>,
38
54
  ) {
39
55
  if (isRef(symbol)) {
40
- trace(TracePhase.symbol.flow, () => `Emitting ref to symbol`);
56
+ debug.trace(TracePhase.symbol.flow, () => `Emitting ref to symbol`);
41
57
  } else {
42
- trace(
58
+ debug.trace(
43
59
  TracePhase.symbol.flow,
44
60
  () => `Emitting symbol ${formatSymbolName(symbol)}`,
45
61
  );
@@ -58,7 +74,7 @@ export function emitSymbol(
58
74
  (context.context[ScopeContext.id] || context.context[MemberContext.id])
59
75
  ) {
60
76
  // don't cross scope boundaries.
61
- trace(
77
+ debug.trace(
62
78
  TracePhase.symbol.flow,
63
79
  () => `Not emitting symbol across scope boundary`,
64
80
  );
@@ -69,27 +85,39 @@ export function emitSymbol(
69
85
  }
70
86
 
71
87
  if (!symbolTaker) {
72
- trace(TracePhase.symbol.flow, () => `No symbol taker found, not emitting`);
88
+ debug.trace(
89
+ TracePhase.symbol.flow,
90
+ () => `No symbol taker found, not emitting`,
91
+ );
73
92
  return;
74
93
  }
75
94
 
76
95
  if (isRef(symbol)) {
77
- effect<OutputSymbol | undefined>((prevSymbol) => {
78
- onCleanup(() => {
79
- if (symbol.value) {
80
- symbolTaker.takenSymbols!.delete(symbol.value);
96
+ effect<OutputSymbol | undefined>(
97
+ (prevSymbol) => {
98
+ onCleanup(() => {
99
+ if (symbol.value) {
100
+ symbolTaker.takenSymbols!.delete(symbol.value);
101
+ }
102
+ });
103
+ if (symbol.value === undefined) {
104
+ symbolTaker.takenSymbols!.delete(prevSymbol!);
105
+ return undefined;
106
+ } else {
107
+ symbolTaker.takenSymbols!.add(symbol.value);
108
+ return symbol.value;
81
109
  }
82
- });
83
- if (symbol.value === undefined) {
84
- symbolTaker.takenSymbols!.delete(prevSymbol!);
85
- return undefined;
86
- } else {
87
- symbolTaker.takenSymbols!.add(symbol.value);
88
- return symbol.value;
89
- }
90
- });
110
+ },
111
+ undefined,
112
+ {
113
+ debug: {
114
+ name: "symbolFlow:emitRef",
115
+ type: "symbol",
116
+ },
117
+ },
118
+ );
91
119
  } else {
92
- trace(
120
+ debug.trace(
93
121
  TracePhase.symbol.flow,
94
122
  () =>
95
123
  `Emitting symbol ${formatSymbolName(symbol)} taken by ${symbolTaker.componentOwner?.name ?? "unknown component"}`,
@@ -103,19 +131,28 @@ export function emitSymbol(
103
131
 
104
132
  export function moveTakenMembersTo(baseSymbol: OutputSymbol) {
105
133
  const taken = takeSymbols();
106
- effect(() => {
107
- for (const symbol of taken) {
108
- if (symbol.isTransient) {
109
- symbol.moveMembersTo(baseSymbol);
110
- }
134
+ effect(
135
+ () => {
136
+ for (const symbol of taken) {
137
+ if (symbol.isTransient) {
138
+ symbol.moveMembersTo(baseSymbol);
139
+ }
111
140
 
112
- for (const refkey of symbol.refkeys) {
113
- if (!baseSymbol.refkeys.includes(refkey)) {
114
- baseSymbol.refkeys.push(refkey);
141
+ for (const refkey of symbol.refkeys) {
142
+ if (!baseSymbol.refkeys.includes(refkey)) {
143
+ baseSymbol.refkeys.push(refkey);
144
+ }
115
145
  }
116
146
  }
117
- }
118
- });
147
+ },
148
+ undefined,
149
+ {
150
+ debug: {
151
+ name: "symbolFlow:moveTakenMembers",
152
+ type: "symbol",
153
+ },
154
+ },
155
+ );
119
156
  }
120
157
 
121
158
  export function instantiateTakenMembersTo(
@@ -0,0 +1,41 @@
1
+ import { shallowRef } from "@vue/reactivity";
2
+ import { expect, it } from "vitest";
3
+ import { renderTree } from "../render.js";
4
+ import { flushJobs } from "../scheduler.js";
5
+ import { BasicSymbol } from "./basic-symbol.js";
6
+ import { emitSymbol } from "./symbol-flow.js";
7
+ import { createSymbolSlot } from "./symbol-slot.jsx";
8
+
9
+ it("captures firstSymbol", async () => {
10
+ const Slot = createSymbolSlot();
11
+
12
+ renderTree(
13
+ <Slot>
14
+ {() => {
15
+ emitSymbol(new BasicSymbol("a", undefined));
16
+ }}
17
+ </Slot>,
18
+ );
19
+ await flushJobs();
20
+ expect(Slot.firstSymbol.value).toBeDefined();
21
+ expect(Slot.firstSymbol.value!.name).toBe("a");
22
+ });
23
+
24
+ it("captures firstSymbol when emitting a ref to a symbol", async () => {
25
+ const Slot = createSymbolSlot();
26
+ const symref = shallowRef<BasicSymbol | undefined>();
27
+
28
+ renderTree(
29
+ <Slot>
30
+ {() => {
31
+ emitSymbol(symref);
32
+ }}
33
+ </Slot>,
34
+ );
35
+ await flushJobs();
36
+ expect(Slot.firstSymbol.value).toBeUndefined();
37
+ symref.value = new BasicSymbol("a", undefined);
38
+ await flushJobs();
39
+ expect(Slot.firstSymbol.value).toBeDefined();
40
+ expect(Slot.firstSymbol.value!.name).toBe("a");
41
+ });
@@ -50,36 +50,63 @@ export function createSymbolSlot(): SymbolSlot {
50
50
  Object.defineProperty(SymbolSlot, "firstSymbol", {
51
51
  get() {
52
52
  const ref = shallowRef();
53
- effect(() => {
54
- ref.value = symbolSlotRef.value?.values().next().value;
55
- });
53
+ effect(
54
+ () => {
55
+ ref.value = symbolSlotRef.value?.values().next().value;
56
+ },
57
+ undefined,
58
+ {
59
+ debug: {
60
+ name: "symbolSlot:firstSymbol",
61
+ type: "symbol",
62
+ },
63
+ },
64
+ );
56
65
  return ref;
57
66
  },
58
67
  });
59
68
 
60
69
  SymbolSlot.copyMembersTo = (baseSymbol: OutputSymbol) => {
61
- effect(() => {
62
- if (!symbolSlotRef.value) {
63
- return;
64
- }
70
+ effect(
71
+ () => {
72
+ if (!symbolSlotRef.value) {
73
+ return;
74
+ }
65
75
 
66
- for (const symbol of symbolSlotRef.value) {
67
- symbol.copyMembersTo(baseSymbol);
68
- }
69
- });
76
+ for (const symbol of symbolSlotRef.value) {
77
+ symbol.copyMembersTo(baseSymbol);
78
+ }
79
+ },
80
+ undefined,
81
+ {
82
+ debug: {
83
+ name: "symbolSlot:copyMembers",
84
+ type: "symbol",
85
+ },
86
+ },
87
+ );
70
88
  };
71
89
 
72
90
  SymbolSlot.moveMembersTo = (baseSymbol: OutputSymbol) => {
73
- effect(() => {
74
- if (!symbolSlotRef.value) {
75
- return;
76
- }
77
- for (const symbol of symbolSlotRef.value) {
78
- if (symbol.isTransient) {
79
- symbol.moveMembersTo(baseSymbol);
91
+ effect(
92
+ () => {
93
+ if (!symbolSlotRef.value) {
94
+ return;
80
95
  }
81
- }
82
- });
96
+ for (const symbol of symbolSlotRef.value) {
97
+ if (symbol.isTransient) {
98
+ symbol.moveMembersTo(baseSymbol);
99
+ }
100
+ }
101
+ },
102
+ undefined,
103
+ {
104
+ debug: {
105
+ name: "symbolSlot:moveMembers",
106
+ type: "symbol",
107
+ },
108
+ },
109
+ );
83
110
  };
84
111
 
85
112
  return SymbolSlot as any;