protobufjs 8.6.0 → 8.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ext/README.md CHANGED
@@ -21,7 +21,7 @@ const decodedRoot = protobuf.Root.fromDescriptor(buffer);
21
21
 
22
22
  The extension requires reflection metadata and also works with `protobufjs/light.js` when schemas are loaded from JSON or otherwise provided as reflection objects.
23
23
 
24
- Importing the extension adds `.fromDescriptor(descriptor[, syntaxOrEdition])` and `#toDescriptor([syntaxOrEdition])` methods to reflection objects and exports the bundled descriptor types from `google.protobuf`. Descriptor inputs can be decoded messages, readers, or buffers of the corresponding descriptor messages.
24
+ Importing the extension adds `.fromDescriptor(descriptor[, editionOrContext])` and `#toDescriptor([syntaxOrEdition])` methods to reflection objects and exports the bundled descriptor types from `google.protobuf`. Descriptor inputs can be decoded messages, readers, or buffers of the corresponding descriptor messages. Direct object descriptor imports accept either an edition string or a descriptor context with `edition`, `features` and `keepCase`.
25
25
 
26
26
  The conversion covers descriptor messages that correspond to protobuf.js reflection objects: files and file sets, messages, fields and map fields, oneofs, enums, services and methods. Descriptor-only metadata such as source locations, generated-code annotations and uninterpreted options remains available through the exported descriptor message types, but is not mapped onto reflection objects. File names are inferred when generating descriptors because roots do not retain exact file/package boundaries.
27
27
 
@@ -1,6 +1,7 @@
1
1
  import * as $protobuf from "..";
