|
1 | | -// Extension for reflection interoperability with descriptor.proto types |
| 1 | +// [WIP] Extension for reflection interoperability with descriptor.proto types |
2 | 2 | // var protobuf = require("protobufjs"), |
3 | 3 | // descriptor = require("protobufjs/ext/descriptor"); |
4 | 4 | // ... |
|
7 | 7 | var protobuf = require(".."); |
8 | 8 |
|
9 | 9 | /** |
10 | | - * Descriptor extension. |
| 10 | + * Descriptor extension (ext/descriptor). |
11 | 11 | * @namespace |
12 | 12 | * @property {Type} FileDescriptorSet Descriptor set describing a root |
13 | 13 | * @property {Type} DescriptorProto Descriptor describing a type |
14 | 14 | * @property {Type} FieldDescriptorProto Descriptor describing a field |
15 | 15 | */ |
16 | 16 | var descriptor = module.exports = protobuf.Root.fromJSON(require("../google/protobuf/descriptor.json")).lookup(".google.protobuf"); |
17 | 17 |
|
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; |
21 | 24 |
|
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; |
27 | 40 |
|
28 | 41 | /** |
29 | 42 | * Creates a root from a descriptor set. |
30 | 43 | * @param {FileDescriptorSet|Reader|Uint8Array} descriptor Descriptor |
31 | 44 | * @returns {Root} Root instance |
| 45 | + * @see Part of the {@link descriptor} extension (ext/descriptor) |
32 | 46 | */ |
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; |
34 | 55 | throw Error("not implemented"); |
35 | 56 | }; |
36 | 57 |
|
37 | 58 | /** |
38 | 59 | * Converts a root to a descriptor set. |
39 | 60 | * @returns {FileDescriptorSet} Descriptor |
| 61 | + * @param {string} [syntax="proto2"] Syntax |
| 62 | + * @see Part of the {@link descriptor} extension (ext/descriptor) |
40 | 63 | */ |
41 | | -protobuf.Root.prototype.toDescriptor = function toDescriptorSet() { |
| 64 | +Root.prototype.toDescriptor = function toDescriptor(syntax) { |
42 | 65 | throw Error("not implemented"); |
43 | 66 | }; |
44 | 67 |
|
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; |
46 | 87 |
|
47 | 88 | /** |
48 | 89 | * Creates a type from a descriptor. |
49 | 90 | * @param {DescriptorProto|Reader|Uint8Array} descriptor Descriptor |
| 91 | + * @param {string} [syntax="proto2"] Syntax |
50 | 92 | * @returns {Type} Type instance |
| 93 | + * @see Part of the {@link descriptor} extension (ext/descriptor) |
51 | 94 | */ |
52 | | -protobuf.Type.fromDescriptor = function fromDescriptor(descriptor) { |
| 95 | +Type.fromDescriptor = function fromDescriptor(descriptor, syntax) { |
53 | 96 |
|
54 | 97 | // Decode the descriptor message if specified as a buffer: |
55 | 98 | if (typeof descriptor.length === "number") |
56 | | - descriptor = DescriptorProto.decode(reader); |
| 99 | + descriptor = google.DescriptorProto.decode(descriptor); |
57 | 100 |
|
58 | 101 | // 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; |
63 | 104 |
|
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 | + } |
65 | 127 |
|
66 | 128 | return type; |
67 | 129 | }; |
68 | 130 |
|
69 | 131 | /** |
70 | 132 | * 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) |
72 | 136 | */ |
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; |
75 | 163 | }; |
76 | 164 |
|
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; |
78 | 199 |
|
79 | 200 | /** |
80 | 201 | * Creates a field from a descriptor. |
81 | 202 | * @param {FieldDescriptorProto|Reader|Uint8Array} descriptor Descriptor |
| 203 | + * @param {string} [syntax="proto2"] Syntax |
82 | 204 | * @returns {Field} Field instance |
| 205 | + * @see Part of the {@link descriptor} extension (ext/descriptor) |
83 | 206 | */ |
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; |
86 | 257 | }; |
87 | 258 |
|
88 | 259 | /** |
89 | 260 | * Converts a field to a descriptor. |
90 | 261 | * @returns {FieldDescriptorProto} Descriptor |
| 262 | + * @param {string} [syntax="proto2"] Syntax |
| 263 | + * @see Part of the {@link descriptor} extension (ext/descriptor) |
91 | 264 | */ |
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; |
94 | 312 | }; |
| 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