Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sync option to deserializer #2011

Merged
merged 5 commits into from
Feb 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions core/serialization/deserializer/montage-deserializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var MontageDeserializer = exports.MontageDeserializer = Montage.specialize({
},

init: {
value: function (serialization, _require, objectRequires, locationId) {
value: function (serialization, _require, objectRequires, locationId, isSync) {
if (typeof serialization === "string") {
this._serializationString = serialization;
} else {
Expand All @@ -35,8 +35,9 @@ var MontageDeserializer = exports.MontageDeserializer = Montage.specialize({
this._locationId = locationId ? locationId.indexOf(_require.location) === 0 ? locationId : _require.location + locationId : locationId;

this._reviver = new MontageReviver().init(
_require, objectRequires, this.constructor
_require, objectRequires, this.constructor, isSync
);
this._isSync = isSync;

return this;
}
Expand All @@ -48,33 +49,53 @@ var MontageDeserializer = exports.MontageDeserializer = Montage.specialize({
* link against the serialization.
* @param {Element} element The root element to resolve element references
* against.
* @return {Promise}
* @return {Promise|object} Deserialized objects if the deserializer was
* initialized with sync set to true, or a Promise for the deserialized
* objects otherwise.
*/
deserialize: {
value: function (instances, element) {
var context = this._locationId && MontageDeserializer.moduleContexts.get(this._locationId);
var context = this._locationId && MontageDeserializer.moduleContexts.get(this._locationId),
circularError;
if (context) {
if (context._objects.root) {
return Promise.resolve(context._objects);
return this._isSync ? context._objects : Promise.resolve(context._objects);
} else {
return Promise.reject(new Error(
circularError = new Error(
"Unable to deserialize because a circular dependency was detected. " +
"Module \"" + this._locationId + "\" has already been loaded but " +
"its root could not be resolved."
));
);
if (this._isSync) {
throw circularError;
} else {
return Promise.reject(circularError);
}
}
}

try {
var serialization = JSON.parse(this._serializationString);
context = new MontageContext()
.init(serialization, this._reviver, instances, element, this._require);
.init(serialization, this._reviver, instances, element, this._require, this._isSync);
if (this._locationId) {
MontageDeserializer.moduleContexts.set(this._locationId, context);
}
return context.getObjects();
try {
return context.getObjects();
} catch (ex) {
if (this._isSync) {
throw ex;
} else {
return Promise.reject(ex);
}
}
} catch (ex) {
return this._formatSerializationSyntaxError(this._serializationString);
if (this._isSync) {
throw ex;
} else {
return this._formatSerializationSyntaxError(this._serializationString);
}
}
}
},
Expand Down
28 changes: 14 additions & 14 deletions core/serialization/deserializer/montage-interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ var MontageContext = Montage.specialize({
},

init: {
value: function (serialization, reviver, objects, element, _require) {
value: function (serialization, reviver, objects, element, _require, isSync) {
this._reviver = reviver;
this._serialization = serialization;
this._objects = Object.create(null);
Expand All @@ -112,6 +112,7 @@ var MontageContext = Montage.specialize({

this._element = element;
this._require = _require;
this._isSync = isSync;

return this;
}
Expand All @@ -128,9 +129,7 @@ var MontageContext = Montage.specialize({
var serialization = this._serialization,
reviver = this._reviver,
objects = this._objects,
object;


object, notFoundError;

if (label in objects) {
return objects[label];
Expand All @@ -145,9 +144,12 @@ var MontageContext = Montage.specialize({

return object;
} else {
return Promise.reject(
new Error("Object with label '" + label + "' was not found.")
);
notFoundError = new Error("Object with label '" + label + "' was not found.");
if (this._isSync) {
throw notFoundError;
} else {
return Promise.reject(notFoundError);
}
}
}
},
Expand All @@ -170,8 +172,10 @@ var MontageContext = Montage.specialize({
}

if (promises.length === 0) {
return Promise.resolve(this._invokeDidReviveObjects());
result = this._invokeDidReviveObjects();
marchant marked this conversation as resolved.
Show resolved Hide resolved
return this._isSync ? result : Promise.resolve(result);
} else {
// We shouldn't get here if this._isSync is true
return Promise.all(promises).then(function() {
return self._invokeDidReviveObjects();
});
Expand Down Expand Up @@ -208,12 +212,8 @@ var MontageContext = Montage.specialize({
result;

if (typeof reviver.didReviveObjects === "function") {
result = reviver.didReviveObjects(this._objects, this);
if (Promise.is(result)) {
return result.then(function() {
return self._objects;
});
}
reviver.didReviveObjects(this._objects, this);
marchant marked this conversation as resolved.
Show resolved Hide resolved
return self._objects;
}

return this._objects;
Expand Down
112 changes: 53 additions & 59 deletions core/serialization/deserializer/montage-reviver.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,6 @@ var ModuleLoader = Montage.specialize({
}
},

getExports: {
value: function (_require, moduleId) {
var moduleDescriptor = this.getModuleDescriptor(_require, moduleId);
return moduleDescriptor ? moduleDescriptor.exports : void 0;
}
},

getModule: {
value: function (moduleId, label) {
var objectRequires = this._objectRequires,
Expand All @@ -97,14 +90,16 @@ var ModuleLoader = Montage.specialize({
_require = this._require;
}

module = this.getExports(_require, moduleId);

if (!module && (moduleId.endsWith(".mjson") || moduleId.endsWith(".meta"))) {
module = this.getModuleDescriptor(_require, moduleId).text;
}
try {
module = _require(moduleId);
} catch (err) {
if (!module && (moduleId.endsWith(".mjson") || moduleId.endsWith(".meta"))) {
module = this.getModuleDescriptor(_require, moduleId).text;
}

if (!module) {
module = _require.async(moduleId);
if (!module) {
module = _require.async(moduleId);
}
}

return module;
Expand All @@ -131,10 +126,11 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
* that also needs to be deserialized.
*/
init: {
value: function (_require, objectRequires, deserializerConstructor) {
value: function (_require, objectRequires, deserializerConstructor, isSync) {
this.moduleLoader = new ModuleLoader().init(_require, objectRequires);
this._require = _require;
this._deserializerConstructor = deserializerConstructor;
this._isSync = isSync;
return this;
}
},
Expand Down Expand Up @@ -341,7 +337,7 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
// should be rejected as an error.
error = this._checkLabel(label, isAlias);
if (error) {
return Promise.reject(error);
throw error;
marchant marked this conversation as resolved.
Show resolved Hide resolved
}

// Check if the optional "debugger" unit is set for this object
Expand Down Expand Up @@ -419,7 +415,7 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
}
return element;
} else {
return Promise.reject(new Error("Element with id '" + elementId + "' was not found."));
throw new Error("Element with id '" + elementId + "' was not found.");
marchant marked this conversation as resolved.
Show resolved Hide resolved
}
}
},
Expand Down Expand Up @@ -469,14 +465,20 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
)) {
// We have a circular reference. If we wanted to forbid circular
// references this is where we would throw an error.
return Promise.resolve(this._deserializerConstructor.moduleContexts.get(location)._objects.root);
return this._deserializerConstructor.moduleContexts.get(location)._objects.root;
marchant marked this conversation as resolved.
Show resolved Hide resolved
}

if (isObjectDescriptor && !Promise.is(module) && !module.montageObject) {
module = context._require.async(locationDesc.moduleId);
}

if (Promise.is(module)) {
if (this._isSync) {
throw new Error(
"Tried to revive montage object with label " + label +
" synchronously but the module was not loaded: " + JSON.stringify(value)
);
}
return module.then(function (exports) {
marchant marked this conversation as resolved.
Show resolved Hide resolved
return self.instantiateObject(exports, locationDesc, value, objectName, context, label);
}, function (error) {
Expand Down Expand Up @@ -687,14 +689,9 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont

didReviveObjects: {
value: function (objects, context) {
var self = this;

return Promise.all([
this._deserializeBindings(context),
this._deserializeUnits(context)
]).then(function () {
self._invokeDeserializedFromSerialization(objects, context);
});
this._deserializeBindings(context);
marchant marked this conversation as resolved.
Show resolved Hide resolved
this._deserializeUnits(context);
this._invokeDeserializedFromSerialization(objects, context);
}
},

Expand Down Expand Up @@ -731,17 +728,13 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
bindingsToDeserializeDesc;

if (bindingsToDeserialize) {
try {
for (var i = 0, length = bindingsToDeserialize.length; i < length; i++) {
bindingsToDeserializeDesc = bindingsToDeserialize[i];
Bindings.deserializeObjectBindings(
unitDeserializer.initWithContext(context),
bindingsToDeserializeDesc.object,
bindingsToDeserializeDesc.bindings
);
}
} catch (ex) {
return Promise.reject(ex);
for (var i = 0, length = bindingsToDeserialize.length; i < length; i++) {
marchant marked this conversation as resolved.
Show resolved Hide resolved
bindingsToDeserializeDesc = bindingsToDeserialize[i];
Bindings.deserializeObjectBindings(
unitDeserializer.initWithContext(context),
bindingsToDeserializeDesc.object,
bindingsToDeserializeDesc.bindings
);
}
}
}
Expand All @@ -753,19 +746,15 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
unitDeserializer = new UnitDeserializer(),
unitNames;

try {
for (var i = 0, unitsDesc; (unitsDesc = unitsToDeserialize[i]); i++) {
unitNames = unitsDesc.unitNames;
for (var i = 0, unitsDesc; (unitsDesc = unitsToDeserialize[i]); i++) {
marchant marked this conversation as resolved.
Show resolved Hide resolved
unitNames = unitsDesc.unitNames;

for (var j = 0, unitName; (unitName = unitNames[j]); j++) {
if (unitName in unitsDesc.objectDesc) {
unitDeserializer.initWithContext(context);
MontageReviver._unitRevivers.get(unitName)(unitDeserializer, unitsDesc.object, unitsDesc.objectDesc[unitName]);
}
for (var j = 0, unitName; (unitName = unitNames[j]); j++) {
if (unitName in unitsDesc.objectDesc) {
unitDeserializer.initWithContext(context);
MontageReviver._unitRevivers.get(unitName)(unitDeserializer, unitsDesc.object, unitsDesc.objectDesc[unitName]);
}
}
} catch (ex) {
return Promise.reject(ex);
}
}
},
Expand All @@ -785,24 +774,31 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont

reviveValue: {
value: function(value, context, label) {
var type = this.getTypeOf(value);
var type = this.getTypeOf(value),
revived;

if (type === "string" || type === "number" || type === "boolean" || type === "null" || type === "undefined") {
return this.reviveNativeValue(value, context, label);
revived = this.reviveNativeValue(value, context, label);
} else if (type === "regexp") {
return this.reviveRegExp(value, context, label);
revived = this.reviveRegExp(value, context, label);
} else if (type === "reference") {
return this.reviveObjectReference(value, context, label);
revived = this.reviveObjectReference(value, context, label);
} else if (type === "array") {
return this.reviveArray(value, context, label);
revived = this.reviveArray(value, context, label);
} else if (type === "object") {
return this.reviveObjectLiteral(value, context, label);
revived = this.reviveObjectLiteral(value, context, label);
} else if (type === "Element") {
return this.reviveElement(value, context, label);
revived = this.reviveElement(value, context, label);
} else if (type === "binding") {
return value;
revived = value;
} else {
return this._callReviveMethod("revive" + type, value, context, label);
revived = this._callReviveMethod("revive" + type, value, context, label);
}

if (this._isSync && Promise.is(revived)) {
throw new Error("Unable to revive value with label " + label + " synchronously: " + value);
} else {
return revived;
}
}
},
Expand Down Expand Up @@ -913,9 +909,7 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont

reviveExternalObject: {
value: function(value, context, label) {
return Promise.reject(
new Error("External object '" + label + "' not found in user objects.")
);
throw new Error("External object '" + label + "' not found in user objects.");
}
},

Expand Down
Loading