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

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 (269) 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/AppendFile.d.ts.map +1 -1
  8. package/dist/src/components/AppendFile.js +14 -3
  9. package/dist/src/components/AppendFile.js.map +1 -1
  10. package/dist/src/components/Block.js +1 -1
  11. package/dist/src/components/Block.js.map +1 -1
  12. package/dist/src/components/Declaration.d.ts.map +1 -1
  13. package/dist/src/components/Declaration.js +2 -1
  14. package/dist/src/components/Declaration.js.map +1 -1
  15. package/dist/src/components/Scope.d.ts.map +1 -1
  16. package/dist/src/components/Scope.js +4 -1
  17. package/dist/src/components/Scope.js.map +1 -1
  18. package/dist/src/components/TemplateFile.d.ts.map +1 -1
  19. package/dist/src/components/TemplateFile.js +18 -3
  20. package/dist/src/components/TemplateFile.js.map +1 -1
  21. package/dist/src/content-slot.d.ts.map +1 -1
  22. package/dist/src/content-slot.js +6 -5
  23. package/dist/src/content-slot.js.map +1 -1
  24. package/dist/src/context.d.ts.map +1 -1
  25. package/dist/src/context.js +8 -1
  26. package/dist/src/context.js.map +1 -1
  27. package/dist/src/debug/cli.d.ts +6 -0
  28. package/dist/src/debug/cli.d.ts.map +1 -0
  29. package/dist/src/{debug.js → debug/cli.js} +78 -84
  30. package/dist/src/debug/cli.js.map +1 -0
  31. package/dist/src/debug/diagnostics.test.d.ts +2 -0
  32. package/dist/src/debug/diagnostics.test.d.ts.map +1 -0
  33. package/dist/src/debug/diagnostics.test.js +45 -0
  34. package/dist/src/debug/diagnostics.test.js.map +1 -0
  35. package/dist/src/debug/effects.d.ts +69 -0
  36. package/dist/src/debug/effects.d.ts.map +1 -0
  37. package/dist/src/debug/effects.js +228 -0
  38. package/dist/src/debug/effects.js.map +1 -0
  39. package/dist/src/debug/effects.test.d.ts +2 -0
  40. package/dist/src/debug/effects.test.d.ts.map +1 -0
  41. package/dist/src/debug/effects.test.js +86 -0
  42. package/dist/src/debug/effects.test.js.map +1 -0
  43. package/dist/src/debug/files.d.ts +14 -0
  44. package/dist/src/debug/files.d.ts.map +1 -0
  45. package/dist/src/debug/files.js +40 -0
  46. package/dist/src/debug/files.js.map +1 -0
  47. package/dist/src/debug/files.test.d.ts +2 -0
  48. package/dist/src/debug/files.test.d.ts.map +1 -0
  49. package/dist/src/debug/files.test.js +89 -0
  50. package/dist/src/debug/files.test.js.map +1 -0
  51. package/dist/src/debug/index.d.ts +60 -0
  52. package/dist/src/debug/index.d.ts.map +1 -0
  53. package/dist/src/debug/index.js +68 -0
  54. package/dist/src/debug/index.js.map +1 -0
  55. package/dist/src/debug/render.d.ts +57 -0
  56. package/dist/src/debug/render.d.ts.map +1 -0
  57. package/dist/src/debug/render.js +519 -0
  58. package/dist/src/debug/render.js.map +1 -0
  59. package/dist/src/debug/render.test.d.ts +2 -0
  60. package/dist/src/debug/render.test.d.ts.map +1 -0
  61. package/dist/src/debug/render.test.js +328 -0
  62. package/dist/src/debug/render.test.js.map +1 -0
  63. package/dist/src/debug/serialize.d.ts +9 -0
  64. package/dist/src/debug/serialize.d.ts.map +1 -0
  65. package/dist/src/debug/serialize.js +70 -0
  66. package/dist/src/debug/serialize.js.map +1 -0
  67. package/dist/src/debug/symbols.d.ts +9 -0
  68. package/dist/src/debug/symbols.d.ts.map +1 -0
  69. package/dist/src/debug/symbols.js +164 -0
  70. package/dist/src/debug/symbols.js.map +1 -0
  71. package/dist/src/debug/symbols.test.d.ts +2 -0
  72. package/dist/src/debug/symbols.test.d.ts.map +1 -0
  73. package/dist/src/debug/symbols.test.js +104 -0
  74. package/dist/src/debug/symbols.test.js.map +1 -0
  75. package/dist/src/debug/trace.d.ts +342 -0
  76. package/dist/src/debug/trace.d.ts.map +1 -0
  77. package/dist/src/debug/trace.js +443 -0
  78. package/dist/src/debug/trace.js.map +1 -0
  79. package/dist/src/devtools/devtools-protocol.d.ts +232 -0
  80. package/dist/src/devtools/devtools-protocol.d.ts.map +1 -0
  81. package/dist/src/devtools/devtools-protocol.js +2 -0
  82. package/dist/src/devtools/devtools-protocol.js.map +1 -0
  83. package/dist/src/devtools/devtools-server.browser.d.ts +28 -0
  84. package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -0
  85. package/dist/src/devtools/devtools-server.browser.js +36 -0
  86. package/dist/src/devtools/devtools-server.browser.js.map +1 -0
  87. package/dist/src/devtools/devtools-server.d.ts +72 -0
  88. package/dist/src/devtools/devtools-server.d.ts.map +1 -0
  89. package/dist/src/devtools/devtools-server.js +256 -0
  90. package/dist/src/devtools/devtools-server.js.map +1 -0
  91. package/dist/src/devtools/devtools-transport.d.ts +23 -0
  92. package/dist/src/devtools/devtools-transport.d.ts.map +1 -0
  93. package/dist/src/devtools/devtools-transport.js +114 -0
  94. package/dist/src/devtools/devtools-transport.js.map +1 -0
  95. package/dist/src/devtools-entry.browser.d.ts +4 -0
  96. package/dist/src/devtools-entry.browser.d.ts.map +1 -0
  97. package/dist/src/devtools-entry.browser.js +2 -0
  98. package/dist/src/devtools-entry.browser.js.map +1 -0
  99. package/dist/src/devtools-entry.d.ts +4 -0
  100. package/dist/src/devtools-entry.d.ts.map +1 -0
  101. package/dist/src/devtools-entry.js +2 -0
  102. package/dist/src/devtools-entry.js.map +1 -0
  103. package/dist/src/diagnostics.d.ts +34 -0
  104. package/dist/src/diagnostics.d.ts.map +1 -0
  105. package/dist/src/diagnostics.js +89 -0
  106. package/dist/src/diagnostics.js.map +1 -0
  107. package/dist/src/index.d.ts +3 -2
  108. package/dist/src/index.d.ts.map +1 -1
  109. package/dist/src/index.js +3 -2
  110. package/dist/src/index.js.map +1 -1
  111. package/dist/src/print-hook.d.ts +14 -0
  112. package/dist/src/print-hook.d.ts.map +1 -0
  113. package/dist/src/print-hook.js +10 -0
  114. package/dist/src/print-hook.js.map +1 -0
  115. package/dist/src/reactive-union-set.d.ts.map +1 -1
  116. package/dist/src/reactive-union-set.js +15 -0
  117. package/dist/src/reactive-union-set.js.map +1 -1
  118. package/dist/src/reactivity.d.ts +17 -3
  119. package/dist/src/reactivity.d.ts.map +1 -1
  120. package/dist/src/reactivity.js +162 -14
  121. package/dist/src/reactivity.js.map +1 -1
  122. package/dist/src/render-stack.d.ts +29 -0
  123. package/dist/src/render-stack.d.ts.map +1 -0
  124. package/dist/src/render-stack.js +247 -0
  125. package/dist/src/render-stack.js.map +1 -0
  126. package/dist/src/render.d.ts +9 -19
  127. package/dist/src/render.d.ts.map +1 -1
  128. package/dist/src/render.js +363 -153
  129. package/dist/src/render.js.map +1 -1
  130. package/dist/src/resource.d.ts.map +1 -1
  131. package/dist/src/resource.js +5 -0
  132. package/dist/src/resource.js.map +1 -1
  133. package/dist/src/runtime/component.d.ts +7 -1
  134. package/dist/src/runtime/component.d.ts.map +1 -1
  135. package/dist/src/runtime/component.js +4 -1
  136. package/dist/src/runtime/component.js.map +1 -1
  137. package/dist/src/scheduler.d.ts +3 -0
  138. package/dist/src/scheduler.d.ts.map +1 -1
  139. package/dist/src/scheduler.js +45 -2
  140. package/dist/src/scheduler.js.map +1 -1
  141. package/dist/src/symbols/basic-symbol.d.ts.map +1 -1
  142. package/dist/src/symbols/basic-symbol.js +6 -1
  143. package/dist/src/symbols/basic-symbol.js.map +1 -1
  144. package/dist/src/symbols/decl.d.ts.map +1 -1
  145. package/dist/src/symbols/decl.js +5 -1
  146. package/dist/src/symbols/decl.js.map +1 -1
  147. package/dist/src/symbols/output-scope.d.ts +2 -1
  148. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  149. package/dist/src/symbols/output-scope.js +13 -8
  150. package/dist/src/symbols/output-scope.js.map +1 -1
  151. package/dist/src/symbols/output-symbol.d.ts +1 -0
  152. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  153. package/dist/src/symbols/output-symbol.js +23 -6
  154. package/dist/src/symbols/output-symbol.js.map +1 -1
  155. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  156. package/dist/src/symbols/symbol-flow.js +22 -6
  157. package/dist/src/symbols/symbol-flow.js.map +1 -1
  158. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  159. package/dist/src/symbols/symbol-slot.js +15 -0
  160. package/dist/src/symbols/symbol-slot.js.map +1 -1
  161. package/dist/src/symbols/symbol-slot.test.d.ts +2 -0
  162. package/dist/src/symbols/symbol-slot.test.d.ts.map +1 -0
  163. package/dist/src/symbols/symbol-slot.test.js +35 -0
  164. package/dist/src/symbols/symbol-slot.test.js.map +1 -0
  165. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  166. package/dist/src/symbols/symbol-table.js +6 -5
  167. package/dist/src/symbols/symbol-table.js.map +1 -1
  168. package/dist/src/trace.d.ts +2 -0
  169. package/dist/src/trace.d.ts.map +1 -0
  170. package/dist/src/trace.js +2 -0
  171. package/dist/src/trace.js.map +1 -0
  172. package/dist/src/tracer.d.ts +2 -228
  173. package/dist/src/tracer.d.ts.map +1 -1
  174. package/dist/src/tracer.js +5 -298
  175. package/dist/src/tracer.js.map +1 -1
  176. package/dist/src/utils.d.ts.map +1 -1
  177. package/dist/src/utils.js +5 -0
  178. package/dist/src/utils.js.map +1 -1
  179. package/dist/test/components/append-file.test.d.ts.map +1 -1
  180. package/dist/test/components/append-file.test.js +18 -10
  181. package/dist/test/components/append-file.test.js.map +1 -1
  182. package/dist/test/components/template-file.test.d.ts.map +1 -1
  183. package/dist/test/components/template-file.test.js +6 -4
  184. package/dist/test/components/template-file.test.js.map +1 -1
  185. package/dist/test/rendering/basic.test.js +3 -0
  186. package/dist/test/rendering/basic.test.js.map +1 -1
  187. package/dist/test/rendering/print-render-stack.test.d.ts +2 -0
  188. package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -0
  189. package/dist/test/rendering/print-render-stack.test.js +207 -0
  190. package/dist/test/rendering/print-render-stack.test.js.map +1 -0
  191. package/dist/testing/create-test-wrapper.d.ts +1 -1
  192. package/dist/testing/create-test-wrapper.d.ts.map +1 -1
  193. package/dist/testing/create-test-wrapper.js +1 -1
  194. package/dist/testing/create-test-wrapper.js.map +1 -1
  195. package/dist/testing/devtools-utils.d.ts +26 -0
  196. package/dist/testing/devtools-utils.d.ts.map +1 -0
  197. package/dist/testing/devtools-utils.js +140 -0
  198. package/dist/testing/devtools-utils.js.map +1 -0
  199. package/dist/testing/extend-expect.d.ts.map +1 -1
  200. package/dist/testing/extend-expect.js +63 -1
  201. package/dist/testing/extend-expect.js.map +1 -1
  202. package/dist/testing/render.d.ts +2 -2
  203. package/dist/testing/render.d.ts.map +1 -1
  204. package/dist/testing/render.js +2 -2
  205. package/dist/testing/render.js.map +1 -1
  206. package/dist/tsconfig.tsbuildinfo +1 -1
  207. package/package.json +21 -7
  208. package/scripts/copy-devtools-ui.mjs +26 -0
  209. package/src/binder.ts +71 -16
  210. package/src/components/AppendFile.tsx +14 -9
  211. package/src/components/Block.tsx +1 -1
  212. package/src/components/Declaration.tsx +2 -1
  213. package/src/components/Scope.tsx +4 -1
  214. package/src/components/TemplateFile.tsx +18 -9
  215. package/src/content-slot.tsx +6 -6
  216. package/src/context.ts +15 -4
  217. package/src/{debug.ts → debug/cli.ts} +112 -127
  218. package/src/debug/diagnostics.test.tsx +55 -0
  219. package/src/debug/effects.test.tsx +96 -0
  220. package/src/debug/effects.ts +313 -0
  221. package/src/debug/files.test.tsx +96 -0
  222. package/src/debug/files.ts +40 -0
  223. package/src/debug/index.ts +126 -0
  224. package/src/debug/render.test.tsx +379 -0
  225. package/src/debug/render.ts +639 -0
  226. package/src/debug/serialize.ts +85 -0
  227. package/src/debug/symbols.test.tsx +106 -0
  228. package/src/debug/symbols.ts +230 -0
  229. package/src/debug/trace.ts +312 -0
  230. package/src/devtools/devtools-protocol.ts +312 -0
  231. package/src/devtools/devtools-server.browser.ts +71 -0
  232. package/src/devtools/devtools-server.ts +290 -0
  233. package/src/devtools/devtools-transport.ts +154 -0
  234. package/src/devtools-entry.browser.ts +52 -0
  235. package/src/devtools-entry.ts +54 -0
  236. package/src/diagnostics.ts +141 -0
  237. package/src/index.ts +2 -6
  238. package/src/print-hook.ts +22 -0
  239. package/src/reactive-union-set.ts +71 -41
  240. package/src/reactivity.ts +206 -23
  241. package/src/render-stack.ts +289 -0
  242. package/src/render.ts +464 -212
  243. package/src/resource.ts +28 -19
  244. package/src/runtime/component.ts +11 -0
  245. package/src/scheduler.ts +55 -3
  246. package/src/symbols/basic-symbol.ts +6 -1
  247. package/src/symbols/decl.ts +5 -1
  248. package/src/symbols/output-scope.ts +21 -12
  249. package/src/symbols/output-symbol.ts +33 -12
  250. package/src/symbols/symbol-flow.ts +68 -37
  251. package/src/symbols/symbol-slot.test.tsx +41 -0
  252. package/src/symbols/symbol-slot.tsx +47 -20
  253. package/src/symbols/symbol-table.ts +6 -10
  254. package/src/trace.ts +1 -0
  255. package/src/tracer.ts +13 -242
  256. package/src/utils.tsx +22 -13
  257. package/temp/api.json +1811 -277
  258. package/test/components/append-file.test.tsx +36 -29
  259. package/test/components/template-file.test.tsx +11 -11
  260. package/test/rendering/basic.test.tsx +4 -0
  261. package/test/rendering/print-render-stack.test.tsx +244 -0
  262. package/testing/create-test-wrapper.tsx +1 -1
  263. package/testing/devtools-utils.ts +203 -0
  264. package/testing/extend-expect.ts +89 -0
  265. package/testing/render.ts +2 -2
  266. package/testing/vitest.d.ts +9 -0
  267. package/dist/src/debug.d.ts +0 -15
  268. package/dist/src/debug.d.ts.map +0 -1
  269. package/dist/src/debug.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@alloy-js/core",
