immutable-assign
Advanced tools
Comparing version 1.0.18 to 1.0.19
@@ -10,5 +10,2 @@ // Place your settings in this file to overwrite default and user settings. | ||
} | ||
, | ||
"typescript.check.workspaceVersion": false, | ||
"editor.wordWrap": true | ||
} |
@@ -10,3 +10,6 @@ | ||
disableHasReturnCheck: boolean; | ||
disableExtraStatementCheck: boolean; | ||
// Disable validation for extra statements in the getProp() function, | ||
// which is needed when running the coverage, e.g., istanbul.js does add | ||
// instrument statements in our getProp() function, which can be safely ignored. | ||
disableExtraStatementCheck: boolean; | ||
} | ||
@@ -13,0 +16,0 @@ |
{ | ||
"name": "immutable-assign", | ||
"version": "1.0.18", | ||
"description": "", | ||
"version": "1.0.19", | ||
"description": "Lightweight immutable helper that allows you to continue working with Plain JavaScript Objects", | ||
"main": "src/iassign.js", | ||
"types": "src/iassign.d.ts", | ||
"scripts": { | ||
"test": "node_modules\\.bin\\jasmine", | ||
"postinstall": "npm run build", | ||
"test": "node node_modules/istanbul/lib/cli.js cover node_modules/jasmine/bin/jasmine.js", | ||
"test-backup": "node node_modules/jasmine/bin/jasmine.js", | ||
"test-karma": "node_modules\\.bin\\karma start", | ||
"test-karma-mac": "node_modules\\.bin\\karma start --browsers Safari,Chrome", | ||
"cover": "node_modules\\.bin\\istanbul cover node_modules\\jasmine\\bin\\jasmine.js", | ||
"build": "gulp" | ||
"cover": "node node_modules/istanbul/lib/cli.js cover node_modules/jasmine/bin/jasmine.js", | ||
"build": "gulp", | ||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls" | ||
}, | ||
@@ -35,2 +39,3 @@ "author": { | ||
"devDependencies": { | ||
"coveralls": "^2.11.15", | ||
"deep-freeze": "0.0.1", | ||
@@ -37,0 +42,0 @@ "edge-launcher": "*", |
254
README.md
# immutable-assign (iassign.js) | ||
Lightweight immutable helper that allows you to continue working with POJO (Plain Old JavaScript Object), and supports full TypeScript type checking | ||
Lightweight immutable helper that allows you to continue working with POJO (Plain Old JavaScript Object), and supports full TypeScript type checking. | ||
[![NPM version][3]][4] [![Build Status][1]][2] [![coverage status][5]][6] | ||
This library is trying to solve following problems: | ||
@@ -14,6 +16,8 @@ | ||
This library has only one method **iassign()**, which accept a POJO object and return you a new POJO object with specific property updated. I have added some options to freeze input and output using [deep-freeze](https://github.com/substack/deep-freeze), which can be used in development to make sure they don't change unintentionally by us or the 3rd party libraries. | ||
This library is an alternative to [Immutable.js](https://facebook.github.io/immutable-js/), it has only one method **iassign()**, which accept a POJO object and return you a new POJO object with specific property updated. However, since it works with other libraries such as lodash (refer to [example 4](#example-4-work-with-3rd-party-libraries-eg-lodash)), it provides all the functionalities you need plus immutability. | ||
This library will leave your POJO objects completely untouched (except the optional deep-freeze), it does not wrap around nor add methods/properties to your POJO objects. | ||
* I have added some options to freeze input and output using [deep-freeze](https://github.com/substack/deep-freeze), which can be used in development to make sure they don't change unintentionally by us or the 3rd party libraries. | ||
This library will leave your POJO objects completely untouched (except the optional deep-freeze), it does not wrap around nor add any methods/properties to your POJO objects. | ||
This library works in JavaScript and it works really well with TypeScript, because of its [generic type argument inference](https://www.typescriptlang.org/docs/handbook/generics.html); and since you are working with POJO (not the wrapper objects), you can utilize the full power of TypeScript: IntelliSense, type checking and refactoring, etc. | ||
@@ -29,3 +33,3 @@ | ||
#### Function Signature | ||
#### Function Signature (TypeScript syntax) | ||
@@ -54,3 +58,3 @@ ```javascript | ||
####Example 1: Update nested property | ||
####Example 1: Update object | ||
@@ -63,2 +67,175 @@ ```javascript | ||
var map1 = { a:1, b:2, c:3 }; | ||
// | ||
// Calling iassign() to update map1.b | ||
// | ||
var map2 = iassign( | ||
map1, | ||
function (m) { return m; }, | ||
function (m) { m.b = 50; return m; } | ||
); | ||
// map2 = { a:1, b: 50, c:3 } | ||
// map2 !== map1 | ||
``` | ||
####Example 2: Update list/array | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var list1 = [1, 2]; | ||
// | ||
// 1. Calling iassign() to push items to list1 | ||
// | ||
var list2 = iassign( | ||
list1, | ||
function (l) { return l; }, | ||
function (l) { l.push(3, 4, 5); return l; } | ||
); | ||
// list2 = [1, 2, 3, 4, 5] | ||
// list2 !== list1 | ||
// | ||
// 2. Calling iassign() to unshift item to list2 | ||
// | ||
var list3 = iassign( | ||
list2, | ||
function (l) { return l; }, | ||
function (l) { l.unshift(0); return l; } | ||
); | ||
// list3 = [0, 1, 2, 3, 4, 5] | ||
// list3 !== list2 | ||
// | ||
// 3. Calling iassign() to concat list1, list2 and list3 | ||
// | ||
var list4 = iassign( | ||
list1, | ||
function (l) { return l; }, | ||
function (l) { return l.concat(list2, list3); } | ||
); | ||
// list4 = [1, 2, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] | ||
// list4 !== list1 | ||
``` | ||
####Example 3: Update nested structures | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var nested1 = { a:{ b:{ c:[3, 4, 5] } } }; | ||
// | ||
// Calling iassign() to assign d to nested1.a.b | ||
// | ||
var nested2 = iassign( | ||
nested1, | ||
function (n) { return n.a.b; }, | ||
function (b) { b.d = 6; return b; } | ||
); | ||
// nested2 = { a:{ b:{ c:[3, 4, 5], d: 6 } } } | ||
// nested2 !== nested1 | ||
// | ||
// Calling iassign() to increment nested2.a.b.d | ||
// | ||
var nested3 = iassign( | ||
nested2, | ||
function (n) { return n.a.b.d; }, | ||
function (d) { return d + 1; } | ||
); | ||
// nested3 = { a:{ b:{ c:[3, 4, 5], d: 7 } } } | ||
// nested3 !== nested2 | ||
// | ||
// Calling iassign() to push item to nested3.a.b.c | ||
// | ||
var nested4 = iassign( | ||
nested3, | ||
function (n) { return n.a.b.c; }, | ||
function (c) { c.push(6); return c; } | ||
); | ||
// nested4 = { a:{ b:{ c:[3, 4, 5, 6], d: 7 } } } | ||
// nested4 !== nested3 | ||
``` | ||
####Example 4: Work with 3rd party libraries, e.g., lodash | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var _ = require("lodash"); | ||
var nested1 = { a: { b: { c: [1, 2, 3] } } }; | ||
// | ||
// Calling iassign() and _.map() to increment to every item in "c" array | ||
// | ||
var nested2 = iassign( | ||
nested1, | ||
function (n) { return n.a.b.c; }, | ||
function (c) { | ||
return _.map(c, function (i) { return i + 1; }); | ||
} | ||
); | ||
// nested2 = { a: { b: { c: [2, 3, 4] } } }; | ||
// nested2 !== nested1 | ||
// | ||
// Calling iassign() and _.flatMap() | ||
// | ||
var nested3 = iassign( | ||
nested2, | ||
function (n) { return n.a.b.c; }, | ||
function (c) { | ||
return _.flatMap(c, function (i) { return [i, i]; }); | ||
} | ||
); | ||
// nested3 = { a: { b: { c: [2, 2, 3, 3, 4, 4] } } }; | ||
// nested3 !== nested2 | ||
``` | ||
####Example 5: Update list/array 2 | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var list1 = [3, 1, 4]; | ||
// | ||
// Calling iassign() to sort array | ||
// | ||
var list2 = iassign( | ||
list1, | ||
function (l) { return l; }, | ||
function (l) { return l.sort(); } | ||
); | ||
// list2 = [1, 3, 4]; | ||
// list2 !== list1 | ||
``` | ||
####Advanced example 6: Update nested property | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }]], c2: {} }, b2: {} }, a2: {} }; | ||
@@ -103,5 +280,7 @@ | ||
####Example 2: Update array | ||
####Advanced example 7: Update array | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }]], c2: {} }, b2: {} }, a2: {} }; | ||
@@ -146,46 +325,23 @@ | ||
####Example 3: Update nested property, referring to external context. | ||
####Advanced example 8: Update nested property, referring to external context. | ||
```javascript | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }]] } } }; | ||
var iassign = require("immutable-assign"); | ||
var o1 = { a: { b: { c: [{ d: 11, e: 12 }, { d: 21, e: 22 }] } } }; | ||
// | ||
// Calling iassign() to push increment to o1.a.b.c[0].d | ||
// | ||
var p1 = { a: 0 }; | ||
var external = { a: 0 }; | ||
var o2 = iassign( | ||
o1, | ||
function (o, ctx) { return o.a.b.c[ctx.p1.a][0]; }, | ||
function (o, ctx) { return o.a.b.c[ctx.external.a]; }, | ||
function (ci) { ci.d++; return ci; }, | ||
{ p1: p1 } | ||
{ external: external } | ||
); | ||
``` | ||
####Example 4: Work with 3rd party libraries, e.g., lodash | ||
```javascript | ||
var iassign = require("immutable-assign"); | ||
var _ = require("lodash"); | ||
// Deep freeze both input and output, can be used in development to make sure they don't change. | ||
iassign.freeze = true; | ||
var o1 = { a: { b: { c: [1, 2, 3] } } }; | ||
// Deep freeze both input and output, can be used in development to make sure they don't change. | ||
iassign.freeze = true; | ||
// | ||
// Calling iassign() and _.map() to increment to every item in "c" array | ||
// | ||
var o2 = iassign( | ||
o1, | ||
function (o) { return o.a.b.c; }, | ||
function (c) { | ||
return _.map(c, function (i) { return i + 1; }); | ||
} | ||
); | ||
``` | ||
```javascript | ||
// | ||
// Jasmine Tests | ||
@@ -195,6 +351,6 @@ // | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [1, 2, 3] } } }); | ||
expect(o1).toEqual({ a: { b: { c: [{ d: 11, e: 12 }, { d: 21, e: 22 }] }); | ||
// expect o2.a.b.c has been updated. | ||
expect(o2.a.b.c).toEqual([2, 3, 4]); | ||
// expect o2 inner property has been updated. | ||
expect(o2.a.b.c[external.a].d).toBe(12); | ||
@@ -207,10 +363,22 @@ // expect object graph for changed property in o2 is now different from (!==) o1. | ||
expect(o2.a.b.c[0]).not.toBe(o1.a.b.c[0]); | ||
expect(o2.a.b.c[0].d).not.toBe(o1.a.b.c[0].d); | ||
// expect object graph for unchanged property in o2 is still equal to (===) o1. | ||
expect(o2.a.b.c[0].e).toBe(o1.a.b.c[0].e); | ||
expect(o2.a.b.c[1]).toBe(o1.a.b.c[1]); | ||
expect(o2.a.b.c[1].d).toBe(o1.a.b.c[1].d); | ||
expect(o2.a.b.c[1].e).toBe(o1.a.b.c[1].e); | ||
``` | ||
##Constraints | ||
* getProp() must be a pure function; I.e., it cannot access anything other than the input parameters. e.g., it must not access "this" or "window" objects. In addition, it must not modify the input parameters. It should only return a property that needs to be updated. | ||
* getProp() currently does not support comments in the function body, you can work around this by putting comments outside of the function body. | ||
##History | ||
* 1.0.19 - Added TypeScript types to package.json | ||
* 1.0.18 - Tested on Mac (Safari 10 and Chrome 54) | ||
@@ -220,1 +388,7 @@ * 1.0.16 - Tested in Node.js and major browsers (IE 11, Chrome 52, Firefox 47, Edge 13, PhantomJS 2) | ||
[1]: https://travis-ci.org/engineforce/ImmutableAssign.svg?branch=master | ||
[2]: https://travis-ci.org/engineforce/ImmutableAssign | ||
[3]: https://badge.fury.io/js/immutable-assign.svg | ||
[4]: https://badge.fury.io/js/immutable-assign | ||
[5]: https://coveralls.io/repos/github/engineforce/ImmutableAssign/badge.svg?branch=master | ||
[6]: https://coveralls.io/github/engineforce/ImmutableAssign?branch=master |
@@ -701,3 +701,69 @@ "use strict"; | ||
}); | ||
it("Answer stackoverflow: http://stackoverflow.com/questions/40519819/how-to-make-this-piece-of-code-looks-better", function () { | ||
var state = | ||
{ | ||
sideCart: { | ||
orderItems: { | ||
1: { | ||
id: 'orderItems-1', | ||
name: 'AI Brown\'s BBQ Fillet of Beef with Brown Mushroom Brandy Sauce', | ||
quantity: 10, | ||
price: 12, | ||
subitems: ['0', '1', '2'], | ||
instruction: 'No rosemary for beef', | ||
}, | ||
2: { | ||
id: 'orderItems-2', | ||
name: 'AI Brown\'s BBQ Fillet', | ||
quantity: 10, | ||
price: 14, | ||
subitems: ['0', '1', '2'], | ||
instruction: 'No rosemary for beef', | ||
} | ||
} | ||
} | ||
}; | ||
// For validation | ||
var stateText = JSON.stringify(state); | ||
var item = {id: 1}; | ||
var newState = iassign(state, | ||
// Return the property you need to modify in you state. | ||
// This function must be pure function, therefore "item" | ||
// need to be passed in via the context parameter. | ||
function(state, context) { | ||
return state.sideCart.orderItems[context.item.id] | ||
}, | ||
// Modify selected part of your state | ||
// Don't need to be pure, therefore you can access "item" directly | ||
function(currentItem) { | ||
if (currentItem.quantity) | ||
item.quantity = currentItem.quantity + 1; | ||
else | ||
item.quantity = 1; | ||
return item; | ||
}, | ||
// Context | ||
{ | ||
item: item | ||
}); | ||
expect(newState.sideCart.orderItems[1].quantity).toBe(11); | ||
// Expect state has not changed | ||
expect(JSON.stringify(state)).toBe(stateText); | ||
// expect object graph for changed property in newState is now different from (!==) state. | ||
expect(state).not.toBe(newState); | ||
expect(state.sideCart).not.toBe(newState.sideCart); | ||
expect(state.sideCart.orderItems).not.toBe(newState.sideCart.orderItems); | ||
expect(state.sideCart.orderItems[1]).not.toBe(newState.sideCart.orderItems[1]); | ||
expect(state.sideCart.orderItems[1].quantity).not.toBe(newState.sideCart.orderItems[1].quantity); | ||
// expect object graph for unchanged property in newState is still equal to (===) state. | ||
expect(state.sideCart.orderItems[2]).toBe(newState.sideCart.orderItems[2]); | ||
}); | ||
}); | ||
}); |
@@ -238,3 +238,3 @@ "use strict"; | ||
iassign(o1, function (o) { return o.a.b.c; }, function (ci) { ci[0].push(3); return ci; }); | ||
}).toThrowError(TypeError, /Can't|writable|doesn't|support|readonly/i); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly/i); | ||
expect(function () { | ||
@@ -364,3 +364,3 @@ iassign(o1, function (o) { return o.a.b.c[0]; }, function (ci) { ci[0].d++; return ci; }); | ||
iassign(o1, function (o) { return o.a.b.c; }, function (ci) { ci[0].push(3); return ci; }); | ||
}).toThrowError(TypeError, /Can't|writable|doesn't|support|readonly/i); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly/i); | ||
expect(function () { | ||
@@ -398,3 +398,3 @@ iassign(o1, function (o) { return o.a.b.c[0]; }, function (ci) { ci[0].d++; return ci; }); | ||
o2.a.b.c[0].push(3); | ||
}).toThrowError(TypeError, /Can't|writable|doesn't|support|readonly/i); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly/i); | ||
expect(function () { | ||
@@ -401,0 +401,0 @@ o2.a.b.c[0][0].d++; |
@@ -297,3 +297,3 @@ | ||
iassign(o1, function (o) { return o.a.b.c; }, function (ci) { ci[0].push(<any>3); return ci; }); | ||
}).toThrowError(TypeError, /Can't|writable|doesn't|support|readonly/i); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly/i); | ||
@@ -481,3 +481,3 @@ expect(() => { | ||
iassign(o1, function (o) { return o.a.b.c; }, function (ci) { ci[0].push(<any>3); return ci; }); | ||
}).toThrowError(TypeError, /Can't|writable|doesn't|support|readonly/i); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly/i); | ||
@@ -528,3 +528,3 @@ expect(() => { | ||
o2.a.b.c[0].push(<any>3); | ||
}).toThrowError(TypeError, /Can't|writable|doesn't|support|readonly/i); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly/i); | ||
@@ -531,0 +531,0 @@ expect(() => { |
"use strict"; | ||
// TODO: handle comments in getProp() function. | ||
declare var define; | ||
@@ -4,0 +6,0 @@ |
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
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
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
827933
27
23764
386
18
1