Skip to content

Commit

Permalink
Other: ext/descriptor support for various standard options, see #757
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodeIO committed Apr 14, 2017
1 parent 2d8ce6e commit 9a23ded
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 71 deletions.
4 changes: 2 additions & 2 deletions bench/data/static_pbjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ $root.Test = (function() {
if (message.long != null && message.hasOwnProperty("long"))
writer.uint32(8).int64(message.long);
if (message["enum"] != null && message.hasOwnProperty("enum"))
writer.uint32(16).uint32(message["enum"]);
writer.uint32(16).int32(message["enum"]);
if (message.sint32 != null && message.hasOwnProperty("sint32"))
writer.uint32(24).sint32(message.sint32);
return writer;
Expand All @@ -147,7 +147,7 @@ $root.Test = (function() {
message.long = reader.int64();
break;
case 2:
message["enum"] = reader.uint32();
message["enum"] = reader.int32();
break;
case 3:
message.sint32 = reader.sint32();
Expand Down
2 changes: 1 addition & 1 deletion cli/lib/tsd-jsdoc/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ function getTypeOf(element) {

// begins writing the definition of the specified element
function begin(element, is_interface) {
writeComment(element.comment, is_interface || isInterface(element) || isClassLike(element) || isNamespace(element) || element.isEnum);
writeComment(element.comment, is_interface || isInterface(element) || isClassLike(element) || isNamespace(element) || element.isEnum || element.scope === "global");
if (element.scope !== "global" || options.module)
return;
write("export ");
Expand Down
16 changes: 8 additions & 8 deletions ext/descriptor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ The extension adds `.fromDescriptor(descriptor[, syntax])` and `#toDescriptor([s
| Descriptor type | protobuf.js type | Remarks
|--------------------------|------------------|---------
| FileDescriptorSet | Root |
| FileDescriptorProto | Root | except dependencies, sourceCodeInfo
| FileOptions | Root | not supported
| FileDescriptorProto | Root | except dependencies
| FileOptions | Root |
| DescriptorProto | Type |
| MessageOptions | Type | not supported
| FieldDescriptorProto | Field | except defaultValue
| MessageOptions | Type |
| FieldDescriptorProto | Field |
| FieldOptions | Field |
| OneofDescriptorProto | OneOf |
| OneofOptions | OneOf | not supported
| OneofOptions | OneOf |
| EnumDescriptorProto | Enum |
| EnumValueDescriptorProto | Enum |
| EnumOptions | Enum | only allowAlias
| EnumOptions | Enum |
| EnumValueOptions | Enum | not supported
| ServiceDescriptorProto | Service |
| ServiceOptions | Service | not supported
| ServiceOptions | Service |
| MethodDescriptorProto | Method |
| MethodOptions | Method | not supported
| MethodOptions | Method |
| UninterpretedOption | | not supported
| SourceCodeInfo | | not supported
| GeneratedCodeInfo | | not supported
Expand Down
41 changes: 32 additions & 9 deletions ext/descriptor/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,29 @@ type ReservedRangeProperties = {
end?: number;
};

type FieldOptionsProperties = {
packed?: boolean;
};

type FieldDescriptorProtoProperties = {
name?: string;
number?: number;
label?: FieldDescriptorProtoLabel;
type?: FieldDescriptorProtoType;
label?: FieldDescriptorProto_Label;
type?: FieldDescriptorProto_Type;
typeName?: string;
extendee?: string;
defaultValue?: any;
defaultValue?: string;
oneofIndex?: number;
jsonName?: any;
options?: FieldOptionsProperties;
};

type FieldDescriptorProtoLabel = number;
type FieldDescriptorProto_Label = number;

type FieldDescriptorProtoType = number;
type FieldDescriptorProto_Type = number;

type FieldOptionsProperties = {
packed?: boolean;
jstype?: FieldOptions_JSType;
};

type FieldOptions_JSType = number;

type EnumDescriptorProtoProperties = {
name?: string;
Expand Down Expand Up @@ -102,23 +105,43 @@ type MethodDescriptorProtoProperties = {
clientStreaming?: boolean;
serverStreaming?: boolean;
};

export const FileDescriptorSet: $protobuf.Type;

export const FileDescriptorProto: $protobuf.Type;

export const DescriptorProto: $protobuf.Type;

export const FieldDescriptorProto: $protobuf.Type;

export const OneofDescriptorProto: $protobuf.Type;

export const EnumDescriptorProto: $protobuf.Type;

export const ServiceDescriptorProto: $protobuf.Type;

export const EnumValueDescriptorProto: $protobuf.Type;

export const MethodDescriptorProto: $protobuf.Type;

export const FileOptions: $protobuf.Type;

export const MessageOptions: $protobuf.Type;

export const FieldOptions: $protobuf.Type;

export const OneofOptions: $protobuf.Type;

export const EnumOptions: $protobuf.Type;

export const EnumValueOptions: $protobuf.Type;

export const ServiceOptions: $protobuf.Type;

export const MethodOptions: $protobuf.Type;

export const UninterpretedOption: $protobuf.Type;

export const SourceCodeInfo: $protobuf.Type;

export const GeneratedCodeInfo: $protobuf.Type;
92 changes: 71 additions & 21 deletions ext/descriptor/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use strict";
var $protobuf = require("../..");
var $protobuf = require("../.."); // requires the full library (uses parser exports)
module.exports = exports = $protobuf.descriptor = $protobuf.Root.fromJSON(require("../../google/protobuf/descriptor.json")).lookup(".google.protobuf");

var Namespace = $protobuf.Namespace,
Expand Down Expand Up @@ -73,6 +73,12 @@ Root.fromDescriptor = function fromDescriptor(descriptor) {
if (fileDescriptor.extension)
for (i = 0; i < fileDescriptor.extension.length; ++i)
filePackage.add(Field.fromDescriptor(fileDescriptor.extension[i]));
var opts = fromDescriptorOptions(fileDescriptor.options, exports.FileOptions);
if (opts) {
var ks = Object.keys(opts);
for (i = 0; i < ks.length; ++i)
filePackage.setOption(ks[i], opts[ks[i]]);
}
}
}

Expand Down Expand Up @@ -114,6 +120,9 @@ function Root_toDescriptorRecursive(ns, files, syntax) {
else if (nested instanceof /* plain */ Namespace)
Root_toDescriptorRecursive(nested, files, syntax); // requires new file

// Keep package-level options
file.options = toDescriptorOptions(ns.options, exports.FileOptions);

// And keep the file only if there is at least one nested object
if (file.messageType.length + file.enumType.length + file.extension.length + file.service.length)
files.push(file);
Expand Down Expand Up @@ -180,7 +189,7 @@ Type.fromDescriptor = function fromDescriptor(descriptor, syntax) {
descriptor = exports.DescriptorProto.decode(descriptor);

// Create the message type
var type = new Type(descriptor.name.length ? descriptor.name : "Type" + unnamedMessageIndex++),
var type = new Type(descriptor.name.length ? descriptor.name : "Type" + unnamedMessageIndex++, fromDescriptorOptions(descriptor.options, exports.MessageOptions)),
i;

/* Oneofs */ if (descriptor.oneofDecl)
Expand Down Expand Up @@ -273,8 +282,7 @@ Type.prototype.toDescriptor = function toDescriptor(syntax) {
/* Ranges */ else
descriptor.reservedRange.push(exports.DescriptorProto.ReservedRange.create({ start: this.reserved[i][0], end: this.reserved[i][1] }));

if (this.options && this.options.map_entry)
descriptor.options = exports.MessageOptions.create({ map_entry: true });
descriptor.options = toDescriptorOptions(this.options, exports.MessageOptions);

return descriptor;
};
Expand Down Expand Up @@ -392,10 +400,25 @@ Field.fromDescriptor = function fromDescriptor(descriptor, syntax) {
descriptor.extendee.length ? descriptor.extendee : undefined
);

if (descriptor.options)
field.options = fromDescriptorOptions(descriptor.options, exports.FieldOptions);
if (descriptor.defaultValue && descriptor.defaultValue.length)
field.setOption("default", descriptor.defaultValue);
field.options = fromDescriptorOptions(descriptor.options, exports.FieldOptions);

if (descriptor.defaultValue && descriptor.defaultValue.length) {
var defaultValue = descriptor.defaultValue;
switch (defaultValue) {
case "true": case "TRUE":
defaultValue = true;
break;
case "false": case "FALSE":
defaultValue = false;
break;
default:
var match = $protobuf.parse.numberRe.exec(defaultValue);
if (match)
defaultValue = parseInt(defaultValue);
break;
}
field.setOption("default", defaultValue);
}

if (packableDescriptorType(descriptor.type)) {
if (syntax === "proto3") { // defaults to packed=true (internal preset is packed=true)
Expand Down Expand Up @@ -522,7 +545,7 @@ Enum.fromDescriptor = function fromDescriptor(descriptor) {
return new Enum(
descriptor.name && descriptor.name.length ? descriptor.name : "Enum" + unnamedEnumIndex++,
values,
descriptor.options && descriptor.options.allowAlias ? { allowAlias: true } : undefined
fromDescriptorOptions(descriptor.options, exports.EnumOptions)
);
};

Expand All @@ -540,7 +563,8 @@ Enum.prototype.toDescriptor = function toDescriptor() {

return exports.EnumDescriptorProto.create({
name: this.name,
value: values
value: values,
options: toDescriptorOptions(this.options, exports.EnumOptions)
});
};

Expand Down Expand Up @@ -572,6 +596,7 @@ OneOf.fromDescriptor = function fromDescriptor(descriptor) {
return new OneOf(
// unnamedOneOfIndex is global, not per type, because we have no ref to a type here
descriptor.name && descriptor.name.length ? descriptor.name : "oneof" + unnamedOneofIndex++
// fromDescriptorOptions(descriptor.options, exports.OneofOptions) - only uninterpreted_option
);
};

Expand All @@ -583,6 +608,7 @@ OneOf.fromDescriptor = function fromDescriptor(descriptor) {
OneOf.prototype.toDescriptor = function toDescriptor() {
return exports.OneofDescriptorProto.create({
name: this.name
// options: toDescriptorOptions(this.options, exports.OneofOptions) - only uninterpreted_option
});
};

Expand Down Expand Up @@ -612,7 +638,7 @@ Service.fromDescriptor = function fromDescriptor(descriptor) {
if (typeof descriptor.length === "number")
descriptor = exports.ServiceDescriptorProto.decode(descriptor);

var service = new Service(descriptor.name && descriptor.name.length ? descriptor.name : "Service" + unnamedServiceIndex++);
var service = new Service(descriptor.name && descriptor.name.length ? descriptor.name : "Service" + unnamedServiceIndex++, fromDescriptorOptions(descriptor.options, exports.ServiceOptions));
if (descriptor.method)
for (var i = 0; i < descriptor.method.length; ++i)
service.add(Method.fromDescriptor(descriptor.method[i]));
Expand All @@ -634,7 +660,8 @@ Service.prototype.toDescriptor = function toDescriptor() {

return exports.ServiceDescriptorProto.create({
name: this.name,
methods: methods
methods: methods,
options: toDescriptorOptions(this.options, exports.ServiceOptions)
});
};

Expand Down Expand Up @@ -674,7 +701,8 @@ Method.fromDescriptor = function fromDescriptor(descriptor) {
descriptor.inputType,
descriptor.outputType,
Boolean(descriptor.clientStreaming),
Boolean(descriptor.serverStreaming)
Boolean(descriptor.serverStreaming),
fromDescriptorOptions(descriptor.options, exports.MethodOptions)
);
};

Expand All @@ -689,7 +717,8 @@ Method.prototype.toDescriptor = function toDescriptor() {
inputType: this.resolvedRequestType ? this.resolvedRequestType.fullName : this.requestType,
outputType: this.resolvedResponseType ? this.resolvedResponseType.fullName : this.responseType,
clientStreaming: this.requestStream,
serverStreaming: this.responseStream
serverStreaming: this.responseStream,
options: toDescriptorOptions(this.options, exports.MethodOptions)
});
};

Expand Down Expand Up @@ -769,20 +798,34 @@ function toDescriptorType(type, resolvedType) {

// Converts descriptor options to an options object
function fromDescriptorOptions(options, type) {
if (!options)
return undefined;
var out = [];
for (var i = 0, key; i < type.fieldsArray.length; ++i)
if ((key = type._fieldsArray[i].name) !== "uninterpretedOption")
if (options.hasOwnProperty(key)) // eslint-disable-line no-prototype-builtins
out.push(key, options[key]);
for (var i = 0, field, key, val; i < type.fieldsArray.length; ++i)
if ((key = (field = type._fieldsArray[i]).name) !== "uninterpretedOption")
if (options.hasOwnProperty(key)) { // eslint-disable-line no-prototype-builtins
val = options[key];
if (field.resolvedType instanceof Enum && typeof val === "number" && field.resolvedType.valuesById[val] !== undefined)
val = field.resolvedType.valuesById[val];
out.push(underScore(key), val);
}
return out.length ? $protobuf.util.toObject(out) : undefined;
}

// Converts an options object to descriptor options
function toDescriptorOptions(options, type) {
if (!options)
return undefined;
var out = [];
for (var i = 0, key; i < type.fieldsArray.length; ++i)
if ((key = type._fieldsArray[i].name) !== "default")
out.push(key, options[key]);
for (var i = 0, ks = Object.keys(options), key, val; i < ks.length; ++i) {
val = options[key = ks[i]];
if (key === "default")
continue;
var field = type.fields[key];
if (!field && !(field = type.fields[key = $protobuf.parse.camelCase(key)]))
continue;
out.push(key, val);
}
return out.length ? type.fromObject($protobuf.util.toObject(out)) : undefined;
}

Expand All @@ -805,6 +848,13 @@ function shortname(from, to) {
return toPath.slice(j).join(".");
}

// copied here from cli/targets/proto.js
function underScore(str) {
return str.substring(0,1)
+ str.substring(1)
.replace(/([A-Z])(?=[a-z]|$)/g, function($0, $1) { return "_" + $1.toLowerCase(); });
}

// --- exports ---

/**
Expand Down
12 changes: 7 additions & 5 deletions ext/descriptor/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ var proto = require("../../google/protobuf/descriptor.json")/*{
}
}*/;

var root = protobuf.Root.fromJSON(proto).resolveAll();
// var root = protobuf.Root.fromJSON(proto).resolveAll();
var root = protobuf.loadSync("tests/data/google/protobuf/descriptor.proto").resolveAll();

// console.log("Original proto", JSON.stringify(root, null, 2));

Expand All @@ -41,12 +42,13 @@ var root2 = protobuf.Root.fromDescriptor(buf, "proto2").resolveAll();
// console.log("\nDecoded proto", JSON.stringify(root2, null, 2));

var diff = require("deep-diff").diff(root.toJSON(), root2.toJSON());
if (diff)
if (diff) {
diff.forEach(function(diff) {
console.log(diff.kind + " @ " + diff.path.join("."));
console.log("lhs:", diff.lhs);
console.log("rhs:", diff.rhs);
console.log("lhs:", typeof diff.lhs, diff.lhs);
console.log("rhs:", typeof diff.rhs, diff.rhs);
console.log();
});
else
process.exit(1);
} else
console.log("no differences");
3 changes: 3 additions & 0 deletions src/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ function camelCase(str) {
.replace(camelCaseRe, function($0, $1) { return $1.toUpperCase(); });
}

parse.camelCase = camelCase;
parse.numberRe = numberRe;

/**
* Result object returned from {@link parse}.
* @typedef ParserResult
Expand Down
Loading

0 comments on commit 9a23ded

Please sign in to comment.