3
- "version": "0.23.0-dev.0",
3
+ "version": "0.23.0-dev.8",
4
4
  "description": "",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/alloy-framework/alloy.git"
8
+ },
5
9
  "main": "./dist/src/index.js",
6
10
  "exports": {
7
11
  ".": {
@@ -23,33 +27,43 @@
23
27
  },
24
28
  "./components": {
25
29
  "import": "./dist/src/components/index.js"
30
+ },
31
+ "./devtools": {
32
+ "types": "./dist/src/devtools-entry.d.ts",
33
+ "browser": "./dist/src/devtools-entry.browser.js",
34
+ "import": "./dist/src/devtools-entry.js"
26
35
  }
27
36
  },
28
37
  "browser": {
29
38
  "./dist/src/host/alloy-host.js": "./dist/src/host/alloy-host.browser.js",
30
39
  "./src/host/alloy-host.ts": "./src/host/alloy-host.browser.ts",
31
40
  "./dist/src/inspect.js": "./dist/src/inspect.browser.js",
32
- "./src/inspect.ts": "./src/inspect.browser.ts"
41
+ "./src/inspect.ts": "./src/inspect.browser.ts",
42
+ "./dist/src/devtools/devtools-server.js": "./dist/src/devtools/devtools-server.browser.js",
43
+ "./src/devtools/devtools-server.ts": "./src/devtools/devtools-server.browser.ts"
33
44
  },
