src/js_container_factory.js

const instanceContainerTypes = new WeakMap();
/**
 * @class
 * @summary A class to construct alternative sequential/mapping typings based on key type
 * @implements {ContainerFactory}
 * 
 * @description
 * Use containers with the interfaces of the Array and ES6 Map classes as the
 * constructed containers based on the type of the key to be used for indexing
 * the container: a number indicates an Array and anything else uses a Map.
 *
 * Pass an instance of this class as the containerFactory option when
 * constructing a LensFactory. The container types to be used can be customized
 * when constructing this factory.
 */
class JsContainerFactory {
  /**
   * Construct a factory object
   * @param {Object} containerTypes
   * @param {Function} [containerTypes.Map = Map]  Map-equivalent container to construct
   * @param {Function} [containerTypes.Array = Array]  Array-equivalent container to construct
   */
  constructor(containerTypes = {Map, Array}) {
    instanceContainerTypes.set(this, {...containerTypes});
  }
  
  /**
   * The container type provided by this instance
   * @type {Object}
   *
   * @property {Function} Map  The "map" type
   * @property {Function} Array The "array" type
   */
  get containerTypes() {
    return {
      Map, Array,
      ...(instanceContainerTypes.get(this) ||
        /* istanbul ignore next: this shouldn't be possible */ {})
    };
  }
  
  /**
   * Construct the missing container
   * @param {Array} keys  The keys up to and including the one into the missing container
   * @returns {*} The missing container
   */
  construct(keys) {
    const types = instanceContainerTypes.get(this);
    const k = keys[keys.length - 1];
    return (typeof k === 'number')
      ? new (types.Array || Array)()
      : new (types.Map || Map)();
  }
}

export const DEFAULT_FACTORY = new JsContainerFactory();

export default JsContainerFactory;