UNPKG

foop

Version:

interfaces that describe their intentions.

267 lines (237 loc) 6.65 kB
// conditionals /* eslint complexity: "OFF" */ // debugging /* eslint max-depth: "OFF" */ const isObjNotNull = require('../is/objNotNull') const isNullOrUndefined = require('../is/nullOrUndefined') const isFunction = require('../is/function') const isRegExp = require('../is/regexp') const isError = require('../is/error') const isTrue = require('../is/true') const isDate = require('../is/date') const isArray = require('../is/array') const isObj = require('../is/obj') const toS = require('../is/toS') const hasOwnProperty = require('../util/hasOwnProperty') const ObjectKeys = require('../util/keys') const ObjectOrArrayKeys = require('../util/keysObjOrArray') const ENV_DEBUG = require('../env/debug') // const ENV_DEBUG = true const isNotRealOrNotEqToString = (x, y) => !x || !y || x.toString() !== y.toString() /* prettier-ignore */ /** * @desc checks value equality, used by eq which compares all types * @since 4.1.0 * @memberOf Traverse * @protected * * @TODO !!!!!! USE ENUM FLAGS ON LOOSE TO ALLOW MORE CONFIG FOR ==, COMPARATOR, VALUEOF, walk proto (check ownProps...)... * * @param {*} x compare to y * @param {*} y compare to x * @param {boolean | number} [loose=false] use == checks when typof != * @return {boolean} * * @example * * eqValue(1, 1) //=> true * eqValue('1', 1) //=> false * eqValue('1', 1, true) //=> true * eqValue({}, {}) //=> true * */ module.exports = function eqValue(x, y, loose) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('eqValue', {x, y, loose}) } // if (x === y) { // if (ENV_DEBUG) { // console.log('===', {x, y}) // } // // noop // } // else if (isNullOrUndefined(x) || isNullOrUndefined(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('null or undef !=', {x, y}) } if (x !== y) { return false } } else if (typeof x !== typeof y) { // eslint-disable-next-line if (isTrue(loose) && x == y) { // ignore } else { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('typeof !=', {x, y}) } return false } } // @TODO put this up first? else if (toS(x) !== toS(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('diff str types', {x: toS(x), y: toS(y)}) } return false } else if (isObjNotNull(x)) { // use .equals if the method exists if (hasOwnProperty(x, 'equals')) { return x.equals(y) } /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('isObjNotNull', {x}) } // if (isArray(x)) { // if (x.length !== y.length) { // return false // } // } // @NOTE .toString will be covered for functions and regexes in objStrict if (isRegExp(x) || isRegExp(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('regexp', {x, y}) } if (isNotRealOrNotEqToString(x, y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('regexp !=', {x, y}) } return false } } else if (isDate(x) || isDate(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('dates', {x, y}) } if (!isDate(x) || !isDate(y) || x.getTime() !== y.getTime()) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('!= dates', {x, y}) } return false } } else if (isError(x) || isError(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('isError', {x, y}) } if (!isError(x) || !isError(y) || x.stack !== y.stack) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('!= errors', {x, y}) } return false } } // @NOTE this is covered by toString != toString // else if (isArray(x) && !isArray(y)) { // /* istanbul ignore next: dev */ // if (ENV_DEBUG) { // console.log('isArray(x) || isArray(y)!') // } // // return false // } // else if (!isArray(x) && isArray(y)) { // /* istanbul ignore next: dev */ // if (ENV_DEBUG) { // console.log('!isArray(x) && isArray(y):') // } // // return false // } // @TODO considering, we already know it is not null & undefined // if (isPrimitive(x) || isPrimitive(y)) { // return x.valueOf() === y.valueOf() // } else { // @TODO ObjectOrArrayKeys, but have to have else where they are both array // // @NOTE it will traverse through values if they are == here const xKeys = ObjectKeys(x) const yKeys = ObjectKeys(y).length // diff length if (xKeys.length !== yKeys) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('!= obj key length', {xKeys, yKeys}) } return false } for (let k = 0; k < xKeys.length; k++) { if (!hasOwnProperty(y, xKeys[k])) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('!= obj property', {y, val: xKeys[k]}) } return false } } } } else if (toS(x) === toS(y) && x !== y) { // isString(x) || isBoolean(x) || isNumber(x) || isIterator(x) /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('same str types - diff values', {s: toS(x), x, y}) } return false } // // @TODO put this up first? // else if (toS(x) !== toS(y)) { // /* istanbul ignore next: dev */ // if (ENV_DEBUG) { // console.log('diff str types', {x: toS(x), y: toS(y)}) // } // // return false // } // go deeper else if (isFunction(x) || isFunction(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('isFunction(x) && isFunction(y):') console.log(x.toString()) console.log(y.toString()) } if (isNotRealOrNotEqToString(x, y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('x.toString() !== y.toString()', x.toString() !== y.toString()) } return false } else { return true } } // @TODO why? else if (isObj(x) && isObj(y)) { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('isObj(x) && isObj(y):') } return false } // else { /* istanbul ignore next: dev */ if (ENV_DEBUG) { console.log('eqeqeq:', {[toS(x) + 'X']: x, [toS(y) + 'Y']: y}) } return true // } }