u(updates(, object))
Update as many values as you want, as deeply as you want. The updates
parameter can either be an object, a function, or a value. Everything returned from u
is frozen recursively.
If updates
is an object, for each key/value, it will apply the updates specified in the value to object[key]
.
If updates
is a function, it will call the function with object
and return the value.
If updates
is a value, it will return that value.
Sometimes, you may want to set an entire object to a property, or a function. In that case, you'll need to use a function to return that value, otherwise it would be interpreted as an update. Ex. function() { return { a: 0 }; }
.
Also available at u.update(...)
.
Object properties:
var person = {
name: {
first: 'Jane',
last: 'West'
}
};
var result = u({ name: { first: 'Susan' } }, person);
expect(result).to.eql({ name: { first: 'Susan', last: 'West' } });
Array elements:
var scoreboard = {
scores: [12, 28]
};
var result = u({ scores: { 1: 36 } }, scoreboard);
expect(result).to.eql({ scores: [12, 36] });
var person = {
name: {
first: 'Mike',
last: 'Smith'
},
scores: [12, 28]
};
var result = u({ name: { last: 'Jones' }, scores: { 1: 36 } }, person);
expect(result).to.eql({ name: { first: 'Mike', last: 'Jones' }, scores: [12, 36] });
function increment(i) { return i + 1; }
var scoreboard = {
scores: {
team1: 0,
team2: 0
}
};
var result = u({ scores: { team2: increment } }, scoreboard);
expect(result).to.eql({ scores: { team1: 0, team2: 1 } });
Non-trivial array manipulations, such as element removal/insertion/sorting, can be implemented with functions. Because there are so many possible manipulations, we don't provide any helpers and leave this up to you. Simply ensure your function is pure and does not mutate its arguments.
function addTodo(todos) { return [].concat(todos, [{ done: false }]); }
var state = {
todos: [
{ done: false },
{ done: false }
]
};
var result = u({ todos: addTodo }, state);
expect(result).to.eql({ todos: [{ done: false }, { done: false }, { done: false }]});
var result = u({ foo: 'bar' }, null);
expect(result).to.eql({ foo: 'bar' });
var result = u({ 0: 'foo', 1: 'bar' }, null);
expect(result).to.eql(['foo', 'bar']);
function increment(i) { return i + 1; }
var addOneYear = u({ age: increment });
var result = addOneYear({ name: 'Shannon Barnes', age: 62 });
expect(result).to.eql({ name: 'Shannon Barnes', age: 63 });
var key = 'age';
var result = u({ person: { [key]: 21 } }, { person: { name: 'Olivier P.', age: 20 } });
expect(result).to.eql({ person: { name: 'Olivier P.', age: 21 } });
u.freeze
Freeze your initial state to protect against mutations. Only performs the freezing in development, and returns the original object unchanged in production.
var state = u.freeze({ someKey: "Some Value" })
state.someKey = "Mutate" // ERROR in development
u._
All updeep functions are curried. If you want to partially apply a function in an order other than the default argument order, you can use the placeholder.
function increment(i) { return i + 1; }
var updateJoe = u(u._, { name: "Joe Merrill", age: 21 });
var result = updateJoe({ age: increment });
expect(result).to.eql({ name: "Joe Merrill", age: 22 });
u.updateIn(path(, value)(, object))
Update a single value with a simple string or array path. Can be use to update nested objects, arrays, or a combination. Can also be used to update every element of a nested array with '*'
.
var result = u.updateIn('bunny.color', 'brown', { bunny: { color: 'black' } });
expect(result).to.eql({ bunny: { color: 'brown' } });
var result = u.updateIn('0.1.color', 'brown', [[{ color: 'blue' }, { color: 'red' }], []]);
expect(result).to.eql( [[{ color: 'blue' }, { color: 'brown' }], []]);
function increment(i) { return i + 1; }
var result = u.updateIn('bunny.age', increment, { bunny: { age: 2 } });
expect(result).to.eql({ bunny: { age: 3 } });
var result = u({ pets: u.updateIn([0, 'bunny', 'age'], 3) }, { pets: [{ bunny: { age: 2 } }] });
expect(result).to.eql({ pets: [{ bunny: { age: 3 } }] });
var result = u.updateIn('todos.*.done', true, {
todos: [
{ done: false },
{ done: false },
]
});
expect(result).to.eql({
todos: [
{ done: true },
{ done: true },
]
});
u.constant(object)
Sometimes, you want to replace an object outright rather than merging it.
You'll need to use a function that returns the new object.
u.constant
creates that function for you.
var user = {
name: 'Mitch',
favorites: {
band: 'Nirvana',
movie: 'The Matrix'
}
};
var newFavorites = {
band: 'Coldplay'
};
var result = u({ favorites: u.constant(newFavorites) }, user);
expect(result).to.eql({ name: 'Mitch', favorites: { band: 'Coldplay' } });
var alwaysFour = u.constant(4);
expect(alwaysFour(32)).to.eql(4);
u.if(predicate(, updates)(, object))
Apply updates
if predicate
is truthy, or if predicate
is a function.
It evaluates to truthy when called with object
.
function isEven(x) { return x % 2 === 0; }
function increment(x) { return x + 1; }
var result = u({ value: u.if(isEven, increment) }, { value: 2 });
expect(result).to.eql({ value: 3 });
u.ifElse(predicate(, trueUpdates)(, falseUpdates)(, object))
Apply trueUpdates
if predicate
is truthy, or if predicate
is a function.
It evaluates to truthy when called with object
. Otherwise, apply falseUpdates
.
function isEven(x) { return x % 2 === 0; }
function increment(x) { return x + 1; }
function decrement(x) { return x - 1; }
var result = u({ value: u.ifElse(isEven, increment, decrement) }, { value: 3 });
expect(result).to.eql({ value: 2 });
u.map(iteratee(, object))
If iteratee is a function, map it over the values in object
.
If it is an object, apply it as updates to each value in object
,
which is equivalent to u.map(u(...), object)
).
function increment(x) { return x + 1; }
var result = u({ values: u.map(increment) }, { values: [0, 1] });
expect(result).to.eql({ values: [1, 2] });
function increment(x) { return x + 1; }
var result = u.map(increment, [0, 1, 2]);
expect(result).to.eql([1, 2, 3]);
function increment(x) { return x + 1; }
var result = u.map(increment, { a: 0, b: 1, c: 2 });
expect(result).to.eql({ a: 1, b: 2, c: 3 });
var result = u.map({ a: 100 }, [{ a: 0 }, { a: 1 }]);
expect(result).to.eql([{ a: 100 }, { a: 100 }]);
u.omit(predicate(, object))
Remove properties. See _.omit
.
var user = { user: { email: 'john@aol.com', username: 'john123', authToken: '1211..' } };
var result = u({ user: u.omit('authToken') }, user);
expect(result).to.eql({ user: { email: 'john@aol.com', username: 'john123' } });
var user = {
user: {
email: 'john@aol.com',
username: 'john123',
authToken: '1211..',
SSN: 5551234
}
};
var result = u({ user: u.omit(['authToken', 'SSN']) }, user);
expect(result).to.eql({ user: { email: 'john@aol.com', username: 'john123' } });
u.omitBy(predicate(, object))
Remove properties. See _.omitBy
.
var user = {
user: {
email: 'john@aol.com',
username: 'john123',
authToken: '1211..',
SSN: 5551234
}
};
function isSensitive(value, key) { return key == 'SSN' }
var result = u({ user: u.omitBy(isSensitive, user);
expect(result).to.eql({ user: { email: 'john@aol.com', username: 'john123', authToken: '1211..' } });
u.reject(predicate(, object))
Reject items from an array. See _.reject
.
function isEven(i) { return i % 2 === 0; }
var result = u({ values: u.reject(isEven) }, { values: [1, 2, 3, 4] });
expect(result).to.eql({ values: [1, 3] });
u.withDefault(default(, updates)(, object))
Like u()
, but start with the default value if the original value is undefined.
var result = u({ value: u.withDefault([], { 0: 3 }) }, {});
expect(result).to.eql({ value: [3] });
See the tests for more examples.
u.is(path(, predicate)(, object))
Returns true
if the predicate
matches the path
applied to the object
.
If the predicate
is a function, the result is returned. If not, they are compared with ===
.
var result = u.is('friend.age', 22, { friend: { age: 22 } });
expect(result).to.eql(true);
function isEven(i) { return i % 2 === 0; }
var result = u.is('friend.age', isEven, { friend: { age: 22 } });
expect(result).to.eql(true);
var person = {
person: {
name: {
first: 'Jen',
last: 'Matthews'
}
}
};
// Update person's last name to Simpson if their first name is Jen
var result = u({
person: u.if(
u.is('name.first', 'Jen'),
u.updateIn('name.last', 'Simpson')
)
}, person);
expect(result).to.eql({ person: { name: { first: 'Jen', last: 'Simpson' } } });