166 lines
4.8 KiB
JavaScript
166 lines
4.8 KiB
JavaScript
var assert = require('./assert');
|
|
var isObject = require('./isObject');
|
|
var isFunction = require('./isFunction');
|
|
var isArray = require('./isArray');
|
|
var isNumber = require('./isNumber');
|
|
var assign = require('./assign');
|
|
|
|
function getShallowCopy(x) {
|
|
if (isObject(x)) {
|
|
if (x instanceof Date || x instanceof RegExp) {
|
|
return x;
|
|
}
|
|
return assign({}, x);
|
|
}
|
|
if (isArray(x)) {
|
|
return x.concat();
|
|
}
|
|
return x;
|
|
}
|
|
|
|
function isCommand(k) {
|
|
return update.commands.hasOwnProperty(k);
|
|
}
|
|
|
|
function getCommand(k) {
|
|
return update.commands[k];
|
|
}
|
|
|
|
function update(instance, patch) {
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isObject(patch), function () { return 'Invalid argument patch ' + assert.stringify(patch) + ' supplied to function update(instance, patch): expected an object containing commands'; });
|
|
}
|
|
|
|
var value = instance;
|
|
var isChanged = false;
|
|
var newValue;
|
|
for (var k in patch) {
|
|
if (patch.hasOwnProperty(k)) {
|
|
if (isCommand(k)) {
|
|
newValue = getCommand(k)(patch[k], value);
|
|
if (newValue !== instance) {
|
|
isChanged = true;
|
|
value = newValue;
|
|
} else {
|
|
value = instance;
|
|
}
|
|
}
|
|
else {
|
|
if (value === instance) {
|
|
value = getShallowCopy(instance);
|
|
}
|
|
newValue = update(value[k], patch[k]);
|
|
isChanged = isChanged || ( newValue !== value[k] );
|
|
value[k] = newValue;
|
|
}
|
|
}
|
|
}
|
|
return isChanged ? value : instance;
|
|
}
|
|
|
|
// built-in commands
|
|
|
|
function $apply(f, value) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isFunction(f), 'Invalid argument f supplied to immutability helper { $apply: f } (expected a function)');
|
|
}
|
|
return f(value);
|
|
}
|
|
|
|
function $push(elements, arr) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isArray(elements), 'Invalid argument elements supplied to immutability helper { $push: elements } (expected an array)');
|
|
assert(isArray(arr), 'Invalid value supplied to immutability helper $push (expected an array)');
|
|
}
|
|
if (elements.length > 0) {
|
|
return arr.concat(elements);
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function $remove(keys, obj) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isArray(keys), 'Invalid argument keys supplied to immutability helper { $remove: keys } (expected an array)');
|
|
assert(isObject(obj), 'Invalid value supplied to immutability helper $remove (expected an object)');
|
|
}
|
|
if (keys.length > 0) {
|
|
obj = getShallowCopy(obj);
|
|
for (var i = 0, len = keys.length; i < len; i++ ) {
|
|
delete obj[keys[i]];
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function $set(value) {
|
|
return value;
|
|
}
|
|
|
|
function $splice(splices, arr) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isArray(splices) && splices.every(isArray), 'Invalid argument splices supplied to immutability helper { $splice: splices } (expected an array of arrays)');
|
|
assert(isArray(arr), 'Invalid value supplied to immutability helper $splice (expected an array)');
|
|
}
|
|
if (splices.length > 0) {
|
|
arr = getShallowCopy(arr);
|
|
return splices.reduce(function (acc, splice) {
|
|
acc.splice.apply(acc, splice);
|
|
return acc;
|
|
}, arr);
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function $swap(config, arr) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isObject(config), 'Invalid argument config supplied to immutability helper { $swap: config } (expected an object)');
|
|
assert(isNumber(config.from), 'Invalid argument config.from supplied to immutability helper { $swap: config } (expected a number)');
|
|
assert(isNumber(config.to), 'Invalid argument config.to supplied to immutability helper { $swap: config } (expected a number)');
|
|
assert(isArray(arr), 'Invalid value supplied to immutability helper $swap (expected an array)');
|
|
}
|
|
if (config.from !== config.to) {
|
|
arr = getShallowCopy(arr);
|
|
var element = arr[config.to];
|
|
arr[config.to] = arr[config.from];
|
|
arr[config.from] = element;
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function $unshift(elements, arr) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isArray(elements), 'Invalid argument elements supplied to immutability helper {$unshift: elements} (expected an array)');
|
|
assert(isArray(arr), 'Invalid value supplied to immutability helper $unshift (expected an array)');
|
|
}
|
|
if (elements.length > 0) {
|
|
return elements.concat(arr);
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function $merge(whatToMerge, value) {
|
|
var isChanged = false;
|
|
var result = getShallowCopy(value);
|
|
for (var k in whatToMerge) {
|
|
if (whatToMerge.hasOwnProperty(k)) {
|
|
result[k] = whatToMerge[k];
|
|
isChanged = isChanged || ( result[k] !== value[k] );
|
|
}
|
|
}
|
|
return isChanged ? result : value;
|
|
}
|
|
|
|
update.commands = {
|
|
$apply: $apply,
|
|
$push: $push,
|
|
$remove: $remove,
|
|
$set: $set,
|
|
$splice: $splice,
|
|
$swap: $swap,
|
|
$unshift: $unshift,
|
|
$merge: $merge
|
|
};
|
|
|
|
module.exports = update;
|