immutable-assign
Advanced tools
Comparing version 1.0.30 to 1.0.31
@@ -15,2 +15,5 @@ | ||
disableExtraStatementCheck?: boolean; | ||
// Return the same object if setProp() returns its parameter (i.e., reference pointer not changed). | ||
ignoreIfNoChange?: boolean; | ||
} | ||
@@ -51,2 +54,6 @@ | ||
obj?: TObj): TObj; | ||
// In ES6, you cannot set property on imported module directly, because they are default | ||
// to readonly, in this case you need to use this method. | ||
setOption(option: IIassignOption); | ||
} | ||
@@ -53,0 +60,0 @@ } |
@@ -49,2 +49,5 @@ "use strict"; | ||
iassign.maxGetPropCacheSize = 100; | ||
iassign.setOption = function (option) { | ||
copyOption(iassign, option); | ||
}; | ||
// Immutable Assign | ||
@@ -66,3 +69,3 @@ function _iassign(obj, // Object to set property, it will not be modified. | ||
} | ||
option = copyOption(option); | ||
option = copyOption(undefined, option, iassign); | ||
if (deepFreeze && (option.freeze || option.freezeInput)) { | ||
@@ -72,4 +75,11 @@ deepFreeze(obj); | ||
if (!getProp) { | ||
var newValue = undefined; | ||
if (option.ignoreIfNoChange) { | ||
newValue = setProp(obj); | ||
if (newValue === obj) { | ||
return obj; | ||
} | ||
} | ||
obj = quickCopy(obj, option.useConstructor); | ||
obj = setProp(obj); | ||
obj = option.ignoreIfNoChange ? newValue : setProp(obj); | ||
} | ||
@@ -79,4 +89,11 @@ else { | ||
var value = getProp(obj, context); | ||
var newValue = undefined; | ||
if (option.ignoreIfNoChange) { | ||
newValue = setProp(value); | ||
if (newValue === value) { | ||
return obj; | ||
} | ||
} | ||
var getPropFuncInfo = parseGetPropFuncInfo(getProp, option); | ||
obj = updateProperty(obj, setProp, context, getPropFuncInfo, option); | ||
obj = updateProperty(obj, setProp, newValue, context, getPropFuncInfo, option); | ||
} | ||
@@ -92,41 +109,47 @@ if (deepFreeze && (option.freeze || option.freezeOutput)) { | ||
// For performance | ||
function copyOption(option) { | ||
var newOption = {}; | ||
newOption.freeze = iassign.freeze; | ||
newOption.freezeInput = iassign.freezeInput; | ||
newOption.freezeOutput = iassign.freezeOutput; | ||
newOption.useConstructor = iassign.useConstructor; | ||
newOption.disableAllCheck = iassign.disableAllCheck; | ||
newOption.disableHasReturnCheck = iassign.disableHasReturnCheck; | ||
newOption.disableExtraStatementCheck = iassign.disableExtraStatementCheck; | ||
newOption.maxGetPropCacheSize = iassign.maxGetPropCacheSize; | ||
function copyOption(target, option, defaultOption) { | ||
if (target === void 0) { target = {}; } | ||
if (defaultOption) { | ||
target.freeze = defaultOption.freeze; | ||
target.freezeInput = defaultOption.freezeInput; | ||
target.freezeOutput = defaultOption.freezeOutput; | ||
target.useConstructor = defaultOption.useConstructor; | ||
target.disableAllCheck = defaultOption.disableAllCheck; | ||
target.disableHasReturnCheck = defaultOption.disableHasReturnCheck; | ||
target.disableExtraStatementCheck = defaultOption.disableExtraStatementCheck; | ||
target.maxGetPropCacheSize = defaultOption.maxGetPropCacheSize; | ||
target.ignoreIfNoChange = defaultOption.ignoreIfNoChange; | ||
} | ||
if (option) { | ||
if (option.freeze != undefined) { | ||
newOption.freeze = option.freeze; | ||
target.freeze = option.freeze; | ||
} | ||
if (option.freezeInput != undefined) { | ||
newOption.freezeInput = option.freezeInput; | ||
target.freezeInput = option.freezeInput; | ||
} | ||
if (option.freezeOutput != undefined) { | ||
newOption.freezeOutput = option.freezeOutput; | ||
target.freezeOutput = option.freezeOutput; | ||
} | ||
if (option.useConstructor != undefined) { | ||
newOption.useConstructor = option.useConstructor; | ||
target.useConstructor = option.useConstructor; | ||
} | ||
if (option.disableAllCheck != undefined) { | ||
newOption.disableAllCheck = option.disableAllCheck; | ||
target.disableAllCheck = option.disableAllCheck; | ||
} | ||
if (option.disableHasReturnCheck != undefined) { | ||
newOption.disableHasReturnCheck = option.disableHasReturnCheck; | ||
target.disableHasReturnCheck = option.disableHasReturnCheck; | ||
} | ||
if (option.disableExtraStatementCheck != undefined) { | ||
newOption.disableExtraStatementCheck = option.disableExtraStatementCheck; | ||
target.disableExtraStatementCheck = option.disableExtraStatementCheck; | ||
} | ||
if (option.maxGetPropCacheSize != undefined) { | ||
newOption.maxGetPropCacheSize = option.maxGetPropCacheSize; | ||
target.maxGetPropCacheSize = option.maxGetPropCacheSize; | ||
} | ||
if (option.ignoreIfNoChange != undefined) { | ||
target.ignoreIfNoChange = option.ignoreIfNoChange; | ||
} | ||
} | ||
return newOption; | ||
return target; | ||
} | ||
function updateProperty(obj, setProp, context, getPropFuncInfo, option) { | ||
function updateProperty(obj, setProp, newValue, context, getPropFuncInfo, option) { | ||
var propValue = undefined; | ||
@@ -139,3 +162,3 @@ for (var propIndex = 0; propIndex < getPropFuncInfo.funcTokens.length; ++propIndex) { | ||
if (!subAccessorText) { | ||
propValue = setProp(propValue); | ||
propValue = option.ignoreIfNoChange ? newValue : setProp(propValue); | ||
} | ||
@@ -152,6 +175,7 @@ obj = propValue; | ||
if (!subAccessorText) { | ||
propValue = setProp(propValue); | ||
propValue = option.ignoreIfNoChange ? newValue : setProp(propValue); | ||
} | ||
prevPropValue[propName] = propValue; | ||
} | ||
//console.log(propValue); | ||
} | ||
@@ -283,3 +307,3 @@ return obj; | ||
function postProcessTokens(getPropFuncInfo) { | ||
var _loop_1 = function() { | ||
var _loop_1 = function () { | ||
var token = getPropFuncInfo.funcTokens[propIndex]; | ||
@@ -434,3 +458,1 @@ var propName = token.propName, propNameSource = token.propNameSource, subAccessorText = token.subAccessorText; | ||
}); | ||
//declare var iassign: IIassign; | ||
//export = iassign; |
@@ -9,11 +9,16 @@ var gulp = require('gulp'); | ||
var clientTsProject = ts.createProject('tsconfig.json'); | ||
var projectPaths = ["tsconfig.json"]; | ||
var clientTsResult = clientTsProject.src() | ||
.pipe(ts(clientTsProject)); | ||
projectPaths.forEach((projectPath) => { | ||
var clientTsProject = ts.createProject(projectPath); | ||
return merge([ | ||
clientTsResult.pipe(gulp.dest('./')), | ||
clientTsResult.dts.pipe(gulp.dest('./')) | ||
]); | ||
var clientTsResult = clientTsProject.src() | ||
.pipe(clientTsProject()); | ||
return merge([ | ||
clientTsResult.pipe(gulp.dest('./')), | ||
clientTsResult.dts.pipe(gulp.dest('./')) | ||
]); | ||
}); | ||
}); | ||
@@ -20,0 +25,0 @@ |
{ | ||
"name": "immutable-assign", | ||
"version": "1.0.30", | ||
"version": "1.0.31", | ||
"description": "Lightweight immutable helper that allows you to continue working with Plain JavaScript Objects", | ||
@@ -46,3 +46,3 @@ "main": "src/iassign.js", | ||
"gulp-less": "^3.1.0", | ||
"gulp-typescript": "^2.14.1", | ||
"gulp-typescript": "^3.1.6", | ||
"immutable": "^3.8.1", | ||
@@ -63,4 +63,5 @@ "istanbul": "^0.4.3", | ||
"timm": "^1.2.3", | ||
"typescript": "^2.3.2", | ||
"vinyl-source-stream": "^1.1.0" | ||
} | ||
} |
@@ -40,7 +40,7 @@ # immutable-assign (iassign.js) | ||
##Install with npm | ||
## Install with npm | ||
npm install immutable-assign --save | ||
#### Function Signature (TypeScript syntax) | ||
### Function Signature (TypeScript syntax) | ||
@@ -73,2 +73,6 @@ ```javascript | ||
// In ES6, you cannot set property on imported module directly, because they are default | ||
// to readonly, in this case you need to use this method. | ||
iassign.setOption(option: IIassignOption): void; | ||
// Options, can be applied globally or individually | ||
@@ -79,2 +83,3 @@ interface IIassignOption { | ||
freezeOutput?: boolean; // Deep freeze output | ||
useConstructor?: boolean; // Uses the constructor to create new instances | ||
@@ -85,7 +90,12 @@ // Disable validation for extra statements in the getProp() function, | ||
disableExtraStatementCheck?: boolean; | ||
// Return the same object if setProp() returns its parameter (i.e., reference pointer not changed). | ||
ignoreIfNoChange?: boolean; | ||
} | ||
``` | ||
####Example 1: Update object | ||
<br /> | ||
### Example 1: Update object | ||
```javascript | ||
@@ -110,4 +120,6 @@ var iassign = require("immutable-assign"); | ||
####Example 2: Update list/array | ||
<br /> | ||
### Example 2: Update list/array | ||
```javascript | ||
@@ -160,4 +172,6 @@ var iassign = require("immutable-assign"); | ||
####Example 3: Update nested structures | ||
<br /> | ||
### Example 3: Update nested structures | ||
```javascript | ||
@@ -203,4 +217,6 @@ var iassign = require("immutable-assign"); | ||
####Example 4: Work with 3rd party libraries, e.g., lodash | ||
<br /> | ||
### Example 4: Work with 3rd party libraries, e.g., lodash | ||
```javascript | ||
@@ -240,4 +256,5 @@ var iassign = require("immutable-assign"); | ||
<br /> | ||
####Advanced example 5: Update nested property | ||
### Advanced example 5: Update nested property | ||
@@ -284,4 +301,6 @@ ```javascript | ||
####Advanced example 6: Update array | ||
<br /> | ||
### Advanced example 6: Update array | ||
```javascript | ||
@@ -326,4 +345,5 @@ var iassign = require("immutable-assign"); | ||
<br /> | ||
####Advanced example 7: Update nested property, referring to external context. | ||
### Advanced example 7: Update nested property, referring to external context. | ||
@@ -372,4 +392,6 @@ ```javascript | ||
####Example 8: Update nested structures using iassign.fp() and currying | ||
<br /> | ||
### Example 8: Update nested structures using iassign.fp() and currying | ||
```javascript | ||
@@ -425,3 +447,3 @@ var iassign = require("immutable-assign"); | ||
##Constraints | ||
## Constraints | ||
@@ -432,4 +454,8 @@ * 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. | ||
##History | ||
## History | ||
* 1.0.31 - | ||
* Added ignoreIfNoChange option, which cause iassign to return the same object if setProp() returns its parameter (i.e., reference pointer not changed). | ||
* Added setOption() function to allow you set the iassign options globally in ES6 | ||
* 1.0.30 - [Support classes](https://github.com/engineforce/ImmutableAssign/issues/4) | ||
@@ -436,0 +462,0 @@ * 1.0.29 - Supported ES6 [Arrow Functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) |
"use strict"; | ||
var __extends = (this && this.__extends) || function (d, b) { | ||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
(function (root, factory) { | ||
@@ -74,2 +79,134 @@ if (typeof module === 'object' && typeof module.exports === 'object') { | ||
}); | ||
it("Access array item, need to detect change but the setProp is setting the inner property.", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
expect(function () { | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { ci.d++; return ci; }, undefined, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly|not|read-only/i); | ||
}); | ||
it("Access array item, need to detect change and no change", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
deepFreeze(o1); | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { return ci; }, undefined, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }); | ||
// expect o2 === o1, because no change in the setProp(). | ||
expect(o2).toBe(o1); | ||
}); | ||
it("Access array item, need to detect change but the setProp is setting the inner property, use setOption()", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
iassign.setOption({ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(function () { | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { ci.d++; return ci; }); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly|not|read-only/i); | ||
iassign.setOption({ | ||
ignoreIfNoChange: false, | ||
freeze: false, | ||
}); | ||
}); | ||
it("Access array item, need to detect change and no change, use setOption()", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
iassign.setOption({ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { return ci; }); | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }); | ||
// expect o2 === o1, because no change in the setProp(). | ||
expect(o2).toBe(o1); | ||
iassign.setOption({ | ||
ignoreIfNoChange: false, | ||
freeze: false, | ||
}); | ||
}); | ||
it("Access array item, need to detect change and ensure setProp() is called once", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
// No change to the root object | ||
var count = 0; | ||
var o2 = iassign(o1, function (o) { count++; return o; }, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(count).toBe(1); | ||
expect(o2).toBe(o1); | ||
// Has change to the root object | ||
var count = 0; | ||
var o2 = iassign(o1, function (o) { count++; return {}; }, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(count).toBe(1); | ||
expect(o2).not.toBe(o1); | ||
// No change to the object properties | ||
count = 0; | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { count++; return ci; }, undefined, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(count).toBe(1); | ||
expect(o2).toBe(o1); | ||
// Has change to the object properties | ||
count = 0; | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { count++; return {}; }, undefined, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(count).toBe(1); | ||
expect(o2).not.toBe(o1); | ||
// No change to the root object, used getProp() | ||
count = 0; | ||
var o2 = iassign(o1, function (o) { return o; }, function (o) { count++; return o; }, undefined, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(count).toBe(1); | ||
expect(o2).toBe(o1); | ||
// Has change to the root object, used getProp() | ||
count = 0; | ||
var o2 = iassign(o1, function (o) { return o; }, function (o) { count++; return {}; }, undefined, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(count).toBe(1); | ||
expect(o2).not.toBe(o1); | ||
}); | ||
it("Access array item, need to detect change and has change", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
deepFreeze(o1); | ||
var o2 = iassign(o1, function (o) { return o.a.b.c[0][0]; }, function (ci) { ci.d++; return ci; }, { | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
// | ||
// Jasmine Tests | ||
// | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }); | ||
// expect o2 inner property has been updated. | ||
expect(o2.a.b.c[0][0].d).toBe(12); | ||
// expect object graph for changed property in o2 is now different from (!==) o1. | ||
expect(o2).not.toBe(o1); | ||
expect(o2.a).not.toBe(o1.a); | ||
expect(o2.a.b).not.toBe(o1.a.b); | ||
expect(o2.a.b.c).not.toBe(o1.a.b.c); | ||
expect(o2.a.b.c[0]).not.toBe(o1.a.b.c[0]); | ||
expect(o2.a.b.c[0][0]).not.toBe(o1.a.b.c[0][0]); | ||
expect(o2.a.b.c[0][0].d).not.toBe(o1.a.b.c[0][0].d); | ||
// expect object graph for unchanged property in o2 is still equal to (===) o1. | ||
expect(o2.a2).toBe(o1.a2); | ||
expect(o2.a.b2).toBe(o1.a.b2); | ||
expect(o2.a.b.c2).toBe(o1.a.b.c2); | ||
expect(o2.a.b.c[0][0].e).toBe(o1.a.b.c[0][0].e); | ||
expect(o2.a.b.c[1][0]).toBe(o1.a.b.c[1][0]); | ||
expect(o2.a.b.c[2][0]).toBe(o1.a.b.c[2][0]); | ||
}); | ||
it("Access array 1", function () { | ||
@@ -594,4 +731,5 @@ var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
function ChildKlass() { | ||
_super.apply(this, arguments); | ||
this.prop = 101; | ||
var _this = _super !== null && _super.apply(this, arguments) || this; | ||
_this.prop = 101; | ||
return _this; | ||
} | ||
@@ -598,0 +736,0 @@ ChildKlass.prototype.func2 = function () { return "ChildKlass" + this.prop; }; |
@@ -86,2 +86,223 @@ | ||
it("Access array item, need to detect change but the setProp is setting the inner property.", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
expect(() => { | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { ci.d++; return ci; }, | ||
undefined, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly|not|read-only/i); | ||
}); | ||
it("Access array item, need to detect change and no change", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
deepFreeze(o1); | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { return ci; }, | ||
undefined, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }) | ||
// expect o2 === o1, because no change in the setProp(). | ||
expect(o2).toBe(o1); | ||
}); | ||
it("Access array item, need to detect change but the setProp is setting the inner property, use setOption()", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
iassign.setOption({ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
expect(() => { | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { ci.d++; return ci; } | ||
); | ||
}).toThrowError(TypeError, /Cannot|Can't|writable|doesn't|support|readonly|not|read-only/i); | ||
iassign.setOption({ | ||
ignoreIfNoChange: false, | ||
freeze: false, | ||
}); | ||
}); | ||
it("Access array item, need to detect change and no change, use setOption()", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
iassign.setOption({ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
}); | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { return ci; } | ||
); | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }) | ||
// expect o2 === o1, because no change in the setProp(). | ||
expect(o2).toBe(o1); | ||
iassign.setOption({ | ||
ignoreIfNoChange: false, | ||
freeze: false, | ||
}); | ||
}); | ||
it("Access array item, need to detect change and ensure setProp() is called once", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
// No change to the root object | ||
var count = 0; | ||
var o2 = iassign( | ||
o1, | ||
(o) => { count++; return o; }, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
expect(count).toBe(1); | ||
expect(o2).toBe(o1); | ||
// Has change to the root object | ||
var count = 0; | ||
var o2 = iassign( | ||
o1, | ||
(o) => { count++; return <any>{}; }, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
expect(count).toBe(1); | ||
expect(o2).not.toBe(o1); | ||
// No change to the object properties | ||
count = 0; | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { count++; return ci; }, | ||
undefined, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
expect(count).toBe(1); | ||
expect(o2).toBe(o1); | ||
// Has change to the object properties | ||
count = 0; | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { count++; return <any>{}; }, | ||
undefined, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
expect(count).toBe(1); | ||
expect(o2).not.toBe(o1); | ||
// No change to the root object, used getProp() | ||
count = 0; | ||
var o2 = iassign( | ||
o1, | ||
(o) => o, | ||
(o) => { count++; return o; }, | ||
undefined, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
expect(count).toBe(1); | ||
expect(o2).toBe(o1); | ||
// Has change to the root object, used getProp() | ||
count = 0; | ||
var o2 = iassign( | ||
o1, | ||
(o) => o, | ||
(o) => { count++; return <any>{}; }, | ||
undefined, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
expect(count).toBe(1); | ||
expect(o2).not.toBe(o1); | ||
}); | ||
it("Access array item, need to detect change and has change", function () { | ||
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
deepFreeze(o1); | ||
var o2 = iassign( | ||
o1, | ||
(o) => o.a.b.c[0][0], | ||
(ci) => { ci.d++; return ci; }, | ||
{ | ||
ignoreIfNoChange: true, | ||
freeze: true, | ||
} | ||
); | ||
// | ||
// Jasmine Tests | ||
// | ||
// expect o1 has not been changed | ||
expect(o1).toEqual({ a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }) | ||
// expect o2 inner property has been updated. | ||
expect(o2.a.b.c[0][0].d).toBe(12); | ||
// expect object graph for changed property in o2 is now different from (!==) o1. | ||
expect(o2).not.toBe(o1); | ||
expect(o2.a).not.toBe(o1.a); | ||
expect(o2.a.b).not.toBe(o1.a.b); | ||
expect(o2.a.b.c).not.toBe(o1.a.b.c); | ||
expect(o2.a.b.c[0]).not.toBe(o1.a.b.c[0]); | ||
expect(o2.a.b.c[0][0]).not.toBe(o1.a.b.c[0][0]); | ||
expect(o2.a.b.c[0][0].d).not.toBe(o1.a.b.c[0][0].d); | ||
// expect object graph for unchanged property in o2 is still equal to (===) o1. | ||
expect(o2.a2).toBe(o1.a2); | ||
expect(o2.a.b2).toBe(o1.a.b2); | ||
expect(o2.a.b.c2).toBe(o1.a.b.c2); | ||
expect(o2.a.b.c[0][0].e).toBe(o1.a.b.c[0][0].e); | ||
expect(o2.a.b.c[1][0]).toBe(o1.a.b.c[1][0]); | ||
expect(o2.a.b.c[2][0]).toBe(o1.a.b.c[2][0]); | ||
}); | ||
it("Access array 1", function () { | ||
@@ -877,3 +1098,3 @@ var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }], [{ d: 31, e: 32 }]], c2: {} }, b2: {} }, a2: {} }; | ||
arr: [1], | ||
obj: { prop: 1, func: function() { return "Klass" + this.prop; } }, | ||
obj: { prop: 1, func: function () { return "Klass" + this.prop; } }, | ||
inst: new Klass(), | ||
@@ -880,0 +1101,0 @@ inst2: new ChildKlass(), |
@@ -15,2 +15,5 @@ | ||
disableExtraStatementCheck?: boolean; | ||
// Return the same object if setProp() returns its parameter (i.e., reference pointer not changed). | ||
ignoreIfNoChange?: boolean; | ||
} | ||
@@ -51,2 +54,6 @@ | ||
obj?: TObj): TObj; | ||
// In ES6, you cannot set property on imported module directly, because they are default | ||
// to readonly, in this case you need to use this method. | ||
setOption(option: IIassignOption); | ||
} | ||
@@ -53,0 +60,0 @@ } |
@@ -49,2 +49,5 @@ "use strict"; | ||
iassign.maxGetPropCacheSize = 100; | ||
iassign.setOption = function (option) { | ||
copyOption(iassign, option); | ||
}; | ||
// Immutable Assign | ||
@@ -66,3 +69,3 @@ function _iassign(obj, // Object to set property, it will not be modified. | ||
} | ||
option = copyOption(option); | ||
option = copyOption(undefined, option, iassign); | ||
if (deepFreeze && (option.freeze || option.freezeInput)) { | ||
@@ -72,4 +75,11 @@ deepFreeze(obj); | ||
if (!getProp) { | ||
var newValue = undefined; | ||
if (option.ignoreIfNoChange) { | ||
newValue = setProp(obj); | ||
if (newValue === obj) { | ||
return obj; | ||
} | ||
} | ||
obj = quickCopy(obj, option.useConstructor); | ||
obj = setProp(obj); | ||
obj = option.ignoreIfNoChange ? newValue : setProp(obj); | ||
} | ||
@@ -79,4 +89,11 @@ else { | ||
var value = getProp(obj, context); | ||
var newValue = undefined; | ||
if (option.ignoreIfNoChange) { | ||
newValue = setProp(value); | ||
if (newValue === value) { | ||
return obj; | ||
} | ||
} | ||
var getPropFuncInfo = parseGetPropFuncInfo(getProp, option); | ||
obj = updateProperty(obj, setProp, context, getPropFuncInfo, option); | ||
obj = updateProperty(obj, setProp, newValue, context, getPropFuncInfo, option); | ||
} | ||
@@ -92,41 +109,47 @@ if (deepFreeze && (option.freeze || option.freezeOutput)) { | ||
// For performance | ||
function copyOption(option) { | ||
var newOption = {}; | ||
newOption.freeze = iassign.freeze; | ||
newOption.freezeInput = iassign.freezeInput; | ||
newOption.freezeOutput = iassign.freezeOutput; | ||
newOption.useConstructor = iassign.useConstructor; | ||
newOption.disableAllCheck = iassign.disableAllCheck; | ||
newOption.disableHasReturnCheck = iassign.disableHasReturnCheck; | ||
newOption.disableExtraStatementCheck = iassign.disableExtraStatementCheck; | ||
newOption.maxGetPropCacheSize = iassign.maxGetPropCacheSize; | ||
function copyOption(target, option, defaultOption) { | ||
if (target === void 0) { target = {}; } | ||
if (defaultOption) { | ||
target.freeze = defaultOption.freeze; | ||
target.freezeInput = defaultOption.freezeInput; | ||
target.freezeOutput = defaultOption.freezeOutput; | ||
target.useConstructor = defaultOption.useConstructor; | ||
target.disableAllCheck = defaultOption.disableAllCheck; | ||
target.disableHasReturnCheck = defaultOption.disableHasReturnCheck; | ||
target.disableExtraStatementCheck = defaultOption.disableExtraStatementCheck; | ||
target.maxGetPropCacheSize = defaultOption.maxGetPropCacheSize; | ||
target.ignoreIfNoChange = defaultOption.ignoreIfNoChange; | ||
} | ||
if (option) { | ||
if (option.freeze != undefined) { | ||
newOption.freeze = option.freeze; | ||
target.freeze = option.freeze; | ||
} | ||
if (option.freezeInput != undefined) { | ||
newOption.freezeInput = option.freezeInput; | ||
target.freezeInput = option.freezeInput; | ||
} | ||
if (option.freezeOutput != undefined) { | ||
newOption.freezeOutput = option.freezeOutput; | ||
target.freezeOutput = option.freezeOutput; | ||
} | ||
if (option.useConstructor != undefined) { | ||
newOption.useConstructor = option.useConstructor; | ||
target.useConstructor = option.useConstructor; | ||
} | ||
if (option.disableAllCheck != undefined) { | ||
newOption.disableAllCheck = option.disableAllCheck; | ||
target.disableAllCheck = option.disableAllCheck; | ||
} | ||
if (option.disableHasReturnCheck != undefined) { | ||
newOption.disableHasReturnCheck = option.disableHasReturnCheck; | ||
target.disableHasReturnCheck = option.disableHasReturnCheck; | ||
} | ||
if (option.disableExtraStatementCheck != undefined) { | ||
newOption.disableExtraStatementCheck = option.disableExtraStatementCheck; | ||
target.disableExtraStatementCheck = option.disableExtraStatementCheck; | ||
} | ||
if (option.maxGetPropCacheSize != undefined) { | ||
newOption.maxGetPropCacheSize = option.maxGetPropCacheSize; | ||
target.maxGetPropCacheSize = option.maxGetPropCacheSize; | ||
} | ||
if (option.ignoreIfNoChange != undefined) { | ||
target.ignoreIfNoChange = option.ignoreIfNoChange; | ||
} | ||
} | ||
return newOption; | ||
return target; | ||
} | ||
function updateProperty(obj, setProp, context, getPropFuncInfo, option) { | ||
function updateProperty(obj, setProp, newValue, context, getPropFuncInfo, option) { | ||
var propValue = undefined; | ||
@@ -139,3 +162,3 @@ for (var propIndex = 0; propIndex < getPropFuncInfo.funcTokens.length; ++propIndex) { | ||
if (!subAccessorText) { | ||
propValue = setProp(propValue); | ||
propValue = option.ignoreIfNoChange ? newValue : setProp(propValue); | ||
} | ||
@@ -152,6 +175,7 @@ obj = propValue; | ||
if (!subAccessorText) { | ||
propValue = setProp(propValue); | ||
propValue = option.ignoreIfNoChange ? newValue : setProp(propValue); | ||
} | ||
prevPropValue[propName] = propValue; | ||
} | ||
//console.log(propValue); | ||
} | ||
@@ -283,3 +307,3 @@ return obj; | ||
function postProcessTokens(getPropFuncInfo) { | ||
var _loop_1 = function() { | ||
var _loop_1 = function () { | ||
var token = getPropFuncInfo.funcTokens[propIndex]; | ||
@@ -434,3 +458,1 @@ var propName = token.propName, propNameSource = token.propNameSource, subAccessorText = token.subAccessorText; | ||
}); | ||
//declare var iassign: IIassign; | ||
//export = iassign; |
@@ -21,2 +21,5 @@ "use strict"; | ||
maxGetPropCacheSize?: number; | ||
// Return the same object if setProp() returns its parameter (i.e., reference pointer not changed). | ||
ignoreIfNoChange?: boolean; | ||
} | ||
@@ -57,2 +60,6 @@ | ||
obj?: TObj): TObj; | ||
// In ES6, you cannot set property on imported module directly, because they are default | ||
// to readonly, in this case you need to use this method. | ||
setOption(option: IIassignOption); | ||
} | ||
@@ -112,2 +119,6 @@ | ||
iassign.setOption = function (option) { | ||
copyOption(iassign, option); | ||
} | ||
// Immutable Assign | ||
@@ -133,3 +144,3 @@ function _iassign<TObj, TProp, TContext>( | ||
option = copyOption(option); | ||
option = copyOption(undefined, option, iassign); | ||
@@ -141,4 +152,13 @@ if (deepFreeze && (option.freeze || option.freezeInput)) { | ||
if (!getProp) { | ||
let newValue = undefined; | ||
if (option.ignoreIfNoChange) { | ||
newValue = setProp(<any>obj); | ||
if (<any>newValue === <any>obj) { | ||
return obj; | ||
} | ||
} | ||
obj = quickCopy(obj, option.useConstructor); | ||
obj = <any>setProp(<any>obj); | ||
obj = option.ignoreIfNoChange ? newValue : <any>setProp(<any>obj); | ||
} | ||
@@ -149,5 +169,13 @@ else { | ||
let newValue = undefined; | ||
if (option.ignoreIfNoChange) { | ||
newValue = setProp(value); | ||
if (newValue === value) { | ||
return obj; | ||
} | ||
} | ||
let getPropFuncInfo = parseGetPropFuncInfo(getProp, option); | ||
obj = updateProperty(obj, setProp, context, getPropFuncInfo, option); | ||
obj = updateProperty(obj, setProp, newValue, context, getPropFuncInfo, option); | ||
} | ||
@@ -174,26 +202,29 @@ | ||
// For performance | ||
function copyOption(option) { | ||
let newOption: IIassign = <any>{}; | ||
function copyOption(target: IIassignOption = {}, option: IIassignOption, defaultOption?: IIassignOption) { | ||
newOption.freeze = iassign.freeze; | ||
newOption.freezeInput = iassign.freezeInput; | ||
newOption.freezeOutput = iassign.freezeOutput; | ||
newOption.useConstructor = iassign.useConstructor; | ||
newOption.disableAllCheck = iassign.disableAllCheck; | ||
newOption.disableHasReturnCheck = iassign.disableHasReturnCheck; | ||
newOption.disableExtraStatementCheck = iassign.disableExtraStatementCheck; | ||
newOption.maxGetPropCacheSize = iassign.maxGetPropCacheSize; | ||
if (defaultOption) { | ||
target.freeze = defaultOption.freeze; | ||
target.freezeInput = defaultOption.freezeInput; | ||
target.freezeOutput = defaultOption.freezeOutput; | ||
target.useConstructor = defaultOption.useConstructor; | ||
target.disableAllCheck = defaultOption.disableAllCheck; | ||
target.disableHasReturnCheck = defaultOption.disableHasReturnCheck; | ||
target.disableExtraStatementCheck = defaultOption.disableExtraStatementCheck; | ||
target.maxGetPropCacheSize = defaultOption.maxGetPropCacheSize; | ||
target.ignoreIfNoChange = defaultOption.ignoreIfNoChange; | ||
} | ||
if (option) { | ||
if (option.freeze != undefined) { newOption.freeze = option.freeze; } | ||
if (option.freezeInput != undefined) { newOption.freezeInput = option.freezeInput; } | ||
if (option.freezeOutput != undefined) { newOption.freezeOutput = option.freezeOutput; } | ||
if (option.useConstructor != undefined) { newOption.useConstructor = option.useConstructor; } | ||
if (option.disableAllCheck != undefined) { newOption.disableAllCheck = option.disableAllCheck; } | ||
if (option.disableHasReturnCheck != undefined) { newOption.disableHasReturnCheck = option.disableHasReturnCheck; } | ||
if (option.disableExtraStatementCheck != undefined) { newOption.disableExtraStatementCheck = option.disableExtraStatementCheck; } | ||
if (option.maxGetPropCacheSize != undefined) { newOption.maxGetPropCacheSize = option.maxGetPropCacheSize; } | ||
if (option.freeze != undefined) { target.freeze = option.freeze; } | ||
if (option.freezeInput != undefined) { target.freezeInput = option.freezeInput; } | ||
if (option.freezeOutput != undefined) { target.freezeOutput = option.freezeOutput; } | ||
if (option.useConstructor != undefined) { target.useConstructor = option.useConstructor; } | ||
if (option.disableAllCheck != undefined) { target.disableAllCheck = option.disableAllCheck; } | ||
if (option.disableHasReturnCheck != undefined) { target.disableHasReturnCheck = option.disableHasReturnCheck; } | ||
if (option.disableExtraStatementCheck != undefined) { target.disableExtraStatementCheck = option.disableExtraStatementCheck; } | ||
if (option.maxGetPropCacheSize != undefined) { target.maxGetPropCacheSize = option.maxGetPropCacheSize; } | ||
if (option.ignoreIfNoChange != undefined) { target.ignoreIfNoChange = option.ignoreIfNoChange; } | ||
} | ||
return newOption; | ||
return target; | ||
} | ||
@@ -204,4 +235,5 @@ | ||
setProp: setPropFunc<TProp>, | ||
newValue: TProp, | ||
context: TContext, | ||
getPropFuncInfo: IGetPropFuncInfo, | ||
getPropFuncInfo: IGetPropFuncInfo, | ||
option: IIassignOption): TObj { | ||
@@ -212,3 +244,3 @@ | ||
for (var propIndex = 0; propIndex < getPropFuncInfo.funcTokens.length; ++propIndex) { | ||
let {propName, propNameSource, subAccessorText, getPropName} = getPropFuncInfo.funcTokens[propIndex]; | ||
let { propName, propNameSource, subAccessorText, getPropName } = getPropFuncInfo.funcTokens[propIndex]; | ||
@@ -221,3 +253,3 @@ //console.log(propName); | ||
if (!subAccessorText) { | ||
propValue = setProp(propValue); | ||
propValue = option.ignoreIfNoChange ? newValue : setProp(propValue); | ||
} | ||
@@ -237,3 +269,3 @@ | ||
if (!subAccessorText) { | ||
propValue = setProp(propValue); | ||
propValue = option.ignoreIfNoChange ? newValue : setProp(propValue); | ||
} | ||
@@ -417,3 +449,3 @@ | ||
let token = getPropFuncInfo.funcTokens[propIndex]; | ||
let {propName, propNameSource, subAccessorText} = token; | ||
let { propName, propNameSource, subAccessorText } = token; | ||
@@ -525,4 +557,3 @@ if (propNameSource == ePropNameSource.inBracket && isNaN(<any>propName)) { | ||
else if (typeof (value) === "object") { | ||
if (useConstructor) | ||
{ | ||
if (useConstructor) { | ||
const target = new (value as any).constructor(); | ||
@@ -529,0 +560,0 @@ return extend(target, value); |
@@ -5,2 +5,3 @@ { | ||
"module": "commonjs", | ||
"removeComments": false, | ||
"jsx": "preserve" /*, | ||
@@ -7,0 +8,0 @@ "declaration": true */ |
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
993778
26164
468
25