All files / src/renderer/dom replaceChild.ts

89.36% Statements 42/47
84.62% Branches 22/26
100% Functions 6/6
89.36% Lines 42/47

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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 13817x 17x 17x 17x   17x       39x   39x       35x 35x     35x   35x       4x     4x   4x   7x   12x   3x           9x         9x   9x     9x   4x     9x             4x         4x   4x   4x   4x     4x   4x   4x                                             39x   39x     42x   39x     3x               7x   7x   12x   4x     8x     3x    
import { isPrimitive } from "../../utils/shared";
import areEquivalentValues from "../areEquivalentValues";
import createNodes from "../createNodes";
import { endMarker } from "../createTemplate";
 
export default function replaceChild(markerNode: Node, newChild: Node, oldChild: Node) {
 
    const {
        parentNode
    } = markerNode;
 
    if (isPrimitive(newChild) &&
        isPrimitive(oldChild)) {
 
        // Find the node whose old value matches the old child
        const oldChildNode = findPreviousSibling(markerNode,
            node => node instanceof Text &&
                (node as Text).textContent === oldChild.toString());
 
        Eif (oldChildNode !== null) { // Otherwise already updated???
 
            (oldChildNode as Text).textContent = newChild.toString();
        }
 
    }
    else Eif ((oldChild as any).patcher !== undefined) { // Patching data
 
        // Find the node whose patching data matches this one
        let oldChildNode = null;
 
        findPreviousSibling(
            markerNode,
            node => testThisOrAnyParent(node, n => {
 
                if (n._$patchingData === undefined) {
 
                    return false;
                }
 
                const {
                    patcher,
                    values
                } = n._$patchingData;
 
                const {
                    patcher: otherPatcher,
                    values: otherValues
                } = oldChild as any;
 
                const r = patcher === otherPatcher &&
                    areEquivalentValues(values, otherValues);
 
                if (r === true) {
 
                    oldChildNode = n;
                }
 
                return r;
            }));
 
        const {
            patcher: oldPatcher,
            rules,
            values: oldValues
        } = (oldChildNode as any)._$patchingData;
 
        const {
            patcher,
            values
        } = (newChild as any);
 
        Eif (patcher === oldPatcher) {
 
            Eif ((newChild as any).rules === null) {
 
                (newChild as any).rules = rules; // Transfer the compiled rules
            }
 
            oldPatcher.patchNode(oldChildNode, rules, oldValues, values);
 
            (newChild as any).node = (oldChild as any).node;
 
            (oldChildNode as any)._$patchingData.values = values; // Update the latest values 
        }
        else { // Different patchers (type of nodes)
 
            const {
                parentNode
            } = oldChildNode;
 
            const newChildNode = createNodes(newChild as any);
 
            parentNode.replaceChild(newChildNode, oldChildNode);
        }
    }
    else { // They are nodes
 
        parentNode.replaceChild(newChild, oldChild);
    }
}
 
function findPreviousSibling(markerNode: Node, predicate: (node: any) => boolean): Node {
 
    let {
        previousSibling
    } = markerNode;
 
    while (previousSibling !== null &&
        (previousSibling as Comment).textContent !== endMarker) {
 
        if (predicate(previousSibling) === true) {
 
            return previousSibling;
        }
 
        previousSibling = previousSibling.previousSibling;
    }
 
    return null;
}
 
function testThisOrAnyParent(node: Node, predicate: (n: any) => boolean): boolean {
 
    let parentNode = node;
 
    while (parentNode !== null) {
 
        if (predicate(parentNode) === true) {
 
            return true;
        }
 
        parentNode = parentNode.parentNode;
    }
 
    return false;
}