34
45
  "keywords": [],
35
46
  "author": "brian.terlson@microsoft.com",
36
47
  "license": "MIT",
37
48
  "dependencies": {
49
+ "@types/ws": "^8.18.1",
38
50
  "@vue/reactivity": "^3.5.13",
39
- "picocolors": "^1.1.1",
40
51
  "cli-table3": "^0.6.5",
52
+ "devalue": "^5.6.2",
41
53
  "pathe": "^2.0.3",
42
- "prettier": "^3.6.2"
54
+ "picocolors": "^1.1.1",
55
+ "prettier": "^3.6.2",
56
+ "ws": "^8.19.0"
43
57
  },
44
58
  "devDependencies": {
45
- "@alloy-js/cli": "~0.22.0 || >= 0.23.0-dev.0",
46
- "@alloy-js/rollup-plugin": "~0.1.0 || >= 0.1.1-dev.0",
59
+ "@alloy-js/cli": "~0.22.0 || >= 0.23.0-dev.3",
60
+ "@alloy-js/rollup-plugin": "~0.1.0 || >= 0.1.1-dev.1",
47
61
  "@microsoft/api-extractor": "~7.52.8",
48
62
  "@rollup/plugin-typescript": "^12.1.2",
49
63
  "concurrently": "^9.2.0",
50
64
  "typescript": "^5.8.3",
51
65
  "vite": "^7.0.6",
52
- "vitest": "^3.2.4"
66
+ "vitest": "3.2.4"
53
67
  },
