@alloy-js/core 0.23.0-dev.0 → 0.23.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -22
- package/dist/devtools/index.html +68 -0
- package/dist/src/binder.d.ts +2 -0
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +55 -12
- package/dist/src/binder.js.map +1 -1
- package/dist/src/components/AccessExpression.d.ts +78 -0
- package/dist/src/components/AccessExpression.d.ts.map +1 -0
- package/dist/src/components/AccessExpression.js +218 -0
- package/dist/src/components/AccessExpression.js.map +1 -0
- package/dist/src/components/AccessExpression.test.d.ts +2 -0
- package/dist/src/components/AccessExpression.test.d.ts.map +1 -0
- package/dist/src/components/AccessExpression.test.js +137 -0
- package/dist/src/components/AccessExpression.test.js.map +1 -0
- package/dist/src/components/AppendFile.d.ts.map +1 -1
- package/dist/src/components/AppendFile.js +14 -3
- package/dist/src/components/AppendFile.js.map +1 -1
- package/dist/src/components/Block.js +1 -1
- package/dist/src/components/Block.js.map +1 -1
- package/dist/src/components/Declaration.d.ts.map +1 -1
- package/dist/src/components/Declaration.js +2 -1
- package/dist/src/components/Declaration.js.map +1 -1
- package/dist/src/components/Prose.js +2 -2
- package/dist/src/components/Prose.js.map +1 -1
- package/dist/src/components/Scope.d.ts.map +1 -1
- package/dist/src/components/Scope.js +6 -1
- package/dist/src/components/Scope.js.map +1 -1
- package/dist/src/components/SourceDirectory.d.ts.map +1 -1
- package/dist/src/components/SourceDirectory.js +1 -2
- package/dist/src/components/SourceDirectory.js.map +1 -1
- package/dist/src/components/TemplateFile.d.ts.map +1 -1
- package/dist/src/components/TemplateFile.js +18 -3
- package/dist/src/components/TemplateFile.js.map +1 -1
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/components/index.js +1 -0
- package/dist/src/components/index.js.map +1 -1
- package/dist/src/content-slot.d.ts.map +1 -1
- package/dist/src/content-slot.js +7 -6
- package/dist/src/content-slot.js.map +1 -1
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +10 -3
- package/dist/src/context.js.map +1 -1
- package/dist/src/debug/cli.d.ts +6 -0
- package/dist/src/debug/cli.d.ts.map +1 -0
- package/dist/src/{debug.js → debug/cli.js} +78 -84
- package/dist/src/debug/cli.js.map +1 -0
- package/dist/src/debug/diagnostics.test.d.ts +2 -0
- package/dist/src/debug/diagnostics.test.d.ts.map +1 -0
- package/dist/src/debug/diagnostics.test.js +45 -0
- package/dist/src/debug/diagnostics.test.js.map +1 -0
- package/dist/src/debug/effects.d.ts +73 -0
- package/dist/src/debug/effects.d.ts.map +1 -0
- package/dist/src/debug/effects.js +228 -0
- package/dist/src/debug/effects.js.map +1 -0
- package/dist/src/debug/effects.test.d.ts +2 -0
- package/dist/src/debug/effects.test.d.ts.map +1 -0
- package/dist/src/debug/effects.test.js +84 -0
- package/dist/src/debug/effects.test.js.map +1 -0
- package/dist/src/debug/files.d.ts +14 -0
- package/dist/src/debug/files.d.ts.map +1 -0
- package/dist/src/debug/files.js +40 -0
- package/dist/src/debug/files.js.map +1 -0
- package/dist/src/debug/files.test.d.ts +2 -0
- package/dist/src/debug/files.test.d.ts.map +1 -0
- package/dist/src/debug/files.test.js +89 -0
- package/dist/src/debug/files.test.js.map +1 -0
- package/dist/src/debug/index.d.ts +61 -0
- package/dist/src/debug/index.d.ts.map +1 -0
- package/dist/src/debug/index.js +69 -0
- package/dist/src/debug/index.js.map +1 -0
- package/dist/src/debug/render.d.ts +57 -0
- package/dist/src/debug/render.d.ts.map +1 -0
- package/dist/src/debug/render.js +519 -0
- package/dist/src/debug/render.js.map +1 -0
- package/dist/src/debug/render.test.d.ts +2 -0
- package/dist/src/debug/render.test.d.ts.map +1 -0
- package/dist/src/debug/render.test.js +328 -0
- package/dist/src/debug/render.test.js.map +1 -0
- package/dist/src/debug/serialize.d.ts +9 -0
- package/dist/src/debug/serialize.d.ts.map +1 -0
- package/dist/src/debug/serialize.js +70 -0
- package/dist/src/debug/serialize.js.map +1 -0
- package/dist/src/debug/symbols.d.ts +15 -0
- package/dist/src/debug/symbols.d.ts.map +1 -0
- package/dist/src/debug/symbols.js +173 -0
- package/dist/src/debug/symbols.js.map +1 -0
- package/dist/src/debug/symbols.test.d.ts +2 -0
- package/dist/src/debug/symbols.test.d.ts.map +1 -0
- package/dist/src/debug/symbols.test.js +104 -0
- package/dist/src/debug/symbols.test.js.map +1 -0
- package/dist/src/debug/trace.d.ts +342 -0
- package/dist/src/debug/trace.d.ts.map +1 -0
- package/dist/src/debug/trace.js +443 -0
- package/dist/src/debug/trace.js.map +1 -0
- package/dist/src/devtools/devtools-protocol.d.ts +232 -0
- package/dist/src/devtools/devtools-protocol.d.ts.map +1 -0
- package/dist/src/devtools/devtools-protocol.js +2 -0
- package/dist/src/devtools/devtools-protocol.js.map +1 -0
- package/dist/src/devtools/devtools-server.browser.d.ts +28 -0
- package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -0
- package/dist/src/devtools/devtools-server.browser.js +36 -0
- package/dist/src/devtools/devtools-server.browser.js.map +1 -0
- package/dist/src/devtools/devtools-server.d.ts +72 -0
- package/dist/src/devtools/devtools-server.d.ts.map +1 -0
- package/dist/src/devtools/devtools-server.js +256 -0
- package/dist/src/devtools/devtools-server.js.map +1 -0
- package/dist/src/devtools/devtools-transport.d.ts +23 -0
- package/dist/src/devtools/devtools-transport.d.ts.map +1 -0
- package/dist/src/devtools/devtools-transport.js +114 -0
- package/dist/src/devtools/devtools-transport.js.map +1 -0
- package/dist/src/devtools-entry.browser.d.ts +4 -0
- package/dist/src/devtools-entry.browser.d.ts.map +1 -0
- package/dist/src/devtools-entry.browser.js +2 -0
- package/dist/src/devtools-entry.browser.js.map +1 -0
- package/dist/src/devtools-entry.d.ts +4 -0
- package/dist/src/devtools-entry.d.ts.map +1 -0
- package/dist/src/devtools-entry.js +2 -0
- package/dist/src/devtools-entry.js.map +1 -0
- package/dist/src/diagnostics.d.ts +34 -0
- package/dist/src/diagnostics.d.ts.map +1 -0
- package/dist/src/diagnostics.js +89 -0
- package/dist/src/diagnostics.js.map +1 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/print-hook.d.ts +14 -0
- package/dist/src/print-hook.d.ts.map +1 -0
- package/dist/src/print-hook.js +10 -0
- package/dist/src/print-hook.js.map +1 -0
- package/dist/src/reactive-union-set.d.ts.map +1 -1
- package/dist/src/reactive-union-set.js +28 -3
- package/dist/src/reactive-union-set.js.map +1 -1
- package/dist/src/reactivity.d.ts +50 -8
- package/dist/src/reactivity.d.ts.map +1 -1
- package/dist/src/reactivity.js +225 -39
- package/dist/src/reactivity.js.map +1 -1
- package/dist/src/render-stack.d.ts +30 -0
- package/dist/src/render-stack.d.ts.map +1 -0
- package/dist/src/render-stack.js +251 -0
- package/dist/src/render-stack.js.map +1 -0
- package/dist/src/render.d.ts +9 -19
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +371 -159
- package/dist/src/render.js.map +1 -1
- package/dist/src/resource.d.ts.map +1 -1
- package/dist/src/resource.js +5 -0
- package/dist/src/resource.js.map +1 -1
- package/dist/src/runtime/component.d.ts +7 -1
- package/dist/src/runtime/component.d.ts.map +1 -1
- package/dist/src/runtime/component.js +4 -1
- package/dist/src/runtime/component.js.map +1 -1
- package/dist/src/scheduler.d.ts +8 -0
- package/dist/src/scheduler.d.ts.map +1 -1
- package/dist/src/scheduler.js +69 -3
- package/dist/src/scheduler.js.map +1 -1
- package/dist/src/symbols/basic-symbol.d.ts.map +1 -1
- package/dist/src/symbols/basic-symbol.js +6 -1
- package/dist/src/symbols/basic-symbol.js.map +1 -1
- package/dist/src/symbols/decl.d.ts.map +1 -1
- package/dist/src/symbols/decl.js +5 -1
- package/dist/src/symbols/decl.js.map +1 -1
- package/dist/src/symbols/output-scope.d.ts +2 -1
- package/dist/src/symbols/output-scope.d.ts.map +1 -1
- package/dist/src/symbols/output-scope.js +13 -8
- package/dist/src/symbols/output-scope.js.map +1 -1
- package/dist/src/symbols/output-symbol.d.ts +1 -0
- package/dist/src/symbols/output-symbol.d.ts.map +1 -1
- package/dist/src/symbols/output-symbol.js +25 -8
- package/dist/src/symbols/output-symbol.js.map +1 -1
- package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
- package/dist/src/symbols/symbol-flow.js +24 -8
- package/dist/src/symbols/symbol-flow.js.map +1 -1
- package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
- package/dist/src/symbols/symbol-slot.js +15 -0
- package/dist/src/symbols/symbol-slot.js.map +1 -1
- package/dist/src/symbols/symbol-slot.test.d.ts +2 -0
- package/dist/src/symbols/symbol-slot.test.d.ts.map +1 -0
- package/dist/src/symbols/symbol-slot.test.js +35 -0
- package/dist/src/symbols/symbol-slot.test.js.map +1 -0
- package/dist/src/symbols/symbol-table.d.ts.map +1 -1
- package/dist/src/symbols/symbol-table.js +6 -5
- package/dist/src/symbols/symbol-table.js.map +1 -1
- package/dist/src/trace.d.ts +2 -0
- package/dist/src/trace.d.ts.map +1 -0
- package/dist/src/trace.js +2 -0
- package/dist/src/trace.js.map +1 -0
- package/dist/src/tracer.d.ts +2 -228
- package/dist/src/tracer.d.ts.map +1 -1
- package/dist/src/tracer.js +5 -298
- package/dist/src/tracer.js.map +1 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +7 -5
- package/dist/src/utils.js.map +1 -1
- package/dist/test/components/append-file.test.d.ts.map +1 -1
- package/dist/test/components/append-file.test.js +18 -10
- package/dist/test/components/append-file.test.js.map +1 -1
- package/dist/test/components/template-file.test.d.ts.map +1 -1
- package/dist/test/components/template-file.test.js +6 -4
- package/dist/test/components/template-file.test.js.map +1 -1
- package/dist/test/lazy-isempty.test.d.ts +2 -0
- package/dist/test/lazy-isempty.test.d.ts.map +1 -0
- package/dist/test/lazy-isempty.test.js +89 -0
- package/dist/test/lazy-isempty.test.js.map +1 -0
- package/dist/test/reactive-union-set-disposers.test.d.ts +2 -0
- package/dist/test/reactive-union-set-disposers.test.d.ts.map +1 -0
- package/dist/test/reactive-union-set-disposers.test.js +98 -0
- package/dist/test/reactive-union-set-disposers.test.js.map +1 -0
- package/dist/test/reactivity/shallow-reactive.test.d.ts +2 -0
- package/dist/test/reactivity/shallow-reactive.test.d.ts.map +1 -0
- package/dist/test/reactivity/shallow-reactive.test.js +52 -0
- package/dist/test/reactivity/shallow-reactive.test.js.map +1 -0
- package/dist/test/rendering/basic.test.js +3 -0
- package/dist/test/rendering/basic.test.js.map +1 -1
- package/dist/test/rendering/print-render-stack.test.d.ts +2 -0
- package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -0
- package/dist/test/rendering/print-render-stack.test.js +207 -0
- package/dist/test/rendering/print-render-stack.test.js.map +1 -0
- package/dist/test/scheduler-extended.test.d.ts +2 -0
- package/dist/test/scheduler-extended.test.d.ts.map +1 -0
- package/dist/test/scheduler-extended.test.js +96 -0
- package/dist/test/scheduler-extended.test.js.map +1 -0
- package/dist/test/scheduler.test.d.ts +2 -0
- package/dist/test/scheduler.test.d.ts.map +1 -0
- package/dist/test/scheduler.test.js +46 -0
- package/dist/test/scheduler.test.js.map +1 -0
- package/dist/testing/create-test-wrapper.d.ts +1 -1
- package/dist/testing/create-test-wrapper.d.ts.map +1 -1
- package/dist/testing/create-test-wrapper.js +1 -1
- package/dist/testing/create-test-wrapper.js.map +1 -1
- package/dist/testing/devtools-utils.d.ts +26 -0
- package/dist/testing/devtools-utils.d.ts.map +1 -0
- package/dist/testing/devtools-utils.js +140 -0
- package/dist/testing/devtools-utils.js.map +1 -0
- package/dist/testing/extend-expect.d.ts.map +1 -1
- package/dist/testing/extend-expect.js +63 -1
- package/dist/testing/extend-expect.js.map +1 -1
- package/dist/testing/render.d.ts +2 -2
- package/dist/testing/render.d.ts.map +1 -1
- package/dist/testing/render.js +2 -2
- package/dist/testing/render.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +21 -7
- package/scripts/copy-devtools-ui.mjs +26 -0
- package/src/binder.ts +71 -16
- package/src/components/AccessExpression.test.tsx +132 -0
- package/src/components/AccessExpression.tsx +344 -0
- package/src/components/AppendFile.tsx +14 -9
- package/src/components/Block.tsx +1 -1
- package/src/components/Declaration.tsx +2 -1
- package/src/components/Prose.tsx +1 -1
- package/src/components/Scope.tsx +6 -1
- package/src/components/SourceDirectory.tsx +1 -2
- package/src/components/TemplateFile.tsx +18 -9
- package/src/components/index.tsx +1 -0
- package/src/content-slot.tsx +7 -7
- package/src/context.ts +17 -6
- package/src/{debug.ts → debug/cli.ts} +112 -127
- package/src/debug/diagnostics.test.tsx +55 -0
- package/src/debug/effects.test.tsx +89 -0
- package/src/debug/effects.ts +317 -0
- package/src/debug/files.test.tsx +96 -0
- package/src/debug/files.ts +40 -0
- package/src/debug/index.ts +128 -0
- package/src/debug/render.test.tsx +379 -0
- package/src/debug/render.ts +639 -0
- package/src/debug/serialize.ts +85 -0
- package/src/debug/symbols.test.tsx +106 -0
- package/src/debug/symbols.ts +239 -0
- package/src/debug/trace.ts +312 -0
- package/src/devtools/devtools-protocol.ts +312 -0
- package/src/devtools/devtools-server.browser.ts +71 -0
- package/src/devtools/devtools-server.ts +290 -0
- package/src/devtools/devtools-transport.ts +154 -0
- package/src/devtools-entry.browser.ts +52 -0
- package/src/devtools-entry.ts +54 -0
- package/src/diagnostics.ts +141 -0
- package/src/index.ts +2 -7
- package/src/print-hook.ts +22 -0
- package/src/reactive-union-set.ts +85 -44
- package/src/reactivity.ts +301 -59
- package/src/render-stack.ts +294 -0
- package/src/render.ts +470 -216
- package/src/resource.ts +28 -19
- package/src/runtime/component.ts +11 -0
- package/src/scheduler.ts +80 -4
- package/src/symbols/basic-symbol.ts +6 -1
- package/src/symbols/decl.ts +5 -1
- package/src/symbols/output-scope.ts +21 -13
- package/src/symbols/output-symbol.ts +34 -14
- package/src/symbols/symbol-flow.ts +76 -39
- package/src/symbols/symbol-slot.test.tsx +41 -0
- package/src/symbols/symbol-slot.tsx +47 -20
- package/src/symbols/symbol-table.ts +6 -10
- package/src/trace.ts +1 -0
- package/src/tracer.ts +13 -242
- package/src/utils.tsx +24 -17
- package/temp/api.json +4187 -1603
- package/test/components/append-file.test.tsx +36 -29
- package/test/components/template-file.test.tsx +11 -11
- package/test/lazy-isempty.test.tsx +106 -0
- package/test/reactive-union-set-disposers.test.tsx +112 -0
- package/test/reactivity/shallow-reactive.test.tsx +56 -0
- package/test/rendering/basic.test.tsx +4 -0
- package/test/rendering/print-render-stack.test.tsx +244 -0
- package/test/scheduler-extended.test.tsx +122 -0
- package/test/scheduler.test.tsx +50 -0
- package/testing/create-test-wrapper.tsx +1 -1
- package/testing/devtools-utils.ts +203 -0
- package/testing/extend-expect.ts +89 -0
- package/testing/render.ts +2 -2
- package/testing/vitest.d.ts +9 -0
- package/dist/src/debug.d.ts +0 -15
- package/dist/src/debug.d.ts.map +0 -1
- package/dist/src/debug.js.map +0 -1
package/src/render.ts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
|
-
import { isRef
|
|
1
|
+
import { isRef } from "@vue/reactivity";
|
|
2
2
|
import { Doc, doc } from "prettier";
|
|
3
3
|
import prettier from "prettier/doc.js";
|
|
4
4
|
import { useContext } from "./context.js";
|
|
5
5
|
import { SourceFileContext } from "./context/source-file.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
debug,
|
|
8
|
+
getRenderNodeId,
|
|
9
|
+
isDevtoolsEnabled,
|
|
10
|
+
type RenderTreeNodeInfo,
|
|
11
|
+
} from "./debug/index.js";
|
|
12
|
+
import { broadcastDevtoolsMessage } from "./devtools/devtools-server.js";
|
|
13
|
+
import {
|
|
14
|
+
attachDiagnosticsCollector,
|
|
15
|
+
DiagnosticsCollector,
|
|
16
|
+
emitDiagnostic,
|
|
17
|
+
reportDiagnostics,
|
|
18
|
+
} from "./diagnostics.js";
|
|
19
|
+
import {
|
|
20
|
+
isPrintHook,
|
|
21
|
+
printHookTag,
|
|
22
|
+
type PrintHook,
|
|
23
|
+
type RenderedTextTree,
|
|
24
|
+
} from "./print-hook.js";
|
|
7
25
|
import {
|
|
8
26
|
Context,
|
|
9
27
|
CustomContext,
|
|
@@ -11,22 +29,111 @@ import {
|
|
|
11
29
|
getContext,
|
|
12
30
|
getElementCache,
|
|
13
31
|
isCustomContext,
|
|
32
|
+
onCleanup,
|
|
33
|
+
ref,
|
|
14
34
|
root,
|
|
15
35
|
untrack,
|
|
16
36
|
} from "./reactivity.js";
|
|
17
37
|
import { isRefkeyable, toRefkey } from "./refkey.js";
|
|
38
|
+
import {
|
|
39
|
+
getRenderStackSnapshot,
|
|
40
|
+
popStack,
|
|
41
|
+
printRenderStack,
|
|
42
|
+
pushStack,
|
|
43
|
+
} from "./render-stack.js";
|
|
18
44
|
import {
|
|
19
45
|
Child,
|
|
20
46
|
Children,
|
|
21
|
-
Component,
|
|
22
47
|
isComponentCreator,
|
|
23
48
|
isRenderableObject,
|
|
24
|
-
Props,
|
|
25
49
|
RENDERABLE,
|
|
26
50
|
} from "./runtime/component.js";
|
|
27
51
|
import { IntrinsicElement, isIntrinsicElement } from "./runtime/intrinsic.js";
|
|
28
|
-
import { flushJobs, flushJobsAsync } from "./scheduler.js";
|
|
29
|
-
|
|
52
|
+
import { flushJobs, flushJobsAsync, waitForSignal } from "./scheduler.js";
|
|
53
|
+
|
|
54
|
+
const notifiedErrors = new WeakSet<object>();
|
|
55
|
+
let lastRenderError: {
|
|
56
|
+
error: { name: string; message: string; stack?: string };
|
|
57
|
+
componentStack: Array<{
|
|
58
|
+
name: string;
|
|
59
|
+
props?: Record<string, unknown> | undefined;
|
|
60
|
+
propsSerialized?: string;
|
|
61
|
+
renderNodeId?: number;
|
|
62
|
+
source?: RenderTreeNodeInfo["source"];
|
|
63
|
+
}>;
|
|
64
|
+
} | null = null;
|
|
65
|
+
|
|
66
|
+
function normalizeRenderError(error: unknown): {
|
|
67
|
+
name: string;
|
|
68
|
+
message: string;
|
|
69
|
+
stack?: string;
|
|
70
|
+
} {
|
|
71
|
+
if (error instanceof Error) {
|
|
72
|
+
return {
|
|
73
|
+
name: error.name || error.constructor?.name || "Error",
|
|
74
|
+
message: error.message || "",
|
|
75
|
+
stack: error.stack,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (error && typeof error === "object") {
|
|
79
|
+
const anyError = error as {
|
|
80
|
+
name?: string;
|
|
81
|
+
message?: string;
|
|
82
|
+
stack?: string;
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
name: anyError.name || "Error",
|
|
86
|
+
message: anyError.message || String(error),
|
|
87
|
+
stack: anyError.stack,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
name: "Error",
|
|
92
|
+
message: String(error),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function notifyRenderError(error: unknown) {
|
|
97
|
+
if (error && typeof error === "object") {
|
|
98
|
+
if (notifiedErrors.has(error)) return;
|
|
99
|
+
notifiedErrors.add(error);
|
|
100
|
+
}
|
|
101
|
+
if (lastRenderError) return;
|
|
102
|
+
|
|
103
|
+
const { name, message, stack } = normalizeRenderError(error);
|
|
104
|
+
const componentStack = getRenderStackSnapshot().map((entry) => {
|
|
105
|
+
const renderNode = entry.context?.meta?.renderNode as
|
|
106
|
+
| RenderedTextTree
|
|
107
|
+
| undefined;
|
|
108
|
+
const renderNodeId = renderNode ? getRenderNodeId(renderNode) : undefined;
|
|
109
|
+
return {
|
|
110
|
+
name: entry.displayName,
|
|
111
|
+
props: entry.props as Record<string, unknown> | undefined,
|
|
112
|
+
renderNodeId,
|
|
113
|
+
source: entry.source,
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Output to console
|
|
118
|
+
printRenderStack(error);
|
|
119
|
+
|
|
120
|
+
// Send to devtools if enabled
|
|
121
|
+
debug.render.error({ name, message, stack }, componentStack);
|
|
122
|
+
|
|
123
|
+
// Store for diagnostics
|
|
124
|
+
lastRenderError = { error: { name, message, stack }, componentStack };
|
|
125
|
+
const lastEntry = componentStack.at(-1);
|
|
126
|
+
emitDiagnostic({
|
|
127
|
+
severity: "error",
|
|
128
|
+
message: `${name}: ${message}`,
|
|
129
|
+
source: lastEntry?.source,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function reportLastRenderError() {
|
|
134
|
+
// Error already reported in notifyRenderError via debug.renderError
|
|
135
|
+
lastRenderError = null;
|
|
136
|
+
}
|
|
30
137
|
|
|
31
138
|
const {
|
|
32
139
|
builders: {
|
|
@@ -152,23 +259,36 @@ export interface ContentOutputFile extends OutputFileBase {
|
|
|
152
259
|
export type OutputFile = ContentOutputFile | CopyOutputFile;
|
|
153
260
|
|
|
154
261
|
const nodesToContext = new WeakMap<RenderedTextTree, Context>();
|
|
262
|
+
const diagnosticsByTree = new WeakMap<RenderedTextTree, DiagnosticsCollector>();
|
|
155
263
|
|
|
156
264
|
export function getContextForRenderNode(node: RenderedTextTree) {
|
|
157
265
|
return nodesToContext.get(node);
|
|
158
266
|
}
|
|
159
267
|
|
|
160
|
-
export
|
|
268
|
+
export function getDiagnosticsForTree(tree: RenderedTextTree) {
|
|
269
|
+
return diagnosticsByTree.get(tree)?.getDiagnostics() ?? [];
|
|
270
|
+
}
|
|
161
271
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
272
|
+
function reportDiagnosticsForTree(tree: RenderedTextTree) {
|
|
273
|
+
const diagnostics = diagnosticsByTree.get(tree);
|
|
274
|
+
if (!diagnostics) return;
|
|
275
|
+
const entries = diagnostics.getDiagnostics();
|
|
276
|
+
if (entries.length === 0) return;
|
|
277
|
+
reportDiagnostics(diagnostics);
|
|
278
|
+
void broadcastDevtoolsMessage({
|
|
279
|
+
type: "diagnostics:report",
|
|
280
|
+
diagnostics: entries,
|
|
281
|
+
});
|
|
170
282
|
}
|
|
171
283
|
|
|
284
|
+
// Re-export from print-hook.ts to maintain backwards compatibility
|
|
285
|
+
export {
|
|
286
|
+
isPrintHook,
|
|
287
|
+
printHookTag,
|
|
288
|
+
type PrintHook,
|
|
289
|
+
type RenderedTextTree,
|
|
290
|
+
} from "./print-hook.js";
|
|
291
|
+
|
|
172
292
|
export function createRenderTreeHook(
|
|
173
293
|
subtree: RenderedTextTree,
|
|
174
294
|
hooks: Omit<PrintHook, typeof printHookTag | "subtree">,
|
|
@@ -180,12 +300,6 @@ export function createRenderTreeHook(
|
|
|
180
300
|
};
|
|
181
301
|
}
|
|
182
302
|
|
|
183
|
-
export function isPrintHook(type: unknown): type is PrintHook {
|
|
184
|
-
return typeof type === "object" && type !== null && printHookTag in type;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export type RenderedTextTree = (string | RenderedTextTree | PrintHook)[];
|
|
188
|
-
|
|
189
303
|
/**
|
|
190
304
|
* Render a component tree to source directories and files. Will ensure that
|
|
191
305
|
* all non-async scheduled jobs are completed before returning. If async jobs
|
|
@@ -198,7 +312,14 @@ export function render(
|
|
|
198
312
|
): OutputDirectory {
|
|
199
313
|
const tree = renderTree(children);
|
|
200
314
|
flushJobs();
|
|
201
|
-
|
|
315
|
+
const output = sourceFilesForTree(tree, options);
|
|
316
|
+
reportDiagnosticsForTree(tree);
|
|
317
|
+
reportLastRenderError();
|
|
318
|
+
debug.render.complete();
|
|
319
|
+
if (isDevtoolsEnabled()) {
|
|
320
|
+
void waitForSignal();
|
|
321
|
+
}
|
|
322
|
+
return output;
|
|
202
323
|
}
|
|
203
324
|
|
|
204
325
|
/**
|
|
@@ -209,23 +330,16 @@ export async function renderAsync(
|
|
|
209
330
|
children: Children,
|
|
210
331
|
options?: PrintTreeOptions,
|
|
211
332
|
): Promise<OutputDirectory> {
|
|
333
|
+
await debug.prepare();
|
|
212
334
|
const tree = renderTree(children);
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Convert a rendered text tree to source directories and files. Will ensure that
|
|
218
|
-
* all scheduled jobs are completed, including async ones.
|
|
219
|
-
*/
|
|
220
|
-
export async function sourceFilesForTreeAsync(
|
|
221
|
-
tree: RenderedTextTree,
|
|
222
|
-
options?: PrintTreeOptions,
|
|
223
|
-
) {
|
|
224
|
-
// if we await here, we ensure all reactive updates are flushed.
|
|
225
|
-
// sourceFilesForTree will flush again, but won't find anything, because tree
|
|
226
|
-
// printing won't schedule anything.
|
|
335
|
+
// Ensure all reactive updates are flushed before printing.
|
|
227
336
|
await flushJobsAsync();
|
|
228
|
-
|
|
337
|
+
const output = sourceFilesForTree(tree, options);
|
|
338
|
+
reportDiagnosticsForTree(tree);
|
|
339
|
+
reportLastRenderError();
|
|
340
|
+
debug.render.complete();
|
|
341
|
+
|
|
342
|
+
return output;
|
|
229
343
|
}
|
|
230
344
|
|
|
231
345
|
/**
|
|
@@ -241,9 +355,12 @@ export function sourceFilesForTree(
|
|
|
241
355
|
collectSourceFiles(undefined, tree);
|
|
242
356
|
|
|
243
357
|
if (!rootDirectory) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
358
|
+
emitDiagnostic({
|
|
359
|
+
severity: "error",
|
|
360
|
+
message:
|
|
361
|
+
"No root directory found. Make sure you are using the output component.",
|
|
362
|
+
});
|
|
363
|
+
return { kind: "directory", path: "", contents: [] };
|
|
247
364
|
}
|
|
248
365
|
|
|
249
366
|
return rootDirectory;
|
|
@@ -327,25 +444,35 @@ export function sourceFilesForTree(
|
|
|
327
444
|
}
|
|
328
445
|
export function renderTree(children: Children) {
|
|
329
446
|
const rootElem: RenderedTextTree = [];
|
|
447
|
+
const diagnostics = new DiagnosticsCollector();
|
|
448
|
+
lastRenderError = null;
|
|
449
|
+
debug.effect.reset();
|
|
450
|
+
debug.symbols.reset();
|
|
451
|
+
debug.files.reset();
|
|
452
|
+
debug.render.initialize(rootElem);
|
|
330
453
|
try {
|
|
331
454
|
root(() => {
|
|
455
|
+
attachDiagnosticsCollector(diagnostics);
|
|
332
456
|
renderWorker(rootElem, children);
|
|
333
457
|
});
|
|
334
458
|
} catch (e) {
|
|
335
|
-
|
|
459
|
+
notifyRenderError(e);
|
|
460
|
+
reportLastRenderError();
|
|
336
461
|
throw e;
|
|
337
462
|
}
|
|
338
463
|
|
|
464
|
+
diagnosticsByTree.set(rootElem, diagnostics);
|
|
465
|
+
|
|
339
466
|
return rootElem;
|
|
340
467
|
}
|
|
341
468
|
|
|
342
469
|
function renderWorker(node: RenderedTextTree, children: Children) {
|
|
470
|
+
if (lastRenderError) return;
|
|
343
471
|
if (!getContext()) {
|
|
344
472
|
throw new Error(
|
|
345
473
|
"Cannot render without a context. Make sure you are using the Output component.",
|
|
346
474
|
);
|
|
347
475
|
}
|
|
348
|
-
trace(TracePhase.render.worker, () => dumpChildren(children));
|
|
349
476
|
|
|
350
477
|
if (Array.isArray(node)) {
|
|
351
478
|
nodesToContext.set(node, getContext()!);
|
|
@@ -354,6 +481,7 @@ function renderWorker(node: RenderedTextTree, children: Children) {
|
|
|
354
481
|
if (Array.isArray(children)) {
|
|
355
482
|
for (const child of (children as any).flat(Infinity)) {
|
|
356
483
|
appendChild(node, child);
|
|
484
|
+
if (lastRenderError) break;
|
|
357
485
|
}
|
|
358
486
|
} else {
|
|
359
487
|
appendChild(node, children);
|
|
@@ -370,11 +498,12 @@ export function notifyContentState() {
|
|
|
370
498
|
const startContext = getContext()!;
|
|
371
499
|
|
|
372
500
|
if (startContext.childrenWithContent === 0) {
|
|
373
|
-
if (startContext.
|
|
501
|
+
if (startContext._lastEmpty) {
|
|
374
502
|
// it was already empty, no work to do.
|
|
375
503
|
return;
|
|
376
504
|
}
|
|
377
505
|
|
|
506
|
+
startContext._lastEmpty = true;
|
|
378
507
|
if (startContext.isEmpty) {
|
|
379
508
|
startContext.isEmpty.value = true;
|
|
380
509
|
}
|
|
@@ -386,18 +515,24 @@ export function notifyContentState() {
|
|
|
386
515
|
break;
|
|
387
516
|
}
|
|
388
517
|
current.childrenWithContent--;
|
|
518
|
+
if (current.childrenWithContent > 0) {
|
|
519
|
+
// This isn't the last content so we have no work to do
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
current._lastEmpty = true;
|
|
389
523
|
if (current.isEmpty) {
|
|
390
524
|
current.isEmpty.value = true;
|
|
391
525
|
}
|
|
392
526
|
current = current.owner;
|
|
393
527
|
}
|
|
394
528
|
} else {
|
|
395
|
-
if (startContext.
|
|
529
|
+
if (!startContext._lastEmpty) {
|
|
396
530
|
// it was already non-empty, no work to do.
|
|
397
531
|
return;
|
|
398
532
|
}
|
|
399
533
|
|
|
400
|
-
|
|
534
|
+
startContext._lastEmpty = false;
|
|
535
|
+
if (startContext.isEmpty) {
|
|
401
536
|
startContext.isEmpty.value = false;
|
|
402
537
|
}
|
|
403
538
|
|
|
@@ -410,7 +545,8 @@ export function notifyContentState() {
|
|
|
410
545
|
break;
|
|
411
546
|
}
|
|
412
547
|
|
|
413
|
-
|
|
548
|
+
current._lastEmpty = false;
|
|
549
|
+
if (current.isEmpty) {
|
|
414
550
|
current.isEmpty.value = false;
|
|
415
551
|
}
|
|
416
552
|
|
|
@@ -421,95 +557,120 @@ export function notifyContentState() {
|
|
|
421
557
|
}
|
|
422
558
|
|
|
423
559
|
function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
424
|
-
|
|
560
|
+
if (lastRenderError) return;
|
|
425
561
|
const child = normalizeChild(rawChild);
|
|
426
562
|
|
|
427
563
|
if (typeof child === "string") {
|
|
428
564
|
if (child !== "") {
|
|
429
565
|
contentAdded();
|
|
566
|
+
debug.render.appendTextNode(node, node.length, child);
|
|
430
567
|
}
|
|
431
568
|
node.push(child);
|
|
432
569
|
} else {
|
|
433
570
|
const cache = getElementCache();
|
|
434
571
|
if (cache.has(child as any)) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
572
|
+
const cachedNode = cache.get(child as any)!;
|
|
573
|
+
// recordSubtreeAdded detects cached nodes automatically and re-adds their children
|
|
574
|
+
if (isCustomContext(child)) {
|
|
575
|
+
debug.render.appendCustomContext(node, cachedNode);
|
|
576
|
+
} else {
|
|
577
|
+
debug.render.appendFragmentChild(node, cachedNode);
|
|
578
|
+
}
|
|
579
|
+
node.push(cachedNode);
|
|
440
580
|
return;
|
|
441
581
|
}
|
|
442
582
|
if (isCustomContext(child)) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
() => "CustomContext: " + debugPrintChild(child),
|
|
446
|
-
);
|
|
583
|
+
const newNode: RenderedTextTree = [];
|
|
584
|
+
debug.render.appendCustomContext(node, newNode);
|
|
447
585
|
child.useCustomContext((children) => {
|
|
448
|
-
const newNode: RenderedTextTree = [];
|
|
449
586
|
renderWorker(newNode, children);
|
|
450
587
|
node.push(newNode);
|
|
451
588
|
cache.set(child, newNode);
|
|
452
589
|
notifyContentState();
|
|
590
|
+
notifyFileUpdateForNode(node);
|
|
453
591
|
});
|
|
454
592
|
} else if (isIntrinsicElement(child)) {
|
|
455
|
-
trace(
|
|
456
|
-
TracePhase.render.appendChild,
|
|
457
|
-
() => "IntrinsicElement: " + debugPrintChild(child),
|
|
458
|
-
);
|
|
459
593
|
// don't need a new context here because intrinsics are never reactive
|
|
594
|
+
const intrinsic = child as IntrinsicElement;
|
|
460
595
|
const newNode: RenderedTextTree = [];
|
|
461
596
|
|
|
462
597
|
function formatHookWithChildren(command: (doc: Doc) => Doc) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
print(tree
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
598
|
+
const hook = createRenderTreeHook(newNode, {
|
|
599
|
+
print(tree, print) {
|
|
600
|
+
return command(print(tree));
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
debug.render.appendPrintHook(
|
|
604
|
+
node,
|
|
605
|
+
node.length,
|
|
606
|
+
hook,
|
|
607
|
+
intrinsic.name,
|
|
608
|
+
newNode,
|
|
469
609
|
);
|
|
610
|
+
node.push(hook);
|
|
470
611
|
renderWorker(newNode, (child as any).props.children);
|
|
612
|
+
notifyFileUpdateForNode(node);
|
|
471
613
|
}
|
|
472
614
|
|
|
473
615
|
function formatHook(command: Doc) {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
);
|
|
616
|
+
const hook = createRenderTreeHook(newNode, {
|
|
617
|
+
print() {
|
|
618
|
+
return command;
|
|
619
|
+
},
|
|
620
|
+
});
|
|
621
|
+
debug.render.appendPrintHook(node, node.length, hook, intrinsic.name);
|
|
622
|
+
node.push(hook);
|
|
623
|
+
return hook;
|
|
481
624
|
}
|
|
482
625
|
|
|
483
626
|
switch (child.name) {
|
|
484
627
|
case "indent":
|
|
485
628
|
return formatHookWithChildren(indent);
|
|
486
629
|
case "indentIfBreak":
|
|
487
|
-
|
|
488
|
-
createRenderTreeHook(newNode, {
|
|
630
|
+
{
|
|
631
|
+
const hook = createRenderTreeHook(newNode, {
|
|
489
632
|
print(tree, print) {
|
|
490
633
|
return indentIfBreak(print(tree), {
|
|
491
634
|
groupId: child.props.groupId,
|
|
492
635
|
negate: child.props.negate,
|
|
493
636
|
});
|
|
494
637
|
},
|
|
495
|
-
})
|
|
496
|
-
|
|
638
|
+
});
|
|
639
|
+
debug.render.appendPrintHook(
|
|
640
|
+
node,
|
|
641
|
+
node.length,
|
|
642
|
+
hook,
|
|
643
|
+
intrinsic.name,
|
|
644
|
+
newNode,
|
|
645
|
+
);
|
|
646
|
+
node.push(hook);
|
|
647
|
+
}
|
|
497
648
|
renderWorker(newNode, child.props.children);
|
|
649
|
+
notifyFileUpdateForNode(node);
|
|
498
650
|
return;
|
|
499
651
|
case "fill":
|
|
500
652
|
return formatHookWithChildren(fill as any);
|
|
501
653
|
case "group":
|
|
502
|
-
|
|
503
|
-
createRenderTreeHook(newNode, {
|
|
654
|
+
{
|
|
655
|
+
const hook = createRenderTreeHook(newNode, {
|
|
504
656
|
print(tree, print) {
|
|
505
657
|
return group(print(tree), {
|
|
506
658
|
id: child.props.id,
|
|
507
659
|
shouldBreak: child.props.shouldBreak,
|
|
508
660
|
});
|
|
509
661
|
},
|
|
510
|
-
})
|
|
511
|
-
|
|
662
|
+
});
|
|
663
|
+
debug.render.appendPrintHook(
|
|
664
|
+
node,
|
|
665
|
+
node.length,
|
|
666
|
+
hook,
|
|
667
|
+
intrinsic.name,
|
|
668
|
+
newNode,
|
|
669
|
+
);
|
|
670
|
+
node.push(hook);
|
|
671
|
+
}
|
|
512
672
|
renderWorker(newNode, child.props.children);
|
|
673
|
+
notifyFileUpdateForNode(node);
|
|
513
674
|
return;
|
|
514
675
|
case "line":
|
|
515
676
|
case "br":
|
|
@@ -524,17 +685,26 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
524
685
|
case "lbr":
|
|
525
686
|
return formatHook(literalline);
|
|
526
687
|
case "align":
|
|
527
|
-
|
|
528
|
-
createRenderTreeHook(newNode, {
|
|
688
|
+
{
|
|
689
|
+
const hook = createRenderTreeHook(newNode, {
|
|
529
690
|
print(tree, print) {
|
|
530
691
|
return align(
|
|
531
692
|
(child.props as any).width ?? (child.props as any).string!,
|
|
532
693
|
print(tree),
|
|
533
694
|
);
|
|
534
695
|
},
|
|
535
|
-
})
|
|
536
|
-
|
|
696
|
+
});
|
|
697
|
+
debug.render.appendPrintHook(
|
|
698
|
+
node,
|
|
699
|
+
node.length,
|
|
700
|
+
hook,
|
|
701
|
+
intrinsic.name,
|
|
702
|
+
newNode,
|
|
703
|
+
);
|
|
704
|
+
node.push(hook);
|
|
705
|
+
}
|
|
537
706
|
renderWorker(newNode, (child as any).props.children);
|
|
707
|
+
notifyFileUpdateForNode(node);
|
|
538
708
|
return;
|
|
539
709
|
case "lineSuffix":
|
|
540
710
|
return formatHookWithChildren(lineSuffix);
|
|
@@ -549,17 +719,33 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
549
719
|
case "markAsRoot":
|
|
550
720
|
return formatHookWithChildren(markAsRoot);
|
|
551
721
|
case "ifBreak":
|
|
552
|
-
|
|
553
|
-
createRenderTreeHook(newNode, {
|
|
722
|
+
{
|
|
723
|
+
const hook = createRenderTreeHook(newNode, {
|
|
554
724
|
print(tree, print) {
|
|
555
725
|
return ifBreak(
|
|
556
726
|
print((tree as RenderedTextTree[])[0]),
|
|
557
727
|
print((tree as RenderedTextTree[])[1]),
|
|
558
728
|
);
|
|
559
729
|
},
|
|
560
|
-
})
|
|
561
|
-
|
|
730
|
+
});
|
|
731
|
+
debug.render.appendPrintHook(
|
|
732
|
+
node,
|
|
733
|
+
node.length,
|
|
734
|
+
hook,
|
|
735
|
+
intrinsic.name,
|
|
736
|
+
newNode,
|
|
737
|
+
);
|
|
738
|
+
node.push(hook);
|
|
739
|
+
}
|
|
562
740
|
newNode.push([], []);
|
|
741
|
+
debug.render.appendFragmentChild(
|
|
742
|
+
newNode,
|
|
743
|
+
newNode[0] as RenderedTextTree,
|
|
744
|
+
);
|
|
745
|
+
debug.render.appendFragmentChild(
|
|
746
|
+
newNode,
|
|
747
|
+
newNode[1] as RenderedTextTree,
|
|
748
|
+
);
|
|
563
749
|
renderWorker(
|
|
564
750
|
newNode[0] as RenderedTextTree[],
|
|
565
751
|
(child as any).props.children,
|
|
@@ -568,65 +754,204 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
568
754
|
newNode[1] as RenderedTextTree[],
|
|
569
755
|
(child as any).props.flatContents,
|
|
570
756
|
);
|
|
757
|
+
notifyFileUpdateForNode(node);
|
|
571
758
|
return;
|
|
572
759
|
default:
|
|
573
760
|
throw new Error("Unknown intrinsic element");
|
|
574
761
|
}
|
|
575
762
|
} else if (isComponentCreator(child)) {
|
|
763
|
+
const index = node.length;
|
|
764
|
+
const rerenderToken = isDevtoolsEnabled() ? ref(0) : undefined;
|
|
765
|
+
const breakNext = isDevtoolsEnabled() ? ref(false) : undefined;
|
|
576
766
|
// todo: remove this effect (only needed for context, not needed for anything else)
|
|
577
|
-
effect(
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
767
|
+
effect(
|
|
768
|
+
() => {
|
|
769
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
770
|
+
rerenderToken?.value;
|
|
771
|
+
const context = getContext();
|
|
772
|
+
context!.childrenWithContent = 0;
|
|
773
|
+
|
|
774
|
+
if (context) context.componentOwner = child;
|
|
775
|
+
const existing = node[index];
|
|
776
|
+
const componentRoot: RenderedTextTree =
|
|
777
|
+
Array.isArray(existing) ? existing : [];
|
|
778
|
+
context!.meta ??= {};
|
|
779
|
+
context!.meta.renderNode = componentRoot;
|
|
780
|
+
const propsSource = (child.props ?? undefined) as
|
|
781
|
+
| Record<string, unknown>
|
|
782
|
+
| undefined;
|
|
783
|
+
const debugSession = debug.render.beginComponent({
|
|
784
|
+
parent: node,
|
|
785
|
+
index,
|
|
786
|
+
node: componentRoot,
|
|
787
|
+
component: child,
|
|
788
|
+
propsSource,
|
|
789
|
+
source: child.source,
|
|
790
|
+
isExisting: Array.isArray(existing),
|
|
791
|
+
actions: {
|
|
792
|
+
rerender: () => {
|
|
793
|
+
lastRenderError = null;
|
|
794
|
+
if (rerenderToken) rerenderToken.value++;
|
|
795
|
+
},
|
|
796
|
+
rerenderAndBreak: () => {
|
|
797
|
+
lastRenderError = null;
|
|
798
|
+
if (breakNext) breakNext.value = true;
|
|
799
|
+
if (rerenderToken) rerenderToken.value++;
|
|
800
|
+
},
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
if (Array.isArray(existing)) {
|
|
804
|
+
componentRoot.length = 0;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
pushStack(child.component, child.props, child.source);
|
|
808
|
+
let renderFailed = false;
|
|
809
|
+
let childResult: Children | undefined;
|
|
810
|
+
try {
|
|
811
|
+
childResult = untrack(() => {
|
|
812
|
+
const shouldBreak = breakNext?.value;
|
|
813
|
+
if (shouldBreak) {
|
|
814
|
+
breakNext!.value = false;
|
|
815
|
+
// eslint-disable-next-line no-debugger
|
|
816
|
+
debugger;
|
|
817
|
+
}
|
|
818
|
+
return child();
|
|
819
|
+
});
|
|
820
|
+
} catch (error) {
|
|
821
|
+
notifyRenderError(error);
|
|
822
|
+
renderFailed = true;
|
|
823
|
+
throw error;
|
|
824
|
+
}
|
|
825
|
+
try {
|
|
826
|
+
if (context?.meta?.directory) {
|
|
827
|
+
debugSession.recordDirectory(context.meta.directory.path);
|
|
828
|
+
}
|
|
829
|
+
if (context?.meta?.sourceFile) {
|
|
830
|
+
context.meta.renderNode = componentRoot;
|
|
831
|
+
debugSession.recordFile(
|
|
832
|
+
context.meta.sourceFile.path,
|
|
833
|
+
context.meta.sourceFile.filetype,
|
|
834
|
+
);
|
|
835
|
+
context.meta.sourceFileReady = false;
|
|
836
|
+
}
|
|
837
|
+
if (!renderFailed) {
|
|
838
|
+
renderWorker(componentRoot, childResult);
|
|
839
|
+
}
|
|
840
|
+
} finally {
|
|
841
|
+
popStack();
|
|
842
|
+
}
|
|
843
|
+
if (renderFailed) {
|
|
844
|
+
node[index] = componentRoot;
|
|
845
|
+
cache.set(child, componentRoot);
|
|
846
|
+
notifyFileUpdateForNode(node);
|
|
847
|
+
notifyContentState();
|
|
848
|
+
onCleanup(() => debugSession.dispose());
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (context?.meta?.sourceFile) {
|
|
852
|
+
context.meta.sourceFileReady = true;
|
|
853
|
+
notifyFileUpdateForNode(componentRoot);
|
|
854
|
+
}
|
|
855
|
+
node[index] = componentRoot;
|
|
856
|
+
cache.set(child, componentRoot);
|
|
857
|
+
notifyContentState();
|
|
858
|
+
onCleanup(() => debugSession.dispose());
|
|
859
|
+
},
|
|
860
|
+
undefined,
|
|
861
|
+
{
|
|
862
|
+
debug: {
|
|
863
|
+
name: `render:${child.component.name || "Anonymous"}`,
|
|
864
|
+
type: "render",
|
|
865
|
+
},
|
|
866
|
+
},
|
|
867
|
+
);
|
|
603
868
|
} else if (typeof child === "function") {
|
|
604
|
-
trace(TracePhase.render.appendChild, () => "Memo: " + child.toString());
|
|
605
869
|
const index = node.length;
|
|
606
|
-
effect(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
870
|
+
effect(
|
|
871
|
+
() => {
|
|
872
|
+
let res: Child | Children | undefined;
|
|
873
|
+
let renderFailed = false;
|
|
874
|
+
try {
|
|
875
|
+
res = child();
|
|
876
|
+
while (typeof res === "function" && !isComponentCreator(res)) {
|
|
877
|
+
res = res();
|
|
878
|
+
}
|
|
879
|
+
} catch (error) {
|
|
880
|
+
notifyRenderError(error);
|
|
881
|
+
renderFailed = true;
|
|
882
|
+
throw error;
|
|
883
|
+
}
|
|
884
|
+
const context = getContext();
|
|
885
|
+
context!.childrenWithContent = 0;
|
|
886
|
+
|
|
887
|
+
const existing = node[index];
|
|
888
|
+
const memoNode: RenderedTextTree =
|
|
889
|
+
Array.isArray(existing) ? existing : [];
|
|
890
|
+
|
|
891
|
+
debug.render.prepareMemoNode(node, memoNode, Array.isArray(existing));
|
|
892
|
+
if (Array.isArray(existing)) {
|
|
893
|
+
memoNode.length = 0;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
if (!renderFailed) {
|
|
897
|
+
renderWorker(memoNode, res);
|
|
898
|
+
}
|
|
899
|
+
node[index] = memoNode;
|
|
900
|
+
cache.set(child, memoNode);
|
|
901
|
+
notifyFileUpdateForNode(node);
|
|
902
|
+
notifyContentState();
|
|
903
|
+
return memoNode;
|
|
904
|
+
},
|
|
905
|
+
undefined,
|
|
906
|
+
{
|
|
907
|
+
debug: {
|
|
908
|
+
name: `render:memo:${child.name || "anonymous"}`,
|
|
909
|
+
type: "render",
|
|
910
|
+
},
|
|
911
|
+
},
|
|
912
|
+
);
|
|
624
913
|
} else {
|
|
625
914
|
throw new Error("Unexpected child type");
|
|
626
915
|
}
|
|
627
916
|
}
|
|
628
917
|
}
|
|
629
918
|
|
|
919
|
+
function findSourceFileContext(node: RenderedTextTree) {
|
|
920
|
+
let context: Context | null | undefined =
|
|
921
|
+
getContextForRenderNode(node) ?? null;
|
|
922
|
+
while (context) {
|
|
923
|
+
if (context.meta?.sourceFile) return context;
|
|
924
|
+
context = context.owner;
|
|
925
|
+
}
|
|
926
|
+
return undefined;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function notifyFileUpdateForNode(node: RenderedTextTree) {
|
|
930
|
+
// Only do the expensive printTree when devtools are actually enabled
|
|
931
|
+
if (!isDevtoolsEnabled()) return;
|
|
932
|
+
const context = findSourceFileContext(node);
|
|
933
|
+
if (!context?.meta?.sourceFile) return;
|
|
934
|
+
if (context.meta.sourceFileReady === false) return;
|
|
935
|
+
const sourceFile = context.meta.sourceFile;
|
|
936
|
+
const renderNode: RenderedTextTree =
|
|
937
|
+
(context.meta.renderNode as RenderedTextTree | undefined) ?? node;
|
|
938
|
+
// Pass noFlush here since it flushes jobs and can re-enter rendering
|
|
939
|
+
// during effect setup, triggering premature cleanup.
|
|
940
|
+
const contents = printTree(renderNode, {
|
|
941
|
+
printWidth: context.meta?.printOptions?.printWidth,
|
|
942
|
+
tabWidth: context.meta?.printOptions?.tabWidth,
|
|
943
|
+
useTabs: context.meta?.printOptions?.useTabs,
|
|
944
|
+
insertFinalNewLine: context.meta?.printOptions?.insertFinalNewLine ?? true,
|
|
945
|
+
noFlush: true,
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
debug.files.updated({
|
|
949
|
+
path: sourceFile.path,
|
|
950
|
+
filetype: sourceFile.filetype,
|
|
951
|
+
contents,
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
|
|
630
955
|
type NormalizedChildren = NormalizedChild | NormalizedChildren[];
|
|
631
956
|
type NormalizedChild =
|
|
632
957
|
| string
|
|
@@ -669,31 +994,6 @@ function normalizeChild(child: Child): NormalizedChildren {
|
|
|
669
994
|
}
|
|
670
995
|
}
|
|
671
996
|
|
|
672
|
-
function dumpChildren(children: Children): string {
|
|
673
|
-
if (Array.isArray(children)) {
|
|
674
|
-
return `[ ${children.map(debugPrintChild).join(", ")} ]`;
|
|
675
|
-
}
|
|
676
|
-
return debugPrintChild(children);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
function debugPrintChild(child: Children): string {
|
|
680
|
-
if (isComponentCreator(child)) {
|
|
681
|
-
return "<" + child.component.name + ">";
|
|
682
|
-
} else if (typeof child === "function") {
|
|
683
|
-
return "$memo";
|
|
684
|
-
} else if (isRef(child)) {
|
|
685
|
-
return "$ref";
|
|
686
|
-
} else if (isIntrinsicElement(child)) {
|
|
687
|
-
return `<${child.name}>`;
|
|
688
|
-
} else if (isRenderableObject(child)) {
|
|
689
|
-
return `CustomChildElement(${JSON.stringify(child)})`;
|
|
690
|
-
} else if (isRefkeyable(child)) {
|
|
691
|
-
return `refkey`;
|
|
692
|
-
} else {
|
|
693
|
-
return JSON.stringify(child);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
997
|
export interface PrintTreeOptions {
|
|
698
998
|
/**
|
|
699
999
|
* The number of characters the printer will wrap on. Defaults to 100
|
|
@@ -716,6 +1016,12 @@ export interface PrintTreeOptions {
|
|
|
716
1016
|
* @default true
|
|
717
1017
|
*/
|
|
718
1018
|
insertFinalNewLine?: boolean;
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Skip flushing scheduled jobs before printing.
|
|
1022
|
+
* @default false
|
|
1023
|
+
*/
|
|
1024
|
+
noFlush?: boolean;
|
|
719
1025
|
}
|
|
720
1026
|
|
|
721
1027
|
const defaultPrintTreeOptions: PrintTreeOptions = {
|
|
@@ -735,8 +1041,10 @@ export function printTree(tree: RenderedTextTree, options?: PrintTreeOptions) {
|
|
|
735
1041
|
),
|
|
736
1042
|
};
|
|
737
1043
|
|
|
738
|
-
|
|
739
|
-
|
|
1044
|
+
if (!options.noFlush) {
|
|
1045
|
+
// make sure queue is empty
|
|
1046
|
+
flushJobs();
|
|
1047
|
+
}
|
|
740
1048
|
|
|
741
1049
|
const d = printTreeWorker(tree);
|
|
742
1050
|
const result = doc.printer.printDocToString(
|
|
@@ -768,57 +1076,3 @@ function printTreeWorker(tree: RenderedTextTree): Doc {
|
|
|
768
1076
|
|
|
769
1077
|
return doc;
|
|
770
1078
|
}
|
|
771
|
-
// debugging utilities
|
|
772
|
-
const renderStack: {
|
|
773
|
-
component: Component<any>;
|
|
774
|
-
props: Props;
|
|
775
|
-
}[] = [];
|
|
776
|
-
|
|
777
|
-
export function pushStack(component: Component<any>, props: Props) {
|
|
778
|
-
if (!shouldDebug()) return;
|
|
779
|
-
renderStack.push({ component, props });
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
export function popStack() {
|
|
783
|
-
if (!shouldDebug()) return;
|
|
784
|
-
renderStack.pop();
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
export function printRenderStack() {
|
|
788
|
-
if (!shouldDebug()) return;
|
|
789
|
-
|
|
790
|
-
// eslint-disable-next-line no-console
|
|
791
|
-
console.error("Error rendering:");
|
|
792
|
-
for (let i = renderStack.length - 1; i >= 0; i--) {
|
|
793
|
-
const { component, props } = renderStack[i];
|
|
794
|
-
// eslint-disable-next-line no-console
|
|
795
|
-
console.error(` at ${component.name}(${inspectProps(props)})`);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
function inspectProps(props: Props) {
|
|
800
|
-
return JSON.stringify(
|
|
801
|
-
Object.fromEntries(
|
|
802
|
-
Object.entries(props).map(([key, value]) => {
|
|
803
|
-
let safeValue;
|
|
804
|
-
switch (typeof value) {
|
|
805
|
-
case "string":
|
|
806
|
-
case "number":
|
|
807
|
-
case "boolean":
|
|
808
|
-
safeValue = value;
|
|
809
|
-
break;
|
|
810
|
-
case "undefined":
|
|
811
|
-
safeValue = "undefined";
|
|
812
|
-
break;
|
|
813
|
-
case "object":
|
|
814
|
-
safeValue = value ? "{...}" : null;
|
|
815
|
-
break;
|
|
816
|
-
case "function":
|
|
817
|
-
safeValue = "function";
|
|
818
|
-
break;
|
|
819
|
-
}
|
|
820
|
-
return [key, safeValue];
|
|
821
|
-
}),
|
|
822
|
-
),
|
|
823
|
-
);
|
|
824
|
-
}
|