@alloy-js/core 0.23.0-dev.1 → 0.23.0-dev.11
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 +80 -0
- package/dist/src/binder.d.ts +2 -0
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +60 -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/For.d.ts.map +1 -1
- package/dist/src/components/For.js +1 -1
- package/dist/src/components/For.js.map +1 -1
- package/dist/src/components/List.d.ts.map +1 -1
- package/dist/src/components/List.js +1 -1
- package/dist/src/components/List.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/Switch.d.ts.map +1 -1
- package/dist/src/components/Switch.js +1 -1
- package/dist/src/components/Switch.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} +79 -82
- 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 +46 -0
- package/dist/src/debug/diagnostics.test.js.map +1 -0
- package/dist/src/debug/effects.d.ts +81 -0
- package/dist/src/debug/effects.d.ts.map +1 -0
- package/dist/src/debug/effects.js +358 -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 +256 -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 +29 -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 +66 -0
- package/dist/src/debug/files.test.js.map +1 -0
- package/dist/src/debug/index.d.ts +63 -0
- package/dist/src/debug/index.d.ts.map +1 -0
- package/dist/src/debug/index.js +71 -0
- package/dist/src/debug/index.js.map +1 -0
- package/dist/src/debug/message-format.test.d.ts +2 -0
- package/dist/src/debug/message-format.test.d.ts.map +1 -0
- package/dist/src/debug/message-format.test.js +700 -0
- package/dist/src/debug/message-format.test.js.map +1 -0
- package/dist/src/debug/render-tree-orphans.test.d.ts +2 -0
- package/dist/src/debug/render-tree-orphans.test.d.ts.map +1 -0
- package/dist/src/debug/render-tree-orphans.test.js +297 -0
- package/dist/src/debug/render-tree-orphans.test.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 +472 -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 +291 -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 +16 -0
- package/dist/src/debug/symbols.d.ts.map +1 -0
- package/dist/src/debug/symbols.js +196 -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 +93 -0
- package/dist/src/debug/symbols.test.js.map +1 -0
- package/dist/src/debug/trace-writer.d.ts +55 -0
- package/dist/src/debug/trace-writer.d.ts.map +1 -0
- package/dist/src/debug/trace-writer.js +658 -0
- package/dist/src/debug/trace-writer.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 +446 -0
- package/dist/src/debug/trace.js.map +1 -0
- package/dist/src/devtools/devtools-protocol.d.ts +389 -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 +23 -0
- package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -0
- package/dist/src/devtools/devtools-server.browser.js +33 -0
- package/dist/src/devtools/devtools-server.browser.js.map +1 -0
- package/dist/src/devtools/devtools-server.d.ts +66 -0
- package/dist/src/devtools/devtools-server.d.ts.map +1 -0
- package/dist/src/devtools/devtools-server.js +444 -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 +60 -7
- package/dist/src/reactivity.d.ts.map +1 -1
- package/dist/src/reactivity.js +308 -39
- package/dist/src/reactivity.js.map +1 -1
- package/dist/src/render-stack.d.ts +18 -1
- package/dist/src/render-stack.d.ts.map +1 -1
- package/dist/src/render-stack.js +61 -1
- package/dist/src/render-stack.js.map +1 -1
- package/dist/src/render.d.ts +8 -15
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +424 -109
- 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/scheduler.d.ts +13 -0
- package/dist/src/scheduler.d.ts.map +1 -1
- package/dist/src/scheduler.js +150 -13
- 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 +17 -9
- 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.map +1 -1
- package/dist/test/rendering/print-render-stack.test.js +91 -98
- package/dist/test/rendering/print-render-stack.test.js.map +1 -1
- 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 +35 -0
- package/dist/testing/devtools-utils.d.ts.map +1 -0
- package/dist/testing/devtools-utils.js +162 -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 +117 -53
- 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/For.tsx +14 -10
- package/src/components/List.tsx +7 -4
- package/src/components/Prose.tsx +1 -1
- package/src/components/Scope.tsx +6 -1
- package/src/components/SourceDirectory.tsx +1 -2
- package/src/components/Switch.tsx +11 -7
- 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} +114 -125
- package/src/debug/diagnostics.test.tsx +56 -0
- package/src/debug/effects.test.tsx +301 -0
- package/src/debug/effects.ts +531 -0
- package/src/debug/files.test.tsx +76 -0
- package/src/debug/files.ts +40 -0
- package/src/debug/index.ts +132 -0
- package/src/debug/message-format.test.tsx +759 -0
- package/src/debug/render-tree-orphans.test.tsx +344 -0
- package/src/debug/render.test.tsx +357 -0
- package/src/debug/render.ts +698 -0
- package/src/debug/serialize.ts +85 -0
- package/src/debug/symbols.test.tsx +105 -0
- package/src/debug/symbols.ts +322 -0
- package/src/debug/trace-writer.ts +969 -0
- package/src/debug/trace.ts +309 -0
- package/src/devtools/devtools-protocol.ts +497 -0
- package/src/devtools/devtools-server.browser.ts +62 -0
- package/src/devtools/devtools-server.ts +468 -0
- package/src/devtools/devtools-transport.ts +154 -0
- package/src/devtools-entry.browser.ts +48 -0
- package/src/devtools-entry.ts +48 -0
- package/src/diagnostics.ts +150 -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 +396 -58
- package/src/render-stack.ts +73 -1
- package/src/render.ts +544 -161
- package/src/resource.ts +28 -19
- package/src/scheduler.ts +209 -14
- 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 +31 -21
- package/temp/api.json +5700 -3015
- 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 +52 -43
- 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 +245 -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 -14
- package/dist/src/debug.d.ts.map +0 -1
- package/dist/src/debug.js.map +0 -1
package/src/render.ts
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
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 {
|
|
7
|
+
debug,
|
|
8
|
+
getRenderNodeId,
|
|
9
|
+
isDevtoolsConnected,
|
|
10
|
+
isDevtoolsEnabled,
|
|
11
|
+
type RenderTreeNodeInfo,
|
|
12
|
+
} from "./debug/index.js";
|
|
13
|
+
import {
|
|
14
|
+
beginTransaction,
|
|
15
|
+
closeTrace,
|
|
16
|
+
commitTransaction,
|
|
17
|
+
notifyDiagnosticsReport,
|
|
18
|
+
} from "./debug/trace-writer.js";
|
|
19
|
+
import { isTraceEnabled } from "./debug/trace.js";
|
|
20
|
+
import {
|
|
21
|
+
attachDiagnosticsCollector,
|
|
22
|
+
DiagnosticsCollector,
|
|
23
|
+
emitDiagnostic,
|
|
24
|
+
reportDiagnostics,
|
|
25
|
+
} from "./diagnostics.js";
|
|
26
|
+
import {
|
|
27
|
+
isPrintHook,
|
|
28
|
+
printHookTag,
|
|
29
|
+
type PrintHook,
|
|
30
|
+
type RenderedTextTree,
|
|
31
|
+
} from "./print-hook.js";
|
|
6
32
|
import {
|
|
7
33
|
Context,
|
|
8
34
|
CustomContext,
|
|
@@ -10,11 +36,18 @@ import {
|
|
|
10
36
|
getContext,
|
|
11
37
|
getElementCache,
|
|
12
38
|
isCustomContext,
|
|
39
|
+
onCleanup,
|
|
40
|
+
ref,
|
|
13
41
|
root,
|
|
14
42
|
untrack,
|
|
15
43
|
} from "./reactivity.js";
|
|
16
44
|
import { isRefkeyable, toRefkey } from "./refkey.js";
|
|
17
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
getRenderStackSnapshot,
|
|
47
|
+
popStack,
|
|
48
|
+
printRenderStack,
|
|
49
|
+
pushStack,
|
|
50
|
+
} from "./render-stack.js";
|
|
18
51
|
import {
|
|
19
52
|
Child,
|
|
20
53
|
Children,
|
|
@@ -23,8 +56,128 @@ import {
|
|
|
23
56
|
RENDERABLE,
|
|
24
57
|
} from "./runtime/component.js";
|
|
25
58
|
import { IntrinsicElement, isIntrinsicElement } from "./runtime/intrinsic.js";
|
|
26
|
-
import { flushJobs, flushJobsAsync } from "./scheduler.js";
|
|
27
|
-
|
|
59
|
+
import { flushJobs, flushJobsAsync, waitForSignal } from "./scheduler.js";
|
|
60
|
+
|
|
61
|
+
const notifiedErrors = new WeakSet<object>();
|
|
62
|
+
|
|
63
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
// Deferred file printing: mark files dirty during render, print once at end
|
|
65
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
interface DirtyFileEntry {
|
|
67
|
+
renderNode: RenderedTextTree;
|
|
68
|
+
printOptions: {
|
|
69
|
+
printWidth?: number;
|
|
70
|
+
tabWidth?: number;
|
|
71
|
+
useTabs?: boolean;
|
|
72
|
+
insertFinalNewLine?: boolean;
|
|
73
|
+
};
|
|
74
|
+
path: string;
|
|
75
|
+
filetype: string;
|
|
76
|
+
}
|
|
77
|
+
const dirtyFiles = new Map<string, DirtyFileEntry>();
|
|
78
|
+
const lastFlushTimeByFile = new Map<string, number>();
|
|
79
|
+
const DEVTOOLS_FLUSH_INTERVAL_MS = 1000;
|
|
80
|
+
|
|
81
|
+
function flushDirtyFile(path: string): void {
|
|
82
|
+
const entry = dirtyFiles.get(path);
|
|
83
|
+
if (!entry) return;
|
|
84
|
+
dirtyFiles.delete(path);
|
|
85
|
+
const contents = printTree(entry.renderNode, {
|
|
86
|
+
...entry.printOptions,
|
|
87
|
+
insertFinalNewLine: entry.printOptions.insertFinalNewLine ?? true,
|
|
88
|
+
noFlush: true,
|
|
89
|
+
});
|
|
90
|
+
debug.files.updated({ path: entry.path, filetype: entry.filetype, contents });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function flushDirtyFiles(): void {
|
|
94
|
+
for (const path of [...dirtyFiles.keys()]) {
|
|
95
|
+
flushDirtyFile(path);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let lastRenderError: {
|
|
100
|
+
error: { name: string; message: string; stack?: string };
|
|
101
|
+
componentStack: Array<{
|
|
102
|
+
name: string;
|
|
103
|
+
props?: Record<string, unknown> | undefined;
|
|
104
|
+
propsSerialized?: string;
|
|
105
|
+
renderNodeId?: number;
|
|
106
|
+
source?: RenderTreeNodeInfo["source"];
|
|
107
|
+
}>;
|
|
108
|
+
} | null = null;
|
|
109
|
+
|
|
110
|
+
function normalizeRenderError(error: unknown): {
|
|
111
|
+
name: string;
|
|
112
|
+
message: string;
|
|
113
|
+
stack?: string;
|
|
114
|
+
} {
|
|
115
|
+
if (error instanceof Error) {
|
|
116
|
+
return {
|
|
117
|
+
name: error.name || error.constructor?.name || "Error",
|
|
118
|
+
message: error.message || "",
|
|
119
|
+
stack: error.stack,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (error && typeof error === "object") {
|
|
123
|
+
const anyError = error as {
|
|
124
|
+
name?: string;
|
|
125
|
+
message?: string;
|
|
126
|
+
stack?: string;
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
name: anyError.name || "Error",
|
|
130
|
+
message: anyError.message || String(error),
|
|
131
|
+
stack: anyError.stack,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
name: "Error",
|
|
136
|
+
message: String(error),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function notifyRenderError(error: unknown) {
|
|
141
|
+
if (error && typeof error === "object") {
|
|
142
|
+
if (notifiedErrors.has(error)) return;
|
|
143
|
+
notifiedErrors.add(error);
|
|
144
|
+
}
|
|
145
|
+
if (lastRenderError) return;
|
|
146
|
+
|
|
147
|
+
const { name, message, stack } = normalizeRenderError(error);
|
|
148
|
+
const componentStack = getRenderStackSnapshot().map((entry) => {
|
|
149
|
+
const renderNode = entry.context?.meta?.renderNode as
|
|
150
|
+
| RenderedTextTree
|
|
151
|
+
| undefined;
|
|
152
|
+
const renderNodeId = renderNode ? getRenderNodeId(renderNode) : undefined;
|
|
153
|
+
return {
|
|
154
|
+
name: entry.displayName,
|
|
155
|
+
props: entry.props as Record<string, unknown> | undefined,
|
|
156
|
+
renderNodeId,
|
|
157
|
+
source: entry.source,
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Output to console
|
|
162
|
+
printRenderStack(error);
|
|
163
|
+
|
|
164
|
+
// Send to devtools if enabled
|
|
165
|
+
debug.render.error({ name, message, stack }, componentStack);
|
|
166
|
+
|
|
167
|
+
// Store for diagnostics
|
|
168
|
+
lastRenderError = { error: { name, message, stack }, componentStack };
|
|
169
|
+
const lastEntry = componentStack.at(-1);
|
|
170
|
+
emitDiagnostic({
|
|
171
|
+
severity: "error",
|
|
172
|
+
message: `${name}: ${message}`,
|
|
173
|
+
source: lastEntry?.source,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function reportLastRenderError() {
|
|
178
|
+
// Error already reported in notifyRenderError via debug.renderError
|
|
179
|
+
lastRenderError = null;
|
|
180
|
+
}
|
|
28
181
|
|
|
29
182
|
const {
|
|
30
183
|
builders: {
|
|
@@ -150,23 +303,33 @@ export interface ContentOutputFile extends OutputFileBase {
|
|
|
150
303
|
export type OutputFile = ContentOutputFile | CopyOutputFile;
|
|
151
304
|
|
|
152
305
|
const nodesToContext = new WeakMap<RenderedTextTree, Context>();
|
|
306
|
+
const diagnosticsByTree = new WeakMap<RenderedTextTree, DiagnosticsCollector>();
|
|
153
307
|
|
|
154
308
|
export function getContextForRenderNode(node: RenderedTextTree) {
|
|
155
309
|
return nodesToContext.get(node);
|
|
156
310
|
}
|
|
157
311
|
|
|
158
|
-
export
|
|
312
|
+
export function getDiagnosticsForTree(tree: RenderedTextTree) {
|
|
313
|
+
return diagnosticsByTree.get(tree)?.getDiagnostics() ?? [];
|
|
314
|
+
}
|
|
159
315
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
167
|
-
subtree: RenderedTextTree;
|
|
316
|
+
function reportDiagnosticsForTree(tree: RenderedTextTree) {
|
|
317
|
+
const diagnostics = diagnosticsByTree.get(tree);
|
|
318
|
+
if (!diagnostics) return;
|
|
319
|
+
const entries = diagnostics.getDiagnostics();
|
|
320
|
+
if (entries.length === 0) return;
|
|
321
|
+
reportDiagnostics(diagnostics);
|
|
322
|
+
notifyDiagnosticsReport(entries);
|
|
168
323
|
}
|
|
169
324
|
|
|
325
|
+
// Re-export from print-hook.ts to maintain backwards compatibility
|
|
326
|
+
export {
|
|
327
|
+
isPrintHook,
|
|
328
|
+
printHookTag,
|
|
329
|
+
type PrintHook,
|
|
330
|
+
type RenderedTextTree,
|
|
331
|
+
} from "./print-hook.js";
|
|
332
|
+
|
|
170
333
|
export function createRenderTreeHook(
|
|
171
334
|
subtree: RenderedTextTree,
|
|
172
335
|
hooks: Omit<PrintHook, typeof printHookTag | "subtree">,
|
|
@@ -178,12 +341,6 @@ export function createRenderTreeHook(
|
|
|
178
341
|
};
|
|
179
342
|
}
|
|
180
343
|
|
|
181
|
-
export function isPrintHook(type: unknown): type is PrintHook {
|
|
182
|
-
return typeof type === "object" && type !== null && printHookTag in type;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export type RenderedTextTree = (string | RenderedTextTree | PrintHook)[];
|
|
186
|
-
|
|
187
344
|
/**
|
|
188
345
|
* Render a component tree to source directories and files. Will ensure that
|
|
189
346
|
* all non-async scheduled jobs are completed before returning. If async jobs
|
|
@@ -196,7 +353,18 @@ export function render(
|
|
|
196
353
|
): OutputDirectory {
|
|
197
354
|
const tree = renderTree(children);
|
|
198
355
|
flushJobs();
|
|
199
|
-
|
|
356
|
+
const output = sourceFilesForTree(tree, options);
|
|
357
|
+
flushDirtyFiles();
|
|
358
|
+
reportDiagnosticsForTree(tree);
|
|
359
|
+
reportLastRenderError();
|
|
360
|
+
debug.render.complete();
|
|
361
|
+
// Only close the trace DB when devtools is NOT running. When devtools is
|
|
362
|
+
// active the DB must remain open for post-render reactive updates.
|
|
363
|
+
if (isTraceEnabled() && !isDevtoolsEnabled()) closeTrace();
|
|
364
|
+
if (isDevtoolsEnabled()) {
|
|
365
|
+
void waitForSignal();
|
|
366
|
+
}
|
|
367
|
+
return output;
|
|
200
368
|
}
|
|
201
369
|
|
|
202
370
|
/**
|
|
@@ -207,23 +375,20 @@ export async function renderAsync(
|
|
|
207
375
|
children: Children,
|
|
208
376
|
options?: PrintTreeOptions,
|
|
209
377
|
): Promise<OutputDirectory> {
|
|
378
|
+
await debug.prepare();
|
|
210
379
|
const tree = renderTree(children);
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Convert a rendered text tree to source directories and files. Will ensure that
|
|
216
|
-
* all scheduled jobs are completed, including async ones.
|
|
217
|
-
*/
|
|
218
|
-
export async function sourceFilesForTreeAsync(
|
|
219
|
-
tree: RenderedTextTree,
|
|
220
|
-
options?: PrintTreeOptions,
|
|
221
|
-
) {
|
|
222
|
-
// if we await here, we ensure all reactive updates are flushed.
|
|
223
|
-
// sourceFilesForTree will flush again, but won't find anything, because tree
|
|
224
|
-
// printing won't schedule anything.
|
|
380
|
+
// Ensure all reactive updates are flushed before printing.
|
|
225
381
|
await flushJobsAsync();
|
|
226
|
-
|
|
382
|
+
const output = sourceFilesForTree(tree, options);
|
|
383
|
+
flushDirtyFiles();
|
|
384
|
+
reportDiagnosticsForTree(tree);
|
|
385
|
+
reportLastRenderError();
|
|
386
|
+
debug.render.complete();
|
|
387
|
+
// Only close the trace DB when devtools is NOT running. When devtools is
|
|
388
|
+
// active the DB must remain open for post-render reactive updates.
|
|
389
|
+
if (isTraceEnabled() && !isDevtoolsEnabled()) closeTrace();
|
|
390
|
+
|
|
391
|
+
return output;
|
|
227
392
|
}
|
|
228
393
|
|
|
229
394
|
/**
|
|
@@ -239,9 +404,12 @@ export function sourceFilesForTree(
|
|
|
239
404
|
collectSourceFiles(undefined, tree);
|
|
240
405
|
|
|
241
406
|
if (!rootDirectory) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
407
|
+
emitDiagnostic({
|
|
408
|
+
severity: "error",
|
|
409
|
+
message:
|
|
410
|
+
"No root directory found. Make sure you are using the output component.",
|
|
411
|
+
});
|
|
412
|
+
return { kind: "directory", path: "", contents: [] };
|
|
245
413
|
}
|
|
246
414
|
|
|
247
415
|
return rootDirectory;
|
|
@@ -325,25 +493,41 @@ export function sourceFilesForTree(
|
|
|
325
493
|
}
|
|
326
494
|
export function renderTree(children: Children) {
|
|
327
495
|
const rootElem: RenderedTextTree = [];
|
|
496
|
+
const diagnostics = new DiagnosticsCollector();
|
|
497
|
+
lastRenderError = null;
|
|
498
|
+
debug.effect.reset();
|
|
499
|
+
debug.symbols.reset();
|
|
500
|
+
debug.files.reset();
|
|
501
|
+
dirtyFiles.clear();
|
|
502
|
+
lastFlushTimeByFile.clear();
|
|
503
|
+
debug.render.initialize(rootElem);
|
|
504
|
+
if (isTraceEnabled()) beginTransaction();
|
|
328
505
|
try {
|
|
329
506
|
root(() => {
|
|
507
|
+
attachDiagnosticsCollector(diagnostics);
|
|
330
508
|
renderWorker(rootElem, children);
|
|
331
509
|
});
|
|
332
510
|
} catch (e) {
|
|
333
|
-
|
|
511
|
+
if (isTraceEnabled()) commitTransaction();
|
|
512
|
+
flushDirtyFiles();
|
|
513
|
+
notifyRenderError(e);
|
|
514
|
+
reportLastRenderError();
|
|
334
515
|
throw e;
|
|
335
516
|
}
|
|
517
|
+
if (isTraceEnabled()) commitTransaction();
|
|
518
|
+
|
|
519
|
+
diagnosticsByTree.set(rootElem, diagnostics);
|
|
336
520
|
|
|
337
521
|
return rootElem;
|
|
338
522
|
}
|
|
339
523
|
|
|
340
524
|
function renderWorker(node: RenderedTextTree, children: Children) {
|
|
525
|
+
if (lastRenderError) return;
|
|
341
526
|
if (!getContext()) {
|
|
342
527
|
throw new Error(
|
|
343
528
|
"Cannot render without a context. Make sure you are using the Output component.",
|
|
344
529
|
);
|
|
345
530
|
}
|
|
346
|
-
trace(TracePhase.render.worker, () => dumpChildren(children));
|
|
347
531
|
|
|
348
532
|
if (Array.isArray(node)) {
|
|
349
533
|
nodesToContext.set(node, getContext()!);
|
|
@@ -352,6 +536,7 @@ function renderWorker(node: RenderedTextTree, children: Children) {
|
|
|
352
536
|
if (Array.isArray(children)) {
|
|
353
537
|
for (const child of (children as any).flat(Infinity)) {
|
|
354
538
|
appendChild(node, child);
|
|
539
|
+
if (lastRenderError) break;
|
|
355
540
|
}
|
|
356
541
|
} else {
|
|
357
542
|
appendChild(node, children);
|
|
@@ -368,11 +553,12 @@ export function notifyContentState() {
|
|
|
368
553
|
const startContext = getContext()!;
|
|
369
554
|
|
|
370
555
|
if (startContext.childrenWithContent === 0) {
|
|
371
|
-
if (startContext.
|
|
556
|
+
if (startContext._lastEmpty) {
|
|
372
557
|
// it was already empty, no work to do.
|
|
373
558
|
return;
|
|
374
559
|
}
|
|
375
560
|
|
|
561
|
+
startContext._lastEmpty = true;
|
|
376
562
|
if (startContext.isEmpty) {
|
|
377
563
|
startContext.isEmpty.value = true;
|
|
378
564
|
}
|
|
@@ -384,18 +570,24 @@ export function notifyContentState() {
|
|
|
384
570
|
break;
|
|
385
571
|
}
|
|
386
572
|
current.childrenWithContent--;
|
|
573
|
+
if (current.childrenWithContent > 0) {
|
|
574
|
+
// This isn't the last content so we have no work to do
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
current._lastEmpty = true;
|
|
387
578
|
if (current.isEmpty) {
|
|
388
579
|
current.isEmpty.value = true;
|
|
389
580
|
}
|
|
390
581
|
current = current.owner;
|
|
391
582
|
}
|
|
392
583
|
} else {
|
|
393
|
-
if (startContext.
|
|
584
|
+
if (!startContext._lastEmpty) {
|
|
394
585
|
// it was already non-empty, no work to do.
|
|
395
586
|
return;
|
|
396
587
|
}
|
|
397
588
|
|
|
398
|
-
|
|
589
|
+
startContext._lastEmpty = false;
|
|
590
|
+
if (startContext.isEmpty) {
|
|
399
591
|
startContext.isEmpty.value = false;
|
|
400
592
|
}
|
|
401
593
|
|
|
@@ -408,7 +600,8 @@ export function notifyContentState() {
|
|
|
408
600
|
break;
|
|
409
601
|
}
|
|
410
602
|
|
|
411
|
-
|
|
603
|
+
current._lastEmpty = false;
|
|
604
|
+
if (current.isEmpty) {
|
|
412
605
|
current.isEmpty.value = false;
|
|
413
606
|
}
|
|
414
607
|
|
|
@@ -419,95 +612,120 @@ export function notifyContentState() {
|
|
|
419
612
|
}
|
|
420
613
|
|
|
421
614
|
function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
422
|
-
|
|
615
|
+
if (lastRenderError) return;
|
|
423
616
|
const child = normalizeChild(rawChild);
|
|
424
617
|
|
|
425
618
|
if (typeof child === "string") {
|
|
426
619
|
if (child !== "") {
|
|
427
620
|
contentAdded();
|
|
621
|
+
debug.render.appendTextNode(node, node.length, child);
|
|
428
622
|
}
|
|
429
623
|
node.push(child);
|
|
430
624
|
} else {
|
|
431
625
|
const cache = getElementCache();
|
|
432
626
|
if (cache.has(child as any)) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
627
|
+
const cachedNode = cache.get(child as any)!;
|
|
628
|
+
// recordSubtreeAdded detects cached nodes automatically and re-adds their children
|
|
629
|
+
if (isCustomContext(child)) {
|
|
630
|
+
debug.render.appendCustomContext(node, cachedNode);
|
|
631
|
+
} else {
|
|
632
|
+
debug.render.appendFragmentChild(node, cachedNode);
|
|
633
|
+
}
|
|
634
|
+
node.push(cachedNode);
|
|
438
635
|
return;
|
|
439
636
|
}
|
|
440
637
|
if (isCustomContext(child)) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
() => "CustomContext: " + debugPrintChild(child),
|
|
444
|
-
);
|
|
638
|
+
const newNode: RenderedTextTree = [];
|
|
639
|
+
debug.render.appendCustomContext(node, newNode);
|
|
445
640
|
child.useCustomContext((children) => {
|
|
446
|
-
const newNode: RenderedTextTree = [];
|
|
447
641
|
renderWorker(newNode, children);
|
|
448
642
|
node.push(newNode);
|
|
449
643
|
cache.set(child, newNode);
|
|
450
644
|
notifyContentState();
|
|
645
|
+
notifyFileUpdateForNode(node);
|
|
451
646
|
});
|
|
452
647
|
} else if (isIntrinsicElement(child)) {
|
|
453
|
-
trace(
|
|
454
|
-
TracePhase.render.appendChild,
|
|
455
|
-
() => "IntrinsicElement: " + debugPrintChild(child),
|
|
456
|
-
);
|
|
457
648
|
// don't need a new context here because intrinsics are never reactive
|
|
649
|
+
const intrinsic = child as IntrinsicElement;
|
|
458
650
|
const newNode: RenderedTextTree = [];
|
|
459
651
|
|
|
460
652
|
function formatHookWithChildren(command: (doc: Doc) => Doc) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
print(tree
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
653
|
+
const hook = createRenderTreeHook(newNode, {
|
|
654
|
+
print(tree, print) {
|
|
655
|
+
return command(print(tree));
|
|
656
|
+
},
|
|
657
|
+
});
|
|
658
|
+
debug.render.appendPrintHook(
|
|
659
|
+
node,
|
|
660
|
+
node.length,
|
|
661
|
+
hook,
|
|
662
|
+
intrinsic.name,
|
|
663
|
+
newNode,
|
|
467
664
|
);
|
|
665
|
+
node.push(hook);
|
|
468
666
|
renderWorker(newNode, (child as any).props.children);
|
|
667
|
+
notifyFileUpdateForNode(node);
|
|
469
668
|
}
|
|
470
669
|
|
|
471
670
|
function formatHook(command: Doc) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
);
|
|
671
|
+
const hook = createRenderTreeHook(newNode, {
|
|
672
|
+
print() {
|
|
673
|
+
return command;
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
debug.render.appendPrintHook(node, node.length, hook, intrinsic.name);
|
|
677
|
+
node.push(hook);
|
|
678
|
+
return hook;
|
|
479
679
|
}
|
|
480
680
|
|
|
481
681
|
switch (child.name) {
|
|
482
682
|
case "indent":
|
|
483
683
|
return formatHookWithChildren(indent);
|
|
484
684
|
case "indentIfBreak":
|
|
485
|
-
|
|
486
|
-
createRenderTreeHook(newNode, {
|
|
685
|
+
{
|
|
686
|
+
const hook = createRenderTreeHook(newNode, {
|
|
487
687
|
print(tree, print) {
|
|
488
688
|
return indentIfBreak(print(tree), {
|
|
489
689
|
groupId: child.props.groupId,
|
|
490
690
|
negate: child.props.negate,
|
|
491
691
|
});
|
|
492
692
|
},
|
|
493
|
-
})
|
|
494
|
-
|
|
693
|
+
});
|
|
694
|
+
debug.render.appendPrintHook(
|
|
695
|
+
node,
|
|
696
|
+
node.length,
|
|
697
|
+
hook,
|
|
698
|
+
intrinsic.name,
|
|
699
|
+
newNode,
|
|
700
|
+
);
|
|
701
|
+
node.push(hook);
|
|
702
|
+
}
|
|
495
703
|
renderWorker(newNode, child.props.children);
|
|
704
|
+
notifyFileUpdateForNode(node);
|
|
496
705
|
return;
|
|
497
706
|
case "fill":
|
|
498
707
|
return formatHookWithChildren(fill as any);
|
|
499
708
|
case "group":
|
|
500
|
-
|
|
501
|
-
createRenderTreeHook(newNode, {
|
|
709
|
+
{
|
|
710
|
+
const hook = createRenderTreeHook(newNode, {
|
|
502
711
|
print(tree, print) {
|
|
503
712
|
return group(print(tree), {
|
|
504
713
|
id: child.props.id,
|
|
505
714
|
shouldBreak: child.props.shouldBreak,
|
|
506
715
|
});
|
|
507
716
|
},
|
|
508
|
-
})
|
|
509
|
-
|
|
717
|
+
});
|
|
718
|
+
debug.render.appendPrintHook(
|
|
719
|
+
node,
|
|
720
|
+
node.length,
|
|
721
|
+
hook,
|
|
722
|
+
intrinsic.name,
|
|
723
|
+
newNode,
|
|
724
|
+
);
|
|
725
|
+
node.push(hook);
|
|
726
|
+
}
|
|
510
727
|
renderWorker(newNode, child.props.children);
|
|
728
|
+
notifyFileUpdateForNode(node);
|
|
511
729
|
return;
|
|
512
730
|
case "line":
|
|
513
731
|
case "br":
|
|
@@ -522,17 +740,26 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
522
740
|
case "lbr":
|
|
523
741
|
return formatHook(literalline);
|
|
524
742
|
case "align":
|
|
525
|
-
|
|
526
|
-
createRenderTreeHook(newNode, {
|
|
743
|
+
{
|
|
744
|
+
const hook = createRenderTreeHook(newNode, {
|
|
527
745
|
print(tree, print) {
|
|
528
746
|
return align(
|
|
529
747
|
(child.props as any).width ?? (child.props as any).string!,
|
|
530
748
|
print(tree),
|
|
531
749
|
);
|
|
532
750
|
},
|
|
533
|
-
})
|
|
534
|
-
|
|
751
|
+
});
|
|
752
|
+
debug.render.appendPrintHook(
|
|
753
|
+
node,
|
|
754
|
+
node.length,
|
|
755
|
+
hook,
|
|
756
|
+
intrinsic.name,
|
|
757
|
+
newNode,
|
|
758
|
+
);
|
|
759
|
+
node.push(hook);
|
|
760
|
+
}
|
|
535
761
|
renderWorker(newNode, (child as any).props.children);
|
|
762
|
+
notifyFileUpdateForNode(node);
|
|
536
763
|
return;
|
|
537
764
|
case "lineSuffix":
|
|
538
765
|
return formatHookWithChildren(lineSuffix);
|
|
@@ -547,17 +774,33 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
547
774
|
case "markAsRoot":
|
|
548
775
|
return formatHookWithChildren(markAsRoot);
|
|
549
776
|
case "ifBreak":
|
|
550
|
-
|
|
551
|
-
createRenderTreeHook(newNode, {
|
|
777
|
+
{
|
|
778
|
+
const hook = createRenderTreeHook(newNode, {
|
|
552
779
|
print(tree, print) {
|
|
553
780
|
return ifBreak(
|
|
554
781
|
print((tree as RenderedTextTree[])[0]),
|
|
555
782
|
print((tree as RenderedTextTree[])[1]),
|
|
556
783
|
);
|
|
557
784
|
},
|
|
558
|
-
})
|
|
559
|
-
|
|
785
|
+
});
|
|
786
|
+
debug.render.appendPrintHook(
|
|
787
|
+
node,
|
|
788
|
+
node.length,
|
|
789
|
+
hook,
|
|
790
|
+
intrinsic.name,
|
|
791
|
+
newNode,
|
|
792
|
+
);
|
|
793
|
+
node.push(hook);
|
|
794
|
+
}
|
|
560
795
|
newNode.push([], []);
|
|
796
|
+
debug.render.appendFragmentChild(
|
|
797
|
+
newNode,
|
|
798
|
+
newNode[0] as RenderedTextTree,
|
|
799
|
+
);
|
|
800
|
+
debug.render.appendFragmentChild(
|
|
801
|
+
newNode,
|
|
802
|
+
newNode[1] as RenderedTextTree,
|
|
803
|
+
);
|
|
561
804
|
renderWorker(
|
|
562
805
|
newNode[0] as RenderedTextTree[],
|
|
563
806
|
(child as any).props.children,
|
|
@@ -566,66 +809,223 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
|
|
|
566
809
|
newNode[1] as RenderedTextTree[],
|
|
567
810
|
(child as any).props.flatContents,
|
|
568
811
|
);
|
|
812
|
+
notifyFileUpdateForNode(node);
|
|
569
813
|
return;
|
|
570
814
|
default:
|
|
571
815
|
throw new Error("Unknown intrinsic element");
|
|
572
816
|
}
|
|
573
817
|
} else if (isComponentCreator(child)) {
|
|
818
|
+
const index = node.length;
|
|
819
|
+
const rerenderToken =
|
|
820
|
+
isDevtoolsEnabled() ? ref(0, { isInfrastructure: true }) : undefined;
|
|
821
|
+
const breakNext =
|
|
822
|
+
isDevtoolsEnabled() ?
|
|
823
|
+
ref(false, { isInfrastructure: true })
|
|
824
|
+
: undefined;
|
|
574
825
|
// todo: remove this effect (only needed for context, not needed for anything else)
|
|
575
|
-
effect(
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
826
|
+
effect(
|
|
827
|
+
() => {
|
|
828
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
829
|
+
rerenderToken?.value;
|
|
830
|
+
const context = getContext();
|
|
831
|
+
context!.childrenWithContent = 0;
|
|
832
|
+
|
|
833
|
+
if (context) context.componentOwner = child;
|
|
834
|
+
const existing = node[index];
|
|
835
|
+
const componentRoot: RenderedTextTree =
|
|
836
|
+
Array.isArray(existing) ? existing : [];
|
|
837
|
+
context!.meta ??= {};
|
|
838
|
+
context!.meta.renderNode = componentRoot;
|
|
839
|
+
const propsSource = (child.props ?? undefined) as
|
|
840
|
+
| Record<string, unknown>
|
|
841
|
+
| undefined;
|
|
842
|
+
const debugSession = debug.render.beginComponent({
|
|
843
|
+
parent: node,
|
|
844
|
+
index,
|
|
845
|
+
node: componentRoot,
|
|
846
|
+
component: child,
|
|
847
|
+
propsSource,
|
|
848
|
+
source: child.source,
|
|
849
|
+
isExisting: Array.isArray(existing),
|
|
850
|
+
actions: {
|
|
851
|
+
rerender:
|
|
852
|
+
rerenderToken ?
|
|
853
|
+
() => {
|
|
854
|
+
lastRenderError = null;
|
|
855
|
+
rerenderToken.value++;
|
|
856
|
+
}
|
|
857
|
+
: () => {},
|
|
858
|
+
rerenderAndBreak:
|
|
859
|
+
breakNext && rerenderToken ?
|
|
860
|
+
() => {
|
|
861
|
+
lastRenderError = null;
|
|
862
|
+
breakNext.value = true;
|
|
863
|
+
rerenderToken.value++;
|
|
864
|
+
}
|
|
865
|
+
: () => {},
|
|
866
|
+
},
|
|
867
|
+
});
|
|
868
|
+
if (Array.isArray(existing)) {
|
|
869
|
+
componentRoot.length = 0;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
pushStack(child.component, child.props, child.source);
|
|
873
|
+
let renderFailed = false;
|
|
874
|
+
let childResult: Children | undefined;
|
|
875
|
+
try {
|
|
876
|
+
childResult = untrack(() => {
|
|
877
|
+
const shouldBreak = breakNext?.value ?? false;
|
|
878
|
+
if (shouldBreak) {
|
|
879
|
+
breakNext!.value = false;
|
|
880
|
+
// eslint-disable-next-line no-debugger
|
|
881
|
+
debugger;
|
|
882
|
+
}
|
|
883
|
+
return child();
|
|
884
|
+
});
|
|
885
|
+
} catch (error) {
|
|
886
|
+
notifyRenderError(error);
|
|
887
|
+
renderFailed = true;
|
|
888
|
+
throw error;
|
|
889
|
+
}
|
|
890
|
+
try {
|
|
891
|
+
if (context?.meta?.directory) {
|
|
892
|
+
debugSession.recordDirectory(context.meta.directory.path);
|
|
893
|
+
}
|
|
894
|
+
if (context?.meta?.sourceFile) {
|
|
895
|
+
context.meta.renderNode = componentRoot;
|
|
896
|
+
debugSession.recordFile(
|
|
897
|
+
context.meta.sourceFile.path,
|
|
898
|
+
context.meta.sourceFile.filetype,
|
|
899
|
+
);
|
|
900
|
+
context.meta.sourceFileReady = false;
|
|
901
|
+
}
|
|
902
|
+
if (!renderFailed) {
|
|
903
|
+
renderWorker(componentRoot, childResult);
|
|
904
|
+
}
|
|
905
|
+
} finally {
|
|
906
|
+
popStack();
|
|
907
|
+
}
|
|
908
|
+
if (renderFailed) {
|
|
909
|
+
node[index] = componentRoot;
|
|
910
|
+
cache.set(child, componentRoot);
|
|
911
|
+
notifyFileUpdateForNode(node);
|
|
912
|
+
notifyContentState();
|
|
913
|
+
onCleanup(() => debugSession.dispose());
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
if (context?.meta?.sourceFile) {
|
|
917
|
+
context.meta.sourceFileReady = true;
|
|
918
|
+
notifyFileUpdateForNode(componentRoot);
|
|
919
|
+
}
|
|
920
|
+
node[index] = componentRoot;
|
|
921
|
+
cache.set(child, componentRoot);
|
|
922
|
+
notifyContentState();
|
|
923
|
+
onCleanup(() => debugSession.dispose());
|
|
924
|
+
},
|
|
925
|
+
undefined,
|
|
926
|
+
{
|
|
927
|
+
debug: {
|
|
928
|
+
name: `render:${child.component.name || "Anonymous"}`,
|
|
929
|
+
type: "render",
|
|
930
|
+
},
|
|
931
|
+
},
|
|
932
|
+
);
|
|
602
933
|
} else if (typeof child === "function") {
|
|
603
|
-
trace(TracePhase.render.appendChild, () => "Memo: " + child.toString());
|
|
604
934
|
const index = node.length;
|
|
605
|
-
effect(
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
935
|
+
effect(
|
|
936
|
+
() => {
|
|
937
|
+
let res: Child | Children | undefined;
|
|
938
|
+
let renderFailed = false;
|
|
939
|
+
try {
|
|
940
|
+
res = child();
|
|
941
|
+
while (typeof res === "function" && !isComponentCreator(res)) {
|
|
942
|
+
res = res();
|
|
943
|
+
}
|
|
944
|
+
} catch (error) {
|
|
945
|
+
notifyRenderError(error);
|
|
946
|
+
renderFailed = true;
|
|
947
|
+
throw error;
|
|
948
|
+
}
|
|
949
|
+
const context = getContext();
|
|
950
|
+
context!.childrenWithContent = 0;
|
|
951
|
+
|
|
952
|
+
const existing = node[index];
|
|
953
|
+
const memoNode: RenderedTextTree =
|
|
954
|
+
Array.isArray(existing) ? existing : [];
|
|
955
|
+
|
|
956
|
+
debug.render.prepareMemoNode(node, memoNode, Array.isArray(existing));
|
|
957
|
+
if (Array.isArray(existing)) {
|
|
958
|
+
memoNode.length = 0;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if (!renderFailed) {
|
|
962
|
+
renderWorker(memoNode, res);
|
|
963
|
+
}
|
|
964
|
+
node[index] = memoNode;
|
|
965
|
+
cache.set(child, memoNode);
|
|
966
|
+
notifyFileUpdateForNode(node);
|
|
967
|
+
notifyContentState();
|
|
968
|
+
return memoNode;
|
|
969
|
+
},
|
|
970
|
+
undefined,
|
|
971
|
+
{
|
|
972
|
+
debug: {
|
|
973
|
+
name: `render:memo:${child.name || "anonymous"}`,
|
|
974
|
+
type: "render",
|
|
975
|
+
},
|
|
976
|
+
},
|
|
977
|
+
);
|
|
623
978
|
} else {
|
|
624
979
|
throw new Error("Unexpected child type");
|
|
625
980
|
}
|
|
626
981
|
}
|
|
627
982
|
}
|
|
628
983
|
|
|
984
|
+
function findSourceFileContext(node: RenderedTextTree) {
|
|
985
|
+
let context: Context | null | undefined =
|
|
986
|
+
getContextForRenderNode(node) ?? null;
|
|
987
|
+
while (context) {
|
|
988
|
+
if (context.meta?.sourceFile) return context;
|
|
989
|
+
context = context.owner;
|
|
990
|
+
}
|
|
991
|
+
return undefined;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
function notifyFileUpdateForNode(node: RenderedTextTree) {
|
|
995
|
+
// Only track when devtools or trace are actually enabled
|
|
996
|
+
if (!isDevtoolsEnabled() && !isTraceEnabled()) return;
|
|
997
|
+
const context = findSourceFileContext(node);
|
|
998
|
+
if (!context?.meta?.sourceFile) return;
|
|
999
|
+
if (context.meta.sourceFileReady === false) return;
|
|
1000
|
+
const sourceFile = context.meta.sourceFile;
|
|
1001
|
+
const renderNode: RenderedTextTree =
|
|
1002
|
+
(context.meta.renderNode as RenderedTextTree | undefined) ?? node;
|
|
1003
|
+
|
|
1004
|
+
// Mark this file as dirty — defer the expensive printTree to end of render
|
|
1005
|
+
dirtyFiles.set(sourceFile.path, {
|
|
1006
|
+
renderNode,
|
|
1007
|
+
printOptions: {
|
|
1008
|
+
printWidth: context.meta?.printOptions?.printWidth,
|
|
1009
|
+
tabWidth: context.meta?.printOptions?.tabWidth,
|
|
1010
|
+
useTabs: context.meta?.printOptions?.useTabs,
|
|
1011
|
+
insertFinalNewLine: context.meta?.printOptions?.insertFinalNewLine,
|
|
1012
|
+
},
|
|
1013
|
+
path: sourceFile.path,
|
|
1014
|
+
filetype: sourceFile.filetype,
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
// When a devtools client is connected, throttle file flushing to ~1s per file
|
|
1018
|
+
// so the user can watch content build up during rendering.
|
|
1019
|
+
if (isDevtoolsConnected()) {
|
|
1020
|
+
const now = Date.now();
|
|
1021
|
+
const lastFlush = lastFlushTimeByFile.get(sourceFile.path) ?? 0;
|
|
1022
|
+
if (now - lastFlush >= DEVTOOLS_FLUSH_INTERVAL_MS) {
|
|
1023
|
+
lastFlushTimeByFile.set(sourceFile.path, now);
|
|
1024
|
+
flushDirtyFile(sourceFile.path);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
629
1029
|
type NormalizedChildren = NormalizedChild | NormalizedChildren[];
|
|
630
1030
|
type NormalizedChild =
|
|
631
1031
|
| string
|
|
@@ -668,31 +1068,6 @@ function normalizeChild(child: Child): NormalizedChildren {
|
|
|
668
1068
|
}
|
|
669
1069
|
}
|
|
670
1070
|
|
|
671
|
-
function dumpChildren(children: Children): string {
|
|
672
|
-
if (Array.isArray(children)) {
|
|
673
|
-
return `[ ${children.map(debugPrintChild).join(", ")} ]`;
|
|
674
|
-
}
|
|
675
|
-
return debugPrintChild(children);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
function debugPrintChild(child: Children): string {
|
|
679
|
-
if (isComponentCreator(child)) {
|
|
680
|
-
return "<" + child.component.name + ">";
|
|
681
|
-
} else if (typeof child === "function") {
|
|
682
|
-
return "$memo";
|
|
683
|
-
} else if (isRef(child)) {
|
|
684
|
-
return "$ref";
|
|
685
|
-
} else if (isIntrinsicElement(child)) {
|
|
686
|
-
return `<${child.name}>`;
|
|
687
|
-
} else if (isRenderableObject(child)) {
|
|
688
|
-
return `CustomChildElement(${JSON.stringify(child)})`;
|
|
689
|
-
} else if (isRefkeyable(child)) {
|
|
690
|
-
return `refkey`;
|
|
691
|
-
} else {
|
|
692
|
-
return JSON.stringify(child);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
1071
|
export interface PrintTreeOptions {
|
|
697
1072
|
/**
|
|
698
1073
|
* The number of characters the printer will wrap on. Defaults to 100
|
|
@@ -715,6 +1090,12 @@ export interface PrintTreeOptions {
|
|
|
715
1090
|
* @default true
|
|
716
1091
|
*/
|
|
717
1092
|
insertFinalNewLine?: boolean;
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Skip flushing scheduled jobs before printing.
|
|
1096
|
+
* @default false
|
|
1097
|
+
*/
|
|
1098
|
+
noFlush?: boolean;
|
|
718
1099
|
}
|
|
719
1100
|
|
|
720
1101
|
const defaultPrintTreeOptions: PrintTreeOptions = {
|
|
@@ -734,8 +1115,10 @@ export function printTree(tree: RenderedTextTree, options?: PrintTreeOptions) {
|
|
|
734
1115
|
),
|
|
735
1116
|
};
|
|
736
1117
|
|
|
737
|
-
|
|
738
|
-
|
|
1118
|
+
if (!options.noFlush) {
|
|
1119
|
+
// make sure queue is empty
|
|
1120
|
+
flushJobs();
|
|
1121
|
+
}
|
|
739
1122
|
|
|
740
1123
|
const d = printTreeWorker(tree);
|
|
741
1124
|
const result = doc.printer.printDocToString(
|