UNPKG

@rybr/lenses

Version:

a simple and light package meant to ease data traversal, manipulation, mutation, and transformation

232 lines (205 loc) 6.76 kB
/* * SFCC has implemented Java Collection classes * Many native ES5 Array functions do not exist * This will add support */ const { loadGlobal, TYPES, getConstructorName } = require('./helpers') const protos = require('./protos') const polyfills = require('./polyfills.sfcc') const getIterator = input => (input instanceof dw.util.Iterator ? input : input.iterator()) const Collection = { toArray: input => { const output = [] const iterator = getIterator(input) while (iterator.hasNext()) { output.push(iterator.next()) } return output }, find: (callback, thisRef) => input => { const iterator = getIterator(input) let item while (iterator.hasNext()) { item = iterator.next() if (callback.call(thisRef, item, i, input)) { return item } } }, map: (callback, thisRef) => input => { const iterator = getIterator(input) let index = 0 const result = [] while (iterator.hasNext()) { result.push(callback.call(thisRef, iterator.next(), index, input)) index++ } return result }, filter: (callback, thisRef) => input => { const iterator = getIterator(input) let index = 0 const result = [] while (iterator.hasNext()) { const nextValue = iterator.next() if (callback.call(thisRef, nextValue, index, input)) { result.push(nextValue) } index++ } return result }, forEach: (callback, thisRef) => input => { const iterator = getIterator(input) let index = 0 while (iterator.hasNext()) { callback.call(thisRef, iterator.next(), index, input) index++ } }, // prettier-ignore concat: (...args) => input => { const output = Collection.toArray(input) for (var i = 0; i < args.length; i++) { if (TYPES.ARRAY.is(args[i])) { output.push(...args[i]) } else if (args[i] instanceof dw.util.Collection) { output.push(...Collection.toArray(args[i])) } else { output.push(args[i]) } } }, every: (callback, thisRef) => input => { const iterator = getIterator(input) let index = 0 while (iterator.hasNext()) { if (!callback.call(thisRef, iterator.next(), index, input)) { return false } index++ } return true }, some: (callback, thisRef) => input => { const iterator = getIterator(input) let index = 0 while (iterator.hasNext()) { if (callback.call(thisRef, iterator.next(), index, input)) { return true } index++ } return false }, getIndex: index => input => { const iterator = getIterator(input) let i = 0 while (iterator.hasNext()) { if (i === index) { return iterator.next() } iterator.next() index++ } }, reduce: (callback, initVal) => input => { const iterator = getIterator(input) let index = 0 let acc = initVal === undefined ? iterator.next() : initVal while (iterator.hasNext()) { acc = callback(acc, iterator.next(), index, input) index++ } return acc }, sort: callback => input => { const iterator = getIterator(input) const output = Collection.toArray(input) return output.sort(callback) }, } const hasNativeFunction = (input, name) => { try { return TYPES.FUNCTION.is(input[name]) } catch (e) { return false } } // prettier-ignore const callbackWrapper = (name, type) => (...args) => input => { if (input == null) { return input } if (hasNativeFunction(input, name)) { return protos.call(name, ...args)(input) } else if (type.is(input) && polyfills[type.toString()] && polyfills[type.toString()][name]) { return polyfills[type.toString()][name](...args)(input) } else if (input instanceof dw.util.Collection || input instanceof dw.util.Iterator) { return Collection[name](...args)(input) } else { throw new Error(`The function ${name} does not exist for type ${getConstructorName(input)}`) } } const isEmpty = input => { if (input == null) { return true } else if (TYPES.STRING.is(input)) { return !input || input == '' || input.length === 0 } else if (TYPES.ARRAY.is(input)) { return input.length === 0 } else if (input instanceof dw.util.Collection) { return input.isEmpty() } else if (input instanceof dw.util.Iterator) { return input.hasNext() } else if (TYPES.OBJECT.is(input)) { return Object.keys(input).length === 0 } else { return false } } //Create common curried version of Array and Object prototypes //To be used in conjunction with 'get' module.exports = protos //Special ES5 support module.exports.toArray = () => input => { if (input == null) { return input } if (TYPES.ARRAY.is(input)) { return input } else if (input instanceof dw.util.Collection || input instanceof dw.util.Iterator) { return Collection.toArray(input) } else { throw new Error(`Cannot convert input of type ${getConstructorName(input)} into Array`) } } //Collection, Iterable, and pollyfill support module.exports.filter = callbackWrapper('filter', TYPES.ARRAY) module.exports.find = callbackWrapper('find', TYPES.ARRAY) module.exports.map = callbackWrapper('map', TYPES.ARRAY) module.exports.forEach = callbackWrapper('forEach', TYPES.ARRAY) module.exports.concat = callbackWrapper('concat', TYPES.ARRAY) module.exports.every = callbackWrapper('every', TYPES.ARRAY) module.exports.some = callbackWrapper('some', TYPES.ARRAY) module.exports.getIndex = callbackWrapper('getIndex', TYPES.ARRAY) module.exports.reduce = callbackWrapper('reduce', TYPES.ARRAY) //Object module.exports.values = callbackWrapper('values', TYPES.OBJECT) module.exports.entries = callbackWrapper('entries', TYPES.OBJECT) //Java class specific prototypes module.exports.contains = protos._call('contains') module.exports.containsAll = protos._call('containsAll') module.exports.add = protos._call('add') module.exports.addAll = protos._call('addAll') module.exports.clear = protos._call('clear') module.exports.remove = protos._call('remove') module.exports.removeAll = protos._call('removeAll') //custom functions module.exports.isEmpty = () => input => isEmpty(input) module.exports.isNotEmpty = () => input => !isEmpty(input) module.exports.getProp = key => input => { return input != null ? (Object.hasOwnProperty.call(input, key) ? input[key] : undefined) : input } //for browser static import loadGlobal(module.exports)