Permalink
Browse files

Other: Moved custom wrappers to its own module instead, also makes th…

…e API easier to use manually, see #677
  • Loading branch information...
dcodeIO committed Apr 11, 2017
1 parent ed34b09 commit 48e66d975bf7b4e6bdbb68ec24386c98b16c54c5
Showing with 165 additions and 19 deletions.
  1. +3 −9 src/common.js
  2. +1 −0 src/index-minimal.js
  3. +20 −5 src/type.js
  4. +2 −2 src/util.js
  5. +3 −3 src/util/minimal.js
  6. +76 −0 src/wrappers.js
  7. +60 −0 tests/comp_google_protobuf_any.js
@@ -1,6 +1,8 @@
"use strict";
module.exports = common;
var Type = require("./type");
/**
* Provides common type definitions.
* Can also be used to provide additional google types or your own custom types.
@@ -51,15 +53,7 @@ common("any", {
type: "bytes",
id: 2
}
}/*,
options: Object.create({
__fromObject: function(object) {
return this.fromObject(object);
},
__toObject: function(options) {
return this.toObject(options);
}
})*/
}
}
});
@@ -19,6 +19,7 @@ protobuf.BufferReader = require("./reader_buffer");
protobuf.util = require("./util/minimal");
protobuf.rpc = require("./rpc");
protobuf.roots = require("./roots");
protobuf.wrappers = require("./wrappers");
protobuf.configure = configure;
/* istanbul ignore next */
@@ -17,7 +17,8 @@ var Enum = require("./enum"),
encoder = require("./encoder"),
decoder = require("./decoder"),
verifier = require("./verifier"),
converter = require("./converter");
converter = require("./converter"),
wrappers = require("./wrappers");
/**
* Constructs a new reflected message type instance.
@@ -428,10 +429,13 @@ Type.prototype.create = function create(properties) {
Type.prototype.setup = function setup() {
// Sets up everything at once so that the prototype chain does not have to be re-evaluated
// multiple times (V8, soft-deopt prototype-check).
var fullName = this.fullName,
types = [];
for (var i = 0; i < /* initializes */ this.fieldsArray.length; ++i)
types.push(this._fieldsArray[i].resolve().resolvedType);
// Replace setup methods with type-specific generated functions
this.encode = encoder(this).eof(fullName + "$encode", {
Writer : Writer,
types : types,
@@ -450,14 +454,25 @@ Type.prototype.setup = function setup() {
types : types,
util : util
});
if (this.options && this.options.__formObject)
this.fromObject = this.options.__formObject.bind({ fromObject: this.fromObject });
this.toObject = converter.toObject(this).eof(fullName + "$toObject", {
types : types,
util : util
});
if (this.options && this.options.__toObject)
this.toObject = this.options.__toObject.bind({ toObject: this.toObject });
// Inject custom wrappers for common types
var wrapper = wrappers[fullName];
if (wrapper) {
var originalThis = Object.create(this);
// if (wrapper.fromObject) {
originalThis.fromObject = this.fromObject;
this.fromObject = wrapper.fromObject.bind(originalThis);
// }
// if (wrapper.toObject) {
originalThis.toObject = this.toObject;
this.toObject = wrapper.toObject.bind(originalThis);
// }
}
return this;
};
@@ -85,7 +85,7 @@ util.decorateType = function decorateType(ctor, typeName) {
return ctor.$type;
}
/* istanbul ignore if */
/* istanbul ignore next */
if (!Type)
Type = require("./type");
@@ -109,7 +109,7 @@ util.decorateEnum = function decorateEnum(object) {
if (object.$type)
return object.$type;
/* istanbul ignore if */
/* istanbul ignore next */
if (!Enum)
Enum = require("./enum");
@@ -376,17 +376,17 @@ util.oneOfSetter = function setOneOf(fieldNames) {
/**
* Default conversion options used for {@link Message#toJSON} implementations.
*
*
* These options are close to proto3's JSON mapping with the exception that internal types like Any are handled just like messages. More precisely:
*
*
* - Longs become strings
* - Enums become string keys
* - Bytes become base64 encoded strings
* - (Sub-)Messages become plain objects
* - Maps become plain objects with all string keys
* - Repeated fields become arrays
* - NaN and Infinity for float and double fields become strings
*
*
* @type {ConversionOptions}
* @see https://developers.google.com/protocol-buffers/docs/proto3?hl=en#json
*/
@@ -0,0 +1,76 @@
"use strict";
/**
* Wrappers for common types.
* @namespace
*/
var wrappers = exports;
var util = require("./util/minimal");
/**
* From object converter part of a {@link Wrapper}.
* @typedef WrapperFromObjectConverter
* @type {function}
* @param {Object.<string,*>} object Plain object
* @returns {Message<{}>}
* @this Type
*/
/**
* To object converter part of a {@link Wrapper}.
* @typedef WrapperToObjectConverter
* @type {function}
* @param {Message<{}>} message Message instance
* @param {ConversionOptions=} options Conversion options
* @returns {Object.<string,*>}
* @this Type
*/
/**
* Common type wrapper part of {@link wrappers}.
* @typedef Wrapper
* @type {Object}
* @property {WrapperFromObjectConverter} [fromObject] From object converter
* @property {WrapperToObjectConverter} [toObject] To object converter
*/
/**
* Custom wrapper for Any.
* @type {Wrapper}
*/
wrappers[".google.protobuf.Any"] = {
fromObject: function(object) {
// unwrap value type if mapped
if (object && object["@type"]) {
var type = this.lookup(object["@type"]);
/* istanbul ignore else */
if (type)
return type.fromObject(object);
}
return this.fromObject(object);
},
toObject: function(message, options) {
// decode value if requested and unmapped
if (options && options.json && message.type_url && message.value) {
var type = this.lookup(message.type_url);
/* istanbul ignore else */
if (type)
message = type.decode(message.value);
}
// wrap value if unmapped
if (!(message instanceof this.ctor)) {
var object = message.toObject(options);
object["@type"] = message.$type.fullName;
return object;
}
return this.toObject(message, options);
}
};
@@ -0,0 +1,60 @@
var tape = require("tape");
var protobuf = require("..");
var root = protobuf.Root.fromJSON({
nested: {
Foo: {
fields: {
foo: {
id: 1,
type: "google.protobuf.Any"
}
}
},
Bar: {
fields: {
bar: {
id: 1,
type: "string"
}
}
}
}
}).addJSON(protobuf.common["google/protobuf/any.proto"].nested).resolveAll();
var Any = root.lookupType(".google.protobuf.Any"),
Foo = root.lookupType(".Foo"),
Bar = root.lookupType(".Bar");
tape.test("google.protobuf.Any", function(test) {
var foo = Foo.fromObject({
foo: {
type_url: ".Bar",
value: [1 << 3 | 2, 1, 97] // value = "a"
}
});
test.ok(foo.foo instanceof Any.ctor, "should keep explicit Any in fromObject");
test.same(foo.foo, { type_url: ".Bar", value: [10, 1, 97] }, "should keep explicit Any in fromObject properly");
var obj = Foo.toObject(foo);
test.same(obj.foo, { type_url: ".Bar", value: [10, 1, 97] }, "should keep explicit Any in toObject properly");
obj = Foo.toObject(foo, { json: true });
test.same(obj.foo, { "@type": ".Bar", bar: "a" }, "should decode explicitly Any in toObject if requested");
foo = Foo.fromObject({
foo: {
"@type": ".Bar",
bar: "a"
}
});
test.ok(foo.foo instanceof Bar.ctor, "should unwrap wrapped Bar in fromObject");
test.same(foo.foo, { bar: "a" }, "should unwrap wrapper Bar in fromObject properly");
obj = Foo.toObject(foo);
test.same(obj.foo, { "@type": ".Bar", bar: "a" }, "should wrap Bar in toObject properly");
test.end();
});

0 comments on commit 48e66d9

Please sign in to comment.