UNPKG

rambda

Version:

Lightweight and faster alternative to Ramda with included TS definitions

212 lines (165 loc) 4.17 kB
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 (equalsFn(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 (equalsFn(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 equalsFn(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] && !equalsFn(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 } if (bRegex[0]) { return false } const aDate = parseDate(a) const bDate = parseDate(b) if (aDate[0]) { return bDate[0] ? aDate[1] === bDate[1] : false } 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 && !equalsFn(aValue, bValue)) { loopObjectFlag = false } } }) return loopObjectFlag } return false } export function equals(a) { return b => equalsFn(a, b) }