"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = diff;
const richTypes = { Date: true, RegExp: true, String: true, Number: true };
function diff(obj, newObj, options = { cyclesFix: true }, _stack = []) {
    let diffs = [];
    const isObjArray = Array.isArray(obj);
    for (const key in obj) {
        const objKey = obj[key];
        const path = isObjArray ? +key : key;
        if (!(key in newObj)) {
            diffs.push({
                type: "REMOVE",
                path: [path],
                oldValue: obj[key],
            });
            continue;
        }
        const newObjKey = newObj[key];
        const areCompatibleObjects = typeof objKey === "object" &&
            typeof newObjKey === "object" &&
            Array.isArray(objKey) === Array.isArray(newObjKey);
        if (objKey &&
            newObjKey &&
            areCompatibleObjects &&
            !richTypes[Object.getPrototypeOf(objKey)?.constructor?.name] &&
            (!options.cyclesFix || !_stack.includes(objKey))) {
            diffs.push.apply(diffs, diff(objKey, newObjKey, options, options.cyclesFix ? _stack.concat([objKey]) : []).map((difference) => {
                difference.path.unshift(path);
                return difference;
            }));
        }
        else if (objKey !== newObjKey &&
            // treat NaN values as equivalent
            !(Number.isNaN(objKey) && Number.isNaN(newObjKey)) &&
            !(areCompatibleObjects &&
                (isNaN(objKey)
                    ? objKey + "" === newObjKey + ""
                    : +objKey === +newObjKey))) {
            diffs.push({
                path: [path],
                type: "CHANGE",
                value: newObjKey,
                oldValue: objKey,
            });
        }
    }
    const isNewObjArray = Array.isArray(newObj);
    for (const key in newObj) {
        if (!(key in obj)) {
            diffs.push({
                type: "CREATE",
                path: [isNewObjArray ? +key : key],
                value: newObj[key],
            });
        }
    }
    return diffs;
}
