// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
export function cloneDeep(obj) {
    return cloneDeepInner(obj, new Set());
}
export function merge(base, other) {
    if (typeof other === 'object' && other !== null && !Array.isArray(other)) {
        for (const [key, value] of Object.entries(other)) {
            if (key in base) {
                const baseValue = base[key];
                if (typeof baseValue === 'object' && baseValue !== null && !Array.isArray(baseValue)) {
                    base[key] = merge(baseValue, value);
                }
                else {
                    base[key] = value;
                }
            }
            else {
                base[key] = value;
            }
        }
        return base;
    }
    else {
        return other;
    }
}
function cloneDeepInner(obj, seenObjects) {
    if (seenObjects.has(obj)) {
        throw new Error('Circular reference detected');
    }
    else if (typeof obj === 'object') {
        if (obj === null) {
            return null;
        }
        else {
            seenObjects.add(obj);
            if (Array.isArray(obj)) {
                const result = [];
                for (const item of obj) {
                    result.push(cloneDeepInner(item, new Set(seenObjects)));
                }
                return result;
            }
            else {
                const result = {};
                for (const key of Object.getOwnPropertyNames(obj)) {
                    const value = obj[key];
                    result[key] = cloneDeepInner(value, new Set(seenObjects));
                }
                return result;
            }
        }
    }
    else {
        return obj;
    }
}
/**
 * Performs a partial deep comparison between `obj` and `source` to
 * determine if `obj` contains equivalent property values.
 */
export function isMatch(obj, source) {
    return obj === source || (typeof obj === typeof source && isMatchInner(obj, source));
}
function isMatchInner(obj, source) {
    if (obj === null || obj === undefined) {
        return false;
    }
    for (const k of Object.keys(source)) {
        const key = k;
        const sourceValue = source[key];
        if (isStrictComparable(sourceValue)) {
            if (obj[key] !== sourceValue) {
                return false;
            }
        }
        else if (!isMatchInner(obj[key], sourceValue)) {
            return false;
        }
    }
    return true;
}
/**
 * Check if `value` is suitable for strict equality comparisons, i.e. `===`.
 */
function isStrictComparable(value) {
    const type = typeof value;
    return (
    // eslint-disable-next-line no-self-compare
    value === value && !(value !== null && value !== undefined && (type === 'object' || type === 'function')));
}
/**
 * Removes `undefined` and `null` direct properties from an object.
 *
 * @remarks
 * Note that this does not recurse through sub-objects.
 */
export function removeNullishProps(obj) {
    const result = {};
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (obj[key] !== undefined && obj[key] !== null) {
                result[key] = obj[key];
            }
        }
    }
    return result;
}
//# sourceMappingURL=objectUtilities.js.map