Repository URL to install this package:
|
Version:
1.2.6 ▾
|
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.composeClass = exports.ChainSnippet = exports.ContainerBase = void 0;
var _exotic = require("../../exotic");
var _dopemerge = _interopRequireDefault(require("../src/deps/dopemerge"));
var _keys = _interopRequireDefault(require("../src/deps/util/keys"));
var _entries = _interopRequireDefault(require("../src/deps/reduce/entries"));
var _reduce = _interopRequireDefault(require("../src/deps/reduce/reduce"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// almost all lodash/ramda/underscore style utils
// operation helper functions
// import { merge, ObjectKeys, reduceEntries, reduce } from 'chain
// all typechecks, all type corersions
/**
* @param {*} value
* @return {Boolean}
*/
const hasStore = value => (0, _exotic.hasOwnProp)(value, 'store');
/**
* @param {String | Primitive} key
* @param {*} value
* @return {Boolean}
* @see hasStore
*/
const shouldClear = (key, value) => (0, _exotic.isSet)(value) || (0, _exotic.isMap)(value) || hasStore(value);
/**
* ------------ additional resources -----------
* # internal @IMPORTANT @README
* https://jira.skava.net/confluence/display/ux/Exporting+in+es4-5-6-7
*
* # external
*
* https://blog.prototypr.io/design-system-ac88c6740f53
* http://demo.patternlab.io/?p=atoms-button
*
* https://github.com/acdlite/recompose/blob/master/src/packages/recompose/renameProps.js
*
*
* @todo tutorial on weakmap, weakset, set, map, symbol, exotic
* https://github.com/jonschlinkert/kind-of
* https://www.ecma-international.org/ecma-262/8.0/index.html#sec-weakmap-objects
* https://www.ecma-international.org/ecma-262/8.0/index.html#sec-symbol-objects
* https://www.ecma-international.org/ecma-262/8.0/index.html#sec-map-objects
* https://www.ecma-international.org/ecma-262/8.0/index.html#sec-set-objects
*
*
* @todo tutorial on container interface specification
*/
let Generic = class Generic {}; // eslint-disable-next-line
const composeClass = (Klass = Generic) => {
/**
* {@link https://tc39.github.io/ecma262/#sec-map-objects emca-map}
* {@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}
*
* @docs https://jira.skava.net/confluence/display/ux/Sprint+8+-+container
* @docs https://jira.skava.net/confluence/display/ux/Container+Layer
* @tutorial https://github.com/fluents/chain-able/wiki
*
* libs (large very powerful toolsets to built anything)
* @see modules/chain-able
* @see modules/exotic
*
* utils (small tools for solving some more specific problems)
* @see modules/deps
* @see modules/thisless
*
* our containers built with libs & utils ^:
* @see modules/router
* @see modules/state-tree
* @see modules/view-container
*
* ---
*
* @classdesc this class is a slice of chain-able container builders
* @see https://github.com/fluents/chain-able/wiki/ContainerBase
*
* it focuses on a very specific container, that has the most/best
* - easiest,
* - powerful
* - reusable
* - standard
*
* @prop {Map} store
*
*/
let ContainerBase = class ContainerBase extends Klass {
constructor(...args) {
super(...args);
/**
* @type {Map}
* @description we put all of our properties on this store
* this is the fastest, most consistent way to deal with all property storage
* and conforms to our common interface
*/
this.store = new Map();
}
setDebug(shouldDebug = true) {
return this.set('debug', shouldDebug);
}
getDebug() {
return this.get('debug');
}
};
/**
* @desc get value for key path in the Map store
*
* @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
*
* @example
* // if it was an obj
* this.store[name]
*/
ContainerBase.prototype.get = function (name) {
return this.store.get(name);
};
/**
* @desc sets the value using the key on store
* adds or updates an element with a specified key and value
*
* @memberOf ContainerBase
* @since 0.4.0
*
* @param {Primitive} key Primitive to reference the value
* @param {any} value any data to store
* @return {ContainerBase} @ContainerBase
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set mozilla-map-set}
* @see {@link mozilla-map-set}
* @see ContainerBase.store
*
* @example
*
* const chain = new Chain()
* chain.set('eh', true)
* chain.get('eh')
* //=> true
*
*/
ContainerBase.prototype.set = function (name, value) {
this.store[name] = value;
return this;
};
/**
* @desc checks each property of the object
* calls the chains accordingly
*
* @param {Object} obj object with functions to hydrate from
* @return {ContainerBase} @ContainerBase
*
* @example
*
* const from = new Chain().from({eh: true})
* const eh = new Chain().set('eh', true)
* eq(from, eh)
* //=> true
*
*/
ContainerBase.prototype.from = function (obj) {
const keys = (0, _keys.default)(obj);
for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) {
const key = keys[keyIndex];
const value = obj[key];
const fn = this[key];
if ((0, _exotic.isFunction)(fn)) {
fn.call(this, value);
} else {
this.set(key, value);
}
}
return this;
};
/**
* @desc spreads the entries from ContainerBase.store (Map)
* return store.entries, plus all chain properties if they exist
*
* @memberOf ContainerBase
* @version 4.0.0 <- improved reducing
* @since 0.4.0
*
* @param {boolean} [chains=false] if true, returns all properties that are chains
* @return {Object} reduced object containing all properties from the store, and when `chains` is true, all instance properties, and recursive chains
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries mozilla-map-entries}
* @see {@link mozilla-map-entries}
* @see deps/reduce/entries
*
* @example
*
* map.set('a', 'alpha').set('b', 'beta').entries()
* //=> {a: 'alpha', b: 'beta'}
*
*/
ContainerBase.prototype.entries = function (chains) {
const reduced = (0, _reduce.default)(this.store);
if ((0, _exotic.isUndefined)(chains)) {
return reduced;
}
const reducer = (0, _entries.default)(reduced);
reducer(this);
reducer(reduced);
return reduced;
};
/**
* @desc tap a value with a function
* @modifies this.store.get(name)
* Invokes interceptor with the obj, and then returns obj.
* The primary purpose of this method is to "tap into" a method chain, in
* order to perform operations on intermediate results within the chain.
*
* @param {string | any} name key to `.get`
* @param {Function} fn function to tap with
* @return {Chain} @ContainerBase
*
* {@link https://github.com/jashkenas/underscore/blob/master/underscore.js#L1161 underscore-tap}
* {@link https://github.com/ramda/ramda/blob/master/src/internal/_xtap.js ramda-xtap}
* {@link https://github.com/ramda/ramda/blob/master/src/tap.js ramda-tap}
* {@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 underscore-tap}
* @see {@link tapable}
* @see {@link ramda-tap}
*
* @see ContainerBase.set
* @see ContainerBase.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]}
*
*/
ContainerBase.prototype.tap = function (name, fn) {
// get value, tap it, set it
return this.set(name, fn(this.get(name), _dopemerge.default));
};
/**
* @return {Array<number | string | *>} keys
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/keys mozilla-set-keys}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys mozilla-map-keys}
* @see {@link mozilla-map-keys}
* @see {@link mozilla-set-keys}
*
* @example
*
* Chain.set('eh', 1).keys()
* //=> ['eh']
*
*/
ContainerBase.prototype.keys = function () {
return (0, _exotic.toArray)(this.store.keys());
};
/**
* @desc clears the map,
* goes through this properties,
* calls .clear if they are instanceof ContainerBase or Map
*
* @memberOf ContainerBase
* @since 4.0.0 (moved only to ContainerBase, added option to clear this keys)
* @since 0.4.0 (in ContainerBase)
* @since 0.3.0 (in ContainerBase)
*
* @param {boolean | undefined} [clearPropertiesThatAreChainLike=true] checks properties on the object, if they are `chain-like`, clears them as well
* @return {ContainerBase} @ContainerBase
*
* @see https://github.com/fliphub/flipchain/issues/2
* @see ChainedSet
* @see ContainerBase
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear map-clear}
* @see {@link map-clear}
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.entries()
* //=> {eh: 1}
* chain.clear()
* chain.entries()
* //=> {}
*
*/
ContainerBase.prototype.clear = function (clearPropertiesThatAreChainLike = true) {
this.store.clear();
if (clearPropertiesThatAreChainLike === false) {
return this;
}
const keys = (0, _keys.default)(this);
for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) {
const key = keys[keyIndex];
const property = this[key];
if (shouldClear(key, property)) {
this[key].clear();
}
}
return this;
};
/**
* @desc calls .delete on this.store.map
* @since 0.3.0
* @memberOf ContainerBase
*
* @param {Primitive} key on a Map: key referencing the value. on a Set: the index
* @return {ContainerBase}
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete mozilla-map-delete}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete mozilla-set-delete}
* @see {@link mozilla-map-delete}
* @see {@link mozilla-set-delete}
* @see ChainedSet
* @see ContainerBase
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.get('eh')
* //=> 1
*
* chain.delete('eh', 1)
* chain.get('eh')
* //=> undefined
*
*/
ContainerBase.prototype.delete = function (key) {
this.store.delete(key);
return this;
};
/**
* @desc checks whether the store has a value for a given key
* @memberOf ContainerBase
* @since 0.3.0
*
* @param {any} keyOrValue key when Map, value when Set
* @return {boolean} `this.store.has(keyOrValue)`
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has mozilla-map-has}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has mozilla-set-has}
* @see {@link mozilla-map-has}
* @see {@link mozilla-set-has}
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1).has('eh')
* //=> true
* chain.has('canada')
* //=> false
*
*/
ContainerBase.prototype.has = function (keyOrValue) {
return this.store.has(keyOrValue);
};
/**
* @desc spreads the entries from ContainerBase.store.values
* allocates a new array, adds the values from the iterator
*
* @memberOf ContainerBase
* @since 0.4.0
*
* @return {Array<any>} toArr(this.store.values())
*
* @NOTE look at ContainerBase.constructor to ensure not to use `new Array...`
* @NOTE moved from ContainerBase and ChainedSet to ContainerBase @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]
*
*/
ContainerBase.prototype.values = function () {
return (0, _exotic.toArray)(this.store.values());
}; // --- symbols ---
/**
* @desc Iterator for looping values in the store
*
* @type {generator}
* @return {Object} {value: undefined | any, done: true | false}
*
* @NOTE assigned to a variable so buble ignores it
* @NOTE both Map & Set collections iterate with `[key, val]`
*
* @see https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html
* @see http://exploringjs.com/es6/ch_iteration.html#_maps-1
* @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
* @see this.store
*
* @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
* }
*
*/
ContainerBase.prototype[Symbol.iterator] = function () {
return (0, _exotic.fromKeyValueToIterator)(this.keys(), this.values(), this.store.size);
};
/**
* @desc symbol method for toString, toJSON, toNumber
* @memberOf ContainerBase
* @since 1.0.2
* @version 2
*
* @param {string} hint enum[default, string, number]
* @return {Primitive}
*
* {@link http://2ality.com/2015/09/well-known-symbols-es6.html#default-tostring-tags well-known-symbols-es6}
* @see {@link well-known-symbols-es6}
*
* @example
*
* const chain = new Chain()
* chain.toNumber = () => 1
* +chain;
* //=> 1
* chain + 1
* //=>
*
* @example
*
* const chain = new Chain()
* chain.toString = () => 'eh'
* chain + ''
* //=> 'eh'
*
*/
ContainerBase.prototype[Symbol.toPrimitive] = 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();
};
/**
* @see https://jira.skava.net/confluence/display/ux/getters+and+setters+in+es5-6
* @name length
* @method length
* @readonly
* @see ContainerBase.store
* @return {number}
* @example for (var i = 0; i < chain.length; i++)
*/
Object.defineProperty(ContainerBase.prototype, 'length', {
enumerable: false,
get() {
return this.store.size;
}
});
Object.defineProperty(ContainerBase.prototype, Symbol.hasInstance, {
enumerable: false,
value: instance => (0, _exotic.isObj)(instance) === false ? false : isPrototypeOf(ContainerBase.prototype, instance) || hasStore(instance)
});
return ContainerBase;
};
exports.composeClass = composeClass;
const ContainerBase = composeClass();
exports.ChainSnippet = exports.ContainerBase = ContainerBase;
ContainerBase.composeClass = composeClass;
var _default = ContainerBase;
exports.default = _default;