Repository: gcanti/tcomb
Pull request #154 (2015-10-03 16:42:41)

`t.update` should not change the reference when no changes occurs
#153


Patch:
diff --git a/.eslintrc b/.eslintrc
index 151b5e9..9cbd2dd 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -8,5 +8,6 @@
     "modules": true
   },
   "rules": {
+    "semi": 1
   }
 }
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f627a6..875c7c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,11 @@
 **Note**: Gaps between patch versions are faulty/broken releases.
 **Note**: A feature tagged as Experimental is in a high state of flux, you're at risk of it changing without notice.
 
+## v2.5.1
+
+- **Internal**
+  - `t.update` should not change the reference when no changes occurs, fix #153
+
 ## v2.5.0
 
 - **New Feature**
diff --git a/index.js b/index.js
index 6e478c4..33c4f85 100644
--- a/index.js
+++ b/index.js
@@ -164,17 +164,20 @@ function update(instance, spec) {
   }
 
   var value = getShallowCopy(instance);
+  var isChanged = false;
   for (var k in spec) {
     if (spec.hasOwnProperty(k)) {
       if (update.commands.hasOwnProperty(k)) {
         return update.commands[k](spec[k], value);
       }
       else {
-        value[k] = update(value[k], spec[k]);
+        var newValue = update(value[k], spec[k]);
+        isChanged = ( newValue !== value[k] );
+        value[k] = newValue;
       }
     }
   }
-  return value;
+  return isChanged ? value : instance;
 }
 
 // built-in commands
diff --git a/package.json b/package.json
index 07dfb20..8accd5e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "tcomb",
-  "version": "2.5.0",
+  "version": "2.5.1",
   "description": "Type checking and DDD for JavaScript",
   "main": "index.js",
   "scripts": {


Test patch:
diff --git a/test/update.js b/test/update.js
index ff07d7c..f58b4c0 100644
--- a/test/update.js
+++ b/test/update.js
@@ -9,6 +9,10 @@ describe('t.update(instance, spec)', function () {
   var Tuple = t.tuple([t.String, t.Number]);
   var List = t.list(t.Number);
   var Dict = t.dict(t.String, t.Number);
+  var Point = t.struct({
+    x: t.Number,
+    y: t.Number
+  });
 
   it('should throw if spec is invalid', function () {
     throwsWithMessage(function () {
@@ -84,12 +88,20 @@ describe('t.update(instance, spec)', function () {
     assert.deepEqual(actual, [1, 3, 2, 4]);
   });
 
+  it('should not change the reference when no changes occurs', function () {
+    var p1 = {x: 0, y: 1};
+    var p2 = update(p1, {});
+    assert.strictEqual(p1, p2);
+    var p3 = update(p1, {x: {$set: 0}});
+    assert.strictEqual(p1, p3);
+
+    var n1 = {a: {b: {c: 1}}};
+    var n2 = t.update(n1, {a: {b: {c: {$set: 1}}}})
+    assert.strictEqual(n1, n2);
+  });
+
   describe('structs', function () {
 
-    var Point = t.struct({
-      x: t.Number,
-      y: t.Number
-    });
     var instance = new Point({x: 0, y: 1});
 
     it('should handle $set command', function () {
@@ -124,6 +136,14 @@ describe('t.update(instance, spec)', function () {
       assert.deepEqual(updated, {a: 1, b: {c: 5, d: 3, e: 6}});
     });
 
+    it('should not change the reference when no changes occurs', function () {
+      var p1 = new Point({x: 0, y: 1});
+      var p2 = Point.update(p1, {});
+      assert.strictEqual(p1, p2);
+      var p3 = Point.update(p1, {x: {$set: 0}});
+      assert.strictEqual(p1, p3);
+    });
+
   });
 
   describe('tuples', function () {