@blazingedge/update
Advanced tools
Comparing version 1.1.6 to 1.2.0
@@ -22,6 +22,8 @@ 'use strict'; | ||
function extend(dst, src) { | ||
for (var key in src) { | ||
dst[key] = src[key]; | ||
}return dst; | ||
function cloneObject(object) { | ||
var clone = Object.create(protoOf(object)); | ||
for (var key in object) { | ||
clone[key] = object[key]; | ||
} | ||
return clone; | ||
} | ||
@@ -35,3 +37,3 @@ | ||
function applyChange(key, val, data, original, dataIsArray, removeLater) { | ||
function applyValue(key, val, data, original, dataIsArray, removeLater) { | ||
if (val === data[key] || val === REMOVE && !dataIsArray && !(key in data)) { | ||
@@ -42,3 +44,3 @@ return data; | ||
if (data === original) { | ||
data = dataIsArray ? data.slice() : extend({}, data); | ||
data = dataIsArray ? data.slice() : cloneObject(data); | ||
} | ||
@@ -79,3 +81,3 @@ | ||
for (var i = 0; i < n; ++i) { | ||
ret = applyChange(i, f(array[i]), ret, array, true, true); | ||
ret = applyValue(i, f(array[i]), ret, array, true, true); | ||
} | ||
@@ -94,3 +96,3 @@ | ||
var ret = keys.reduce(function (acc, key) { | ||
return applyChange(key, f(data[key]), acc, data, dataIsArray, dataIsArray); | ||
return applyValue(key, f(data[key]), acc, data, dataIsArray, dataIsArray); | ||
}, data); | ||
@@ -111,6 +113,9 @@ | ||
function applyChange(data, change) { | ||
if (isFunc(change)) return change(data); | ||
if (isProps(change)) return patch(data, change); | ||
return change; | ||
} | ||
function patch(data, props) { | ||
if (isFunc(props)) return props(data); | ||
if (!isProps(props)) return props; | ||
var dataIsArray = isArray(data); | ||
@@ -120,4 +125,4 @@ var ret = data; | ||
for (var key in props) { | ||
var val = patch(data[key], props[key]); | ||
ret = applyChange(key, val, ret, data, dataIsArray, dataIsArray); | ||
var val = applyChange(data[key], props[key]); | ||
ret = applyValue(key, val, ret, data, dataIsArray, dataIsArray); | ||
} | ||
@@ -192,3 +197,3 @@ | ||
function updatePath(data, parts, index, change) { | ||
if (index === parts.length) return patch(data, change); | ||
if (index === parts.length) return applyChange(data, change); | ||
@@ -214,4 +219,5 @@ var part = parts[index++]; | ||
// part is a key/index | ||
var val = updatePath(data[part], parts, index, change); | ||
return applyChange(part, val, data, data, isArray(data), false); | ||
return applyValue(part, val, data, data, isArray(data), false); | ||
} | ||
@@ -222,3 +228,3 @@ | ||
case 2: | ||
return patch(arguments[0], arguments[1]); | ||
return applyChange(arguments[0], arguments[1]); | ||
case 3: | ||
@@ -225,0 +231,0 @@ return updatePath(arguments[0], toPathParts(arguments[1]), 0, arguments[2]); |
{ | ||
"name": "@blazingedge/update", | ||
"version": "1.1.6", | ||
"version": "1.2.0", | ||
"description": "Utility for immutable deep updates of objects.", | ||
@@ -5,0 +5,0 @@ "main": "lib", |
@@ -62,8 +62,8 @@ [![Build Status](https://travis-ci.org/blazing-edge-labs/update.svg?branch=master)](https://travis-ci.org/blazing-edge-labs/update) | ||
### Path with "**`*`**" | ||
### Path with "**\***" | ||
To apply a change to all values of an array/object, we can use "**`*`**". | ||
To apply a change to all values of an array/object, we can use "**\***". | ||
```js | ||
update(state, 'path.to.users[*].balance', n => n + 100) | ||
update(state, 'path.to.users[*].balance.amount', n => n + 100) | ||
@@ -70,0 +70,0 @@ update(state, 'path.to.users[*]', (user) => { |
@@ -9,5 +9,8 @@ const { isArray } = Array | ||
function extend (dst, src) { | ||
for (const key in src) dst[key] = src[key] | ||
return dst | ||
function cloneObject (object) { | ||
const clone = Object.create(protoOf(object)) | ||
for (const key in object) { | ||
clone[key] = object[key] | ||
} | ||
return clone | ||
} | ||
@@ -19,3 +22,3 @@ | ||
function applyChange (key, val, data, original, dataIsArray, removeLater) { | ||
function applyValue (key, val, data, original, dataIsArray, removeLater) { | ||
if (val === data[key] || val === REMOVE && !dataIsArray && !(key in data)) { | ||
@@ -26,3 +29,3 @@ return data | ||
if (data === original) { | ||
data = dataIsArray ? data.slice() : extend({}, data) | ||
data = dataIsArray ? data.slice() : cloneObject(data) | ||
} | ||
@@ -65,3 +68,3 @@ | ||
for (let i = 0; i < n; ++i) { | ||
ret = applyChange(i, f(array[i]), ret, array, true, true) | ||
ret = applyValue(i, f(array[i]), ret, array, true, true) | ||
} | ||
@@ -80,3 +83,3 @@ | ||
const ret = keys.reduce((acc, key) => { | ||
return applyChange(key, f(data[key]), acc, data, dataIsArray, dataIsArray) | ||
return applyValue(key, f(data[key]), acc, data, dataIsArray, dataIsArray) | ||
}, data) | ||
@@ -98,6 +101,9 @@ | ||
function applyChange (data, change) { | ||
if (isFunc(change)) return change(data) | ||
if (isProps(change)) return patch(data, change) | ||
return change | ||
} | ||
function patch (data, props) { | ||
if (isFunc(props)) return props(data) | ||
if (!isProps(props)) return props | ||
const dataIsArray = isArray(data) | ||
@@ -107,4 +113,4 @@ let ret = data | ||
for (const key in props) { | ||
const val = patch(data[key], props[key]) | ||
ret = applyChange(key, val, ret, data, dataIsArray, dataIsArray) | ||
const val = applyChange(data[key], props[key]) | ||
ret = applyValue(key, val, ret, data, dataIsArray, dataIsArray) | ||
} | ||
@@ -166,3 +172,3 @@ | ||
function updatePath (data, parts, index, change) { | ||
if (index === parts.length) return patch(data, change) | ||
if (index === parts.length) return applyChange(data, change) | ||
@@ -189,4 +195,5 @@ let part = parts[index++] | ||
// part is a key/index | ||
const val = updatePath(data[part], parts, index, change) | ||
return applyChange(part, val, data, data, isArray(data), false) | ||
return applyValue(part, val, data, data, isArray(data), false) | ||
} | ||
@@ -196,3 +203,3 @@ | ||
switch (arguments.length) { | ||
case 2: return patch(arguments[0], arguments[1]) | ||
case 2: return applyChange(arguments[0], arguments[1]) | ||
case 3: return updatePath(arguments[0], toPathParts(arguments[1]), 0, arguments[2]) | ||
@@ -199,0 +206,0 @@ default: throw new TypeError('invalid number of arguments') |
@@ -8,2 +8,4 @@ const test = require('tape') | ||
class MyClass {} | ||
const instance = new MyClass | ||
const noProto = Object.create(null) | ||
@@ -22,6 +24,10 @@ const data = { | ||
}, | ||
instance: new MyClass, | ||
instance, | ||
noProto, | ||
} | ||
const instance = new MyClass | ||
const newInstance = new MyClass | ||
const newNoProto = Object.create(null) | ||
newNoProto.foo = 1 | ||
newNoProto.bar = 2 | ||
@@ -45,3 +51,4 @@ const result = update(data, { | ||
}, | ||
instance, | ||
instance: newInstance, | ||
noProto: newNoProto, | ||
}) | ||
@@ -61,2 +68,3 @@ | ||
instance, | ||
noProto: newNoProto, | ||
}) | ||
@@ -68,3 +76,17 @@ | ||
t.is(result.b.bc, data.b.bc, 'same since content is not changed') | ||
t.is(result.instance, instance, 'handle instances as values') | ||
t.is(result.instance, newInstance, 'handle instances as values') | ||
t.is(result.noProto, newNoProto, 'handle Object.create(null) as values') | ||
const result2 = update(result, { | ||
noProto: { | ||
zing: 3, | ||
bar: REMOVE, | ||
}, | ||
}) | ||
t.isNot(result2.noProto, result.noProto, 'changed noProto is not same object') | ||
t.is(Object.getPrototypeOf(result2.noProto), null, 'new noProto does not have prototype') | ||
t.same(result2.noProto, { foo: 1, zing: 3 }) | ||
t.end() | ||
@@ -71,0 +93,0 @@ }) |
20888
525