@fictjs/runtime 0.2.0 → 0.2.2
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/dist/advanced.cjs +8 -8
- package/dist/advanced.js +3 -3
- package/dist/{chunk-BSUMPMKX.cjs → chunk-3A4VW6AK.cjs} +7 -7
- package/dist/{chunk-BSUMPMKX.cjs.map → chunk-3A4VW6AK.cjs.map} +1 -1
- package/dist/{chunk-J74L7UYP.cjs → chunk-3U7EBKEU.cjs} +5 -3
- package/dist/chunk-3U7EBKEU.cjs.map +1 -0
- package/dist/{chunk-QV5GOCR5.js → chunk-LU2LD2WJ.js} +2 -2
- package/dist/{chunk-FG3M7EBL.js → chunk-TEYUDPTA.js} +2 -2
- package/dist/{chunk-FG3M7EBL.js.map → chunk-TEYUDPTA.js.map} +1 -1
- package/dist/{chunk-527QSKFM.cjs → chunk-URDFDRHR.cjs} +16 -16
- package/dist/{chunk-527QSKFM.cjs.map → chunk-URDFDRHR.cjs.map} +1 -1
- package/dist/{chunk-5KXEEQUO.js → chunk-YVS4WJ2W.js} +5 -3
- package/dist/chunk-YVS4WJ2W.js.map +1 -0
- package/dist/index.cjs +46 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.dev.js +12 -14
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +10 -14
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +64 -42
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +32 -10
- package/dist/internal.js.map +1 -1
- package/package.json +1 -1
- package/src/context.ts +1 -1
- package/src/dom.ts +4 -1
- package/src/error-boundary.ts +9 -9
- package/src/signal.ts +2 -1
- package/src/store.ts +42 -20
- package/src/suspense.ts +0 -5
- package/dist/chunk-5KXEEQUO.js.map +0 -1
- package/dist/chunk-J74L7UYP.cjs.map +0 -1
- package/dist/jsx-runtime.d.cts +0 -671
- package/dist/jsx-runtime.d.ts +0 -671
- /package/dist/{chunk-QV5GOCR5.js.map → chunk-LU2LD2WJ.js.map} +0 -0
package/dist/internal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts","../src/reconcile.ts","../src/list-helpers.ts"],"sourcesContent":["import { signal, batch, type SignalAccessor } from './signal'\n\nconst PROXY = Symbol('fict:store-proxy')\nconst TARGET = Symbol('fict:store-target')\nconst ITERATE_KEY = Symbol('fict:iterate')\n\n// ============================================================================\n// Store (Deep Proxy)\n// ============================================================================\n\nexport type Store<T> = T\n\n/**\n * Create a Store: a reactive proxy that allows fine-grained access and mutation.\n *\n * @param initialValue - The initial state object\n * @returns [store, setStore]\n */\nexport function createStore<T extends object>(\n initialValue: T,\n): [Store<T>, (fn: (state: T) => void | T) => void] {\n const unwrapped = unwrap(initialValue)\n const wrapped = wrap(unwrapped)\n\n function setStore(fn: (state: T) => void | T) {\n batch(() => {\n const result = fn(wrapped)\n if (result !== undefined) {\n reconcile(wrapped, result)\n }\n })\n }\n\n return [wrapped, setStore]\n}\n\n// Map of target object -> Proxy\nconst proxyCache = new WeakMap<object, any>()\n// Map of target object -> Map<key, Signal>\nconst signalCache = new WeakMap<object, Map<string | symbol, SignalAccessor<any>>>()\n\nfunction wrap<T>(value: T): T {\n if (value === null || typeof value !== 'object') return value\n if ((value as any)[PROXY]) return value\n\n if (proxyCache.has(value)) return proxyCache.get(value)\n\n const handler: ProxyHandler<any> = {\n get(target, prop, receiver) {\n if (prop === PROXY) return true\n if (prop === TARGET) return target\n\n const value = Reflect.get(target, prop, receiver)\n\n // Track property access\n track(target, prop)\n\n // Recursively wrap objects\n return wrap(value)\n },\n has(target, prop) {\n const result = Reflect.has(target, prop)\n track(target, prop)\n return result\n },\n ownKeys(target) {\n track(target, ITERATE_KEY)\n return Reflect.ownKeys(target)\n },\n getOwnPropertyDescriptor(target, prop) {\n track(target, prop)\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n set(target, prop, value, receiver) {\n if (prop === PROXY || prop === TARGET) return false\n\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const oldValue = Reflect.get(target, prop, receiver)\n if (oldValue === value) return true\n\n const result = Reflect.set(target, prop, value, receiver)\n if (result) {\n trigger(target, prop)\n if (!hadKey) {\n trigger(target, ITERATE_KEY)\n }\n }\n return result\n },\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n if (result) {\n trigger(target, prop)\n if (hadKey) {\n trigger(target, ITERATE_KEY)\n }\n }\n return result\n },\n }\n\n const proxy = new Proxy(value, handler)\n proxyCache.set(value, proxy)\n return proxy as T\n}\n\nfunction unwrap<T>(value: T): T {\n if (value && typeof value === 'object' && (value as any)[PROXY]) {\n return (value as any)[TARGET]\n }\n return value\n}\n\nfunction track(target: object, prop: string | symbol) {\n let signals = signalCache.get(target)\n if (!signals) {\n signals = new Map()\n signalCache.set(target, signals)\n }\n\n let s = signals.get(prop)\n if (!s) {\n const initial =\n prop === ITERATE_KEY ? (Reflect.ownKeys(target).length as number) : getLastValue(target, prop)\n s = signal(initial)\n signals.set(prop, s)\n }\n s() // subscribe\n}\n\nfunction trigger(target: object, prop: string | symbol) {\n const signals = signalCache.get(target)\n if (signals) {\n const s = signals.get(prop)\n if (s) {\n if (prop === ITERATE_KEY) {\n s(Reflect.ownKeys(target).length)\n } else {\n s(getLastValue(target, prop)) // notify with new value\n }\n }\n }\n}\n\nfunction getLastValue(target: any, prop: string | symbol) {\n return target[prop]\n}\n\n/**\n * Reconcile a store path with a new value (shallow merge/diff)\n */\nfunction reconcile(target: any, value: any) {\n if (target === value) return\n if (value === null || typeof value !== 'object') {\n throw new Error(\n `[Fict] Cannot replace store with primitive value: ${String(\n value,\n )}. setStore should return an object/array to merge.`,\n )\n }\n\n const realTarget = unwrap(target)\n const realValue = unwrap(value)\n\n const keys = new Set([...Object.keys(realTarget), ...Object.keys(realValue)])\n for (const key of keys) {\n if (realValue[key] === undefined && realTarget[key] !== undefined) {\n // deleted\n delete target[key] // Triggers proxy trap\n } else if (realTarget[key] !== realValue[key]) {\n target[key] = realValue[key] // Triggers proxy trap\n }\n }\n\n // Fix array length if needed\n if (Array.isArray(target) && target.length !== realValue.length) {\n target.length = realValue.length\n }\n}\n\n// ============================================================================\n// Diffing Signal (for List Items)\n// ============================================================================\n\n/**\n * Creates a signal that returns a Stable Proxy.\n * Updates to the signal (via set) will diff the new value against the old value\n * and trigger property-specific updates.\n */\nexport function createDiffingSignal<T extends object>(initialValue: T) {\n let currentValue = unwrap(initialValue)\n const signals = new Map<string | symbol, SignalAccessor<any>>()\n let iterateSignal: SignalAccessor<number> | undefined\n\n const getPropSignal = (prop: string | symbol) => {\n let s = signals.get(prop)\n if (!s) {\n s = signal((currentValue as any)[prop])\n signals.set(prop, s)\n }\n return s\n }\n\n const trackIterate = () => {\n if (!iterateSignal) {\n iterateSignal = signal(Reflect.ownKeys(currentValue).length)\n }\n iterateSignal()\n }\n\n const updateIterate = (value: T) => {\n if (iterateSignal) {\n iterateSignal(Reflect.ownKeys(value).length)\n }\n }\n\n // The stable proxy we return\n const proxy = new Proxy({} as T, {\n get(_, prop) {\n if (prop === PROXY) return true\n if (prop === TARGET) return currentValue\n\n // Subscribe to property\n const s = getPropSignal(prop)\n return s()\n },\n ownKeys() {\n trackIterate()\n return Reflect.ownKeys(currentValue)\n },\n has(target, prop) {\n getPropSignal(prop)()\n return Reflect.has(currentValue, prop)\n },\n getOwnPropertyDescriptor(target, prop) {\n getPropSignal(prop)()\n return Reflect.getOwnPropertyDescriptor(currentValue, prop)\n },\n })\n\n const read = () => proxy\n\n const write = (newValue: T) => {\n const next = unwrap(newValue)\n const prev = currentValue\n currentValue = next\n\n if (prev === next) {\n // Same ref update: re-evaluate all tracked signals\n // This is necessary for in-place mutations\n for (const [prop, s] of signals) {\n const newVal = (next as any)[prop]\n s(newVal)\n }\n updateIterate(next)\n return\n }\n\n // Diff logic\n // We only trigger signals for properties that exist in our cache (tracked)\n // and have changed.\n for (const [prop, s] of signals) {\n const oldVal = (prev as any)[prop]\n const newVal = (next as any)[prop]\n if (oldVal !== newVal) {\n s(newVal)\n }\n }\n updateIterate(next)\n\n // Note: If new properties appeared that weren't tracked, we don't care\n // because no one is listening.\n // If we assume shape stability (Keyed List), this is efficient.\n }\n\n return [read, write] as const\n}\n","/**\n * Fict DOM Reconciliation\n *\n * Efficient array reconciliation algorithm based on udomdiff.\n * https://github.com/WebReflection/udomdiff\n *\n * This algorithm uses a 5-step strategy:\n * 1. Common prefix - skip matching nodes at start\n * 2. Common suffix - skip matching nodes at end\n * 3. Append - insert remaining new nodes\n * 4. Remove - remove remaining old nodes\n * 5. Swap/Map fallback - handle complex rearrangements\n *\n * Most real-world updates (95%+) use fast paths without building a Map.\n */\n\n/**\n * Reconcile two arrays of DOM nodes, efficiently updating the DOM.\n *\n * @param parentNode - The parent element containing the nodes\n * @param a - The old array of nodes (currently in DOM)\n * @param b - The new array of nodes (target state)\n *\n * **Note:** This function may mutate the input array `a` during the swap\n * optimization (step 5a). If you need to preserve the original array,\n * pass a shallow copy: `reconcileArrays(parent, [...oldNodes], newNodes)`.\n *\n * @example\n * ```ts\n * const oldNodes = [node1, node2, node3]\n * const newNodes = [node1, node4, node3] // node2 replaced with node4\n * reconcileArrays(parent, oldNodes, newNodes)\n * ```\n */\nexport default function reconcileArrays(parentNode: ParentNode, a: Node[], b: Node[]): void {\n const bLength = b.length\n let aEnd = a.length\n let bEnd = bLength\n let aStart = 0\n let bStart = 0\n const after = aEnd > 0 ? a[aEnd - 1]!.nextSibling : null\n let map: Map<Node, number> | null = null\n\n while (aStart < aEnd || bStart < bEnd) {\n // 1. Common prefix - nodes match at start\n if (a[aStart] === b[bStart]) {\n aStart++\n bStart++\n continue\n }\n\n // 2. Common suffix - nodes match at end\n while (a[aEnd - 1] === b[bEnd - 1]) {\n aEnd--\n bEnd--\n }\n\n // 3. Append - old array exhausted, insert remaining new nodes\n if (aEnd === aStart) {\n const node: Node | null =\n bEnd < bLength ? (bStart ? b[bStart - 1]!.nextSibling : (b[bEnd - bStart] ?? null)) : after\n\n const count = bEnd - bStart\n const doc = (parentNode as Node).ownerDocument\n if (count > 1 && doc) {\n const frag = doc.createDocumentFragment()\n for (let i = bStart; i < bEnd; i++) {\n frag.appendChild(b[i]!)\n }\n parentNode.insertBefore(frag, node)\n bStart = bEnd\n } else {\n while (bStart < bEnd) {\n parentNode.insertBefore(b[bStart++]!, node)\n }\n }\n }\n // 4. Remove - new array exhausted, remove remaining old nodes\n else if (bEnd === bStart) {\n while (aStart < aEnd) {\n const nodeToRemove = a[aStart]!\n if (!map || !map.has(nodeToRemove)) {\n nodeToRemove.parentNode?.removeChild(nodeToRemove)\n }\n aStart++\n }\n }\n // 5a. Swap backward - detect backward swap pattern\n else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {\n const node = a[--aEnd]!.nextSibling\n parentNode.insertBefore(b[bStart++]!, a[aStart++]!.nextSibling)\n parentNode.insertBefore(b[--bEnd]!, node)\n // Update reference in old array for potential future matches\n a[aEnd] = b[bEnd]!\n }\n // 5b. Map fallback - use Map for complex rearrangements\n else {\n // Build map on first use (lazy initialization)\n if (!map) {\n map = new Map()\n let i = bStart\n while (i < bEnd) {\n map.set(b[i]!, i++)\n }\n }\n\n const index = map.get(a[aStart]!)\n\n if (index != null) {\n if (bStart < index && index < bEnd) {\n // Check for longest increasing subsequence\n let i = aStart\n let sequence = 1\n let t: number | undefined\n\n while (++i < aEnd && i < bEnd) {\n t = map.get(a[i]!)\n if (t == null || t !== index + sequence) break\n sequence++\n }\n\n // Use optimal strategy based on sequence length\n if (sequence > index - bStart) {\n // Sequence is long enough - insert nodes before current\n const node = a[aStart]!\n while (bStart < index) {\n parentNode.insertBefore(b[bStart++]!, node)\n }\n } else {\n // Short sequence - replace\n parentNode.replaceChild(b[bStart++]!, a[aStart++]!)\n }\n } else {\n aStart++\n }\n } else {\n // Node not in new array - remove it\n const nodeToRemove = a[aStart++]!\n nodeToRemove.parentNode?.removeChild(nodeToRemove)\n }\n }\n }\n}\n\n/**\n * Simple reconciliation for keyed lists.\n * Uses the same algorithm but works with keyed blocks.\n *\n * @param parentNode - The parent element\n * @param oldNodes - Old nodes in DOM order\n * @param newNodes - New nodes in target order\n */\nexport function reconcileNodes(parentNode: ParentNode, oldNodes: Node[], newNodes: Node[]): void {\n reconcileArrays(parentNode, oldNodes, newNodes)\n}\n","/**\n * List Helpers for Compiler-Generated Fine-Grained Updates\n *\n * These helpers are used by the compiler to generate efficient keyed list rendering.\n * They provide low-level primitives for DOM node manipulation without rebuilding.\n */\n\nimport { createElement } from './dom'\nimport { createRenderEffect } from './effect'\nimport {\n createRootContext,\n destroyRoot,\n flushOnMount,\n getCurrentRoot,\n popRoot,\n pushRoot,\n type RootContext,\n} from './lifecycle'\nimport { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'\nimport reconcileArrays from './reconcile'\nimport { batch } from './scheduler'\nimport { createSignal, effectScope, flush, setActiveSub, type Signal } from './signal'\nimport type { FictNode } from './types'\n\n// Re-export shared DOM helpers for compiler-generated code\nexport { insertNodesBefore, removeNodes, toNodeArray }\n\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A keyed block represents a single item in a list with its associated DOM nodes and state\n */\ninterface KeyedBlock<T = unknown> {\n /** Unique key for this block */\n key: string | number\n /** DOM nodes belonging to this block */\n nodes: Node[]\n /** Root context for lifecycle management */\n root: RootContext\n /** Signal containing the current item value */\n item: Signal<T>\n /** Signal containing the current index */\n index: Signal<number>\n /** Last raw item value assigned to this block */\n rawItem: T\n /** Last raw index value assigned to this block */\n rawIndex: number\n}\n\n/**\n * Container for managing keyed list blocks\n */\ninterface KeyedListContainer<T = unknown> {\n /** Start marker comment node */\n startMarker: Comment\n /** End marker comment node */\n endMarker: Comment\n /** Map of key to block */\n blocks: Map<string | number, KeyedBlock<T>>\n /** Scratch map reused for the next render */\n nextBlocks: Map<string | number, KeyedBlock<T>>\n /** Current nodes in DOM order (including markers) */\n currentNodes: Node[]\n /** Next-frame node buffer to avoid reallocations */\n nextNodes: Node[]\n /** Ordered blocks in current DOM order */\n orderedBlocks: KeyedBlock<T>[]\n /** Next-frame ordered block buffer to avoid reallocations */\n nextOrderedBlocks: KeyedBlock<T>[]\n /** Track position of keys in the ordered buffer to handle duplicates */\n orderedIndexByKey: Map<string | number, number>\n /** Cleanup function */\n dispose: () => void\n}\n\n/**\n * Binding handle returned by createKeyedList for compiler-generated code\n */\nexport interface KeyedListBinding {\n /** Document fragment placeholder inserted by the compiler/runtime */\n marker: DocumentFragment\n /** Start marker comment node */\n startMarker: Comment\n /** End marker comment node */\n endMarker: Comment\n /** Flush pending items - call after markers are inserted into DOM */\n flush?: () => void\n /** Cleanup function */\n dispose: () => void\n}\n\ntype FineGrainedRenderItem<T> = (\n itemSig: Signal<T>,\n indexSig: Signal<number>,\n key: string | number,\n) => Node[]\n\n// ============================================================================\n// DOM Manipulation Primitives\n// ============================================================================\n\n/**\n * Move nodes to a position before the anchor node.\n * This is optimized to avoid unnecessary DOM operations.\n *\n * @param parent - Parent node to move nodes within\n * @param nodes - Array of nodes to move\n * @param anchor - Node to insert before (or null for end)\n */\nexport function moveNodesBefore(parent: Node, nodes: Node[], anchor: Node | null): void {\n // Insert in reverse order to maintain correct sequence\n // This way each node becomes the new anchor for the next\n for (let i = nodes.length - 1; i >= 0; i--) {\n const node = nodes[i]!\n if (!node || !(node instanceof Node)) {\n const message = isDev ? 'Invalid node in moveNodesBefore' : 'FICT:E_NODE'\n throw new Error(message)\n }\n // Only move if not already in correct position\n if (node.nextSibling !== anchor) {\n if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {\n parent.ownerDocument.adoptNode(node)\n }\n try {\n parent.insertBefore(node, anchor)\n } catch (e: any) {\n if (parent.ownerDocument) {\n try {\n const clone = parent.ownerDocument.importNode(node, true)\n parent.insertBefore(clone, anchor)\n // Update the nodes array with the clone to maintain correct references.\n // This ensures future operations (like removal or reordering) work correctly.\n nodes[i] = clone\n if (isDev) {\n console.warn(\n `[fict] Node cloning fallback triggered during list reordering. ` +\n `This may indicate cross-document node insertion. ` +\n `The node reference has been updated to the clone.`,\n )\n }\n anchor = clone\n continue\n } catch {\n // Clone fallback failed\n }\n }\n throw e\n }\n }\n anchor = node\n }\n}\n\n/**\n * Remove an array of nodes from the DOM\n *\n * @param nodes - Array of nodes to remove\n */\n// Number.MAX_SAFE_INTEGER is 2^53 - 1, but we reset earlier to avoid any precision issues\nconst MAX_SAFE_VERSION = 0x1fffffffffffff // 2^53 - 1\n\nexport function createVersionedSignalAccessor<T>(initialValue: T): Signal<T> {\n let current = initialValue\n let version = 0\n const track = createSignal(version)\n\n function accessor(value?: T): T | void {\n if (arguments.length === 0) {\n track()\n return current\n }\n current = value as T\n // This is safe because we only care about version changes, not absolute values\n version = version >= MAX_SAFE_VERSION ? 1 : version + 1\n track(version)\n }\n\n return accessor as Signal<T>\n}\n\n// ============================================================================\n// Keyed List Container\n// ============================================================================\n\n/**\n * Create a container for managing a keyed list.\n * This sets up the marker nodes and provides cleanup.\n *\n * @returns Container object with markers, blocks map, and dispose function\n */\nfunction createKeyedListContainer<T = unknown>(): KeyedListContainer<T> {\n const startMarker = document.createComment('fict:list:start')\n const endMarker = document.createComment('fict:list:end')\n\n const dispose = () => {\n // Clean up all blocks\n for (const block of container.blocks.values()) {\n destroyRoot(block.root)\n // Nodes are removed by parent disposal or specific cleanup if needed\n // But for list disposal, we just clear the container\n }\n container.blocks.clear()\n container.nextBlocks.clear()\n\n // Remove nodes (including markers)\n // Check if markers are still in DOM before using Range\n if (!startMarker.parentNode || !endMarker.parentNode) {\n // Markers already removed, nothing to do\n container.currentNodes = []\n container.nextNodes = []\n container.orderedBlocks.length = 0\n container.nextOrderedBlocks.length = 0\n container.orderedIndexByKey.clear()\n return\n }\n const range = document.createRange()\n range.setStartBefore(startMarker)\n range.setEndAfter(endMarker)\n range.deleteContents()\n\n // Clear cache\n container.currentNodes = []\n container.nextNodes = []\n container.nextBlocks.clear()\n container.orderedBlocks.length = 0\n container.nextOrderedBlocks.length = 0\n container.orderedIndexByKey.clear()\n }\n\n const container: KeyedListContainer<T> = {\n startMarker,\n endMarker,\n blocks: new Map<string | number, KeyedBlock<T>>(),\n nextBlocks: new Map<string | number, KeyedBlock<T>>(),\n currentNodes: [startMarker, endMarker],\n nextNodes: [],\n orderedBlocks: [],\n nextOrderedBlocks: [],\n orderedIndexByKey: new Map<string | number, number>(),\n dispose,\n }\n\n return container\n}\n\n// ============================================================================\n// Block Creation Helpers\n// ============================================================================\n\n/**\n * Create a new keyed block with the given render function\n *\n * @param key - Unique key for this block\n * @param item - Initial item value\n * @param index - Initial index\n * @param render - Function that creates the DOM nodes and sets up bindings\n * @returns New KeyedBlock\n */\nfunction createKeyedBlock<T>(\n key: string | number,\n item: T,\n index: number,\n render: (item: Signal<T>, index: Signal<number>, key: string | number) => Node[],\n needsIndex = true,\n hostRoot?: RootContext,\n): KeyedBlock<T> {\n // Use versioned signal for all item types; avoid diffing proxy overhead for objects\n const itemSig = createVersionedSignalAccessor(item)\n\n const indexSig = needsIndex\n ? createSignal<number>(index)\n : (((next?: number) => {\n if (arguments.length === 0) return index\n index = next as number\n return index\n }) as Signal<number>)\n const root = createRootContext(hostRoot)\n const prevRoot = pushRoot(root)\n // maintaining proper cleanup chain. The scope will be disposed when\n // the root is destroyed, ensuring nested effects are properly cleaned up.\n let nodes: Node[] = []\n let scopeDispose: (() => void) | undefined\n\n // First, isolate from parent effect to prevent child effects from being\n // purged when the outer effect (e.g., performDiff) re-runs\n const prevSub = setActiveSub(undefined)\n\n try {\n // Create an effectScope that will track all effects created during render\n scopeDispose = effectScope(() => {\n const rendered = render(itemSig, indexSig, key)\n // If render returns real DOM nodes/arrays, preserve them to avoid\n // reparenting side-effects (tests may pre-insert them).\n if (\n rendered instanceof Node ||\n (Array.isArray(rendered) && rendered.every(n => n instanceof Node))\n ) {\n nodes = toNodeArray(rendered)\n } else {\n const element = createElement(rendered as unknown as FictNode)\n nodes = toNodeArray(element)\n }\n })\n\n // Register the scope cleanup with the root so effects are cleaned up\n // when the block is destroyed\n if (scopeDispose) {\n root.cleanups.push(scopeDispose)\n }\n } finally {\n setActiveSub(prevSub)\n popRoot(prevRoot)\n }\n\n return {\n key,\n nodes,\n root,\n item: itemSig,\n index: indexSig,\n rawItem: item,\n rawIndex: index,\n }\n}\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\n/**\n * Check if a node is between two markers\n */\nexport function isNodeBetweenMarkers(\n node: Node,\n startMarker: Comment,\n endMarker: Comment,\n): boolean {\n let current: Node | null = startMarker.nextSibling\n while (current && current !== endMarker) {\n if (current === node) return true\n current = current.nextSibling\n }\n return false\n}\n\nfunction reorderBySwap<T>(\n parent: ParentNode & Node,\n first: KeyedBlock<T>,\n second: KeyedBlock<T>,\n): boolean {\n if (first === second) return false\n const firstNodes = first.nodes\n const secondNodes = second.nodes\n if (firstNodes.length === 0 || secondNodes.length === 0) return false\n const lastFirst = firstNodes[firstNodes.length - 1]!\n const lastSecond = secondNodes[secondNodes.length - 1]!\n const afterFirst = lastFirst.nextSibling\n const afterSecond = lastSecond.nextSibling\n moveNodesBefore(parent, firstNodes, afterSecond)\n moveNodesBefore(parent, secondNodes, afterFirst)\n return true\n}\n\nfunction getLISIndices(sequence: number[]): number[] {\n const predecessors = new Array<number>(sequence.length)\n const result: number[] = []\n\n for (let i = 0; i < sequence.length; i++) {\n const value = sequence[i]!\n if (value < 0) {\n predecessors[i] = -1\n continue\n }\n\n let low = 0\n let high = result.length\n while (low < high) {\n const mid = (low + high) >> 1\n if (sequence[result[mid]!]! < value) {\n low = mid + 1\n } else {\n high = mid\n }\n }\n\n predecessors[i] = low > 0 ? result[low - 1]! : -1\n if (low === result.length) {\n result.push(i)\n } else {\n result[low] = i\n }\n }\n\n const lis: number[] = new Array(result.length)\n let k = result.length > 0 ? result[result.length - 1]! : -1\n for (let i = result.length - 1; i >= 0; i--) {\n lis[i] = k\n k = predecessors[k]!\n }\n return lis\n}\n\nfunction reorderByLIS<T>(\n parent: ParentNode & Node,\n endMarker: Comment,\n prev: KeyedBlock<T>[],\n next: KeyedBlock<T>[],\n): boolean {\n const positions = new Map<KeyedBlock<T>, number>()\n for (let i = 0; i < prev.length; i++) {\n positions.set(prev[i]!, i)\n }\n\n const sequence = new Array<number>(next.length)\n for (let i = 0; i < next.length; i++) {\n const position = positions.get(next[i]!)\n if (position === undefined) return false\n sequence[i] = position\n }\n\n const lisIndices = getLISIndices(sequence)\n if (lisIndices.length === sequence.length) return true\n\n const inLIS = new Array<boolean>(sequence.length).fill(false)\n for (let i = 0; i < lisIndices.length; i++) {\n inLIS[lisIndices[i]!] = true\n }\n\n let anchor: Node | null = endMarker\n let moved = false\n for (let i = next.length - 1; i >= 0; i--) {\n const block = next[i]!\n const nodes = block.nodes\n if (nodes.length === 0) continue\n if (inLIS[i]) {\n anchor = nodes[0]!\n continue\n }\n moveNodesBefore(parent, nodes, anchor)\n anchor = nodes[0]!\n moved = true\n }\n\n return moved\n}\n\n// ============================================================================\n// High-Level List Binding (for compiler-generated code)\n// ============================================================================\n\n/**\n * Create a keyed list binding with automatic diffing and DOM updates.\n * This is used by compiler-generated code for efficient list rendering.\n *\n * @param getItems - Function that returns the current array of items\n * @param keyFn - Function to extract unique key from each item\n * @param renderItem - Function that creates DOM nodes for each item\n * @returns Binding handle with markers and dispose function\n */\nexport function createKeyedList<T>(\n getItems: () => T[],\n keyFn: (item: T, index: number) => string | number,\n renderItem: FineGrainedRenderItem<T>,\n needsIndex?: boolean,\n): KeyedListBinding {\n const resolvedNeedsIndex =\n arguments.length >= 4 ? !!needsIndex : renderItem.length > 1 /* has index param */\n return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex)\n}\n\nfunction createFineGrainedKeyedList<T>(\n getItems: () => T[],\n keyFn: (item: T, index: number) => string | number,\n renderItem: FineGrainedRenderItem<T>,\n needsIndex: boolean,\n): KeyedListBinding {\n const container = createKeyedListContainer<T>()\n const hostRoot = getCurrentRoot()\n const fragment = document.createDocumentFragment()\n fragment.append(container.startMarker, container.endMarker)\n let disposed = false\n let effectDispose: (() => void) | undefined\n let connectObserver: MutationObserver | null = null\n let effectStarted = false\n let startScheduled = false\n\n const getConnectedParent = (): (ParentNode & Node) | null => {\n const endParent = container.endMarker.parentNode\n const startParent = container.startMarker.parentNode\n if (\n endParent &&\n startParent &&\n endParent === startParent &&\n (endParent as Node).nodeType !== 11\n ) {\n const parentNode = endParent as ParentNode & Node\n if ('isConnected' in parentNode && !parentNode.isConnected) return null\n return parentNode\n }\n return null\n }\n\n const performDiff = () => {\n if (disposed) return\n const parent = getConnectedParent()\n if (!parent) return\n batch(() => {\n const oldBlocks = container.blocks\n const newBlocks = container.nextBlocks\n const prevOrderedBlocks = container.orderedBlocks\n const nextOrderedBlocks = container.nextOrderedBlocks\n const orderedIndexByKey = container.orderedIndexByKey\n const newItems = getItems()\n\n if (newItems.length === 0) {\n if (oldBlocks.size > 0) {\n // Destroy all block roots first\n for (const block of oldBlocks.values()) {\n destroyRoot(block.root)\n }\n // Use Range.deleteContents for efficient bulk DOM removal\n const range = document.createRange()\n range.setStartAfter(container.startMarker)\n range.setEndBefore(container.endMarker)\n range.deleteContents()\n }\n oldBlocks.clear()\n newBlocks.clear()\n prevOrderedBlocks.length = 0\n nextOrderedBlocks.length = 0\n orderedIndexByKey.clear()\n container.currentNodes.length = 0\n container.currentNodes.push(container.startMarker, container.endMarker)\n container.nextNodes.length = 0\n return\n }\n\n const prevCount = prevOrderedBlocks.length\n if (prevCount > 0 && newItems.length === prevCount && orderedIndexByKey.size === prevCount) {\n let stableOrder = true\n const seen = new Set<string | number>()\n for (let i = 0; i < prevCount; i++) {\n const item = newItems[i]!\n const key = keyFn(item, i)\n if (seen.has(key) || prevOrderedBlocks[i]!.key !== key) {\n stableOrder = false\n break\n }\n seen.add(key)\n }\n if (stableOrder) {\n for (let i = 0; i < prevCount; i++) {\n const item = newItems[i]!\n const block = prevOrderedBlocks[i]!\n if (block.rawItem !== item) {\n block.rawItem = item\n block.item(item)\n }\n if (needsIndex && block.rawIndex !== i) {\n block.rawIndex = i\n block.index(i)\n }\n }\n return\n }\n }\n\n newBlocks.clear()\n nextOrderedBlocks.length = 0\n orderedIndexByKey.clear()\n const createdBlocks: KeyedBlock<T>[] = []\n let appendCandidate = prevCount > 0 && newItems.length >= prevCount\n const appendedBlocks: KeyedBlock<T>[] = []\n let mismatchCount = 0\n let mismatchFirst = -1\n let mismatchSecond = -1\n let hasDuplicateKey = false\n\n // Phase 1: Build new blocks map (reuse or create)\n newItems.forEach((item, index) => {\n const key = keyFn(item, index)\n // Micro-optimization: single Map.get instead of has+get\n let block = oldBlocks.get(key)\n const existed = block !== undefined\n\n if (block) {\n if (block.rawItem !== item) {\n block.rawItem = item\n block.item(item)\n }\n if (needsIndex && block.rawIndex !== index) {\n block.rawIndex = index\n block.index(index)\n }\n }\n\n if (block) {\n // Reusing existing block from oldBlocks\n newBlocks.set(key, block)\n oldBlocks.delete(key)\n } else {\n // If newBlocks already has this key (duplicate key case), clean up the previous block\n const existingBlock = newBlocks.get(key)\n if (existingBlock) {\n if (isDev) {\n console.warn(\n `[fict] Duplicate key \"${String(key)}\" detected in list rendering. ` +\n `Each item should have a unique key. The previous item with this key will be replaced.`,\n )\n }\n destroyRoot(existingBlock.root)\n removeNodes(existingBlock.nodes)\n }\n // Create new block\n block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot)\n createdBlocks.push(block)\n }\n\n const resolvedBlock = block\n\n newBlocks.set(key, resolvedBlock)\n\n // Micro-optimization: single Map.get instead of checking position multiple times\n const position = orderedIndexByKey.get(key)\n if (position !== undefined) {\n appendCandidate = false\n hasDuplicateKey = true\n const prior = nextOrderedBlocks[position]\n if (prior && prior !== resolvedBlock) {\n destroyRoot(prior.root)\n removeNodes(prior.nodes)\n }\n nextOrderedBlocks[position] = resolvedBlock\n } else {\n if (appendCandidate) {\n if (index < prevCount) {\n if (!prevOrderedBlocks[index] || prevOrderedBlocks[index]!.key !== key) {\n appendCandidate = false\n }\n } else if (existed) {\n appendCandidate = false\n }\n }\n const nextIndex = nextOrderedBlocks.length\n orderedIndexByKey.set(key, nextIndex)\n nextOrderedBlocks.push(resolvedBlock)\n if (\n mismatchCount < 3 &&\n (nextIndex >= prevCount || prevOrderedBlocks[nextIndex] !== resolvedBlock)\n ) {\n if (mismatchCount === 0) {\n mismatchFirst = nextIndex\n } else if (mismatchCount === 1) {\n mismatchSecond = nextIndex\n }\n mismatchCount++\n }\n }\n\n if (appendCandidate && index >= prevCount) {\n appendedBlocks.push(resolvedBlock)\n }\n })\n\n const canAppend =\n appendCandidate &&\n prevCount > 0 &&\n newItems.length > prevCount &&\n oldBlocks.size === 0 &&\n appendedBlocks.length > 0\n if (canAppend) {\n const appendedNodes: Node[] = []\n for (const block of appendedBlocks) {\n for (let i = 0; i < block.nodes.length; i++) {\n appendedNodes.push(block.nodes[i]!)\n }\n }\n if (appendedNodes.length > 0) {\n insertNodesBefore(parent, appendedNodes, container.endMarker)\n const currentNodes = container.currentNodes\n currentNodes.pop()\n for (let i = 0; i < appendedNodes.length; i++) {\n currentNodes.push(appendedNodes[i]!)\n }\n currentNodes.push(container.endMarker)\n }\n\n container.blocks = newBlocks\n container.nextBlocks = oldBlocks\n container.orderedBlocks = nextOrderedBlocks\n container.nextOrderedBlocks = prevOrderedBlocks\n for (const block of createdBlocks) {\n if (newBlocks.get(block.key) === block) {\n flushOnMount(block.root)\n }\n }\n return\n }\n\n // Phase 2: Remove old blocks that are no longer in the list\n if (oldBlocks.size > 0) {\n for (const block of oldBlocks.values()) {\n destroyRoot(block.root)\n removeNodes(block.nodes)\n }\n oldBlocks.clear()\n }\n\n const canReorderInPlace =\n createdBlocks.length === 0 &&\n oldBlocks.size === 0 &&\n nextOrderedBlocks.length === prevOrderedBlocks.length\n\n let skipReconcile = false\n let updateNodeBuffer = true\n\n if (canReorderInPlace && nextOrderedBlocks.length > 0 && !hasDuplicateKey) {\n if (mismatchCount === 0) {\n skipReconcile = true\n updateNodeBuffer = false\n } else if (\n mismatchCount === 2 &&\n prevOrderedBlocks[mismatchFirst] === nextOrderedBlocks[mismatchSecond] &&\n prevOrderedBlocks[mismatchSecond] === nextOrderedBlocks[mismatchFirst]\n ) {\n if (\n reorderBySwap(\n parent,\n prevOrderedBlocks[mismatchFirst]!,\n prevOrderedBlocks[mismatchSecond]!,\n )\n ) {\n skipReconcile = true\n }\n } else if (\n reorderByLIS(parent, container.endMarker, prevOrderedBlocks, nextOrderedBlocks)\n ) {\n skipReconcile = true\n }\n }\n\n // Phase 3: Reconcile DOM with buffered node arrays\n if (!skipReconcile && (newBlocks.size > 0 || container.currentNodes.length > 0)) {\n const prevNodes = container.currentNodes\n const nextNodes = container.nextNodes\n nextNodes.length = 0\n nextNodes.push(container.startMarker)\n\n for (let i = 0; i < nextOrderedBlocks.length; i++) {\n const nodes = nextOrderedBlocks[i]!.nodes\n for (let j = 0; j < nodes.length; j++) {\n nextNodes.push(nodes[j]!)\n }\n }\n\n nextNodes.push(container.endMarker)\n\n reconcileArrays(parent, prevNodes, nextNodes)\n\n // Swap buffers to reuse arrays on next diff\n container.currentNodes = nextNodes\n container.nextNodes = prevNodes\n } else if (skipReconcile && updateNodeBuffer) {\n const prevNodes = container.currentNodes\n const nextNodes = container.nextNodes\n nextNodes.length = 0\n nextNodes.push(container.startMarker)\n for (let i = 0; i < nextOrderedBlocks.length; i++) {\n const nodes = nextOrderedBlocks[i]!.nodes\n for (let j = 0; j < nodes.length; j++) {\n nextNodes.push(nodes[j]!)\n }\n }\n nextNodes.push(container.endMarker)\n container.currentNodes = nextNodes\n container.nextNodes = prevNodes\n }\n\n // Swap block maps for reuse\n container.blocks = newBlocks\n container.nextBlocks = oldBlocks\n container.orderedBlocks = nextOrderedBlocks\n container.nextOrderedBlocks = prevOrderedBlocks\n for (const block of createdBlocks) {\n if (newBlocks.get(block.key) === block) {\n flushOnMount(block.root)\n }\n }\n })\n }\n\n const disconnectObserver = () => {\n connectObserver?.disconnect()\n connectObserver = null\n }\n\n const ensureEffectStarted = (): boolean => {\n if (disposed || effectStarted) return effectStarted\n const parent = getConnectedParent()\n if (!parent) return false\n const start = () => {\n effectDispose = createRenderEffect(performDiff)\n effectStarted = true\n }\n if (hostRoot) {\n const prev = pushRoot(hostRoot)\n try {\n start()\n } finally {\n popRoot(prev)\n }\n } else {\n start()\n }\n return true\n }\n\n const waitForConnection = () => {\n if (connectObserver || typeof MutationObserver === 'undefined') return\n connectObserver = new MutationObserver(() => {\n if (disposed) return\n if (getConnectedParent()) {\n disconnectObserver()\n if (ensureEffectStarted()) {\n flush()\n }\n }\n })\n connectObserver.observe(document, { childList: true, subtree: true })\n }\n\n const scheduleStart = () => {\n if (startScheduled || disposed || effectStarted) return\n startScheduled = true\n const run = () => {\n startScheduled = false\n if (!ensureEffectStarted()) {\n waitForConnection()\n }\n }\n if (typeof queueMicrotask === 'function') {\n queueMicrotask(run)\n } else {\n Promise.resolve()\n .then(run)\n .catch(() => undefined)\n }\n }\n\n scheduleStart()\n\n return {\n get marker() {\n scheduleStart()\n return fragment\n },\n startMarker: container.startMarker,\n endMarker: container.endMarker,\n // Flush pending items - call after markers are inserted into DOM\n flush: () => {\n if (disposed) return\n scheduleStart()\n if (ensureEffectStarted()) {\n flush()\n } else {\n waitForConnection()\n }\n },\n dispose: () => {\n disposed = true\n effectDispose?.()\n disconnectObserver()\n container.dispose()\n },\n }\n}\n"],"mappings":"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","names":["unwrap","prop","value","track","batch"]}
|
|
1
|
+
{"version":3,"sources":["../src/store.ts","../src/reconcile.ts","../src/list-helpers.ts"],"sourcesContent":["import { signal, batch, type SignalAccessor } from './signal'\n\nconst PROXY = Symbol('fict:store-proxy')\nconst TARGET = Symbol('fict:store-target')\nconst ITERATE_KEY = Symbol('fict:iterate')\n\n// ============================================================================\n// Store (Deep Proxy)\n// ============================================================================\n\nexport type Store<T> = T\n\n/**\n * Create a Store: a reactive proxy that allows fine-grained access and mutation.\n *\n * @param initialValue - The initial state object\n * @returns [store, setStore]\n */\nexport function createStore<T extends object>(\n initialValue: T,\n): [Store<T>, (fn: (state: T) => void | T) => void] {\n const unwrapped = unwrap(initialValue)\n const wrapped = wrap(unwrapped)\n\n function setStore(fn: (state: T) => void | T) {\n batch(() => {\n const result = fn(wrapped)\n if (result !== undefined) {\n reconcile(wrapped, result)\n }\n })\n }\n\n return [wrapped, setStore]\n}\n\n// Map of target object -> Proxy\nconst proxyCache = new WeakMap<object, unknown>()\n// Map of target object -> Map<key, Signal>\nconst signalCache = new WeakMap<object, Map<string | symbol, SignalAccessor<unknown>>>()\n\nfunction wrap<T>(value: T): T {\n if (value === null || typeof value !== 'object') return value\n if (Reflect.get(value, PROXY)) return value\n\n if (proxyCache.has(value)) return proxyCache.get(value) as T\n\n const handler: ProxyHandler<object> = {\n get(target, prop, receiver) {\n if (prop === PROXY) return true\n if (prop === TARGET) return target\n\n const value = Reflect.get(target, prop, receiver)\n\n // Track property access\n track(target, prop)\n\n // Recursively wrap objects\n return wrap(value)\n },\n has(target, prop) {\n const result = Reflect.has(target, prop)\n track(target, prop)\n return result\n },\n ownKeys(target) {\n track(target, ITERATE_KEY)\n return Reflect.ownKeys(target)\n },\n getOwnPropertyDescriptor(target, prop) {\n track(target, prop)\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n set(target, prop, value, receiver) {\n if (prop === PROXY || prop === TARGET) return false\n\n const isArrayLength = Array.isArray(target) && prop === 'length'\n const oldLength = isArrayLength ? target.length : undefined\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const oldValue = Reflect.get(target, prop, receiver)\n if (oldValue === value) return true\n\n const result = Reflect.set(target, prop, value, receiver)\n if (result) {\n trigger(target, prop)\n if (!hadKey) {\n trigger(target, ITERATE_KEY)\n }\n if (isArrayLength) {\n const nextLength = target.length\n if (typeof oldLength === 'number' && nextLength < oldLength) {\n const signals = signalCache.get(target)\n if (signals) {\n for (const key of signals.keys()) {\n if (typeof key !== 'string') continue\n const index = Number(key)\n if (!Number.isInteger(index) || String(index) !== key) continue\n if (index >= nextLength && index < oldLength) {\n trigger(target, key)\n }\n }\n }\n }\n trigger(target, ITERATE_KEY)\n }\n }\n return result\n },\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n if (result) {\n trigger(target, prop)\n if (hadKey) {\n trigger(target, ITERATE_KEY)\n }\n }\n return result\n },\n }\n\n const proxy = new Proxy(value, handler)\n proxyCache.set(value, proxy)\n return proxy as T\n}\n\nfunction unwrap<T>(value: T): T {\n if (value && typeof value === 'object' && Reflect.get(value, PROXY)) {\n return Reflect.get(value, TARGET) as T\n }\n return value\n}\n\nfunction track(target: object, prop: string | symbol) {\n let signals = signalCache.get(target)\n if (!signals) {\n signals = new Map()\n signalCache.set(target, signals)\n }\n\n let s = signals.get(prop)\n if (!s) {\n const initial =\n prop === ITERATE_KEY ? (Reflect.ownKeys(target).length as number) : getLastValue(target, prop)\n s = signal(initial)\n signals.set(prop, s)\n }\n s() // subscribe\n}\n\nfunction trigger(target: object, prop: string | symbol) {\n const signals = signalCache.get(target)\n if (signals) {\n const s = signals.get(prop)\n if (s) {\n if (prop === ITERATE_KEY) {\n s(Reflect.ownKeys(target).length)\n } else {\n s(getLastValue(target, prop)) // notify with new value\n }\n }\n }\n}\n\nfunction getLastValue(target: object, prop: string | symbol) {\n return Reflect.get(target, prop)\n}\n\n/**\n * Reconcile a store path with a new value (shallow merge/diff)\n */\nfunction reconcile(target: object, value: unknown) {\n if (target === value) return\n if (value === null || typeof value !== 'object') {\n throw new Error(\n `[Fict] Cannot replace store with primitive value: ${String(\n value,\n )}. setStore should return an object/array to merge.`,\n )\n }\n\n const realTarget = unwrap(target)\n const realValue = unwrap(value)\n\n const keys = new Set([...Object.keys(realTarget), ...Object.keys(realValue)])\n for (const key of keys) {\n const rTarget = realTarget as Record<string, unknown>\n const rValue = realValue as Record<string, unknown>\n\n if (rValue[key] === undefined && rTarget[key] !== undefined) {\n // deleted\n delete (target as Record<string, unknown>)[key] // Triggers proxy trap\n } else if (rTarget[key] !== rValue[key]) {\n ;(target as Record<string, unknown>)[key] = rValue[key] // Triggers proxy trap\n }\n }\n\n // Fix array length if needed\n if (Array.isArray(target) && Array.isArray(realValue) && target.length !== realValue.length) {\n target.length = realValue.length\n }\n}\n\n// ============================================================================\n// Diffing Signal (for List Items)\n// ============================================================================\n\n/**\n * Creates a signal that returns a Stable Proxy.\n * Updates to the signal (via set) will diff the new value against the old value\n * and trigger property-specific updates.\n */\nexport function createDiffingSignal<T extends object>(initialValue: T) {\n let currentValue = unwrap(initialValue)\n const signals = new Map<string | symbol, SignalAccessor<unknown>>()\n let iterateSignal: SignalAccessor<number> | undefined\n\n const getPropSignal = (prop: string | symbol) => {\n let s = signals.get(prop)\n if (!s) {\n s = signal(Reflect.get(currentValue as object, prop))\n signals.set(prop, s)\n }\n return s\n }\n\n const trackIterate = () => {\n if (!iterateSignal) {\n iterateSignal = signal(Reflect.ownKeys(currentValue).length)\n }\n iterateSignal()\n }\n\n const updateIterate = (value: T) => {\n if (iterateSignal) {\n iterateSignal(Reflect.ownKeys(value).length)\n }\n }\n\n // The stable proxy we return\n const proxy = new Proxy({} as T, {\n get(_, prop) {\n if (prop === PROXY) return true\n if (prop === TARGET) return currentValue\n\n // Subscribe to property\n const s = getPropSignal(prop)\n return s()\n },\n ownKeys() {\n trackIterate()\n return Reflect.ownKeys(currentValue)\n },\n has(target, prop) {\n getPropSignal(prop)()\n return Reflect.has(currentValue, prop)\n },\n getOwnPropertyDescriptor(target, prop) {\n getPropSignal(prop)()\n return Reflect.getOwnPropertyDescriptor(currentValue, prop)\n },\n })\n\n const read = () => proxy\n\n const write = (newValue: T) => {\n const next = unwrap(newValue)\n const prev = currentValue\n currentValue = next\n\n if (prev === next) {\n // Same ref update: re-evaluate all tracked signals\n // This is necessary for in-place mutations\n for (const [prop, s] of signals) {\n const newVal = Reflect.get(next as object, prop)\n s(newVal)\n }\n updateIterate(next)\n return\n }\n\n // Diff logic\n // We only trigger signals for properties that exist in our cache (tracked)\n // and have changed.\n for (const [prop, s] of signals) {\n const oldVal = Reflect.get(prev as object, prop)\n const newVal = Reflect.get(next as object, prop)\n if (oldVal !== newVal) {\n s(newVal)\n }\n }\n updateIterate(next)\n\n // Note: If new properties appeared that weren't tracked, we don't care\n // because no one is listening.\n // If we assume shape stability (Keyed List), this is efficient.\n }\n\n return [read, write] as const\n}\n","/**\n * Fict DOM Reconciliation\n *\n * Efficient array reconciliation algorithm based on udomdiff.\n * https://github.com/WebReflection/udomdiff\n *\n * This algorithm uses a 5-step strategy:\n * 1. Common prefix - skip matching nodes at start\n * 2. Common suffix - skip matching nodes at end\n * 3. Append - insert remaining new nodes\n * 4. Remove - remove remaining old nodes\n * 5. Swap/Map fallback - handle complex rearrangements\n *\n * Most real-world updates (95%+) use fast paths without building a Map.\n */\n\n/**\n * Reconcile two arrays of DOM nodes, efficiently updating the DOM.\n *\n * @param parentNode - The parent element containing the nodes\n * @param a - The old array of nodes (currently in DOM)\n * @param b - The new array of nodes (target state)\n *\n * **Note:** This function may mutate the input array `a` during the swap\n * optimization (step 5a). If you need to preserve the original array,\n * pass a shallow copy: `reconcileArrays(parent, [...oldNodes], newNodes)`.\n *\n * @example\n * ```ts\n * const oldNodes = [node1, node2, node3]\n * const newNodes = [node1, node4, node3] // node2 replaced with node4\n * reconcileArrays(parent, oldNodes, newNodes)\n * ```\n */\nexport default function reconcileArrays(parentNode: ParentNode, a: Node[], b: Node[]): void {\n const bLength = b.length\n let aEnd = a.length\n let bEnd = bLength\n let aStart = 0\n let bStart = 0\n const after = aEnd > 0 ? a[aEnd - 1]!.nextSibling : null\n let map: Map<Node, number> | null = null\n\n while (aStart < aEnd || bStart < bEnd) {\n // 1. Common prefix - nodes match at start\n if (a[aStart] === b[bStart]) {\n aStart++\n bStart++\n continue\n }\n\n // 2. Common suffix - nodes match at end\n while (a[aEnd - 1] === b[bEnd - 1]) {\n aEnd--\n bEnd--\n }\n\n // 3. Append - old array exhausted, insert remaining new nodes\n if (aEnd === aStart) {\n const node: Node | null =\n bEnd < bLength ? (bStart ? b[bStart - 1]!.nextSibling : (b[bEnd - bStart] ?? null)) : after\n\n const count = bEnd - bStart\n const doc = (parentNode as Node).ownerDocument\n if (count > 1 && doc) {\n const frag = doc.createDocumentFragment()\n for (let i = bStart; i < bEnd; i++) {\n frag.appendChild(b[i]!)\n }\n parentNode.insertBefore(frag, node)\n bStart = bEnd\n } else {\n while (bStart < bEnd) {\n parentNode.insertBefore(b[bStart++]!, node)\n }\n }\n }\n // 4. Remove - new array exhausted, remove remaining old nodes\n else if (bEnd === bStart) {\n while (aStart < aEnd) {\n const nodeToRemove = a[aStart]!\n if (!map || !map.has(nodeToRemove)) {\n nodeToRemove.parentNode?.removeChild(nodeToRemove)\n }\n aStart++\n }\n }\n // 5a. Swap backward - detect backward swap pattern\n else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {\n const node = a[--aEnd]!.nextSibling\n parentNode.insertBefore(b[bStart++]!, a[aStart++]!.nextSibling)\n parentNode.insertBefore(b[--bEnd]!, node)\n // Update reference in old array for potential future matches\n a[aEnd] = b[bEnd]!\n }\n // 5b. Map fallback - use Map for complex rearrangements\n else {\n // Build map on first use (lazy initialization)\n if (!map) {\n map = new Map()\n let i = bStart\n while (i < bEnd) {\n map.set(b[i]!, i++)\n }\n }\n\n const index = map.get(a[aStart]!)\n\n if (index != null) {\n if (bStart < index && index < bEnd) {\n // Check for longest increasing subsequence\n let i = aStart\n let sequence = 1\n let t: number | undefined\n\n while (++i < aEnd && i < bEnd) {\n t = map.get(a[i]!)\n if (t == null || t !== index + sequence) break\n sequence++\n }\n\n // Use optimal strategy based on sequence length\n if (sequence > index - bStart) {\n // Sequence is long enough - insert nodes before current\n const node = a[aStart]!\n while (bStart < index) {\n parentNode.insertBefore(b[bStart++]!, node)\n }\n } else {\n // Short sequence - replace\n parentNode.replaceChild(b[bStart++]!, a[aStart++]!)\n }\n } else {\n aStart++\n }\n } else {\n // Node not in new array - remove it\n const nodeToRemove = a[aStart++]!\n nodeToRemove.parentNode?.removeChild(nodeToRemove)\n }\n }\n }\n}\n\n/**\n * Simple reconciliation for keyed lists.\n * Uses the same algorithm but works with keyed blocks.\n *\n * @param parentNode - The parent element\n * @param oldNodes - Old nodes in DOM order\n * @param newNodes - New nodes in target order\n */\nexport function reconcileNodes(parentNode: ParentNode, oldNodes: Node[], newNodes: Node[]): void {\n reconcileArrays(parentNode, oldNodes, newNodes)\n}\n","/**\n * List Helpers for Compiler-Generated Fine-Grained Updates\n *\n * These helpers are used by the compiler to generate efficient keyed list rendering.\n * They provide low-level primitives for DOM node manipulation without rebuilding.\n */\n\nimport { createElement } from './dom'\nimport { createRenderEffect } from './effect'\nimport {\n createRootContext,\n destroyRoot,\n flushOnMount,\n getCurrentRoot,\n popRoot,\n pushRoot,\n type RootContext,\n} from './lifecycle'\nimport { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'\nimport reconcileArrays from './reconcile'\nimport { batch } from './scheduler'\nimport { createSignal, effectScope, flush, setActiveSub, type Signal } from './signal'\nimport type { FictNode } from './types'\n\n// Re-export shared DOM helpers for compiler-generated code\nexport { insertNodesBefore, removeNodes, toNodeArray }\n\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A keyed block represents a single item in a list with its associated DOM nodes and state\n */\ninterface KeyedBlock<T = unknown> {\n /** Unique key for this block */\n key: string | number\n /** DOM nodes belonging to this block */\n nodes: Node[]\n /** Root context for lifecycle management */\n root: RootContext\n /** Signal containing the current item value */\n item: Signal<T>\n /** Signal containing the current index */\n index: Signal<number>\n /** Last raw item value assigned to this block */\n rawItem: T\n /** Last raw index value assigned to this block */\n rawIndex: number\n}\n\n/**\n * Container for managing keyed list blocks\n */\ninterface KeyedListContainer<T = unknown> {\n /** Start marker comment node */\n startMarker: Comment\n /** End marker comment node */\n endMarker: Comment\n /** Map of key to block */\n blocks: Map<string | number, KeyedBlock<T>>\n /** Scratch map reused for the next render */\n nextBlocks: Map<string | number, KeyedBlock<T>>\n /** Current nodes in DOM order (including markers) */\n currentNodes: Node[]\n /** Next-frame node buffer to avoid reallocations */\n nextNodes: Node[]\n /** Ordered blocks in current DOM order */\n orderedBlocks: KeyedBlock<T>[]\n /** Next-frame ordered block buffer to avoid reallocations */\n nextOrderedBlocks: KeyedBlock<T>[]\n /** Track position of keys in the ordered buffer to handle duplicates */\n orderedIndexByKey: Map<string | number, number>\n /** Cleanup function */\n dispose: () => void\n}\n\n/**\n * Binding handle returned by createKeyedList for compiler-generated code\n */\nexport interface KeyedListBinding {\n /** Document fragment placeholder inserted by the compiler/runtime */\n marker: DocumentFragment\n /** Start marker comment node */\n startMarker: Comment\n /** End marker comment node */\n endMarker: Comment\n /** Flush pending items - call after markers are inserted into DOM */\n flush?: () => void\n /** Cleanup function */\n dispose: () => void\n}\n\ntype FineGrainedRenderItem<T> = (\n itemSig: Signal<T>,\n indexSig: Signal<number>,\n key: string | number,\n) => Node[]\n\n// ============================================================================\n// DOM Manipulation Primitives\n// ============================================================================\n\n/**\n * Move nodes to a position before the anchor node.\n * This is optimized to avoid unnecessary DOM operations.\n *\n * @param parent - Parent node to move nodes within\n * @param nodes - Array of nodes to move\n * @param anchor - Node to insert before (or null for end)\n */\nexport function moveNodesBefore(parent: Node, nodes: Node[], anchor: Node | null): void {\n // Insert in reverse order to maintain correct sequence\n // This way each node becomes the new anchor for the next\n for (let i = nodes.length - 1; i >= 0; i--) {\n const node = nodes[i]!\n if (!node || !(node instanceof Node)) {\n const message = isDev ? 'Invalid node in moveNodesBefore' : 'FICT:E_NODE'\n throw new Error(message)\n }\n // Only move if not already in correct position\n if (node.nextSibling !== anchor) {\n if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {\n parent.ownerDocument.adoptNode(node)\n }\n try {\n parent.insertBefore(node, anchor)\n } catch (e: any) {\n if (parent.ownerDocument) {\n try {\n const clone = parent.ownerDocument.importNode(node, true)\n parent.insertBefore(clone, anchor)\n // Update the nodes array with the clone to maintain correct references.\n // This ensures future operations (like removal or reordering) work correctly.\n nodes[i] = clone\n if (isDev) {\n console.warn(\n `[fict] Node cloning fallback triggered during list reordering. ` +\n `This may indicate cross-document node insertion. ` +\n `The node reference has been updated to the clone.`,\n )\n }\n anchor = clone\n continue\n } catch {\n // Clone fallback failed\n }\n }\n throw e\n }\n }\n anchor = node\n }\n}\n\n/**\n * Remove an array of nodes from the DOM\n *\n * @param nodes - Array of nodes to remove\n */\n// Number.MAX_SAFE_INTEGER is 2^53 - 1, but we reset earlier to avoid any precision issues\nconst MAX_SAFE_VERSION = 0x1fffffffffffff // 2^53 - 1\n\nexport function createVersionedSignalAccessor<T>(initialValue: T): Signal<T> {\n let current = initialValue\n let version = 0\n const track = createSignal(version)\n\n function accessor(value?: T): T | void {\n if (arguments.length === 0) {\n track()\n return current\n }\n current = value as T\n // This is safe because we only care about version changes, not absolute values\n version = version >= MAX_SAFE_VERSION ? 1 : version + 1\n track(version)\n }\n\n return accessor as Signal<T>\n}\n\n// ============================================================================\n// Keyed List Container\n// ============================================================================\n\n/**\n * Create a container for managing a keyed list.\n * This sets up the marker nodes and provides cleanup.\n *\n * @returns Container object with markers, blocks map, and dispose function\n */\nfunction createKeyedListContainer<T = unknown>(): KeyedListContainer<T> {\n const startMarker = document.createComment('fict:list:start')\n const endMarker = document.createComment('fict:list:end')\n\n const dispose = () => {\n // Clean up all blocks\n for (const block of container.blocks.values()) {\n destroyRoot(block.root)\n // Nodes are removed by parent disposal or specific cleanup if needed\n // But for list disposal, we just clear the container\n }\n container.blocks.clear()\n container.nextBlocks.clear()\n\n // Remove nodes (including markers)\n // Check if markers are still in DOM before using Range\n if (!startMarker.parentNode || !endMarker.parentNode) {\n // Markers already removed, nothing to do\n container.currentNodes = []\n container.nextNodes = []\n container.orderedBlocks.length = 0\n container.nextOrderedBlocks.length = 0\n container.orderedIndexByKey.clear()\n return\n }\n const range = document.createRange()\n range.setStartBefore(startMarker)\n range.setEndAfter(endMarker)\n range.deleteContents()\n\n // Clear cache\n container.currentNodes = []\n container.nextNodes = []\n container.nextBlocks.clear()\n container.orderedBlocks.length = 0\n container.nextOrderedBlocks.length = 0\n container.orderedIndexByKey.clear()\n }\n\n const container: KeyedListContainer<T> = {\n startMarker,\n endMarker,\n blocks: new Map<string | number, KeyedBlock<T>>(),\n nextBlocks: new Map<string | number, KeyedBlock<T>>(),\n currentNodes: [startMarker, endMarker],\n nextNodes: [],\n orderedBlocks: [],\n nextOrderedBlocks: [],\n orderedIndexByKey: new Map<string | number, number>(),\n dispose,\n }\n\n return container\n}\n\n// ============================================================================\n// Block Creation Helpers\n// ============================================================================\n\n/**\n * Create a new keyed block with the given render function\n *\n * @param key - Unique key for this block\n * @param item - Initial item value\n * @param index - Initial index\n * @param render - Function that creates the DOM nodes and sets up bindings\n * @returns New KeyedBlock\n */\nfunction createKeyedBlock<T>(\n key: string | number,\n item: T,\n index: number,\n render: (item: Signal<T>, index: Signal<number>, key: string | number) => Node[],\n needsIndex = true,\n hostRoot?: RootContext,\n): KeyedBlock<T> {\n // Use versioned signal for all item types; avoid diffing proxy overhead for objects\n const itemSig = createVersionedSignalAccessor(item)\n\n const indexSig = needsIndex\n ? createSignal<number>(index)\n : (((next?: number) => {\n if (arguments.length === 0) return index\n index = next as number\n return index\n }) as Signal<number>)\n const root = createRootContext(hostRoot)\n const prevRoot = pushRoot(root)\n // maintaining proper cleanup chain. The scope will be disposed when\n // the root is destroyed, ensuring nested effects are properly cleaned up.\n let nodes: Node[] = []\n let scopeDispose: (() => void) | undefined\n\n // First, isolate from parent effect to prevent child effects from being\n // purged when the outer effect (e.g., performDiff) re-runs\n const prevSub = setActiveSub(undefined)\n\n try {\n // Create an effectScope that will track all effects created during render\n scopeDispose = effectScope(() => {\n const rendered = render(itemSig, indexSig, key)\n // If render returns real DOM nodes/arrays, preserve them to avoid\n // reparenting side-effects (tests may pre-insert them).\n if (\n rendered instanceof Node ||\n (Array.isArray(rendered) && rendered.every(n => n instanceof Node))\n ) {\n nodes = toNodeArray(rendered)\n } else {\n const element = createElement(rendered as unknown as FictNode)\n nodes = toNodeArray(element)\n }\n })\n\n // Register the scope cleanup with the root so effects are cleaned up\n // when the block is destroyed\n if (scopeDispose) {\n root.cleanups.push(scopeDispose)\n }\n } finally {\n setActiveSub(prevSub)\n popRoot(prevRoot)\n }\n\n return {\n key,\n nodes,\n root,\n item: itemSig,\n index: indexSig,\n rawItem: item,\n rawIndex: index,\n }\n}\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\n/**\n * Check if a node is between two markers\n */\nexport function isNodeBetweenMarkers(\n node: Node,\n startMarker: Comment,\n endMarker: Comment,\n): boolean {\n let current: Node | null = startMarker.nextSibling\n while (current && current !== endMarker) {\n if (current === node) return true\n current = current.nextSibling\n }\n return false\n}\n\nfunction reorderBySwap<T>(\n parent: ParentNode & Node,\n first: KeyedBlock<T>,\n second: KeyedBlock<T>,\n): boolean {\n if (first === second) return false\n const firstNodes = first.nodes\n const secondNodes = second.nodes\n if (firstNodes.length === 0 || secondNodes.length === 0) return false\n const lastFirst = firstNodes[firstNodes.length - 1]!\n const lastSecond = secondNodes[secondNodes.length - 1]!\n const afterFirst = lastFirst.nextSibling\n const afterSecond = lastSecond.nextSibling\n moveNodesBefore(parent, firstNodes, afterSecond)\n moveNodesBefore(parent, secondNodes, afterFirst)\n return true\n}\n\nfunction getLISIndices(sequence: number[]): number[] {\n const predecessors = new Array<number>(sequence.length)\n const result: number[] = []\n\n for (let i = 0; i < sequence.length; i++) {\n const value = sequence[i]!\n if (value < 0) {\n predecessors[i] = -1\n continue\n }\n\n let low = 0\n let high = result.length\n while (low < high) {\n const mid = (low + high) >> 1\n if (sequence[result[mid]!]! < value) {\n low = mid + 1\n } else {\n high = mid\n }\n }\n\n predecessors[i] = low > 0 ? result[low - 1]! : -1\n if (low === result.length) {\n result.push(i)\n } else {\n result[low] = i\n }\n }\n\n const lis: number[] = new Array(result.length)\n let k = result.length > 0 ? result[result.length - 1]! : -1\n for (let i = result.length - 1; i >= 0; i--) {\n lis[i] = k\n k = predecessors[k]!\n }\n return lis\n}\n\nfunction reorderByLIS<T>(\n parent: ParentNode & Node,\n endMarker: Comment,\n prev: KeyedBlock<T>[],\n next: KeyedBlock<T>[],\n): boolean {\n const positions = new Map<KeyedBlock<T>, number>()\n for (let i = 0; i < prev.length; i++) {\n positions.set(prev[i]!, i)\n }\n\n const sequence = new Array<number>(next.length)\n for (let i = 0; i < next.length; i++) {\n const position = positions.get(next[i]!)\n if (position === undefined) return false\n sequence[i] = position\n }\n\n const lisIndices = getLISIndices(sequence)\n if (lisIndices.length === sequence.length) return true\n\n const inLIS = new Array<boolean>(sequence.length).fill(false)\n for (let i = 0; i < lisIndices.length; i++) {\n inLIS[lisIndices[i]!] = true\n }\n\n let anchor: Node | null = endMarker\n let moved = false\n for (let i = next.length - 1; i >= 0; i--) {\n const block = next[i]!\n const nodes = block.nodes\n if (nodes.length === 0) continue\n if (inLIS[i]) {\n anchor = nodes[0]!\n continue\n }\n moveNodesBefore(parent, nodes, anchor)\n anchor = nodes[0]!\n moved = true\n }\n\n return moved\n}\n\n// ============================================================================\n// High-Level List Binding (for compiler-generated code)\n// ============================================================================\n\n/**\n * Create a keyed list binding with automatic diffing and DOM updates.\n * This is used by compiler-generated code for efficient list rendering.\n *\n * @param getItems - Function that returns the current array of items\n * @param keyFn - Function to extract unique key from each item\n * @param renderItem - Function that creates DOM nodes for each item\n * @returns Binding handle with markers and dispose function\n */\nexport function createKeyedList<T>(\n getItems: () => T[],\n keyFn: (item: T, index: number) => string | number,\n renderItem: FineGrainedRenderItem<T>,\n needsIndex?: boolean,\n): KeyedListBinding {\n const resolvedNeedsIndex =\n arguments.length >= 4 ? !!needsIndex : renderItem.length > 1 /* has index param */\n return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex)\n}\n\nfunction createFineGrainedKeyedList<T>(\n getItems: () => T[],\n keyFn: (item: T, index: number) => string | number,\n renderItem: FineGrainedRenderItem<T>,\n needsIndex: boolean,\n): KeyedListBinding {\n const container = createKeyedListContainer<T>()\n const hostRoot = getCurrentRoot()\n const fragment = document.createDocumentFragment()\n fragment.append(container.startMarker, container.endMarker)\n let disposed = false\n let effectDispose: (() => void) | undefined\n let connectObserver: MutationObserver | null = null\n let effectStarted = false\n let startScheduled = false\n\n const getConnectedParent = (): (ParentNode & Node) | null => {\n const endParent = container.endMarker.parentNode\n const startParent = container.startMarker.parentNode\n if (\n endParent &&\n startParent &&\n endParent === startParent &&\n (endParent as Node).nodeType !== 11\n ) {\n const parentNode = endParent as ParentNode & Node\n if ('isConnected' in parentNode && !parentNode.isConnected) return null\n return parentNode\n }\n return null\n }\n\n const performDiff = () => {\n if (disposed) return\n const parent = getConnectedParent()\n if (!parent) return\n batch(() => {\n const oldBlocks = container.blocks\n const newBlocks = container.nextBlocks\n const prevOrderedBlocks = container.orderedBlocks\n const nextOrderedBlocks = container.nextOrderedBlocks\n const orderedIndexByKey = container.orderedIndexByKey\n const newItems = getItems()\n\n if (newItems.length === 0) {\n if (oldBlocks.size > 0) {\n // Destroy all block roots first\n for (const block of oldBlocks.values()) {\n destroyRoot(block.root)\n }\n // Use Range.deleteContents for efficient bulk DOM removal\n const range = document.createRange()\n range.setStartAfter(container.startMarker)\n range.setEndBefore(container.endMarker)\n range.deleteContents()\n }\n oldBlocks.clear()\n newBlocks.clear()\n prevOrderedBlocks.length = 0\n nextOrderedBlocks.length = 0\n orderedIndexByKey.clear()\n container.currentNodes.length = 0\n container.currentNodes.push(container.startMarker, container.endMarker)\n container.nextNodes.length = 0\n return\n }\n\n const prevCount = prevOrderedBlocks.length\n if (prevCount > 0 && newItems.length === prevCount && orderedIndexByKey.size === prevCount) {\n let stableOrder = true\n const seen = new Set<string | number>()\n for (let i = 0; i < prevCount; i++) {\n const item = newItems[i]!\n const key = keyFn(item, i)\n if (seen.has(key) || prevOrderedBlocks[i]!.key !== key) {\n stableOrder = false\n break\n }\n seen.add(key)\n }\n if (stableOrder) {\n for (let i = 0; i < prevCount; i++) {\n const item = newItems[i]!\n const block = prevOrderedBlocks[i]!\n if (block.rawItem !== item) {\n block.rawItem = item\n block.item(item)\n }\n if (needsIndex && block.rawIndex !== i) {\n block.rawIndex = i\n block.index(i)\n }\n }\n return\n }\n }\n\n newBlocks.clear()\n nextOrderedBlocks.length = 0\n orderedIndexByKey.clear()\n const createdBlocks: KeyedBlock<T>[] = []\n let appendCandidate = prevCount > 0 && newItems.length >= prevCount\n const appendedBlocks: KeyedBlock<T>[] = []\n let mismatchCount = 0\n let mismatchFirst = -1\n let mismatchSecond = -1\n let hasDuplicateKey = false\n\n // Phase 1: Build new blocks map (reuse or create)\n newItems.forEach((item, index) => {\n const key = keyFn(item, index)\n // Micro-optimization: single Map.get instead of has+get\n let block = oldBlocks.get(key)\n const existed = block !== undefined\n\n if (block) {\n if (block.rawItem !== item) {\n block.rawItem = item\n block.item(item)\n }\n if (needsIndex && block.rawIndex !== index) {\n block.rawIndex = index\n block.index(index)\n }\n }\n\n if (block) {\n // Reusing existing block from oldBlocks\n newBlocks.set(key, block)\n oldBlocks.delete(key)\n } else {\n // If newBlocks already has this key (duplicate key case), clean up the previous block\n const existingBlock = newBlocks.get(key)\n if (existingBlock) {\n if (isDev) {\n console.warn(\n `[fict] Duplicate key \"${String(key)}\" detected in list rendering. ` +\n `Each item should have a unique key. The previous item with this key will be replaced.`,\n )\n }\n destroyRoot(existingBlock.root)\n removeNodes(existingBlock.nodes)\n }\n // Create new block\n block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot)\n createdBlocks.push(block)\n }\n\n const resolvedBlock = block\n\n newBlocks.set(key, resolvedBlock)\n\n // Micro-optimization: single Map.get instead of checking position multiple times\n const position = orderedIndexByKey.get(key)\n if (position !== undefined) {\n appendCandidate = false\n hasDuplicateKey = true\n const prior = nextOrderedBlocks[position]\n if (prior && prior !== resolvedBlock) {\n destroyRoot(prior.root)\n removeNodes(prior.nodes)\n }\n nextOrderedBlocks[position] = resolvedBlock\n } else {\n if (appendCandidate) {\n if (index < prevCount) {\n if (!prevOrderedBlocks[index] || prevOrderedBlocks[index]!.key !== key) {\n appendCandidate = false\n }\n } else if (existed) {\n appendCandidate = false\n }\n }\n const nextIndex = nextOrderedBlocks.length\n orderedIndexByKey.set(key, nextIndex)\n nextOrderedBlocks.push(resolvedBlock)\n if (\n mismatchCount < 3 &&\n (nextIndex >= prevCount || prevOrderedBlocks[nextIndex] !== resolvedBlock)\n ) {\n if (mismatchCount === 0) {\n mismatchFirst = nextIndex\n } else if (mismatchCount === 1) {\n mismatchSecond = nextIndex\n }\n mismatchCount++\n }\n }\n\n if (appendCandidate && index >= prevCount) {\n appendedBlocks.push(resolvedBlock)\n }\n })\n\n const canAppend =\n appendCandidate &&\n prevCount > 0 &&\n newItems.length > prevCount &&\n oldBlocks.size === 0 &&\n appendedBlocks.length > 0\n if (canAppend) {\n const appendedNodes: Node[] = []\n for (const block of appendedBlocks) {\n for (let i = 0; i < block.nodes.length; i++) {\n appendedNodes.push(block.nodes[i]!)\n }\n }\n if (appendedNodes.length > 0) {\n insertNodesBefore(parent, appendedNodes, container.endMarker)\n const currentNodes = container.currentNodes\n currentNodes.pop()\n for (let i = 0; i < appendedNodes.length; i++) {\n currentNodes.push(appendedNodes[i]!)\n }\n currentNodes.push(container.endMarker)\n }\n\n container.blocks = newBlocks\n container.nextBlocks = oldBlocks\n container.orderedBlocks = nextOrderedBlocks\n container.nextOrderedBlocks = prevOrderedBlocks\n for (const block of createdBlocks) {\n if (newBlocks.get(block.key) === block) {\n flushOnMount(block.root)\n }\n }\n return\n }\n\n // Phase 2: Remove old blocks that are no longer in the list\n if (oldBlocks.size > 0) {\n for (const block of oldBlocks.values()) {\n destroyRoot(block.root)\n removeNodes(block.nodes)\n }\n oldBlocks.clear()\n }\n\n const canReorderInPlace =\n createdBlocks.length === 0 &&\n oldBlocks.size === 0 &&\n nextOrderedBlocks.length === prevOrderedBlocks.length\n\n let skipReconcile = false\n let updateNodeBuffer = true\n\n if (canReorderInPlace && nextOrderedBlocks.length > 0 && !hasDuplicateKey) {\n if (mismatchCount === 0) {\n skipReconcile = true\n updateNodeBuffer = false\n } else if (\n mismatchCount === 2 &&\n prevOrderedBlocks[mismatchFirst] === nextOrderedBlocks[mismatchSecond] &&\n prevOrderedBlocks[mismatchSecond] === nextOrderedBlocks[mismatchFirst]\n ) {\n if (\n reorderBySwap(\n parent,\n prevOrderedBlocks[mismatchFirst]!,\n prevOrderedBlocks[mismatchSecond]!,\n )\n ) {\n skipReconcile = true\n }\n } else if (\n reorderByLIS(parent, container.endMarker, prevOrderedBlocks, nextOrderedBlocks)\n ) {\n skipReconcile = true\n }\n }\n\n // Phase 3: Reconcile DOM with buffered node arrays\n if (!skipReconcile && (newBlocks.size > 0 || container.currentNodes.length > 0)) {\n const prevNodes = container.currentNodes\n const nextNodes = container.nextNodes\n nextNodes.length = 0\n nextNodes.push(container.startMarker)\n\n for (let i = 0; i < nextOrderedBlocks.length; i++) {\n const nodes = nextOrderedBlocks[i]!.nodes\n for (let j = 0; j < nodes.length; j++) {\n nextNodes.push(nodes[j]!)\n }\n }\n\n nextNodes.push(container.endMarker)\n\n reconcileArrays(parent, prevNodes, nextNodes)\n\n // Swap buffers to reuse arrays on next diff\n container.currentNodes = nextNodes\n container.nextNodes = prevNodes\n } else if (skipReconcile && updateNodeBuffer) {\n const prevNodes = container.currentNodes\n const nextNodes = container.nextNodes\n nextNodes.length = 0\n nextNodes.push(container.startMarker)\n for (let i = 0; i < nextOrderedBlocks.length; i++) {\n const nodes = nextOrderedBlocks[i]!.nodes\n for (let j = 0; j < nodes.length; j++) {\n nextNodes.push(nodes[j]!)\n }\n }\n nextNodes.push(container.endMarker)\n container.currentNodes = nextNodes\n container.nextNodes = prevNodes\n }\n\n // Swap block maps for reuse\n container.blocks = newBlocks\n container.nextBlocks = oldBlocks\n container.orderedBlocks = nextOrderedBlocks\n container.nextOrderedBlocks = prevOrderedBlocks\n for (const block of createdBlocks) {\n if (newBlocks.get(block.key) === block) {\n flushOnMount(block.root)\n }\n }\n })\n }\n\n const disconnectObserver = () => {\n connectObserver?.disconnect()\n connectObserver = null\n }\n\n const ensureEffectStarted = (): boolean => {\n if (disposed || effectStarted) return effectStarted\n const parent = getConnectedParent()\n if (!parent) return false\n const start = () => {\n effectDispose = createRenderEffect(performDiff)\n effectStarted = true\n }\n if (hostRoot) {\n const prev = pushRoot(hostRoot)\n try {\n start()\n } finally {\n popRoot(prev)\n }\n } else {\n start()\n }\n return true\n }\n\n const waitForConnection = () => {\n if (connectObserver || typeof MutationObserver === 'undefined') return\n connectObserver = new MutationObserver(() => {\n if (disposed) return\n if (getConnectedParent()) {\n disconnectObserver()\n if (ensureEffectStarted()) {\n flush()\n }\n }\n })\n connectObserver.observe(document, { childList: true, subtree: true })\n }\n\n const scheduleStart = () => {\n if (startScheduled || disposed || effectStarted) return\n startScheduled = true\n const run = () => {\n startScheduled = false\n if (!ensureEffectStarted()) {\n waitForConnection()\n }\n }\n if (typeof queueMicrotask === 'function') {\n queueMicrotask(run)\n } else {\n Promise.resolve()\n .then(run)\n .catch(() => undefined)\n }\n }\n\n scheduleStart()\n\n return {\n get marker() {\n scheduleStart()\n return fragment\n },\n startMarker: container.startMarker,\n endMarker: container.endMarker,\n // Flush pending items - call after markers are inserted into DOM\n flush: () => {\n if (disposed) return\n scheduleStart()\n if (ensureEffectStarted()) {\n flush()\n } else {\n waitForConnection()\n }\n },\n dispose: () => {\n disposed = true\n effectDispose?.()\n disconnectObserver()\n container.dispose()\n },\n }\n}\n"],"mappings":"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","names":["unwrap","prop","value","track","batch"]}
|
package/package.json
CHANGED
package/src/context.ts
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
47
|
import { createElement } from './dom'
|
|
48
|
+
import { createRenderEffect } from './effect'
|
|
48
49
|
import {
|
|
49
50
|
createRootContext,
|
|
50
51
|
destroyRoot,
|
|
@@ -55,7 +56,6 @@ import {
|
|
|
55
56
|
type RootContext,
|
|
56
57
|
} from './lifecycle'
|
|
57
58
|
import { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'
|
|
58
|
-
import { createRenderEffect } from './effect'
|
|
59
59
|
import type { BaseProps, FictNode } from './types'
|
|
60
60
|
|
|
61
61
|
// ============================================================================
|
package/src/dom.ts
CHANGED
|
@@ -687,7 +687,10 @@ const setProperty: AttributeSetter = (el: Element, key: string, value: unknown):
|
|
|
687
687
|
* Set innerHTML on an element (used for dangerouslySetInnerHTML)
|
|
688
688
|
*/
|
|
689
689
|
const setInnerHTML: AttributeSetter = (el: Element, _key: string, value: unknown): void => {
|
|
690
|
-
|
|
690
|
+
const next = value == null ? '' : String(value)
|
|
691
|
+
const node = el as HTMLElement
|
|
692
|
+
if (node.innerHTML === next) return
|
|
693
|
+
node.innerHTML = next
|
|
691
694
|
}
|
|
692
695
|
|
|
693
696
|
/**
|
package/src/error-boundary.ts
CHANGED
|
@@ -10,11 +10,10 @@ import {
|
|
|
10
10
|
registerErrorHandler,
|
|
11
11
|
} from './lifecycle'
|
|
12
12
|
import { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'
|
|
13
|
-
import { createSignal } from './signal'
|
|
14
13
|
import type { BaseProps, FictNode } from './types'
|
|
15
14
|
|
|
16
15
|
interface ErrorBoundaryProps extends BaseProps {
|
|
17
|
-
fallback: FictNode | ((err: unknown) => FictNode)
|
|
16
|
+
fallback: FictNode | ((err: unknown, reset?: () => void) => FictNode)
|
|
18
17
|
onError?: (err: unknown) => void
|
|
19
18
|
resetKeys?: unknown | (() => unknown)
|
|
20
19
|
}
|
|
@@ -24,17 +23,17 @@ export function ErrorBoundary(props: ErrorBoundaryProps): FictNode {
|
|
|
24
23
|
const marker = document.createComment('fict:error-boundary')
|
|
25
24
|
fragment.appendChild(marker)
|
|
26
25
|
|
|
27
|
-
const currentView = createSignal<FictNode | null>(props.children ?? null)
|
|
28
26
|
const hostRoot = getCurrentRoot()
|
|
29
27
|
|
|
30
28
|
let cleanup: (() => void) | undefined
|
|
31
29
|
let activeNodes: Node[] = []
|
|
32
30
|
let renderingFallback = false
|
|
33
31
|
|
|
32
|
+
let reset = () => {}
|
|
34
33
|
const toView = (err: unknown | null): FictNode | null => {
|
|
35
34
|
if (err != null) {
|
|
36
35
|
return typeof props.fallback === 'function'
|
|
37
|
-
? (props.fallback as (e: unknown) => FictNode)(err)
|
|
36
|
+
? (props.fallback as (e: unknown, reset?: () => void) => FictNode)(err, reset)
|
|
38
37
|
: props.fallback
|
|
39
38
|
}
|
|
40
39
|
return props.children ?? null
|
|
@@ -66,7 +65,6 @@ export function ErrorBoundary(props: ErrorBoundaryProps): FictNode {
|
|
|
66
65
|
}
|
|
67
66
|
} catch (err) {
|
|
68
67
|
popRoot(prev)
|
|
69
|
-
flushOnMount(root)
|
|
70
68
|
destroyRoot(root)
|
|
71
69
|
// Fall back immediately on render errors, avoid infinite recursion
|
|
72
70
|
if (renderingFallback) {
|
|
@@ -100,10 +98,12 @@ export function ErrorBoundary(props: ErrorBoundaryProps): FictNode {
|
|
|
100
98
|
activeNodes = nodes
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
renderValue(
|
|
106
|
-
}
|
|
101
|
+
reset = () => {
|
|
102
|
+
renderingFallback = false
|
|
103
|
+
renderValue(toView(null))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
renderValue(props.children ?? null)
|
|
107
107
|
|
|
108
108
|
registerErrorHandler(err => {
|
|
109
109
|
renderValue(toView(err))
|
package/src/signal.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
registerRootCleanup,
|
|
8
8
|
type RootContext,
|
|
9
9
|
} from './lifecycle'
|
|
10
|
+
import type { SuspenseToken } from './types'
|
|
10
11
|
|
|
11
12
|
const isDev =
|
|
12
13
|
typeof __DEV__ !== 'undefined'
|
|
@@ -820,7 +821,7 @@ function runEffect(e: EffectNode): void {
|
|
|
820
821
|
try {
|
|
821
822
|
isDirty = checkDirty(e.deps, e)
|
|
822
823
|
} catch (err) {
|
|
823
|
-
if (handleSuspend(err as
|
|
824
|
+
if (handleSuspend(err as SuspenseToken, e.root)) {
|
|
824
825
|
if (e.flags !== 0) {
|
|
825
826
|
e.flags = Watching
|
|
826
827
|
}
|
package/src/store.ts
CHANGED
|
@@ -35,17 +35,17 @@ export function createStore<T extends object>(
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Map of target object -> Proxy
|
|
38
|
-
const proxyCache = new WeakMap<object,
|
|
38
|
+
const proxyCache = new WeakMap<object, unknown>()
|
|
39
39
|
// Map of target object -> Map<key, Signal>
|
|
40
|
-
const signalCache = new WeakMap<object, Map<string | symbol, SignalAccessor<
|
|
40
|
+
const signalCache = new WeakMap<object, Map<string | symbol, SignalAccessor<unknown>>>()
|
|
41
41
|
|
|
42
42
|
function wrap<T>(value: T): T {
|
|
43
43
|
if (value === null || typeof value !== 'object') return value
|
|
44
|
-
if ((value
|
|
44
|
+
if (Reflect.get(value, PROXY)) return value
|
|
45
45
|
|
|
46
|
-
if (proxyCache.has(value)) return proxyCache.get(value)
|
|
46
|
+
if (proxyCache.has(value)) return proxyCache.get(value) as T
|
|
47
47
|
|
|
48
|
-
const handler: ProxyHandler<
|
|
48
|
+
const handler: ProxyHandler<object> = {
|
|
49
49
|
get(target, prop, receiver) {
|
|
50
50
|
if (prop === PROXY) return true
|
|
51
51
|
if (prop === TARGET) return target
|
|
@@ -74,6 +74,8 @@ function wrap<T>(value: T): T {
|
|
|
74
74
|
set(target, prop, value, receiver) {
|
|
75
75
|
if (prop === PROXY || prop === TARGET) return false
|
|
76
76
|
|
|
77
|
+
const isArrayLength = Array.isArray(target) && prop === 'length'
|
|
78
|
+
const oldLength = isArrayLength ? target.length : undefined
|
|
77
79
|
const hadKey = Object.prototype.hasOwnProperty.call(target, prop)
|
|
78
80
|
const oldValue = Reflect.get(target, prop, receiver)
|
|
79
81
|
if (oldValue === value) return true
|
|
@@ -84,6 +86,23 @@ function wrap<T>(value: T): T {
|
|
|
84
86
|
if (!hadKey) {
|
|
85
87
|
trigger(target, ITERATE_KEY)
|
|
86
88
|
}
|
|
89
|
+
if (isArrayLength) {
|
|
90
|
+
const nextLength = target.length
|
|
91
|
+
if (typeof oldLength === 'number' && nextLength < oldLength) {
|
|
92
|
+
const signals = signalCache.get(target)
|
|
93
|
+
if (signals) {
|
|
94
|
+
for (const key of signals.keys()) {
|
|
95
|
+
if (typeof key !== 'string') continue
|
|
96
|
+
const index = Number(key)
|
|
97
|
+
if (!Number.isInteger(index) || String(index) !== key) continue
|
|
98
|
+
if (index >= nextLength && index < oldLength) {
|
|
99
|
+
trigger(target, key)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
trigger(target, ITERATE_KEY)
|
|
105
|
+
}
|
|
87
106
|
}
|
|
88
107
|
return result
|
|
89
108
|
},
|
|
@@ -106,8 +125,8 @@ function wrap<T>(value: T): T {
|
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
function unwrap<T>(value: T): T {
|
|
109
|
-
if (value && typeof value === 'object' && (value
|
|
110
|
-
return (value as
|
|
128
|
+
if (value && typeof value === 'object' && Reflect.get(value, PROXY)) {
|
|
129
|
+
return Reflect.get(value, TARGET) as T
|
|
111
130
|
}
|
|
112
131
|
return value
|
|
113
132
|
}
|
|
@@ -143,14 +162,14 @@ function trigger(target: object, prop: string | symbol) {
|
|
|
143
162
|
}
|
|
144
163
|
}
|
|
145
164
|
|
|
146
|
-
function getLastValue(target:
|
|
147
|
-
return target
|
|
165
|
+
function getLastValue(target: object, prop: string | symbol) {
|
|
166
|
+
return Reflect.get(target, prop)
|
|
148
167
|
}
|
|
149
168
|
|
|
150
169
|
/**
|
|
151
170
|
* Reconcile a store path with a new value (shallow merge/diff)
|
|
152
171
|
*/
|
|
153
|
-
function reconcile(target:
|
|
172
|
+
function reconcile(target: object, value: unknown) {
|
|
154
173
|
if (target === value) return
|
|
155
174
|
if (value === null || typeof value !== 'object') {
|
|
156
175
|
throw new Error(
|
|
@@ -165,16 +184,19 @@ function reconcile(target: any, value: any) {
|
|
|
165
184
|
|
|
166
185
|
const keys = new Set([...Object.keys(realTarget), ...Object.keys(realValue)])
|
|
167
186
|
for (const key of keys) {
|
|
168
|
-
|
|
187
|
+
const rTarget = realTarget as Record<string, unknown>
|
|
188
|
+
const rValue = realValue as Record<string, unknown>
|
|
189
|
+
|
|
190
|
+
if (rValue[key] === undefined && rTarget[key] !== undefined) {
|
|
169
191
|
// deleted
|
|
170
|
-
delete target[key] // Triggers proxy trap
|
|
171
|
-
} else if (
|
|
172
|
-
target[key] =
|
|
192
|
+
delete (target as Record<string, unknown>)[key] // Triggers proxy trap
|
|
193
|
+
} else if (rTarget[key] !== rValue[key]) {
|
|
194
|
+
;(target as Record<string, unknown>)[key] = rValue[key] // Triggers proxy trap
|
|
173
195
|
}
|
|
174
196
|
}
|
|
175
197
|
|
|
176
198
|
// Fix array length if needed
|
|
177
|
-
if (Array.isArray(target) && target.length !== realValue.length) {
|
|
199
|
+
if (Array.isArray(target) && Array.isArray(realValue) && target.length !== realValue.length) {
|
|
178
200
|
target.length = realValue.length
|
|
179
201
|
}
|
|
180
202
|
}
|
|
@@ -190,13 +212,13 @@ function reconcile(target: any, value: any) {
|
|
|
190
212
|
*/
|
|
191
213
|
export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
192
214
|
let currentValue = unwrap(initialValue)
|
|
193
|
-
const signals = new Map<string | symbol, SignalAccessor<
|
|
215
|
+
const signals = new Map<string | symbol, SignalAccessor<unknown>>()
|
|
194
216
|
let iterateSignal: SignalAccessor<number> | undefined
|
|
195
217
|
|
|
196
218
|
const getPropSignal = (prop: string | symbol) => {
|
|
197
219
|
let s = signals.get(prop)
|
|
198
220
|
if (!s) {
|
|
199
|
-
s = signal((currentValue as
|
|
221
|
+
s = signal(Reflect.get(currentValue as object, prop))
|
|
200
222
|
signals.set(prop, s)
|
|
201
223
|
}
|
|
202
224
|
return s
|
|
@@ -250,7 +272,7 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
|
250
272
|
// Same ref update: re-evaluate all tracked signals
|
|
251
273
|
// This is necessary for in-place mutations
|
|
252
274
|
for (const [prop, s] of signals) {
|
|
253
|
-
const newVal = (next as
|
|
275
|
+
const newVal = Reflect.get(next as object, prop)
|
|
254
276
|
s(newVal)
|
|
255
277
|
}
|
|
256
278
|
updateIterate(next)
|
|
@@ -261,8 +283,8 @@ export function createDiffingSignal<T extends object>(initialValue: T) {
|
|
|
261
283
|
// We only trigger signals for properties that exist in our cache (tracked)
|
|
262
284
|
// and have changed.
|
|
263
285
|
for (const [prop, s] of signals) {
|
|
264
|
-
const oldVal = (prev as
|
|
265
|
-
const newVal = (next as
|
|
286
|
+
const oldVal = Reflect.get(prev as object, prop)
|
|
287
|
+
const newVal = Reflect.get(next as object, prop)
|
|
266
288
|
if (oldVal !== newVal) {
|
|
267
289
|
s(newVal)
|
|
268
290
|
}
|
package/src/suspense.ts
CHANGED
|
@@ -49,7 +49,6 @@ const isThenable = (value: unknown): value is PromiseLike<unknown> =>
|
|
|
49
49
|
typeof (value as PromiseLike<unknown>).then === 'function'
|
|
50
50
|
|
|
51
51
|
export function Suspense(props: SuspenseProps): FictNode {
|
|
52
|
-
const currentView = createSignal<FictNode | null>(props.children ?? null)
|
|
53
52
|
const pending = createSignal(0)
|
|
54
53
|
let resolvedOnce = false
|
|
55
54
|
let epoch = 0
|
|
@@ -97,7 +96,6 @@ export function Suspense(props: SuspenseProps): FictNode {
|
|
|
97
96
|
}
|
|
98
97
|
} catch (err) {
|
|
99
98
|
popRoot(prev)
|
|
100
|
-
flushOnMount(root)
|
|
101
99
|
destroyRoot(root)
|
|
102
100
|
if (!handleError(err, { source: 'render' }, hostRoot)) {
|
|
103
101
|
throw err
|
|
@@ -132,7 +130,6 @@ export function Suspense(props: SuspenseProps): FictNode {
|
|
|
132
130
|
pending(pending() + 1)
|
|
133
131
|
// Directly render fallback instead of using switchView to avoid
|
|
134
132
|
// triggering the effect which would cause duplicate renders
|
|
135
|
-
currentView(toFallback())
|
|
136
133
|
renderView(toFallback())
|
|
137
134
|
|
|
138
135
|
const thenable = (token as SuspenseToken).then
|
|
@@ -157,7 +154,6 @@ export function Suspense(props: SuspenseProps): FictNode {
|
|
|
157
154
|
pending(newPending)
|
|
158
155
|
if (newPending === 0) {
|
|
159
156
|
// Directly render children instead of using switchView
|
|
160
|
-
currentView(props.children ?? null)
|
|
161
157
|
renderView(props.children ?? null)
|
|
162
158
|
onResolveMaybe()
|
|
163
159
|
}
|
|
@@ -198,7 +194,6 @@ export function Suspense(props: SuspenseProps): FictNode {
|
|
|
198
194
|
epoch++
|
|
199
195
|
pending(0)
|
|
200
196
|
// Directly render children instead of using switchView
|
|
201
|
-
currentView(props.children ?? null)
|
|
202
197
|
renderView(props.children ?? null)
|
|
203
198
|
}
|
|
204
199
|
})
|