54
68
  "type": "module",
55
69
  "scripts": {
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { copyFile, mkdir } from "fs/promises";
4
+ import { dirname, join } from "path";
5
+ import { fileURLToPath } from "url";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ const srcFile = join(__dirname, "../../devtools/dist/index.html");
11
+ const destFile = join(__dirname, "../dist/devtools/index.html");
12
+
13
+ async function copyDevtoolsUi() {
14
+ try {
15
+ await mkdir(dirname(destFile), { recursive: true });
16
+ await copyFile(srcFile, destFile);
17
+ // eslint-disable-next-line no-console
18
+ console.log("Copied devtools UI to core dist");
19
+ } catch (error) {
20
+ // eslint-disable-next-line no-console
21
+ console.error("Failed to copy devtools UI:", error);
22
+ process.exit(1);
23
+ }
24
+ }
25
+
26
+ void copyDevtoolsUi();
package/src/binder.ts CHANGED
@@ -2,8 +2,11 @@ import { computed, Ref, ShallowRef, shallowRef } from "@vue/reactivity";
2
2
  import { useBinder } from "./context/binder.js";
3
3
  import { useMemberContext } from "./context/member-scope.js";
4
4
  import { useScope } from "./context/scope.js";
5
- import { effect } from "./reactivity.js";
5
+ import { debug, TracePhase } from "./debug/index.js";
6
+ import { emitDiagnostic, type DiagnosticHandle } from "./diagnostics.js";
7
+ import { effect, onCleanup } from "./reactivity.js";
6
8
  import {
9
+ inspectRefkey,
7
10
  isMemberRefkey,
8
11
  MemberRefkey,
9
12
  refkey,
@@ -13,12 +16,7 @@ import {
13
16
  } from "./refkey.js";
14
17
  import { OutputScope } from "./symbols/output-scope.js";
15
18
  import { type OutputSymbol } from "./symbols/output-symbol.js";
16
- import {
17
- formatRefkeys,
18
- formatSymbolName,
19
- trace,
20
- TracePhase,
21
- } from "./tracer.js";
19
+ import { formatRefkeys, formatSymbolName } from "./tracer.js";
22
20
  export type Metadata = object;
23
21
 
24
22
  /**
@@ -211,6 +209,24 @@ export interface BinderOptions {
211
209
  nameConflictResolver?: NameConflictResolver;
212
210
  }
213
211
 
212
+ export function createScope<TScope extends OutputScope, Args extends unknown[]>(
213
+ ctor: new (...args: Args) => TScope,
214
+ ...args: Args
215
+ ): TScope {
216
+ const scope = new ctor(...args);
217
+ debug.symbols.registerScope(scope);
218
+ return scope;
219
+ }
220
+
221
+ export function createSymbol<
222
+ TSymbol extends OutputSymbol,
223
+ Args extends unknown[],
224
+ >(ctor: new (...args: Args) => TSymbol, ...args: Args): TSymbol {
225
+ const symbol = new ctor(...args);
226
+ debug.symbols.registerSymbol(symbol);
227
+ return symbol;
228
+ }
229
+
214
230
  export function createOutputBinder(options: BinderOptions = {}): Binder {
215
231
  const binder: Binder = {
216
232
  resolveDeclarationByKey,
@@ -247,6 +263,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
247
263
  }
248
264
 
249
265
  function notifySymbolDeleted(symbol: OutputSymbol) {
266
+ debug.symbols.unregisterSymbol(symbol);
250
267
  if (!refkey) {
251
268
  return;
252
269
  }
@@ -458,25 +475,25 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
458
475
  const resolvedSymbol = getSymbolForRefkey(refkey);
459
476
 
460
477
  return computed(() => {
461
- trace(
478
+ debug.trace(
462
479
  TracePhase.resolve.pending,
463
480
  () => `Resolving ${formatRefkeys(refkey)}.`,
464
481
  );
465
482
  const symbol = resolvedSymbol.value as TSymbol;
466
483
  if (!symbol) {
467
- trace(
484
+ debug.trace(
468
485
  TracePhase.resolve.failure,
469
486
  () => `No symbol for ${formatRefkeys(refkey)}.`,
470
487
  );
471
488
  return undefined;
472
489
  }
473
- trace(
490
+ debug.trace(
474
491
  TracePhase.resolve.pending,
475
492
  () =>
476
493
  `${formatRefkeys(refkey)} resolved to ${formatSymbolName(symbol)}.`,
477
494
  );
478
495
  if (symbol.isTransient) {
479
- trace(
496
+ debug.trace(
480
497
  TracePhase.resolve.failure,
481
498
  () => `Symbol ${formatSymbolName(symbol)} is transient.`,
482
499
  );
@@ -485,7 +502,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
485
502
 
486
503
  const chain = scopeChain(symbol.scope);
487
504
  if (chain.some((scope) => scope.isTransient)) {
488
- trace(
505
+ debug.trace(
489
506
  TracePhase.resolve.failure,
490
507
  () => `Symbol ${formatSymbolName(symbol)} is in a transient scope.`,
491
508
  );
@@ -533,7 +550,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
533
550
  for (const descriptor of allDescriptors) {
534
551
  const member = descriptor.symbol as TSymbol;
535
552
  if (currentBase.isTyped && !currentBase.hasTypeSymbol) {
536
- trace(
553
+ debug.trace(
537
554
  TracePhase.resolve.pending,
538
555
  () =>
539
556
  `${formatRefkeys(refkey)} needs type information from a parent type.`,
@@ -550,7 +567,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
550
567
  currentBase = member;
551
568
  }
552
569
 
553
- trace(
570
+ debug.trace(
554
571
  TracePhase.resolve.success,
555
572
  () =>
556
573
  `${formatRefkeys(refkey)} successfully resolved to ${formatSymbolName(symbol)}.`,
@@ -628,7 +645,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
628
645
  function notifySymbolCreated(symbol: OutputSymbol): void {
629
646
  effect<Refkey[]>((oldRefkeys) => {
630
647
  if (symbol.refkeys) {
631
- trace(
648
+ debug.trace(
632
649
  TracePhase.resolve.pending,
633
650
  () => `Notifying resolutions for ${formatRefkeys(symbol.refkeys)}.`,
634
651
  );
@@ -702,11 +719,49 @@ export function resolve<
702
719
  throw new Error("Can't resolve refkey without a binder");
703
720
  }
704
721
 
705
- return binder.resolveDeclarationByKey(
722
+ const result = binder.resolveDeclarationByKey(
706
723
  scope as TScope,
707
724
  refkey,
708
725
  options,
709
726
  ) as any;
727
+
728
+ let diagnosticHandle: DiagnosticHandle | null = null;
729
+
730
+ effect(
731
+ () => {
732
+ if (result.value === undefined) {
733
+ // Emit diagnostic for this specific reference site
734
+ if (!diagnosticHandle) {
735
+ diagnosticHandle = emitDiagnostic({
736
+ severity: "warning",
737
+ message: `Unresolved refkey: ${inspectRefkey(refkey)}`,
738
+ });
739
+ }
740
+ } else {
741
+ // Dismiss diagnostic when resolved
742
+ if (diagnosticHandle) {
743
+ diagnosticHandle.dismiss();
744
+ diagnosticHandle = null;
745
+ }
746
+ }
747
+ },
748
+ undefined,
749
+ {
750
+ debug: {
751
+ name: `binder:resolve:${inspectRefkey(refkey)}`,
752
+ type: "binder",
753
+ },
754
+ },
755
+ );
756
+
757
+ onCleanup(() => {
758
+ if (diagnosticHandle) {
759
+ diagnosticHandle.dismiss();
760
+ diagnosticHandle = null;
761
+ }
762
+ });
763
+
764
+ return result;
710
765
  }
711
766
 
712
767
  /**
@@ -2,6 +2,7 @@ import { computed } from "@vue/reactivity";
2
2
  import { join } from "pathe";
3
3
  import { useContext } from "../context.js";
4
4
  import { SourceDirectoryContext } from "../context/source-directory.js";
5
+ import { emitDiagnostic } from "../diagnostics.js";
5
6
  import { createFileResource } from "../resource.js";
6
7
  import { Children, isComponentCreator } from "../runtime/component.js";
7
8
  import { childrenArray } from "../utils.jsx";
@@ -98,9 +99,11 @@ export function AppendFile(props: AppendFileProps): Children {
98
99
  } else if ("content" in regionProps) {
99
100
  content = regionProps.content;
100
101
  } else {
101
- throw new Error(
102
- `AppendRegion "${regionProps.id}" must have either children or content`,
103
- );
102
+ emitDiagnostic({
103
+ message: `AppendRegion "${regionProps.id}" must have either children or content`,
104
+ severity: "error",
105
+ });
106
+ // Still register the region to avoid duplicate "region not found" diagnostic
104
107
  }
105
108
 
106
109
  appendRegions[regionProps.id] = content;
@@ -115,9 +118,10 @@ export function AppendFile(props: AppendFileProps): Children {
115
118
  // Validate that all requested regions have corresponding AppendRegion children
116
119
  for (const regionId of regions) {
117
120
  if (!(regionId in appendRegions)) {
118
- throw new Error(
119
- `Region "${regionId}" specified but no corresponding AppendRegion child found`,
120
- );
121
+ emitDiagnostic({
122
+ message: `Region "${regionId}" specified but no corresponding AppendRegion child found`,
123
+ severity: "error",
124
+ });
121
125
  }
122
126
  }
123
127
 
@@ -181,9 +185,10 @@ export function AppendFile(props: AppendFileProps): Children {
181
185
  for (const regionId of regions) {
182
186
  const info = sigilInfo[regionId];
183
187
  if (info && info.start !== null && info.end === null) {
184
- throw new Error(
185
- `Region "${regionId}" has start sigil but no corresponding end sigil`,
186
- );
188
+ emitDiagnostic({
189
+ message: `Region "${regionId}" has start sigil but no corresponding end sigil`,
190
+ severity: "error",
191
+ });
187
192
  }
188
193
  }
189
194
 
@@ -1,5 +1,5 @@
1
- import { computed } from "@vue/reactivity";
2
1
  import { createContentSlot } from "../content-slot.jsx";
2
+ import { computed } from "../reactivity.js";
3
3
  import type { Children } from "../runtime/component.js";
4
4
  import { Indent } from "./Indent.jsx";
5
5
 
@@ -1,3 +1,4 @@
1
+ import { createSymbol } from "../binder.js";
1
2
  import { useContext } from "../context.js";
2
3
  import { BinderContext } from "../context/binder.js";
3
4
  import { DeclarationContext } from "../context/declaration.js";
@@ -83,7 +84,7 @@ export function Declaration(props: DeclarationProps) {
83
84
  );
84
85
  }
85
86
 
86
- declaration = new BasicSymbol(props.name, scope.symbols, {
87
+ declaration = createSymbol(BasicSymbol, props.name, scope.symbols, {
87
88
  binder,
88
89
  refkeys: [props.refkey ?? []].flat(),
89
90
  metadata: props.metadata,
@@ -1,3 +1,4 @@
1
+ import { createScope } from "../binder.js";
1
2
  import { ScopeContext, useScope } from "../context/scope.js";
2
3
  import type { Children } from "../runtime/component.js";
3
4
  import { BasicScope } from "../symbols/basic-scope.js";
@@ -58,7 +59,9 @@ export function Scope(props: ScopeProps) {
58
59
  "Scope component can only make scopes within a BasicScope",
59
60
  );
60
61
  }
61
- scope = new BasicScope(props.name ?? "", parentScope, {
62
+ const binder = parentScope?.binder;
63
+ scope = createScope(BasicScope, props.name ?? "", parentScope, {
64
+ binder,
62
65
  metadata: props.metadata,
63
66
  ownerSymbol: props.ownerSymbol,
64
67
  });
@@ -1,4 +1,5 @@
1
1
  import { computed } from "@vue/reactivity";
2
+ import { emitDiagnostic } from "../diagnostics.js";
2
3
  import { createFileResource } from "../resource.js";
3
4
  import { Children, isComponentCreator } from "../runtime/component.js";
4
5
  import { childrenArray } from "../utils.jsx";
@@ -85,9 +86,12 @@ export function TemplateFile(props: TemplateFileProps): Children {
85
86
  } else if ("value" in variableProps) {
86
87
  value = variableProps.value;
87
88
  } else {
88
- throw new Error(
89
- `TemplateVariable "${variableProps.name}" must have either children or value`,
90
- );
89
+ emitDiagnostic({
90
+ message: `TemplateVariable "${variableProps.name}" must have either children or value`,
91
+ severity: "error",
92
+ });
93
+ // Still register the variable to avoid duplicate diagnostics
94
+ value = "";
91
95
  }
92
96
 
93
97
  templateVariables[variableProps.name] = value;
@@ -100,9 +104,11 @@ export function TemplateFile(props: TemplateFileProps): Children {
100
104
  }
101
105
 
102
106
  if (templateResource.error) {
103
- throw new Error(
104
- `Failed to read template file "${props.src}": ${templateResource.error}`,
105
- );
107
+ emitDiagnostic({
108
+ message: `Failed to read template file "${props.src}": ${templateResource.error}`,
109
+ severity: "error",
110
+ });
111
+ return "";
106
112
  }
107
113
 
108
114
  const templateContent = templateResource.data!;
@@ -131,9 +137,12 @@ export function TemplateFile(props: TemplateFileProps): Children {
131
137
  if (variableName in templateVariables) {
132
138
  result.push(templateVariables[variableName]);
133
139
  } else {
134
- throw new Error(
135
- `Template variable "${variableName}" not found in TemplateVariable children`,
136
- );
140
+ emitDiagnostic({
141
+ message: `Template variable "${variableName}" not found in TemplateVariable children`,
142
+ severity: "error",
143
+ });
144
+ // Keep the placeholder in the output to make the error visible
145
+ result.push(`{{ ${variableName} }}`);
137
146
  }
138
147
 
139
148
  lastIndex = matchStart + fullMatch.length;
@@ -1,4 +1,4 @@
1
- import { effect, Ref, shallowRef } from "@vue/reactivity";
1
+ import { computed, Ref, shallowRef } from "@vue/reactivity";
2
2
  import { Show } from "./components/Show.jsx";
3
3
  import { getContext } from "./reactivity.js";
4
4
  import { Children, Component } from "./runtime/component.js";
@@ -54,14 +54,14 @@ export interface ContentSlot {
54
54
  * ```
55
55
  */
56
56
  export function createContentSlot(): ContentSlot {
57
- const isEmpty = shallowRef<boolean>(false);
57
+ // Holds a reference to the rendering context's isEmpty ref once ContentSlot
58
+ // renders. Before that, reads fall through to a default of "not empty".
59
+ const isEmptySource = shallowRef<Ref<boolean>>();
60
+ const isEmpty = computed(() => isEmptySource.value?.value ?? false);
58
61
 
59
62
  function ContentSlot(props: { children: Children }) {
60
63
  const context = getContext()!;
61
- effect(() => {
62
- isEmpty.value = context.isEmpty!.value;
63
- });
64
-
64
+ isEmptySource.value = context.isEmpty!;
65
65
  return props.children;
66
66
  }
67
67
  ContentSlot.ref = isEmpty;
package/src/context.ts CHANGED
@@ -38,12 +38,22 @@ export function createContext<T = unknown>(
38
38
  const id = Symbol(name ?? "context");
39
39
  function Provider(props: ContextProviderProps<T>) {
40
40
  const context = getContext();
41
+ const contextName = name ?? "anonymous";
41
42
 
42
43
  const rendered = shallowRef();
43
- effect(() => {
44
- context!.context![id] = props.value;
45
- rendered.value = () => props.children;
46
- }, undefined);
44
+ effect(
45
+ () => {
46
+ context!.context![id] = props.value;
47
+ rendered.value = () => props.children;
48
+ },
49
+ undefined,
50
+ {
51
+ debug: {
52
+ name: `context:provider:${contextName}`,
53
+ type: "context",
54
+ },
55
+ },
56
+ );
47
57
 
48
58
  return rendered.value;
49
59
  }
@@ -54,6 +64,7 @@ export function createContext<T = unknown>(
54
64
  Provider,
55
65
  ProviderStc: stc(Provider),
56
66
  };
67
+ (Provider as any).contextName = name;
57
68
  contextsByKey.set(id, ctx);
58
69
  return ctx;
59
70
  }