UNPKG

underarm

Version:

Transducers for JavaScript with Underscore API and Async extensions

310 lines (269 loc) 8.88 kB
'use strict' var dispatcher = require('redispatch') module.exports = function(_r){ var _ = _r._, as = _r.as, // sentinel to ignore wrapped objects (maintain only last item) IGNORE = _r.IGNORE = {} // Transducer Functions // -------------------- var core = require('transduce/core'), value = _r.value = dispatcher(), wrap = _r.wrap = dispatcher(), unwrap = _r.unwrap = dispatcher(), empty = _r.empty = dispatcher(), append = _r.append = dispatcher(), reduce = _r.reduce = dispatcher(), _reduce = core.reduce, _unreduced = core.unreduced, transduce = _r.transduce = dispatcher(), _transduce = core.transduce, into = _r.into = dispatcher(), transducer = _r.transducer = dispatcher(), iterator = _r.iterator = dispatcher(), _iterable = core.iterable, _protocols = core.protocols, toArray = _r.toArray = dispatcher(), _toArray = core.into([]), _util = require('./util-internal'), iteratee = _r.iteratee = dispatcher() _r.resolveSingleValue = resolveSingleValue _r.resolveMultipleValues = resolveMultipleValues _r.reduced = core.reduced _r.isReduced = core.isReduced _r.foldl = reduce _r.inject = reduce _r.deref = unwrap _r.conj = append _r.conjoin = append _r.dispatch = dispatch var compose = _r.compose = core.compose _r.transformer = core.transformer _r.iterable = _iterable _r.protocols = _protocols _r.isFunction = _util.isFunction var isArray = _r.isArray = _util.isArray var isString = _r.isString = _util.isString _r.isRegExp = _util.isRegExp _r.isNumber = _util.isNumber _r.isUndefined = _util.isUndefined _r.arrayPush = _util.arrayPush _r.objectMerge = _util.objectMerge _r.stringAppend = _util.stringAppend var identity = _r.identity = _util.identity // Dispatchers // ----------- // Resolves the value of the wrapped object, similar to underscore. // Returns an array, or single value (to match underscore API) // depending on whether the chained transformation resolves to single value. value.register(function(self){ if(!self._opts.resolveSingleValue){ return self.into() } var ret = self.into(IGNORE) return ret === IGNORE ? void 0 : ret }) _r.prototype.value = function(){ return value(this) } // Helper to mark transducer to expect single value when // resolving. Only valid when chaining, but this should be passed // when called as a function function resolveSingleValue(self){ _resolveSingleValue(self, true) } // Helper to mark transducer to expect multiple values when // resolving. Only valid when chaining, but this should be passed // when called as a function. function resolveMultipleValues(self){ _resolveSingleValue(self, false) } function _resolveSingleValue(self, single){ if(as(self)){ self._opts.resolveSingleValue = single } } // Composes and returns the underlying wrapped functions for give chained object transducer.register(function(self){ var fns = self._wrappedFns return fns.length ? compose.apply(null, fns) : identity }) _r.prototype.transducer = _r.prototype.compose = function() { return transducer(this) } reduce.register(function(xf, init, coll) { if(as(xf)){ xf = transducer(xf) } if (coll === null || coll === void 0) coll = empty(coll) return _reduce(xf, init, coll) }) // Calls transduce using the chained transformation if function not passed _r.prototype.reduce = function(init, coll){ if(coll === void 0){ coll = this._wrapped } return reduce(this, init, coll) } transduce.register(function(xf, f, init, coll){ if(as(xf)){ xf = transducer(xf) } return unwrap(_transduce(xf, f, init, coll)) }) // Calls transduce using the chained transformation _r.prototype.transduce = function(f, init, coll){ if(coll === void 0){ coll = this._wrapped } return transduce(this, f, init, coll) } // Returns a new coll consisting of to-coll with all of the items of // from-coll conjoined. A transducer (step function) may be supplied. into.register(function(to, xf, from){ if(from === void 0){ from = xf xf = void 0 } if(from === void 0){ from = empty() } if(as(xf)){ xf = transducer(xf) } if(to === void 0){ to = empty(from) } if(xf === void 0){ return reduce(append, to, from) } return transduce(xf, append, to, from) }) // Calls into using the chained transformation _r.prototype.into = function(to, from){ if(from === void 0){ from = this._wrapped } return into(to, this, from) } // Returns a new collection of the empty value of the from collection toArray.register(function(xf, from){ if(as(xf)){ xf = transducer(xf) } if(arguments.length === 1){ return _toArray(xf) } return _toArray(xf, from) }) // calls toArray with chained transformation and optional wrapped object _r.prototype.toArray = function(from){ if(from === void 0){ from = this._wrapped } return toArray(this, from) } // Wraps a value used as source for use during chained transformation. // // Default returns value, or _r.empty() if undefined. // // Dispatch function. To support different types, // call _r.unwrap.register wrap.register(function(value){ if(isString(value)){ value = [value] } else if(value === null || value === void 0){ value = empty() } return value }) // Unwraps (deref) a possibly wrapped value // Default unwraps values created with _r.reduced, // or calls value() on chained _r transformations, // otherwise returns parameter. // // Dispatch function. To support different types, // call _r.unwrap.register unwrap.register(function(value){ if(as(value)){ return value.value() } return _unreduced(value) }) // Returns an iterator that has next function // and returns {value, done}. Default looks for // object with iterator Symbol (or '@@iterator'). // This is available with _r.iterator.Symbol // // Dispatch function. To support different types // call _r.iterator.register and supply function that returns // an iterator after checking the input using appropriate // predicates. Return undefined if not supported, so other // dispatched functions can be checked iterator.register(function(value){ return _iterable(value)[_protocols.iterator]() }) // Mostly internal function that generates a callback from the given value. // For use with generating callbacks for map, filter, find, etc. // // Default returns _.iteratee. // // Dispatch function. To support different types // call _r.iteratee.register and supply function that returns // a callback after checking the input using appropriate // predicates. Return undefined if not supported, so other // dispatched functions can be checked iteratee.register(function(value){ if(as(value)){ return _riteratee(value) } return _.iteratee(value) }) function _riteratee(value){ return function(item){ return value.withSource(item).value() } } // Returns empty object of the same type as argument. // Default returns [] if isArray or undefined, {} if _.isObject // and an internal sentinel to ignore otherwise // // Dispatch function. To support different types // call _r.empty.register and supply function that returns // an empty object after checking the input using appropriate // predicates. Return undefined if not supported, so other // dispatched functions can be checked empty.register(function(obj){ if(obj === void 0 || isArray(obj) || iterator(obj)){ return [] // array if not specified or from array } else if(_.isObject(obj)){ return {} // object if from object } // ignore by default. Default append just maintains last item. return IGNORE }) // Appends (conjoins) the item to the collection, and returns collection // // Dispatch function. To support different types // call _r.append.register and supply function that append to the object // (first param) with the item and optional key after checking the input // using appropriate predicates. // // Return undefined if not supported, so other dispatched functions can be checked append.register(function(obj, item){ if(isArray(obj)){ obj.push(item) return obj } // just maintain last item return item }) // Reducer that dispatches to empty, unwrap and append function Dispatch(){} Dispatch.prototype.init = empty Dispatch.prototype.result = unwrap Dispatch.prototype.step = append function dispatch(){ return new Dispatch() } }