src/set.js
function set(base, path, value, { withArrays, sameValue }) {
  if (path.length === 0) {
    return value;
  }

  const [key, nextKey] = path;
  const isArrayKeys = Array.isArray(key);
  let currentBase = base;

  if (!base || typeof base !== 'object') {
    currentBase = (isArrayKeys && typeof key[0] === 'number') || (withArrays && typeof key === 'number') ? [] : {};
  }

  if (isArrayKeys) {
    if (Array.isArray(currentBase)) {
      return reduceWithArray(set)(currentBase, path, key, nextKey, value, { withArrays, sameValue }, [...currentBase]);
    }

    return {
      ...currentBase,
      ...reduceWithObject(set)(currentBase, path, key, nextKey, value, { withArrays, sameValue }, {}),
    };
  }

  if (Array.isArray(currentBase)) {
    return [
      ...currentBase.slice(0, key),
      set(nextBase(currentBase, key, nextKey, withArrays), path.slice(1), value, { withArrays, sameValue }),
      ...currentBase.slice(key + 1),
    ];
  }

  return {
    ...currentBase,
    [key]: set(nextBase(currentBase, key, nextKey, withArrays), path.slice(1), value, { withArrays, sameValue }),
  };
}
function set(base, path, value, { withArrays, sameValue }) {
  if (path.length === 0) {
    return value;
  }

  const [key, nextKey] = path;
  const isArrayKeys = Array.isArray(key);
  let currentBase = base;

  if (!base || typeof base !== 'object') {
    currentBase = (isArrayKeys && typeof key[0] === 'number') || (withArrays && typeof key === 'number') ? [] : {};
  }

  if (isArrayKeys) {
    if (Array.isArray(currentBase)) {
      return reduceWithArray(set)(currentBase, path, key, nextKey, value, { withArrays, sameValue }, [...currentBase]);
    }

    return {
      ...currentBase,
      ...reduceWithObject(set)(currentBase, path, key, nextKey, value, { withArrays, sameValue }, {}),
    };
  }

  if (Array.isArray(currentBase)) {
    return [
      ...currentBase.slice(0, key),
      set(nextBase(currentBase, key, nextKey, withArrays), path.slice(1), value, { withArrays, sameValue }),
      ...currentBase.slice(key + 1),
    ];
  }

  return {
    ...currentBase,
    [key]: set(nextBase(currentBase, key, nextKey, withArrays), path.slice(1), value, { withArrays, sameValue }),
  };
}
function set ( base , path , value , { withArrays , sameValue } ) { if ( path . length === 0 ) { return value ; } const [ key , nextKey ] = path ; const isArrayKeys = Array . isArray ( key ) ; let currentBase = base ; if ( ! base || typeof base !== 'object' ) { currentBase = ( isArrayKeys && typeof key [ 0 ] === 'number' ) || ( withArrays && typeof key === 'number' ) ? [ ] : { } ; } if ( isArrayKeys ) { if ( Array . isArray ( currentBase ) ) { return reduceWithArray ( set ) ( currentBase , path , key , nextKey , value , { withArrays , sameValue } , [ ... currentBase ] ) ; } return { ... currentBase , ... reduceWithObject ( set ) ( currentBase , path , key , nextKey , value , { withArrays , sameValue } , { } ) , } ; } if ( Array . isArray ( currentBase ) ) { return [ ... currentBase . slice ( 0 , key ) , set ( nextBase ( currentBase , key , nextKey , withArrays ) , path . slice ( 1 ) , value , { withArrays , sameValue } ) , ... currentBase . slice ( key + 1 ) , ] ; } return { ... currentBase , [ key ] : set ( nextBase ( currentBase , key , nextKey , withArrays ) , path . slice ( 1 ) , value , { withArrays , sameValue } ) , } ; }
Recursive immutable set
@param base current base
@param path current path
@param value current value
@param config
- withArrays create arrays instead of object when nextKey is a number and key has no value in the current base
- sameValue use the same value for each element
@returns {*} a new instance of the given level
Recursive immutable set