'use strict'; var assign = require('Object.assign'); var keyOf = require('keyOf'); var invariant = require('invariant'); var hasOwnProperty = { } .hasOwnProperty; function shallowCopy(x){ if (Array.isArray(x)) { return x.concat(); } else if (x && typeof x === 'object') { return assign(new x.constructor(), x); } else { return x; } } var COMMAND_PUSH = keyOf({ $push: null } ); var COMMAND_UNSHIFT = keyOf({ $unshift: null } ); var COMMAND_SPLICE = keyOf({ $splice: null } ); var COMMAND_SET = keyOf({ $set: null } ); var COMMAND_MERGE = keyOf({ $merge: null } ); var COMMAND_APPLY = keyOf({ $apply: null } ); var ALL_COMMANDS_LIST = [COMMAND_PUSH, COMMAND_UNSHIFT, COMMAND_SPLICE, COMMAND_SET, COMMAND_MERGE, COMMAND_APPLY] ; var ALL_COMMANDS_SET = { } ; ALL_COMMANDS_LIST.forEach(function (command){ ALL_COMMANDS_SET[command] = true ; } ); function invariantArrayCase(value, spec, command){ invariant(Array.isArray(value), 'update(): expected target of %s to be an array; got %s.', command, value); var specValue = spec[command]; invariant(Array.isArray(specValue), 'update(): expected spec of %s to be an array; got %s. ' + 'Did you forget to wrap your parameter in an array?', command, specValue); } function update(value, spec){ invariant(typeof spec === 'object', 'update(): You provided a key path to update() that did not contain one ' + 'of %s. Did you forget to include {%s: ...}?', ALL_COMMANDS_LIST.join(', '), COMMAND_SET); if (hasOwnProperty.call(spec, COMMAND_SET)) { invariant(_AN_Read_length('length', Object.keys(spec)) === 1, 'Cannot have more than one key in an object with %s', COMMAND_SET); return spec[COMMAND_SET]; } var nextValue = shallowCopy(value); if (hasOwnProperty.call(spec, COMMAND_MERGE)) { var mergeObj = spec[COMMAND_MERGE]; invariant(mergeObj && typeof mergeObj === 'object', 'update(): %s expects a spec of type \'object\'; got %s', COMMAND_MERGE, mergeObj); invariant(nextValue && typeof nextValue === 'object', 'update(): %s expects a target of type \'object\'; got %s', COMMAND_MERGE, nextValue); assign(nextValue, spec[COMMAND_MERGE]); } if (hasOwnProperty.call(spec, COMMAND_PUSH)) { invariantArrayCase(value, spec, COMMAND_PUSH); spec[COMMAND_PUSH].forEach(function (item){ nextValue.push(item); } ); } if (hasOwnProperty.call(spec, COMMAND_UNSHIFT)) { invariantArrayCase(value, spec, COMMAND_UNSHIFT); spec[COMMAND_UNSHIFT].forEach(function (item){ nextValue.unshift(item); } ); } if (hasOwnProperty.call(spec, COMMAND_SPLICE)) { invariant(Array.isArray(value), 'Expected %s target to be an array; got %s', COMMAND_SPLICE, value); invariant(Array.isArray(spec[COMMAND_SPLICE]), 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]); spec[COMMAND_SPLICE].forEach(function (args){ invariant(Array.isArray(args), 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]); nextValue.splice.apply(nextValue, args); } ); } if (hasOwnProperty.call(spec, COMMAND_APPLY)) { invariant(typeof spec[COMMAND_APPLY] === 'function', 'update(): expected spec of %s to be a function; got %s.', COMMAND_APPLY, spec[COMMAND_APPLY]); nextValue = spec[COMMAND_APPLY](nextValue); } for (var k in spec){ if (!(ALL_COMMANDS_SET.hasOwnProperty(k) && ALL_COMMANDS_SET[k])) { nextValue[k] = update(value[k], spec[k]); } } return nextValue; } module.exports = update;