UNPKG

chain-able

Version:

interfaces that describe their intentions.

2,058 lines (1,896 loc) 184 kB
(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