Skip to content
Open
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
15 changes: 13 additions & 2 deletions src/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ var Enum = require("./enum"),
types = require("./types"),
util = require("./util");

var wrapperValueRe = /^\.google\.protobuf\.(?:DoubleValue|FloatValue|Int64Value|UInt64Value|Int32Value|UInt32Value|BoolValue|StringValue|BytesValue)$/;

/**
* Generates a partial value fromObject conveter.
* @param {Codegen} gen Codegen instance
Expand Down Expand Up @@ -41,10 +43,13 @@ function genValuePartial_fromObject(gen, field, fieldIndex, prop) {
("break");
} gen
("}");
} else gen
} else {
if (!wrapperValueRe.test(field.resolvedType.fullName)) gen
("if(typeof d%s!==\"object\")", prop)
("throw TypeError(%j)", field.fullName + ": object expected")
("throw TypeError(%j)", field.fullName + ": object expected");
gen
("m%s=types[%i].fromObject(d%s,q+1)", prop, fieldIndex, prop);
}
} else {
var isUnsigned = false;
switch (field.type) {
Expand Down Expand Up @@ -112,6 +117,9 @@ converter.fromObject = function fromObject(mtype) {
("if(q===undefined)q=0")
("if(q>util.recursionLimit)")
("throw Error(\"max depth exceeded\")");
if (wrapperValueRe.test(mtype.fullName)) gen
("if(d!=null&&typeof d!==\"object\")")
("d={value:d}");
if (!fields.length) return gen
("return new this.ctor");
gen
Expand Down Expand Up @@ -313,6 +321,9 @@ converter.toObject = function toObject(mtype) {
gen
("}");
}
if (wrapperValueRe.test(mtype.fullName)) gen
("if(o.json)")
("return d.value");
return gen
("return d");
/* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
Expand Down
54 changes: 54 additions & 0 deletions tests/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,60 @@ tape.test("pbjs generates correct ES6 static-module imports", function(test) {
});
});

tape.test("pbjs generates static wrapper conversions", function(test) {
cliTest(test, function() {
var root = new protobuf.Root().addJSON(protobuf.common["google/protobuf/wrappers.proto"].nested).addJSON({
WrapperContainer: {
fields: {
name: {
id: 1,
type: "google.protobuf.StringValue"
},
count: {
id: 2,
type: "google.protobuf.Int64Value"
},
flag: {
id: 3,
type: "google.protobuf.BoolValue"
},
data: {
id: 4,
type: "google.protobuf.BytesValue"
}
}
}
}).resolveAll();

var staticTarget = require("../cli/targets/static");

staticTarget(root, {
create: true,
encode: true,
decode: true,
convert: true
}, function(err, jsCode) {
test.error(err, "static code generation worked");

var $protobuf = protobuf;
eval(jsCode);

var WrapperContainer = protobuf.roots.default.WrapperContainer;
var object = {
name: "abc",
count: "123",
flag: false,
data: "AQI="
};
var message = WrapperContainer.fromObject(object);

test.same(WrapperContainer.toObject(message, { json: true, bytes: String, longs: String }), object, "should use wrapper scalar representation for json conversion");
test.same(WrapperContainer.toObject(message, { bytes: String, longs: String }).name, { value: "abc" }, "should preserve wrapper object representation without json conversion");
test.end();
});
});
});

tape.test("pbjs escapes static target names", function(test) {
cliTest(test, function() {
var root = protobuf.Root.fromJSON({
Expand Down
69 changes: 69 additions & 0 deletions tests/comp_google_protobuf_wrappers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
var tape = require("tape");

var protobuf = require("..");

var root = new protobuf.Root().addJSON(protobuf.common["google/protobuf/wrappers.proto"].nested).addJSON({
Foo: {
fields: {
stringValue: {
id: 1,
type: "google.protobuf.StringValue"
},
int64Value: {
id: 2,
type: "google.protobuf.Int64Value"
},
boolValue: {
id: 3,
type: "google.protobuf.BoolValue"
},
bytesValue: {
id: 4,
type: "google.protobuf.BytesValue"
}
}
}
}).resolveAll();

var Foo = root.lookupType("Foo"),
StringValue = root.lookupType("google.protobuf.StringValue");

tape.test("google.protobuf wrapper types", function(test) {

var foo = Foo.fromObject({
stringValue: "abc",
int64Value: "123",
boolValue: false,
bytesValue: "AQI="
});

test.same(Foo.toObject(foo, { json: true, bytes: String, longs: String }), {
stringValue: "abc",
int64Value: "123",
boolValue: false,
bytesValue: "AQI="
}, "should convert wrapper fields using their JSON scalar representation");

foo = Foo.fromObject({
stringValue: {
value: "abc"
}
});

test.same(Foo.toObject(foo), {
stringValue: {
value: "abc"
}
}, "should preserve the existing object representation without json conversion");

var stringValue = StringValue.fromObject("abc");

test.same(StringValue.toObject(stringValue), {
value: "abc"
}, "should preserve direct wrapper objects without json conversion");
test.equal(StringValue.toObject(stringValue, { json: true }), "abc", "should unwrap direct wrapper objects with json conversion");

test.same(StringValue.toObject(StringValue.fromObject({})), {}, "should preserve empty wrapper objects");

test.end();
});
Loading