2
2
  import {
3
3
  IDescriptorProto,
4
+ IDescriptorContext,
4
5
  IEnumDescriptorProto,
5
6
  IFieldDescriptorProto,
6
7
  IFileDescriptorSet,
@@ -16,7 +17,7 @@ type DescriptorInput<T> = T | $protobuf.Reader | Uint8Array;
16
17
  declare module ".." {
17
18
  namespace Root {
18
19
  /** Creates a root from a descriptor set. */
19
- function fromDescriptor(descriptor: DescriptorInput<IFileDescriptorSet>): $protobuf.Root;
20
+ function fromDescriptor(descriptor: DescriptorInput<IFileDescriptorSet>, options?: { keepCase?: boolean }): $protobuf.Root;
20
21
  }
21
22
 
22
23
  interface Root {
@@ -26,7 +27,7 @@ declare module ".." {
26
27
 
27
28
  namespace Type {
28
29
  /** Creates a type from a descriptor. */
29
- function fromDescriptor(descriptor: DescriptorInput<IDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Type;
30
+ function fromDescriptor(descriptor: DescriptorInput<IDescriptorProto>, editionOrContext?: string | IDescriptorContext): $protobuf.Type;
30
31
  }
31
32
 
32
33
  interface Type {
@@ -36,7 +37,7 @@ declare module ".." {
36
37
 
37
38
  namespace Field {
38
39
  /** Creates a field from a descriptor. */
39
- function fromDescriptor(descriptor: DescriptorInput<IFieldDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Field;
40
+ function fromDescriptor(descriptor: DescriptorInput<IFieldDescriptorProto>, editionOrContext?: string | IDescriptorContext): $protobuf.Field;
40
41
  }
41
42
 
42
43
  interface Field {
@@ -46,7 +47,7 @@ declare module ".." {
46
47
 
47
48
  namespace Enum {
48
49
  /** Creates an enum from a descriptor. */
49
- function fromDescriptor(descriptor: DescriptorInput<IEnumDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Enum;
50
+ function fromDescriptor(descriptor: DescriptorInput<IEnumDescriptorProto>, editionOrContext?: string | IDescriptorContext): $protobuf.Enum;
50
51
  }
51
52
 
52
53
  interface Enum {
@@ -56,7 +57,7 @@ declare module ".." {
56
57
 
57
58
  namespace OneOf {
58
59
  /** Creates a oneof from a descriptor. */
59
- function fromDescriptor(descriptor: DescriptorInput<IOneofDescriptorProto>): $protobuf.OneOf;
60
+ function fromDescriptor(descriptor: DescriptorInput<IOneofDescriptorProto>, editionOrContext?: string | IDescriptorContext): $protobuf.OneOf;
60
61
  }
61
62
 
62
63
  interface OneOf {
@@ -66,7 +67,7 @@ declare module ".." {
66
67
 
67
68
  namespace Service {
68
69
  /** Creates a service from a descriptor. */
69
- function fromDescriptor(descriptor: DescriptorInput<IServiceDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Service;
70
+ function fromDescriptor(descriptor: DescriptorInput<IServiceDescriptorProto>, editionOrContext?: string | IDescriptorContext): $protobuf.Service;
70
71
  }
71
72
 
72
73
  interface Service {
@@ -76,7 +77,7 @@ declare module ".." {
76
77
 
77
78
  namespace Method {
78
79
  /** Creates a method from a descriptor. */
79
- function fromDescriptor(descriptor: DescriptorInput<IMethodDescriptorProto>): $protobuf.Method;
80
+ function fromDescriptor(descriptor: DescriptorInput<IMethodDescriptorProto>, editionOrContext?: string | IDescriptorContext): $protobuf.Method;
80
81
  }
81
82
 
82
83
  interface Method {
@@ -170,6 +170,19 @@ export interface IFileOptions {
170
170
  /** Values of he FileOptions.OptimizeMode enum. */
171
171
  export type IFileOptionsOptimizeMode = number;
172
172
 
173
+ /** Descriptor context. */
174
+ export interface IDescriptorContext {
175
+
176
+ /** Syntax or edition to use for direct object descriptor imports */
177
+ edition?: string;
178
+
179
+ /** File-level features to apply for direct object descriptor imports */
180
+ features?: IFeatureSet;
181
+
182
+ /** Uses proto field names as reflected field names */
183
+ keepCase?: boolean;
184
+ }
185
+
173
186
  /** Properties of a DescriptorProto message. */
174
187
  export interface IDescriptorProto {
175
188
 
@@ -398,12 +411,7 @@ export interface IMethodDescriptorProto {
398
411
  serverStreaming?: boolean;
399
412
  }
400
413
 
401
- /**
402
- * Properties of a MethodOptions message.
403
- *
404
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
405
- *
406
- */
414
+ /** Properties of a MethodOptions message. */
407
415
  export interface IMethodOptions {
408
416
  deprecated?: boolean;
409
417
  }
package/ext/descriptor.js CHANGED
@@ -88,14 +88,24 @@ var numberRe = patterns.numberRe,
88
88
  * @property {number} LITE_RUNTIME=3
89
89
  */
90
90
 
91
+ /**
92
+ * Descriptor context.
93
+ * @interface IDescriptorContext
94
+ * @property {string} [edition="proto2"] Syntax or edition to use for direct object descriptor imports
95
+ * @property {IFeatureSet} [features] File-level features to apply for direct object descriptor imports
96
+ * @property {boolean} [keepCase=false] Uses proto field names as reflected field names
97
+ */
98
+
91
99
  /**
92
100
  * Creates a root from a descriptor set.
93
101
  * @param {IFileDescriptorSet|Reader|Uint8Array} descriptor Descriptor
102
+ * @param {{keepCase?: boolean}} [options] Conversion options
94
103
  * @returns {Root} Root instance
95
104
  */
96
- Root.fromDescriptor = function fromDescriptor(descriptor) {
105
+ Root.fromDescriptor = function fromDescriptor(descriptor, options) {
97
106
 
98
107
  descriptor = decodeDescriptor(descriptor, exports.FileDescriptorSet);
108
+ options = options || {};
99
109
 
100
110
  var root = new Root();
101
111
 
@@ -106,26 +116,35 @@ Root.fromDescriptor = function fromDescriptor(descriptor) {
106
116
  filePackage = root;
107
117
  if ((fileDescriptor = descriptor.file[j])["package"] && fileDescriptor["package"].length)
108
118
  filePackage = root.define(fileDescriptor["package"]);
109
- var edition = editionFromDescriptor(fileDescriptor);
119
+ var fileOptions = fromDescriptorOptions(fileDescriptor.options, exports.FileOptions),
120
+ ctx = descriptorContext({
121
+ edition: editionFromDescriptor(fileDescriptor),
122
+ features: fileOptions && fileOptions.features,
123
+ keepCase: options && options.keepCase
124
+ });
110
125
  if (fileDescriptor.name && fileDescriptor.name.length)
111
126
  root.files.push(filePackage.filename = fileDescriptor.name);
127
+ var groupTypes = groupTypeNames(fileDescriptor.extension);
112
128
  if (fileDescriptor.messageType)
113
- for (i = 0; i < fileDescriptor.messageType.length; ++i)
114
- filePackage.add(Type.fromDescriptor(fileDescriptor.messageType[i], edition));
129
+ for (i = 0; i < fileDescriptor.messageType.length; ++i) {
130
+ var type = Type_fromDescriptor(fileDescriptor.messageType[i], ctx, false, 0);
131
+ if (groupTypes[type.name])
132
+ type.group = true;
133
+ filePackage.add(type);
134
+ }
115
135
  if (fileDescriptor.enumType)
116
136
  for (i = 0; i < fileDescriptor.enumType.length; ++i)
117
- filePackage.add(Enum.fromDescriptor(fileDescriptor.enumType[i], edition));
137
+ filePackage.add(Enum_fromDescriptor(fileDescriptor.enumType[i], ctx, false));
118
138
  if (fileDescriptor.extension)
119
139
  for (i = 0; i < fileDescriptor.extension.length; ++i)
120
- filePackage.add(Field.fromDescriptor(fileDescriptor.extension[i], edition));
140
+ filePackage.add(Field_fromDescriptor(fileDescriptor.extension[i], ctx, false));
121
141
  if (fileDescriptor.service)
122
142
  for (i = 0; i < fileDescriptor.service.length; ++i)
123
- filePackage.add(Service.fromDescriptor(fileDescriptor.service[i], edition));
124
- var opts = fromDescriptorOptions(fileDescriptor.options, exports.FileOptions);
125
- if (opts) {
126
- var ks = Object.keys(opts);
143
+ filePackage.add(Service_fromDescriptor(fileDescriptor.service[i], ctx, false));
144
+ if (fileOptions) {
145
+ var ks = Object.keys(fileOptions);
127
146
  for (i = 0; i < ks.length; ++i)
128
- filePackage.setOption(ks[i], opts[ks[i]]);
147
+ filePackage.setOption(ks[i], fileOptions[ks[i]]);
129
148
  }
130
149
  }
131
150
  }
@@ -215,16 +234,15 @@ var unnamedMessageIndex = 0;
215
234
 
216
235
  /**
217
236
  * Creates a type from a descriptor.
218
- *
219
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
220
- *
221
237
  * @param {IDescriptorProto|Reader|Uint8Array} descriptor Descriptor
222
- * @param {string} [edition="proto2"] The syntax or edition to use
223
- * @param {boolean} [nested=false] Whether or not this is a nested object
224
- * @param {number} [depth] Current nesting depth, defaults to `0`
238
+ * @param {string|IDescriptorContext} [editionOrContext="proto2"] Syntax/edition shorthand or descriptor context
225
239
  * @returns {Type} Type instance
226
240
  */
227
- Type.fromDescriptor = function fromDescriptor(descriptor, edition, nested, depth) {
241
+ Type.fromDescriptor = function fromDescriptor(descriptor, editionOrContext) {
242
+ return Type_fromDescriptor(descriptor, descriptorContext(editionOrContext), false, 0);
243
+ };
244
+
245
+ function Type_fromDescriptor(descriptor, ctx, nested, depth) {
228
246
  if (depth === undefined)
229
247
  depth = 0;
230
248
  if (depth > $protobuf.util.nestingLimit)
@@ -235,36 +253,43 @@ Type.fromDescriptor = function fromDescriptor(descriptor, edition, nested, depth
235
253
  i,
236
254
  mapEntries = {};
237
255
 
238
- if (!nested)
239
- type._edition = edition;
256
+ if (!nested) {
257
+ type._edition = ctx.edition;
258
+ applyContextFeatures(type, ctx);
259
+ }
240
260
 
241
261
  if (descriptor.nestedType)
242
262
  for (i = 0; i < descriptor.nestedType.length; ++i)
243
263
  if (descriptor.nestedType[i].options && descriptor.nestedType[i].options.mapEntry)
244
264
  mapEntries[descriptor.nestedType[i].name] = descriptor.nestedType[i];
245
265
 
266
+ var groupTypes = groupTypeNames(descriptor.field, descriptor.extension);
267
+
246
268
  /* Oneofs */ if (descriptor.oneofDecl)
247
269
  for (i = 0; i < descriptor.oneofDecl.length; ++i)
248
- type.add(OneOf.fromDescriptor(descriptor.oneofDecl[i]));
270
+ type.add(OneOf_fromDescriptor(descriptor.oneofDecl[i], ctx, true));
249
271
  /* Fields */ if (descriptor.field)
250
272
  for (i = 0; i < descriptor.field.length; ++i) {
251
- var field = FieldBase_fromDescriptor(descriptor.field[i], edition, true, mapEntries);
273
+ var field = FieldBase_fromDescriptor(descriptor.field[i], ctx, true, mapEntries);
252
274
  type.add(field);
253
275
  if (descriptor.field[i].hasOwnProperty("oneofIndex")) // eslint-disable-line no-prototype-builtins
254
276
  type.oneofsArray[descriptor.field[i].oneofIndex].add(field);
255
277
  }
256
278
  /* Extension fields */ if (descriptor.extension)
257
279
  for (i = 0; i < descriptor.extension.length; ++i)
258
- type.add(Field.fromDescriptor(descriptor.extension[i], edition, true));
280
+ type.add(Field_fromDescriptor(descriptor.extension[i], ctx, true));
259
281
  /* Nested types */ if (descriptor.nestedType)
260
282
  for (i = 0; i < descriptor.nestedType.length; ++i) {
261
283
  if (descriptor.nestedType[i].options && descriptor.nestedType[i].options.mapEntry)
262
284
  continue;
263
- type.add(Type.fromDescriptor(descriptor.nestedType[i], edition, true, depth + 1));
285
+ var nestedType = Type_fromDescriptor(descriptor.nestedType[i], ctx, true, depth + 1);
286
+ if (groupTypes[nestedType.name])
287
+ nestedType.group = true;
288
+ type.add(nestedType);
264
289
  }
265
290
  /* Nested enums */ if (descriptor.enumType)
266
291
  for (i = 0; i < descriptor.enumType.length; ++i)
267
- type.add(Enum.fromDescriptor(descriptor.enumType[i], edition, true));
292
+ type.add(Enum_fromDescriptor(descriptor.enumType[i], ctx, true));
268
293
  /* Extension ranges */ if (descriptor.extensionRange && descriptor.extensionRange.length) {
269
294
  type.extensions = [];
270
295
  for (i = 0; i < descriptor.extensionRange.length; ++i)
@@ -281,7 +306,7 @@ Type.fromDescriptor = function fromDescriptor(descriptor, edition, nested, depth
281
306
  }
282
307
 
283
308
  return type;
284
- };
309
+ }
285
310
 
286
311
  /**
287
312
  * Converts a type to a descriptor.
@@ -339,15 +364,31 @@ Type.prototype.toDescriptor = function toDescriptor(edition) {
339
364
 
340
365
  // --- FieldBase ---
341
366
 
342
- function FieldBase_fromDescriptor(descriptor, edition, nested, mapEntries) {
367
+ function FieldBase_fromDescriptor(descriptor, ctx, nested, mapEntries) {
343
368
  var entryName = descriptor.typeName && descriptor.typeName.substring(descriptor.typeName.lastIndexOf(".") + 1),
344
369
  mapEntry = descriptor.label === 3 && descriptor.type === 11 && entryName
345
370
  ? mapEntries[entryName]
346
371
  : null;
347
372
 
348
373
  return mapEntry
349
- ? MapField_fromDescriptor(descriptor, mapEntry)
350
- : Field.fromDescriptor(descriptor, edition, nested);
374
+ ? MapField_fromDescriptor(descriptor, mapEntry, ctx)
375
+ : Field_fromDescriptor(descriptor, ctx, nested);
376
+ }
377
+
378
+ function fieldNameFromDescriptor(descriptor, ctx) {
379
+ return ctx.keepCase && descriptor.name.length
380
+ ? descriptor.name
381
+ : descriptor.jsonName && descriptor.jsonName.length
382
+ ? descriptor.jsonName
383
+ : descriptor.name.length ? descriptor.name : "field" + descriptor.number;
384
+ }
385
+
386
+ function applyFieldNamesFromDescriptor(field, descriptor) {
387
+ if (descriptor.name.length && descriptor.name !== field.name)
388
+ field.protoName = descriptor.name;
389
+ if (descriptor.jsonName && descriptor.jsonName.length)
390
+ field.jsonName = descriptor.jsonName;
391
+ return field;
351
392
  }
352
393
 
353
394
  // --- Field ---
@@ -419,16 +460,15 @@ function FieldBase_fromDescriptor(descriptor, edition, nested, mapEntries) {
419
460
 
420
461
  /**
421
462
  * Creates a field from a descriptor.
422
- *
423
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
424
- *
425
463
  * @param {IFieldDescriptorProto|Reader|Uint8Array} descriptor Descriptor
426
- * @param {string} [edition="proto2"] The syntax or edition to use
427
- * @param {boolean} [nested=false] Whether or not this is a top-level object
464
+ * @param {string|IDescriptorContext} [editionOrContext="proto2"] Syntax/edition shorthand or descriptor context
428
465
  * @returns {Field} Field instance
429
466
  */
430
- Field.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
467
+ Field.fromDescriptor = function fromDescriptor(descriptor, editionOrContext) {
468
+ return Field_fromDescriptor(descriptor, descriptorContext(editionOrContext), false);
469
+ };
431
470
 
471
+ function Field_fromDescriptor(descriptor, ctx, nested) {
432
472
  descriptor = decodeDescriptor(descriptor, exports.FieldDescriptorProto);
433
473
 
434
474
  if (typeof descriptor.number !== "number")
@@ -460,27 +500,20 @@ Field.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
460
500
  throw Error("illegal type name: " + extendee);
461
501
  } else
462
502
  extendee = undefined;
463
- // Prefer json_name as the JS field name when present, while retaining both
464
- // descriptor names for round-tripping and ProtoJSON lookup.
465
- var fieldName = descriptor.jsonName && descriptor.jsonName.length
466
- ? descriptor.jsonName
467
- : descriptor.name.length ? descriptor.name : "field" + descriptor.number;
468
- var field = new Field(
469
- fieldName,
503
+ var field = applyFieldNamesFromDescriptor(new Field(
504
+ fieldNameFromDescriptor(descriptor, ctx),
470
505
  descriptor.number,
471
506
  fieldType,
472
507
  fieldRule,
473
508
  extendee
474
- );
475
- if (descriptor.name.length && descriptor.name !== fieldName)
476
- field.protoName = descriptor.name;
477
- if (descriptor.jsonName && descriptor.jsonName.length)
478
- field.jsonName = descriptor.jsonName;
509
+ ), descriptor);
479
510
 
480
511
  if (!nested)
481
- field._edition = edition;
512
+ field._edition = ctx.edition;
482
513
 
483
514
  field.options = fromDescriptorOptions(descriptor.options, exports.FieldOptions);
515
+ if (!nested)
516
+ applyContextFeatures(field, ctx);
484
517
  if (descriptor.proto3Optional || descriptor.proto3_optional)
485
518
  (field.options || (field.options = {})).proto3_optional = true;
486
519
 
@@ -502,20 +535,12 @@ Field.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
502
535
  field.setOption("default", defaultValue);
503
536
  }
504
537
 
505
- if (packableDescriptorType(descriptor.type)) {
506
- if (edition === "proto3") { // defaults to packed=true (internal preset is packed=true)
507
- if (descriptor.options && !descriptor.options.packed)
508
- field.setOption("packed", false);
509
- } else if ((!edition || edition === "proto2") && descriptor.options && descriptor.options.packed) // defaults to packed=false
510
- field.setOption("packed", true);
511
- }
512
-
513
538
  return field;
514
- };
539
+ }
515
540
 
516
541
  // --- MapField ---
517
542
 
518
- function MapField_fromDescriptor(descriptor, entryDescriptor) {
543
+ function MapField_fromDescriptor(descriptor, entryDescriptor, ctx) {
519
544
  function entryField(number) {
520
545
  if (entryDescriptor.field)
521
546
  for (var i = 0; i < entryDescriptor.field.length; ++i)
@@ -530,13 +555,13 @@ function MapField_fromDescriptor(descriptor, entryDescriptor) {
530
555
  ? valueDescriptor.typeName
531
556
  : fromDescriptorType(valueDescriptor.type);
532
557
 
533
- return new MapField(
534
- descriptor.name.length ? descriptor.name : "field" + descriptor.number,
558
+ return applyFieldNamesFromDescriptor(new MapField(
559
+ fieldNameFromDescriptor(descriptor, ctx),
535
560
  descriptor.number,
536
561
  fromDescriptorType(keyDescriptor.type),
537
562
  valueType,
538
563
  fromDescriptorOptions(descriptor.options, exports.FieldOptions)
539
- );
564
+ ), descriptor);
540
565
  }
541
566
 
542
567
  /**
@@ -658,16 +683,15 @@ var unnamedEnumIndex = 0;
658
683
 
659
684
  /**
660
685
  * Creates an enum from a descriptor.
661
- *
662
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
663
- *
664
686
  * @param {IEnumDescriptorProto|Reader|Uint8Array} descriptor Descriptor
665
- * @param {string} [edition="proto2"] The syntax or edition to use
666
- * @param {boolean} [nested=false] Whether or not this is a top-level object
687
+ * @param {string|IDescriptorContext} [editionOrContext="proto2"] Syntax/edition shorthand or descriptor context
667
688
  * @returns {Enum} Enum instance
668
689
  */
669
- Enum.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
690
+ Enum.fromDescriptor = function fromDescriptor(descriptor, editionOrContext) {
691
+ return Enum_fromDescriptor(descriptor, descriptorContext(editionOrContext), false);
692
+ };
670
693
 
694
+ function Enum_fromDescriptor(descriptor, ctx, nested) {
671
695
  descriptor = decodeDescriptor(descriptor, exports.EnumDescriptorProto);
672
696
 
673
697
  // Construct values object
@@ -694,8 +718,10 @@ Enum.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
694
718
  valuesOptions
695
719
  );
696
720
 
697
- if (!nested)
698
- enm._edition = edition;
721
+ if (!nested) {
722
+ enm._edition = ctx.edition;
723
+ applyContextFeatures(enm, ctx);
724
+ }
699
725
 
700
726
  /* Reserved... */ if (descriptor.reservedRange && descriptor.reservedRange.length || descriptor.reservedName && descriptor.reservedName.length) {
701
727
  enm.reserved = [];
@@ -708,7 +734,7 @@ Enum.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
708
734
  }
709
735
 
710
736
  return enm;
711
- };
737
+ }
712
738
 
713
739
  /**
714
740
  * Converts an enum to a descriptor.
@@ -763,22 +789,28 @@ var unnamedOneofIndex = 0;
763
789
 
764
790
  /**
765
791
  * Creates a oneof from a descriptor.
766
- *
767
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
768
- *
769
792
  * @param {IOneofDescriptorProto|Reader|Uint8Array} descriptor Descriptor
793
+ * @param {string|IDescriptorContext} [editionOrContext="proto2"] Syntax/edition shorthand or descriptor context
770
794
  * @returns {OneOf} OneOf instance
771
795
  */
772
- OneOf.fromDescriptor = function fromDescriptor(descriptor) {
796
+ OneOf.fromDescriptor = function fromDescriptor(descriptor, editionOrContext) {
797
+ return OneOf_fromDescriptor(descriptor, descriptorContext(editionOrContext), false);
798
+ };
773
799
 
800
+ function OneOf_fromDescriptor(descriptor, ctx, nested) {
774
801
  descriptor = decodeDescriptor(descriptor, exports.OneofDescriptorProto);
775
802
 
776
- return new OneOf(
803
+ var oneof = new OneOf(
777
804
  // unnamedOneOfIndex is global, not per type, because we have no ref to a type here
778
805
  descriptor.name && descriptor.name.length ? descriptor.name : "oneof" + unnamedOneofIndex++,
779
806
  fromDescriptorOptions(descriptor.options, exports.OneofOptions)
780
807
  );
781
- };
808
+ if (!nested) {
809
+ oneof._edition = ctx.edition;
810
+ applyContextFeatures(oneof, ctx);
811
+ }
812
+ return oneof;
813
+ }
782
814
 
783
815
  /**
784
816
  * Converts a oneof to a descriptor.
@@ -811,27 +843,28 @@ var unnamedServiceIndex = 0;
811
843
 
812
844
  /**
813
845
  * Creates a service from a descriptor.
814
- *
815
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
816
- *
817
846
  * @param {IServiceDescriptorProto|Reader|Uint8Array} descriptor Descriptor
818
- * @param {string} [edition="proto2"] The syntax or edition to use
819
- * @param {boolean} [nested=false] Whether or not this is a top-level object
847
+ * @param {string|IDescriptorContext} [editionOrContext="proto2"] Syntax/edition shorthand or descriptor context
820
848
  * @returns {Service} Service instance
821
849
  */
822
- Service.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
850
+ Service.fromDescriptor = function fromDescriptor(descriptor, editionOrContext) {
851
+ return Service_fromDescriptor(descriptor, descriptorContext(editionOrContext), false);
852
+ };
823
853
 
854
+ function Service_fromDescriptor(descriptor, ctx, nested) {
824
855
  descriptor = decodeDescriptor(descriptor, exports.ServiceDescriptorProto);
825
856
 
826
857
  var service = new Service(descriptor.name && descriptor.name.length ? descriptor.name : "Service" + unnamedServiceIndex++, fromDescriptorOptions(descriptor.options, exports.ServiceOptions));
827
- if (!nested)
828
- service._edition = edition;
858
+ if (!nested) {
859
+ service._edition = ctx.edition;
860
+ applyContextFeatures(service, ctx);
861
+ }
829
862
  if (descriptor.method)
830
863
  for (var i = 0; i < descriptor.method.length; ++i)
831
- service.add(Method.fromDescriptor(descriptor.method[i]));
864
+ service.add(Method_fromDescriptor(descriptor.method[i], ctx, true));
832
865
 
833
866
  return service;
834
- };
867
+ }
835
868
 
836
869
  /**
837
870
  * Converts a service to a descriptor.
@@ -866,9 +899,6 @@ Service.prototype.toDescriptor = function toDescriptor() {
866
899
 
867
900
  /**
868
901
  * Properties of a MethodOptions message.
869
- *
870
- * Warning: this is not safe to use with editions protos, since it discards relevant file context.
871
- *
872
902
  * @interface IMethodOptions
873
903
  * @property {boolean} [deprecated]
874
904
  */
@@ -878,10 +908,14 @@ var unnamedMethodIndex = 0;
878
908
  /**
879
909
  * Creates a method from a descriptor.
880
910
  * @param {IMethodDescriptorProto|Reader|Uint8Array} descriptor Descriptor
911
+ * @param {string|IDescriptorContext} [editionOrContext="proto2"] Syntax/edition shorthand or descriptor context
881
912
  * @returns {Method} Reflected method instance
882
913
  */
883
- Method.fromDescriptor = function fromDescriptor(descriptor) {
914
+ Method.fromDescriptor = function fromDescriptor(descriptor, editionOrContext) {
915
+ return Method_fromDescriptor(descriptor, descriptorContext(editionOrContext), false);
916
+ };
884
917
 
918
+ function Method_fromDescriptor(descriptor, ctx, nested) {
885
919
  descriptor = decodeDescriptor(descriptor, exports.MethodDescriptorProto);
886
920
 
887
921
  var inputType = descriptor.inputType,
@@ -896,7 +930,7 @@ Method.fromDescriptor = function fromDescriptor(descriptor) {
896
930
  throw Error("illegal type name: " + outputType);
897
931
  }
898
932
 
899
- return new Method(
933
+ var method = new Method(
900
934
  // unnamedMethodIndex is global, not per service, because we have no ref to a service here
901
935
  descriptor.name && descriptor.name.length ? descriptor.name : "Method" + unnamedMethodIndex++,
902
936
  "rpc",
@@ -906,7 +940,12 @@ Method.fromDescriptor = function fromDescriptor(descriptor) {
906
940
  Boolean(descriptor.serverStreaming),
907
941
  fromDescriptorOptions(descriptor.options, exports.MethodOptions)
908
942
  );
909
- };
943
+ if (!nested) {
944
+ method._edition = ctx.edition;
945
+ applyContextFeatures(method, ctx);
946
+ }
947
+ return method;
948
+ }
910
949
 
911
950
  /**
912
951
  * Converts a method to a descriptor.
@@ -925,6 +964,24 @@ Method.prototype.toDescriptor = function toDescriptor() {
925
964
 
926
965
  // --- utility ---
927
966
 
967
+ function descriptorContext(editionOrContext) {
968
+ if (editionOrContext && typeof editionOrContext === "object") {
969
+ var ctx = $protobuf.util.merge({}, editionOrContext);
970
+ if (!ctx.edition)
971
+ ctx.edition = "proto2";
972
+ return ctx;
973
+ }
974
+ return { edition: editionOrContext || "proto2" };
975
+ }
976
+
977
+ function applyContextFeatures(object, ctx) {
978
+ if (!ctx.features)
979
+ return object;
980
+ var options = object.options || (object.options = {});
981
+ options.features = $protobuf.util.merge({}, ctx.features, options.features);
982
+ return object;
983
+ }
984
+
928
985
  // Converts a descriptor type to a protobuf.js basic type
929
986
  function fromDescriptorType(type) {
930
987
  switch (type) {
@@ -948,26 +1005,20 @@ function fromDescriptorType(type) {
948
1005
  throw Error("illegal type: " + type);
949
1006
  }
950
1007
 
951
- // Tests if a descriptor type is packable
952
- function packableDescriptorType(type) {
953
- switch (type) {
954
- case 1: // double
955
- case 2: // float
956
- case 3: // int64
957
- case 4: // uint64
958
- case 5: // int32
959
- case 6: // fixed64
960
- case 7: // fixed32
961
- case 8: // bool
962
- case 13: // uint32
963
- case 14: // enum (!)
964
- case 15: // sfixed32
965
- case 16: // sfixed64
966
- case 17: // sint32
967
- case 18: // sint64
968
- return true;
1008
+ function groupTypeNames() {
1009
+ var names = {};
1010
+ for (var a = 0; a < arguments.length; ++a) {
1011
+ var fields = arguments[a];
1012
+ if (!fields)
1013
+ continue;
1014
+ for (var i = 0; i < fields.length; ++i)
1015
+ if (fields[i].type === 10 && fields[i].typeName) {
1016
+ var name = fields[i].typeName.split(".").pop();
1017
+ if (name)
1018
+ names[name] = true;
1019
+ }
969
1020
  }
970
- return false;
1021
+ return names;
971
1022
  }
972
1023
 
973
1024
  // Converts a protobuf.js basic type to a descriptor type