node-vitals
Version:
Do more with less. A simple, high-performing, functional JavaScript library.
518 lines (441 loc) • 13.1 kB
JavaScript
/**
* -----------------------------------------------------------------------------
* VITALS METHOD: fuse
* -----------------------------------------------------------------------------
* @section base
* @version 4.1.3
* @see [vitals.fuse]{@link https://github.com/imaginate/vitals/wiki/vitals.fuse}
*
* @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 merge = require('./helpers/merge.js');
var own = require('./helpers/own.js');
var _is = require('./helpers/is.js');
////////////////////////////////////////////////////////////////////////////////
// VITALS METHOD: fuse
////////////////////////////////////////////////////////////////////////////////
var fuse = (function fusePrivateScope() {
//////////////////////////////////////////////////////////
// PUBLIC METHODS
// - fuse
// - fuse.value (fuse.val)
// - fuse.value.start (fuse.value.top)
// - fuse.object (fuse.obj)
// - fuse.array (fuse.arr)
// - fuse.string (fuse.str)
//////////////////////////////////////////////////////////
/**
* Merges objects, concatenates arrays, appends properties, and combines
* strings.
*
* @public
* @param {!(Object|function|Array|string)} dest
* @param {...*} vals - All rules occur in order of appearance. For object and
* array dest types `null` is skipped. Remaining details per dest type:
* - object: If only one val is provided and it is an array it is considered
* an array of vals. Object vals are merged with the dest. All other
* values are converted to strings and appended as new keys (if the key
* exists on the dest the property's value is replaced with undefined).
* - array: Array vals are concatenated to the dest. All other values are
* pushed to the dest.
* - string: If only one val is provided and it is an array it is considered
* an array of vals. All non-string vals are converted to strings and
* appended to the dest.
* @return {!(Object|function|Array|string)}
*/
function fuse(dest, vals) {
if (arguments.length < 2) throw _error('No val defined');
if ( _is.str(dest) ) {
vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals;
return _is.arr(vals) ? _fuseStrs(dest, vals) : _fuseStr(dest, vals);
}
if ( !_is._obj(dest) ) throw _error.type('dest');
dest = _is.args(dest) ? sliceArr(dest) : dest;
if ( _is.arr(dest) ) {
if (arguments.length > 2) {
vals = sliceArr(arguments, 1);
return _fuseArrs(dest, vals);
}
return _fuseArr(dest, vals);
}
vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals;
return _is.arr(vals) ? _fuseObjs(dest, vals) : _fuseObj(dest, vals);
}
/**
* Appends properties and combines strings.
*
* @public
* @param {!(Object|function|Array|string)} dest
* @param {...*} vals - Details per dest type:
* - object: All vals are converted to strings and appended as new keys (if
* the key exists on the dest the property's value is replaced with
* undefined).
* - array: All vals are pushed to the dest.
* - string: All vals are converted to strings and appended to the dest.
* @return {!(Object|function|Array|string)}
*/
fuse.value = function fuseValue(dest, vals) {
if (arguments.length < 2) throw _error('No val defined', 'value');
if ( _is.str(dest) ) {
if (arguments.length < 3) return _fuseStr(dest, vals);
vals = sliceArr(arguments, 1);
return _fuseStrs(dest, vals);
}
if ( !_is._obj(dest) ) throw _error.type('dest', 'value');
dest = _is.args(dest) ? sliceArr(dest) : dest;
if (arguments.length < 3) {
return _is.arr(dest) ? _fuseArrVal(dest, vals) : _fuseObjVal(dest, vals);
}
vals = sliceArr(arguments, 1);
return _is.arr(dest) ? _fuseArrsVal(dest, vals) : _fuseObjsVal(dest, vals);
};
// define shorthand
fuse.val = fuse.value;
/**
* Appends properties and combines strings to the start of their destination.
*
* @public
* @param {!(Object|function|Array|string)} dest
* @param {...*} vals - Details per dest type:
* - object: All vals are converted to strings and appended as new keys (if
* the key exists on the dest the property's value remains unchanged).
* - array: All vals are unshifted to the dest.
* - string: All vals are converted to strings and appended to the beginning
* of the dest.
* @return {!(Object|function|Array|string)}
*/
fuse.value.start = function fuseValueStart(dest, vals) {
if (arguments.length < 2) throw _error('No val defined', 'value.start');
if ( _is.str(dest) ) {
if (arguments.length < 3) return _fuseStrTop(dest, vals);
vals = sliceArr(arguments, 1);
return _fuseStrsTop(dest, vals);
}
if ( !_is._obj(dest) ) throw _error.type('dest', 'value.start');
dest = _is.args(dest) ? sliceArr(dest) : dest;
if (arguments.length < 3) {
return _is.arr(dest)
? _fuseArrValTop(dest, vals)
: _fuseObjValTop(dest, vals);
}
vals = sliceArr(arguments, 1);
return _is.arr(dest)
? _fuseArrsValTop(dest, vals)
: _fuseObjsValTop(dest, vals);
};
// define shorthand
fuse.val.start = fuse.value.start;
fuse.value.top = fuse.value.start;
fuse.val.top = fuse.value.start;
/**
* Appends properties/keys to an object.
*
* @public
* @param {!(Object|function)} dest
* @param {...*} vals - Any vals that are `null` are skipped. All other vals
* that are not objects are converted to a string and appended as new keys
* (if the key exists on the dest the key's value is replaced with
* undefined). If only one val is provided and it is an array then it is
* considered an array of vals. All object vals are merged with the dest
* (if the key exists on the dest the key's value is with replaced with the
* value from the merged object).
* @return {!(Object|function)}
*/
fuse.object = function fuseObject(dest, vals) {
if ( !_is._obj(dest) ) throw _error.type('dest', 'object');
if (arguments.length < 2) throw _error('No val defined', 'object');
vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals;
return _is.arr(vals) ? _fuseObjs(dest, vals) : _fuseObj(dest, vals);
};
// define shorthand
fuse.obj = fuse.object;
/**
* Appends values to an array and concatenates arrays.
*
* @public
* @param {!Array} dest
* @param {...*} vals - Details per val type:
* - null: All null vals are skipped.
* - array: All array vals are concatenated to the dest.
* - other: All other vals are pushed to the dest array.
* @return {!Array}
*/
fuse.array = function fuseArray(dest, vals) {
if ( !_is._arr(dest) ) throw _error.type('dest', 'array');
if (arguments.length < 2) throw _error('No val defined', 'array');
dest = _is.args(dest) ? sliceArr(dest) : dest;
if (arguments.length > 2) {
vals = sliceArr(arguments, 1);
return _fuseArrs(dest, vals);
}
return _fuseArr(dest, vals);
};
// define shorthand
fuse.arr = fuse.array;
/**
* Appends strings to a string.
*
* @public
* @param {string} dest
* @param {...*} vals - All non-string vals are converted to strings.
* @return {string}
*/
fuse.string = function fuseString(dest, vals) {
if ( !_is.str(dest) ) throw _error.type('dest', 'string');
if (arguments.length < 2) throw _error('No val defined', 'string');
vals = arguments.length > 2 ? sliceArr(arguments, 1) : vals;
return _is.arr(vals) ? _fuseStrs(dest, vals) : _fuseStr(dest, vals);
};
// define shorthand
fuse.str = fuse.string;
//////////////////////////////////////////////////////////
// PRIVATE METHODS - MAIN
//////////////////////////////////////////////////////////
/**
* @private
* @param {!(Object|function)} dest
* @param {*} val
* @return {!(Object|function)}
*/
function _fuseObj(dest, val) {
if ( _is._obj(val) ) return merge(dest, val);
if ( !_is.nil(val) ) dest[val] = undefined;
return dest;
}
/**
* @private
* @param {!(Object|function)} dest
* @param {!Array<*>} vals
* @return {!(Object|function)}
*/
function _fuseObjs(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest = _fuseObj(dest, vals[i]);
}
return dest;
}
/**
* @private
* @param {!(Object|function)} dest
* @param {*} val
* @return {!(Object|function)}
*/
function _fuseObjVal(dest, val) {
dest[val] = undefined;
return dest;
}
/**
* @private
* @param {!(Object|function)} dest
* @param {!Array<*>} vals
* @return {!(Object|function)}
*/
function _fuseObjsVal(dest, vals) {
/** @type {*} */
var val;
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
val = vals[i];
dest[val] = undefined;
}
return dest;
}
/**
* @private
* @param {!(Object|function)} dest
* @param {*} val
* @return {!(Object|function)}
*/
function _fuseObjValTop(dest, val) {
if ( !own(dest, val) ) dest[val] = undefined;
return dest;
}
/**
* @private
* @param {!(Object|function)} dest
* @param {!Array<*>} vals
* @return {!(Object|function)}
*/
function _fuseObjsValTop(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest = _fuseObjValTop(dest, vals[i]);
}
return dest;
}
/**
* @private
* @param {!Array} dest
* @param {*} val
* @return {!Array}
*/
function _fuseArr(dest, val) {
if ( _is.arr(val) ) return dest.concat(val);
if ( !_is.nil(val) ) dest.push(val);
return dest;
}
/**
* @private
* @param {!Array} dest
* @param {!Array<*>} vals
* @return {!Array}
*/
function _fuseArrs(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest = _fuseArr(dest, vals[i]);
}
return dest;
}
/**
* @private
* @param {!Array} dest
* @param {*} val
* @return {!Array}
*/
function _fuseArrVal(dest, val) {
dest.push(val);
return dest;
}
/**
* @private
* @param {!Array} dest
* @param {!Array<*>} vals
* @return {!Array}
*/
function _fuseArrsVal(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest.push( vals[i] );
}
return dest;
}
/**
* @private
* @param {!Array} dest
* @param {*} val
* @return {!Array}
*/
function _fuseArrValTop(dest, val) {
dest.unshift(val);
return dest;
}
/**
* @private
* @param {!Array} dest
* @param {!Array<*>} vals
* @return {!Array}
*/
function _fuseArrsValTop(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest.unshift( vals[i] );
}
return dest;
}
/**
* @private
* @param {string} dest
* @param {*} val
* @return {string}
*/
function _fuseStr(dest, val) {
return dest + val;
}
/**
* @private
* @param {string} dest
* @param {!Array<*>} vals
* @return {string}
*/
function _fuseStrs(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest += vals[i];
}
return dest;
}
/**
* @private
* @param {string} dest
* @param {*} val
* @return {string}
*/
function _fuseStrTop(dest, val) {
return val + dest;
}
/**
* @private
* @param {string} dest
* @param {!Array<*>} vals
* @return {string}
*/
function _fuseStrsTop(dest, vals) {
/** @type {number} */
var len;
/** @type {number} */
var i;
len = vals.length;
i = -1;
while (++i < len) {
dest = vals[i] + dest;
}
return dest;
}
//////////////////////////////////////////////////////////
// PRIVATE METHODS - GENERAL
//////////////////////////////////////////////////////////
/**
* @private
* @type {!ErrorAid}
*/
var _error = newErrorMaker('fuse');
//////////////////////////////////////////////////////////
// END OF PRIVATE SCOPE FOR FUSE
return fuse;
})();
module.exports = fuse;