UNPKG

node-vitals

Version:

Do more with less. A simple, high-performing, functional JavaScript library.

1,175 lines (1,017 loc) 32.7 kB
/** * ----------------------------------------------------------------------------- * VITALS METHOD: cut * ----------------------------------------------------------------------------- * @section base * @version 4.1.3 * @see [vitals.cut]{@link https://github.com/imaginate/vitals/wiki/vitals.cut} * * @author Adam Smith <adam@imaginate.life> (https://github.com/imaginate) * @copyright 2017 Adam A Smith <adam@imaginate.life> (https://github.com/imaginate) * * Annotations: * @see [JSDoc3](http://usejsdoc.org) * @see [Closure Compiler JSDoc Syntax](https://developers.google.com/closure/compiler/docs/js-for-compiler) */ 'use strict'; var newErrorMaker = require('./helpers/new-error-maker.js'); var sliceArr = require('./helpers/slice-arr.js'); var escape = require('./helpers/escape.js'); var match = require('./helpers/match.js'); var own = require('./helpers/own.js'); var copy = require('./copy.js'); var _is = require('./helpers/is.js'); var is = require('./is.js'); //////////////////////////////////////////////////////////////////////////////// // VITALS METHOD: cut //////////////////////////////////////////////////////////////////////////////// var cut = (function cutPrivateScope() { ////////////////////////////////////////////////////////// // PUBLIC METHODS // - cut // - cut.property (cut.prop) // - cut.key // - cut.index (cut.i) // - cut.type // - cut.value (cut.val) // - cut.pattern // - cut.properties (cut.props) // - cut.keys // - cut.indexes (cut.ii) // - cut.values (cut.vals) // - cut.patterns ////////////////////////////////////////////////////////// /** * Removes properties from an object/array or substring patterns from a string * and returns the amended source. * * @public * @param {!(Object|function|Array|string)} source * @param {...*} vals - If only one val is provided and it is an array it is * considered an array of vals. Details are as follows (per source type): * - object source: * -- leading val is RegExp: This method will delete all properties with * keys that [match](https://github.com/imaginate/vitals/wiki/vitals.has#haspattern) * each val. If any following vals are not a RegExp they are converted * to a string. * -- leading val is string: This method will delete all properties where * `key === val`. All vals are converted to a string. * -- leading val is function: The val is considered a filter function * (i.e. if it returns false the property is deleted). It has the * optional params - value, key, source. Note this method lazily clones * the source based on the filter's [length property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) * (i.e. if you alter the source object within the filter ensure to * define the filter's third param so you can safely assume all * references to the source are its original values). * -- all other cases: This method will delete all properties where * `value === val`. * - array source: * -- all vals are numbers: This method will splice from the source each * corresponding index. * -- leading val is function: The val is considered a filter function * (i.e. if it returns false the property is spliced from the source). * It has the optional params - value, index, source. Note this method * lazily clones the source based on the filter's [length property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) * (i.e. if you alter the source object within the filter ensure to * define the filter's third param so you can safely assume all * references to the source are its original values). * -- all other cases: This method will splice from the source all * properties where `value === val`. * - string source: All vals that are not a RegExp or string are converted * to a string. Each matching substring is removed from the source. * @param {Object=} thisArg - If source is an object/array, val is a filter * function, and thisArg is defined the filter is bound to its value. * @return {!(Object|function|Array|string)} The amended source. */ function cut(source, vals, thisArg) { if (arguments.length < 2) throw _error('No val defined'); if ( _is.str(source) ) { vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals; return _is.arr(vals) ? _cutPatterns(source, vals) : _cutPattern(source, vals); } if ( !_is._obj(source) ) throw _error.type('source'); source = _is.args(source) ? sliceArr(source) : source; if ( _is.func(vals) ) { if ( !_is.nil.un.obj(thisArg) ) throw _error.type('thisArg'); return _is.arr(source) ? _filterArr(source, vals, thisArg) : _filterObj(source, vals, thisArg); } vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals; return _is.arr(vals) ? _cutProps(source, vals) : _cutProp(source, vals); } /** * Removes a property from an object/array and returns the object. * * @public * @param {!(Object|function|Array)} source * @param {*} val - The details are as follows (per source type): * - object source: * -- val is RegExp: This method will delete all properties with a key * that [matches](https://github.com/imaginate/vitals/wiki/vitals.has#haspattern) * the val. * -- val is string: This method will delete all properties where * `key === val`. * -- val is function: The val is considered a filter function (i.e. if it * returns false the property is deleted). It has the optional params - * value, key, source. Note this method lazily clones the source based * on the filter's [length property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) * (i.e. if you alter the source object within the filter ensure to * define the filter's third param so you can safely assume all * references to the source are its original values). * -- all other cases: This method will delete all properties where * `value === val`. * - array source: * -- val is number: This method will splice the index from the source. * -- val is function: The val is considered a filter function (i.e. if it * returns false the property is spliced from the source). It has the * optional params - value, index, source. Note this method lazily * clones the source based on the filter's [length property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) * (i.e. if you alter the source object within the filter ensure to * define the filter's third param so you can safely assume all * references to the source are its original values). * -- all other cases: This method will splice from the source all * properties where `value === val`. * @param {Object=} thisArg - If val is a filter function and thisArg is * defined the filter is bound to its value. * @return {!(Object|function|Array)} */ cut.property = function cutProperty(source, val, thisArg) { if ( !_is._obj(source) ) throw _error.type('source', 'property'); if (arguments.length < 2) throw _error('No val defined', 'property'); source = _is.args(source) ? sliceArr(source) : source; if ( _is.func(val) ) { if ( !_is.nil.un.obj(thisArg) ) throw _error.type('thisArg', 'property'); return _is.arr(source) ? _filterArr(source, val, thisArg) : _filterObj(source, val, thisArg); } return _cutProp(source, val); }; // define shorthand cut.prop = cut.property; /** * Removes a property by key from an object and returns the object. * * @public * @param {!(Object|function)} source * @param {*} key - If the key is not a string it is converted to a string. * If the key exists in the source object it is deleted. * @return {!(Object|function)} */ cut.key = function cutKey(source, key) { if ( !_is._obj(source) ) throw _error.type('source', 'key'); if (arguments.length < 2) throw _error('No key defined', 'key'); return _cutKey(source, key); }; /** * Removes a property by index from an array and returns the array. If an * array-like object is supplied it is sliced before removing the property. * * @public * @param {!(Object|function|Array)} source * @param {number} index - The index to remove. * @param {number=} toIndex - If defined all indexes from index to toIndex * (not including toIndex) are removed. * @return {!Array} */ cut.index = function cutIndex(source, index, toIndex) { if ( !_is._obj(source) ) throw _error.type('source', 'index'); if ( !_is.num(source.length) ) throw _error.type('source.length', 'index'); if ( !_is.num(index) ) throw _error.type('index', 'index'); if ( !_is.un.num(toIndex) ) throw _error.type('toIndex', 'index'); source = _is.arr(source) ? source : sliceArr(source); return _cutIndex(source, index, toIndex); }; // define shorthand cut.i = cut.index; /** * Removes all properties from an object/array with a value that matches a * given type and returns the object. This method uses [vitals.is](https://github.com/imaginate/vitals/wiki/vitals.is) * to complete type checks. * * @public * @param {!(Object|function|Array)} source * @param {string} type - The type to check for. Refer to [vitals.is](https://github.com/imaginate/vitals/wiki/vitals.is) * for acceptable options. * @return {!(Object|function|Array)} */ cut.type = function cutType(source, type) { if ( !_is._obj(source) ) throw _error.type('source', 'type'); if ( !_is.str(type) ) throw _error.type('type', 'type'); source = _is.args(source) ? sliceArr(source) : source; if ( _is.empty(source) ) { is(type, ''); // run once to catch invalid types return source; } return _cutType(source, type); }; /** * Removes all properties from an object/array with a value and returns the * object. * * @public * @param {!(Object|function|Array)} source * @param {*} val * @return {!(Object|function|Array)} */ cut.value = function cutValue(source, val) { if ( !_is._obj(source) ) throw _error.type('source', 'value'); if (arguments.length < 2) throw _error('No val defined', 'value'); source = _is.args(source) ? sliceArr(source) : source; return _cutVal(source, val); }; // define shorthand cut.val = cut.value; /** * Removes a pattern from a string and returns the amended string. * * @public * @param {string} source * @param {*} pattern - If pattern is not a string or RegExp it is converted * to a string. * @return {string} */ cut.pattern = function cutPattern(source, pattern) { if ( !_is.str(source) ) throw _error.type('source', 'pattern'); if (arguments.length < 2) throw _error('No pattern defined', 'pattern'); return _cutPattern(source, pattern); }; /** * Removes properties from an object/array and returns the object. * * @public * @param {!(Object|function|Array)} source * @param {...*} vals - If only one val is provided and it is an array it is * considered an array of vals. Details are as follows (per source type): * - object source: * -- leading val is RegExp: This method will delete all properties with * keys that [match](https://github.com/imaginate/vitals/wiki/vitals.has#haspattern) * each val. If any following vals are not a RegExp they are converted * to a string. * -- leading val is string: This method will delete all properties where * `key === val`. All vals are converted to a string. * -- all other cases: This method will delete all properties where * `value === val`. * - array source: * -- all vals are numbers: This method will splice from the source each * corresponding index. * -- all other cases: This method will splice from the source all * properties where `value === val`. * @return {!(Object|function|Array)} */ cut.properties = function cutProperties(source, vals) { if ( !_is._obj(source) ) throw _error.type('source', 'properties'); if (arguments.length < 2) throw _error('No val defined', 'properties'); source = _is.args(source) ? sliceArr(source) : source; vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals; return _is.arr(vals) ? _cutProps(source, vals) : _cutProp(source, vals); }; // define shorthand cut.props = cut.properties; /** * Removes properties by key from an object and returns the object. * * @public * @param {!(Object|function)} source * @param {...*} keys - If only one key is provided and it is an array it is * considered an array of keys. If a key is not a string it is converted to * a string. If the key exists in the source object it is deleted. * @return {!(Object|function)} */ cut.keys = function cutKeys(source, keys) { if ( !_is._obj(source) ) throw _error.type('source', 'keys'); if (arguments.length < 2) throw _error('No key defined', 'keys'); keys = arguments.length > 2 ? sliceArr(arguments, 1) : keys; return _is.arr(keys) ? _cutKeys(source, keys) : _cutKey(source, keys); }; /** * Removes properties by index from an array and returns the array. If an * array-like object is supplied it is sliced before completing the cut. * * @public * @param {!(Object|function|Array)} source * @param {...number} indexes - If only one index is provided and it is an * array it is considered an array of indexes. The indexes to remove. * @return {!Array} */ cut.indexes = function cutIndexes(source, indexes) { if ( !_is._obj(source) ) throw _error.type('source', 'indexes'); if ( !_is.num(source.length) ) throw _error.type('source.length', 'indexes'); if (arguments.length < 2) throw _error('No index defined', 'indexes'); source = _is.arr(source) ? source : sliceArr(source); indexes = arguments.length > 2 ? sliceArr(arguments, 1) : indexes; if ( !_is.arr(indexes) ) { if ( !_is.num(indexes) ) throw _error.type('index', 'indexes'); return _cutIndex(source, indexes); } if ( !is('!nums', indexes) ) throw _error.type('index', 'indexes'); return _cutIndexes(source, indexes); }; // define shorthand cut.ii = cut.indexes; /** * Removes all properties from an object/array with a value and returns the * object. * * @public * @param {!(Object|function|Array)} source * @param {...*} vals - If only one val is provided and it is an array it is * considered an array of vals. * @return {!(Object|function|Array)} */ cut.values = function cutValues(source, vals) { if ( !_is._obj(source) ) throw _error.type('source', 'value'); if (arguments.length < 2) throw _error('No val defined', 'value'); source = _is.args(source) ? sliceArr(source) : source; vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals; return _is.arr(vals) ? _cutVals(source, vals) : _cutVal(source, vals); }; // define shorthand cut.vals = cut.values; /** * Removes patterns from a string and returns the amended string. * * @public * @param {string} source * @param {...*} patterns - If only one pattern is provided and it is an array * it is considered an array of patterns. If a pattern is not a string or * RegExp it is converted to a string. * @return {string} */ cut.patterns = function cutPatterns(source, patterns) { if ( !_is.str(source) ) throw _error.type('source', 'patterns'); if (arguments.length < 2) throw _error('No pattern defined', 'patterns'); patterns = arguments.length > 2 ? sliceArr(arguments, 1) : patterns; return _is.arr(patterns) ? _cutPatterns(source, patterns) : _cutPattern(source, patterns); }; ////////////////////////////////////////////////////////// // PRIVATE METHODS - MAIN ////////////////////////////////////////////////////////// /** * @private * @param {!(Object|function|Array)} source * @param {*} val * @return {!(Object|function|Array)} */ function _cutProp(source, val) { return _is.arr(source) ? _is.num(val) ? _spliceKey(source, val) : _spliceVal(source, val) : is('!str|regex', val) ? _deleteKey(source, val) : _deleteVal(source, val); } /** * @private * @param {!(Object|function|Array)} source * @param {!Array<*>} vals * @return {!(Object|function|Array)} */ function _cutProps(source, vals) { return _is.arr(source) ? is('nums', vals) ? _spliceKeys(source, vals) : _spliceVals(source, vals) : is('!str|regex', vals[0]) ? _deleteKeys(source, vals) : _deleteVals(source, vals); } /** * @private * @param {!(Object|function)} source * @param {*} key * @return {!(Object|function)} */ function _cutKey(source, key) { delete source[key]; return source; } /** * @private * @param {!(Object|function)} source * @param {!Array} keys * @return {!(Object|function)} */ function _cutKeys(source, keys) { /** @type {number} */ var len; /** @type {number} */ var i; len = keys.length; i = -1; while (++i < len) delete source[ keys[i] ]; return source; } /** * @private * @param {!Array} source * @param {number} key * @param {number=} toKey * @return {!Array} */ function _cutIndex(source, key, toKey) { /** @type {number} */ var len; len = source.length; key = key < 0 ? len + key : key; if (key >= len) return source; if ( _is.undefined(toKey) ) { if (key < 0) return source; source.splice(key, 1); return source; } key = key < 0 ? 0 : key; toKey = toKey > len ? len : toKey < 0 ? len + toKey : toKey; if (key >= toKey) return source; source.splice(key, toKey - key); return source; } /** * @private * @param {!Array} source * @param {!Array<number>} keys * @return {!Array} */ function _cutIndexes(source, keys) { return _spliceKeys(source, keys); } /** * @private * @param {!(Object|function|Array)} source * @param {string} type * @return {!(Object|function|Array)} */ function _cutType(source, type) { return _is.arr(source) ? _spliceValByType(source, type) : _deleteValByType(source, type); } /** * @private * @param {!(Object|function|Array)} source * @param {*} val * @return {!(Object|function|Array)} */ function _cutVal(source, val) { return _is.arr(source) ? _spliceVal(source, val) : _deleteVal(source, val); } /** * @private * @param {!(Object|function|Array)} source * @param {!Array<*>} vals * @return {!(Object|function|Array)} */ function _cutVals(source, vals) { return _is.arr(source) ? _spliceVals(source, vals) : _deleteVals(source, vals); } /** * @private * @param {string} source * @param {*} pattern * @return {string} */ function _cutPattern(source, pattern) { if ( !_is.regex(pattern) ) { pattern = String(pattern); pattern = escape(pattern); pattern = new RegExp(pattern, 'g'); } return source.replace(pattern, ''); } /** * @private * @param {string} source * @param {!Array} patterns * @return {string} */ function _cutPatterns(source, patterns) { /** @type {number} */ var len; /** @type {number} */ var i; len = patterns.length; i = -1; while (++i < len) { source = _cutPattern(source, patterns[i]); } return source; } ////////////////////////////////////////////////////////// // PRIVATE METHODS - DELETE ////////////////////////////////////////////////////////// /** * @private * @param {!(Object|function)} source * @param {*} key * @param {boolean=} useMatch * @return {!(Object|function)} */ function _deleteKey(source, key, useMatch) { /** @type {!RegExp} */ var pattern; useMatch = _is.undefined(useMatch) ? _is.regex(key) : useMatch; if (!useMatch) { if ( own(source, key) ) delete source[key]; return source; } pattern = key; for (key in source) { if ( own(source, key) && match(key, pattern) ) { delete source[key]; } } return source; } /** * @private * @param {!(Object|function)} source * @param {!Array} keys * @return {!(Object|function)} */ function _deleteKeys(source, keys) { /** @type {boolean} */ var useMatch; /** @type {number} */ var len; /** @type {number} */ var i; useMatch = _is.regex( keys[0] ); len = keys.length; i = -1; while (++i < len) { source = _deleteKey(source, keys[i], useMatch); } return source; } /** * @private * @param {!(Object|function)} source * @param {*} val * @return {!(Object|function)} */ function _deleteVal(source, val) { /** @type {string} */ var key; for (key in source) { if ( own(source, key) && source[key] === val ) { delete source[key]; } } return source; } /** * @private * @param {(!Object|function)} source * @param {string} type * @return {(!Object|function)} */ function _deleteValByType(source, type) { /** @type {string} */ var key; for (key in source) { if ( own(source, key) && is(type, source[key]) ) delete source[key]; } return source; } /** * @private * @param {!(Object|function)} source * @param {!Array} vals * @return {!(Object|function)} */ function _deleteVals(source, vals) { /** @type {number} */ var len; /** @type {number} */ var i; len = vals.length; i = -1; while (++i < len) { source = _deleteVal(source, vals[i]); } return source; } ////////////////////////////////////////////////////////// // PRIVATE METHODS - SPLICE ////////////////////////////////////////////////////////// /** * @private * @param {!Array} source * @param {number} key * @return {!Array} */ function _spliceKey(source, key) { /** @type {number} */ var len; len = source.length; key = key < 0 ? len + key : key; if (key < 0 || key >= len) return source; source.splice(key, 1); return source; } /** * @private * @param {!Array} source * @param {!Array<number>} keys * @return {!Array} */ function _spliceKeys(source, keys) { /** @type {!Object} */ var sorted; /** @type {number} */ var first; /** @type {number} */ var count; /** @type {number} */ var i; if (!source.length || !keys.length) return source; if (keys.length < 2) return _spliceKey(source, keys[0]); sorted = _sortIndexes(keys, source.length); i = sorted.first.length; while (i--) { first = sorted.first[i]; count = sorted.last[i] - first + 1; source.splice(first, count); } return source; } /** * @private * @param {!Array} source * @param {*} val * @return {!Array} */ function _spliceVal(source, val) { /** @type {number} */ var i; i = source.length; while (i--) { if (source[i] === val) source.splice(i, 1); } return source; } /** * @private * @param {!Array} source * @param {string} type * @return {!Array} */ function _spliceValByType(source, type) { /** @type {number} */ var i; i = source.length; while (i--) { if ( is(type, source[i]) ) source.splice(i, 1); } return source; } /** * @private * @param {!Array} source * @param {!Array} vals * @return {!Array} */ function _spliceVals(source, vals) { /** @type {*} */ var val; /** @type {number} */ var len; /** @type {number} */ var ii; /** @type {number} */ var i; len = vals.length; i = source.length; while (i--) { val = source[i]; ii = len; while (ii--) { if (vals[ii] === val) { source.splice(i, 1); break; } } } return source; } ////////////////////////////////////////////////////////// // PRIVATE METHODS - FILTER ////////////////////////////////////////////////////////// /** * @private * @param {!(Object|function)} source * @param {function} filter * @param {Object=} thisArg * @return {!(Object|function)} */ function _filterObj(source, filter, thisArg) { /** @type {!Object} */ var obj; /** @type {string} */ var key; filter = _is.undefined(thisArg) ? filter : _bind(filter, thisArg); obj = filter.length > 2 ? copy(source) : source; switch (filter.length) { case 0: for (key in obj) { if ( own(obj, key) && !filter() ) delete source[key]; } break; case 1: for (key in obj) { if ( own(obj, key) && !filter(obj[key]) ) delete source[key]; } break; case 2: for (key in obj) { if ( own(obj, key) && !filter(obj[key], key) ) delete source[key]; } break; default: for (key in obj) { if ( own(obj, key) && !filter(obj[key], key, obj) ) delete source[key]; } } return source; } /** * @private * @param {!Array} source * @param {function} filter * @param {Object=} thisArg * @return {!Array} */ function _filterArr(source, filter, thisArg) { /** @type {!Array} */ var arr; /** @type {number} */ var i; filter = _is.undefined(thisArg) ? filter : _bind(filter, thisArg); arr = filter.length > 2 ? copy.arr(source) : source; i = arr.length; switch (filter.length) { case 0: while (i--) filter() || source.splice(i, 1); break; case 1: while (i--) filter(arr[i]) || source.splice(i, 1); break; case 2: while (i--) filter(arr[i], i) || source.splice(i, 1); break; default: while (i--) filter(arr[i], i, arr) || source.splice(i, 1); } return source; } ////////////////////////////////////////////////////////// // PRIVATE METHODS - SORT ////////////////////////////////////////////////////////// /** * @typedef {!{ * first: !Array<number>, * last: !Array<number> * }} SortedIndexes */ /** * @private * @param {!Array<number>} indexes * @param {number} sourceLen * @return {!SortedIndexes} */ var _sortIndexes = (function() { /** * @private * @param {!Array<number>} indexes * @param {number} sourceLen * @return {!SortedIndexes} */ function sortIndexes(indexes, sourceLen) { /** @type {number} */ var index; /** @type {number} */ var len; /** @type {number} */ var i; setup(); len = indexes.length; i = 0; // push 1st index index = parse(indexes[i], sourceLen); while (index === -1 && ++i < len) { index = parse(indexes[i], sourceLen); } push(index); // push remaining indexes while (++i < len) { index = parse(indexes[i], sourceLen); if (index !== -1) sort(index, 0, last.length); } return result(); } ////////////////////////////// // SORT MEMBERS // - FIRST // - LAST /** @type {!Array<number>} */ var first; /** @type {!Array<number>} */ var last; ////////////////////////////// // SORT METHODS // - SETUP // - RESULT // - PARSE // - PUSH // - UNSHIFT // - INSERT // - REMOVE // - SORT // - COMPARE PREV // - COMPARE NEXT /** * @private * @type {function} */ function setup() { first = []; last = []; } /** * @private * @return {!SortedIndexes} */ function result() { return { first: first, last: last }; } /** * @private * @param {number} index * @param {number} len * @return {number} If invalid index is given -1 is returned. */ function parse(index, len) { index = index < 0 ? len + index : index; return index < 0 || index >= len ? -1 : index; } /** * @private * @param {number} index */ function push(index) { first.push(index); last.push(index); } /** * @private * @param {number} index */ function unshift(index) { first.unshift(index); last.unshift(index); } /** * @private * @param {number} index * @param {number} pos */ function insert(index, pos) { first.splice(pos, 0, index); last.splice(pos, 0, index); } /** * @private * @param {number} index * @param {number} pos */ function remove(pos) { first.splice(pos, 1); last.splice(pos, 1); } /** * @private * @param {number} index * @param {number} left * @param {number} right */ function sort(index, left, right) { /** @type {number} */ var mid; /** @type {number} */ var min; mid = (left + right) >>> 1; min = first[mid]; if (index < min) comparePrev(index, left, mid); else if (index > last[mid]) compareNext(index, mid, right); } /** * @private * @param {number} index * @param {number} left * @param {number} mid */ function comparePrev(index, left, mid) { /** @type {number} */ var prev; /** @type {number} */ var min; /** @type {number} */ var max; min = first[mid]; if (!mid) { if (index === --min) first[mid] = index; else unshift(index); return; } prev = mid - 1; max = last[prev]; if (index === --min) { if (index === ++max) { last[prev] = last[mid]; remove(mid); } else first[mid] = index; } else if (index > max) { if (index === ++max) last[prev] = index; else insert(index, mid); } else sort(index, left, prev); } /** * @private * @param {number} index * @param {number} mid * @param {number} right */ function compareNext(index, mid, right) { /** @type {number} */ var next; /** @type {number} */ var min; /** @type {number} */ var max; next = mid + 1; max = last[mid]; if (next === last.length) { if (index === ++max) last[mid] = index; else push(index); return; } min = first[next]; if (index === ++max) { if (index === --min) { last[mid] = last[next]; remove(next); } else last[mid] = index; } else if (index < min) { if (index === --min) first[next] = index; else insert(index, next); } else sort(index, next, right); } // END OF INDEX SORT PRIVATE SCOPE return sortIndexes; })(); ////////////////////////////////////////////////////////// // PRIVATE METHODS - GENERAL ////////////////////////////////////////////////////////// /** * @private * @param {function} func * @param {Object} thisArg * @return {function} */ function _bind(func, thisArg) { switch (func.length) { case 0: return function filter() { return func.call(thisArg); }; case 1: return function filter(val) { return func.call(thisArg, val); }; case 2: return function filter(val, key) { return func.call(thisArg, val, key); }; } return function filter(val, key, obj) { return func.call(thisArg, val, key, obj); }; } /** * @private * @type {!ErrorAid} */ var _error = newErrorMaker('cut'); ////////////////////////////////////////////////////////// // END OF PRIVATE SCOPE FOR CUT return cut; })(); module.exports = cut;