seamless-immutable
Advanced tools
Comparing version 1.3.0 to 2.0.0
{ | ||
"name": "seamless-immutable", | ||
"version": "1.3.0", | ||
"version": "2.0.0", | ||
"description": "Immutable data structures for JavaScript which are backwards-compatible with normal JS Arrays and Objects.", | ||
@@ -5,0 +5,0 @@ "main": "seamless-immutable.js", |
@@ -193,2 +193,24 @@ seamless-immutable | ||
### Releases | ||
#### 2.0.0 | ||
Breaking API change: `#merge` now takes exactly one or exactly two arguments. The second is optional and allows specifying `deep: true`. | ||
#### 1.3.0 | ||
Don't bother returning a new value from `#merge` if no changes would result. | ||
#### 1.2.0 | ||
Make error message for invalid `#asObject` less fancy, resulting in a performance improvement. | ||
#### 1.1.0 | ||
Adds `#asMutable` | ||
#### 1.0.0 | ||
Initial stable release | ||
[1]: https://secure.travis-ci.org/rtfeldman/seamless-immutable.svg | ||
@@ -195,0 +217,0 @@ [2]: https://travis-ci.org/rtfeldman/seamless-immutable |
@@ -218,5 +218,6 @@ (function(){ | ||
* | ||
* @param {object} other - The other object to merge. Multiple objects can be passed, either as an array or as extra arguments. In such a case, the later an object appears in that list, the higher its priority. | ||
* @param {object} other - The other object to merge. Multiple objects can be passed as an array. In such a case, the later an object appears in that list, the higher its priority. | ||
* @param {object} config - Optional config object what contains settings. Right now only {deep: true} is supported for a merge deep | ||
*/ | ||
function merge(arg) { | ||
function merge(other, config) { | ||
// Calling .merge() with no arguments is a no-op. Don't bother cloning. | ||
@@ -227,5 +228,10 @@ if (arguments.length === 0) { | ||
if (other === null || (typeof other !== "object")) { | ||
throw new TypeError("Immutable#merge can only be invoked with objects or arrays, not " + JSON.stringify(other)); | ||
} | ||
var anyChanges = false, | ||
result = quickCopy(this, {}), // A shallow clone of this object. | ||
receivedArray = (arg instanceof Array), | ||
receivedArray = (other instanceof Array), | ||
deep = config && config.deep, | ||
key; | ||
@@ -245,24 +251,22 @@ | ||
result[key] = immutableValue; | ||
if (deep && currentObj[key] !== null && typeof currentObj[key] === "object" && typeof immutableValue === "object" ) { | ||
result[key] = currentObj[key].merge(immutableValue, config); | ||
} else { | ||
result[key] = immutableValue; | ||
} | ||
} | ||
// Achieve prioritization by overriding previous values that get in the way. | ||
if (!receivedArray && arguments.length === 1) { | ||
if (!receivedArray) { | ||
// The most common use case: just merge one object into the existing one. | ||
for (key in arg) { | ||
addToResult(this, arg, key); | ||
for (key in other) { | ||
addToResult(this, other, key); | ||
} | ||
} else { | ||
// We also accept either an Array or multiple arguments. | ||
var others = receivedArray ? arg : | ||
Array.prototype.slice.call(arguments); | ||
// Note: If we don't convert arguments into an Array, IE9 will end up | ||
// including the arguments object in the final result object. | ||
// Can't make this stuff up. | ||
// We also accept an Array | ||
for (var index in other) { | ||
var otherFromArray = other[index]; | ||
for (var index in others) { | ||
var other = others[index]; | ||
for (key in other) { | ||
addToResult(this, other, key); | ||
for (key in otherFromArray) { | ||
addToResult(this, otherFromArray, key); | ||
} | ||
@@ -340,2 +344,2 @@ } | ||
} | ||
})(); | ||
})(); |
@@ -11,2 +11,2 @@ var testMerge = require("./ImmutableObject/test-merge.js"); | ||
testToMutable(); | ||
}); | ||
}); |
@@ -12,5 +12,14 @@ var Immutable = require("../../seamless-immutable.js"); | ||
// Anything but an object, array, or undefined. | ||
function invalidMergeArgumentSpecifier() { | ||
return JSC.one_of([ | ||
(function() { return function() {}; }), | ||
JSC.integer(), JSC.number(), JSC.string(), | ||
true, Infinity, -Infinity | ||
]); | ||
} | ||
module.exports = function() { | ||
describe("#merge", function() { | ||
function generateMergeTestsFor(specifiers) { | ||
function generateMergeTestsFor(specifiers, config) { | ||
var runs = 100; | ||
@@ -20,10 +29,4 @@ | ||
check(runs, specifiers, function(list) { | ||
var useVarArgs = !(list instanceof Array); | ||
list = list instanceof Array ? list : [list]; | ||
if (arguments.length > 1) { | ||
list = Array.prototype.slice.call(arguments); | ||
} else if (useVarArgs) { | ||
list = [list] | ||
} | ||
assert.notStrictEqual(list.length, 0, "Can't usefully check merge() with no objects"); | ||
@@ -36,5 +39,3 @@ | ||
return useVarArgs ? | ||
immutable.merge.apply(immutable, others) : | ||
immutable.merge(others); | ||
return immutable.merge(others, config); | ||
} | ||
@@ -66,3 +67,3 @@ | ||
expectedChanges[key] = newValue; | ||
assert(Immutable.isImmutable(expectedChanges[key])) | ||
assert(Immutable.isImmutable(expectedChanges[key])); | ||
@@ -170,2 +171,30 @@ mutable[key] = newValue; | ||
it("Throws an exception if you pass it a non-object", function() { | ||
check(100, [TestUtils.ComplexObjectSpecifier(), invalidMergeArgumentSpecifier()], function(obj, nonObj) { | ||
assert.isObject(obj, 0, "Test error: this specifier should always generate an object, which " + JSON.stringify(obj) + " was not."); | ||
assert.isNotObject(nonObj, 0, "Test error: this specifier should always generate a non-object, which" + JSON.stringify(nonObj) + " was not."); | ||
var immutable = Immutable(obj); | ||
assert.throws(function() { | ||
immutable.merge(nonObj); | ||
}, TypeError) | ||
}); | ||
}); | ||
it("merges deep when the config tells it to", function() { | ||
var original = Immutable({all: "your base", are: {belong: "to us", you: {have: "x", make: "your time"}}}); | ||
var toMerge = {are: {you: {have: "no chance to survive"}}}; | ||
var expectedShallow = Immutable({all: "your base", are: {you: {have: "no chance to survive"}}}); | ||
var actualShallow = original.merge(toMerge); | ||
assert.deepEqual(actualShallow, expectedShallow); | ||
var expectedDeep = Immutable({all: "your base", are: {belong: "to us", you: {have: "no chance to survive", make: "your time"}}}); | ||
var actualDeep = original.merge(toMerge, {deep: true}); | ||
assert.deepEqual(actualDeep, expectedDeep); | ||
}); | ||
describe("when passed a single object", function() { | ||
@@ -175,4 +204,4 @@ generateMergeTestsFor([TestUtils.ComplexObjectSpecifier()]); | ||
describe("when passed multiple objects", function() { | ||
generateMergeTestsFor([TestUtils.ComplexObjectSpecifier(), TestUtils.ComplexObjectSpecifier(), TestUtils.ComplexObjectSpecifier()]); | ||
describe("when passed a single object with deep set to true", function() { | ||
generateMergeTestsFor([TestUtils.ComplexObjectSpecifier()], {deep: true}); | ||
}); | ||
@@ -183,3 +212,7 @@ | ||
}); | ||
describe("when passed an array of objects with deep set to true", function() { | ||
generateMergeTestsFor([generateArrayOfObjects], {deep: true}); | ||
}); | ||
}); | ||
}; | ||
}; |
72121
1130
220