117 lines
2.7 KiB
JavaScript
117 lines
2.7 KiB
JavaScript
/**
|
|
* Takes any input and guarantees an array back.
|
|
*
|
|
* - converts array-like objects (e.g. `arguments`) to a real array
|
|
* - converts `undefined` to an empty array
|
|
* - converts any another other, singular value (including `null`) into an array containing that value
|
|
* - ignores input which is already an array
|
|
*
|
|
* @module array-back
|
|
* @example
|
|
* > const arrayify = require('array-back')
|
|
*
|
|
* > arrayify(undefined)
|
|
* []
|
|
*
|
|
* > arrayify(null)
|
|
* [ null ]
|
|
*
|
|
* > arrayify(0)
|
|
* [ 0 ]
|
|
*
|
|
* > arrayify([ 1, 2 ])
|
|
* [ 1, 2 ]
|
|
*
|
|
* > function f(){ return arrayify(arguments); }
|
|
* > f(1,2,3)
|
|
* [ 1, 2, 3 ]
|
|
*/
|
|
|
|
function isObject (input) {
|
|
return typeof input === 'object' && input !== null
|
|
}
|
|
|
|
function isArrayLike (input) {
|
|
return isObject(input) && typeof input.length === 'number'
|
|
}
|
|
|
|
/**
|
|
* @param {*} - the input value to convert to an array
|
|
* @returns {Array}
|
|
* @alias module:array-back
|
|
*/
|
|
function arrayify (input) {
|
|
if (Array.isArray(input)) {
|
|
return input
|
|
} else {
|
|
if (input === undefined) {
|
|
return []
|
|
} else if (isArrayLike(input)) {
|
|
return Array.prototype.slice.call(input)
|
|
} else {
|
|
return [ input ]
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find and either replace or remove items in an array.
|
|
*
|
|
* @module find-replace
|
|
* @example
|
|
* > const findReplace = require('find-replace')
|
|
* > const numbers = [ 1, 2, 3]
|
|
*
|
|
* > findReplace(numbers, n => n === 2, 'two')
|
|
* [ 1, 'two', 3 ]
|
|
*
|
|
* > findReplace(numbers, n => n === 2, [ 'two', 'zwei' ])
|
|
* [ 1, [ 'two', 'zwei' ], 3 ]
|
|
*
|
|
* > findReplace(numbers, n => n === 2, 'two', 'zwei')
|
|
* [ 1, 'two', 'zwei', 3 ]
|
|
*
|
|
* > findReplace(numbers, n => n === 2) // no replacement, so remove
|
|
* [ 1, 3 ]
|
|
*/
|
|
|
|
/**
|
|
* @param {array} - The input array
|
|
* @param {testFn} - A predicate function which, if returning `true` causes the current item to be operated on.
|
|
* @param [replaceWith] {...any} - If specified, found values will be replaced with these values, else removed.
|
|
* @returns {array}
|
|
* @alias module:find-replace
|
|
*/
|
|
function findReplace (array, testFn) {
|
|
const found = [];
|
|
const replaceWiths = arrayify(arguments);
|
|
replaceWiths.splice(0, 2);
|
|
|
|
arrayify(array).forEach((value, index) => {
|
|
let expanded = [];
|
|
replaceWiths.forEach(replaceWith => {
|
|
if (typeof replaceWith === 'function') {
|
|
expanded = expanded.concat(replaceWith(value));
|
|
} else {
|
|
expanded.push(replaceWith);
|
|
}
|
|
});
|
|
|
|
if (testFn(value)) {
|
|
found.push({
|
|
index: index,
|
|
replaceWithValue: expanded
|
|
});
|
|
}
|
|
});
|
|
|
|
found.reverse().forEach(item => {
|
|
const spliceArgs = [ item.index, 1 ].concat(item.replaceWithValue);
|
|
array.splice.apply(array, spliceArgs);
|
|
});
|
|
|
|
return array
|
|
}
|
|
|
|
export default findReplace;
|