can-reflect
Advanced tools
Comparing version 1.16.5 to 1.16.6
{ | ||
"name": "can-reflect", | ||
"version": "1.16.5", | ||
"version": "1.16.6", | ||
"description": "reflection on unknown data types", | ||
@@ -5,0 +5,0 @@ "homepage": "http://canjs.com", |
@@ -439,4 +439,36 @@ var QUnit = require('steal-qunit'); | ||
QUnit.test("Correctly serializes after throwing for circular reference", function(){ | ||
function SimpleType(){} | ||
var a = new SimpleType(); | ||
var b = new SimpleType(); | ||
a.b = b; | ||
b.a = a; | ||
getSetReflections.setKeyValue(a, canSymbol.for("can.serialize"), function(){ | ||
return { | ||
b: shapeReflections.serialize(this.b) | ||
}; | ||
}); | ||
getSetReflections.setKeyValue(b, canSymbol.for("can.serialize"), function(){ | ||
return { | ||
a: shapeReflections.serialize(this.a) | ||
}; | ||
}); | ||
try{ | ||
shapeReflections.serialize(a, window.Map); | ||
QUnit.ok(false); | ||
}catch(e){ | ||
QUnit.ok(true); | ||
a = [1,2]; | ||
shapeReflections.serialize(a, window.Map); | ||
b = a; | ||
b.shift(); | ||
var s = shapeReflections.serialize(b, window.Map); | ||
QUnit.equal(s.length, 1, "there is one item"); | ||
QUnit.equal(s[0], 2, "correct item"); | ||
} | ||
}); | ||
QUnit.test("updateDeep basics", function(){ | ||
@@ -443,0 +475,0 @@ |
@@ -92,4 +92,2 @@ var canSymbol = require("can-symbol"); | ||
var serializeMap = null; | ||
var hasUpdateSymbol = helpers.makeGetFirstSymbolValue(["can.updateDeep","can.assignDeep","can.setKeyValue"]); | ||
@@ -127,5 +125,44 @@ var shouldUpdateOrAssign = function(obj){ | ||
function makeSerializer(methodName, symbolsToCheck){ | ||
// A local variable that is shared with all operations that occur withing a single | ||
// outer call to serialize() | ||
var serializeMap = null; | ||
// Holds the value of running serialize(), preserving the same map for all | ||
// internal instances. | ||
function SerializeOperation(MapType) { | ||
this.first = !serializeMap; | ||
if(this.first) { | ||
serializeMap = createSerializeMap(MapType); | ||
} | ||
this.map = serializeMap; | ||
this.result = null; | ||
} | ||
SerializeOperation.prototype.end = function(){ | ||
// If this is the first, outer call, clean up the serializeMap. | ||
if(this.first) { | ||
serializeMap = null; | ||
} | ||
return this.result; | ||
}; | ||
function createSerializeMap(Type) { | ||
var MapType = Type || ArrayMap; | ||
return { | ||
unwrap: new MapType(), | ||
serialize: new MapType() , | ||
isSerializing: { | ||
unwrap: new MapType(), | ||
serialize: new MapType() | ||
}, | ||
circularReferenceIsSerializing: { | ||
unwrap: new MapType(), | ||
serialize: new MapType() | ||
} | ||
}; | ||
} | ||
return function serializer(value, MapType){ | ||
if (isSerializedHelper(value)) { | ||
@@ -135,22 +172,6 @@ return value; | ||
var firstSerialize; | ||
if(!serializeMap) { | ||
MapType = MapType || ArrayMap; | ||
serializeMap = { | ||
unwrap: new MapType(), | ||
serialize: new MapType() , | ||
isSerializing: { | ||
unwrap: new MapType(), | ||
serialize: new MapType() | ||
}, | ||
circularReferenceIsSerializing: { | ||
unwrap: new MapType(), | ||
serialize: new MapType() | ||
} | ||
}; | ||
firstSerialize = true; | ||
} | ||
var serialized; | ||
var operation = new SerializeOperation(MapType); | ||
if(typeReflections.isValueLike(value)) { | ||
serialized = this[methodName](getSetReflections.getValue(value)); | ||
operation.result = this[methodName](getSetReflections.getValue(value)); | ||
@@ -163,16 +184,13 @@ } else { | ||
var isListLike = typeReflections.isIteratorLike(value) || typeReflections.isMoreListLikeThanMapLike(value); | ||
serialized = isListLike ? [] : {}; | ||
operation.result = isListLike ? [] : {}; | ||
// handle maping to what is serialized | ||
if(serializeMap) { | ||
if( serializeMap[methodName].has(value) ) { | ||
// if we are in the process of serializing the first time, setup circular reference detection. | ||
if(serializeMap.isSerializing[methodName].has(value)) { | ||
serializeMap.circularReferenceIsSerializing[methodName].set(value, true); | ||
} | ||
return serializeMap[methodName].get(value); | ||
} else { | ||
serializeMap[methodName].set(value, serialized); | ||
if( operation.map[methodName].has(value) ) { | ||
// if we are in the process of serializing the first time, setup circular reference detection. | ||
if(operation.map.isSerializing[methodName].has(value)) { | ||
operation.map.circularReferenceIsSerializing[methodName].set(value, true); | ||
} | ||
return operation.map[methodName].get(value); | ||
} else { | ||
operation.map[methodName].set(value, operation.result); | ||
} | ||
@@ -184,10 +202,11 @@ | ||
// mark that we are serializing | ||
serializeMap.isSerializing[methodName].set(value, true); | ||
var result = serializer.call(value, serialized); | ||
serializeMap.isSerializing[methodName].delete(value); | ||
operation.map.isSerializing[methodName].set(value, true); | ||
var oldResult = operation.result; | ||
operation.result = serializer.call(value, oldResult); | ||
operation.map.isSerializing[methodName].delete(value); | ||
// if the result differs, but this was circular, blow up. | ||
if(result !== serialized) { | ||
if(operation.result !== oldResult) { | ||
// jshint -W073 | ||
if(serializeMap.circularReferenceIsSerializing[methodName].has(value)) { | ||
if(operation.map.circularReferenceIsSerializing[methodName].has(value)) { | ||
// Circular references should use a custom serializer | ||
@@ -199,10 +218,8 @@ // that sets the serialized value on the object | ||
// } | ||
operation.end(); | ||
throw new Error("Cannot serialize cirular reference!"); | ||
} | ||
serializeMap[methodName].set(value, result); | ||
operation.map[methodName].set(value, operation.result); | ||
} | ||
if(firstSerialize) { | ||
serializeMap = null; | ||
} | ||
return result; | ||
return operation.end(); | ||
} | ||
@@ -212,14 +229,12 @@ } | ||
if (typeof obj ==='function') { | ||
if(serializeMap) { | ||
serializeMap[methodName].set(value, value); | ||
} | ||
operation.map[methodName].set(value, value); | ||
serialized = value; | ||
operation.result = value; | ||
} else if( isListLike ) { | ||
this.eachIndex(value,function(childValue, index){ | ||
serialized[index] = this[methodName](childValue); | ||
operation.result[index] = this[methodName](childValue); | ||
},this); | ||
} else { | ||
this.eachKey(value,function(childValue, prop){ | ||
serialized[prop] = this[methodName](childValue); | ||
operation.result[prop] = this[methodName](childValue); | ||
},this); | ||
@@ -229,7 +244,3 @@ } | ||
if(firstSerialize) { | ||
serializeMap = null; | ||
} | ||
return serialized; | ||
return operation.end(); | ||
}; | ||
@@ -236,0 +247,0 @@ } |
178123
4838