@askrjs/askr 0.0.46 → 0.0.47
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/benchmark.js +2 -2
- package/dist/renderer/cleanup.js +33 -1
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/dom.js +31 -11
- package/dist/renderer/dom.js.map +1 -1
- package/dist/renderer/reconcile.js +34 -19
- package/dist/renderer/reconcile.js.map +1 -1
- package/package.json +3 -3
|
@@ -9,6 +9,19 @@ import { evaluateCaseState, evaluateShowState } from "../runtime/control.js";
|
|
|
9
9
|
import { applyRendererFastPath } from "./fastpath.js";
|
|
10
10
|
import { performBulkPositionalKeyedTextUpdate } from "./children.js";
|
|
11
11
|
import { createDOMNode, syncComponentElement, updateElementFromVnode } from "./dom.js";
|
|
12
|
+
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
13
|
+
function getParentNamespace(parent) {
|
|
14
|
+
return parent.namespaceURI === SVG_NAMESPACE ? SVG_NAMESPACE : void 0;
|
|
15
|
+
}
|
|
16
|
+
function resolveChildNamespace(type, parentNamespace) {
|
|
17
|
+
if (type === "svg") return SVG_NAMESPACE;
|
|
18
|
+
if (parentNamespace === SVG_NAMESPACE && type !== "foreignObject") return SVG_NAMESPACE;
|
|
19
|
+
}
|
|
20
|
+
function canReuseIntrinsicElementInNamespace(existing, type, parentNamespace) {
|
|
21
|
+
if (!tagNamesEqualIgnoreCase(existing.tagName, type)) return false;
|
|
22
|
+
const expectedNamespace = resolveChildNamespace(type, parentNamespace);
|
|
23
|
+
return expectedNamespace === void 0 ? true : existing.namespaceURI === expectedNamespace;
|
|
24
|
+
}
|
|
12
25
|
function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
|
|
13
26
|
const keyedVnodes = extractKeyedChildren(newChildren);
|
|
14
27
|
const ensuredOldKeyMap = oldKeyMap || buildKeyMapFromDOM(parent);
|
|
@@ -84,7 +97,7 @@ function tryPositionalBulkUpdate(parent, keyedVnodes) {
|
|
|
84
97
|
const total = keyedVnodes.length;
|
|
85
98
|
if (total < 10) return null;
|
|
86
99
|
if (parent.children.length !== total) return null;
|
|
87
|
-
const matchCount = countPositionalMatches(parent, keyedVnodes);
|
|
100
|
+
const matchCount = countPositionalMatches(parent, keyedVnodes, getParentNamespace(parent));
|
|
88
101
|
const matchFraction = matchCount / total;
|
|
89
102
|
if (keyedVnodes.length > 0) {
|
|
90
103
|
if (matchCount !== total && matchFraction >= .1) return null;
|
|
@@ -99,7 +112,7 @@ function tryPositionalBulkUpdate(parent, keyedVnodes) {
|
|
|
99
112
|
}
|
|
100
113
|
}
|
|
101
114
|
/** Count how many vnodes match parent children by position and tag */
|
|
102
|
-
function countPositionalMatches(parent, keyedVnodes) {
|
|
115
|
+
function countPositionalMatches(parent, keyedVnodes, parentNamespace) {
|
|
103
116
|
let matchCount = 0;
|
|
104
117
|
try {
|
|
105
118
|
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
@@ -108,7 +121,7 @@ function countPositionalMatches(parent, keyedVnodes) {
|
|
|
108
121
|
if (!vnode || typeof vnode !== "object" || typeof vnode.type !== "string") continue;
|
|
109
122
|
const el = parent.children[i];
|
|
110
123
|
if (!el) continue;
|
|
111
|
-
if (
|
|
124
|
+
if (canReuseIntrinsicElementInNamespace(el, vnode.type, parentNamespace)) {
|
|
112
125
|
const actualKey = el.getAttribute("data-key");
|
|
113
126
|
if (actualKey === String(expectedKey) || actualKey !== null && !Number.isNaN(Number(actualKey)) && Number(actualKey) === expectedKey) matchCount++;
|
|
114
127
|
}
|
|
@@ -219,7 +232,7 @@ function scanForElementByKey(parent, k, keyStr, usedOldEls) {
|
|
|
219
232
|
function reconcileSingleChild(child, index, parent, resolveOldElOnce, resolveUnkeyedOnce, usedOldEls, newKeyMap) {
|
|
220
233
|
const resolvedControlBoundary = prepareControlBoundaryResolution(child);
|
|
221
234
|
if (resolvedControlBoundary !== null) {
|
|
222
|
-
if (resolvedControlBoundary.remount) return createDOMNode(resolvedControlBoundary.vnode);
|
|
235
|
+
if (resolvedControlBoundary.remount) return createDOMNode(resolvedControlBoundary.vnode, getParentNamespace(parent));
|
|
223
236
|
return reconcileSingleChild(resolvedControlBoundary.vnode, index, parent, resolveOldElOnce, resolveUnkeyedOnce, usedOldEls, newKeyMap);
|
|
224
237
|
}
|
|
225
238
|
const key = extractKey(child);
|
|
@@ -229,24 +242,25 @@ function reconcileSingleChild(child, index, parent, resolveOldElOnce, resolveUnk
|
|
|
229
242
|
/** Reconcile a keyed child */
|
|
230
243
|
function reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap) {
|
|
231
244
|
const el = resolveOldElOnce(key);
|
|
245
|
+
const parentNamespace = getParentNamespace(parent);
|
|
232
246
|
if (el && el.parentElement === parent) try {
|
|
233
247
|
const childObj = child;
|
|
234
248
|
if (childObj && typeof childObj === "object" && typeof childObj.type === "string") {
|
|
235
|
-
if (
|
|
249
|
+
if (canReuseIntrinsicElementInNamespace(el, childObj.type, parentNamespace)) {
|
|
236
250
|
updateElementFromVnode(el, child);
|
|
237
251
|
newKeyMap.set(key, el);
|
|
238
252
|
return el;
|
|
239
253
|
}
|
|
240
254
|
}
|
|
241
255
|
if (isComponentVNode(child)) {
|
|
242
|
-
const synced = syncComponentElement(el, child, child.type, (child.props ?? {}) || {});
|
|
256
|
+
const synced = syncComponentElement(el, child, child.type, (child.props ?? {}) || {}, parentNamespace);
|
|
243
257
|
if (synced) {
|
|
244
258
|
if (synced instanceof Element) newKeyMap.set(key, synced);
|
|
245
259
|
return synced;
|
|
246
260
|
}
|
|
247
261
|
}
|
|
248
262
|
} catch {}
|
|
249
|
-
const dom = createDOMNode(child);
|
|
263
|
+
const dom = createDOMNode(child, parentNamespace);
|
|
250
264
|
if (dom) {
|
|
251
265
|
if (dom instanceof Element) newKeyMap.set(key, dom);
|
|
252
266
|
return dom;
|
|
@@ -255,6 +269,7 @@ function reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap) {
|
|
|
255
269
|
}
|
|
256
270
|
/** Reconcile an unkeyed or primitive child */
|
|
257
271
|
function reconcileUnkeyedChild(child, index, parent, resolveUnkeyedOnce, usedOldEls) {
|
|
272
|
+
const parentNamespace = getParentNamespace(parent);
|
|
258
273
|
try {
|
|
259
274
|
const existing = parent.childNodes[index];
|
|
260
275
|
if (typeof child === "string" || typeof child === "number") {
|
|
@@ -263,24 +278,24 @@ function reconcileUnkeyedChild(child, index, parent, resolveUnkeyedOnce, usedOld
|
|
|
263
278
|
usedOldEls.add(existing);
|
|
264
279
|
return existing;
|
|
265
280
|
}
|
|
266
|
-
return createDOMNode(child);
|
|
281
|
+
return createDOMNode(child, parentNamespace);
|
|
267
282
|
}
|
|
268
283
|
if (existing instanceof Element) {
|
|
269
|
-
const synced = trySyncComponentChild(existing, child, usedOldEls);
|
|
284
|
+
const synced = trySyncComponentChild(existing, child, usedOldEls, parentNamespace);
|
|
270
285
|
if (synced) return synced;
|
|
271
286
|
}
|
|
272
|
-
if (existing instanceof Element && canReuseElement(existing, child)) {
|
|
287
|
+
if (existing instanceof Element && canReuseElement(existing, child, parentNamespace)) {
|
|
273
288
|
updateElementFromVnode(existing, child);
|
|
274
289
|
usedOldEls.add(existing);
|
|
275
290
|
return existing;
|
|
276
291
|
}
|
|
277
292
|
const avail = resolveUnkeyedOnce();
|
|
278
293
|
if (avail) {
|
|
279
|
-
const reuseResult = tryReuseElement(avail, child, usedOldEls);
|
|
294
|
+
const reuseResult = tryReuseElement(avail, child, usedOldEls, parentNamespace);
|
|
280
295
|
if (reuseResult) return reuseResult;
|
|
281
296
|
}
|
|
282
297
|
} catch {}
|
|
283
|
-
return createDOMNode(child);
|
|
298
|
+
return createDOMNode(child, parentNamespace);
|
|
284
299
|
}
|
|
285
300
|
function isComponentVNode(child) {
|
|
286
301
|
return typeof child === "object" && child !== null && "type" in child && typeof child.type === "function";
|
|
@@ -311,21 +326,21 @@ function evaluateControlBoundaryChildren(controlState) {
|
|
|
311
326
|
if (controlState.kind === "show") return evaluateShowState(controlState);
|
|
312
327
|
return evaluateCaseState(controlState);
|
|
313
328
|
}
|
|
314
|
-
function trySyncComponentChild(existing, child, usedOldEls) {
|
|
329
|
+
function trySyncComponentChild(existing, child, usedOldEls, parentNamespace) {
|
|
315
330
|
if (!isComponentVNode(child)) return null;
|
|
316
|
-
const synced = syncComponentElement(existing, child, child.type, (child.props ?? {}) || {});
|
|
331
|
+
const synced = syncComponentElement(existing, child, child.type, (child.props ?? {}) || {}, parentNamespace);
|
|
317
332
|
if (!synced) return null;
|
|
318
333
|
usedOldEls.add(existing);
|
|
319
334
|
usedOldEls.add(synced);
|
|
320
335
|
return synced;
|
|
321
336
|
}
|
|
322
337
|
/** Check if existing element can be reused for child */
|
|
323
|
-
function canReuseElement(existing, child) {
|
|
338
|
+
function canReuseElement(existing, child, parentNamespace) {
|
|
324
339
|
if (!existing) return false;
|
|
325
340
|
if (typeof child !== "object" || child === null || !("type" in child)) return false;
|
|
326
341
|
const childObj = child;
|
|
327
342
|
const existingKey = existing.getAttribute("data-key");
|
|
328
|
-
return (existingKey === null || existingKey === void 0) && typeof childObj.type === "string" &&
|
|
343
|
+
return (existingKey === null || existingKey === void 0) && typeof childObj.type === "string" && canReuseIntrinsicElementInNamespace(existing, childObj.type, parentNamespace);
|
|
329
344
|
}
|
|
330
345
|
/** Collect unkeyed element children in DOM order. */
|
|
331
346
|
function collectUnkeyedElements(parent) {
|
|
@@ -334,13 +349,13 @@ function collectUnkeyedElements(parent) {
|
|
|
334
349
|
return elements;
|
|
335
350
|
}
|
|
336
351
|
/** Try to reuse available element for child */
|
|
337
|
-
function tryReuseElement(avail, child, usedOldEls) {
|
|
352
|
+
function tryReuseElement(avail, child, usedOldEls, parentNamespace) {
|
|
338
353
|
if (typeof child === "string" || typeof child === "number") return null;
|
|
339
|
-
const synced = trySyncComponentChild(avail, child, usedOldEls);
|
|
354
|
+
const synced = trySyncComponentChild(avail, child, usedOldEls, parentNamespace);
|
|
340
355
|
if (synced) return synced;
|
|
341
356
|
if (typeof child === "object" && child !== null && "type" in child) {
|
|
342
357
|
const childObj = child;
|
|
343
|
-
if (typeof childObj.type === "string" &&
|
|
358
|
+
if (typeof childObj.type === "string" && canReuseIntrinsicElementInNamespace(avail, childObj.type, parentNamespace)) {
|
|
344
359
|
updateElementFromVnode(avail, child);
|
|
345
360
|
usedOldEls.add(avail);
|
|
346
361
|
return avail;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile.js","names":[],"sources":["../../src/renderer/reconcile.ts"],"sourcesContent":["/**\n * ─────────────────────────────────────────────────────────────────────────────\n * RENDERER & RECONCILIATION INVARIANTS (LOCKED)\n * ─────────────────────────────────────────────────────────────────────────────\n *\n * These invariants are NON-NEGOTIABLE. Any optimization or fast-path MUST\n * preserve them. Violations WILL produce incorrect DOM.\n *\n * 1. DOM ORDER DERIVES ONLY FROM CURRENT VNODE ORDER\n * --------------------------------------------------\n * - Final DOM child order MUST be reconstructed from the current vnode list.\n * - Reusing an existing DOM node does NOT imply it stays in the same position.\n * - Appending an existing Node to a DocumentFragment is the ONLY valid way\n * to express reordering (it moves the node).\n *\n * ❌ NEVER skip fragment insertion because a node already has a parent.\n * ✅ ALWAYS append reused nodes into the fragment to establish order.\n *\n *\n * 2. VNODE IDENTITY ≠ VNODE STABILITY\n * ----------------------------------\n * - VNodes are mutable.\n * - `vnodeA === vnodeB` does NOT imply semantic equality.\n * - DOM reuse MUST NOT be gated on vnode identity alone.\n *\n * DOM reuse is allowed ONLY when:\n * - element type is unchanged\n * - structural shape is compatible\n * - updates are applied explicitly via updateElementFromVnode\n *\n * ❌ NEVER assume \"same object\" means \"no changes\".\n *\n *\n * 3. KEYED RECONCILIATION IS ELEMENT-ONLY\n * --------------------------------------\n * - Keyed reconciliation assumes ELEMENT nodes, not Text or Comment nodes.\n * - Any fast-path using `parent.children[i]` MUST prove:\n * - all children are elements\n * - no text nodes are present\n *\n * ❌ NEVER index `parent.children` when text nodes may exist.\n * ✅ Use `parent.childNodes` or bail out to full reconciliation.\n *\n *\n * 4. PRIMITIVES MAP TO TEXT NODES\n * -------------------------------\n * - string/number children represent Text nodes, not Elements.\n * - Reconciliation MUST attempt Text-to-Text reuse before replacement.\n *\n * ❌ NEVER update element.textContent as a substitute for text reconciliation\n * unless the shape is explicitly guaranteed.\n *\n *\n * 5. FAST-PATHS MUST BE STRICTLY SAFE\n * ----------------------------------\n * - Fast-paths are OPTIONAL.\n * - Correctness always beats performance.\n *\n * A fast-path MUST:\n * - prove its eligibility\n * - fall back cleanly on ANY ambiguity\n * - never partially apply\n *\n *\n * 6. CLEANUP IS POSITION-INDEPENDENT\n * ---------------------------------\n * - Cleanup is based on removal from the DOM, not vnode position.\n * - Any node removed or replaced MUST:\n * - remove listeners\n * - cleanup component instances\n *\n *\n * 7. FOR-BOUNDARY & KEYED LISTS OBEY THE SAME RULES\n * ------------------------------------------------\n * - For-boundaries are NOT special in ordering semantics.\n * - Cached DOM nodes MUST still be reordered via fragment insertion.\n * - Cache is an optimization, not an ownership claim.\n *\n *\n * If you are unsure whether an optimization preserves these invariants:\n * DO NOT APPLY IT.\n *\n * ─────────────────────────────────────────────────────────────────────────────\n */\n\nimport type { DOMElement, VNode } from './types';\nimport {\n createDOMNode,\n syncComponentElement,\n updateElementFromVnode,\n performBulkPositionalKeyedTextUpdate,\n} from './dom';\nimport type { Props } from '../common/props';\nimport {\n keyedElements,\n _reconcilerRecordedParents,\n planKeyedReorderFastPath,\n} from './keyed';\nimport { teardownNodeSubtree } from './cleanup';\nimport { applyRendererFastPath } from './fastpath';\nimport { getRuntimeEnv } from './env';\nimport type { ComponentFunction } from '../runtime/component';\nimport {\n evaluateCaseState,\n evaluateShowState,\n type ControlBoundaryState,\n} from '../runtime/control';\nimport { evaluateForState } from '../runtime/for';\nimport { __FOR_BOUNDARY__ } from '../common/vnode';\nimport {\n extractKey,\n checkPropChanges,\n recordFastPathStats,\n recordDOMReplace,\n tagNamesEqualIgnoreCase,\n} from './utils';\n\nexport const IS_DOM_AVAILABLE = typeof document !== 'undefined';\n\n// Helper type for narrowings\ntype VnodeObj = VNode & { type?: unknown; props?: Record<string, unknown> };\ntype ComponentVNode = DOMElement & { type: ComponentFunction };\n\nexport function reconcileKeyedChildren(\n parent: Element,\n newChildren: VNode[],\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> {\n const keyedVnodes = extractKeyedChildren(newChildren);\n\n // Ensure we have a key map before reconciliation to avoid O(n) DOM scans\n // during O(n) reconciliation loop (which would be O(n²))\n const ensuredOldKeyMap = oldKeyMap || buildKeyMapFromDOM(parent);\n\n // Try fast paths first\n const fastPathResult = tryFastPaths(\n parent,\n newChildren,\n keyedVnodes,\n ensuredOldKeyMap\n );\n if (fastPathResult) {\n return fastPathResult;\n }\n\n // Full reconciliation\n return performFullReconciliation(\n parent,\n newChildren,\n keyedVnodes,\n ensuredOldKeyMap\n );\n}\n\n/** Build key map from DOM children */\nfunction buildKeyMapFromDOM(parent: Element): Map<string | number, Element> {\n const keyMap = new Map<string | number, Element>();\n try {\n for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {\n const k = el.getAttribute('data-key');\n if (k !== null) {\n keyMap.set(k, el);\n const n = Number(k);\n if (!Number.isNaN(n)) keyMap.set(n, el);\n }\n }\n } catch {\n // Ignore\n }\n return keyMap;\n}\n\n/** Extract keyed children in a single pass. */\nfunction extractKeyedChildren(\n newChildren: VNode[]\n): Array<{ key: string | number; vnode: VNode }> {\n const keyedVnodes: Array<{ key: string | number; vnode: VNode }> = [];\n\n for (let i = 0; i < newChildren.length; i++) {\n const child = newChildren[i];\n const key = extractKey(child);\n if (key !== undefined) {\n keyedVnodes.push({ key, vnode: child });\n }\n }\n\n return keyedVnodes;\n}\n\n/** Try fast paths before full reconciliation */\nfunction tryFastPaths(\n parent: Element,\n newChildren: VNode[],\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> | null {\n try {\n const forcedResult = tryForcedPositionalBulkUpdate(\n parent,\n newChildren,\n keyedVnodes\n );\n if (forcedResult) {\n return forcedResult;\n }\n\n // Try renderer fast-path for large keyed reorder-only updates\n const rendererResult = tryRendererFastPath(\n parent,\n keyedVnodes,\n newChildren.length,\n oldKeyMap\n );\n if (rendererResult) {\n return rendererResult;\n }\n\n // Try positional bulk update for medium-sized lists\n const positionalResult = tryPositionalBulkUpdate(parent, keyedVnodes);\n if (positionalResult) {\n return positionalResult;\n }\n } catch {\n // Fall through to full reconciliation\n }\n\n return null;\n}\n\n/** Try renderer fast-path */\nfunction tryRendererFastPath(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n totalChildren: number,\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> | null {\n const decision = planKeyedReorderFastPath(\n parent,\n keyedVnodes,\n totalChildren,\n oldKeyMap\n );\n\n if (decision.useFastPath) {\n try {\n const map = applyRendererFastPath(parent, keyedVnodes, oldKeyMap);\n if (map) {\n keyedElements.set(parent, map);\n return map;\n }\n } catch {\n // Fall through\n }\n }\n\n return null;\n}\n\n/** Try the explicit test/bench forced positional keyed path. */\nfunction tryForcedPositionalBulkUpdate(\n parent: Element,\n newChildren: VNode[],\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): Map<string | number, Element> | null {\n if (getRuntimeEnv().ASKR_FORCE_BULK_POSREUSE !== '1') return null;\n if (keyedVnodes.length === 0 || keyedVnodes.length !== newChildren.length) {\n return null;\n }\n\n try {\n const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);\n recordFastPathStats(stats, 'bulkKeyedPositionalForced');\n\n rebuildKeyedMap(parent);\n return keyedElements.get(parent) as Map<string | number, Element>;\n } catch {\n return null;\n }\n}\n\n/** Try positional bulk update for medium-sized lists */\nfunction tryPositionalBulkUpdate(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): Map<string | number, Element> | null {\n const total = keyedVnodes.length;\n if (total < 10) return null;\n\n // CRITICAL INVARIANT: Only use children[] indexing if element-only is guaranteed\n // If parent has text nodes or comment nodes, bail to full reconciliation\n if (parent.children.length !== total) {\n return null;\n }\n\n const matchCount = countPositionalMatches(parent, keyedVnodes);\n\n // For keyed lists, the positional bulk update path makes sense in two cases:\n // 1. Perfect match (100%): All keys are in the right positions, just update text\n // 2. Very low match (<10%): Keys changed en-masse, treat as bulk re-key, reuse nodes by position\n // ANY mismatch at all means we have a reorder and need full reconciliation\n // to preserve DOM node identity correctly.\n const matchFraction = matchCount / total;\n\n if (keyedVnodes.length > 0) {\n // For keyed lists: require perfect match or very low match\n // matchCount !== total catches ANY reordering, even just 2 swapped elements\n if (matchCount !== total && matchFraction >= 0.1) {\n return null;\n }\n } else {\n // For unkeyed lists: use original threshold\n if (matchFraction < 0.9) {\n return null;\n }\n }\n\n // Check for prop changes that would prevent positional update\n if (hasPositionalPropChanges(parent, keyedVnodes)) {\n return null;\n }\n\n // Perform positional update\n try {\n const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);\n recordFastPathStats(stats, 'bulkKeyedPositionalHits');\n\n rebuildKeyedMap(parent);\n return keyedElements.get(parent) as Map<string | number, Element>;\n } catch {\n return null;\n }\n}\n\n/** Count how many vnodes match parent children by position and tag */\nfunction countPositionalMatches(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): number {\n let matchCount = 0;\n\n try {\n // For keyed children, use children (elements only) since keyed nodes are elements\n for (let i = 0; i < keyedVnodes.length; i++) {\n const vnode = keyedVnodes[i].vnode as VnodeObj;\n const expectedKey = keyedVnodes[i].key;\n\n if (!vnode || typeof vnode !== 'object' || typeof vnode.type !== 'string')\n continue;\n\n const el = parent.children[i] as Element | undefined;\n if (!el) continue;\n\n // For keyed lists, check BOTH tag name AND key match\n if (tagNamesEqualIgnoreCase(el.tagName, vnode.type)) {\n // Check if the element at this position has the expected key\n const actualKey = el.getAttribute('data-key');\n const keyMatches =\n actualKey === String(expectedKey) ||\n (actualKey !== null &&\n !Number.isNaN(Number(actualKey)) &&\n Number(actualKey) === expectedKey);\n\n if (keyMatches) {\n matchCount++;\n }\n }\n }\n } catch {\n // Ignore\n }\n\n return matchCount;\n}\n\n/** Check if positional prop changes would prevent bulk update */\nfunction hasPositionalPropChanges(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): boolean {\n try {\n // For keyed children, use children (elements only) since keyed nodes are elements\n for (let i = 0; i < keyedVnodes.length; i++) {\n const vnode = keyedVnodes[i].vnode as VnodeObj;\n const el = parent.children[i] as Element | undefined;\n if (!el || !vnode || typeof vnode !== 'object') continue;\n\n if (checkPropChanges(el, vnode.props || {})) {\n return true;\n }\n }\n } catch {\n return true;\n }\n\n return false;\n}\n\n/** Rebuild keyed map from parent children */\nfunction rebuildKeyedMap(parent: Element): void {\n try {\n const map = new Map<string | number, Element>();\n for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {\n const k = el.getAttribute('data-key');\n if (k !== null) {\n map.set(k, el);\n const n = Number(k);\n if (!Number.isNaN(n)) map.set(n, el);\n }\n }\n keyedElements.set(parent, map);\n } catch {\n // Ignore\n }\n}\n\n/** Perform full reconciliation when fast paths don't apply */\nfunction performFullReconciliation(\n parent: Element,\n newChildren: VNode[],\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> {\n const newKeyMap = new Map<string | number, Element>();\n const finalNodes: Node[] = [];\n const usedOldEls = new WeakSet<Node>();\n\n const resolveOldElOnce = createOldElResolver(parent, oldKeyMap, usedOldEls);\n const unkeyedEls = collectUnkeyedElements(parent);\n let unkeyedIndex = 0;\n const resolveUnkeyedOnce = (): Element | undefined => {\n while (unkeyedIndex < unkeyedEls.length) {\n const candidate = unkeyedEls[unkeyedIndex++];\n if (!usedOldEls.has(candidate)) return candidate;\n }\n return undefined;\n };\n\n // Positional reconciliation\n for (let i = 0; i < newChildren.length; i++) {\n const child = newChildren[i];\n const node = reconcileSingleChild(\n child,\n i,\n parent,\n resolveOldElOnce,\n resolveUnkeyedOnce,\n usedOldEls,\n newKeyMap\n );\n if (node) finalNodes.push(node);\n }\n\n // SSR guard\n if (typeof document === 'undefined') return newKeyMap;\n\n commitReconciliation(parent, finalNodes);\n keyedElements.delete(parent);\n\n return newKeyMap;\n}\n\n/** Create resolver for finding old elements by key */\nfunction createOldElResolver(\n parent: Element,\n oldKeyMap: Map<string | number, Element> | undefined,\n usedOldEls: WeakSet<Node>\n): (k: string | number) => Element | undefined {\n return (k: string | number) => {\n if (!oldKeyMap) return undefined;\n\n // Fast-path: directly from oldKeyMap\n const direct = oldKeyMap.get(k);\n if (direct && !usedOldEls.has(direct)) {\n usedOldEls.add(direct);\n return direct;\n }\n\n // Try string form\n const s = String(k);\n const byString = oldKeyMap.get(s);\n if (byString && !usedOldEls.has(byString)) {\n usedOldEls.add(byString);\n return byString;\n }\n\n // Try numeric form\n const n = Number(s);\n if (!Number.isNaN(n)) {\n const byNum = oldKeyMap.get(n);\n if (byNum && !usedOldEls.has(byNum)) {\n usedOldEls.add(byNum);\n return byNum;\n }\n }\n\n // Fallback: scan parent children\n return scanForElementByKey(parent, k, s, usedOldEls);\n };\n}\n\n/** Scan parent children for element with matching key */\nfunction scanForElementByKey(\n parent: Element,\n k: string | number,\n keyStr: string,\n usedOldEls: WeakSet<Node>\n): Element | undefined {\n try {\n for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {\n if (usedOldEls.has(ch)) continue;\n const attr = ch.getAttribute('data-key');\n if (attr === keyStr) {\n usedOldEls.add(ch);\n return ch;\n }\n if (attr !== null) {\n const numAttr = Number(attr);\n if (!Number.isNaN(numAttr) && numAttr === (k as number)) {\n usedOldEls.add(ch);\n return ch;\n }\n }\n }\n } catch {\n // Ignore\n }\n return undefined;\n}\n\n/** Reconcile a single child */\nfunction reconcileSingleChild(\n child: VNode,\n index: number,\n parent: Element,\n resolveOldElOnce: (k: string | number) => Element | undefined,\n resolveUnkeyedOnce: () => Element | undefined,\n usedOldEls: WeakSet<Node>,\n newKeyMap: Map<string | number, Element>\n): Node | null {\n const resolvedControlBoundary = prepareControlBoundaryResolution(child);\n if (resolvedControlBoundary !== null) {\n if (resolvedControlBoundary.remount) {\n return createDOMNode(resolvedControlBoundary.vnode);\n }\n\n return reconcileSingleChild(\n resolvedControlBoundary.vnode,\n index,\n parent,\n resolveOldElOnce,\n resolveUnkeyedOnce,\n usedOldEls,\n newKeyMap\n );\n }\n\n // Keyed child\n const key = extractKey(child);\n\n if (key !== undefined) {\n return reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap);\n }\n\n return reconcileUnkeyedChild(\n child,\n index,\n parent,\n resolveUnkeyedOnce,\n usedOldEls\n );\n}\n\n/** Reconcile a keyed child */\nfunction reconcileKeyedChild(\n child: VNode,\n key: string | number,\n parent: Element,\n resolveOldElOnce: (k: string | number) => Element | undefined,\n newKeyMap: Map<string | number, Element>\n): Node | null {\n const el = resolveOldElOnce(key);\n\n if (el && el.parentElement === parent) {\n // Strict keyed guarantee: if the element tag changes for an existing key,\n // replace the DOM node rather than mutating in place.\n try {\n const childObj = child as VnodeObj;\n if (\n childObj &&\n typeof childObj === 'object' &&\n typeof childObj.type === 'string'\n ) {\n if (tagNamesEqualIgnoreCase(el.tagName, childObj.type)) {\n updateElementFromVnode(el, child);\n newKeyMap.set(key, el);\n return el;\n }\n }\n if (isComponentVNode(child)) {\n const synced = syncComponentElement(\n el,\n child,\n child.type,\n ((child.props ?? {}) as Props) || {}\n );\n if (synced) {\n if (synced instanceof Element) newKeyMap.set(key, synced);\n return synced;\n }\n }\n } catch {\n // Fall through to replacement\n }\n }\n\n const dom = createDOMNode(child);\n if (dom) {\n if (dom instanceof Element) newKeyMap.set(key, dom);\n return dom;\n }\n\n return null;\n}\n\n/** Reconcile an unkeyed or primitive child */\nfunction reconcileUnkeyedChild(\n child: VNode,\n index: number,\n parent: Element,\n resolveUnkeyedOnce: () => Element | undefined,\n usedOldEls: WeakSet<Node>\n): Node | null {\n try {\n // Use childNodes (includes Text nodes) instead of children (elements only)\n const existing = parent.childNodes[index] as Node | undefined;\n\n // Primitive child: try to reuse Text node if available\n if (typeof child === 'string' || typeof child === 'number') {\n if (existing && existing.nodeType === 3) {\n // Text node: reuse in-place\n (existing as Text).data = String(child);\n usedOldEls.add(existing);\n return existing;\n }\n return createDOMNode(child);\n }\n\n if (existing instanceof Element) {\n const synced = trySyncComponentChild(existing, child, usedOldEls);\n if (synced) return synced;\n }\n\n // Element child matching existing unkeyed element\n if (existing instanceof Element && canReuseElement(existing, child)) {\n updateElementFromVnode(existing, child);\n usedOldEls.add(existing);\n return existing;\n }\n\n // Try to find available unkeyed element elsewhere\n const avail = resolveUnkeyedOnce();\n if (avail) {\n const reuseResult = tryReuseElement(avail, child, usedOldEls);\n if (reuseResult) return reuseResult;\n }\n } catch {\n // Fall through to create new\n }\n\n const dom = createDOMNode(child);\n return dom;\n}\n\nfunction isComponentVNode(child: VNode): child is ComponentVNode {\n return (\n typeof child === 'object' &&\n child !== null &&\n 'type' in child &&\n typeof (child as VnodeObj).type === 'function'\n );\n}\n\nfunction isControlBoundaryVNode(child: VNode): child is DOMElement {\n return (\n typeof child === 'object' &&\n child !== null &&\n 'type' in child &&\n (child as VnodeObj).type === __FOR_BOUNDARY__\n );\n}\n\nfunction prepareControlBoundaryResolution(child: VNode): {\n remount: boolean;\n vnode: VNode | null;\n} | null {\n if (!isControlBoundaryVNode(child)) {\n return null;\n }\n\n const controlState = child._controlState ?? child._forState;\n if (!controlState) {\n return null;\n }\n if (controlState.kind === 'for') {\n const childrenVNodes = evaluateControlBoundaryChildren(controlState);\n return childrenVNodes.length === 1\n ? { remount: false, vnode: childrenVNodes[0] ?? null }\n : null;\n }\n\n const previousActiveKey = controlState.activeKey;\n const childrenVNodes = evaluateControlBoundaryChildren(controlState);\n\n return {\n remount:\n previousActiveKey !== null &&\n controlState.activeKey !== previousActiveKey,\n vnode: childrenVNodes[0] ?? null,\n };\n}\n\nfunction evaluateControlBoundaryChildren(\n controlState: ControlBoundaryState\n): VNode[] {\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n\n return evaluateCaseState(controlState);\n}\n\nfunction trySyncComponentChild(\n existing: Element,\n child: VNode,\n usedOldEls: WeakSet<Node>\n): Node | null {\n if (!isComponentVNode(child)) return null;\n\n const synced = syncComponentElement(\n existing,\n child,\n child.type,\n ((child.props ?? {}) as Props) || {}\n );\n if (!synced) return null;\n\n usedOldEls.add(existing);\n usedOldEls.add(synced);\n return synced;\n}\n\n/** Check if existing element can be reused for child */\nfunction canReuseElement(existing: Element | undefined, child: VNode): boolean {\n if (!existing) return false;\n if (typeof child !== 'object' || child === null || !('type' in child))\n return false;\n\n const childObj = child as VnodeObj;\n const existingKey = existing.getAttribute('data-key');\n const hasNoKey = existingKey === null || existingKey === undefined;\n\n return (\n hasNoKey &&\n typeof childObj.type === 'string' &&\n tagNamesEqualIgnoreCase(existing.tagName, childObj.type)\n );\n}\n\n/** Collect unkeyed element children in DOM order. */\nfunction collectUnkeyedElements(parent: Element): Element[] {\n const elements: Element[] = [];\n for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {\n if (ch.getAttribute('data-key') === null) elements.push(ch);\n }\n return elements;\n}\n\n/** Try to reuse available element for child */\nfunction tryReuseElement(\n avail: Element,\n child: VNode,\n usedOldEls: WeakSet<Node>\n): Node | null {\n if (typeof child === 'string' || typeof child === 'number') {\n return null;\n }\n\n const synced = trySyncComponentChild(avail, child, usedOldEls);\n if (synced) {\n return synced;\n }\n\n if (typeof child === 'object' && child !== null && 'type' in child) {\n const childObj = child as VnodeObj;\n if (\n typeof childObj.type === 'string' &&\n tagNamesEqualIgnoreCase(avail.tagName, childObj.type)\n ) {\n updateElementFromVnode(avail, child);\n usedOldEls.add(avail);\n return avail;\n }\n }\n\n return null;\n}\n\n/** Commit reconciliation by replacing parent children */\nfunction commitReconciliation(parent: Element, finalNodes: Node[]): void {\n try {\n const finalSet = new Set<Node>(finalNodes);\n\n for (let n = parent.firstChild; n; ) {\n const next = n.nextSibling;\n if (!finalSet.has(n)) {\n teardownNodeSubtree(n);\n parent.removeChild(n);\n }\n n = next;\n }\n\n for (let i = 0; i < finalNodes.length; i++) {\n const desiredNode = finalNodes[i];\n const anchor = parent.childNodes[i] ?? null;\n if (desiredNode !== anchor) {\n parent.insertBefore(desiredNode, anchor);\n }\n }\n } catch {\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < finalNodes.length; i++) {\n fragment.appendChild(finalNodes[i]);\n }\n\n try {\n for (let n = parent.firstChild; n; ) {\n const next = n.nextSibling;\n teardownNodeSubtree(n);\n n = next;\n }\n } catch {\n // Ignore fallback cleanup failures.\n }\n\n recordDOMReplace('reconcile');\n parent.replaceChildren(fragment);\n return;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reconcile.js","names":[],"sources":["../../src/renderer/reconcile.ts"],"sourcesContent":["/**\n * ─────────────────────────────────────────────────────────────────────────────\n * RENDERER & RECONCILIATION INVARIANTS (LOCKED)\n * ─────────────────────────────────────────────────────────────────────────────\n *\n * These invariants are NON-NEGOTIABLE. Any optimization or fast-path MUST\n * preserve them. Violations WILL produce incorrect DOM.\n *\n * 1. DOM ORDER DERIVES ONLY FROM CURRENT VNODE ORDER\n * --------------------------------------------------\n * - Final DOM child order MUST be reconstructed from the current vnode list.\n * - Reusing an existing DOM node does NOT imply it stays in the same position.\n * - Appending an existing Node to a DocumentFragment is the ONLY valid way\n * to express reordering (it moves the node).\n *\n * ❌ NEVER skip fragment insertion because a node already has a parent.\n * ✅ ALWAYS append reused nodes into the fragment to establish order.\n *\n *\n * 2. VNODE IDENTITY ≠ VNODE STABILITY\n * ----------------------------------\n * - VNodes are mutable.\n * - `vnodeA === vnodeB` does NOT imply semantic equality.\n * - DOM reuse MUST NOT be gated on vnode identity alone.\n *\n * DOM reuse is allowed ONLY when:\n * - element type is unchanged\n * - structural shape is compatible\n * - updates are applied explicitly via updateElementFromVnode\n *\n * ❌ NEVER assume \"same object\" means \"no changes\".\n *\n *\n * 3. KEYED RECONCILIATION IS ELEMENT-ONLY\n * --------------------------------------\n * - Keyed reconciliation assumes ELEMENT nodes, not Text or Comment nodes.\n * - Any fast-path using `parent.children[i]` MUST prove:\n * - all children are elements\n * - no text nodes are present\n *\n * ❌ NEVER index `parent.children` when text nodes may exist.\n * ✅ Use `parent.childNodes` or bail out to full reconciliation.\n *\n *\n * 4. PRIMITIVES MAP TO TEXT NODES\n * -------------------------------\n * - string/number children represent Text nodes, not Elements.\n * - Reconciliation MUST attempt Text-to-Text reuse before replacement.\n *\n * ❌ NEVER update element.textContent as a substitute for text reconciliation\n * unless the shape is explicitly guaranteed.\n *\n *\n * 5. FAST-PATHS MUST BE STRICTLY SAFE\n * ----------------------------------\n * - Fast-paths are OPTIONAL.\n * - Correctness always beats performance.\n *\n * A fast-path MUST:\n * - prove its eligibility\n * - fall back cleanly on ANY ambiguity\n * - never partially apply\n *\n *\n * 6. CLEANUP IS POSITION-INDEPENDENT\n * ---------------------------------\n * - Cleanup is based on removal from the DOM, not vnode position.\n * - Any node removed or replaced MUST:\n * - remove listeners\n * - cleanup component instances\n *\n *\n * 7. FOR-BOUNDARY & KEYED LISTS OBEY THE SAME RULES\n * ------------------------------------------------\n * - For-boundaries are NOT special in ordering semantics.\n * - Cached DOM nodes MUST still be reordered via fragment insertion.\n * - Cache is an optimization, not an ownership claim.\n *\n *\n * If you are unsure whether an optimization preserves these invariants:\n * DO NOT APPLY IT.\n *\n * ─────────────────────────────────────────────────────────────────────────────\n */\n\nimport type { DOMElement, VNode } from './types';\nimport {\n createDOMNode,\n syncComponentElement,\n updateElementFromVnode,\n performBulkPositionalKeyedTextUpdate,\n} from './dom';\nimport type { Props } from '../common/props';\nimport {\n keyedElements,\n _reconcilerRecordedParents,\n planKeyedReorderFastPath,\n} from './keyed';\nimport { teardownNodeSubtree } from './cleanup';\nimport { applyRendererFastPath } from './fastpath';\nimport { getRuntimeEnv } from './env';\nimport type { ComponentFunction } from '../runtime/component';\nimport {\n evaluateCaseState,\n evaluateShowState,\n type ControlBoundaryState,\n} from '../runtime/control';\nimport { evaluateForState } from '../runtime/for';\nimport { __FOR_BOUNDARY__ } from '../common/vnode';\nimport {\n extractKey,\n checkPropChanges,\n recordFastPathStats,\n recordDOMReplace,\n tagNamesEqualIgnoreCase,\n} from './utils';\n\nexport const IS_DOM_AVAILABLE = typeof document !== 'undefined';\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n\nfunction getParentNamespace(parent: Element): string | undefined {\n return parent.namespaceURI === SVG_NAMESPACE ? SVG_NAMESPACE : undefined;\n}\n\nfunction resolveChildNamespace(\n type: string,\n parentNamespace: string | undefined\n): string | undefined {\n if (type === 'svg') return SVG_NAMESPACE;\n if (parentNamespace === SVG_NAMESPACE && type !== 'foreignObject') {\n return SVG_NAMESPACE;\n }\n return undefined;\n}\n\nfunction canReuseIntrinsicElementInNamespace(\n existing: Element,\n type: string,\n parentNamespace: string | undefined\n): boolean {\n if (!tagNamesEqualIgnoreCase(existing.tagName, type)) {\n return false;\n }\n\n const expectedNamespace = resolveChildNamespace(type, parentNamespace);\n return expectedNamespace === undefined\n ? true\n : existing.namespaceURI === expectedNamespace;\n}\n\n// Helper type for narrowings\ntype VnodeObj = VNode & { type?: unknown; props?: Record<string, unknown> };\ntype ComponentVNode = DOMElement & { type: ComponentFunction };\n\nexport function reconcileKeyedChildren(\n parent: Element,\n newChildren: VNode[],\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> {\n const keyedVnodes = extractKeyedChildren(newChildren);\n\n // Ensure we have a key map before reconciliation to avoid O(n) DOM scans\n // during O(n) reconciliation loop (which would be O(n²))\n const ensuredOldKeyMap = oldKeyMap || buildKeyMapFromDOM(parent);\n\n // Try fast paths first\n const fastPathResult = tryFastPaths(\n parent,\n newChildren,\n keyedVnodes,\n ensuredOldKeyMap\n );\n if (fastPathResult) {\n return fastPathResult;\n }\n\n // Full reconciliation\n return performFullReconciliation(\n parent,\n newChildren,\n keyedVnodes,\n ensuredOldKeyMap\n );\n}\n\n/** Build key map from DOM children */\nfunction buildKeyMapFromDOM(parent: Element): Map<string | number, Element> {\n const keyMap = new Map<string | number, Element>();\n try {\n for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {\n const k = el.getAttribute('data-key');\n if (k !== null) {\n keyMap.set(k, el);\n const n = Number(k);\n if (!Number.isNaN(n)) keyMap.set(n, el);\n }\n }\n } catch {\n // Ignore\n }\n return keyMap;\n}\n\n/** Extract keyed children in a single pass. */\nfunction extractKeyedChildren(\n newChildren: VNode[]\n): Array<{ key: string | number; vnode: VNode }> {\n const keyedVnodes: Array<{ key: string | number; vnode: VNode }> = [];\n\n for (let i = 0; i < newChildren.length; i++) {\n const child = newChildren[i];\n const key = extractKey(child);\n if (key !== undefined) {\n keyedVnodes.push({ key, vnode: child });\n }\n }\n\n return keyedVnodes;\n}\n\n/** Try fast paths before full reconciliation */\nfunction tryFastPaths(\n parent: Element,\n newChildren: VNode[],\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> | null {\n try {\n const forcedResult = tryForcedPositionalBulkUpdate(\n parent,\n newChildren,\n keyedVnodes\n );\n if (forcedResult) {\n return forcedResult;\n }\n\n // Try renderer fast-path for large keyed reorder-only updates\n const rendererResult = tryRendererFastPath(\n parent,\n keyedVnodes,\n newChildren.length,\n oldKeyMap\n );\n if (rendererResult) {\n return rendererResult;\n }\n\n // Try positional bulk update for medium-sized lists\n const positionalResult = tryPositionalBulkUpdate(parent, keyedVnodes);\n if (positionalResult) {\n return positionalResult;\n }\n } catch {\n // Fall through to full reconciliation\n }\n\n return null;\n}\n\n/** Try renderer fast-path */\nfunction tryRendererFastPath(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n totalChildren: number,\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> | null {\n const decision = planKeyedReorderFastPath(\n parent,\n keyedVnodes,\n totalChildren,\n oldKeyMap\n );\n\n if (decision.useFastPath) {\n try {\n const map = applyRendererFastPath(parent, keyedVnodes, oldKeyMap);\n if (map) {\n keyedElements.set(parent, map);\n return map;\n }\n } catch {\n // Fall through\n }\n }\n\n return null;\n}\n\n/** Try the explicit test/bench forced positional keyed path. */\nfunction tryForcedPositionalBulkUpdate(\n parent: Element,\n newChildren: VNode[],\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): Map<string | number, Element> | null {\n if (getRuntimeEnv().ASKR_FORCE_BULK_POSREUSE !== '1') return null;\n if (keyedVnodes.length === 0 || keyedVnodes.length !== newChildren.length) {\n return null;\n }\n\n try {\n const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);\n recordFastPathStats(stats, 'bulkKeyedPositionalForced');\n\n rebuildKeyedMap(parent);\n return keyedElements.get(parent) as Map<string | number, Element>;\n } catch {\n return null;\n }\n}\n\n/** Try positional bulk update for medium-sized lists */\nfunction tryPositionalBulkUpdate(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): Map<string | number, Element> | null {\n const total = keyedVnodes.length;\n if (total < 10) return null;\n\n // CRITICAL INVARIANT: Only use children[] indexing if element-only is guaranteed\n // If parent has text nodes or comment nodes, bail to full reconciliation\n if (parent.children.length !== total) {\n return null;\n }\n\n const parentNamespace = getParentNamespace(parent);\n const matchCount = countPositionalMatches(\n parent,\n keyedVnodes,\n parentNamespace\n );\n\n // For keyed lists, the positional bulk update path makes sense in two cases:\n // 1. Perfect match (100%): All keys are in the right positions, just update text\n // 2. Very low match (<10%): Keys changed en-masse, treat as bulk re-key, reuse nodes by position\n // ANY mismatch at all means we have a reorder and need full reconciliation\n // to preserve DOM node identity correctly.\n const matchFraction = matchCount / total;\n\n if (keyedVnodes.length > 0) {\n // For keyed lists: require perfect match or very low match\n // matchCount !== total catches ANY reordering, even just 2 swapped elements\n if (matchCount !== total && matchFraction >= 0.1) {\n return null;\n }\n } else {\n // For unkeyed lists: use original threshold\n if (matchFraction < 0.9) {\n return null;\n }\n }\n\n // Check for prop changes that would prevent positional update\n if (hasPositionalPropChanges(parent, keyedVnodes)) {\n return null;\n }\n\n // Perform positional update\n try {\n const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);\n recordFastPathStats(stats, 'bulkKeyedPositionalHits');\n\n rebuildKeyedMap(parent);\n return keyedElements.get(parent) as Map<string | number, Element>;\n } catch {\n return null;\n }\n}\n\n/** Count how many vnodes match parent children by position and tag */\nfunction countPositionalMatches(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n parentNamespace: string | undefined\n): number {\n let matchCount = 0;\n\n try {\n // For keyed children, use children (elements only) since keyed nodes are elements\n for (let i = 0; i < keyedVnodes.length; i++) {\n const vnode = keyedVnodes[i].vnode as VnodeObj;\n const expectedKey = keyedVnodes[i].key;\n\n if (!vnode || typeof vnode !== 'object' || typeof vnode.type !== 'string')\n continue;\n\n const el = parent.children[i] as Element | undefined;\n if (!el) continue;\n\n // For keyed lists, check BOTH tag name AND key match\n if (\n canReuseIntrinsicElementInNamespace(el, vnode.type, parentNamespace)\n ) {\n // Check if the element at this position has the expected key\n const actualKey = el.getAttribute('data-key');\n const keyMatches =\n actualKey === String(expectedKey) ||\n (actualKey !== null &&\n !Number.isNaN(Number(actualKey)) &&\n Number(actualKey) === expectedKey);\n\n if (keyMatches) {\n matchCount++;\n }\n }\n }\n } catch {\n // Ignore\n }\n\n return matchCount;\n}\n\n/** Check if positional prop changes would prevent bulk update */\nfunction hasPositionalPropChanges(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): boolean {\n try {\n // For keyed children, use children (elements only) since keyed nodes are elements\n for (let i = 0; i < keyedVnodes.length; i++) {\n const vnode = keyedVnodes[i].vnode as VnodeObj;\n const el = parent.children[i] as Element | undefined;\n if (!el || !vnode || typeof vnode !== 'object') continue;\n\n if (checkPropChanges(el, vnode.props || {})) {\n return true;\n }\n }\n } catch {\n return true;\n }\n\n return false;\n}\n\n/** Rebuild keyed map from parent children */\nfunction rebuildKeyedMap(parent: Element): void {\n try {\n const map = new Map<string | number, Element>();\n for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {\n const k = el.getAttribute('data-key');\n if (k !== null) {\n map.set(k, el);\n const n = Number(k);\n if (!Number.isNaN(n)) map.set(n, el);\n }\n }\n keyedElements.set(parent, map);\n } catch {\n // Ignore\n }\n}\n\n/** Perform full reconciliation when fast paths don't apply */\nfunction performFullReconciliation(\n parent: Element,\n newChildren: VNode[],\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>,\n oldKeyMap: Map<string | number, Element> | undefined\n): Map<string | number, Element> {\n const newKeyMap = new Map<string | number, Element>();\n const finalNodes: Node[] = [];\n const usedOldEls = new WeakSet<Node>();\n\n const resolveOldElOnce = createOldElResolver(parent, oldKeyMap, usedOldEls);\n const unkeyedEls = collectUnkeyedElements(parent);\n let unkeyedIndex = 0;\n const resolveUnkeyedOnce = (): Element | undefined => {\n while (unkeyedIndex < unkeyedEls.length) {\n const candidate = unkeyedEls[unkeyedIndex++];\n if (!usedOldEls.has(candidate)) return candidate;\n }\n return undefined;\n };\n\n // Positional reconciliation\n for (let i = 0; i < newChildren.length; i++) {\n const child = newChildren[i];\n const node = reconcileSingleChild(\n child,\n i,\n parent,\n resolveOldElOnce,\n resolveUnkeyedOnce,\n usedOldEls,\n newKeyMap\n );\n if (node) finalNodes.push(node);\n }\n\n // SSR guard\n if (typeof document === 'undefined') return newKeyMap;\n\n commitReconciliation(parent, finalNodes);\n keyedElements.delete(parent);\n\n return newKeyMap;\n}\n\n/** Create resolver for finding old elements by key */\nfunction createOldElResolver(\n parent: Element,\n oldKeyMap: Map<string | number, Element> | undefined,\n usedOldEls: WeakSet<Node>\n): (k: string | number) => Element | undefined {\n return (k: string | number) => {\n if (!oldKeyMap) return undefined;\n\n // Fast-path: directly from oldKeyMap\n const direct = oldKeyMap.get(k);\n if (direct && !usedOldEls.has(direct)) {\n usedOldEls.add(direct);\n return direct;\n }\n\n // Try string form\n const s = String(k);\n const byString = oldKeyMap.get(s);\n if (byString && !usedOldEls.has(byString)) {\n usedOldEls.add(byString);\n return byString;\n }\n\n // Try numeric form\n const n = Number(s);\n if (!Number.isNaN(n)) {\n const byNum = oldKeyMap.get(n);\n if (byNum && !usedOldEls.has(byNum)) {\n usedOldEls.add(byNum);\n return byNum;\n }\n }\n\n // Fallback: scan parent children\n return scanForElementByKey(parent, k, s, usedOldEls);\n };\n}\n\n/** Scan parent children for element with matching key */\nfunction scanForElementByKey(\n parent: Element,\n k: string | number,\n keyStr: string,\n usedOldEls: WeakSet<Node>\n): Element | undefined {\n try {\n for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {\n if (usedOldEls.has(ch)) continue;\n const attr = ch.getAttribute('data-key');\n if (attr === keyStr) {\n usedOldEls.add(ch);\n return ch;\n }\n if (attr !== null) {\n const numAttr = Number(attr);\n if (!Number.isNaN(numAttr) && numAttr === (k as number)) {\n usedOldEls.add(ch);\n return ch;\n }\n }\n }\n } catch {\n // Ignore\n }\n return undefined;\n}\n\n/** Reconcile a single child */\nfunction reconcileSingleChild(\n child: VNode,\n index: number,\n parent: Element,\n resolveOldElOnce: (k: string | number) => Element | undefined,\n resolveUnkeyedOnce: () => Element | undefined,\n usedOldEls: WeakSet<Node>,\n newKeyMap: Map<string | number, Element>\n): Node | null {\n const resolvedControlBoundary = prepareControlBoundaryResolution(child);\n if (resolvedControlBoundary !== null) {\n if (resolvedControlBoundary.remount) {\n return createDOMNode(\n resolvedControlBoundary.vnode,\n getParentNamespace(parent)\n );\n }\n\n return reconcileSingleChild(\n resolvedControlBoundary.vnode,\n index,\n parent,\n resolveOldElOnce,\n resolveUnkeyedOnce,\n usedOldEls,\n newKeyMap\n );\n }\n\n // Keyed child\n const key = extractKey(child);\n\n if (key !== undefined) {\n return reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap);\n }\n\n return reconcileUnkeyedChild(\n child,\n index,\n parent,\n resolveUnkeyedOnce,\n usedOldEls\n );\n}\n\n/** Reconcile a keyed child */\nfunction reconcileKeyedChild(\n child: VNode,\n key: string | number,\n parent: Element,\n resolveOldElOnce: (k: string | number) => Element | undefined,\n newKeyMap: Map<string | number, Element>\n): Node | null {\n const el = resolveOldElOnce(key);\n const parentNamespace = getParentNamespace(parent);\n\n if (el && el.parentElement === parent) {\n // Strict keyed guarantee: if the element tag changes for an existing key,\n // replace the DOM node rather than mutating in place.\n try {\n const childObj = child as VnodeObj;\n if (\n childObj &&\n typeof childObj === 'object' &&\n typeof childObj.type === 'string'\n ) {\n if (\n canReuseIntrinsicElementInNamespace(\n el,\n childObj.type,\n parentNamespace\n )\n ) {\n updateElementFromVnode(el, child);\n newKeyMap.set(key, el);\n return el;\n }\n }\n if (isComponentVNode(child)) {\n const synced = syncComponentElement(\n el,\n child,\n child.type,\n ((child.props ?? {}) as Props) || {},\n parentNamespace\n );\n if (synced) {\n if (synced instanceof Element) newKeyMap.set(key, synced);\n return synced;\n }\n }\n } catch {\n // Fall through to replacement\n }\n }\n\n const dom = createDOMNode(child, parentNamespace);\n if (dom) {\n if (dom instanceof Element) newKeyMap.set(key, dom);\n return dom;\n }\n\n return null;\n}\n\n/** Reconcile an unkeyed or primitive child */\nfunction reconcileUnkeyedChild(\n child: VNode,\n index: number,\n parent: Element,\n resolveUnkeyedOnce: () => Element | undefined,\n usedOldEls: WeakSet<Node>\n): Node | null {\n const parentNamespace = getParentNamespace(parent);\n\n try {\n // Use childNodes (includes Text nodes) instead of children (elements only)\n const existing = parent.childNodes[index] as Node | undefined;\n\n // Primitive child: try to reuse Text node if available\n if (typeof child === 'string' || typeof child === 'number') {\n if (existing && existing.nodeType === 3) {\n // Text node: reuse in-place\n (existing as Text).data = String(child);\n usedOldEls.add(existing);\n return existing;\n }\n return createDOMNode(child, parentNamespace);\n }\n\n if (existing instanceof Element) {\n const synced = trySyncComponentChild(\n existing,\n child,\n usedOldEls,\n parentNamespace\n );\n if (synced) return synced;\n }\n\n // Element child matching existing unkeyed element\n if (\n existing instanceof Element &&\n canReuseElement(existing, child, parentNamespace)\n ) {\n updateElementFromVnode(existing, child);\n usedOldEls.add(existing);\n return existing;\n }\n\n // Try to find available unkeyed element elsewhere\n const avail = resolveUnkeyedOnce();\n if (avail) {\n const reuseResult = tryReuseElement(\n avail,\n child,\n usedOldEls,\n parentNamespace\n );\n if (reuseResult) return reuseResult;\n }\n } catch {\n // Fall through to create new\n }\n\n const dom = createDOMNode(child, parentNamespace);\n return dom;\n}\n\nfunction isComponentVNode(child: VNode): child is ComponentVNode {\n return (\n typeof child === 'object' &&\n child !== null &&\n 'type' in child &&\n typeof (child as VnodeObj).type === 'function'\n );\n}\n\nfunction isControlBoundaryVNode(child: VNode): child is DOMElement {\n return (\n typeof child === 'object' &&\n child !== null &&\n 'type' in child &&\n (child as VnodeObj).type === __FOR_BOUNDARY__\n );\n}\n\nfunction prepareControlBoundaryResolution(child: VNode): {\n remount: boolean;\n vnode: VNode | null;\n} | null {\n if (!isControlBoundaryVNode(child)) {\n return null;\n }\n\n const controlState = child._controlState ?? child._forState;\n if (!controlState) {\n return null;\n }\n if (controlState.kind === 'for') {\n const childrenVNodes = evaluateControlBoundaryChildren(controlState);\n return childrenVNodes.length === 1\n ? { remount: false, vnode: childrenVNodes[0] ?? null }\n : null;\n }\n\n const previousActiveKey = controlState.activeKey;\n const childrenVNodes = evaluateControlBoundaryChildren(controlState);\n\n return {\n remount:\n previousActiveKey !== null &&\n controlState.activeKey !== previousActiveKey,\n vnode: childrenVNodes[0] ?? null,\n };\n}\n\nfunction evaluateControlBoundaryChildren(\n controlState: ControlBoundaryState\n): VNode[] {\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n\n return evaluateCaseState(controlState);\n}\n\nfunction trySyncComponentChild(\n existing: Element,\n child: VNode,\n usedOldEls: WeakSet<Node>,\n parentNamespace: string | undefined\n): Node | null {\n if (!isComponentVNode(child)) return null;\n\n const synced = syncComponentElement(\n existing,\n child,\n child.type,\n ((child.props ?? {}) as Props) || {},\n parentNamespace\n );\n if (!synced) return null;\n\n usedOldEls.add(existing);\n usedOldEls.add(synced);\n return synced;\n}\n\n/** Check if existing element can be reused for child */\nfunction canReuseElement(\n existing: Element | undefined,\n child: VNode,\n parentNamespace: string | undefined\n): boolean {\n if (!existing) return false;\n if (typeof child !== 'object' || child === null || !('type' in child))\n return false;\n\n const childObj = child as VnodeObj;\n const existingKey = existing.getAttribute('data-key');\n const hasNoKey = existingKey === null || existingKey === undefined;\n\n return (\n hasNoKey &&\n typeof childObj.type === 'string' &&\n canReuseIntrinsicElementInNamespace(\n existing,\n childObj.type,\n parentNamespace\n )\n );\n}\n\n/** Collect unkeyed element children in DOM order. */\nfunction collectUnkeyedElements(parent: Element): Element[] {\n const elements: Element[] = [];\n for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {\n if (ch.getAttribute('data-key') === null) elements.push(ch);\n }\n return elements;\n}\n\n/** Try to reuse available element for child */\nfunction tryReuseElement(\n avail: Element,\n child: VNode,\n usedOldEls: WeakSet<Node>,\n parentNamespace: string | undefined\n): Node | null {\n if (typeof child === 'string' || typeof child === 'number') {\n return null;\n }\n\n const synced = trySyncComponentChild(\n avail,\n child,\n usedOldEls,\n parentNamespace\n );\n if (synced) {\n return synced;\n }\n\n if (typeof child === 'object' && child !== null && 'type' in child) {\n const childObj = child as VnodeObj;\n if (\n typeof childObj.type === 'string' &&\n canReuseIntrinsicElementInNamespace(avail, childObj.type, parentNamespace)\n ) {\n updateElementFromVnode(avail, child);\n usedOldEls.add(avail);\n return avail;\n }\n }\n\n return null;\n}\n\n/** Commit reconciliation by replacing parent children */\nfunction commitReconciliation(parent: Element, finalNodes: Node[]): void {\n try {\n const finalSet = new Set<Node>(finalNodes);\n\n for (let n = parent.firstChild; n; ) {\n const next = n.nextSibling;\n if (!finalSet.has(n)) {\n teardownNodeSubtree(n);\n parent.removeChild(n);\n }\n n = next;\n }\n\n for (let i = 0; i < finalNodes.length; i++) {\n const desiredNode = finalNodes[i];\n const anchor = parent.childNodes[i] ?? null;\n if (desiredNode !== anchor) {\n parent.insertBefore(desiredNode, anchor);\n }\n }\n } catch {\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < finalNodes.length; i++) {\n fragment.appendChild(finalNodes[i]);\n }\n\n try {\n for (let n = parent.firstChild; n; ) {\n const next = n.nextSibling;\n teardownNodeSubtree(n);\n n = next;\n }\n } catch {\n // Ignore fallback cleanup failures.\n }\n\n recordDOMReplace('reconcile');\n parent.replaceChildren(fragment);\n return;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askrjs/askr",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.47",
|
|
4
4
|
"description": "Actor-backed deterministic UI framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"askr",
|
|
@@ -131,11 +131,11 @@
|
|
|
131
131
|
"bench:tier4": "cross-env NODE_ENV=production vp test bench --run --reporter=default --config vitest.bench.tier4.config.ts"
|
|
132
132
|
},
|
|
133
133
|
"devDependencies": {
|
|
134
|
-
"@types/node": "^
|
|
134
|
+
"@types/node": "^26.0.1",
|
|
135
135
|
"@vitest/browser-playwright": "4.1.9",
|
|
136
136
|
"cross-env": "^10.1.0",
|
|
137
137
|
"jsdom": "^29.1.1",
|
|
138
|
-
"playwright": "^1.61.
|
|
138
|
+
"playwright": "^1.61.1",
|
|
139
139
|
"tsd": "^0.33.0",
|
|
140
140
|
"typescript": "^6.0.3",
|
|
141
141
|
"vite-plus": "^0.2.1"
|