@virtualstate/examples
Version:
124 lines • 4.66 kB
JavaScript
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