Implement disposeFiber for fiber tree disposal

Add disposeFiber() function that performs bottom-up teardown of fiber
subtrees: recursively disposes children before parents, calls
host.finalizeInstance for per-instance cleanup, invokes signal disposers,
and clears fiber state. Idempotent via disposed flag. Does NOT call
host.removeChild (that's the commit phase's job).

- Add disposeFiber + HostLike to src/host/fiber.ts
- Add finalizeInstance to HostConfig interface
- Add disposed boolean to Fiber interface
- Export disposeFiber and HostLike from barrel
- Add 7 tests for disposeFiber (3-level tree, idempotency, signal cleanup, etc.)
This commit is contained in:
2026-05-18 17:22:05 +00:00
parent 1e0abb0900
commit 95995f4602
7 changed files with 279 additions and 3 deletions

View File

@@ -30,6 +30,7 @@ export interface HostConfig<TTag extends string, Instance, RootCtx> {
ctx: RootCtx,
): void;
emit?(type: string, id: string, payload: unknown): void;
finalizeInstance?(instance: Instance, ctx: RootCtx): void;
}
export interface Root<TTag extends string, Instance, RootCtx> {
@@ -70,6 +71,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
effect: null,
signalDisposers: [],
prevProps: null,
disposed: false,
};
if (parentFiber) parentFiber.children.push(fiber);
return fiber;
@@ -106,6 +108,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
effect: null,
signalDisposers: [],
prevProps: null,
disposed: false,
};
for (const child of el.children) {
@@ -132,6 +135,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
effect: null,
signalDisposers: [],
prevProps: null,
disposed: false,
};
}
@@ -158,6 +162,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
effect: null,
signalDisposers: [],
prevProps: null,
disposed: false,
};
for (const child of el.children) {
@@ -281,6 +286,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
effect: null,
signalDisposers: [],
prevProps: null,
disposed: false,
};
const payloadChildren = isURoot(node) ? (node as URoot).children : [node];
for (const child of payloadChildren) {