UNPKG

@virtualstate/examples

Version:
124 lines 4.66 kB
import { h } from "@virtualstate/examples"; import { ChildrenSource, createNode, isScalarVNode } from "@virtualstate/fringe"; import { readAllDrain } from "./read.js"; /** * @experimental */ export const IsStaticSymbol = Symbol("Is Static"); /** * @experimental */ export class Static { #weakTree = new WeakMap(); #referenceTree = new Map(); #sourceTree = new Map(); #weakChildrenRecording = new WeakMap(); #weakChildrenRecordingInProgress = new WeakSet(); #state = createNode(); #options = {}; constructor(options, state) { this.#state = state; this.#options = options; } async *[Symbol.asyncIterator]() { const weakTree = this.#weakTree; const referenceTree = this.#referenceTree; const sourceTree = this.#sourceTree; const weakChildrenRecording = this.#weakChildrenRecording; const weakChildrenRecordingInProgress = this.#weakChildrenRecordingInProgress; const options = this.#options; yield mutate(this.#state); // We have a static copy of this.#state from here on function mutate(value) { const existing = getExisting(value); if (existing) return existing; return make(value); } function make(value) { if (isScalarVNode(value) || value[IsStaticSymbol] || !value.children) { return value; } const proxied = new Proxy(value, { get(target, p) { if (typeof p === "symbol" && p === IsStaticSymbol) { return true; } if (p !== "children") { return target[p]; } if (!isVNodeWithChildren(target)) { return target.children; } const asyncIterable = replayChildrenViaRecording(target); const recording = weakChildrenRecording.get(target); if (recording?.length) { asyncIterable[ChildrenSource] = recording[recording.length - 1]; } return asyncIterable; } }); weakTree.set(value, proxied); if (options.reference) { referenceTree.set(value.reference, proxied); } if (options.source) { sourceTree.set(value.source, proxied); } return proxied; } function isVNodeWithChildren(node) { return !!node.children; } async function* replayChildrenViaRecording(node) { const existingRecording = weakChildrenRecording.get(node); if (existingRecording) { return yield* existingRecording; } if (weakChildrenRecordingInProgress.has(node)) { throw new Error("Initial children recording in progress, pre-record if multiple consumers are required"); } weakChildrenRecordingInProgress.add(node); const recording = []; for await (const children of node.children) { const mapped = children.map(mutate); yield mapped; if (!options.yieldAllChildren) { recording[0] = mapped; } else { recording.push(mapped); } } weakChildrenRecording.set(node, recording); weakChildrenRecordingInProgress.delete(node); } function getExisting(value) { const weakExisting = weakTree.get(value); if (weakExisting) { return weakExisting; } const referenceExisting = options.reference && referenceTree.get(value.reference); if (referenceExisting) { return referenceExisting; } const sourceExisting = options.source && sourceTree.get(value.source); if (sourceExisting) { return sourceExisting; } return undefined; } } } function Component({ meta }) { return (h("innerContainer", null, meta, " \u2764\uFE0F")); } const instance = (h(Static, null, h(Component, { meta: "\uD83E\uDDBF" }))); await readAllDrain(instance); await readAllDrain(instance); // We are static now export const _903_TransformStatic = (h("container", { class: "example" }, instance)); export const _903_URL = import.meta.url; //# sourceMappingURL=static.js.map