Skip to content

Commit e49bef8

Browse files
committed
Other: More ext/descriptor progress, see #757
1 parent 6b94336 commit e49bef8

File tree

1 file changed

+276
-28
lines changed

1 file changed

+276
-28
lines changed

ext/descriptor.js

Lines changed: 276 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Extension for reflection interoperability with descriptor.proto types
1+
// [WIP] Extension for reflection interoperability with descriptor.proto types
22
// var protobuf = require("protobufjs"),
33
// descriptor = require("protobufjs/ext/descriptor");
44
// ...
@@ -7,88 +7,336 @@
77
var protobuf = require("..");
88

99
/**
10-
* Descriptor extension.
10+
* Descriptor extension (ext/descriptor).
1111
* @namespace
1212
* @property {Type} FileDescriptorSet Descriptor set describing a root
1313
* @property {Type} DescriptorProto Descriptor describing a type
1414
* @property {Type} FieldDescriptorProto Descriptor describing a field
1515
*/
1616
var descriptor = module.exports = protobuf.Root.fromJSON(require("../google/protobuf/descriptor.json")).lookup(".google.protobuf");
1717

18-
var Root = protobuf.Root,
19-
Type = protobuf.Type,
20-
Field = protobuf.Field;
18+
var google = descriptor,
19+
Root = protobuf.Root,
20+
Enum = protobuf.Enum,
21+
Type = protobuf.Type,
22+
Field = protobuf.Field,
23+
OneOf = protobuf.OneOf;
2124

22-
var FileDescriptorSet = descriptor.FileDescriptorSet,
23-
DescriptorProto = descriptor.DescriptorProto,
24-
FieldDescriptorProto = descriptor.FieldDescriptorProto;
25-
26-
// Root
25+
// Root : FileDescriptorSet
26+
// ------------------------
27+
// [ ] repeated FileDescriptorProto file = 1;
28+
// ├ [ ] optional string name = 1;
29+
// ├ [ ] optional string package = 2;
30+
// ├ [ ] repeated string dependency = 3;
31+
// ├ [ ] repeated int32 public_dependency = 10;
32+
// ├ [ ] repeated int32 weak_dependency = 11;
33+
// ├ [ ] repeated DescriptorProto message_type = 4;
34+
// ├ [ ] repeated EnumDescriptorProto enum_type = 5;
35+
// ├ [ ] repeated ServiceDescriptorProto service = 6;
36+
// ├ [ ] repeated FieldDescriptorProto extension = 7;
37+
// ├ [ ] optional FileOptions options = 8;
38+
// ├ [ ] optional SourceCodeInfo source_code_info = 9;
39+
// └ [x] optional string syntax = 12;
2740

