Source: op/object.js

/**
 * these are a group of operations to mutate a slot with value type of Object
 *
 * @lends Slot.prototype
 *
 * */
const patch = {
  /**
   * patch the object value
   * @example
   * const $$s = $$({ name: 'Tom', color: 'Blue' });
   * $$s.patch({ name: 'Jerry', species: 'Mouse' });
   * console.log($$s.val()); // { name: 'Jerry', species: 'Mouse', colur: 'Blue' }
   *
   * @param {object} obj - object used to patch me
   * @return {Slot} this
   *
   * */
  patch(obj) {
    this.debug && console.info(
      `slot: slot ${this.tag()} is about to be patched`, obj
    );
    return this.val(Object.assign({}, this.val(), obj));
  },
  /**
   * omit the keys
   * @example
   * const $$s = $$({ name: 'Tom', color: 'Blue' });
   * $$s.omit(['color']);
   * console.log($$s.val(); // { name: 'Tom' }
   *
   * @return {Slot} this
   * */
  omit(keys) {
    for (let field of keys) {
      delete this._value[field];
    }
    return this.val(Object.assign({}, this._value));
  },
  /**
   * set the property of Slot's value
   * @example
   * const $$s = $$({ name: 'Tom', color: 'Red' });
   * $$s.set('color', 'Blue');
   * console.log($$s.val(); // { name: 'Tom', color: 'Red' }
   *
   * @return {Slot} this
   * */
  set(prop, value) {
    if (typeof value == 'function') {
      value = value.apply(this, [this._value[prop]]);
    }
    this._value[prop] = value;
    this.val(
      Array.isArray(this._value)?
        [].concat(this._value):
        Object.assign({}, this._value)
    );
    return this;
  },
  /**
   * set the deep property of Slot's value
   * @example
   * const $$s = $$({ name: 'Tom' });
   * $$s.setIn(['friend', 'name'], 'Jerry');
   * console.log($$s.val(); // { name: 'Tom', frien: { 'name': 'Red'} }
   *
   * @example
   * const s = slot({});
   * s.setIn(['a', 1], 'abc'); // { a: [, 'abc'] }
   *
   * @return {Slot} this
   * */
  setIn(path, value) {
    let o = this._value;
    for (let i = 0; i < path.length - 1; ++i) {
      let seg = path[i];
      let nextSeg = path[i + 1];
      o[seg] = o[seg] || (Number.isInteger(nextSeg)? []: {});
      o = o[seg];
    }
    let lastSeg = path[path.length - 1];
    if (typeof value == 'function') {
      value = value.apply(this, [o[lastSeg]]);
    }
    o[lastSeg] = value;
    this.val(Object.assign({}, this._value));
    return this;
  }
};

patch.assoc = patch.set;
patch.assocIn = patch.setIn;

export default patch;