hyperdiff
Version:
Find common, removed and added element between two arrays.
64 lines (50 loc) • 1.72 kB
JavaScript
const { pullAt, cloneDeep } = require('lodash')
const debug = require('debug-logfmt')('hyperdiff')
const isPresent = itemIndex => itemIndex !== -1
function GET_INITIAL_STATE () {
return { common: [], removed: [] }
}
function hasItemWithProps (collection, item, props) {
return props.every(prop => item[prop] === collection[prop])
}
function indexOf (collection, item) {
return collection.indexOf(item)
}
function findIndexWithProps (collection, item, props) {
return collection.findIndex(function (origItem) {
return hasItemWithProps(origItem, item, props)
})
}
function determinateCollections (orig, dist) {
return { first: orig, second: cloneDeep(dist) }
}
function determinateFindIndex (ids, props) {
return props ? findIndexWithProps : indexOf
}
function hyperdiff (orig, dist, props) {
const ids = props ? [].concat(props) : []
const { first, second } = determinateCollections(orig, dist)
const findIndex = determinateFindIndex(ids, props)
debug(
`preconditions first=${JSON.stringify(first)} second=${JSON.stringify(second)} findIndex=${
findIndex.name
}`
)
const results = first.reduce(function (acc, item, index) {
const itemIndex = findIndex(second, item, ids)
const destination = isPresent(itemIndex) ? 'common' : 'removed'
acc[destination].push(item)
pullAt(second, itemIndex)
debug(`index=${index} value=${JSON.stringify(item)} collection=${destination}`)
return acc
}, GET_INITIAL_STATE())
results.added = second
debug(
`added=${JSON.stringify(results.added)} removed=${JSON.stringify(
results.removed
)} common=${JSON.stringify(results.common)}`
)
return results
}
module.exports = hyperdiff