@abide/abide 0.52.0 → 0.53.0
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/AGENTS.md +16 -7
- package/CHANGELOG.md +25 -0
- package/README.md +7 -5
- package/package.json +2 -1
- package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +1 -0
- package/src/lib/ui/compile/analyzeComponent.ts +2 -0
- package/src/lib/ui/compile/compileComponent.ts +3 -1
- package/src/lib/ui/compile/compileSSR.ts +12 -0
- package/src/lib/ui/compile/compileShadow.ts +37 -34
- package/src/lib/ui/compile/desugarSignals.ts +60 -32
- package/src/lib/ui/compile/generateBuild.ts +5 -1
- package/src/lib/ui/compile/hasTopLevelAwait.ts +28 -0
- package/src/lib/ui/compile/isFunctionScopeBoundary.ts +20 -0
- package/src/lib/ui/compile/liftAsyncSubExpressions.ts +2 -2
- package/src/lib/ui/compile/lowerContext.ts +4 -0
- package/src/lib/ui/compile/lowerScript.ts +11 -1
- package/src/lib/ui/compile/renameSignalRefs.ts +18 -0
- package/src/lib/ui/compile/types/AnalyzedComponent.ts +4 -0
- package/src/lib/ui/dom/appendText.ts +29 -8
- package/src/lib/ui/dom/appendTextAt.ts +21 -4
- package/src/lib/ui/dom/attr.ts +16 -1
- package/src/lib/ui/dom/awaitBlock.ts +34 -13
- package/src/lib/ui/dom/each.ts +10 -2
- package/src/lib/ui/dom/eachAsync.ts +9 -1
- package/src/lib/ui/dom/readCellBlocking.ts +29 -0
- package/src/lib/ui/dom/readTextOrSuspend.ts +21 -0
- package/src/lib/ui/dom/spreadAttrs.ts +47 -1
- package/src/lib/ui/dom/switchBlock.ts +19 -2
- package/src/lib/ui/dom/tryBlock.ts +10 -0
- package/src/lib/ui/dom/when.ts +19 -1
- package/src/lib/ui/dom/withSuspense.ts +22 -0
- package/src/lib/ui/runtime/SuspenseSignal.ts +24 -0
- package/src/lib/ui/runtime/flushEffects.ts +18 -10
- package/src/lib/ui/watch.ts +7 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { boundaryFor } from './boundaryFor.ts'
|
|
2
2
|
import { NODE_STATE } from './NODE_STATE.ts'
|
|
3
3
|
import { REACTIVE_CONTEXT } from './REACTIVE_CONTEXT.ts'
|
|
4
|
+
import { SuspenseSignal } from './SuspenseSignal.ts'
|
|
4
5
|
import type { ReactiveNode } from './types/ReactiveNode.ts'
|
|
5
6
|
import { updateIfNecessary } from './updateIfNecessary.ts'
|
|
6
7
|
|
|
@@ -50,16 +51,23 @@ function drain(): void {
|
|
|
50
51
|
try {
|
|
51
52
|
updateIfNecessary(node)
|
|
52
53
|
} catch (error) {
|
|
53
|
-
/* A
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
it
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
/* A `SuspenseSignal` is "no value yet", not an error, and must NEVER route to a
|
|
55
|
+
reactive `{#try}` (that would flash the author's `{:catch}` during loading,
|
|
56
|
+
ADR-0042 D3). Every reading region catches its own suspend locally and re-runs on
|
|
57
|
+
settle (the throwing read subscribed its cell), so a `SuspenseSignal` reaches here
|
|
58
|
+
only if it escaped an unguarded read — surface it via the error collector below
|
|
59
|
+
rather than leaking it to a boundary. A normal error routes to the node's nearest
|
|
60
|
+
`{#try}` boundary: swap the guarded content to the catch branch instead of the
|
|
61
|
+
rethrow fallback — the "later re-run throw" the sync boundary could not catch.
|
|
62
|
+
Reset it CLEAN either way so a later write to its deps can re-queue it (otherwise
|
|
63
|
+
`mark`'s CLEAN→dirty gate leaves it permanently inert). */
|
|
64
|
+
if (!(error instanceof SuspenseSignal)) {
|
|
65
|
+
const boundary = boundaryFor.get(node)
|
|
66
|
+
if (boundary !== undefined) {
|
|
67
|
+
boundary.handle(error)
|
|
68
|
+
node.status = NODE_STATE.CLEAN
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
63
71
|
}
|
|
64
72
|
/* No boundary — one effect throwing must not strand the effects queued behind
|
|
65
73
|
it (they live in this same `batch`, unreachable once we swap
|
package/src/lib/ui/watch.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { REMOTE_FUNCTION } from '../shared/REMOTE_FUNCTION.ts'
|
|
|
3
3
|
import type { CacheOnContext } from '../shared/types/CacheOnContext.ts'
|
|
4
4
|
import type { NamedAsyncIterable } from '../shared/types/NamedAsyncIterable.ts'
|
|
5
5
|
import type { RemoteFunction } from '../shared/types/RemoteFunction.ts'
|
|
6
|
+
import { withSuspense } from './dom/withSuspense.ts'
|
|
6
7
|
import { effect } from './effect.ts'
|
|
7
8
|
import { generationGuard } from './runtime/generationGuard.ts'
|
|
8
9
|
import type { EffectResult } from './runtime/types/EffectResult.ts'
|
|
@@ -61,9 +62,13 @@ export function watch(
|
|
|
61
62
|
also silence the compiler's generated bindings, which build on the client where the test
|
|
62
63
|
DOM sets no global `window`). SSR-safety comes from the compiler stripping author
|
|
63
64
|
`watch(...)` calls, and the subscribable branch's own server guard (cache.on). */
|
|
64
|
-
/* Compiler binding form watch(thunk): a bare auto-tracked effect (== today's $$effect).
|
|
65
|
+
/* Compiler binding form watch(thunk): a bare auto-tracked effect (== today's $$effect). A
|
|
66
|
+
pending blocking `await` read throws a `SuspenseSignal` (ADR-0042) — withhold this reaction
|
|
67
|
+
(e.g. leave a `class:`/`style:` binding untouched) until the value resolves; the read tracked
|
|
68
|
+
its cell, so the effect re-runs on settle. Rethrows any real error. */
|
|
65
69
|
if (argsOrHandler === undefined) {
|
|
66
|
-
|
|
70
|
+
const thunk = source as () => EffectResult
|
|
71
|
+
return effect(() => withSuspense<EffectResult>(thunk, undefined))
|
|
67
72
|
}
|
|
68
73
|
/* watch(fn, args, handler): an rpc selector with explicit args. */
|
|
69
74
|
if (maybeHandler !== undefined) {
|