You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					316 lines
				
				7.6 KiB
			
		
		
			
		
	
	
					316 lines
				
				7.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Load modules
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Declare internals
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const internals = {
							 | 
						||
| 
								 | 
							
								    arrayType: Symbol('array'),
							 | 
						||
| 
								 | 
							
								    bufferType: Symbol('buffer'),
							 | 
						||
| 
								 | 
							
								    dateType: Symbol('date'),
							 | 
						||
| 
								 | 
							
								    errorType: Symbol('error'),
							 | 
						||
| 
								 | 
							
								    genericType: Symbol('generic'),
							 | 
						||
| 
								 | 
							
								    mapType: Symbol('map'),
							 | 
						||
| 
								 | 
							
								    regexType: Symbol('regex'),
							 | 
						||
| 
								 | 
							
								    setType: Symbol('set'),
							 | 
						||
| 
								 | 
							
								    weakMapType: Symbol('weak-map'),
							 | 
						||
| 
								 | 
							
								    weakSetType: Symbol('weak-set'),
							 | 
						||
| 
								 | 
							
								    mismatched: Symbol('mismatched')
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.typeMap = {
							 | 
						||
| 
								 | 
							
								    '[object Array]': internals.arrayType,
							 | 
						||
| 
								 | 
							
								    '[object Date]': internals.dateType,
							 | 
						||
| 
								 | 
							
								    '[object Error]': internals.errorType,
							 | 
						||
| 
								 | 
							
								    '[object Map]': internals.mapType,
							 | 
						||
| 
								 | 
							
								    '[object RegExp]': internals.regexType,
							 | 
						||
| 
								 | 
							
								    '[object Set]': internals.setType,
							 | 
						||
| 
								 | 
							
								    '[object WeakMap]': internals.weakMapType,
							 | 
						||
| 
								 | 
							
								    '[object WeakSet]': internals.weakSetType
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.SeenEntry = class {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    constructor(obj, ref) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        this.obj = obj;
							 | 
						||
| 
								 | 
							
								        this.ref = ref;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    isSame(obj, ref) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return this.obj === obj && this.ref === ref;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.getInternalType = function (obj) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const { typeMap, bufferType, genericType } = internals;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (obj instanceof Buffer) {
							 | 
						||
| 
								 | 
							
								        return bufferType;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const objName = Object.prototype.toString.call(obj);
							 | 
						||
| 
								 | 
							
								    return typeMap[objName] || genericType;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.getSharedType = function (obj, ref, checkPrototype) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (checkPrototype) {
							 | 
						||
| 
								 | 
							
								        if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {
							 | 
						||
| 
								 | 
							
								            return internals.mismatched;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return internals.getInternalType(obj);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const type = internals.getInternalType(obj);
							 | 
						||
| 
								 | 
							
								    if (type !== internals.getInternalType(ref)) {
							 | 
						||
| 
								 | 
							
								        return internals.mismatched;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.valueOf = function (obj) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const objValueOf = obj.valueOf;
							 | 
						||
| 
								 | 
							
								    if (objValueOf === undefined) {
							 | 
						||
| 
								 | 
							
								        return obj;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								        return objValueOf.call(obj);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    catch (err) {
							 | 
						||
| 
								 | 
							
								        return err;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.hasOwnEnumerableProperty = function (obj, key) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return Object.prototype.propertyIsEnumerable.call(obj, key);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.isSetSimpleEqual = function (obj, ref) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (const entry of obj) {
							 | 
						||
| 
								 | 
							
								        if (!ref.has(entry)) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.isDeepEqualObj = function (instanceType, obj, ref, options, seen) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals;
							 | 
						||
| 
								 | 
							
								    const { keys, getOwnPropertySymbols } = Object;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (instanceType === internals.arrayType) {
							 | 
						||
| 
								 | 
							
								        if (options.part) {
							 | 
						||
| 
								 | 
							
								            // Check if any index match any other index
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (let i = 0; i < obj.length; ++i) {
							 | 
						||
| 
								 | 
							
								                const objValue = obj[i];
							 | 
						||
| 
								 | 
							
								                for (let j = 0; j < ref.length; ++j) {
							 | 
						||
| 
								 | 
							
								                    if (isDeepEqual(objValue, ref[j], options, seen)) {
							 | 
						||
| 
								 | 
							
								                        return true;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            if (obj.length !== ref.length) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (let i = 0; i < obj.length; ++i) {
							 | 
						||
| 
								 | 
							
								                if (!isDeepEqual(obj[i], ref[i], options, seen)) {
							 | 
						||
| 
								 | 
							
								                    return false;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (instanceType === internals.setType) {
							 | 
						||
| 
								 | 
							
								        if (obj.size !== ref.size) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!internals.isSetSimpleEqual(obj, ref)) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Check for deep equality
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const ref2 = new Set(ref);
							 | 
						||
| 
								 | 
							
								            for (const objEntry of obj) {
							 | 
						||
| 
								 | 
							
								                if (ref2.delete(objEntry)) {
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                let found = false;
							 | 
						||
| 
								 | 
							
								                for (const refEntry of ref2) {
							 | 
						||
| 
								 | 
							
								                    if (isDeepEqual(objEntry, refEntry, options, seen)) {
							 | 
						||
| 
								 | 
							
								                        ref2.delete(refEntry);
							 | 
						||
| 
								 | 
							
								                        found = true;
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (!found) {
							 | 
						||
| 
								 | 
							
								                    return false;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (instanceType === internals.mapType) {
							 | 
						||
| 
								 | 
							
								        if (obj.size !== ref.size) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (const [key, value] of obj) {
							 | 
						||
| 
								 | 
							
								            if (value === undefined && !ref.has(key)) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (!isDeepEqual(value, ref.get(key), options, seen)) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (instanceType === internals.errorType) {
							 | 
						||
| 
								 | 
							
								        // Always check name and message
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (obj.name !== ref.name || obj.message !== ref.message) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Check .valueOf()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const valueOfObj = valueOf(obj);
							 | 
						||
| 
								 | 
							
								    const valueOfRef = valueOf(ref);
							 | 
						||
| 
								 | 
							
								    if (!(obj === valueOfObj && ref === valueOfRef) &&
							 | 
						||
| 
								 | 
							
								        !isDeepEqual(valueOfObj, valueOfRef, options, seen)) {
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Check properties
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const objKeys = keys(obj);
							 | 
						||
| 
								 | 
							
								    if (!options.part && objKeys.length !== keys(ref).length) {
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (let i = 0; i < objKeys.length; ++i) {
							 | 
						||
| 
								 | 
							
								        const key = objKeys[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!hasOwnEnumerableProperty(ref, key)) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!isDeepEqual(obj[key], ref[key], options, seen)) {
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Check symbols
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (options.symbols) {
							 | 
						||
| 
								 | 
							
								        const objSymbols = getOwnPropertySymbols(obj);
							 | 
						||
| 
								 | 
							
								        const refSymbols = new Set(getOwnPropertySymbols(ref));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (let i = 0; i < objSymbols.length; ++i) {
							 | 
						||
| 
								 | 
							
								            const key = objSymbols[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (hasOwnEnumerableProperty(obj, key)) {
							 | 
						||
| 
								 | 
							
								                if (!hasOwnEnumerableProperty(ref, key)) {
							 | 
						||
| 
								 | 
							
								                    return false;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (!isDeepEqual(obj[key], ref[key], options, seen)) {
							 | 
						||
| 
								 | 
							
								                    return false;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (hasOwnEnumerableProperty(ref, key)) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            refSymbols.delete(key);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (const key of refSymbols) {
							 | 
						||
| 
								 | 
							
								            if (hasOwnEnumerableProperty(ref, key)) {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								internals.isDeepEqual = function (obj, ref, options, seen) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (obj === ref) {                                      // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql
							 | 
						||
| 
								 | 
							
								        return obj !== 0 || 1 / obj === 1 / ref;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const type = typeof obj;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (type !== typeof ref) {
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (type !== 'object' ||
							 | 
						||
| 
								 | 
							
								        obj === null ||
							 | 
						||
| 
								 | 
							
								        ref === null) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return obj !== obj && ref !== ref;                  // NaN
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const instanceType = internals.getSharedType(obj, ref, !!options.prototype);
							 | 
						||
| 
								 | 
							
								    switch (instanceType) {
							 | 
						||
| 
								 | 
							
								        case internals.bufferType:
							 | 
						||
| 
								 | 
							
								            return Buffer.prototype.equals.call(obj, ref);
							 | 
						||
| 
								 | 
							
								        case internals.regexType:
							 | 
						||
| 
								 | 
							
								            return obj.toString() === ref.toString();
							 | 
						||
| 
								 | 
							
								        case internals.mismatched:
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (let i = seen.length - 1; i >= 0; --i) {
							 | 
						||
| 
								 | 
							
								        if (seen[i].isSame(obj, ref)) {
							 | 
						||
| 
								 | 
							
								            return true;                                    // If previous comparison failed, it would have stopped execution
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    seen.push(new internals.SeenEntry(obj, ref));
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								        return !!internals.isDeepEqualObj(instanceType, obj, ref, options, seen);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    finally {
							 | 
						||
| 
								 | 
							
								        seen.pop();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = function (obj, ref, options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    options = options || { prototype: true };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return !!internals.isDeepEqual(obj, ref, options, []);
							 | 
						||
| 
								 | 
							
								};
							 |