const {N,def} = require('../types');
/**
* Functions for adding values to arrays in different ways.
* @alias module:@lumjs/core/arrays.add
*/
const ArrayAdd = module.exports = exports =
{
prepend, before, append, after, insert,
}
function _addWith(array, oldValue, newValue, ifMissing, fn)
{
let pos = array.indexOf(oldValue);
if (pos === -1)
{
if (typeof ifMissing === N)
{
pos = ifMissing;
}
else
{
return false;
}
}
return fn(array, newValue, pos);
}
/**
* Prepend a value to an array.
*
* @param {Array} array - Array to add the value to.
* @param {*} value - Value to add to the array.
* @param {number} [pos=0] Position to prepend at.
*
* If `pos` is `0` then `array.unshift(value)` is used.
* Otherwise `array.splice(pos, 0, value)` is used.
*
* @returns {Array} `array`
* @alias module:@lumjs/core/arrays.add.prepend
*/
function prepend(array, value, pos=0)
{
if (pos === 0)
{
array.unshift(value);
}
else
{
array.splice(pos, 0, value);
}
return array;
}
/**
* Append a value to an array.
*
* @param {Array} array - Array to add the value to.
* @param {*} value - Value to add to the array.
* @param {number} [pos=-1] Position to append at.
*
* If `pos` is `-1` then `array.push(value)` is used.
* Otherwise `array.splice(pos+1, 0, value)` is used.
*
* @returns {Array} `array`
* @alias module:@lumjs/core/arrays.add.append
*/
function append(array, value, pos=-1)
{
if (pos === -1)
{
array.push(value);
}
else
{
array.splice(pos+1, 0, value);
}
return array;
}
/**
* Add a value to an array _before_ an existing value.
*
* This uses `prepend()` to add the value.
*
* @param {Array} array - Array to add the value to.
* @param {*} oldValue - Existing value to find.
* @param {*} newValue - Value to add to the array.
* @param {(number|false)} [ifMissing=0] If `oldValue` is not found.
*
* If this is a `number` it will be used as the `pos` argument.
*
* If this is `false` the function will not add the value at all,
* but will return `false` instead.
*
* @returns {(Array|false)} Usually the input `array`; but will return
* `false` if `ifMissing` was `false` and the `oldValue` was not found.
*
* @alias module:@lumjs/core/arrays.add.before
*/
function before(array, oldValue, newValue, ifMissing=0)
{
return _addWith(array, oldValue, newValue, ifMissing, prepend);
}
/**
* Add a value to an array _after_ an existing value.
*
* This uses `append()` to add the value.
*
* @param {Array} array - Array to add the value to.
* @param {*} oldValue - Existing value to find.
* @param {*} newValue - Value to add to the array.
* @param {(number|false)} [ifMissing=-1] If `oldValue` is not found.
*
* If this is a `number` it will be used as the `pos` argument.
*
* If this is `false` the function will not add the value at all,
* but will return `false` instead.
*
* @returns {(Array|false)} Usually the input `array`; but will return
* `false` if `ifMissing` was `false` and the `oldValue` was not found.
*
* @alias module:@lumjs/core/arrays.add.after
*/
function after(array, oldValue, newValue, ifMissing=-1)
{
return _addWith(array, oldValue, newValue, ifMissing, append);
}
/**
* Insert a value to an array using special logic.
*
* See the `pos` argument for the positioning logic used.
*
* @param {Array} array - Array to add the value to.
* @param {*} value - Value to add to the array.
* @param {number} [pos=-1] Position to insert at.
*
* If `pos` is less than `0` this uses `append()`;
* Otherwise it uses `prepend()`.
*
* @returns {Array} `array`
* @alias module:@lumjs/core/arrays.add.insert
*/
function insert(array, value, pos=-1)
{
if (pos < 0)
{
return append(array, value, pos);
}
else
{
return prepend(array, value, pos);
}
}
/**
* A wrapper class to provide helper methods to Arrays.
*
* Provides wrapped versions of `prepend()`, `append()`,
* `before()`, `after()`, and `insert()`.
*
* The methods obviously pass the array argument, so remove it from
* the argument signature when using the wrapper method. Other than that,
* the rest of the arguments are the same as the wrapped functions.
*
* @alias module:@lumjs/core/arrays.add.At
*/
class ArrayAt
{
/**
* Build a wrapper around an array.
*
* @param {Array} array - Array to wrap.
*/
constructor(array)
{
this.array = array;
}
/**
* Add wrappers for the helper functions to the Array directly.
*
* WARNING: This is monkey patching the array object instance.
* If you're okay with that, cool.
*
* Otherwise, use a new `ArrayAt` object instance instead.
*
* @param {Array} array - Array to add methods to.
*
* @returns {Array} The input `array`
*/
static extend(array)
{
for (const methName in ArrayAdd)
{
const methFunc = ArrayAdd[methName];
def(array, methName, methFunc.bind(array, array));
}
return array;
}
/**
* A static method that calls `new ArrayAt(array)`;
*
* @param {Array} array - Array to wrap
* @returns {module:@lumjs/core/arrays.ArrayAt} A new instance.
*/
static new(array)
{
return new this(array);
}
} // ArrayAt class
// Set up ArrayAt methods, and export the functions.
for (const methName in ArrayAdd)
{
const methFunc = ArrayAdd[methName];
def(ArrayAt.prototype, methName, function()
{
methFunc(this.array, ...arguments);
});
}
def(ArrayAdd, 'At', ArrayAt);