function diff(oldTree, newTree) {
    const patchs = {}; 
    dfs(oldTree, newTree, 0, patchs);
    return patchs;
}
function dfs(oldNode, newNode, index, patchs) {
    let curPatchs = [];
    if (newNode) {
        
        if (oldNode.tagName === newNode.tagName && oldNode.key === newNode.key) {
            
            const props = diffProps(oldNode.props, newNode.props);
            curPatchs.push({ type: "changeProps", props });
            
            diffChildren(oldNode.children, newNode.children, index, patchs);
        } else {
            curPatchs.push({ type: "replaceNode", node: newNode });
        }
    }
    
    if (curPatchs.length) {
        if (patchs[index]) {
            patchs[index] = patchs[index].concat(curPatchs);
        } else {
            patchs[index] = curPatchs;
        }
    }
}
function diffProps(oldProps, newProps) {
    const propsPatchs = [];
    
    
    
    
    for (const key in oldProps) {
        if (!newProps.hasOwnProperty(key))
            propsPatchs.push({ type: "remove", prop: oldProps[key] }); 
        else if (oldProps[key] !== newProps[key])
            propsPatchs.push({
                type: "change",
                prop: oldProps[key],
                value: newProps[k],
            }); 
    }
    for (const key in newProps) {
        if (!oldProps.hasOwnProperty(key))
            propsPatchs.push({ type: "add", prop: newProps[key] }); 
    }
    return propsPatchs;
}
function diffChildren(oldChild, newChild, index, patchs) {
    
    let { change, list } = diffList(oldChild, newChild, index, patchs);
    if (change.length) {
        if (patchs[index]) patchs[index] = patchs[index].concat(change);
        else patchs[index] = change;
    }
    
    oldChild.map((item, i) => {
        let keyIndex = list.indexOf(item.key);
        if (keyIndex) {
            let node = newChild[keyIndex];
            
            dfs(item, node, index, patchs);
        }
    });
}
function diffList(oldList, newList, index, patchs) {
    let change = [];
    let list = [];
    const newKeys = newList.map((item) => item.key);
    oldList.forEach((item) => {
        if (newKeys.includes(item.key)) list.push(item.key);
        else list.push(null);
    });
    
    for (let i = list.length - 1; i >= 0; i--) {
        if (!list[i]) {
            list.splice(i, 1);
            change.push({ type: "remove", index: i });
        }
    }
    
    newList.forEach((item, i) => {
        const { key } = item;
        const index = list.indexOf(key);
        if (index === -1 || key === null) {
            
            change.push({ type: "add", node: item, index: i });
            list.splice(i, 0, key);
        } else if (index !== i) {
            
            change.push({ type: "move", form: index, to: i });
            move(list, index, i);
        }
    });
    return { change, list };
}