Freeze objects returned by helper methods
This commit is contained in:
parent
cc42bbb2a4
commit
b1e000b06d
@ -3,7 +3,8 @@
|
||||
## [unreleased]
|
||||
* Add `u.if` to conditionally update objects.
|
||||
* Add `u.map` to update all values in an array or object.
|
||||
* Replace object outright if null or constant givens as `updates`.
|
||||
* Replace object outright if null or constant provided as `updates`.
|
||||
* Freeze objects returned by helper methods that use `update` like `withDefault`, `map`, `in`, etc. Previously, only `u` did freezing.
|
||||
|
||||
## [0.3.1]
|
||||
* Actually expose `u.in`.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import curry from 'lodash/function/curry';
|
||||
import update from './update';
|
||||
import wrap from './wrap';
|
||||
|
||||
function updateIf(predicate, updates, object) {
|
||||
const test = typeof predicate === 'function' ?
|
||||
@ -13,4 +13,4 @@ function updateIf(predicate, updates, object) {
|
||||
return update(updates, object);
|
||||
}
|
||||
|
||||
export default curry(updateIf);
|
||||
export default wrap(updateIf);
|
||||
|
@ -1,8 +1,12 @@
|
||||
import curry from 'lodash/function/curry';
|
||||
import reject from 'lodash/collection/reject';
|
||||
import update from './update';
|
||||
|
||||
function updateIn(path, value, object) {
|
||||
const parts = Array.isArray(path) ? path : path.split('.');
|
||||
const parts = Array.isArray(path) ?
|
||||
path :
|
||||
reject(path.split('.'), x => !x);
|
||||
|
||||
const updates = parts.reduceRight((acc, key) => ({ [key]: acc }), value);
|
||||
|
||||
return update(updates, object);
|
||||
|
24
lib/index.js
24
lib/index.js
@ -7,20 +7,14 @@ import reject from './reject';
|
||||
import withDefault from './withDefault';
|
||||
import update from './update';
|
||||
|
||||
import curry from 'lodash/function/curry';
|
||||
const u = update;
|
||||
|
||||
function updateAndFreeze(updates, object) {
|
||||
return freeze(update(updates, object));
|
||||
}
|
||||
u.if = _if;
|
||||
u.in = _in;
|
||||
u.freeze = freeze;
|
||||
u.map = map;
|
||||
u.omit = omit;
|
||||
u.reject = reject;
|
||||
u.withDefault = withDefault;
|
||||
|
||||
const updeep = curry(updateAndFreeze);
|
||||
|
||||
updeep.if = _if;
|
||||
updeep.in = _in;
|
||||
updeep.freeze = freeze;
|
||||
updeep.map = map;
|
||||
updeep.omit = omit;
|
||||
updeep.reject = reject;
|
||||
updeep.withDefault = withDefault;
|
||||
|
||||
export default updeep;
|
||||
export default u;
|
||||
|
@ -1,11 +1,9 @@
|
||||
import curry from 'lodash/function/curry';
|
||||
import mapValues from 'lodash/object/mapValues';
|
||||
import update from './update';
|
||||
import wrap from './wrap';
|
||||
|
||||
function map(iteratee, object) {
|
||||
const updater = typeof iteratee === 'function' ?
|
||||
iteratee :
|
||||
val => update(iteratee, val);
|
||||
const updater = update(iteratee);
|
||||
|
||||
if (Array.isArray(object)) {
|
||||
return object.map(updater);
|
||||
@ -14,4 +12,4 @@ function map(iteratee, object) {
|
||||
return mapValues(object, updater);
|
||||
}
|
||||
|
||||
export default curry(map);
|
||||
export default wrap(map);
|
||||
|
10
lib/omit.js
10
lib/omit.js
@ -1,4 +1,8 @@
|
||||
import omit from 'lodash/object/omit';
|
||||
import curry from 'lodash/function/curry';
|
||||
import _omit from 'lodash/object/omit';
|
||||
import wrap from './wrap';
|
||||
|
||||
export default curry((predicate, collection) => omit(collection, predicate));
|
||||
function omit(predicate, collection) {
|
||||
return _omit(collection, predicate);
|
||||
}
|
||||
|
||||
export default wrap(omit);
|
||||
|
@ -1,4 +1,8 @@
|
||||
import reject from 'lodash/collection/reject';
|
||||
import curry from 'lodash/function/curry';
|
||||
import _reject from 'lodash/collection/reject';
|
||||
import wrap from './wrap';
|
||||
|
||||
export default curry((predicate, collection) => reject(collection, predicate));
|
||||
function reject(predicate, collection) {
|
||||
return _reject(collection, predicate);
|
||||
}
|
||||
|
||||
export default wrap(reject);
|
||||
|
@ -1,6 +1,8 @@
|
||||
import reduce from 'lodash/collection/reduce';
|
||||
import isEmpty from 'lodash/lang/isEmpty';
|
||||
import assign from 'lodash/object/assign';
|
||||
import curry from 'lodash/function/curry';
|
||||
import wrap from './wrap';
|
||||
|
||||
function resolveUpdates(updates, object = {}) {
|
||||
return reduce(updates, (acc, value, key) => {
|
||||
@ -43,9 +45,9 @@ function updateArray(updates, object) {
|
||||
* @param {Object|Array} object to update
|
||||
* @return {Object|Array} new object with modifications
|
||||
*/
|
||||
function update(updates, object) {
|
||||
function update(updates, object, ...args) {
|
||||
if (typeof updates === 'function') {
|
||||
return updates(object);
|
||||
return updates(object, ...args);
|
||||
}
|
||||
|
||||
if (updates === null || typeof updates !== 'object') {
|
||||
@ -65,4 +67,4 @@ function update(updates, object) {
|
||||
return assign({}, object, resolvedUpdates);
|
||||
}
|
||||
|
||||
export default update;
|
||||
export default wrap(update);
|
||||
|
@ -1,11 +1,12 @@
|
||||
import update from './update';
|
||||
import curry from 'lodash/function/curry';
|
||||
|
||||
export default function withDefault(defaultValue, updates) {
|
||||
return (value) => {
|
||||
if (typeof value === 'undefined') {
|
||||
function withDefault(defaultValue, updates, object) {
|
||||
if (typeof object === 'undefined') {
|
||||
return update(updates, defaultValue);
|
||||
}
|
||||
|
||||
return update(updates, value);
|
||||
};
|
||||
return update(updates, object);
|
||||
}
|
||||
|
||||
export default curry(withDefault);
|
||||
|
9
lib/wrap.js
Normal file
9
lib/wrap.js
Normal file
@ -0,0 +1,9 @@
|
||||
import curry from 'lodash/function/curry';
|
||||
import freeze from './freeze';
|
||||
|
||||
export default function wrap(func, length = func.length) {
|
||||
return curry(
|
||||
(...args) => freeze(func(...args)),
|
||||
length
|
||||
);
|
||||
}
|
@ -33,4 +33,9 @@ describe('u.if', () => {
|
||||
|
||||
expect(result).to.eql({ a: 3 });
|
||||
});
|
||||
|
||||
it('freezes the result', () => {
|
||||
expect(Object.isFrozen(u.if(true, {}, {}))).to.be.true;
|
||||
expect(Object.isFrozen(u.if(false, {}, {}))).to.be.true;
|
||||
});
|
||||
});
|
||||
|
@ -32,4 +32,14 @@ describe('u.in', () => {
|
||||
const result = u.in('a.b')(3)(object);
|
||||
expect(result).to.eql({ a: { b: 3 } });
|
||||
});
|
||||
|
||||
it('replaces the object outright if the path is empty', () => {
|
||||
const object = {};
|
||||
const result = u.in('', 3, object);
|
||||
expect(result).to.equal(3);
|
||||
});
|
||||
|
||||
it('freezes the result', () => {
|
||||
expect(Object.isFrozen(u.in('a', 0, {}))).to.be.true;
|
||||
});
|
||||
});
|
||||
|
@ -52,4 +52,8 @@ describe('u.map', () => {
|
||||
b: [0, 1],
|
||||
});
|
||||
});
|
||||
|
||||
it('freezes the result', () => {
|
||||
expect(Object.isFrozen(u.map({}, {}))).to.be.true;
|
||||
});
|
||||
});
|
||||
|
14
test/omit-spec.js
Normal file
14
test/omit-spec.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { expect } from 'chai';
|
||||
import u from '../lib';
|
||||
|
||||
describe('u.omit', () => {
|
||||
it('can omit a key', () => {
|
||||
const result = u({ foo: u.omit('bar') }, { foo: { bar: 7 } });
|
||||
|
||||
expect(result).to.eql({ foo: {} });
|
||||
});
|
||||
|
||||
it('freezes the result', () => {
|
||||
expect(Object.isFrozen(u.omit('a', {}))).to.be.true;
|
||||
});
|
||||
});
|
8
test/reject-spec.js
Normal file
8
test/reject-spec.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { expect } from 'chai';
|
||||
import u from '../lib';
|
||||
|
||||
describe('u.reject', () => {
|
||||
it('freezes the result', () => {
|
||||
expect(Object.isFrozen(u.reject('a', []))).to.be.true;
|
||||
});
|
||||
});
|
@ -74,6 +74,13 @@ describe('updeep', () => {
|
||||
expect(result).to.deep.equal({ foo: 4 });
|
||||
});
|
||||
|
||||
it('passes additional arguments on to updates if it is a function', () => {
|
||||
const func = (_, x) => x;
|
||||
const result = u(func, 0, 4);
|
||||
|
||||
expect(result).to.equal(4);
|
||||
});
|
||||
|
||||
it('can update if the value is an array', () => {
|
||||
const object = {};
|
||||
const result = u({ foo: [0, 1] }, object);
|
||||
@ -81,15 +88,6 @@ describe('updeep', () => {
|
||||
expect(result).to.deep.equal({ foo: [0, 1] });
|
||||
});
|
||||
|
||||
it('can use withDefault to default things', () => {
|
||||
const object = {};
|
||||
const result = u({
|
||||
foo: u.withDefault([], { 0: 'bar' }),
|
||||
}, object);
|
||||
|
||||
expect(result).to.eql({ foo: ['bar'] });
|
||||
});
|
||||
|
||||
it('can update when original object is undefined', () => {
|
||||
const result = u({ foo: [0, 1] }, undefined);
|
||||
|
||||
@ -102,12 +100,6 @@ describe('updeep', () => {
|
||||
expect(result).to.eql(8);
|
||||
});
|
||||
|
||||
it('can omit a key', () => {
|
||||
const result = u({ foo: u.omit('bar') }, { foo: { bar: 7 } });
|
||||
|
||||
expect(result).to.eql({ foo: {} });
|
||||
});
|
||||
|
||||
it('deeply freezes the result', () => {
|
||||
const result = u({ foo: { bar: 3 } }, { foo: { bar: 0 } });
|
||||
|
||||
@ -118,12 +110,4 @@ describe('updeep', () => {
|
||||
it('assigns null values', () => {
|
||||
expect(u({isNull: null}, {})).to.eql({isNull: null});
|
||||
});
|
||||
|
||||
it('has additional functions', () => {
|
||||
expect(u.freeze).to.be.a('function');
|
||||
expect(u.if).to.be.a('function');
|
||||
expect(u.in).to.be.a('function');
|
||||
expect(u.omit).to.be.a('function');
|
||||
expect(u.withDefault).to.be.a('function');
|
||||
});
|
||||
});
|
||||
|
31
test/withDefault-spec.js
Normal file
31
test/withDefault-spec.js
Normal file
@ -0,0 +1,31 @@
|
||||
import { expect } from 'chai';
|
||||
import u from '../lib';
|
||||
|
||||
describe('u.withDefault', () => {
|
||||
it('uses the default as the basis for the update if the object is undefined', () => {
|
||||
const inc = x => x + 1;
|
||||
const result = u.withDefault({ a: 0 }, { a: inc }, undefined);
|
||||
|
||||
expect(result).to.eql({ a: 1 });
|
||||
});
|
||||
|
||||
it('uses ignores the default if the object is defined', () => {
|
||||
const inc = x => x + 1;
|
||||
const result = u.withDefault({ a: 0 }, { a: inc }, { a: 3 });
|
||||
|
||||
expect(result).to.eql({ a: 4 });
|
||||
});
|
||||
|
||||
it('can be partially applied', () => {
|
||||
const object = {};
|
||||
const result = u({
|
||||
foo: u.withDefault([], { 0: 'bar' }),
|
||||
}, object);
|
||||
|
||||
expect(result).to.eql({ foo: ['bar'] });
|
||||
});
|
||||
|
||||
it('freezes the result', () => {
|
||||
expect(Object.isFrozen(u.withDefault({}, 'a')(undefined))).to.be.true;
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user