2841
/**
2942
* Creates a root from a descriptor set.
3043
* @param {FileDescriptorSet|Reader|Uint8Array} descriptor Descriptor
3144
* @returns {Root} Root instance
45+
* @see Part of the {@link descriptor} extension (ext/descriptor)
3246
*/
33-
protobuf.Root.fromDescriptor = function fromDescriptorSet(descriptor) {
47+
Root.fromDescriptor = function fromDescriptor(descriptor) {
48+
49+
// Decode the descriptor message if specified as a buffer:
50+
if (typeof descriptor.length === "number")
51+
descriptor = google.FileDescriptorSet.decode(descriptor);
52+
53+
var root = new Root();
54+
root.descriptorRoot = descriptor;
3455
throw Error("not implemented");
3556
};
3657

3758
/**
3859
* Converts a root to a descriptor set.
3960
* @returns {FileDescriptorSet} Descriptor
61+
* @param {string} [syntax="proto2"] Syntax
62+
* @see Part of the {@link descriptor} extension (ext/descriptor)
4063
*/
41-
protobuf.Root.prototype.toDescriptor = function toDescriptorSet() {
64+
Root.prototype.toDescriptor = function toDescriptor(syntax) {
4265
throw Error("not implemented");
4366
};
4467

45-
// Type
68+
// Type : DescriptorProto
69+
// ----------------------
70+
// [x] optional string name = 1;
71+
// [x] repeated FieldDescriptorProto field = 2;
72+
// [x] repeated FieldDescriptorProto extension = 6;
73+
// [x] repeated DescriptorProto nested_type = 3;
74+
// [x] repeated EnumDescriptorProto enum_type = 4;
75+
// [x] repeated ExtensionRange extension_range = 5;
76+
// ├ optional int32 start = 1;
77+
// └ optional int32 end = 2;
78+
// [x] repeated OneofDescriptorProto oneof_decl = 8;
79+
// [ ] optional MessageOptions options = 7;
80+
// └ [ ] optional bool map_entry = 7;
81+
// [x] repeated ReservedRange reserved_range = 9;
82+
// ├ optional int32 start = 1;
83+
// └ optional int32 end = 2;
84+
// [x] repeated string reserved_name = 10;
85+
86+
var unnamedMessageIndex = 0;
4687

4788
/**
4889
* Creates a type from a descriptor.
4990
* @param {DescriptorProto|Reader|Uint8Array} descriptor Descriptor
91+
* @param {string} [syntax="proto2"] Syntax
5092
* @returns {Type} Type instance
93+
* @see Part of the {@link descriptor} extension (ext/descriptor)
5194
*/
52-
protobuf.Type.fromDescriptor = function fromDescriptor(descriptor) {
95+
Type.fromDescriptor = function fromDescriptor(descriptor, syntax) {
5396

5497
// Decode the descriptor message if specified as a buffer:
5598
if (typeof descriptor.length === "number")
56-
descriptor = DescriptorProto.decode(reader);
99+
descriptor = google.DescriptorProto.decode(descriptor);
57100

58101
// Create the message type
59-
var type = new protobuf.Type(descriptor.name);
60-
61-
// Add fields
62-
descriptor.field.map(protobuf.Field.fromDescriptor).forEach(protobuf.Type.prototype.add.bind(type));
102+
var type = new Type(descriptor.name.length ? descriptor.name : "Unnamed" + unnamedMessageIndex++),
103+
i;
63104

64-
// etc.
105+
/* Fields */ for (i = 0; i < descriptor.field.length; ++i)
106+
type.add(protobuf.Field.fromDescriptor(descriptor.field[i], syntax));
107+
/* Extension fields */ for (i = 0; i < descriptor.extension.length; ++i)
108+
type.add(protobuf.Field.fromDescriptor(descriptor.extension[i], syntax));
109+
/* Oneofs */ for (i = 0; i < descriptor.oneofDecl.length; ++i)
110+
type.add(protobuf.OneOf.fromDescriptor(descriptor.oneofDecl[i]));
111+
/* Nested types */ for (i = 0; i < descriptor.nestedType.length; ++i)
112+
type.add(protobuf.Type.fromDescriptor(descriptor.nestedType[i], syntax));
113+
/* Nested enums */ for (i = 0; i < descriptor.enumType.length; ++i)
114+
type.add(protobuf.Enum.fromDescriptor(descriptor.enumType[i]));
115+
/* Extension ranges */ if (descriptor.extensionRange.length) {
116+
type.extensions = [];
117+
for (i = 0; i < descriptor.extensionRange.length; ++i)
118+
type.extensions.push([ descriptor.extensionRange[i].start, descriptor.extensionRange[i].end ]);
119+
}
120+
/* Reserved ranges and names */ if (descriptor.reservedRange.length || descriptor.reservedName.length) {
121+
type.reserved = [];
122+
for (i = 0; i < descriptor.reservedRange.length; ++i)
123+
type.reserved.push([ descriptor.reservedRange[i].start, descriptor.reservedRange[i].end ]);
124+
for (i = 0; i < descriptor.reservedName.length; ++i)
125+
type.reserved.push(descriptor.reservedName[i]);
126+
}
65127

66128
return type;
67129
};
68130

69131
/**
70132
* Converts a type to a descriptor.
71-
* @returns {DescriptorProto}
133+
* @returns {DescriptorProto} Descriptor
134+
* @param {string} [syntax="proto2"] Syntax
135+
* @see Part of the {@link descriptor} extension (ext/descriptor)
72136
*/
73-
protobuf.Type.prototype.toDescriptor = function toDescriptor() {
74-
throw Error("not implemented");
137+
Type.prototype.toDescriptor = function toDescriptor(syntax) {
138+
var descriptor = google.DescriptorProto.create({ name: this.name }),
139+
i;
140+
141+
/* Fields */ for (i = 0; i < this.fieldsArray.length; ++i)
142+
descriptor.field.push(this._fieldsArray[i].toDescriptor(syntax));
143+
/* Nested... */ for (i = 0; i < this.nestedArray.length; ++i) {
144+
var nested = this.nestedArray[i];
145+
/* Extension fields */ if (nested instanceof Field)
146+
descriptor.field.push(nested.toDescriptor(syntax));
147+
/* Oneofs */ else if (nested instanceof OneOf)
148+
descriptor.oneofDecl.push(nested.toDescriptor());
149+
/* Types */ else if (nested instanceof Type)
150+
descriptor.nestedType.push(nested.toDescriptor(syntax));
151+
/* Enums */ else if (nested instanceof Enum)
152+
descriptor.enumType.push(nested.toDescriptor());
153+
}
154+
/* Extension ranges */ if (this.extensions) for (i = 0; i < this.extensions.length; ++i)
155+
descriptor.extensionRange.push(google.DescriptorProto.ExtensionRange.create({ start: this.extensions[i][0], end: this.extensions[i][1] }));
156+
/* Reserved ranges and names */ if (this.reserved) for (i = 0; i < this.reserved.length; ++i)
157+
if (typeof this.reserved[i] === "string")
158+
descriptor.reservedName.push(this.reserved[i]);
159+
else
160+
descriptor.reservedRange.push(google.DescriptorProto.ReservedRange.create({ start: this.reserved[i][0], end: this.reserved[i][1] }));
161+
162+
return descriptor;
75163
};
76164

77-
// Field
165+
// Field : FieldDescriptorProto
166+
// ----------------------------
167+
// [x] optional string name = 1;
168+
// [x] optional int32 number = 3;
169+
// [x] optional Label label = 4;
170+
// ├ LABEL_OPTIONAL = 1;
171+
// ├ LABEL_REQUIRED = 2;
172+
// └ LABEL_REPEATED = 3;
173+
// [x] optional Type type = 5;
174+
// ├ TYPE_DOUBLE = 1;
175+
// ├ TYPE_FLOAT = 2;
176+
// ├ TYPE_INT64 = 3;
177+
// ├ TYPE_UINT64 = 4;
178+
// ├ TYPE_INT32 = 5;
179+
// ├ TYPE_FIXED64 = 6;
180+
// ├ TYPE_FIXED32 = 7;
181+
// ├ TYPE_BOOL = 8;
182+
// ├ TYPE_STRING = 9;
183+
// ├ TYPE_GROUP = 10;
184+
// ├ TYPE_MESSAGE = 11;
185+
// ├ TYPE_BYTES = 12;
186+
// ├ TYPE_UINT32 = 13;
187+
// ├ TYPE_ENUM = 14;
188+
// ├ TYPE_SFIXED32 = 15;
189+
// ├ TYPE_SFIXED64 = 16;
190+
// ├ TYPE_SINT32 = 17;
191+
// └ TYPE_SINT64 = 18;
192+
// [x] optional string type_name = 6;
193+
// [x] optional string extendee = 2;
194+
// [ ] optional string default_value = 7;
195+
// [ ] optional int32 oneof_index = 9;
196+
// [ ] optional string json_name = 10;
197+
// [~] optional FieldOptions options = 8;
198+
// └ [x] optional bool packed = 2;
78199

79200
/**
80201
* Creates a field from a descriptor.
81202
* @param {FieldDescriptorProto|Reader|Uint8Array} descriptor Descriptor
203+
* @param {string} [syntax="proto2"] Syntax
82204
* @returns {Field} Field instance
205+
* @see Part of the {@link descriptor} extension (ext/descriptor)
83206
*/
84-
protobuf.Field.fromDescriptor = function fromDescriptor(descriptor) {
85-
throw Error("not implemented");
207+
Field.fromDescriptor = function fromDescriptor(descriptor, syntax) {
208+
209+
// Decode the descriptor message if specified as a buffer:
210+
if (typeof descriptor.length === "number")
211+
descriptor = google.DescriptorProto.decode(descriptor);
212+
213+
// Rewire field type
214+
var fieldType;
215+
if (descriptor.type_name.length)
216+
fieldType = descriptor.type_name;
217+
else switch (descriptor.type) {
218+
// 0 is reserved for errors
219+
case 1: fieldType = "double"; break;
220+
case 2: fieldType = "float"; break;
221+
case 3: fieldType = "int64"; break;
222+
case 4: fieldType = "uint64"; break;
223+
case 5: fieldType = "int32"; break;
224+
case 6: fieldType = "fixed64"; break;
225+
case 7: fieldType = "fixed32"; break;
226+
case 8: fieldType = "bool"; break;
227+
case 9: fieldType = "string"; break;
228+
case 10: throw Error("unnamed group");
229+
case 11: throw Error("unnamed message");
230+
case 12: fieldType = "bytes"; break;
231+
case 13: fieldType = "uint32"; break;
232+
case 14: throw Error("unnamed enum");
233+
case 15: fieldType = "sfixed32"; break;
234+
case 16: fieldType = "sfixed64"; break;
235+
case 17: fieldType = "sint32"; break;
236+
case 18: fieldType = "sint64"; break;
237+
default: throw Error("illegal type: " + descriptor.type);
238+
}
239+
240+
// Rewire field rule
241+
var fieldRule;
242+
switch (descriptor.label) {
243+
// 0 is reserved for errors
244+
case 1: fieldRule = undefined; break;
245+
case 2: fieldRule = "required"; break;
246+
case 3: fieldRule = "repeated"; break;
247+
default: throw Error("illegal label: " + descriptor.label);
248+
}
249+
250+
var field = new Field(descriptor.name.length ? descriptor.name : "unnamed" + descriptor.number, descriptor.number, fieldType, fieldRule, descriptor.extendee.length ? descriptor.extendee : undefined);
251+
if (syntax === "proto3") {
252+
if (descriptor.options && !descriptor.options.packed)
253+
field.setOption("packed", false);
254+
} else if (!(descriptor.options && descriptor.options.packed))
255+
field.setOption("packed", false);
256+
return field;
86257
};
87258

88259
/**
89260
* Converts a field to a descriptor.
90261
* @returns {FieldDescriptorProto} Descriptor
262+
* @param {string} [syntax="proto2"] Syntax
263+
* @see Part of the {@link descriptor} extension (ext/descriptor)
91264
*/
92-
protobuf.Field.prototype.toDescriptor = function toDescriptor() {
93-
throw Error("not implemented");
265+
Field.prototype.toDescriptor = function toDescriptor(syntax) {
266+
var descriptor = google.FieldDescriptorProto.create({ name: this.name, number: this.id });
267+
268+
// Rewire field type
269+
switch (this.type) {
270+
case "double": descriptor.type = 1; break;
271+
case "float": descriptor.type = 2; break;
272+
case "int64": descriptor.type = 3; break;
273+
case "uint64": descriptor.type = 4; break;
274+
case "int32": descriptor.type = 5; break;
275+
case "fixed64": descriptor.type = 6; break;
276+
case "fixed32": descriptor.type = 7; break;
277+
case "bool": descriptor.type = 8; break;
278+
case "string": descriptor.type = 9; break;
279+
case "bytes": descriptor.type = 12; break;
280+
case "uint32": descriptor.type = 13; break;
281+
case "sfixed32": descriptor.type = 15; break;
282+
case "sfixed64": descriptor.type = 16; break;
283+
case "sint32": descriptor.type = 17; break;
284+
case "sint64": descriptor.type = 18; break;
285+
default:
286+
descriptor.type_name = this.resolvedType ? this.resolvedType.fullName : this.type;
287+
if (this.resolvedType instanceof Enum)
288+
descriptor.type = 14;
289+
else if (this.resolvedType instanceof Type)
290+
descriptor.type = this.resolvedType.group ? 10 : 11;
291+
else
292+
throw Error("illegal type: " + this.type);
293+
break;
294+
}
295+
296+
// Rewire field rule
297+
switch (this.rule) {
298+
case "repeated": descriptor.label = 3; break;
299+
case "required": descriptor.label = 2; break;
300+
default: descriptor.label = 1; break;
301+
}
302+
303+
descriptor.extendee = this.extensionField ? this.extensionField.parent.fullName : this.extend;
304+
305+
if (syntax === "proto3") {
306+
if (!this.packed)
307+
descriptor.options = new google.FieldOptions({ packed: false });
308+
} else if (this.packed)
309+
descriptor.options = new google.FieldOptions({ packed: true });
310+
311+
return descriptor;
94312
};
313+
314+
// Enum : EnumDescriptorProto
315+
// --------------------------
316+
// [ ] optional string name = 1;
317+
// [ ] repeated EnumValueDescriptorProto value = 2;
318+
// ├ [ ] optional string name = 1;
319+
// ├ [ ] optional int32 number = 2;
320+
// └ [ ] optional EnumValueOptions options = 3;
321+
// [ ] optional EnumOptions options = 3;
322+
// └ [ ] optional bool allow_alias = 2;
323+
324+
// OneOf : OneofDescriptorProto
325+
// ----------------------------
326+
// [ ] optional string name = 1;
327+
// [ ] optional OneofOptions options = 2;
328+
329+
// Service : ServiceDescriptorProto
330+
// --------------------------------
331+
// [ ] optional string name = 1;
332+
// [ ] repeated MethodDescriptorProto method = 2;
333+
// [ ] optional ServiceOptions options = 3;
334+
335+
// Method: MethodDescriptorProto
336+
// -----------------------------
337+
// [ ] optional string name = 1;
338+
// [ ] optional string input_type = 2;
339+
// [ ] optional string output_type = 3;
340+
// [ ] optional MethodOptions options = 4;
341+
// [ ] optional bool client_streaming = 5;
342+
// [ ] optional bool server_streaming = 6;

0 commit comments

Comments
 (0)