Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/modules / ___dist / chain-able / src / ChainedMapBase.js
Size: Mime:
"use strict";

const SHORTHANDS_KEY = require("./deps/meta/SHORTHANDS_KEY");

const Chainable = require("./Chainable");

const ObjectKeys = require("./deps/util/keys");

const ArrayFrom = require("./deps/util/from");

const dopemerge = require("./deps/dopemerge");

const reduce = require("./deps/reduce");

const reduceEntries = require("./deps/reduce/entries");

const isFunction = require("./deps/is/function");

const isUndefined = require("./deps/is/undefined");

const getMeta = require("./deps/meta");

const hasOwnPropertyFlipped = require("./deps/flipped/hasOwnPropertyFlipped");

const composer = require("./compose/composer");

const newMap = require("./deps/construct/map");

const hasMerge = hasOwnPropertyFlipped('merge');
/**
 * this is to avoid circular requires
 * because MergeChain & MethodChain extend this
 * yet .method & .merge use those chains
 * ...also, it serves as a non-references creator for extending new instances
 *    of Chainable, where it splits into (Map | Set) -> composed prototype decorators
 *
 *
 * @file
 * @since 4.0.0-alpha.1
 * @inheritdoc
 * @class ChainedMapBase
 * @member ChainedMapBase
 * @category Chainable
 * @extends {Chainable}
 * @type {Chainable}
 *
 * @types ChainedMapBase
 * @tests ChainedMap
 *
 * @prop {Meta} meta meta fn
 * @prop {Map} store main store
 *
 * {@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}
 * @see {@link pony-map}
 * @see {@link mozilla-map}
 * @see {@link emca-map}
 *
 * @see ChainedMap
 * @see Chainable
 * @see MergeChain
 * @see MethodChain
 * @see ChainedMap
 *
 */

const ComposeChainedMapBase = Target => {
  let ChainedMapBase = class ChainedMapBase extends Target {
    /**
     * @param {ChainedMapBase | Chainable | ParentType | any} parent ParentType
     * @constructor
     *
     * @example
     *
     *    class Eh extends ChainedMapBase {}
     *    Object.keys(eh)
     *    //=> ['store', 'meta']
     *
     */
    constructor(parent) {
      super(parent);
      this.store = new Map();
      this.meta = getMeta(this);
    }

  }; // const constructRef = Target.prototype.construct
  // ChainedMapBase.prototype.construct = function() {
  //   this.store = new Map()
  //   this.meta = getMeta(this)
  //   if (constructRef) constructRef.call(this)
  // }

  /**
   * @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.
   *
   * @memberOf ChainedMapBase
   * @version 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/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 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 (name, fn) {
    // get value, tap it, set it
    return this.set(name, fn(this.get(name), dopemerge));
  };
  /**
   * @version 5.0.0 <- moved into ChainedMapBase & ChainedSet for less monomorphic usage
   * @since 5.0.0-beta.7
   * @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']
   *
   */


  ChainedMapBase.prototype.keys = function () {
    return ArrayFrom(this.store.keys());
  };
  /**
   * @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 (obj) {
    const keys = ObjectKeys(obj);

    for (let k = 0; k < keys.length; k++) {
      const key = keys[k];
      const value = obj[key];
      const fn = this[key];

      if (hasMerge(fn)) {
        fn.merge(value);
      } else if (isFunction(fn)) {
        fn.call(this, value);
      } else {
        this.set(key, value);
      }
    }

    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 (methodsAsArray) {
    // default to an array as single argument
    let methods = methodsAsArray; // then not using array

    if (arguments.length > 1) {
      methods = Array.from(arguments);
    }

    methods.forEach(method => {
      this.meta(SHORTHANDS_KEY, method);

      this[method] = value => this.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
   * @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'}
   *
   */


  ChainedMapBase.prototype.entries = function (chains) {
    const reduced = reduce(this.store);
    if (isUndefined(chains)) return reduced;
    const reducer = reduceEntries(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
   * @version 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 (key) {
    // @TODO move this back out...
    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 (key, value) {
    this.store.set(key, value);
    return this;
  };

  return ChainedMapBase;
};
/**
 * @desc ChainedMapBase composer
 * @alias ComposeMap
 * @type {Composer}
 * @method compose
 * @memberOf ChainedMapBase
 *
 * @param {Class | Object | Composable} [Target=Chainable] class to extend
 * @return {Class} ChainedMapBase
 *
 * @example
 *
 *    const heh = class {}
 *    const composed = ChainedMapBase.compose(heh)
 *    const hehchain = new Composed()
 *    hehchain instanceof heh
 *    //=> true
 *
 */


const composed = composer(ComposeChainedMapBase, Chainable);
module.exports = composed;