Skip to main content
Module

x/rambda/source/equals.js

Faster and smaller alternative to Ramda
Latest
File
import { isArray } from './_internals/isArray.js'import { type } from './type.js'
export function _lastIndexOf(valueToFind, list){ if (!isArray(list)) throw new Error(`Cannot read property 'indexOf' of ${ list }`)
const typeOfValue = type(valueToFind) if (![ 'Array', 'NaN', 'Object', 'RegExp' ].includes(typeOfValue)) return list.lastIndexOf(valueToFind)
const { length } = list let index = length let foundIndex = -1
while (--index > -1 && foundIndex === -1) if (equals(list[ index ], valueToFind)) foundIndex = index
return foundIndex}
export function _indexOf(valueToFind, list){ if (!isArray(list)) throw new Error(`Cannot read property 'indexOf' of ${ list }`)
const typeOfValue = type(valueToFind) if (![ 'Array', 'NaN', 'Object', 'RegExp' ].includes(typeOfValue)) return list.indexOf(valueToFind)
let index = -1 let foundIndex = -1 const { length } = list
while (++index < length && foundIndex === -1) if (equals(list[ index ], valueToFind)) foundIndex = index
return foundIndex}
function _arrayFromIterator(iter){ const list = [] let next while (!(next = iter.next()).done) list.push(next.value)
return list}
function _compareSets(a, b){ if (a.size !== b.size) return false
const aList = _arrayFromIterator(a.values()) const bList = _arrayFromIterator(b.values())
const filtered = aList.filter(aInstance => _indexOf(aInstance, bList) === -1)
return filtered.length === 0}
function compareErrors(a, b){ if (a.message !== b.message) return false if (a.toString !== b.toString) return false
return a.toString() === b.toString()}
function parseDate(maybeDate){ if (!maybeDate.toDateString) return [ false ]
return [ true, maybeDate.getTime() ]}
function parseRegex(maybeRegex){ if (maybeRegex.constructor !== RegExp) return [ false ]
return [ true, maybeRegex.toString() ]}
export function equals(a, b){ if (arguments.length === 1) return _b => equals(a, _b)
if (Object.is(a, b)) return true
const aType = type(a)
if (aType !== type(b)) return false if (aType === 'Function') return a.name === undefined ? false : a.name === b.name
if ([ 'NaN', 'Null', 'Undefined' ].includes(aType)) return true
if ([ 'BigInt', 'Number' ].includes(aType)){ if (Object.is(-0, a) !== Object.is(-0, b)) return false
return a.toString() === b.toString() }
if ([ 'Boolean', 'String' ].includes(aType)) return a.toString() === b.toString()
if (aType === 'Array'){ const aClone = Array.from(a) const bClone = Array.from(b)
if (aClone.toString() !== bClone.toString()) return false
let loopArrayFlag = true aClone.forEach((aCloneInstance, aCloneIndex) => { if (loopArrayFlag) if ( aCloneInstance !== bClone[ aCloneIndex ] && !equals(aCloneInstance, bClone[ aCloneIndex ]) ) loopArrayFlag = false
})
return loopArrayFlag }
const aRegex = parseRegex(a) const bRegex = parseRegex(b)
if (aRegex[ 0 ]) return bRegex[ 0 ] ? aRegex[ 1 ] === bRegex[ 1 ] : false else if (bRegex[ 0 ]) return false
const aDate = parseDate(a) const bDate = parseDate(b)
if (aDate[ 0 ]) return bDate[ 0 ] ? aDate[ 1 ] === bDate[ 1 ] : false else if (bDate[ 0 ]) return false
if (a instanceof Error){ if (!(b instanceof Error)) return false
return compareErrors(a, b) }
if (aType === 'Set') return _compareSets(a, b)
if (aType === 'Object'){ const aKeys = Object.keys(a)
if (aKeys.length !== Object.keys(b).length) return false
let loopObjectFlag = true aKeys.forEach(aKeyInstance => { if (loopObjectFlag){ const aValue = a[ aKeyInstance ] const bValue = b[ aKeyInstance ]
if (aValue !== bValue && !equals(aValue, bValue)) loopObjectFlag = false
} })
return loopObjectFlag }
return false}