chain-able
Version:
interfaces that describe their intentions.
2,058 lines (1,896 loc) • 184 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.ChainAble = factory());
}(this, (function () { 'use strict';
function unwrapExports (x) {
return x && x.__esModule ? x['default'] : x;
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
/**
* @desc Checks if `value` is `undefined`.
* @category Lang
*
* @param {*} x value
* @return {boolean} isUndefined
*
* @since 4.0.0-alpha.1
* @memberOf is
* @func isUndefined
*
* @see is/nullOrUndefined
* @see https://github.com/infernojs/inferno/blob/master/packages/inferno-shared/src/index.ts#L57
*
* @NOTE || typeof x === 'undefined'
*
* @example
*
* isUndefined(undefined)
* //=> true
* isUndefined(void 0)
* //=> true
*
* isUndefined(null)
* //=> false
* isUndefined(NaN)
* //=> false
* isUndefined({})
* //=> false
* isUndefined('')
* //=> false
* isUndefined(1)
* //=> false
* isUndefined(false)
* //=> false
*
*/
var _undefined = function (x) { return x === undefined; };
var iterator = Symbol.iterator;
// typeof Symbol !== 'undefined'
// ? Symbol.iterator
// : '@@iterator'
var instance = Symbol.hasInstance;
var primitive = Symbol.toPrimitive;
var prototypeOf = function (obj, comparator) { return Object.prototype.isPrototypeOf.call(obj, comparator); };
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @memberOf is
*
* @param {*} value The value to query.
* @return {string} Returns the `toStringTag`.
*
* @see https://github.com/lodash/lodash/blob/master/.internal/baseGetTag.js
* @TODO obj[Symbol.toStringTag]
*/
var toS = function (obj) { return Object.prototype.toString.call(obj); };
/**
* @desc Checks if `value` is classified as a `Map` object.
* @param {*} x value
* @return {boolean} isMap
*
* @since 3.0.0
* @memberOf is
* @func isMap
* @see https://github.com/jonschlinkert/kind-of
*
* @example
*
* isMap(new Map())
* //=> true
* isMap(new Map.entries())
* //=> false
* isMap(new Set())
* //=> false
* isMap({})
* //=> false
* isMap('')
* //=> false
* isMap(1)
* //=> false
* isMap(new WeakMap)
* // => false
*
* @example
*
* const e = {}
* eh[Symbol.toStringTag] = '[object Map]'
* isMap(eh)
*
* @example
*
* class Eh extends Map()
* isMap(new Eh())
* //=> true
*
*/
var map = function (x) { return x instanceof Map || toS(x) === '[object Map]'; };
/**
* Checks if `value` is classified as a `Set` object.
*
* @since 4.3.0
* @category Lang
* @param {*} x The value to check.
* @return {boolean} Returns `true` if `value` is a set, else `false`.
*
* @example
*
* isSet(new Set)
* // => true
*
* isSet(new WeakSet)
* // => false
*
*/
var set = function (x) { return x instanceof Set || toS(x) === '[object Set]'; };
/**
* Checks if `value` is classified as a `Function` object.
* @category Lang
*
* @param {*} x The value to check.
* @return {boolean} x isFunction
*
* @since 3.0.0
* @memberOf is
* @func isFunction
*
* @NOTE || x instanceof Function
*
* @polyfill safari=9
* The use of `Object#toString` avoids issues with the `typeof` operator
* in Safari 9 which returns 'object' for typed arrays and other constructors.
* there is no polyfill for this
* https://github.com/krambuhl/custom-event-polyfill/issues/2
* browser usage is < 0.3%, very edge case
*
* @example
*
* isFunction(function() {})
* //=> true
* isFunction(() => {})
* //=> true
* isFunction(new Function())
* //=> true
*
* isFunction(1)
* //=> false
* isFunction('')
* //=> false
* isFunction(/abc/)
* // => false
*/
var _function = function (x) { return typeof x === 'function'; };
/**
* Checks if `value` is classified as a `String` **primitive**.
*
* @since 3.0.0
* @category Lang
* @memberOf is
* @param {*} x The value to check.
* @returns {boolean} Returns `true` if `value` is a string, else `false`.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
* @see https://github.com/lodash/lodash/blob/master/isString.js
* @see is/string
*
* @example
*
* isString('abc')
* // => true
*
* isString(new String('abc'))
* // => false
*
* isString(1)
* // => false
*/
var stringPrimitive = function (x) { return typeof x === 'string'; };
/**
* Checks if `value` is classified as a `String` primitive or object.
*
* @since 3.0.0
* @category Lang
*
* @memberOf is
* @extends isStringPrimitive
* @variation also allows String objects
*
* @param {*} x The value to check.
* @return {boolean} Returns `true` if `value` is a string, else `false`.
*
* @see https://github.com/lodash/lodash/blob/master/isString.js
* @see isStringPrimitive
*
* @example
*
* isString('abc')
* // => true
*
* isString(new String('abc'))
* // => true
*
* isString(1)
* // => false
*/
var string = function (x) { return stringPrimitive(x) || toS(x) === '[object String]'; };
/**
* @param {*} x value
* @return {boolean} isFalse
*
* @since 4.0.0-alpha.1
* @memberOf is
* @func isFalse
*
* @example
*
* isFalse(false)
* //=> true
* isFalse(true)
* //=> false
* isFalse(0)
* //=> false
* isFalse('')
* //=> false
*
*/
var _false = function isFalse(x) {
return x === false
};
var keys = Object.keys;
var assign = Object.assign;
/**
* @desc default to configurable and enumerable, unless configured otherwise
* @since 4.0.0
*
* @param {Object} obj object to define on
* @param {Primitive} name property name to define
* @param {Object} descriptor object descriptor
* @return {void}
*
* @tutorial https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
*
* @example
*
* var desc = Object.getOwnPropertyDescriptor(obj, 'eh', {get: () => console.log('eh')})
*
*/
var define = function(obj, name, descriptor) {
Object.defineProperty(
obj,
name,
assign(
{
configurable: true,
enumerable: true,
},
descriptor
)
);
};
var ignored = function (key) { return key === 'parent' || key === 'store' || key === 'meta' || key === 'className'; };
// key === 'decorated' ||
// key === 'transformers' ||
// key === 'inspect' ||
/* istanbul ignore next: wip build */
var dev = process.env.NODE_ENV !== 'production';
var shouldClear = function (key, property) { return !ignored(key) &&
(map(property) || set(property) || (property && property.store)); };
var C = function (SuperClass) {
/* istanbul ignore next: dev */
if (dev) {
if (!SuperClass || !SuperClass.prototype) {
console.log({SuperClass: SuperClass});
throw new TypeError('did not have a super class / target base')
}
}
/**
* @desc Trait class that can inherit any class passed into compose, extended by ChainedMap & ChainedSet
*
* @member Chainable
* @class Chainable
* @category Chainable
* @type {Chainable}
*
* @prop {Chainable | any} parent
* @prop {string} className
*
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/chain chain-pattern}
* @see {@link chain-pattern}
*
* @see ChainedMap
* @see ChainedSet
*
* @tests Chainable
* @types Chainable
*/
var Chainable = (function (SuperClass) {
function Chainable(parent) {
SuperClass.call(this);
if (parent) { this.parent = parent; }
this.className = this.constructor.name;
}
if ( SuperClass ) Chainable.__proto__ = SuperClass;
Chainable.prototype = Object.create( SuperClass && SuperClass.prototype );
Chainable.prototype.constructor = Chainable;
/**
* @desc Iterator for looping values in the store
*
* @since 0.5.0
* @see this.store
* @type {generator}
* @return {Object} {value: undefined | any, done: true | false}
*
* @NOTE assigned to a variable so buble ignores it
* @see https://github.com/sindresorhus/quick-lru/blob/master/index.js
* @see https://stackoverflow.com/questions/36976832/what-is-the-meaning-of-symbol-iterator-in-this-context
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator
* @tests iteration
*
* @example
*
* const chain = new Chain().set('eh', 1)
* for (var [key, val] of chain) console.log({[key]: val})
* //=> {eh: 1}
*
* @example
*
* *[Symbol.iterator](): void { for (const item of this.store) yield item }
*
* @example
*
* const {ChainedSet} = require('chain-able')
* const set = new ChainedSet()
* set.add('eh')
*
* for (const arr of set) {
* const [key, val] = arr
*
* key
* //=> 0
*
* val
* //=> 'eh'
*
* arr.length
* //=> 2
* }
*
*/
Chainable.prototype[iterator] = function () {
var values = this.values();
var size = this.store.size;
var entries = this.entries ? this.entries() : 0;
var keys$$1 = entries === 0 ? new Array(size) : keys(entries);
return {
i: 0,
next: function next() {
var i = this.i;
var key = i;
var val = values[i];
if (entries) { key = keys$$1[i]; }
// done - no more values, or iteration reached size
if ((_undefined(key) && _undefined(val)) || size <= i) {
return {value: undefined, done: true}
}
this.i++;
// return
return {value: [key, val], done: false}
},
}
};
/**
* @desc for ending nested chains
* @since 0.4.0
* @return {Chainable | any}
* @see Chainable.parent
* @see FactoryChain
*
* @example
*
* const parent = 'eh'
* const child = newChain(parent)
* child.end()
* //=> 'eh'
*
*/
Chainable.prototype.end = function end () {
return this.parent
};
/**
* @desc when the condition is true,
* trueBrancher is called,
* else, falseBrancher is called
*
* @since 4.0.0 <- added string-as-has(condition)
* @since 2.0.0
*
* @param {boolean | string} condition when string, checks this.get
* @param {Function} [trueBrancher=Function] called when true
* @param {Function} [falseBrancher=Function] called when false
* @return {Chainable} @chainable
*
* @example
*
*
* const prod = process.env.NODE_ENV === 'production'
* chains.when(prod, c => c.set('prod', true), c => c.set('prod', false))
*
*
*/
Chainable.prototype.when = function when (condition, trueBrancher, falseBrancher) {
if (condition) {
if (_function(trueBrancher)) {
if (string(condition)) {
if (this.get(condition)) {
trueBrancher(this);
}
}
else {
trueBrancher(this);
}
}
}
else if (_function(falseBrancher)) {
falseBrancher(this);
}
return this
};
/**
* @desc clears the map,
* goes through this properties,
* calls .clear if they are instanceof Chainable or Map
*
* @since 4.0.0 (moved only to Chainable, added option to clear this keys)
* @since 0.4.0 (in ChainedMap)
* @since 0.3.0 (in Chainable)
*
* @param {boolean | undefined} [clearPropertiesThatAreChainLike=true] checks properties on the object, if they are `chain-like`, clears them as well
* @return {Chainable} @chainable
*
* @see https://github.com/fliphub/flipchain/issues/2
* @see ChainedSet
* @see ChainedMap
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.entries()
* //=> {eh: 1}
* chain.clear()
* chain.entries()
* //=> {}
*
*/
Chainable.prototype.clear = function clear (clearPropertiesThatAreChainLike) {
var this$1 = this;
this.store.clear();
if (_false(clearPropertiesThatAreChainLike)) { return this }
var keys$$1 = keys(this);
for (var k = 0; k < keys$$1.length; k++) {
var key = keys$$1[k];
var property = this$1[key];
if (shouldClear(key, property)) { this$1[key].clear(); }
}
return this
};
/**
* @desc calls .delete on this.store.map
* @since 0.3.0
*
* @param {Primitive} key on a Map: key referencing the value. on a Set: the index
* @return {Chainable}
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has
* @see ChainedSet
* @see ChainedMap
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.get('eh')
* // => 1
* chain.delete('eh', 1)
* chain.get('eh')
* // => undefined
*
*/
Chainable.prototype.delete = function delete$1 (key) {
this.store.delete(key);
return this
};
/**
* @since 0.3.0
* @param {any} keyOrValue key when Map, value when Set
* @return {boolean}
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1).has('eh')
* //=> true
* chain.has('canada')
* //=> false
*
*/
Chainable.prototype.has = function has (keyOrValue) {
return this.store.has(keyOrValue)
};
/**
* @desc spreads the entries from ChainedMap.store.values
* @since 0.4.0
*
* @return {Array<any>} toArr(this.store.values())
*
* @NOTE look at Chainable.constructor to ensure not to use `new Array...`
* @NOTE moved from ChainedMap and ChainedSet to Chainable @2.0.2
* @NOTE this was [...] & Array.from(this.store.values())
*
* {@link https://kangax.github.io/compat-table/es6/#test-Array_static_methods compat-array-static-methods}
* {@link https://stackoverflow.com/questions/20069828/how-to-convert-set-to-array set-to-array}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values mozilla-map-values}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values mozilla-set-values}
*
* @see {@link mozilla-map-values}
* @see {@link mozilla-set-values}
* @see {@link compat-array-static-methods}
* @see {@link set-to-array}
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.values()
* //=> [1]
*
*/
Chainable.prototype.values = function values () {
var vals = [];
this.store.forEach(function (v) { return vals.push(v); });
return vals
};
/**
* @see http://2ality.com/2015/09/well-known-symbols-es6.html#default-tostring-tags
* @since 1.0.2
*
* @param {string} hint enum[default, string, number]
* @return {Primitive}
*
* @example
*
* const chain = new Chain()
* chain.toNumber = () => 1
* +chain;
* //=> 1
* chain + 1
* //=>
*
* @example
*
* const chain = new Chain()
* chain.toString = () => 'eh'
* chain + ''
* //=> 'eh'
*
*/
Chainable.prototype[primitive] = function (hint) {
/* prettier-ignore */
/**
* hint === 'number'
* `s`tring is 115
* `n`umber is 110
* 110 & 4 = 1
* 115 & 4 = 0
*
* if (hint === 'string' && this.toJSON) return this.toJSON()
* else if (hint === 'number' && this.toNumber) return this.toNumber()
*/
if (hint === 'number' && this.toNumber) { return this.toNumber() }
// hint === 'string'
if (this.toJSON) { return this.toJSON() }
// hint === 'default'
return this.toString()
};
return Chainable;
}(SuperClass));
var ChainPrototype = Chainable.prototype;
/**
* @private
* @since 0.5.0
* @example for (var i = 0; i < chain.length; i++)
* @see ChainedMap.store
* @return {number}
*/
define(ChainPrototype, 'length', {
enumerable: false,
get: function get() {
return this.store.size
},
});
define(ChainPrototype, instance, {
enumerable: false,
value: function (instance$$1) { return instance$$1 && (prototypeOf(ChainPrototype, instance$$1) || instance$$1.store); },
});
return Chainable
};
var c = C((function () {
function anonymous () {}
return anonymous;
}()));
/**
* @since 3.0.0
* @func
* @example
*
* class Target {}
* const TargetChain = Chainable.compose(Target)
* const chain = new TargetChain()
* chain instanceof Target
* //=> true
*
*/
c.compose = C;
var Chainable = c;
/**
* @param {*} x value
* @return {boolean} isObjLoose
*
* @since 3.0.0
* @memberOf is
* @func isObjLoose
* @see is/obj
* @see is/objWithKeys
* @see is/objStrict
* @see is/null
*
* @example
*
* isObjLoose(new Object())
* //=> true
* isObjLoose({})
* //=> true
* isObjLoose(Object.create(null))
* //=> true
* isObjLoose(null)
* //=> true
*
* isObjLoose(new Set())
* //=> false
* isObjLoose(function() {})
* //=> false
* isObjLoose('')
* //=> false
* isObjLoose(1)
* //=> false
*
*/
var objLoose = function (x) { return typeof x === 'object'; };
/**
* @param {*} x value
* @return {boolean} isNull
*
* @since 3.0.0
* @memberOf is
* @func isNull
*
* @example
*
* isNull(null)
* //=> true
*
* isNull(undefined)
* //=> false
* isNull(void 0)
* //=> false
* isNull({})
* //=> false
* isNull('')
* //=> false
* isNull(1)
* //=> false
*
*/
var _null = function (x) { return x === null; };
/**
* @desc Checks if `value` is `null` or `undefined`.
* @alias isNil
* @category Lang
*
* @param {*} x value
* @return {boolean} isNullOrUndefined
*
* @since 4.0.0-alpha.1
* @memberOf is
* @func isNullOrUndefined
*
* @see is/null
* @see is/undefined
* @see https://github.com/infernojs/inferno/blob/master/packages/inferno-shared/src/index.ts#L23
*
* @example
*
* isNullOrUndefined(null)
* //=> true
* isNullOrUndefined(undefined)
* //=> true
* isNullOrUndefined(void 0)
* //=> true
*
* isNullOrUndefined(NaN)
* //=> false
* isNullOrUndefined({})
* //=> false
* isNullOrUndefined('')
* //=> false
* isNullOrUndefined(1)
* //=> false
* isNullOrUndefined(false)
* //=> false
*
*/
var nullOrUndefined = function isNullOrUndef(x) {
return _undefined(x) || _null(x)
};
/**
* @param {*} x value
* @return {boolean} isObjStrict
*
* @since 3.0.0
* @memberOf is
* @func isObjStrict
* @see is/obj
* @see is/objWithKeys
* @see is/objLoose
* @see is/null
* @see https://github.com/sindresorhus/is-obj/blob/master/index.js
* @TODO !Array.isArray
*
* @extends isObjLoose
* @variation null will not count as an object
*
* @example
*
* isObjStrict(new Object())
* //=> true
* isObjStrict({})
* //=> true
* isObjStrict(Object.create(null))
* //=> true
* isObjStrict(null)
* //=> false
*
* isObjStrict(new Set())
* //=> false
* isObjStrict(function() {})
* //=> false
* isObjStrict('')
* //=> false
* isObjStrict(1)
* //=> false
*
*/
var objStrict = function (x) { return !nullOrUndefined(x) && objLoose(x); };
/**
* @func isArray
* @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
* @type {Function}
* @since 3.0.0
*/
var array = Array.isArray;
/**
* @param {*} x value
* @return {boolean} isTrue
*
* @since 4.0.0-alpha.1
* @memberOf is
* @func isTrue
*
* @example
*
* isTrue(true)
* //=> true
* isTrue(false)
* //=> false
* isTrue(1)
* //=> false
* isTrue('')
* //=> false
*
*/
var _true = function (x) { return x === true; };
/**
* Checks if `value` is classified as a `RegExp` object.
*
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @return {boolean} Returns `true` if `value` is a regexp, else `false`.
* @see https://github.com/lodash/lodash/blob/master/isRegExp.js
*
* @example
*
* isRegExp(/abc/)
* // => true
*
* isRegExp('/abc/')
* // => false
*
*/
var regexp = function (obj) { return obj instanceof RegExp || toS(obj) === '[object RegExp]'; };
/**
* @param {*} x value
* @return {boolean} isDate
*
* @since 3.0.0
* @memberOf is
* @func isDate
*
* @example
*
* isDate(new Date())
* //=> true
* isDate(Date.now())
* //=> false
* isDate(1)
* //=> false
* isDate('')
* //=> false
*
* @example
*
* const e = {}
* eh[Symbol.toStringTag] = '[Object Date]'
* isDate(eh)
* //=> true
*
* @example
*
* class Eh extends Date()
* isDate(new Eh())
* //=> true
*/
var date = function (x) { return x instanceof Date || toS(x) === '[object Date]'; };
/**
* @desc Checks if `value` is classified as a boolean primitive or object.
* @category Lang
* @since 3.0.0
*
* @param {*} x value
* @return {boolean} isBoolean
*
* @extends isTrue
* @extends isFalse
* @see is/toS
* @memberOf is
* @func isBoolean
*
* @NOTE could also have typeof x === 'boolean' || (/true|false/).test(x)
*
* @example
*
* isBoolean(false)
* //=> true
* isBoolean(new Boolean(1))
* //=> true
* isBoolean(1)
* //=> false
* isBoolean('')
* //=> false
*
*/
var boolean_1 = function (x) { return _true(x) || _false(x) || toS(x) === '[object Boolean]'; };
/* prettier-ignore */
/**
* @desc when Array -> 'array'
* when null -> 'null'
* else `typeof x`
* @param {any} x
* @return {string} type
*/
var simpleKindOf = function (x) {
return array(x)
? 'array'
: _null(x)
? 'null'
: typeof x
};
var includes = function (haystack, needle) { return haystack.includes(needle); };
var index$4 = includes;
// 1: not null object
// 2: object toString is not a date or regex
function isMergeableObj(val) {
return objStrict(val) && !regexp(val) && !date(val)
}
function emptyTarget(val) {
return array(val) ? [] : {}
}
function cloneIfNeeded(value, optsArg) {
return _true(optsArg.clone) && isMergeableObj(value)
? deepmerge(emptyTarget(value), value, optsArg)
: value
}
/* prettier-ignore */
function defaultArrayMerge(target, source, optsArg) {
var destination = target.slice();
for (var i = 0; i < source.length; i++) {
var v = source[i];
if (_undefined(destination[i])) {
destination[i] = cloneIfNeeded(v, optsArg);
}
else if (isMergeableObj(v)) {
destination[i] = deepmerge(target[i], v, optsArg);
}
// @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT
// === -1
// eslint-disable-next-line prefer-includes/prefer-includes
else if (!~target.indexOf(v)) {
destination.push(cloneIfNeeded(v, optsArg));
}
}
return destination
}
function mergeObj(target, source, optsArg) {
var destination = {};
if (isMergeableObj(target)) {
var targetKeys = keys(target);
for (var k = 0; k < targetKeys.length; k++) {
destination[targetKeys[k]] = cloneIfNeeded(target[targetKeys[k]], optsArg);
}
}
var sourceKeys = keys(source);
for (var s = 0; s < sourceKeys.length; s++) {
var key = sourceKeys[s];
if (!isMergeableObj(source[key]) || !target[key]) {
destination[key] = cloneIfNeeded(source[key], optsArg);
}
else {
destination[key] = deepmerge(target[key], source[key], optsArg);
}
}
return destination
}
function deepmerge(target, source, optsArg) {
if (array(source)) {
var arrayMerge = optsArg.arrayMerge;
return array(target)
? arrayMerge(target, source, optsArg)
: cloneIfNeeded(source, optsArg)
}
// else
return mergeObj(target, source, optsArg)
}
/* prettier-ignore */
// eslint-disable-next-line complexity
function dopemerge(obj1, obj2, opts) {
// if they are identical, fastest === check
if (obj1 === obj2) {
return obj1
}
// setup options
var options = assign(
{
arrayMerge: defaultArrayMerge,
stringToArray: true,
boolToArray: false,
ignoreTypes: ['null', 'undefined'],
// debug: true,
},
opts || {}
);
var ignoreTypes = options.ignoreTypes;
var stringToArray = options.stringToArray;
var boolToArray = options.boolToArray;
var clone = options.clone;
// @NOTE: much better size but oh well
// const ignoreTypes = ['null', 'undefined']
// const stringToArray = true
// const boolToArray = false
// const clone = true
// check one then check the other
if (_true(index$4(ignoreTypes, simpleKindOf(obj1)))) {
return obj2
}
else if (_true(index$4(ignoreTypes, simpleKindOf(obj2)))) {
return obj1
}
// @NOTE uglifier optimizes into a wicked ternary
else if (boolean_1(obj1) && boolean_1(obj2)) {
return boolToArray ? [obj1, obj2] : obj2
}
else if (string(obj1) && string(obj2)) {
return stringToArray ? [obj1, obj2] : obj1 + obj2
}
else if (array(obj1) && string(obj2)) {
return (clone ? obj1.slice(0) : obj1).concat([obj2])
}
else if (string(obj1) && array(obj2)) {
return (clone ? obj2.slice(0) : obj2).concat([obj1])
}
else {
return deepmerge(obj1, obj2, options)
}
}
var dopemerge_1 = dopemerge;
var index$2 = dopemerge_1;
/**
* @tutorial https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from
* @see https://github.com/lodash/lodash/blob/master/.internal/setToArray.js
* ^ could use if needed
*/
var from = Array.from;
/**
* @desc Map -> Object
* @since 4.0.0
*
* @param {Map} map map to reduce, calls entries, turns into an array, then object
* @return {Object} reduced object
*
* @see ArrayFrom
*
* @example
*
* var emptyMap = new Map()
* reduce(emptyMap)
* // => {}
*
* @example
*
* var map = new Map()
* map.set('eh', 1)
* reduce(map)
* // => {eh: 1}
*
*/
var reduce = function (map) {
var reduced = {};
// only need to do this if we actually have values in our Map
if (map.size !== 0) {
reduced = from(map.entries()).reduce(function (acc, ref) {
var key = ref[0];
var value = ref[1];
acc[key] = value;
return acc
}, {});
}
return reduced
};
var index$6 = reduce;
/**
* @desc recursively reduce maps and objects that include reducable data
* @since 4.0.0
*
* @sig reduced => object => isMap(object) -> reduced; merge(object, reduced)
*
* @param {Object | any} reduced merged object and reduced
* @return {Function} Function(values: Object)
*
* @see ChainedMap
*
* @example
*
* const map = new Map()
* map.set('eh', true)
* const nested = new Map()
* nested.set('reduced', true)
*
* const chain = {
* entries() {
* return {
* nested: reduce(nested),
* key: true,
* }
* },
* }
* const reduced = reduce(map)
* reduceEntries(reduced)({chain})
* // => {
* eh: true,
* chain: {
* nested: {
* reduced: true,
* key: true,
* },
* },
* }
*
* @example
*
* const reducedIgnored = {
* canada: {
* store: chain,
* },
* }
* const ignored = reduceEntries(reduced)(reducedIgnored)
* //=> {
* eh: true,
* chain: {
* nested: {
* reduced: true,
* },
* key: true,
* },
* }
*
*/
var entries = function (reduced) { return function (obj) {
var keys$$2 = keys(obj);
for (var k = 0; k < keys$$2.length; k++) {
var key = keys$$2[k];
if (ignored(key)) {
continue
}
var val = obj[key];
if (val && _function(val.entries)) {
assign(reduced, {[key]: val.entries(true) || {}});
}
}
return reduced
}; };
/**
* @param {*} x value
* @return {boolean} isIterator
*
* @since 3.0.0
* @memberOf is
* @func isIterator
* @see https://github.com/jonschlinkert/kind-of/pull/12
*
* @example
*
* isIterator(new Set().values())
* //=> true
* isIterator(new Map.entries())
* //=> true
* isIterator(new Map())
* //=> false
* isIterator('')
* //=> false
* isIterator(1)
* //=> false
*
* @example
*
* const e = {}
* eh[Symbol.toStringTag] = '[Map Iterator]'
* isIterator(eh)
* //=> true
* eh[Symbol.toStringTag] = '[Set Iterator]'
* isIterator(eh)
* //=> true
*
* @example
*
* class Eh extends Set()
* isIterator(new Eh().values())
* //=> true
*
*/
// eslint-disable-next-line
var iterator$2 = function (x) { return ~toS(x).indexOf('Iterator'); };
/**
* @desc anything into an array
* @sig * => Array
* @since 0.0.1
*
* @param {any} ar turn this into an array
* @return {Array} anything into an array
*
* @tests deps/to-arr
* @types deps
*
* @example
*
* toarr([])
* // => []
*
* toarr('')
* // => ['']
*
* toarr('1,2')
* // => ['1', '2']
*
* toarr('1,2')
* // => ['1', '2']
*
* const map = new Map()
* map.set('eh', true)
* const arr = toarr(map.entries())
* // => ['eh', true]
*
* const set = new Set()
* set.add('eh')
* set.add(true)
* const arr = toarr(map.entries())
* // => ['eh', true]
*
* toarr('').concat(toarr(false)).concat(toarr(null))
* // => ['', false, null]
*
*/
var toArr = function(ar) {
// @NOTE: !'' === true
if (stringPrimitive(ar)) { return ar.includes(',') ? ar.split(',') : [ar] }
else if (!ar) { return [ar] }
else if (array(ar)) { return ar }
else if (set(ar) || map(ar) || ar.values) {
/**
* @desc when using `new Set().values`... no forEach o.o
* .values is also on `Object`...
*/
return from(ar.values(ar))
}
else if (iterator$2(ar)) { return from(ar) }
else { return [ar] }
};
var concat = function (one, two) { return toArr(one || []).concat(toArr(two)); };
/* istanbul ignore next: wip build */
var transformers = process.env.NODE_ENV === 'production'
? 'transformers'
: 'transformers';
/* istanbul ignore next: wip build */
var observers = process.env.NODE_ENV === 'production'
? 'observers'
: 'observers';
/* istanbul ignore next: wip build */
var shorthands = process.env.NODE_ENV === 'production'
? 'shorthands'
: 'shorthands';
/* istanbul ignore next: wip build */
var decorated = process.env.NODE_ENV === 'production'
? 'decorated'
: 'decorated';
// will expand this later
var isInKeyMapAsSet = function (x) { return x === observers; };
// @NOTE: using `[]` deopts o.o
// eslint-disable-next-line
// this.shorthands = new Array()
/**
* @since 4.0.0
* @param {Chain} _this
* @return {Chain}
*/
function getMeta(_this) {
// if we already have it, keep it
if (_this.meta) { return _this.meta }
// the store
// shorthands: key -> method
var store = {};
// --- uglifiable functions
/** @desc initialize the store maps when we need them */
/* prettier-ignore */
var ensureInitialized = function (name, value) {
if (!_undefined(store[name])) { return }
// if (
// name === TRANSFORMERS_KEY ||
// name === SHORTHANDS_KEY ||
// name === DECORATED_KEY
// ) {
// store[name] = new Map()
// }
// else
if (isInKeyMapAsSet(name)) {
store[name] = new Set();
}
else {
store[name] = new Map();
}
};
/**
* @since 4.0.0
* @param {Primitive} key
* @param {Primitive | undefined} [prop=undefined]
* @return {boolean}
*/
var has = function (key, prop) {
if (_undefined(prop)) { return !!store[key].size }
else { return store[key].has(prop) }
};
/**
* @since 4.0.0
* @param {Primitive} key
* @param {Primitive | undefined} [prop=undefined]
* @return {any}
*/
var get = function (key, prop) { return (has(key, prop) ? store[key].get(prop) : []); };
/**
* @since 4.0.0
* @param {Primitive} key
* @param {Primitive | undefined} [prop=undefined]
* @param {Primitive | undefined} [value=undefined]
* @return {void}
*/
var set$$2 = function (key, prop, value) {
var storage = store[key];
// when it's a set, we have no `prop`, we just have .add
// so `prop = value` && `value = undefined`
if (set(storage)) {
storage.add(prop);
}
else {
// if (!has(key, prop)) return
var existing = storage.get(prop);
var val = concat(existing, value);
storage.set(prop, val);
}
};
/**
* @since 4.0.0
*
* @desc a single easily minifiable function,
* dynamically setting & getting depending on arguments
* to avoid nested property accessing
* only instantiating when values are **addded**
*
* @param {Primitive} key
* @param {Primitive | undefined} [prop=undefined]
* @param {undefined | any} [value=undefined] (when no value, it's a getter)
* @return {Array | Chain} depending on args
*/
function meta(key, prop, value) {
if (process.env.NODE_ENV === 'DEBUG') {
console.log('USING META', {key: key, prop: prop, value: value});
}
/* prettier-ignore */
if (_undefined(value)) {
// when we want to just access the property, return an array
// @example `.meta('transformers')`
if (_undefined(prop)) {
if (_undefined(store[key])) { return [] }
else { return store[key].size === 0 ? [] : from(store[key].values()) }
}
// we have `key, prop`
//
// 1: should `prop` be a value, (isSet?)
else if (isInKeyMapAsSet(key)) {
ensureInitialized(key);
set$$2(key, prop);
}
// 2: prop is a key, we want to return the [..] for that specific property
// @example `.meta('transformers', 'eh')`
else if (_undefined(store[key])) { return [] }
else { return toArr(get(key, prop)) }
}
// we have `key, prop, value`
else {
ensureInitialized(key);
// we have a value, let's add it
set$$2(key, prop, value);
}
return _this
}
// for debugging
meta.store = store;
// meta.debug = false
return meta
}
var meta = getMeta;
var index$8 = meta;
/**
* @desc ChainedMapBase composer
* @alias ComposeMap
* @type {Composer}
* @method compose
* @memberOf ChainedMapBase
*
* @param {Class | Object | Composable} [SuperClass=Chainable] class to extend
* @return {Class} ChainedMapBase
*
* @example
*
* const heh = class {}
* const composed = ChainedMapBase.compose(heh)
* const hehchain = new Composed()
* hehchain instanceof heh
* //=> true
*
*/
var CMC = function (SuperClass) {
/**
* @classdesc this is to avoid circular requires
* because MergeChain & MethodChain extend this
* yet .method & .merge use those chains
*
* @since 4.0.0-alpha.1
* @inheritdoc
* @class ChainedMapBase
* @member ChainedMapBase
* @category Chainable
* @extends {Chainable}
* @type {Chainable}
*
* @types ChainedMapBase
* @tests ChainedMap
*
* @prop {Meta} meta
* @prop {Map} store
*
* {@link https://ponyfoo.com/articles/es6-maps-in-depth pony-map}
* {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map mozilla-map}
* @see {@link pony-map}
* @see {@link mozilla-map}
*
* @see ChainedMap
* @see Chainable
* @see MergeChain
* @see MethodChain
* @see ChainedMap
*
*/
return (function (SuperClass) {
function ChainedMapBase(parent) {
SuperClass.call(this, parent);
this.store = new Map();
this.meta = index$8(this);
}
if ( SuperClass ) ChainedMapBase.__proto__ = SuperClass;
ChainedMapBase.prototype = Object.create( SuperClass && SuperClass.prototype );
ChainedMapBase.prototype.constructor = ChainedMapBase;
/**
* @desc tap a value with a function
* @modifies this.store.get(name)
* @memberOf ChainedMapBase
* @since 0.7.0
* @since 4.0.0-alpha.1 <- moved from transform & shorthands
*
* @param {string | any} name key to `.get`
* @param {Function} fn function to tap with
* @return {Chain} @chainable
*
* {@link https://github.com/sindresorhus/awesome-tap awesome-tap}
* {@link https://github.com/midknight41/map-factory map-factory}
* {@link https://github.com/webpack/tapable tapable}
* @see {@link tapable}
*
* @see ChainedMapBase.set
* @see ChainedMapBase.get
*
* @example
*
* chain
* .set('moose', {eh: true})
* .tap('moose', moose => {moose.eh = false; return moose})
* .get('moose')
*
* // => {eh: false}
*
* @example
*
* const entries = new Chain()
* .set('str', 'emptyish')
* .tap('str', str => str + '+')
* .set('arr', [1])
* .tap('arr', arr => arr.concat([2]))
* .entries()
*
* //=> {str: 'emptyish+', arr: [1, 2]}
*
*/
ChainedMapBase.prototype.tap = function tap (name, fn) {
return this.set(name, fn(this.get(name), index$2))
};
/**
* @desc checks each property of the object
* calls the chains accordingly
*
* @memberOf ChainedMapBase
* @since 0.5.0
*
* @param {Object} obj object with functions to hydrate from
* @return {Chainable} @chainable
*
* @TODO could also add parsing stringified
*
* @example
*
* const from = new Chain().from({eh: true})
* const eh = new Chain().set('eh', true)
* eq(from, eh)
* // => true
*
*/
ChainedMapBase.prototype.from = function from (obj) {
var this$1 = this;
var keys$$1 = keys(obj);
for (var k = 0; k < keys$$1.length; k++) {
var key = keys$$1[k];
var val = obj[key];
var fn = this$1[key];
if (fn && fn.merge) {
fn.merge(val);
}
else if (_function(fn)) {
fn.call(this$1, val);
}
else {
this$1.set(key, val);
}
}
return this
};
/**
* @desc shorthand methods, from strings to functions that call .set
* @since 0.4.0
* @memberOf ChainedMapBase
*
* @param {Array<string>} methods decorates/extends an object with new shorthand functions to get/set
* @return {ChainedMapBase} @chainable
*
* @example
*
* const chain1 = new Chain()
* chain1.extend(['eh'])
*
* const chain2 = new Chain()
* chain2.eh = val => this.set('eh', val)
*
* eq(chain2.eh, chain1.eh)
* //=> true
*
*/
ChainedMapBase.prototype.extend = function extend (methods) {
var this$1 = this;
methods.forEach(function (method) {
this$1.meta(shorthands, method);
this$1[method] = function (value) { return this$1.set(method, value); };
});
return this
};
/**
* @desc spreads the entries from ChainedMapBase.store (Map)
* return store.entries, plus all chain properties if they exist
* @memberOf ChainedMapBase
*
* @since 4.0.0 <- improved reducing
* @since 0.4.0
*
* @param {boolean} [chains=false] if true, returns all properties that are chains
* @return {Object}
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries mozilla-map-entries}
* @see {@link mozilla-map-entries}
*
* @example
*
* map.set('a', 'alpha').set('b', 'beta').entries()
* //=> {a: 'alpha', b: 'beta'}
*
*/
ChainedMapBase.prototype.entries = function entries$$1 (chains) {
if ( chains === void 0 ) chains = false;
var reduced = index$6(this.store);
if (chains === false) { return reduced }
var reducer = entries(reduced);
reducer(this);
reducer(reduced);
return reduced
};
/**
* @desc get value for key path in the Map store
* ❗ `debug` is a special key and is *not* included into .store
* it goes onto .meta
*
* @memberOf ChainedMapBase
* @since 4.0.0 <- moved debug here
* @since 0.4.0
*
* @param {Primitive} key Primitive data key used as map property to reference the value
* @return {any} value in .store at key
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get mozilla-map-get}
* @see {@link mozilla-map-get}
*
* @example
*
* const chain = new Chain()
* chain.set('eh', true)
* chain.get('eh')
* //=> true
*
* chain.get('nope')
* //=> undefined
*
*/
ChainedMapBase.prototype.get = function get (key) {
if (key === 'debug') { return this.meta.debug }
return this.store.get(key)
};
/**
* @desc sets the value using the key on store
* adds or updates an element with a specified key and value
*
* @memberOf ChainedMapBase
* @since 0.4.0
*
* @param {Primitive} key Primitive to reference the value
* @param {any} value any data to store
* @return {ChainedMapBase} @chainable
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set mozilla-map-set}
* @see {@link mozilla-map-set}
* @see ChainedMapBase.store
*
* @example
*
* const chain = new Chain()
* chain.set('eh', true)
* chain.get('eh')
* //=> true
*
*/
ChainedMapBase.prototype.set = function set (key, value) {
this.store.set(key, value);
return this
};
return ChainedMapBase;
}(SuperClass))
};
var cmc = CMC(Chainable);
cmc.compose = CMC;
var ChainedMapBase = cmc;
var debug = process.env.NODE_ENV === 'debug'; // || process.env.DEBUG = true
/**
* @func isObj
*
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @since 3.0.0
* @category Lang
* @param {*} value The value to check.
* @return {boolean} Returns `true` if `value` is an object, else `false`.
*
* @memberOf is
* @see https://github.com/lodash/lodash/blob/master/isObject.js
* @NOTE Object.prototype.toString.call(val) === '[object Object]'
*
* @example
*
* isObject({})
* // => true
*
* isObject([1, 2, 3])
* // => true
*
* isObject(Function)
* // => true
*
* isObject(null)
* // => false
*/
var obj = function (x) { return objStrict(x) || _function(x); };
/**
* @param {*} x value
* @return {boolean} isError
*
* @memberOf is
* @func isError
*
* @example
*
* isError(new Error())
* //=> true
* isError(new Error().stack)
* //=> false
* isError(1)
* //=> false
* isError('')
* //=> false
*
* @example
*
* const e = {}
* eh[Symbol.toStringTag] = '[Object Error]'
* isError(eh)
* //=> true
*
* @example
*
* class Eh extends Error()
* isError(new Eh())
* //=> true
*
*/
var error$1 = function (x) { return x instanceof Error || toS(x) === '[object Error]'; };
/**
* @param {*} x value
* @return {boolean} isNumber
*
* @since 3.0.0
* @memberOf is
* @func isNumber
* @see is/real
*
* @example
*
* isNumber(1)
* //=> true
* isNumber(Number(1))
* //=> true
* isNumber(NaN)
* //=> true
*
* isNumber(null)
* //=> false
* isNumber(undefined)
* //=> false
* isNumber(void 0)
* //=> false
* isNumber({})
* //=> false
* isNumber('')
* //=> false
* isNumber(false)
* //=> false
*
* @NOTE was not needed except for abstract ==
* const isObj = require('./obj')
* const isSymbol = require('./symbol')
* (isObj(x) || isSymbol(x)
* ? false
* : (/^0x[0-9a-f]+$/i).test(x) ||
* (/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/).test(x))
*/
var number = function (x) { return typeof x === 'number' || toS(x) === '[object Number]'; };
/**
* @desc turns arguments into an array, used as a util, for opt
*
* @since 3.0.0
* @return {Array<Arguments>}
*
* @see https://github.com/aretecode/awesome-deopt
* @see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
*
* @example
*
* function eh() {
* const args = argumentor.apply(null, arguments).slice(1)
*
* console.log(args)
* //=> [1, 10, 100]
* }
* eh(0, 1, 10, 100)
*
*/
var argumentor = function() {
var arguments$1 = arguments;
var len = arguments.length;
var args = new Array(len);
for (var i = 0; i < len; ++i) { args[i] = arguments$1[i]; }
return args
};
var hasOwnProperty_1 = function (haystack, needle) { return Object.prototype.hasOwnProperty.call(haystack, needle); };
var getPrototypeOf = Object.getPrototypeOf;
/* eslint no-new-wrappers: "off" */
/* eslint eqeqeq: "off" */
/* eslint func-style: "off" */
/* eslint complexity: "off" */
/**
* @param {Array | Object | any} xs
* @param {Function} fn
* @TODO: unexpectedly breaks things iterating
* if you are relying on internal functionality
* (such as .path, .get, .value...) with map & set
*
* @NOTE if there is .forEach on the obj already, use it
* otherwise, call function for each
*
*/
var forEach = function(xs, fn) {
if (xs.forEach) { xs.forEach(fn); }
else { for (var i = 0; i < xs.length; i++) { fn(xs[i], i, xs); } }
};
/**
* {@link https://sourcemaking.com/design_patterns/chain_of_responsibility chainofresponsibility}
*
* @param {Traversable} obj object to traverse
*
* @constructor
*
* @example
*
* traverse({})
* //=> new Traverse(obj)
*
*/
var traverse = function(obj) {
return new Traverse(obj)
};
var traverse_1 = traverse;
/**
* @func
* @class TraverseJS
* @classdesc Traverse and transform objects by visiting every node on a recursive walk.
* @prop {any} value
*
* @category traverse
* @memberOf Traverse
* @see deps/traverse
* @category traverse
* @types traverse
* @tests traverse/*
*
* @TODO: symbol, map, set
* @tutorial https://github.com/substack/js-traverse
*
* @param {Traversable} obj any traversable value
*
* @example
*
* traverse({})
* //=> Traverser
*
*/
function Traverse(obj) {
this.value = obj;
}
/**
* @desc Get the element at the array path.
*
* @param {Array<string>} ps paths
* @return {any} value at dot-prop
*
* @memberOf Traverse
* @see this.forEach
* @todo hasOwnProperty
*/
Traverse.prototype.get = function(ps) {
var node = this.value;
for (var i = 0; i < ps.length; i++) {
var key = ps[i];
if (!node || !hasOwnProperty_1(node, key)) {
node = undefined;
break
}
node = node[key];
}
return node
};
/**
* @desc Return whether the element at the array path exists.
*
* @param {Array<string>} pathsArray paths
* @return {boolean} has element at path
*
* @memberOf Traverse
* @see hasOwnProperty
*
* @example
*
* traverse({eh: true}).has(['eh'])
* //=> true
*
* @example
*
* traverse({eh: true}).has(['canada'])
* //=> false
*
*
* @example
*
* traverse([0]).has([2])
* //=> false
*
*/
Traverse.prototype.has = function(pathsArray) {
var node = this.value;
for (var i = 0; i < pathsArray.length; i++) {
var key = pathsArray[i];
if (!node || !hasOwnProperty_1(node, key)) {
return false
}
node = node[key];
}
return true
};
/**
* @desc Set the element at the array path to value.
*
* @param {Array<string>} arrayPath paths
* @param {any} value any value to assign to the element @ the path
* @return {any} value