Comparing version 1.1.2 to 2.1.0
1564
itbl.js
@@ -1,779 +0,959 @@ | ||
;(function(root, factory) { | ||
if (typeof define === 'function' && define.amd) { | ||
define(['lodash'], factory); | ||
} else if (typeof exports === 'object') { | ||
module.exports = factory(require('lodash')); | ||
} else { | ||
root.itbl = factory(root._); | ||
;(function() { | ||
'use strict'; | ||
/** Do basic error checking */ | ||
const ARGS_CHECK = true; | ||
/** Expose internal modules for testing */ | ||
const EXPOSE_INTERNAL = true; | ||
/** check `Symbol`'s are supported */ | ||
if (typeof Symbol === `undefined`) { | ||
throw new Error('es6 Symbols are required for the itbl libary'); | ||
} | ||
}(this, function(_) { | ||
'use strict'; | ||
var isSymbol = _.isSymbol | ||
var isFunction = _.isFunction | ||
/** Detect free variable `global` from Node.js. */ | ||
const freeGlobal = typeof global == 'object' && global && global.Object === Object && global; | ||
/** Detect free variable `self`. */ | ||
const freeSelf = typeof self == 'object' && self && self.Object === Object && self; | ||
var supported = typeof Symbol !== 'undefined' && Symbol != null && isSymbol(Symbol.iterator), | ||
itSymb = supported ? Symbol.iterator : null; | ||
function definitions(addTo) { | ||
/** Detect free variable `exports`. */ | ||
const freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; | ||
/** Detect free variable `module`. */ | ||
const freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; | ||
/** Used as a reference to the global object. */ | ||
const root = freeGlobal || freeSelf || Function('return this')(); | ||
/** Used to restore the original `itbl` reference in `itbl.noConflict`. */ | ||
const oldItbl = root.itbl; | ||
/** Used to access `@@iterator` method */ | ||
const iteratorSymbol = Symbol.iterator; | ||
/** | ||
* Read only boolean value indicating whether es6 iterators are supported. | ||
* Function that returns the first argument it recieves | ||
* | ||
* @private | ||
* @memberOf itbl | ||
* @since 2.0.0 | ||
* | ||
* @param {*} value Any Value. | ||
* | ||
* @returns {boolean} Returns `value` | ||
* @noexcept | ||
*/ | ||
const identity = value => value; | ||
/** | ||
* Used to bind `this` and arguments to funciton | ||
* | ||
*/ | ||
const funcBind = Function.prototype.bind; | ||
/** | ||
* Determine if a value is a function. | ||
* | ||
* @see http://stackoverflow.com/a/17108198 | ||
* | ||
* @private | ||
* @memberOf itbl | ||
* @since 2.0.0 | ||
* | ||
* @param {*} value Value to check if function. | ||
* | ||
* @returns {boolean} Weather value is function or not. | ||
* @noexcept | ||
*/ | ||
const _isFunction = value => typeof value === 'function'; | ||
/** | ||
* @typedef {{ value: *, done: boolean }} Step | ||
*/ | ||
/** | ||
* Base class with prototype containing chained itbl methods. | ||
* This class is returned by `itbl()` and `itbl.wrap()`. | ||
* | ||
* @static | ||
* @extends Iterable | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @property {boolean} | ||
* @name nativeIterators | ||
* @constructor | ||
* @noexcept | ||
* | ||
* <table> | ||
* <tr> | ||
* <td colspan="2">Property attributes of <code>nativeIterators</code></td> | ||
* </tr> | ||
* <tr> <td>Writable</td> <td>no</td> </tr> | ||
* <tr> <td>Enumerable</td> <td>yes</td> </tr> | ||
* <tr> <td>Configurable</td> <td>no</td> </tr> | ||
* </table> | ||
*/ | ||
Object.defineProperty(addTo, 'nativeIterators', { | ||
value: supported, | ||
enumerable: true, | ||
configurable: false, | ||
writable: false | ||
}); | ||
const _Wrapper = function() {}; | ||
/** | ||
* @name [Symbol.iterator] | ||
* | ||
* Get an iterator to the wrapped iterable. | ||
* | ||
* @memberof itbl | ||
* @since 2.0.0 | ||
* @returns {itbl} Returns a wrapped iterator. | ||
* | ||
* @throws Throws if the wrapped value is an iterator or an iterable whose [Symbol.iterator] | ||
* method throws. | ||
*/ | ||
/** | ||
* Symbol or string used by libary to access iterator method, | ||
* defaults to `es6`'s `Symbol.iterator`. | ||
* Can be overwritten by a symbol or by any non-null value convertable | ||
* to a string to allow polyfilled support for iterators. | ||
* @name next | ||
* | ||
* Get the next value of this iterator | ||
* | ||
* ** This method is only defined if the wrapped value is an iterator ** | ||
* | ||
* @memberof itbl | ||
* @since 2.0.0 | ||
* @returns {Step} Returns the next iterator value. | ||
* @throws Throws if the wrapped iterator's next method throws. | ||
* | ||
*/ | ||
/** | ||
* @name return | ||
* | ||
* Returns given value and finishes the iterator. | ||
* | ||
* ** This method is only defined if the wrapped value is defines a return method ** | ||
* | ||
* @memberof itbl | ||
* @since 2.0.0 | ||
* | ||
* @param {*} value The value to return | ||
* | ||
* @returns {Step} Returns a `{@link Step}` with a value of `value`. | ||
* @throws Throws if the wrapped iterator's return method throws. | ||
* | ||
*/ | ||
/** | ||
* @name throw | ||
* | ||
* The throw() method resumes the execution of a generator by throwing an error into it and returns an | ||
* object with two properties done and value. | ||
* | ||
* ** This method is only defined if the wrapped value is an iterator ** | ||
* | ||
* @memberof itbl | ||
* @since 2.0.0 | ||
* | ||
* @param {*} exception The exception to throw. For debugging purposes, it is useful to make it an `instanceof | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error Error}`. | ||
* | ||
* @returns {Step} Returns the next iterator value. | ||
* @throw Throws if the wrapped iterator's return method throws, for a generator function this happens if the | ||
* yield expression is not contained within a try-catch block. | ||
* | ||
*/ | ||
/** | ||
* Checks if `value` is an iterator according to es6 iterator protocols. | ||
* An object is an iterator when it implements a next() method. | ||
* https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols#iterator | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @property {string|Symbol} | ||
* @name iteratorSymbol | ||
* @param {*} value The value to check. | ||
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
* @noexcept | ||
* @example | ||
* | ||
* <table> | ||
* <tr> | ||
* <td colspan="2">Property attributes of <code>iteratorSymbol</code></td> | ||
* </tr> | ||
* <tr> <td>Writable</td> <td>yes</td> </tr> | ||
* <tr> <td>Enumerable</td> <td>yes</td> </tr> | ||
* <tr> <td>Configurable</td> <td>no</td> </tr> | ||
* </table> | ||
* function MyIterable() { } | ||
* MyIterable.prototype[Symbol.iterator] = function*(){ | ||
* while(true) yield 1; | ||
* } | ||
* | ||
* let iterableInstance = new MyIterable(); | ||
* | ||
* itbl.isIterable(iterableInstance); | ||
* // => false (this is an iterable but NOT an iterator) | ||
* | ||
* // generator function that is then called | ||
* itbl.isIterable(iterableInstance[Symbol.iterator]()); | ||
* // => true (this is both an iterator and also iterable) | ||
* | ||
* itbl.isIterator([1, 2, 3][Symbol.iterator]()); | ||
* // => true | ||
* | ||
* for(let i of ['a']) | ||
* itbl.isIterator(i) | ||
* // => false (i is equal to 'a') | ||
*/ | ||
Object.defineProperty(addTo, 'iteratorSymbol', { | ||
get: function() { return itSymb; }, | ||
set: function(v) { | ||
itSymb = isSymbol(v) | ||
? v | ||
: v == null || !isFunction(v.toString) | ||
? null | ||
: v + ''; | ||
}, | ||
enumerable: true, | ||
configurable: false | ||
}); | ||
} | ||
const isIterator = value => value != null && _isFunction(value.next); | ||
// add definitions to module but also export function that | ||
// will add definitions to other objects. | ||
/** | ||
* Checks if `value` is an iterable object according to es6 iterator protocols. | ||
* In order to be iterable, an object must implement the @@iterator method, | ||
* meaning that the object (or one of the objects up its prototype chain) | ||
* must have a property with a Symbol.iterator key which defines a function. | ||
* (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols#iterable) | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {*} value The value to check. | ||
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. | ||
* @noexcept | ||
* @example | ||
* | ||
* | ||
* function MyIterable() { } | ||
* MyIterable.prototype[Symbol.iterator] = function*(){ | ||
* while(true) yield 1; | ||
* } | ||
* | ||
* let iterableInstance = new MyIterable(); | ||
* | ||
* itbl.isIterable(iterableInstance); | ||
* // => true | ||
* | ||
* // generator function that is then called | ||
* itbl.isIterable(iterableInstance[Symbol.iterator]()); | ||
* // => true (this is both an iterator and also iterable) | ||
* | ||
* itbl.isIterable([1, 2, 3]); | ||
* // => true | ||
* | ||
* itbl.isIterable({1: 1, 2: 2, 3: 3}); | ||
* // => false | ||
*/ | ||
const isIterable = value => value != null && _isFunction(value[iteratorSymbol]); | ||
definitions(definitions); | ||
/** | ||
* Wraps an iterator, adding chainable itbl methods. | ||
* The `itbl` objects returned by `_wrapIterable()` will conform to both the | ||
* iterable protocol and the iterator protocol as well as defining the `return()` | ||
* and `throw()` methods if (and only if) `iterator` defines them. | ||
* | ||
* Use the methods parameter to overwrite the `next`, `return`, `throw` or | ||
* `[Symbol.iterator]` methods of `iterator`, `this` is bound to `iterator`. | ||
* | ||
* **Note**: There is no error checking. | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterator} iterator Iterator to wrap. | ||
* @param {function} [methods.next] Replacement `next` method | ||
* @param {function} [methods.return] Replacement `next` method | ||
* @param {function} [methods.throw] Replacement `next` method | ||
* @param {function} [methods[Symbol.iterator]] Replacement `[Symbol.iterator]` method | ||
* | ||
* @return {itbl} Wrapped iterator. | ||
* @noexcept | ||
* | ||
*/ | ||
const _wrapIterator = function _wrapIterator(iterator, methods) { | ||
var wrapper = new _Wrapper(); | ||
/** | ||
* Base class with prototype containing chained itbl methods. | ||
* This class is returned by `itbl()` and `itbl.wrap()`. | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @constructor | ||
* | ||
*/ | ||
var Wrapper = function() {}; | ||
methods = methods != null | ||
? methods | ||
: {}; | ||
wrapper.next = funcBind.call( | ||
methods.next != null | ||
? methods.next | ||
: iterator.next, | ||
iterator | ||
); | ||
var bind = _.bind | ||
if (methods[iteratorSymbol] != null) { | ||
wrapper[iteratorSymbol] = funcBind.call(methods[iteratorSymbol], iterator); | ||
} | ||
else if (iterator[iteratorSymbol] != null) { | ||
wrapper[iteratorSymbol] = funcBind.call(iterator[iteratorSymbol], iterator); | ||
} | ||
else { | ||
wrapper[iteratorSymbol] = () => wrapper; | ||
} | ||
if (methods.return != null) { | ||
wrapper.return = funcBind.call(methods.return, iterator); | ||
} else if (iterator.return != null) { | ||
wrapper.return = funcBind.call(iterator.return, iterator); | ||
} | ||
// the es6 way to implement this class probabaly uses Proxy. | ||
if (methods.throw != null) { | ||
wrapper.throw = funcBind.call(methods.throw, iterator); | ||
} else if (iterator.throw != null) { | ||
wrapper.throw = funcBind.call(iterator.throw, iterator); | ||
} | ||
/** | ||
* Wraps an iterator, adding chainable itbl methods. | ||
* The `itbl.Wrapper` objects returned by `wrapIterable()` will conform to both the | ||
* iterable protocol and the iterator protocol as well as defining the `return()` | ||
* and `throw()` methods if (and only if) `iterator` defines them. | ||
* | ||
* **Note**: There is no error checking. | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {iterator} iterator Iterator to wrap. | ||
* | ||
* @return {itbl.Wrapper} Wrapped iterator. | ||
* | ||
*/ | ||
function wrapIterator(iterator) { | ||
var wrapper = new Wrapper(); | ||
wrapper.next = bind(iterator.next, iterator); | ||
wrapper[definitions.iteratorSymbol] = function() { return this; } | ||
if( isFunction(iterator['return']) ) | ||
wrapper['return'] = bind(iterator['return'], iterator); | ||
if( isFunction(iterator['throw']) ) | ||
wrapper.throw = bind(iterator['throw'], iterator); | ||
return wrapper; | ||
} | ||
return wrapper; | ||
}; | ||
/** | ||
* Wraps an iterable, adding chainable itbl methods. | ||
* The `itbl` objects returned by `_wrapIterable()` will conform to the iterable protocol. | ||
* | ||
* The iterator returned by the `[Symbol.iterator]` method will be wrapped and so contain chainable | ||
* itbl methods. | ||
* | ||
* Use the methods parameter to overwrite the `next`, `return`, `throw` or | ||
* `[Symbol.iterator]` methods of the iterator produced by `iterable`. | ||
* | ||
* **Note**: The objects returned by the `[Symbol.iterator]` method are checked to ensure that they are iterators. | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Iterable to wrap. | ||
* @param {function} [methods.next] Replacement `next` method | ||
* @param {function} [methods.return] Replacement `next` method | ||
* @param {function} [methods.throw] Replacement `next` method | ||
* @param {function} [methods[Symbol.iterator]] Replacement `[Symbol.iterator]` method | ||
* | ||
* @return {itbl} Wrapped iterable. | ||
* @throws Throws `Error` if the objects returned by the `[Symbol.iterator]` method are not iterators. | ||
* | ||
*/ | ||
const _wrapIterable = function _wrapIterable(iterable, methods) { | ||
// the es6 way to implement this class probabaly uses Proxy. | ||
var wrapper = new _Wrapper(); | ||
wrapper[iteratorSymbol] = function() { | ||
let iter = iterable[iteratorSymbol](); | ||
/** | ||
* Wraps an iterable, adding chainable itbl methods. | ||
* The `itbl.Wrapper` objects returned by `wrapIterable()` will conform to the iterable protocol. | ||
* | ||
* **Note**: There is no error checking. | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {iterable} iterable Iterable to wrap. | ||
* | ||
* @return {itbl.Wrapper} Wrapped iterable. | ||
* | ||
*/ | ||
function wrapIterable(iterable) { | ||
if (ARGS_CHECK && !isIterator(iter)) { | ||
throw new Error('itbl: `[Symbol.iterator]` method has not returned an iterator'); | ||
} | ||
return _wrapIterator(iter, methods); | ||
}; | ||
var wrapper = new Wrapper(); | ||
wrapper[definitions.iteratorSymbol] = function() { | ||
return wrapIterator(iterable[definitions.iteratorSymbol]()); | ||
return wrapper; | ||
}; | ||
return wrapper; | ||
} | ||
/** | ||
* Wraps a generator function to produce a @link{itbl wrapped iterable}. | ||
* | ||
* The generator function can be any function that returns an iterator, this includes functions | ||
* declared `function* gen() {}`. | ||
* | ||
* If the function produces independent iterators each time it is called (which `function*() { ... }` does) | ||
* then iterating over the created iterable wil not cause it to change, so it can be used multiple times. | ||
* | ||
* **Note**: The objects returned by the `generator` are checked to ensure that they are iterators and | ||
* wrapped by in an itbl instance. | ||
* | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {function} generator A function that returns iterators. | ||
* | ||
* @returns {itbl} An iterable. | ||
* @throws Throws `Error` if the objects returned by the `[Symbol.iterator]` method are not iterators. | ||
* | ||
*/ | ||
const _generateIterable = generator => _wrapIterable({ [iteratorSymbol]: generator }); | ||
/** | ||
* Gets iterator from `iterable`. This is equivalent to calling `iterable[Symbol.iterator]` but | ||
* produces helpful error messages. | ||
* | ||
* If `iterable` is omitted then an 'empty' iterator is returned. | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Iterable to get N iterator to. | ||
* @param {String} funcName Name of function to blame error on. | ||
* @param {String} iterableName Name of `iterable` to include in error message; | ||
* | ||
* @returns {itbl} An iterator | ||
* @throws {Error} Throws an error if `iterable` is not iterable. | ||
* | ||
* @example | ||
* | ||
* let it = itbl.getIterator([1,2,3]); | ||
* | ||
* it.next() // { value: 1, done: false } | ||
* it.next() // { value: 2, done: false } | ||
* it.next() // { value: 3, done: false } | ||
* it.next() // { value: undefined, done: true } | ||
* | ||
*/ | ||
const _getIterator = function _getIterator(iterable, funcName, iterableName) { | ||
/** | ||
* Wraps a generator function to produce a @link{itbl.Wrapper wrapped iterable}. | ||
* | ||
* The generator function can be any function that returns an iterator, this includes functions | ||
* declared `function* gen() {}`. | ||
* | ||
* If the function produces independant iterators each time it is called (which `function*() { ... }` does) | ||
* then iterating over the created iterable wil not cause it to change, so it can be used multiple times. | ||
* | ||
* **Note**: There is no error checking. | ||
* | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {function} generator A function that returns iterators. | ||
* | ||
* @returns {itbl.Wrapper} An iterable. | ||
* | ||
*/ | ||
function generateIterable(generator) { | ||
var itbl = {}; | ||
itbl[definitions.iteratorSymbol] = generator; | ||
return wrapIterable(itbl); | ||
} | ||
if (ARGS_CHECK && !isIterable(iterable)) { | ||
throw new Error(`\`itbl.${funcName}()\`: ${iterableName} is not iterable as the [Symbol.iterator] method not defined).`); | ||
} | ||
let iterator = iterable[iteratorSymbol](); | ||
if (ARGS_CHECK && !isIterator(iterator)) { | ||
throw new Error(`itbl: ${iterableName} is not iterable as the [Symbol.iterator] method does not return an iterator.`); | ||
} | ||
/** | ||
* Checks if `value` is an iterable objectaccording to es6 iterator protocols. | ||
* In order to be iterable, an object must implement the @@iterator method, | ||
* meaning that the object (or one of the objects up its prototype chain) | ||
* must have a property with a Symbol.iterator key which defines a function. | ||
* (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols#iterable) | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {*} value The value to check. | ||
* @returns {boolean} Returns `true` if `value` is correctly classified, | ||
* else `false`. | ||
* @example | ||
* | ||
* | ||
* function MyIterable() { } | ||
* MyIterable.prototype[Symbol.iterator] = function*(){ | ||
* while(true) yield 1; | ||
* } | ||
* | ||
* let iterableInstance = new MyIterable(); | ||
* | ||
* itbl.isIterable(iterableInstance); | ||
* // => true | ||
* | ||
* // generator function that is then called | ||
* itbl.isIterable(iterableInstance[Symbol.iterator]()); | ||
* // => true (this is both an iterator and also iterable) | ||
* | ||
* itbl.isIterable([1, 2, 3]); | ||
* // => true | ||
* | ||
* itbl.isIterable({1: 1, 2: 2, 3: 3}); | ||
* // => false | ||
*/ | ||
function isIterable(value) { | ||
return value != null && isFunction(value[definitions.iteratorSymbol]); | ||
}; | ||
return _wrapIterator(iterator); | ||
}; | ||
/** | ||
* Wraps `value` to produce an object that conforms to the | ||
* iterable protocol and - if `value` is an iterator - the iterator protocol. | ||
* | ||
* If `value` is an iterable or an iterator, then `value` will be wrapped in an | ||
* instance of `itbl`. | ||
* | ||
* If `value` is not an iterable, an iterator or a function then `wrap` will throw | ||
* an exception. | ||
* | ||
* If `value` is a function, an iterable instance of `itbl` will be returned. | ||
* When the `[Symbol.iterator]` method is called, `value` will be invoked. | ||
* - If `value` returns an iterator it will be wrapped | ||
* - If `value` returns an iterable then its | ||
* `[Symbol.iterator]` method will be called and that iterator wrapped. | ||
* - If `value` returns any other value (including a function) an expception | ||
* will be thrown. | ||
* | ||
* Therefore all of these are roughly equivalent: | ||
* ```javascript | ||
* itbl([6]); | ||
* itbl(function() { return [6]; }); | ||
* itbl(function() { return [6][Symbol.iterator](); }); | ||
* | ||
* // this can only be iterated over once, unlike all the above | ||
* itbl([6][Symbol.iterator]()); | ||
* ``` | ||
* | ||
* These will raise an exception: | ||
* <!-- skip-example --> | ||
* ```javascript | ||
* itbl(function() { return 6; }); | ||
* itbl(6); | ||
* ``` | ||
* | ||
* All itbl functions that take an iterable as their first parameter | ||
* and return an iterable are chainable and so can be called as methods of the | ||
* wrapped value. | ||
* | ||
* The chainable methods are: | ||
* | ||
* `filter` and `map`. | ||
* | ||
* @static | ||
* @name itbl | ||
* @alias wrap | ||
* @since 0.1.0 | ||
* @param {*} value The value to wrap. | ||
* | ||
* @returns {itbl} An iterable which may also be an iterator. | ||
* @throws If `value` defines a `[Symbol.iterator]` method but that method does not | ||
* return valid iterators then an `Error` will be thrown when the wrapped iterable | ||
* is iterated over. | ||
* | ||
* @example | ||
* let students = [ | ||
* { | ||
* name: 'Martin Smith', | ||
* subject: 'Maths', | ||
* }, | ||
* { | ||
* name: 'John Arthur', | ||
* subject: 'English', | ||
* }, | ||
* { | ||
* name: 'Rachel Richardson', | ||
* subject: 'Maths', | ||
* }, | ||
* ]; | ||
* | ||
* // get the name of all maths students | ||
* let mathematicians = itbl(students) | ||
* .filter(_.matchesProperty('subject', 'Maths')) | ||
* .map(_.property('name')); | ||
* | ||
* [...mathematicians]; | ||
* // -> ['Martin Smith', 'Rachel Richardson'] | ||
* | ||
* let arr = [1, 7, 8, 9]; | ||
* | ||
* let arrayReverse = function arrayReverse(array) { | ||
* return itbl(function* () { | ||
* let i = array.length-1; | ||
* while(i >= 0) { | ||
* yield array[i]; | ||
* i--; | ||
* } | ||
* }); | ||
* }; | ||
* | ||
* [...arrayReverse(arr)]; | ||
* // -> [9, 8, 7, 1] | ||
* | ||
*/ | ||
const wrap = function wrap(value) { | ||
/** | ||
* Checks if `value` is an iterator according to es6 iterator protocols. | ||
* An object is an iterator when it implements a next() method. | ||
* https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols#iterator | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {*} value The value to check. | ||
* @returns {boolean} Returns `true` if `value` is correctly classified, | ||
* else `false`. | ||
* @example | ||
* | ||
* function MyIterable() { } | ||
* MyIterable.prototype[Symbol.iterator] = function*(){ | ||
* while(true) yield 1; | ||
* } | ||
* | ||
* let iterableInstance = new MyIterable(); | ||
* | ||
* itbl.isIterable(iterableInstance); | ||
* // => false (this is an iterable but NOT an iterator) | ||
* | ||
* // generator function that is then called | ||
* itbl.isIterable(iterableInstance[Symbol.iterator]()); | ||
* // => true (this is both an iterator and also iterable) | ||
* | ||
* itbl.isIterator([1, 2, 3][Symbol.iterator]()); | ||
* // => true | ||
* | ||
* for(let i of ['a']) | ||
* itbl.isIterator(i) | ||
* // => false (i is equal to 'a') | ||
*/ | ||
function isIterator(value) { | ||
return value != null && isFunction(value.next); | ||
}; | ||
if (value instanceof _Wrapper) { | ||
return value; | ||
} | ||
if (isIterator(value)) { | ||
return _wrapIterator(value); | ||
} | ||
var constant = _.constant | ||
// note iterators may also be iterable but they are treated as iterators | ||
if (isIterable(value)) { | ||
return _wrapIterable(value); | ||
} | ||
if (_isFunction(value)) { | ||
return _generateIterable(function() { | ||
let result = value(); | ||
/** | ||
* Wraps an iterable, iterator, generator function (any function | ||
* that returns iterators), or a value to produce an objcet that conforms to the | ||
* iterable protocol (and iterator protocol if `value` is an iterator). | ||
* | ||
* If a value is provided that is not an iterable or an iterator, or is a function that does | ||
* not return iterators, it (or its return value) is wrapped in an iterable so that `itbl(6)` | ||
* is equivilent to both `itbl(function() { return 6; })` and `itbl([6])` | ||
* | ||
* All itbl functions that take an iterable as their first parameter | ||
* and return an iterable are chainable and so can be called as methods of the | ||
* wrapped value. | ||
* | ||
* The chainable methods are: | ||
* | ||
* `filter` and `map`. | ||
* | ||
* In custom builds, including a function in the build will attach that function | ||
* as a method to all wrapped values. | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @alias itbl | ||
* @since 0.1.0 | ||
* @param {*} value The value to wrap. | ||
* | ||
* @returns {itbl.Wrapper} An iterable which may also be an iterator. | ||
* | ||
*/ | ||
function wrap(value) { | ||
if( isIterator(value) ) | ||
return wrapIterator(value); | ||
// note iterators may also be iterable but they are treated as iterators | ||
if( isIterable(value) ) | ||
return wrapIterable(value); | ||
if( isFunction(value) ) | ||
return generateIterable(function(){ | ||
var it = value(), | ||
count = 0; | ||
if( isIterator(it) ) | ||
return it; | ||
else | ||
if (isIterator(value)) { | ||
return result; | ||
} | ||
// get iterator from iterable | ||
if (isIterable(result)) { | ||
return result[iteratorSymbol](); | ||
} | ||
throw new Error('itbl(): the object returned from value is not an iterable or an iterator'); | ||
}); | ||
} | ||
throw new Error('itbl(): value is not an iterable, an iterator or a generator function'); | ||
}; | ||
/** | ||
* Creates a new iterable whose iterators will have values corresponding to the value | ||
* of the Iterator of the original iterable run through `iteratee`. | ||
* The iteratee is invoked with only one argument (value). | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Iterable to map values of. | ||
* @param {Function} [iteratee = _.identity] Function to run each value though. | ||
* | ||
* @returns {itbl} A new mapped iterable | ||
* @throws {Error} Throws an error if `iterable` is not iterable. | ||
* | ||
* @example | ||
* | ||
* for(let coor of itbl.map([0, 1, 2, 3, 4, 5], x => ({ x, y: Math.exp(x) }))) { | ||
* context.lineTo(coor.x, coor.y); | ||
* } | ||
* | ||
* let mySet = new Set().add(1).add('a').add(NaN); | ||
* | ||
* [...itbl.map(mySet, value => value + 1)]; | ||
* // [2, 'a1', NaN] | ||
* | ||
* var users = [ | ||
* { 'user': 'barney' }, | ||
* { 'user': 'fred' }, | ||
* ]; | ||
* | ||
* [...itbl.map(users, _.property('user'))]; | ||
* // => ['barney', 'fred'] | ||
* | ||
*/ | ||
const map = function map(iterable, iteratee) { | ||
iteratee = iteratee != null | ||
? iteratee | ||
: identity; | ||
if (ARGS_CHECK && !isIterable(iterable)) { | ||
throw new Error('itbl.map: `iterable` does not define the `[Symbol.iterator]` method'); | ||
} | ||
return (isIterator(iterable) | ||
? _wrapIterator | ||
: _wrapIterable | ||
)(iterable, { | ||
next() { | ||
const step = this.next(); | ||
let mapped; | ||
if (!step.done) { | ||
mapped = iteratee(step.value); | ||
} | ||
return { | ||
next: function(){ | ||
return count++ | ||
? { done: true } | ||
: { value: it, done: false }; | ||
} | ||
} | ||
value: mapped, | ||
done: step.done, | ||
}; | ||
}, | ||
}); | ||
return generateIterable(function(){ | ||
var count = 0; | ||
return { | ||
next: function(){ | ||
return count++ | ||
? { done: true } | ||
: { value, done: false }; | ||
} | ||
}; | ||
_Wrapper.prototype.map = function(iteratee) { | ||
return map(this, iteratee); | ||
}; | ||
/** | ||
* Creates a new iterable containing values which the `predicate` returns truthy for. | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Iterable to filter the values of. | ||
* @param {Function} [predicate = _.identity] Function to run each value though. | ||
* | ||
* @returns {itbl} New filtered iterable | ||
* @throws {Error} Throws an error if iterators are not supported or the `iterable` is not iterable. | ||
* | ||
* @example | ||
* | ||
* [...itbl.filter([0,1,2,3,4,5], val => val%2 === 0)]; | ||
* // [0,2,4] | ||
* | ||
* let mySet = new Set().add(1).add('a').add(NaN); | ||
* | ||
* [...itbl.filter(mySet, value => _.isFinite)]; | ||
* // [1] | ||
* | ||
* var users = [ | ||
* { 'user': 'barney', 'age': 36, 'active': true }, | ||
* { 'user': 'fred', 'age': 40, 'active': false } | ||
* ]; | ||
* | ||
* [...itbl.filter(users, function(o) { return !o.active; })]; | ||
* // => objects for ['fred'] | ||
* | ||
* [...itbl.filter(users, _.matches({ 'age': 36, 'active': true }))]; | ||
* // => objects for ['barney'] | ||
* | ||
* [...itbl.filter(users, _.matchesProperty('active', false))]; | ||
* // => objects for ['fred'] | ||
* | ||
* [...itbl.filter(users, _.property('active'))]; | ||
* // => objects for ['barney'] | ||
* | ||
*/ | ||
const filter = function filter(iterable, predicate) { | ||
predicate = predicate != null | ||
? predicate | ||
: identity; | ||
if (ARGS_CHECK && !isIterable(iterable)) { | ||
throw new Error('itbl.filter: `iterable` does not define the `[Symbol.iterator]` method'); | ||
} | ||
}); | ||
} | ||
return (isIterator(iterable) | ||
? _wrapIterator | ||
: _wrapIterable | ||
)(iterable, { | ||
next() { | ||
let step; | ||
/** | ||
* Gets iterator from `iterable`. In `es6` environments using default value of `itbl.iteratorSymbol` when | ||
* `iterable` is a valid iterator, this is equivilent to calling `iterable[Symbol.iterator]`. This function includes | ||
* support for different values of `itbl.iteratorSymbol` and helpful error messages. | ||
* | ||
* If `iterable == null` then an 'done' iterator is returned. | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} [iterable = []] Iterable to get iterator to. | ||
* | ||
* @returns {itbl.Wrapper} An iterator | ||
* @throws {Error} Throws an error if iterators are not supported or the argument is not iterable. | ||
* | ||
* @example | ||
* | ||
* let it = itbl.getIterator([1,2,3]); | ||
* | ||
* it.next() // { value: 1, done: false } | ||
* it.next() // { value: 2, done: false } | ||
* it.next() // { value: 3, done: false } | ||
* it.next() // { value: undefined, done: true } | ||
* | ||
*/ | ||
function getIterator(iterable) { | ||
if( definitions.iteratorSymbol == null ) | ||
throw new Error('itbl: Iterators are natively not supported, set itbl.iteratorSymbol to use iterators'); | ||
if( iterable === undefined ) | ||
return { | ||
next: function() { return { done: true }; } | ||
}; | ||
if( !isIterable(iterable) ) | ||
throw new Error('itbl: argument `iterable` is not iterable as the [Symbol.iterator] method not defined).'); | ||
var iterator = iterable[definitions.iteratorSymbol](); | ||
if( !isIterator(iterator) ) | ||
throw new Error('itbl: argument `iterable` is not iterable as the [Symbol.iterator] method does not return an iterator.'); | ||
while (!(step = this.next()).done && !predicate(step.value)) {} | ||
return wrapIterator(iterator); | ||
} | ||
return step; | ||
}, | ||
}); | ||
}; | ||
_Wrapper.prototype.filter = function(predicate) { | ||
return filter(this, predicate); | ||
}; | ||
var mapValues = _.mapValues | ||
var reduce = _.reduce | ||
/** | ||
* Combines the iterables in `iterable` into a single iterable containing iterables | ||
* of values from each iterable in `iterable`. | ||
* | ||
* ** `iterable` is not checked to see if it is actually an iterable. ** | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Collection of iterators | ||
* | ||
* @returns {itbl} Iterable containing collection of values | ||
* @throws {Error} Throws an error if the values of `iterable` are not iterable. | ||
* | ||
*/ | ||
function _iterableCombine(iterable) { | ||
let n = 0; | ||
let iterators = [...itbl.map(iterable, iterableValue => | ||
_getIterator(iterableValue, 'combine', `${++n}th value of \`collection\``) | ||
)]; | ||
/** | ||
* Combines the iterables in `collection` into a single iterable containing collections | ||
* of values from each iterable in `collection`. | ||
* | ||
* `collection` can either be an iterable containing iterable values that will be combined | ||
* into an iterable containing iterables containing all the values of the iterable from `collection` | ||
* or an object whose own, enumerable properties are iterables to be combined into an | ||
* iterable containing objects whose own, enumberable properties are the same as `collection`'s | ||
* and the values of those properties will be the values of the iterable from `collection`. | ||
* | ||
* The value of `finish` determines when the iteration ends. | ||
* | ||
* * If `finish === 'early' or 'e'` (default) then the iteration ends as soon as the first iterator from | ||
* `collection` ends. | ||
* | ||
* * If `finish === 'late' or 'l'` then the iteration continues untill all iterators from `collection` are done. | ||
* Values corresponding to iterators that have ended are `undefined`. | ||
* | ||
* * If `finish === 'together' or 't'` then all iterators from `collection` must finish on the same iteration or | ||
* else an `Error` is thrown. | ||
* | ||
* **Note**: The return value of the iterator is a collection of the of the return values the iterators | ||
* from `collection`. Return values corresponding to iterators that have not yet ended are `undefined` | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {iterable|Object} collection Collection of iterators | ||
* @param {string} [finish = 'early'] Flag determining when iteration will finish. | ||
* | ||
* @returns {itbl.Wrapper} Iterable containing collection of values | ||
* @example | ||
* | ||
* for(let coor of itbl.combine({ | ||
* x: [1,2,3,4,5], | ||
* y: [1,4,9,16,25] | ||
* })){ | ||
* context.lineTo(coor.x, coor.y); | ||
* } | ||
* | ||
* let mySet = new Set(); | ||
* mySet.add(1); | ||
* mySet.add(Math); | ||
* | ||
* let iterable = itbl.combine([['a','b','c'], ['alpha','beta', 'gamma'], mySet]); | ||
* [...iterable]; | ||
* // [['a', 'alpha', 1], ['b', 'beta', Math]] | ||
*/ | ||
function combine(collection, finish) { | ||
if( finish == null ) | ||
finish = 'early'; | ||
else | ||
{ | ||
finish = (finish === 'e' || finish === 'early') | ||
? 'early' | ||
: (finish === 'l' || finish === 'late') | ||
? 'late' | ||
: (finish === 't' || finish === 'together') | ||
? 'together' | ||
: null; | ||
if( finish == null ) | ||
throw new Error('itbl: parameter finish to combine is not reconised'); | ||
let returnValues = []; | ||
return function() { | ||
let values = [], | ||
anyDone = false, | ||
allDone = true, | ||
i = 0; | ||
for (let step of iterators.map(iterator => iterator.next())) { | ||
returnValues[i] = step.done ? step.value : returnValues[i]; | ||
values.push(!step.done ? step.value : undefined); | ||
anyDone = anyDone || step.done; | ||
allDone = allDone && step.done; | ||
// TODO don't like having index variable in for-of loop | ||
++i; | ||
} | ||
return { values, returnValues, anyDone, allDone }; | ||
}; | ||
} | ||
var create = isIterable(collection) | ||
? Array | ||
: Object, | ||
finishLate = (finish === 'late'); | ||
/** | ||
* Combines the iterables in `collection` into a single iterable containing collections | ||
* of values from each iterable in `collection`. | ||
* | ||
* `collection` can either be an Iterable or an object containing Iterables which | ||
* will be combined. The first value in the combined Iterable will be an Iterable or | ||
* an object containing the first values of the Iterables in `collection`, the second | ||
* value containing the second values of the Iterables in `collection` and so on. | ||
* | ||
* The value of `finish` determines when the iteration ends. | ||
* | ||
* * If `finish === 'early' or 'e'` (default) then the iteration ends as soon as the first iterator from | ||
* `collection` ends. | ||
* | ||
* * If `finish === 'late' or 'l'` then the iteration continues untill all iterators from `collection` are done. | ||
* Values corresponding to iterators that have ended are `undefined`. | ||
* | ||
* * If `finish === 'together' or 't'` then all iterators from `collection` must finish on the same iteration or | ||
* else an `Error` is thrown. | ||
* | ||
* **Note**: The return value of the iterator is a collection of the of the return values the iterators | ||
* from `collection`. Return values corresponding to iterators that have not yet ended are `undefined` | ||
* | ||
* `combine` is particularly powerful when used with | ||
* [es6 destructuring assignment](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable|Object} collection Collection of iterators | ||
* @param {string} [finish = 'early'] Flag determining when iteration will finish. | ||
* | ||
* @returns {itbl} Iterable containing collection of values | ||
* @example | ||
* | ||
* let mySet = new Set(); | ||
* mySet.add(1); | ||
* mySet.add(Math); | ||
* | ||
* [...itbl.combine([['a','b','c'], mySet, ['alpha','beta', 'gamma']])]; | ||
* // -> [['a', 1, 'alpha'], ['b', Math, 'beta']] | ||
* | ||
* // with `finish === late` | ||
* [...itbl.combine([['a','b','c'], ['alpha','beta', 'gamma'], mySet], 'late')]; | ||
* // [['a', 1, 'alpha'], ['b', Math, 'beta'], ['c', undefined, 'gamma']] | ||
* | ||
* let coordinates = itbl.combine({ | ||
* x: [1,2,3,4,5], | ||
* y: [1,4,9,16,25], | ||
* }); | ||
* | ||
* for(let coor of coordinates) { | ||
* context.lineTo(coor.x, coor.y); | ||
* } | ||
* | ||
* // more concise syntax using object destructuring | ||
* for(let {x, y} of coordinates) { | ||
* context.lineTo(x,y); | ||
* } | ||
* | ||
*/ | ||
const combine = function combine(collection, finish) { | ||
// TODO potential infinite loop if an iterator changes it's mind about whether it is done or not | ||
let finishLate = false, | ||
finishTogether = false; | ||
switch (finish) { | ||
case undefined: | ||
case null: | ||
case 'e': | ||
case 'early': | ||
break; | ||
case 'l': | ||
case 'late': | ||
finishLate = true; | ||
break; | ||
case 't': | ||
case 'together': | ||
finishTogether = true; | ||
break; | ||
default: | ||
throw new Error('`itbl.combine()`: `finish` is not recognised'); | ||
} | ||
return generateIterable(function() { | ||
// TODO slightly unhelpful error message generated | ||
// also mapValues on array converts to an object, don't that that | ||
// makes any difference | ||
var its = mapValues(collection, getIterator), | ||
done = false; | ||
var returnValues = create(), | ||
anyValues, | ||
values, | ||
cb = finishLate | ||
? function lateCb(every, it, key) { | ||
if( returnValues.hasOwnProperty(key) ) | ||
return every; | ||
var step = it.next(); | ||
if( step.done ) | ||
{ | ||
returnValues[key] = step.value; | ||
return every; | ||
let combiningFunction = isIterable(collection) | ||
? _iterableCombine | ||
: _objectCombine; | ||
return _generateIterable(function() { | ||
let rawCombined = combiningFunction(collection); | ||
return { | ||
next: function() { | ||
let { values, returnValues, anyDone, allDone } = rawCombined(); | ||
if ((!finishLate && anyDone) || allDone) { | ||
if (finishTogether && !allDone) { | ||
throw new Error("`itbl.combine()`: iterables combined with `finish === 'together'` have not finished together"); | ||
} | ||
else | ||
{ | ||
values[key] = step.value; | ||
return false; | ||
} | ||
return { | ||
value: returnValues, | ||
done: true, | ||
}; | ||
} | ||
: function earlyCb(some, it, key) { | ||
var step = it.next(); | ||
if( step.done ) | ||
{ | ||
returnValues[key] = step.value; | ||
return true; | ||
} | ||
else | ||
{ | ||
anyValues = true; | ||
values[key] = step.value; | ||
return some; | ||
} | ||
}; | ||
return { | ||
next: function() { | ||
if( done ) | ||
return { done: true } | ||
values = create(); | ||
anyValues = false; | ||
if( reduce(its, cb, !!finishLate) ) | ||
{ | ||
if( finish === 'together' && anyValues ) | ||
throw new Error("itbl: iterables combined with finish === 'together' have not finished together"); | ||
done = true; | ||
return { | ||
value: returnValues, | ||
done: true | ||
} | ||
} | ||
else | ||
return { | ||
value: values, | ||
done: false | ||
} | ||
} | ||
}; | ||
}); | ||
}; | ||
done: false, | ||
}; | ||
}, | ||
}; | ||
}); | ||
}; | ||
var parseIteratee = _.iteratee | ||
/** | ||
* Combines all `object`'s own enumerable values (which must be iterators) into a single iterable containing objects | ||
* containing values from each iterable in `object`. | ||
* | ||
* | ||
* | ||
* @private | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Object} object Collection of iterators | ||
* | ||
* @returns {itbl} Iterable containing collection of values. | ||
* @throws {Error} Throws an error if any own enumerable values of `object` are not enumerable. | ||
* | ||
*/ | ||
function _objectCombine(object) { | ||
let iterators = {}; | ||
/** | ||
* Creates a new iterable containing values which the `predicate` returns truthy for. | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Iterable to filter the values of. | ||
* @param {Function} [predicate = _.identity] Function to run each value though. | ||
* | ||
* @returns {itbl.Wrapper} New filtered iterable | ||
* @throws {Error} Throws an error if iterators are not supported or the `iterable` is not iterable. | ||
* | ||
* @example | ||
* | ||
* [...itbl.filter([0,1,2,3,4,5], val => val%2 === 0)] | ||
* // [0,2,4] | ||
* | ||
* let mySet = new Set().add(1).add('a').add(NaN) | ||
* | ||
* [...itbl.filter(mySet, value => _.isFinite)] | ||
* // [1] | ||
* | ||
* var users = [ | ||
* { 'user': 'barney', 'age': 36, 'active': true }, | ||
* { 'user': 'fred', 'age': 40, 'active': false } | ||
* ]; | ||
* | ||
* [...itbl.filter(users, function(o) { return !o.active; })]; | ||
* // => objects for ['fred'] | ||
* | ||
* // The `_.matches` iteratee shorthand. | ||
* [...itbl.filter(users, { 'age': 36, 'active': true })]; | ||
* // => objects for ['barney'] | ||
* | ||
* // The `_.matchesProperty` iteratee shorthand. | ||
* [...itbl.filter(users, ['active', false])]; | ||
* // => objects for ['fred'] | ||
* | ||
* // The `_.property` iteratee shorthand. | ||
* [...itbl.filter(users, 'active')]; | ||
* // => objects for ['barney'] | ||
* | ||
*/ | ||
function filter(iterable, predicate) { | ||
for (let key of Object.keys(object)) { | ||
iterators[key] = _getIterator(object[key], 'combine', `\`collection.${key}\` is not an iterator`); | ||
} | ||
let returnValues = {}; | ||
predicate = parseIteratee(predicate); | ||
return function() { | ||
let values = {}, | ||
return generateIterable(function() { | ||
var it = getIterator(iterable); | ||
return { | ||
next: function FilteredIterator() { | ||
var step; | ||
anyDone = false, | ||
allDone = true; | ||
while( !(step = it.next()).done && !predicate(step.value) ); | ||
if( step.done ) | ||
return { done: true }; | ||
else | ||
return { value: step.value, done: false }; | ||
} | ||
}; | ||
}); | ||
} | ||
for (let key of Object.keys(iterators)) { | ||
let step = iterators[key].next(); | ||
returnValues[key] = step.done ? step.value : returnValues[key]; | ||
Wrapper.prototype.filter = function(predicate) { | ||
return filter(this, predicate); | ||
}; | ||
values [key] = !step.done ? step.value : undefined; | ||
anyDone = anyDone || step.done; | ||
allDone = allDone && step.done; | ||
// TODO make sure iterator is closed if mapping is interupted | ||
} | ||
/** | ||
* Creates a new iterable whose iterators will have values coresponding to the value | ||
* of the Iterator of the original iterable run through `iteratee`. | ||
* The iteratee is invoked with only one argument (value). | ||
* | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Iterable to map values of. | ||
* @param {Function} [iteratee = _.identity] Function to run each value though. | ||
* | ||
* @returns {itbl.Wrapper} A new mapped iterable | ||
* @throws {Error} Throws an error if iterators are not supported or the `iterable` is not iterable. | ||
* | ||
* @example | ||
* | ||
* for(let coor of itbl.map([0,1,2,3,4,5], x => ({ x, y: Math.exp(x)))) { | ||
* context.lineTo(coor.x, coor.y); | ||
* } | ||
* | ||
* let mySet = new Set().add(1).add('a').add(NaN) | ||
* | ||
* [...itbl.map(mySet, value => value + 1)] | ||
* // [2, 'a1', NaN] | ||
* | ||
* var users = [ | ||
* { 'user': 'barney' }, | ||
* { 'user': 'fred' } | ||
* ]; | ||
* | ||
* // The `_.property` iteratee shorthand. | ||
* [...itbl.map(users, 'user'); | ||
* // => ['barney', 'fred'] | ||
* | ||
*/ | ||
function map(iterable, iteratee) { | ||
iteratee = parseIteratee(iteratee); | ||
return generateIterable(function() { | ||
var it = getIterator(iterable); | ||
return { | ||
next: function MappedIterator() { | ||
var step = it.next(); | ||
if( step.done ) | ||
return { done: true }; | ||
else | ||
return { value: iteratee(step.value), done: false }; | ||
} | ||
return { values, returnValues, anyDone, allDone }; | ||
}; | ||
}); | ||
} | ||
Wrapper.prototype.map = function(iteratee) { | ||
return map(this, iteratee); | ||
}; | ||
} | ||
/** | ||
* Reverts the `itbl` variable to its previous value and returns a reference to | ||
* the `itbl` function. | ||
* | ||
* @static | ||
* @since 2.0.0 | ||
* @memberOf itbl | ||
* @returns {itbl} Returns the `itbl` function. | ||
* @example | ||
* | ||
* var IterableUtil = itbl.noConflict(); | ||
*/ | ||
function noConflict() { | ||
if (root.itbl === this) { | ||
root.itbl = oldItbl; | ||
} | ||
return this; | ||
} | ||
/** | ||
* Iterates over `iterable` and creates an array containing the values contained | ||
* within iterable. Behavour is designed to replicate the `es6` syntax: `[...iterable]`. | ||
* | ||
* @static | ||
* @memberOf itbl | ||
* @since 0.1.0 | ||
* @param {Iterable} iterable Values to put into array. | ||
* | ||
* @returns {array} Array containing values of `iterable`. | ||
* @throws {Error} Throws an error if iterators are not supported or the argument is not iterable. | ||
* | ||
* @example | ||
* | ||
* function *gen() { | ||
* yield 1; | ||
* yield 2; | ||
* yield 3; | ||
* } | ||
* | ||
* itbl.toArray(gen()); | ||
* // [1,2,3] | ||
* | ||
* let mySet = new Set(); | ||
* mySet.add(1); | ||
* mySet.add(Math); | ||
* | ||
* itbl.toArray(mySet); | ||
* [1, Math]; | ||
*/ | ||
function toArray(iterable) { | ||
let it = getIterator(iterable), | ||
arr = [], | ||
step; | ||
while( !(step = it.next()).done ) | ||
arr.push(step.value); | ||
return arr; | ||
} | ||
let itbl = wrap; | ||
itbl.prototype = _Wrapper.prototype; | ||
itbl.prototype.constructor = itbl; | ||
var itbl = function itbl(value) { | ||
return wrap(value); | ||
}; | ||
Object.assign(itbl, { | ||
combine, | ||
filter, | ||
isIterable, | ||
isIterator, | ||
itbl, | ||
noConflict, | ||
map, | ||
wrap, | ||
}, EXPOSE_INTERNAL | ||
? { | ||
_wrapIterable, | ||
_wrapIterator, | ||
_generateIterable, | ||
_getIterator, | ||
_Wrapper, | ||
} | ||
: {}); | ||
definitions(itbl); | ||
/*--------------------------------------------------------------------------*/ | ||
itbl.combine = combine; | ||
itbl.filter = filter; | ||
itbl.isIterable = isIterable; | ||
itbl.isIterator = isIterator; | ||
itbl.map = map; | ||
itbl.toArray = toArray; | ||
itbl.itbl = itbl; | ||
itbl.wrap = wrap; | ||
// Export itbl. | ||
// Some AMD build optimizers, like r.js, check for condition patterns like: | ||
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { | ||
// Expose itbl on the global object to prevent errors when itbl is | ||
// loaded by a script tag in the presence of an AMD loader. | ||
// See http://requirejs.org/docs/errors.html#mismatch for more details. | ||
// Use `itbl.noConflict` to remove Lodash from the global object. | ||
root.itbl = itbl; | ||
return itbl; | ||
})); | ||
// Define as a module. | ||
define('itbl', function() { | ||
return itbl; | ||
}); | ||
} | ||
// Check for `exports` after `define` in case a build optimizer adds it. | ||
else if (freeModule) { | ||
// Export for Node.js. | ||
freeModule.exports = itbl; | ||
// Export for CommonJS support. | ||
freeExports.itbl = itbl; | ||
} | ||
else { | ||
// Export to the global object. | ||
root.itbl = itbl; | ||
} | ||
}.call(this)); |
{ | ||
"name": "itbl", | ||
"version": "1.1.2", | ||
"version": "2.1.0", | ||
"description": "Utility libary for es6 iterators", | ||
"main": "itbl.js", | ||
"scripts": {}, | ||
"scripts": { | ||
"style": "npm run style:main", | ||
"style:main": "jscs itbl.js", | ||
"style:test": "jscs test/*.js", | ||
"test": "npm run test:main", | ||
"test:doc": "markdown-doctest doc/*.md", | ||
"test:main": "babel-node test/test.babel.js", | ||
"doc": "babel-node lib/build-doc.babel.js github && npm run test:doc", | ||
"doc:site": "node lib/build-doc site" | ||
}, | ||
"keywords": [ | ||
@@ -23,22 +32,7 @@ "util", | ||
"fs-extra": "^0.30.0", | ||
"gulp-eol-enforce": "^0.1.0", | ||
"gulp-line-ending-corrector": "^1.0.1", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-replace": "^0.5.4", | ||
"gulp-umd": "^0.2.0", | ||
"run-sequence": "^1.2.2", | ||
"vinyl-file": "^2.0.0", | ||
"vinyl-fs": "^2.4.3" | ||
}, | ||
"dependencies": { | ||
"lodash": "^4.15.0" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"latest" | ||
], | ||
"plugins": [ | ||
"transform-runtime" | ||
] | ||
"itbl": "1.1.2", | ||
"jscs": "^3.0.7", | ||
"lodash": "^4.16.3", | ||
"qunit-extras": "^2.1.0" | ||
} | ||
} |
@@ -24,39 +24,17 @@ # itbl | ||
let itbl = require('itbl'); | ||
// Load indevidual methods | ||
var map = require('itbl/map'); | ||
var wrap = require('itbl/wrap'); | ||
``` | ||
### Dependancies | ||
## Contributing | ||
The libary current has [lodash](https://lodash.com) as a dependancy. In [Node.js](https://nodejs.org) or [Browserify](http://browserify.org) make sure lodash is installed as a dependancy of your project. | ||
Contributions are welcome, | ||
[the style guidelines are taken from lodash](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md) | ||
and are enforced using [JCSC](https://www.npmjs.com/package/jscs): | ||
```ah | ||
$ npm install lodash | ||
```bash | ||
$ npm run style | ||
``` | ||
## Built With | ||
* [gulp](http://gulpjs.com) | ||
* [docdown](https://github.com/jdalton/docdown) | ||
## Contributing | ||
Contributions are welcome, style guide has not been written yet but will look very similar to [lodash's contributing guidelines](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md). | ||
## Versioning | ||
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](tags). | ||
## Authors | ||
* [**Harry Sarson**](https://github.com/HarrySarson) - *Initial work* | ||
## License | ||
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details | ||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details | ||
@@ -66,1 +44,2 @@ ## Acknowledgments | ||
* This libary was inspired by [lodash](https://lodash.com) and the documentation style was heavily influenced by the documentation of lodash. | ||
* Documentation generated by [docdown](https://github.com/jdalton/docdown) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
124187
0
10
14
1408
43
3
1
- Removedlodash@^4.15.0
- Removedlodash@4.17.21(transitive)