All files / src/virtual-dom/nodes/helpers patchChildren.ts

95.45% Statements 42/44
93.75% Branches 30/32
100% Functions 1/1
95.24% Lines 40/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118      4x   12x     12x   12x   12x   8x   8x   6x       12x   12x     12x   10x   10x   10x   10x       2x   1x   1x               1x     2x   2x       8x   8x   4x   1x             4x   2x   2x         2x   1x   1x       1x   1x         2x   2x   2x     4x             12x   1x     12x  
import ElementNode from "../ElementNode";
import TextNode from "../TextNode";
 
export default function patchChildren(container: Node, children: (ElementNode | TextNode)[]): boolean {
 
    let updated: boolean = false;
 
    // Map the keyed nodes from the DOM nodes
    const childNodes = Array.from(container.childNodes);
 
    const keyedNodes = new Map<any, Node>();
 
    for (const node of childNodes) {
 
        let key = (node as HTMLElement).getAttribute?.('key') || null;
 
        if (key !== null) {
 
            keyedNodes.set(key, node);
        }
    }
 
    let domNodesCount = childNodes.length;
 
    const virtualChildrenCount = children.length;
 
    // Loop through the virtual children
    for (let i = 0; i < virtualChildrenCount; ++i) {
 
        const vnode = children[i]; // Get the vnode at the current index
 
        const vnodeKey = (vnode as any).key || null; // Check if the virtual node has a key (set it to null to match the comparison of keys)
 
        const domNode = childNodes[i]; // Get the DOM node at the current index
 
        if (domNode === undefined) {
 
            let newNode;
 
            if (keyedNodes.has(vnodeKey)) { // Find an existing keyed node
 
                newNode = keyedNodes.get(vnodeKey);
 
                Iif (vnode.patchDom(newNode as any) === true) {
 
                    updated = true;
                }
 
            }
            else {
 
                newNode = vnode.createDom();
            }
 
            container.appendChild(newNode);
 
            updated = true;
        }
        else { // domNode !== undefined
 
            const domNodeKey = (domNode as HTMLElement).getAttribute?.('key') || null; // Check if the DOM node has a key
 
            if (vnodeKey === domNodeKey) {
 
                if (vnode.patchDom(domNode as any) === true) {
 
                    updated = true;
                }
            }
            else { //vnodeKey !== domNodeKey
 
                let newNode;
 
                if (keyedNodes.has(vnodeKey)) { // Find an existing keyed node
 
                    newNode = keyedNodes.get(vnodeKey);
 
                    Iif (vnode.patchDom(newNode as any) === true) {
 
                        updated = true;
                    }
 
                    if (domNodesCount >= virtualChildrenCount) {
 
                        container.insertBefore(newNode, domNode);
 
                        --domNodesCount; // The domNode is removed from the container
                    }
                    else {
 
                        container.appendChild(newNode);
 
                        --domNodesCount; // The domNode is added to the container
                    }
                }
                else { // No keyed node found, create a new element
 
                    newNode = vnode.createDom();
 
                    container.insertBefore(newNode, domNode);
 
                    ++domNodesCount; // Update the count of extra nodes to remove
                }
 
                updated = true;
            }
 
        }
    }
 
    // Remove the extra nodes
    for (let i = domNodesCount - 1; i >= virtualChildrenCount; --i) {
 
        container.childNodes[i].remove();
    }
 
    return updated;
}