@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.
- 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/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/Scope.d.ts.map +1 -1
- package/dist/src/components/Scope.js +4 -1
- package/dist/src/components/Scope.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/content-slot.d.ts.map +1 -1
- package/dist/src/content-slot.js +6 -5
- package/dist/src/content-slot.js.map +1 -1
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +8 -1
- 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 +69 -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 +86 -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 +60 -0
- package/dist/src/debug/index.d.ts.map +1 -0
- package/dist/src/debug/index.js +68 -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 +9 -0
- package/dist/src/debug/symbols.d.ts.map +1 -0
- package/dist/src/debug/symbols.js +164 -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 +15 -0
- package/dist/src/reactive-union-set.js.map +1 -1
- package/dist/src/reactivity.d.ts +17 -3
- package/dist/src/reactivity.d.ts.map +1 -1
- package/dist/src/reactivity.js +162 -14
- package/dist/src/reactivity.js.map +1 -1
- package/dist/src/render-stack.d.ts +29 -0
- package/dist/src/render-stack.d.ts.map +1 -0
- package/dist/src/render-stack.js +247 -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 +363 -153
- 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 +3 -0
- package/dist/src/scheduler.d.ts.map +1 -1
- package/dist/src/scheduler.js +45 -2
- 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 +23 -6
- 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 +22 -6
- 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 +5 -0
- 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/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/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/AppendFile.tsx +14 -9
- package/src/components/Block.tsx +1 -1
- package/src/components/Declaration.tsx +2 -1
- package/src/components/Scope.tsx +4 -1
- package/src/components/TemplateFile.tsx +18 -9
- package/src/content-slot.tsx +6 -6
- package/src/context.ts +15 -4
- package/src/{debug.ts → debug/cli.ts} +112 -127
- package/src/debug/diagnostics.test.tsx +55 -0
- package/src/debug/effects.test.tsx +96 -0
- package/src/debug/effects.ts +313 -0
- package/src/debug/files.test.tsx +96 -0
- package/src/debug/files.ts +40 -0
- package/src/debug/index.ts +126 -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 +230 -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 -6
- package/src/print-hook.ts +22 -0
- package/src/reactive-union-set.ts +71 -41
- package/src/reactivity.ts +206 -23
- package/src/render-stack.ts +289 -0
- package/src/render.ts +464 -212
- package/src/resource.ts +28 -19
- package/src/runtime/component.ts +11 -0
- package/src/scheduler.ts +55 -3
- package/src/symbols/basic-symbol.ts +6 -1
- package/src/symbols/decl.ts +5 -1
- package/src/symbols/output-scope.ts +21 -12
- package/src/symbols/output-symbol.ts +33 -12
- package/src/symbols/symbol-flow.ts +68 -37
- 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 +22 -13
- package/temp/api.json +1811 -277
- package/test/components/append-file.test.tsx +36 -29
- package/test/components/template-file.test.tsx +11 -11
- package/test/rendering/basic.test.tsx +4 -0
- package/test/rendering/print-render-stack.test.tsx +244 -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);
|
|
@@ -386,6 +514,10 @@ export function notifyContentState() {
|
|
|
386
514
|
break;
|
|
387
515
|
}
|
|
388
516
|
current.childrenWithContent--;
|
|
517
|
+
if (current.childrenWithContent > 0) {
|
|
518
|
+
// This isn't the last content so we have no work to do
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
389
521
|
if (current.isEmpty) {
|
|
390
522
|
current.isEmpty.value = true;
|
|
391
523
|
}
|
|
@@ -421,95 +553,120 @@ export function notifyContentState() {
|
|
|
421
553
|
}
|
|
422
554
|
|
|
423
555
|
function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
424
|
-
|
|
556
|
+
if (lastRenderError) return;
|
|
425
557
|
const child = normalizeChild(rawChild);
|
|
426
558
|
|
|
427
559
|
if (typeof child === "string") {
|
|
428
560
|
if (child !== "") {
|
|
429
561
|
contentAdded();
|
|
562
|
+
debug.render.appendTextNode(node, node.length, child);
|
|
430
563
|
}
|
|
431
564
|
node.push(child);
|
|
432
565
|
} else {
|
|
433
566
|
const cache = getElementCache();
|
|
434
567
|
if (cache.has(child as any)) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
568
|
+
const cachedNode = cache.get(child as any)!;
|
|
569
|
+
// recordSubtreeAdded detects cached nodes automatically and re-adds their children
|
|
570
|
+
if (isCustomContext(child)) {
|
|
571
|
+
debug.render.appendCustomContext(node, cachedNode);
|
|
572
|
+
} else {
|
|
573
|
+
debug.render.appendFragmentChild(node, cachedNode);
|
|
574
|
+
}
|
|
575
|
+
node.push(cachedNode);
|
|
440
576
|
return;
|
|
441
577
|
}
|
|
442
578
|
if (isCustomContext(child)) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
() => "CustomContext: " + debugPrintChild(child),
|
|
446
|
-
);
|
|
579
|
+
const newNode: RenderedTextTree = [];
|
|
580
|
+
debug.render.appendCustomContext(node, newNode);
|
|
447
581
|
child.useCustomContext((children) => {
|
|
448
|
-
const newNode: RenderedTextTree = [];
|
|
449
582
|
renderWorker(newNode, children);
|
|
450
583
|
node.push(newNode);
|
|
451
584
|
cache.set(child, newNode);
|
|
452
585
|
notifyContentState();
|
|
586
|
+
notifyFileUpdateForNode(node);
|
|
453
587
|
});
|
|
454
588
|
} else if (isIntrinsicElement(child)) {
|
|
455
|
-
trace(
|
|
456
|
-
TracePhase.render.appendChild,
|
|
457
|
-
() => "IntrinsicElement: " + debugPrintChild(child),
|
|
458
|
-
);
|
|
459
589
|
// don't need a new context here because intrinsics are never reactive
|
|
590
|
+
const intrinsic = child as IntrinsicElement;
|
|
460
591
|
const newNode: RenderedTextTree = [];
|
|
461
592
|
|
|
462
593
|
function formatHookWithChildren(command: (doc: Doc) => Doc) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
print(tree
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
594
|
+
const hook = createRenderTreeHook(newNode, {
|
|
595
|
+
print(tree, print) {
|
|
596
|
+
return command(print(tree));
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
debug.render.appendPrintHook(
|
|
600
|
+
node,
|
|
601
|
+
node.length,
|
|
602
|
+
hook,
|
|
603
|
+
intrinsic.name,
|
|
604
|
+
newNode,
|
|
469
605
|
);
|
|
606
|
+
node.push(hook);
|
|
470
607
|
renderWorker(newNode, (child as any).props.children);
|
|
608
|
+
notifyFileUpdateForNode(node);
|
|
471
609
|
}
|
|
472
610
|
|
|
473
611
|
function formatHook(command: Doc) {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
);
|
|
612
|
+
const hook = createRenderTreeHook(newNode, {
|
|
613
|
+
print() {
|
|
614
|
+
return command;
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
debug.render.appendPrintHook(node, node.length, hook, intrinsic.name);
|
|
618
|
+
node.push(hook);
|
|
619
|
+
return hook;
|
|
481
620
|
}
|
|
482
621
|
|
|
483
622
|
switch (child.name) {
|
|
484
623
|
case "indent":
|
|
485
624
|
return formatHookWithChildren(indent);
|
|
486
625
|
case "indentIfBreak":
|
|
487
|
-
|
|
488
|
-
createRenderTreeHook(newNode, {
|
|
626
|
+
{
|
|
627
|
+
const hook = createRenderTreeHook(newNode, {
|
|
489
628
|
print(tree, print) {
|
|
490
629
|
return indentIfBreak(print(tree), {
|
|
491
630
|
groupId: child.props.groupId,
|
|
492
631
|
negate: child.props.negate,
|
|
493
632
|
});
|
|
494
633
|
},
|
|
495
|
-
})
|
|
496
|
-
|
|
634
|
+
});
|
|
635
|
+
debug.render.appendPrintHook(
|
|
636
|
+
node,
|
|
637
|
+
node.length,
|
|
638
|
+
hook,
|
|
639
|
+
intrinsic.name,
|
|
640
|
+
newNode,
|
|
641
|
+
);
|
|
642
|
+
node.push(hook);
|
|
643
|
+
}
|
|
497
644
|
renderWorker(newNode, child.props.children);
|
|
645
|
+
notifyFileUpdateForNode(node);
|
|
498
646
|
return;
|
|
499
647
|
case "fill":
|
|
500
648
|
return formatHookWithChildren(fill as any);
|
|
501
649
|
case "group":
|
|
502
|
-
|
|
503
|
-
createRenderTreeHook(newNode, {
|
|
650
|
+
{
|
|
651
|
+
const hook = createRenderTreeHook(newNode, {
|
|
504
652
|
print(tree, print) {
|
|
505
653
|
return group(print(tree), {
|
|
506
654
|
id: child.props.id,
|
|
507
655
|
shouldBreak: child.props.shouldBreak,
|
|
508
656
|
});
|
|
509
657
|
},
|
|
510
|
-
})
|
|
511
|
-
|
|
658
|
+
});
|
|
659
|
+
debug.render.appendPrintHook(
|
|
660
|
+
node,
|
|
661
|
+
node.length,
|
|
662
|
+
hook,
|
|
663
|
+
intrinsic.name,
|
|
664
|
+
newNode,
|
|
665
|
+
);
|
|
666
|
+
node.push(hook);
|
|
667
|
+
}
|
|
512
668
|
renderWorker(newNode, child.props.children);
|
|
669
|
+
notifyFileUpdateForNode(node);
|
|
513
670
|
return;
|
|
514
671
|
case "line":
|
|
515
672
|
case "br":
|
|
@@ -524,17 +681,26 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
524
681
|
case "lbr":
|
|
525
682
|
return formatHook(literalline);
|
|
526
683
|
case "align":
|
|
527
|
-
|
|
528
|
-
createRenderTreeHook(newNode, {
|
|
684
|
+
{
|
|
685
|
+
const hook = createRenderTreeHook(newNode, {
|
|
529
686
|
print(tree, print) {
|
|
530
687
|
return align(
|
|
531
688
|
(child.props as any).width ?? (child.props as any).string!,
|
|
532
689
|
print(tree),
|
|
533
690
|
);
|
|
534
691
|
},
|
|
535
|
-
})
|
|
536
|
-
|
|
692
|
+
});
|
|
693
|
+
debug.render.appendPrintHook(
|
|
694
|
+
node,
|
|
695
|
+
node.length,
|
|
696
|
+
hook,
|
|
697
|
+
intrinsic.name,
|
|
698
|
+
newNode,
|
|
699
|
+
);
|
|
700
|
+
node.push(hook);
|
|
701
|
+
}
|
|
537
702
|
renderWorker(newNode, (child as any).props.children);
|
|
703
|
+
notifyFileUpdateForNode(node);
|
|
538
704
|
return;
|
|
539
705
|
case "lineSuffix":
|
|
540
706
|
return formatHookWithChildren(lineSuffix);
|
|
@@ -549,17 +715,33 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
549
715
|
case "markAsRoot":
|
|
550
716
|
return formatHookWithChildren(markAsRoot);
|
|
551
717
|
case "ifBreak":
|
|
552
|
-
|
|
553
|
-
createRenderTreeHook(newNode, {
|
|
718
|
+
{
|
|
719
|
+
const hook = createRenderTreeHook(newNode, {
|
|
554
720
|
print(tree, print) {
|
|
555
721
|
return ifBreak(
|
|
556
722
|
print((tree as RenderedTextTree[])[0]),
|
|
557
723
|
print((tree as RenderedTextTree[])[1]),
|
|
558
724
|
);
|
|
559
725
|
},
|
|
560
|
-
})
|
|
561
|
-
|
|
726
|
+
});
|
|
727
|
+
debug.render.appendPrintHook(
|
|
728
|
+
node,
|
|
729
|
+
node.length,
|
|
730
|
+
hook,
|
|
731
|
+
intrinsic.name,
|
|
732
|
+
newNode,
|
|
733
|
+
);
|
|
734
|
+
node.push(hook);
|
|
735
|
+
}
|
|
562
736
|
newNode.push([], []);
|
|
737
|
+
debug.render.appendFragmentChild(
|
|
738
|
+
newNode,
|
|
739
|
+
newNode[0] as RenderedTextTree,
|
|
740
|
+
);
|
|
741
|
+
debug.render.appendFragmentChild(
|
|
742
|
+
newNode,
|
|
743
|
+
newNode[1] as RenderedTextTree,
|
|
744
|
+
);
|
|
563
745
|
renderWorker(
|
|
564
746
|
newNode[0] as RenderedTextTree[],
|
|
565
747
|
(child as any).props.children,
|
|
@@ -568,65 +750,206 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
568
750
|
newNode[1] as RenderedTextTree[],
|
|
569
751
|
(child as any).props.flatContents,
|
|
570
752
|
);
|
|
753
|
+
notifyFileUpdateForNode(node);
|
|
571
754
|
return;
|
|
572
755
|
default:
|
|
573
756
|
throw new Error("Unknown intrinsic element");
|
|
574
757
|
}
|
|
575
758
|
} else if (isComponentCreator(child)) {
|
|
759
|
+
const index = node.length;
|
|
760
|
+
const rerenderToken = ref(0);
|
|
761
|
+
const breakNext = ref(false);
|
|
576
762
|
// 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
|
-
|
|
763
|
+
effect(
|
|
764
|
+
() => {
|
|
765
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
766
|
+
rerenderToken.value;
|
|
767
|
+
const context = getContext();
|
|
768
|
+
context!.childrenWithContent = 0;
|
|
769
|
+
context!.isEmpty ??= ref(true);
|
|
770
|
+
|
|
771
|
+
if (context) context.componentOwner = child;
|
|
772
|
+
const existing = node[index];
|
|
773
|
+
const componentRoot: RenderedTextTree =
|
|
774
|
+
Array.isArray(existing) ? existing : [];
|
|
775
|
+
context!.meta ??= {};
|
|
776
|
+
context!.meta.renderNode = componentRoot;
|
|
777
|
+
const propsSource = (child.props ?? undefined) as
|
|
778
|
+
| Record<string, unknown>
|
|
779
|
+
| undefined;
|
|
780
|
+
const debugSession = debug.render.beginComponent({
|
|
781
|
+
parent: node,
|
|
782
|
+
index,
|
|
783
|
+
node: componentRoot,
|
|
784
|
+
component: child,
|
|
785
|
+
propsSource,
|
|
786
|
+
source: child.source,
|
|
787
|
+
isExisting: Array.isArray(existing),
|
|
788
|
+
actions: {
|
|
789
|
+
rerender: () => {
|
|
790
|
+
lastRenderError = null;
|
|
791
|
+
rerenderToken.value++;
|
|
792
|
+
},
|
|
793
|
+
rerenderAndBreak: () => {
|
|
794
|
+
lastRenderError = null;
|
|
795
|
+
breakNext.value = true;
|
|
796
|
+
rerenderToken.value++;
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
if (Array.isArray(existing)) {
|
|
801
|
+
componentRoot.length = 0;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
pushStack(child.component, child.props, child.source);
|
|
805
|
+
let renderFailed = false;
|
|
806
|
+
let childResult: Children | undefined;
|
|
807
|
+
try {
|
|
808
|
+
childResult = untrack(() => {
|
|
809
|
+
const shouldBreak = breakNext.value;
|
|
810
|
+
if (shouldBreak) {
|
|
811
|
+
breakNext.value = false;
|
|
812
|
+
// eslint-disable-next-line no-debugger
|
|
813
|
+
debugger;
|
|
814
|
+
}
|
|
815
|
+
return child();
|
|
816
|
+
});
|
|
817
|
+
} catch (error) {
|
|
818
|
+
notifyRenderError(error);
|
|
819
|
+
renderFailed = true;
|
|
820
|
+
throw error;
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
if (context?.meta?.directory) {
|
|
824
|
+
debugSession.recordDirectory(context.meta.directory.path);
|
|
825
|
+
}
|
|
826
|
+
if (context?.meta?.sourceFile) {
|
|
827
|
+
context.meta.renderNode = componentRoot;
|
|
828
|
+
debugSession.recordFile(
|
|
829
|
+
context.meta.sourceFile.path,
|
|
830
|
+
context.meta.sourceFile.filetype,
|
|
831
|
+
);
|
|
832
|
+
context.meta.sourceFileReady = false;
|
|
833
|
+
}
|
|
834
|
+
if (!renderFailed) {
|
|
835
|
+
renderWorker(componentRoot, childResult);
|
|
836
|
+
}
|
|
837
|
+
} finally {
|
|
838
|
+
popStack();
|
|
839
|
+
}
|
|
840
|
+
if (renderFailed) {
|
|
841
|
+
node[index] = componentRoot;
|
|
842
|
+
cache.set(child, componentRoot);
|
|
843
|
+
notifyFileUpdateForNode(node);
|
|
844
|
+
notifyContentState();
|
|
845
|
+
onCleanup(() => debugSession.dispose());
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
if (context?.meta?.sourceFile) {
|
|
849
|
+
context.meta.sourceFileReady = true;
|
|
850
|
+
notifyFileUpdateForNode(componentRoot);
|
|
851
|
+
}
|
|
852
|
+
node[index] = componentRoot;
|
|
853
|
+
cache.set(child, componentRoot);
|
|
854
|
+
notifyContentState();
|
|
855
|
+
onCleanup(() => debugSession.dispose());
|
|
856
|
+
},
|
|
857
|
+
undefined,
|
|
858
|
+
{
|
|
859
|
+
debug: {
|
|
860
|
+
name: `render:${child.component.name || "Anonymous"}`,
|
|
861
|
+
type: "render",
|
|
862
|
+
},
|
|
863
|
+
},
|
|
864
|
+
);
|
|
603
865
|
} else if (typeof child === "function") {
|
|
604
|
-
trace(TracePhase.render.appendChild, () => "Memo: " + child.toString());
|
|
605
866
|
const index = node.length;
|
|
606
|
-
effect(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
867
|
+
effect(
|
|
868
|
+
() => {
|
|
869
|
+
let res: Child | Children | undefined;
|
|
870
|
+
let renderFailed = false;
|
|
871
|
+
try {
|
|
872
|
+
res = child();
|
|
873
|
+
while (typeof res === "function" && !isComponentCreator(res)) {
|
|
874
|
+
res = res();
|
|
875
|
+
}
|
|
876
|
+
} catch (error) {
|
|
877
|
+
notifyRenderError(error);
|
|
878
|
+
renderFailed = true;
|
|
879
|
+
throw error;
|
|
880
|
+
}
|
|
881
|
+
const context = getContext();
|
|
882
|
+
context!.childrenWithContent = 0;
|
|
883
|
+
context!.isEmpty ??= ref(true);
|
|
884
|
+
|
|
885
|
+
const existing = node[index];
|
|
886
|
+
const memoNode: RenderedTextTree =
|
|
887
|
+
Array.isArray(existing) ? existing : [];
|
|
888
|
+
|
|
889
|
+
debug.render.prepareMemoNode(node, memoNode, Array.isArray(existing));
|
|
890
|
+
if (Array.isArray(existing)) {
|
|
891
|
+
memoNode.length = 0;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
if (!renderFailed) {
|
|
895
|
+
renderWorker(memoNode, res);
|
|
896
|
+
}
|
|
897
|
+
node[index] = memoNode;
|
|
898
|
+
cache.set(child, memoNode);
|
|
899
|
+
notifyFileUpdateForNode(node);
|
|
900
|
+
notifyContentState();
|
|
901
|
+
return memoNode;
|
|
902
|
+
},
|
|
903
|
+
undefined,
|
|
904
|
+
{
|
|
905
|
+
debug: {
|
|
906
|
+
name: `render:memo:${child.name || "anonymous"}`,
|
|
907
|
+
type: "render",
|
|
908
|
+
},
|
|
909
|
+
},
|
|
910
|
+
);
|
|
624
911
|
} else {
|
|
625
912
|
throw new Error("Unexpected child type");
|
|
626
913
|
}
|
|
627
914
|
}
|
|
628
915
|
}
|
|
629
916
|
|
|
917
|
+
function findSourceFileContext(node: RenderedTextTree) {
|
|
918
|
+
let context: Context | null | undefined =
|
|
919
|
+
getContextForRenderNode(node) ?? null;
|
|
920
|
+
while (context) {
|
|
921
|
+
if (context.meta?.sourceFile) return context;
|
|
922
|
+
context = context.owner;
|
|
923
|
+
}
|
|
924
|
+
return undefined;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function notifyFileUpdateForNode(node: RenderedTextTree) {
|
|
928
|
+
// Only do the expensive printTree when devtools are actually enabled
|
|
929
|
+
if (!isDevtoolsEnabled()) return;
|
|
930
|
+
const context = findSourceFileContext(node);
|
|
931
|
+
if (!context?.meta?.sourceFile) return;
|
|
932
|
+
if (context.meta.sourceFileReady === false) return;
|
|
933
|
+
const sourceFile = context.meta.sourceFile;
|
|
934
|
+
const renderNode: RenderedTextTree =
|
|
935
|
+
(context.meta.renderNode as RenderedTextTree | undefined) ?? node;
|
|
936
|
+
// Pass noFlush here since it flushes jobs and can re-enter rendering
|
|
937
|
+
// during effect setup, triggering premature cleanup.
|
|
938
|
+
const contents = printTree(renderNode, {
|
|
939
|
+
printWidth: context.meta?.printOptions?.printWidth,
|
|
940
|
+
tabWidth: context.meta?.printOptions?.tabWidth,
|
|
941
|
+
useTabs: context.meta?.printOptions?.useTabs,
|
|
942
|
+
insertFinalNewLine: context.meta?.printOptions?.insertFinalNewLine ?? true,
|
|
943
|
+
noFlush: true,
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
debug.files.updated({
|
|
947
|
+
path: sourceFile.path,
|
|
948
|
+
filetype: sourceFile.filetype,
|
|
949
|
+
contents,
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
|
|
630
953
|
type NormalizedChildren = NormalizedChild | NormalizedChildren[];
|
|
631
954
|
type NormalizedChild =
|
|
632
955
|
| string
|
|
@@ -669,31 +992,6 @@ function normalizeChild(child: Child): NormalizedChildren {
|
|
|
669
992
|
}
|
|
670
993
|
}
|
|
671
994
|
|
|
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
995
|
export interface PrintTreeOptions {
|
|
698
996
|
/**
|
|
699
997
|
* The number of characters the printer will wrap on. Defaults to 100
|
|
@@ -716,6 +1014,12 @@ export interface PrintTreeOptions {
|
|
|
716
1014
|
* @default true
|
|
717
1015
|
*/
|
|
718
1016
|
insertFinalNewLine?: boolean;
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Skip flushing scheduled jobs before printing.
|
|
1020
|
+
* @default false
|
|
1021
|
+
*/
|
|
1022
|
+
noFlush?: boolean;
|
|
719
1023
|
}
|
|
720
1024
|
|
|
721
1025
|
const defaultPrintTreeOptions: PrintTreeOptions = {
|
|
@@ -735,8 +1039,10 @@ export function printTree(tree: RenderedTextTree, options?: PrintTreeOptions) {
|
|
|
735
1039
|
),
|
|
736
1040
|
};
|
|
737
1041
|
|
|
738
|
-
|
|
739
|
-
|
|
1042
|
+
if (!options.noFlush) {
|
|
1043
|
+
// make sure queue is empty
|
|
1044
|
+
flushJobs();
|
|
1045
|
+
}
|
|
740
1046
|
|
|
741
1047
|
const d = printTreeWorker(tree);
|
|
742
1048
|
const result = doc.printer.printDocToString(
|
|
@@ -768,57 +1074,3 @@ function printTreeWorker(tree: RenderedTextTree): Doc {
|
|
|
768
1074
|
|
|
769
1075
|
return doc;
|
|
770
1076
|
}
|
|
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
|
-
}
|