object-path-immutable
Advanced tools
Comparing version 0.5.0 to 0.5.1
170
index.js
@@ -1,63 +0,65 @@ | ||
(function (root, factory){ | ||
'use strict'; | ||
/*istanbul ignore next:cant test*/ | ||
/* globals define */ | ||
(function (root, factory) { | ||
'use strict' | ||
/* istanbul ignore next:cant test */ | ||
if (typeof module === 'object' && typeof module.exports === 'object') { | ||
module.exports = factory(); | ||
module.exports = factory() | ||
} else if (typeof define === 'function' && define.amd) { | ||
// AMD. Register as an anonymous module. | ||
define([], factory); | ||
define([], factory) | ||
} else { | ||
// Browser globals | ||
root.objectPath = factory(); | ||
root.objectPath = factory() | ||
} | ||
})(this, function(){ | ||
'use strict'; | ||
})(this, function () { | ||
'use strict' | ||
var _hasOwnProperty = Object.prototype.hasOwnProperty | ||
function isEmpty(value){ | ||
function isEmpty (value) { | ||
if (!value) { | ||
return true; | ||
return true | ||
} | ||
if (isArray(value) && value.length === 0) { | ||
return true; | ||
return true | ||
} else if (!isString(value)) { | ||
for (var i in value) { | ||
if (_hasOwnProperty.call(value, i)) { | ||
return false; | ||
return false | ||
} | ||
} | ||
return true; | ||
return true | ||
} | ||
return false; | ||
return false | ||
} | ||
function isNumber(value){ | ||
return typeof value === 'number'; | ||
function isNumber (value) { | ||
return typeof value === 'number' | ||
} | ||
function isString(obj){ | ||
return typeof obj === 'string'; | ||
function isString (obj) { | ||
return typeof obj === 'string' | ||
} | ||
function isArray(obj){ | ||
function isArray (obj) { | ||
return Array.isArray(obj) | ||
} | ||
function getKey(key){ | ||
var intKey = parseInt(key); | ||
function getKey (key) { | ||
var intKey = parseInt(key) | ||
if (intKey.toString() === key) { | ||
return intKey; | ||
return intKey | ||
} | ||
return key; | ||
return key | ||
} | ||
var objectPathImmutable = function(src) { | ||
var objectPathImmutable = function (src) { | ||
var dest = src | ||
var committed = false | ||
var transaction = Object.keys(api).reduce(function(proxy, prop) { | ||
/*istanbul ignore else*/ | ||
var transaction = Object.keys(api).reduce(function (proxy, prop) { | ||
/* istanbul ignore else */ | ||
if (typeof api[prop] === 'function') { | ||
proxy[prop] = function() { | ||
proxy[prop] = function () { | ||
var args = [dest, src].concat(Array.prototype.slice.call(arguments)) | ||
@@ -74,41 +76,40 @@ | ||
} | ||
return proxy; | ||
return proxy | ||
}, {}) | ||
transaction.value = function() { | ||
transaction.value = function () { | ||
committed = true | ||
return dest | ||
} | ||
return transaction | ||
}; | ||
function clone(obj, createIfEmpty, assumeArray) { | ||
if(obj == null) { | ||
if(createIfEmpty) { | ||
if(assumeArray) { | ||
} | ||
function clone (obj, createIfEmpty, assumeArray) { | ||
if (obj == null) { | ||
if (createIfEmpty) { | ||
if (assumeArray) { | ||
return [] | ||
} | ||
return {} | ||
} | ||
return obj | ||
} else if(isArray(obj)) { | ||
} else if (isArray(obj)) { | ||
return obj.slice() | ||
} | ||
var res = {} | ||
for(var key in obj) { | ||
if(obj.hasOwnProperty(key)) { | ||
for (var key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
res[key] = obj[key] | ||
} | ||
} | ||
return res | ||
} | ||
function changeImmutable(dest, src, path, changeCallback) { | ||
function changeImmutable (dest, src, path, changeCallback) { | ||
if (isNumber(path)) { | ||
@@ -118,6 +119,6 @@ path = [path] | ||
if (isEmpty(path)) { | ||
return src; | ||
return src | ||
} | ||
if (isString(path)) { | ||
return changeImmutable(dest, src, path.split('.').map(getKey), changeCallback); | ||
return changeImmutable(dest, src, path.split('.').map(getKey), changeCallback) | ||
} | ||
@@ -133,3 +134,3 @@ var currentPath = path[0] | ||
} | ||
if (src != null) { | ||
@@ -143,6 +144,6 @@ src = src[currentPath] | ||
} | ||
var api = {} | ||
api.set = function set(dest, src, path, value) { | ||
return changeImmutable(dest, src, path, function(clonedObj, finalPath) { | ||
api.set = function set (dest, src, path, value) { | ||
return changeImmutable(dest, src, path, function (clonedObj, finalPath) { | ||
clonedObj[finalPath] = value | ||
@@ -153,5 +154,5 @@ return clonedObj | ||
api.push = function push(dest, src, path /*, values */) { | ||
api.push = function push (dest, src, path /*, values */) { | ||
var values = Array.prototype.slice.call(arguments, 3) | ||
return changeImmutable(dest, src, path, function(clonedObj, finalPath) { | ||
return changeImmutable(dest, src, path, function (clonedObj, finalPath) { | ||
if (!isArray(clonedObj[finalPath])) { | ||
@@ -166,12 +167,13 @@ clonedObj[finalPath] = values | ||
api.insert = function insert(dest, src, path, value, at) { | ||
at = ~~at; | ||
return changeImmutable(dest, src, path, function(clonedObj, finalPath) { | ||
var arr = clonedObj[finalPath]; | ||
api.insert = function insert (dest, src, path, value, at) { | ||
at = ~~at | ||
return changeImmutable(dest, src, path, function (clonedObj, finalPath) { | ||
var arr = clonedObj[finalPath] | ||
if (!isArray(arr)) { | ||
if (arr != null && typeof arr !== 'undefined') | ||
throw new Error('Expected ' + path + 'to be an array. Instead got ' + typeof path); | ||
arr = []; | ||
if (arr != null && typeof arr !== 'undefined') { | ||
throw new Error('Expected ' + path + 'to be an array. Instead got ' + typeof path) | ||
} | ||
arr = [] | ||
} | ||
var first = arr.slice(0, at) | ||
@@ -183,11 +185,11 @@ first.push(value) | ||
} | ||
api.del = function del(dest, src, path, value, at){ | ||
return changeImmutable(dest, src, path, function(clonedObj, finalPath) { | ||
if(Array.isArray(clonedObj)) { | ||
if(clonedObj[finalPath]) { | ||
api.del = function del (dest, src, path, value, at) { | ||
return changeImmutable(dest, src, path, function (clonedObj, finalPath) { | ||
if (Array.isArray(clonedObj)) { | ||
if (clonedObj[finalPath] !== undefined) { | ||
clonedObj.splice(finalPath, 1) | ||
} | ||
} else { | ||
if(clonedObj.hasOwnProperty(finalPath)) { | ||
if (clonedObj.hasOwnProperty(finalPath)) { | ||
delete clonedObj[finalPath] | ||
@@ -200,5 +202,5 @@ } | ||
api.assign = function assign(dest, src, path, source) { | ||
return changeImmutable(dest, src, path, function(clonedObj, finalPath) { | ||
source = Object(source); | ||
api.assign = function assign (dest, src, path, source) { | ||
return changeImmutable(dest, src, path, function (clonedObj, finalPath) { | ||
source = Object(source) | ||
var target = clone(clonedObj[finalPath], true) | ||
@@ -216,8 +218,8 @@ | ||
} | ||
return Object.keys(api).reduce(function(objectPathImmutable, method) { | ||
objectPathImmutable[method] = api[method].bind(null, null); | ||
return objectPathImmutable; | ||
return Object.keys(api).reduce(function (objectPathImmutable, method) { | ||
objectPathImmutable[method] = api[method].bind(null, null) | ||
return objectPathImmutable | ||
}, objectPathImmutable) | ||
}) |
{ | ||
"name": "object-path-immutable", | ||
"version": "0.5.0", | ||
"version": "0.5.1", | ||
"description": "Modify deep object properties without modifying the original object (immutability). Works great with React and Redux.", | ||
@@ -15,11 +15,14 @@ "author": "Mario Casciaro <mariocasciaro@gmail.com>", | ||
"scripts": { | ||
"test": "istanbul cover ./node_modules/mocha/bin/_mocha test.js --report html -- -R spec" | ||
"pretest": "standard", | ||
"test": "istanbul cover _mocha test.js --report html -- -R spec", | ||
"prepublish": "npm run test" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"chai": "^3.4.1", | ||
"coveralls": "^2.11.4", | ||
"istanbul": "^0.4.1", | ||
"mocha": "^2.3.4", | ||
"mocha-lcov-reporter": "^1.0.0" | ||
"chai": "^3.5.0", | ||
"coveralls": "^2.11.14", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^3.1.1", | ||
"mocha-lcov-reporter": "^1.2.0", | ||
"standard": "^8.3.0" | ||
}, | ||
@@ -26,0 +29,0 @@ "keywords": [ |
@@ -134,3 +134,3 @@ object-path-immutable | ||
//Chaining mode. value() at the end of the chain is used to retrieve the resulting object | ||
var newObj = immutable(obj).set(obj, 'a.b', 'f').del(obj, 'a.c.0').value() | ||
var newObj = immutable(obj).set('a.b', 'f').del('a.c.0').value() | ||
@@ -137,0 +137,0 @@ ``` |
240
test.js
@@ -1,8 +0,10 @@ | ||
'use strict'; | ||
/* globals describe, it */ | ||
'use strict' | ||
var expect = require('chai').expect | ||
var op = require('./index.js') | ||
describe('set', function() { | ||
it('should set a deep key without modifying the original object', function() { | ||
describe('set', function () { | ||
it('should set a deep key without modifying the original object', function () { | ||
var obj = { | ||
@@ -16,16 +18,15 @@ a: { | ||
} | ||
var newObj = op.set(obj, 'a.b', 3) | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(obj.a).to.be.eql({b: 1}) | ||
//this should be the same | ||
// this should be the same | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a.b).to.be.equal(3) | ||
}) | ||
it('should set a deep array', function() { | ||
it('should set a deep array', function () { | ||
var obj = { | ||
@@ -39,5 +40,5 @@ a: { | ||
} | ||
var newObj = op.set(obj, 'a.b.1', 4) | ||
expect(newObj).not.to.be.equal(obj) | ||
@@ -47,7 +48,7 @@ expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a.b).to.be.eql([1, 4, 3]) | ||
}) | ||
it('should create intermediate objects and array', function() { | ||
it('should create intermediate objects and array', function () { | ||
var obj = { | ||
@@ -59,13 +60,13 @@ a: {}, | ||
} | ||
var newObj = op.set(obj, 'a.b.1.f', 'a') | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(obj.a).to.be.eql({}) | ||
expect(newObj.a).to.be.eql({b: [, {f: 'a'}]}) | ||
expect(newObj.a).to.be.eql({b: [, {f: 'a'}]}) // eslint-disable-line no-sparse-arrays | ||
}) | ||
it('should return the original object if passed an empty path', function() { | ||
var obj = {}; | ||
it('should return the original object if passed an empty path', function () { | ||
var obj = {} | ||
@@ -75,3 +76,3 @@ expect(op.set(obj, '', 'yo')).to.be.equal(obj) | ||
it('should set at a numeric path', function() { | ||
it('should set at a numeric path', function () { | ||
expect(op.set([], 0, 'yo')).to.deep.equal(['yo']) | ||
@@ -81,4 +82,4 @@ }) | ||
describe('insert', function(){ | ||
it('should insert value into existing array without modifying the object', function(){ | ||
describe('insert', function () { | ||
it('should insert value into existing array without modifying the object', function () { | ||
var obj = { | ||
@@ -88,13 +89,13 @@ a: ['a'], | ||
} | ||
var newObj = op.insert(obj, 'a', 'b', 0) | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a).to.be.eql(['b', 'a']) | ||
}); | ||
}) | ||
it('should create intermediary array', function(){ | ||
it('should create intermediary array', function () { | ||
var obj = { | ||
@@ -104,22 +105,22 @@ a: [], | ||
} | ||
var newObj = op.insert(obj, 'a.0.1', 'b') | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a).to.be.eql([[, ['b']]]) | ||
expect(newObj.a).to.be.eql([[, ['b']]]) // eslint-disable-line no-sparse-arrays | ||
}) | ||
it('should insert in another index', function(){ | ||
it('should insert in another index', function () { | ||
var obj = { | ||
a: 'b', | ||
b: { | ||
c: [], | ||
d: ['a', 'b'], | ||
e: [{},{f: 'g'}], | ||
f: 'i' | ||
a: 'b', | ||
b: { | ||
c: [], | ||
d: ['a', 'b'], | ||
e: [{}, {f: 'g'}], | ||
f: 'i' | ||
} | ||
} | ||
} | ||
@@ -130,14 +131,14 @@ var newObj = op.insert(obj, 'b.d', 'asdf', 1) | ||
expect(newObj.b.d).to.be.eql(['a', 'asdf', 'b']) | ||
}); | ||
}) | ||
it('should handle sparse array', function(){ | ||
it('should handle sparse array', function () { | ||
var obj = { | ||
a: 'b', | ||
b: { | ||
c: [], | ||
d: ['a', 'b'], | ||
e: [{},{f: 'g'}], | ||
f: 'i' | ||
a: 'b', | ||
b: { | ||
c: [], | ||
d: ['a', 'b'], | ||
e: [{}, {f: 'g'}], | ||
f: 'i' | ||
} | ||
} | ||
} | ||
obj.b.d = new Array(4) | ||
@@ -149,20 +150,14 @@ obj.b.d[0] = 'a' | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.b.d).to.be.eql([ | ||
'a', | ||
'b', | ||
, | ||
'asdf' | ||
, | ||
]) | ||
expect(newObj.b.d).to.be.eql(['a', 'b', , 'asdf']) // eslint-disable-line no-sparse-arrays | ||
}) | ||
it('should throw if asked to insert into something other than an array', | ||
function(){ | ||
expect(function(){ | ||
op.insert({ foo: 'bar' }, 'foo', 'baz'); | ||
}).to.throw(); | ||
function () { | ||
expect(function () { | ||
op.insert({ foo: 'bar' }, 'foo', 'baz') | ||
}).to.throw() | ||
}) | ||
it('should return the original object if passed an empty path', function() { | ||
var obj = {}; | ||
it('should return the original object if passed an empty path', function () { | ||
var obj = {} | ||
@@ -172,3 +167,3 @@ expect(op.insert(obj, '')).to.be.equal(obj) | ||
it('should insert at a numeric path', function() { | ||
it('should insert at a numeric path', function () { | ||
expect(op.insert([[23, 42]], 0, 'yo', 1)).to.deep.equal([[23, 'yo', 42]]) | ||
@@ -178,4 +173,4 @@ }) | ||
describe('push', function() { | ||
it('should push values without modifying the object', function() { | ||
describe('push', function () { | ||
it('should push values without modifying the object', function () { | ||
var obj = { | ||
@@ -185,13 +180,13 @@ a: ['a'], | ||
} | ||
var newObj = op.push(obj, 'a', 'b') | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a).to.be.eql(['a', 'b']) | ||
}) | ||
it('should create intermediate objects/arrays', function() { | ||
it('should create intermediate objects/arrays', function () { | ||
var obj = { | ||
@@ -201,14 +196,14 @@ a: [], | ||
} | ||
var newObj = op.push(obj, 'a.0.1', 'b') | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a).to.be.eql([[, ['b']]]) | ||
expect(newObj.a).to.be.eql([[, ['b']]]) // eslint-disable-line no-sparse-arrays | ||
}) | ||
it('should return the original object if passed an empty path', function() { | ||
var obj = {}; | ||
it('should return the original object if passed an empty path', function () { | ||
var obj = {} | ||
@@ -218,3 +213,3 @@ expect(op.push(obj, '', 'yo')).to.be.equal(obj) | ||
it('should push at a numeric path', function() { | ||
it('should push at a numeric path', function () { | ||
expect(op.insert([[]], 0, 'yo')).to.deep.equal([['yo']]) | ||
@@ -224,4 +219,4 @@ }) | ||
describe('del', function() { | ||
it('should delete deep values without modifying the object', function() { | ||
describe('del', function () { | ||
it('should delete deep values without modifying the object', function () { | ||
var obj = { | ||
@@ -234,14 +229,13 @@ a: { | ||
} | ||
var newObj = op.del(obj, 'a.d') | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a).to.be.eql({f: 2}) | ||
}) | ||
it('should delete deep values in array without modifying the object', function() { | ||
it('should delete deep values in array without modifying the object', function () { | ||
var obj = { | ||
@@ -251,14 +245,14 @@ a: ['a'], | ||
} | ||
var newObj = op.del(obj, 'a.0') | ||
expect(newObj).not.to.be.equal(obj) | ||
expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a).to.be.eql([]) | ||
}) | ||
it('should return the original object if passed an empty path', function() { | ||
var obj = {}; | ||
it('should return the original object if passed an empty path', function () { | ||
var obj = {} | ||
@@ -268,9 +262,13 @@ expect(op.del(obj, '')).to.be.equal(obj) | ||
it('should del at a numeric path', function() { | ||
it('should del at a numeric path', function () { | ||
expect(op.del([23, 'yo', 42], 1)).to.deep.equal([23, 42]) | ||
}) | ||
it('should delete falsy value', function () { | ||
expect(op.del(['', false], 1)).to.deep.equal(['']) | ||
}) | ||
}) | ||
describe('assign', function() { | ||
it('should assign an object without modifying the original object', function() { | ||
describe('assign', function () { | ||
it('should assign an object without modifying the original object', function () { | ||
var obj = { | ||
@@ -284,5 +282,5 @@ a: { | ||
} | ||
var newObj = op.assign(obj, 'a', { b: 3 }) | ||
expect(newObj).not.to.be.equal(obj) | ||
@@ -292,7 +290,7 @@ expect(newObj.a).not.to.be.equal(obj.a) | ||
expect(newObj.c).to.be.equal(obj.c) | ||
expect(newObj.a.b).to.be.equal(3) | ||
}) | ||
it('should keep existing fields that are not overwritten', function() { | ||
it('should keep existing fields that are not overwritten', function () { | ||
var obj = { | ||
@@ -303,5 +301,5 @@ a: { | ||
} | ||
var newObj = op.assign(obj, 'a', { c: 2 }) | ||
expect(newObj).not.to.be.equal(obj) | ||
@@ -312,4 +310,4 @@ expect(newObj.a).not.to.be.equal(obj.a) | ||
}) | ||
it('should create intermediate objects', function() { | ||
it('should create intermediate objects', function () { | ||
var obj = { | ||
@@ -321,5 +319,5 @@ a: {}, | ||
} | ||
var newObj = op.assign(obj, 'a.b', { f: 'a' }) | ||
expect(newObj).not.to.be.equal(obj) | ||
@@ -331,4 +329,4 @@ expect(newObj.a).not.to.be.equal(obj.a) | ||
it('should return the original object if passed an empty path', function() { | ||
var obj = {}; | ||
it('should return the original object if passed an empty path', function () { | ||
var obj = {} | ||
@@ -338,3 +336,3 @@ expect(op.assign(obj, '', {})).to.be.equal(obj) | ||
it('should assign at a numeric path', function() { | ||
it('should assign at a numeric path', function () { | ||
expect(op.assign([{ | ||
@@ -351,3 +349,3 @@ foo: 'bar' | ||
it('does not assign inherited properties', function() { | ||
it('does not assign inherited properties', function () { | ||
var base = { | ||
@@ -372,5 +370,4 @@ fiz: 'biz' | ||
describe('bind', function() { | ||
it('should execute all methods on the bound object', function() { | ||
describe('bind', function () { | ||
it('should execute all methods on the bound object', function () { | ||
var obj = { | ||
@@ -393,4 +390,4 @@ a: { | ||
it('should return the bound object if no operations made', function() { | ||
var obj = {}; | ||
it('should return the bound object if no operations made', function () { | ||
var obj = {} | ||
@@ -400,3 +397,3 @@ expect(op(obj).value()).to.be.equal(obj) | ||
it('should throw if an operation is attempted after `value` called', function (){ | ||
it('should throw if an operation is attempted after `value` called', function () { | ||
var transaction = op({ | ||
@@ -406,23 +403,23 @@ foo: 'bar', | ||
frob: {} | ||
}); | ||
}) | ||
transaction.value(); | ||
transaction.value() | ||
expect(function (){ | ||
expect(function () { | ||
transaction.set('foo', 'baz') | ||
}).to.throw() | ||
expect(function (){ | ||
expect(function () { | ||
transaction.push('fiz', 'biz') | ||
}).to.throw() | ||
expect(function (){ | ||
expect(function () { | ||
transaction.insert('fiz', 'biz', 23) | ||
}).to.throw() | ||
expect(function (){ | ||
expect(function () { | ||
transaction.del('foo') | ||
}).to.throw() | ||
expect(function (){ | ||
expect(function () { | ||
transaction.assign('frob', { | ||
@@ -434,2 +431,1 @@ nard: 23 | ||
}) | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19853
6