protobufjs 7.4.0 → 7.5.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/dist/protobuf.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * protobuf.js v7.4.0 (c) 2016, daniel wirtz
3
- * compiled thu, 22 aug 2024 20:30:39 utc
2
+ * protobuf.js v7.5.1 (c) 2016, daniel wirtz
3
+ * compiled thu, 08 may 2025 17:34:56 utc
4
4
  * licensed under the bsd-3-clause license
5
5
  * see: https://github.com/dcodeio/protobuf.js for details
6
6
  */
@@ -1831,16 +1831,14 @@ function missing(field) {
1831
1831
  */
1832
1832
  function decoder(mtype) {
1833
1833
  /* eslint-disable no-unexpected-multiline */
1834
- var gen = util.codegen(["r", "l"], mtype.name + "$decode")
1834
+ var gen = util.codegen(["r", "l", "e"], mtype.name + "$decode")
1835
1835
  ("if(!(r instanceof Reader))")
1836
1836
  ("r=Reader.create(r)")
1837
1837
  ("var c=l===undefined?r.len:r.pos+l,m=new this.ctor" + (mtype.fieldsArray.filter(function(field) { return field.map; }).length ? ",k,value" : ""))
1838
1838
  ("while(r.pos<c){")
1839
- ("var t=r.uint32()");
1840
- if (mtype.group) gen
1841
- ("if((t&7)===4)")
1842
- ("break");
1843
- gen
1839
+ ("var t=r.uint32()")
1840
+ ("if(t===e)")
1841
+ ("break")
1844
1842
  ("switch(t>>>3){");
1845
1843
 
1846
1844
  var i = 0;
@@ -1906,15 +1904,15 @@ function decoder(mtype) {
1906
1904
  ("}else");
1907
1905
 
1908
1906
  // Non-packed
1909
- if (types.basic[type] === undefined) gen(field.resolvedType.group
1910
- ? "%s.push(types[%i].decode(r))"
1907
+ if (types.basic[type] === undefined) gen(field.delimited
1908
+ ? "%s.push(types[%i].decode(r,undefined,((t&~7)|4)))"
1911
1909
  : "%s.push(types[%i].decode(r,r.uint32()))", ref, i);
1912
1910
  else gen
1913
1911
  ("%s.push(r.%s())", ref, type);
1914
1912
 
1915
1913
  // Non-repeated
1916
- } else if (types.basic[type] === undefined) gen(field.resolvedType.group
1917
- ? "%s=types[%i].decode(r)"
1914
+ } else if (types.basic[type] === undefined) gen(field.delimited
1915
+ ? "%s=types[%i].decode(r,undefined,((t&~7)|4))"
1918
1916
  : "%s=types[%i].decode(r,r.uint32())", ref, i);
1919
1917
  else gen
1920
1918
  ("%s=r.%s()", ref, type);
@@ -1961,7 +1959,7 @@ var Enum = require(15),
1961
1959
  * @ignore
1962
1960
  */
1963
1961
  function genTypePartial(gen, field, fieldIndex, ref) {
1964
- return field.resolvedType.group
1962
+ return field.delimited
1965
1963
  ? gen("types[%i].encode(%s,w.uint32(%i)).uint32(%i)", fieldIndex, ref, (field.id << 3 | 3) >>> 0, (field.id << 3 | 4) >>> 0)
1966
1964
  : gen("types[%i].encode(%s,w.uint32(%i).fork()).ldelim()", fieldIndex, ref, (field.id << 3 | 2) >>> 0);
1967
1965
  }
@@ -2104,6 +2102,12 @@ function Enum(name, values, options, comment, comments, valuesOptions) {
2104
2102
  */
2105
2103
  this.valuesOptions = valuesOptions;
2106
2104
 
2105
+ /**
2106
+ * Resolved values features, if any
2107
+ * @type {Object<string, Object<string, *>>|undefined}
2108
+ */
2109
+ this._valuesFeatures = {};
2110
+
2107
2111
  /**
2108
2112
  * Reserved ranges, if any.
2109
2113
  * @type {Array.<number[]|string>}
@@ -2120,6 +2124,21 @@ function Enum(name, values, options, comment, comments, valuesOptions) {
2120
2124
  this.valuesById[ this.values[keys[i]] = values[keys[i]] ] = keys[i];
2121
2125
  }
2122
2126
 
2127
+ /**
2128
+ * @override
2129
+ */
2130
+ Enum.prototype._resolveFeatures = function _resolveFeatures(edition) {
2131
+ edition = this._edition || edition;
2132
+ ReflectionObject.prototype._resolveFeatures.call(this, edition);
2133
+
2134
+ Object.keys(this.values).forEach(key => {
2135
+ var parentFeaturesCopy = Object.assign({}, this._features);
2136
+ this._valuesFeatures[key] = Object.assign(parentFeaturesCopy, this.valuesOptions && this.valuesOptions[key] && this.valuesOptions[key].features);
2137
+ });
2138
+
2139
+ return this;
2140
+ };
2141
+
2123
2142
  /**
2124
2143
  * Enum descriptor.
2125
2144
  * @interface IEnum
@@ -2137,6 +2156,9 @@ function Enum(name, values, options, comment, comments, valuesOptions) {
2137
2156
  Enum.fromJSON = function fromJSON(name, json) {
2138
2157
  var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
2139
2158
  enm.reserved = json.reserved;
2159
+ if (json.edition)
2160
+ enm._edition = json.edition;
2161
+ enm._defaultEdition = "proto3"; // For backwards-compatibility.
2140
2162
  return enm;
2141
2163
  };
2142
2164
 
@@ -2148,6 +2170,7 @@ Enum.fromJSON = function fromJSON(name, json) {
2148
2170
  Enum.prototype.toJSON = function toJSON(toJSONOptions) {
2149
2171
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
2150
2172
  return util.toObject([
2173
+ "edition" , this._editionToJSON(),
2151
2174
  "options" , this.options,
2152
2175
  "valuesOptions" , this.valuesOptions,
2153
2176
  "values" , this.values,
@@ -2283,7 +2306,11 @@ var ruleRe = /^required|optional|repeated$/;
2283
2306
  * @throws {TypeError} If arguments are invalid
2284
2307
  */
2285
2308
  Field.fromJSON = function fromJSON(name, json) {
2286
- return new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
2309
+ var field = new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
2310
+ if (json.edition)
2311
+ field._edition = json.edition;
2312
+ field._defaultEdition = "proto3"; // For backwards-compatibility.
2313
+ return field;
2287
2314
  };
2288
2315
 
2289
2316
  /**
@@ -2353,18 +2380,6 @@ function Field(name, id, type, rule, extend, options, comment) {
2353
2380
  */
2354
2381
  this.extend = extend || undefined; // toJSON
2355
2382
 
2356
- /**
2357
- * Whether this field is required.
2358
- * @type {boolean}
2359
- */
2360
- this.required = rule === "required";
2361
-
2362
- /**
2363
- * Whether this field is optional.
2364
- * @type {boolean}
2365
- */
2366
- this.optional = !this.required;
2367
-
2368
2383
  /**
2369
2384
  * Whether this field is repeated.
2370
2385
  * @type {boolean}
@@ -2431,13 +2446,6 @@ function Field(name, id, type, rule, extend, options, comment) {
2431
2446
  */
2432
2447
  this.declaringField = null;
2433
2448
 
2434
- /**
2435
- * Internally remembers whether this field is packed.
2436
- * @type {boolean|null}
2437
- * @private
2438
- */
2439
- this._packed = null;
2440
-
2441
2449
  /**
2442
2450
  * Comment for this field.
2443
2451
  * @type {string|null}
@@ -2446,17 +2454,69 @@ function Field(name, id, type, rule, extend, options, comment) {
2446
2454
  }
2447
2455
 
2448
2456
  /**
2449
- * Determines whether this field is packed. Only relevant when repeated and working with proto2.
2457
+ * Determines whether this field is required.
2458
+ * @name Field#required
2459
+ * @type {boolean}
2460
+ * @readonly
2461
+ */
2462
+ Object.defineProperty(Field.prototype, "required", {
2463
+ get: function() {
2464
+ return this._features.field_presence === "LEGACY_REQUIRED";
2465
+ }
2466
+ });
2467
+
2468
+ /**
2469
+ * Determines whether this field is not required.
2470
+ * @name Field#optional
2471
+ * @type {boolean}
2472
+ * @readonly
2473
+ */
2474
+ Object.defineProperty(Field.prototype, "optional", {
2475
+ get: function() {
2476
+ return !this.required;
2477
+ }
2478
+ });
2479
+
2480
+ /**
2481
+ * Determines whether this field uses tag-delimited encoding. In proto2 this
2482
+ * corresponded to group syntax.
2483
+ * @name Field#delimited
2484
+ * @type {boolean}
2485
+ * @readonly
2486
+ */
2487
+ Object.defineProperty(Field.prototype, "delimited", {
2488
+ get: function() {
2489
+ return this.resolvedType instanceof Type &&
2490
+ this._features.message_encoding === "DELIMITED";
2491
+ }
2492
+ });
2493
+
2494
+ /**
2495
+ * Determines whether this field is packed. Only relevant when repeated.
2450
2496
  * @name Field#packed
2451
2497
  * @type {boolean}
2452
2498
  * @readonly
2453
2499
  */
2454
2500
  Object.defineProperty(Field.prototype, "packed", {
2455
2501
  get: function() {
2456
- // defaults to packed=true if not explicity set to false
2457
- if (this._packed === null)
2458
- this._packed = this.getOption("packed") !== false;
2459
- return this._packed;
2502
+ return this._features.repeated_field_encoding === "PACKED";
2503
+ }
2504
+ });
2505
+
2506
+ /**
2507
+ * Determines whether this field tracks presence.
2508
+ * @name Field#hasPresence
2509
+ * @type {boolean}
2510
+ * @readonly
2511
+ */
2512
+ Object.defineProperty(Field.prototype, "hasPresence", {
2513
+ get: function() {
2514
+ if (this.repeated || this.map) {
2515
+ return false;
2516
+ }
2517
+ return this.partOf || // oneofs
2518
+ this.declaringField || this.extensionField || // extensions
2519
+ this._features.field_presence !== "IMPLICIT";
2460
2520
  }
2461
2521
  });
2462
2522
 
@@ -2464,8 +2524,6 @@ Object.defineProperty(Field.prototype, "packed", {
2464
2524
  * @override
2465
2525
  */
2466
2526
  Field.prototype.setOption = function setOption(name, value, ifNotSet) {
2467
- if (name === "packed") // clear cached before setting
2468
- this._packed = null;
2469
2527
  return ReflectionObject.prototype.setOption.call(this, name, value, ifNotSet);
2470
2528
  };
2471
2529
 
@@ -2493,6 +2551,7 @@ Field.prototype.setOption = function setOption(name, value, ifNotSet) {
2493
2551
  Field.prototype.toJSON = function toJSON(toJSONOptions) {
2494
2552
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
2495
2553
  return util.toObject([
2554
+ "edition" , this._editionToJSON(),
2496
2555
  "rule" , this.rule !== "optional" && this.rule || undefined,
2497
2556
  "type" , this.type,
2498
2557
  "id" , this.id,
@@ -2532,7 +2591,7 @@ Field.prototype.resolve = function resolve() {
2532
2591
 
2533
2592
  // remove unnecessary options
2534
2593
  if (this.options) {
2535
- if (this.options.packed === true || this.options.packed !== undefined && this.resolvedType && !(this.resolvedType instanceof Enum))
2594
+ if (this.options.packed !== undefined && this.resolvedType && !(this.resolvedType instanceof Enum))
2536
2595
  delete this.options.packed;
2537
2596
  if (!Object.keys(this.options).length)
2538
2597
  this.options = undefined;
@@ -2570,6 +2629,46 @@ Field.prototype.resolve = function resolve() {
2570
2629
  return ReflectionObject.prototype.resolve.call(this);
2571
2630
  };
2572
2631
 
2632
+ /**
2633
+ * Infers field features from legacy syntax that may have been specified differently.
2634
+ * in older editions.
2635
+ * @param {string|undefined} edition The edition this proto is on, or undefined if pre-editions
2636
+ * @returns {object} The feature values to override
2637
+ */
2638
+ Field.prototype._inferLegacyProtoFeatures = function _inferLegacyProtoFeatures(edition) {
2639
+ if (edition !== "proto2" && edition !== "proto3") {
2640
+ return {};
2641
+ }
2642
+
2643
+ var features = {};
2644
+
2645
+ if (this.rule === "required") {
2646
+ features.field_presence = "LEGACY_REQUIRED";
2647
+ }
2648
+ if (this.parent && types.defaults[this.type] === undefined) {
2649
+ // We can't use resolvedType because types may not have been resolved yet. However,
2650
+ // legacy groups are always in the same scope as the field so we don't have to do a
2651
+ // full scan of the tree.
2652
+ var type = this.parent.get(this.type.split(".").pop());
2653
+ if (type && type instanceof Type && type.group) {
2654
+ features.message_encoding = "DELIMITED";
2655
+ }
2656
+ }
2657
+ if (this.getOption("packed") === true) {
2658
+ features.repeated_field_encoding = "PACKED";
2659
+ } else if (this.getOption("packed") === false) {
2660
+ features.repeated_field_encoding = "EXPANDED";
2661
+ }
2662
+ return features;
2663
+ };
2664
+
2665
+ /**
2666
+ * @override
2667
+ */
2668
+ Field.prototype._resolveFeatures = function _resolveFeatures(edition) {
2669
+ return ReflectionObject.prototype._resolveFeatures.call(this, this._edition || edition);
2670
+ };
2671
+
2573
2672
  /**
2574
2673
  * Decorator function as returned by {@link Field.d} and {@link MapField.d} (TypeScript).
2575
2674
  * @typedef FieldDecorator
@@ -3323,10 +3422,33 @@ function Namespace(name, options) {
3323
3422
  * @private
3324
3423
  */
3325
3424
  this._nestedArray = null;
3425
+
3426
+ /**
3427
+ * Cache lookup calls for any objects contains anywhere under this namespace.
3428
+ * This drastically speeds up resolve for large cross-linked protos where the same
3429
+ * types are looked up repeatedly.
3430
+ * @type {Object.<string,ReflectionObject|null>}
3431
+ * @private
3432
+ */
3433
+ this._lookupCache = {};
3434
+
3435
+ /**
3436
+ * Whether or not objects contained in this namespace need feature resolution.
3437
+ * @type {boolean}
3438
+ * @protected
3439
+ */
3440
+ this._needsRecursiveFeatureResolution = true;
3326
3441
  }
3327
3442
 
3328
3443
  function clearCache(namespace) {
3329
3444
  namespace._nestedArray = null;
3445
+ namespace._lookupCache = {};
3446
+
3447
+ // Also clear parent caches, since they include nested lookups.
3448
+ var parent = namespace;
3449
+ while(parent = parent.parent) {
3450
+ parent._lookupCache = {};
3451
+ }
3330
3452
  return namespace;
3331
3453
  }
3332
3454
 
@@ -3455,6 +3577,23 @@ Namespace.prototype.add = function add(object) {
3455
3577
  }
3456
3578
  }
3457
3579
  this.nested[object.name] = object;
3580
+
3581
+ if (!(this instanceof Type || this instanceof Service || this instanceof Enum || this instanceof Field)) {
3582
+ // This is a package or a root namespace.
3583
+ if (!object._edition) {
3584
+ // Make sure that some edition is set if it hasn't already been specified.
3585
+ object._edition = object._defaultEdition;
3586
+ }
3587
+ }
3588
+
3589
+ this._needsRecursiveFeatureResolution = true;
3590
+
3591
+ // Also clear parent caches, since they need to recurse down.
3592
+ var parent = this;
3593
+ while(parent = parent.parent) {
3594
+ parent._needsRecursiveFeatureResolution = true;
3595
+ }
3596
+
3458
3597
  object.onAdd(this);
3459
3598
  return clearCache(this);
3460
3599
  };
@@ -3517,12 +3656,29 @@ Namespace.prototype.define = function define(path, json) {
3517
3656
  */
3518
3657
  Namespace.prototype.resolveAll = function resolveAll() {
3519
3658
  var nested = this.nestedArray, i = 0;
3659
+ this.resolve();
3520
3660
  while (i < nested.length)
3521
3661
  if (nested[i] instanceof Namespace)
3522
3662
  nested[i++].resolveAll();
3523
3663
  else
3524
3664
  nested[i++].resolve();
3525
- return this.resolve();
3665
+ return this;
3666
+ };
3667
+
3668
+ /**
3669
+ * @override
3670
+ */
3671
+ Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
3672
+ if (!this._needsRecursiveFeatureResolution) return this;
3673
+ this._needsRecursiveFeatureResolution = false;
3674
+
3675
+ edition = this._edition || edition;
3676
+
3677
+ ReflectionObject.prototype._resolveFeaturesRecursive.call(this, edition);
3678
+ this.nestedArray.forEach(nested => {
3679
+ nested._resolveFeaturesRecursive(edition);
3680
+ });
3681
+ return this;
3526
3682
  };
3527
3683
 
3528
3684
  /**
@@ -3533,7 +3689,6 @@ Namespace.prototype.resolveAll = function resolveAll() {
3533
3689
  * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
3534
3690
  */
3535
3691
  Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
3536
-
3537
3692
  /* istanbul ignore next */
3538
3693
  if (typeof filterTypes === "boolean") {
3539
3694
  parentAlreadyChecked = filterTypes;
@@ -3552,25 +3707,48 @@ Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChe
3552
3707
  if (path[0] === "")
3553
3708
  return this.root.lookup(path.slice(1), filterTypes);
3554
3709
 
3710
+ var found = this._lookupImpl(path);
3711
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
3712
+ return found;
3713
+ }
3714
+
3715
+ // If there hasn't been a match, try again at the parent
3716
+ if (this.parent === null || parentAlreadyChecked)
3717
+ return null;
3718
+ return this.parent.lookup(path, filterTypes);
3719
+ };
3720
+
3721
+ /**
3722
+ * Internal helper for lookup that handles searching just at this namespace and below along with caching.
3723
+ * @param {string[]} path Path to look up
3724
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
3725
+ * @private
3726
+ */
3727
+ Namespace.prototype._lookupImpl = function lookup(path) {
3728
+ var flatPath = path.join(".");
3729
+ if(Object.prototype.hasOwnProperty.call(this._lookupCache, flatPath)) {
3730
+ return this._lookupCache[flatPath];
3731
+ }
3732
+
3555
3733
  // Test if the first part matches any nested object, and if so, traverse if path contains more
3556
3734
  var found = this.get(path[0]);
3735
+ var exact = null;
3557
3736
  if (found) {
3558
3737
  if (path.length === 1) {
3559
- if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
3560
- return found;
3561
- } else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
3562
- return found;
3738
+ exact = found;
3739
+ } else if (found instanceof Namespace && (found = found._lookupImpl(path.slice(1))))
3740
+ exact = found;
3563
3741
 
3564
3742
  // Otherwise try each nested namespace
3565
- } else
3743
+ } else {
3566
3744
  for (var i = 0; i < this.nestedArray.length; ++i)
3567
- if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
3568
- return found;
3745
+ if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i]._lookupImpl(path)))
3746
+ exact = found;
3747
+ }
3569
3748
 
3570
- // If there hasn't been a match, try again at the parent
3571
- if (this.parent === null || parentAlreadyChecked)
3572
- return null;
3573
- return this.parent.lookup(path, filterTypes);
3749
+ // Set this even when null, so that when we walk up the tree we can quickly bail on repeated checks back down.
3750
+ this._lookupCache[flatPath] = exact;
3751
+ return exact;
3574
3752
  };
3575
3753
 
3576
3754
  /**
@@ -3653,10 +3831,17 @@ module.exports = ReflectionObject;
3653
3831
 
3654
3832
  ReflectionObject.className = "ReflectionObject";
3655
3833
 
3834
+ const OneOf = require(25);
3656
3835
  var util = require(37);
3657
3836
 
3658
3837
  var Root; // cyclic
3659
3838
 
3839
+ /* eslint-disable no-warning-comments */
3840
+ // TODO: Replace with embedded proto.
3841
+ var editions2023Defaults = {enum_type: "OPEN", field_presence: "EXPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY"};
3842
+ var proto2Defaults = {enum_type: "CLOSED", field_presence: "EXPLICIT", json_format: "LEGACY_BEST_EFFORT", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "EXPANDED", utf8_validation: "NONE"};
3843
+ var proto3Defaults = {enum_type: "OPEN", field_presence: "IMPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY"};
3844
+
3660
3845
  /**
3661
3846
  * Constructs a new reflection object instance.
3662
3847
  * @classdesc Base class of all reflection objects.
@@ -3691,6 +3876,31 @@ function ReflectionObject(name, options) {
3691
3876
  */
3692
3877
  this.name = name;
3693
3878
 
3879
+ /**
3880
+ * The edition specified for this object. Only relevant for top-level objects.
3881
+ * @type {string}
3882
+ */
3883
+ this._edition = null;
3884
+
3885
+ /**
3886
+ * The default edition to use for this object if none is specified. For legacy reasons,
3887
+ * this is proto2 except in the JSON parsing case where it was proto3.
3888
+ * @type {string}
3889
+ */
3890
+ this._defaultEdition = "proto2";
3891
+
3892
+ /**
3893
+ * Resolved Features.
3894
+ * @type {object}
3895
+ */
3896
+ this._features = {};
3897
+
3898
+ /**
3899
+ * Whether or not features have been resolved.
3900
+ * @type {boolean}
3901
+ */
3902
+ this._featuresResolved = false;
3903
+
3694
3904
  /**
3695
3905
  * Parent namespace.
3696
3906
  * @type {Namespace|null}
@@ -3801,6 +4011,83 @@ ReflectionObject.prototype.resolve = function resolve() {
3801
4011
  return this;
3802
4012
  };
3803
4013
 
4014
+ /**
4015
+ * Resolves this objects editions features.
4016
+ * @param {string} edition The edition we're currently resolving for.
4017
+ * @returns {ReflectionObject} `this`
4018
+ */
4019
+ ReflectionObject.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
4020
+ return this._resolveFeatures(this._edition || edition);
4021
+ };
4022
+
4023
+ /**
4024
+ * Resolves child features from parent features
4025
+ * @param {string} edition The edition we're currently resolving for.
4026
+ * @returns {undefined}
4027
+ */
4028
+ ReflectionObject.prototype._resolveFeatures = function _resolveFeatures(edition) {
4029
+ if (this._featuresResolved) {
4030
+ return;
4031
+ }
4032
+
4033
+ var defaults = {};
4034
+
4035
+ /* istanbul ignore if */
4036
+ if (!edition) {
4037
+ throw new Error("Unknown edition for " + this.fullName);
4038
+ }
4039
+
4040
+ var protoFeatures = Object.assign(this.options ? Object.assign({}, this.options.features) : {},
4041
+ this._inferLegacyProtoFeatures(edition));
4042
+
4043
+ if (this._edition) {
4044
+ // For a namespace marked with a specific edition, reset defaults.
4045
+ /* istanbul ignore else */
4046
+ if (edition === "proto2") {
4047
+ defaults = Object.assign({}, proto2Defaults);
4048
+ } else if (edition === "proto3") {
4049
+ defaults = Object.assign({}, proto3Defaults);
4050
+ } else if (edition === "2023") {
4051
+ defaults = Object.assign({}, editions2023Defaults);
4052
+ } else {
4053
+ throw new Error("Unknown edition: " + edition);
4054
+ }
4055
+ this._features = Object.assign(defaults, protoFeatures || {});
4056
+ this._featuresResolved = true;
4057
+ return;
4058
+ }
4059
+
4060
+ // fields in Oneofs aren't actually children of them, so we have to
4061
+ // special-case it
4062
+ /* istanbul ignore else */
4063
+ if (this.partOf instanceof OneOf) {
4064
+ var lexicalParentFeaturesCopy = Object.assign({}, this.partOf._features);
4065
+ this._features = Object.assign(lexicalParentFeaturesCopy, protoFeatures || {});
4066
+ } else if (this.declaringField) {
4067
+ // Skip feature resolution of sister fields.
4068
+ } else if (this.parent) {
4069
+ var parentFeaturesCopy = Object.assign({}, this.parent._features);
4070
+ this._features = Object.assign(parentFeaturesCopy, protoFeatures || {});
4071
+ } else {
4072
+ throw new Error("Unable to find a parent for " + this.fullName);
4073
+ }
4074
+ if (this.extensionField) {
4075
+ // Sister fields should have the same features as their extensions.
4076
+ this.extensionField._features = this._features;
4077
+ }
4078
+ this._featuresResolved = true;
4079
+ };
4080
+
4081
+ /**
4082
+ * Infers features from legacy syntax that may have been specified differently.
4083
+ * in older editions.
4084
+ * @param {string|undefined} edition The edition this proto is on, or undefined if pre-editions
4085
+ * @returns {object} The feature values to override
4086
+ */
4087
+ ReflectionObject.prototype._inferLegacyProtoFeatures = function _inferLegacyProtoFeatures(/*edition*/) {
4088
+ return {};
4089
+ };
4090
+
3804
4091
  /**
3805
4092
  * Gets an option value.
3806
4093
  * @param {string} name Option name
@@ -3816,12 +4103,19 @@ ReflectionObject.prototype.getOption = function getOption(name) {
3816
4103
  * Sets an option.
3817
4104
  * @param {string} name Option name
3818
4105
  * @param {*} value Option value
3819
- * @param {boolean} [ifNotSet] Sets the option only if it isn't currently set
4106
+ * @param {boolean|undefined} [ifNotSet] Sets the option only if it isn't currently set
3820
4107
  * @returns {ReflectionObject} `this`
3821
4108
  */
3822
4109
  ReflectionObject.prototype.setOption = function setOption(name, value, ifNotSet) {
3823
- if (!ifNotSet || !this.options || this.options[name] === undefined)
3824
- (this.options || (this.options = {}))[name] = value;
4110
+ if (!this.options)
4111
+ this.options = {};
4112
+ if (/^features\./.test(name)) {
4113
+ util.setProperty(this.options, name, value, ifNotSet);
4114
+ } else if (!ifNotSet || this.options[name] === undefined) {
4115
+ if (this.getOption(name) !== value) this.resolved = false;
4116
+ this.options[name] = value;
4117
+ }
4118
+
3825
4119
  return this;
3826
4120
  };
3827
4121
 
@@ -3845,10 +4139,11 @@ ReflectionObject.prototype.setParsedOption = function setParsedOption(name, valu
3845
4139
  });
3846
4140
  if (opt) {
3847
4141
  // If we found an existing option - just merge the property value
4142
+ // (If it's a feature, will just write over)
3848
4143
  var newValue = opt[name];
3849
4144
  util.setProperty(newValue, propName, value);
3850
4145
  } else {
3851
- // otherwise, create a new option, set it's property and add it to the list
4146
+ // otherwise, create a new option, set its property and add it to the list
3852
4147
  opt = {};
3853
4148
  opt[name] = util.setProperty({}, propName, value);
3854
4149
  parsedOptions.push(opt);
@@ -3859,6 +4154,7 @@ ReflectionObject.prototype.setParsedOption = function setParsedOption(name, valu
3859
4154
  newOpt[name] = value;
3860
4155
  parsedOptions.push(newOpt);
3861
4156
  }
4157
+
3862
4158
  return this;
3863
4159
  };
3864
4160
 
@@ -3887,12 +4183,25 @@ ReflectionObject.prototype.toString = function toString() {
3887
4183
  return className;
3888
4184
  };
3889
4185
 
4186
+ /**
4187
+ * Converts the edition this object is pinned to for JSON format.
4188
+ * @returns {string|undefined} The edition string for JSON representation
4189
+ */
4190
+ ReflectionObject.prototype._editionToJSON = function _editionToJSON() {
4191
+ if (!this._edition || this._edition === "proto3") {
4192
+ // Avoid emitting proto3 since we need to default to it for backwards
4193
+ // compatibility anyway.
4194
+ return undefined;
4195
+ }
4196
+ return this._edition;
4197
+ };
4198
+
3890
4199
  // Sets up cyclic dependencies (called in index-light)
3891
4200
  ReflectionObject._configure = function(Root_) {
3892
4201
  Root = Root_;
3893
4202
  };
3894
4203
 
3895
- },{"37":37}],25:[function(require,module,exports){
4204
+ },{"25":25,"37":37}],25:[function(require,module,exports){
3896
4205
  "use strict";
3897
4206
  module.exports = OneOf;
3898
4207
 
@@ -4066,6 +4375,25 @@ OneOf.prototype.onRemove = function onRemove(parent) {
4066
4375
  ReflectionObject.prototype.onRemove.call(this, parent);
4067
4376
  };
4068
4377
 
4378
+ /**
4379
+ * Determines whether this field corresponds to a synthetic oneof created for
4380
+ * a proto3 optional field. No behavioral logic should depend on this, but it
4381
+ * can be relevant for reflection.
4382
+ * @name OneOf#isProto3Optional
4383
+ * @type {boolean}
4384
+ * @readonly
4385
+ */
4386
+ Object.defineProperty(OneOf.prototype, "isProto3Optional", {
4387
+ get: function() {
4388
+ if (this.fieldsArray == null || this.fieldsArray.length !== 1) {
4389
+ return false;
4390
+ }
4391
+
4392
+ var field = this.fieldsArray[0];
4393
+ return field.options != null && field.options["proto3_optional"] === true;
4394
+ }
4395
+ });
4396
+
4069
4397
  /**
4070
4398
  * Decorator function as returned by {@link OneOf.d} (TypeScript).
4071
4399
  * @typedef OneOfDecorator
@@ -4113,6 +4441,7 @@ var tokenize = require(34),
4113
4441
  Enum = require(15),
4114
4442
  Service = require(33),
4115
4443
  Method = require(22),
4444
+ ReflectionObject = require(24),
4116
4445
  types = require(36),
4117
4446
  util = require(37);
4118
4447
 
@@ -4124,8 +4453,7 @@ var base10Re = /^[1-9][0-9]*$/,
4124
4453
  base8NegRe = /^-?0[0-7]+$/,
4125
4454
  numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
4126
4455
  nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
4127
- typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/,
4128
- fqTypeRefRe = /^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/;
4456
+ typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/;
4129
4457
 
4130
4458
  /**
4131
4459
  * Result object returned from {@link parse}.
@@ -4133,7 +4461,6 @@ var base10Re = /^[1-9][0-9]*$/,
4133
4461
  * @property {string|undefined} package Package name, if declared
4134
4462
  * @property {string[]|undefined} imports Imports, if any
4135
4463
  * @property {string[]|undefined} weakImports Weak imports, if any
4136
- * @property {string|undefined} syntax Syntax, if specified (either `"proto2"` or `"proto3"`)
4137
4464
  * @property {Root} root Populated root instance
4138
4465
  */
4139
4466
 
@@ -4181,13 +4508,25 @@ function parse(source, root, options) {
4181
4508
  pkg,
4182
4509
  imports,
4183
4510
  weakImports,
4184
- syntax,
4185
- isProto3 = false;
4511
+ edition = "proto2";
4186
4512
 
4187
4513
  var ptr = root;
4188
4514
 
4515
+ var topLevelObjects = [];
4516
+ var topLevelOptions = {};
4517
+
4189
4518
  var applyCase = options.keepCase ? function(name) { return name; } : util.camelCase;
4190
4519
 
4520
+ function resolveFileFeatures() {
4521
+ topLevelObjects.forEach(obj => {
4522
+ obj._edition = edition;
4523
+ Object.keys(topLevelOptions).forEach(opt => {
4524
+ if (obj.getOption(opt) !== undefined) return;
4525
+ obj.setOption(opt, topLevelOptions[opt], true);
4526
+ });
4527
+ });
4528
+ }
4529
+
4191
4530
  /* istanbul ignore next */
4192
4531
  function illegal(token, name, insideTryCatch) {
4193
4532
  var filename = parse.filename;
@@ -4226,7 +4565,6 @@ function parse(source, root, options) {
4226
4565
  try {
4227
4566
  return parseNumber(token, /* insideTryCatch */ true);
4228
4567
  } catch (e) {
4229
-
4230
4568
  /* istanbul ignore else */
4231
4569
  if (acceptTypeRef && typeRefRe.test(token))
4232
4570
  return token;
@@ -4239,10 +4577,23 @@ function parse(source, root, options) {
4239
4577
  function readRanges(target, acceptStrings) {
4240
4578
  var token, start;
4241
4579
  do {
4242
- if (acceptStrings && ((token = peek()) === "\"" || token === "'"))
4243
- target.push(readString());
4244
- else
4245
- target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
4580
+ if (acceptStrings && ((token = peek()) === "\"" || token === "'")) {
4581
+ var str = readString();
4582
+ target.push(str);
4583
+ if (edition >= 2023) {
4584
+ throw illegal(str, "id");
4585
+ }
4586
+ } else {
4587
+ try {
4588
+ target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
4589
+ } catch (err) {
4590
+ if (acceptStrings && typeRefRe.test(token) && edition >= 2023) {
4591
+ target.push(token);
4592
+ } else {
4593
+ throw err;
4594
+ }
4595
+ }
4596
+ }
4246
4597
  } while (skip(",", true));
4247
4598
  var dummy = {options: undefined};
4248
4599
  dummy.setOption = function(name, value) {
@@ -4319,7 +4670,6 @@ function parse(source, root, options) {
4319
4670
  }
4320
4671
 
4321
4672
  function parsePackage() {
4322
-
4323
4673
  /* istanbul ignore if */
4324
4674
  if (pkg !== undefined)
4325
4675
  throw illegal("package");
@@ -4331,6 +4681,7 @@ function parse(source, root, options) {
4331
4681
  throw illegal(pkg, "name");
4332
4682
 
4333
4683
  ptr = ptr.define(pkg);
4684
+
4334
4685
  skip(";");
4335
4686
  }
4336
4687
 
@@ -4356,20 +4707,28 @@ function parse(source, root, options) {
4356
4707
 
4357
4708
  function parseSyntax() {
4358
4709
  skip("=");
4359
- syntax = readString();
4360
- isProto3 = syntax === "proto3";
4710
+ edition = readString();
4361
4711
 
4362
4712
  /* istanbul ignore if */
4363
- if (!isProto3 && syntax !== "proto2")
4364
- throw illegal(syntax, "syntax");
4713
+ if (edition < 2023)
4714
+ throw illegal(edition, "syntax");
4715
+
4716
+ skip(";");
4717
+ }
4718
+
4719
+ function parseEdition() {
4720
+ skip("=");
4721
+ edition = readString();
4722
+ const supportedEditions = ["2023"];
4365
4723
 
4366
- // Syntax is needed to understand the meaning of the optional field rule
4367
- // Otherwise the meaning is ambiguous between proto2 and proto3
4368
- root.setOption("syntax", syntax);
4724
+ /* istanbul ignore if */
4725
+ if (!supportedEditions.includes(edition))
4726
+ throw illegal(edition, "edition");
4369
4727
 
4370
4728
  skip(";");
4371
4729
  }
4372
4730
 
4731
+
4373
4732
  function parseCommon(parent, token) {
4374
4733
  switch (token) {
4375
4734
 
@@ -4437,14 +4796,19 @@ function parse(source, root, options) {
4437
4796
  break;
4438
4797
 
4439
4798
  case "required":
4799
+ if (edition !== "proto2")
4800
+ throw illegal(token);
4801
+ /* eslint-disable no-fallthrough */
4440
4802
  case "repeated":
4441
4803
  parseField(type, token);
4442
4804
  break;
4443
4805
 
4444
4806
  case "optional":
4445
4807
  /* istanbul ignore if */
4446
- if (isProto3) {
4808
+ if (edition === "proto3") {
4447
4809
  parseField(type, "proto3_optional");
4810
+ } else if (edition !== "proto2") {
4811
+ throw illegal(token);
4448
4812
  } else {
4449
4813
  parseField(type, "optional");
4450
4814
  }
@@ -4464,8 +4828,9 @@ function parse(source, root, options) {
4464
4828
 
4465
4829
  default:
4466
4830
  /* istanbul ignore if */
4467
- if (!isProto3 || !typeRefRe.test(token))
4831
+ if (edition === "proto2" || !typeRefRe.test(token)) {
4468
4832
  throw illegal(token);
4833
+ }
4469
4834
 
4470
4835
  push(token);
4471
4836
  parseField(type, "optional");
@@ -4473,6 +4838,9 @@ function parse(source, root, options) {
4473
4838
  }
4474
4839
  });
4475
4840
  parent.add(type);
4841
+ if (parent === ptr) {
4842
+ topLevelObjects.push(type);
4843
+ }
4476
4844
  }
4477
4845
 
4478
4846
  function parseField(parent, rule, extend) {
@@ -4499,6 +4867,7 @@ function parse(source, root, options) {
4499
4867
  var name = next();
4500
4868
 
4501
4869
  /* istanbul ignore if */
4870
+
4502
4871
  if (!nameRe.test(name))
4503
4872
  throw illegal(name, "name");
4504
4873
 
@@ -4506,6 +4875,7 @@ function parse(source, root, options) {
4506
4875
  skip("=");
4507
4876
 
4508
4877
  var field = new Field(name, parseId(next()), type, rule, extend);
4878
+
4509
4879
  ifBlock(field, function parseField_block(token) {
4510
4880
 
4511
4881
  /* istanbul ignore else */
@@ -4528,15 +4898,15 @@ function parse(source, root, options) {
4528
4898
  } else {
4529
4899
  parent.add(field);
4530
4900
  }
4531
-
4532
- // JSON defaults to packed=true if not set so we have to set packed=false explicity when
4533
- // parsing proto2 descriptors without the option, where applicable. This must be done for
4534
- // all known packable types and anything that could be an enum (= is not a basic type).
4535
- if (!isProto3 && field.repeated && (types.packed[type] !== undefined || types.basic[type] === undefined))
4536
- field.setOption("packed", false, /* ifNotSet */ true);
4901
+ if (parent === ptr) {
4902
+ topLevelObjects.push(field);
4903
+ }
4537
4904
  }
4538
4905
 
4539
4906
  function parseGroup(parent, rule) {
4907
+ if (edition >= 2023) {
4908
+ throw illegal("group");
4909
+ }
4540
4910
  var name = next();
4541
4911
 
4542
4912
  /* istanbul ignore if */
@@ -4559,7 +4929,6 @@ function parse(source, root, options) {
4559
4929
  parseOption(type, token);
4560
4930
  skip(";");
4561
4931
  break;
4562
-
4563
4932
  case "required":
4564
4933
  case "repeated":
4565
4934
  parseField(type, token);
@@ -4567,7 +4936,7 @@ function parse(source, root, options) {
4567
4936
 
4568
4937
  case "optional":
4569
4938
  /* istanbul ignore if */
4570
- if (isProto3) {
4939
+ if (edition === "proto3") {
4571
4940
  parseField(type, "proto3_optional");
4572
4941
  } else {
4573
4942
  parseField(type, "optional");
@@ -4582,6 +4951,10 @@ function parse(source, root, options) {
4582
4951
  parseEnum(type, token);
4583
4952
  break;
4584
4953
 
4954
+ case "reserved":
4955
+ readRanges(type.reserved || (type.reserved = []), true);
4956
+ break;
4957
+
4585
4958
  /* istanbul ignore next */
4586
4959
  default:
4587
4960
  throw illegal(token); // there are no groups with proto3 semantics
@@ -4665,6 +5038,7 @@ function parse(source, root, options) {
4665
5038
 
4666
5039
  case "reserved":
4667
5040
  readRanges(enm.reserved || (enm.reserved = []), true);
5041
+ if(enm.reserved === undefined) enm.reserved = [];
4668
5042
  break;
4669
5043
 
4670
5044
  default:
@@ -4672,6 +5046,9 @@ function parse(source, root, options) {
4672
5046
  }
4673
5047
  });
4674
5048
  parent.add(enm);
5049
+ if (parent === ptr) {
5050
+ topLevelObjects.push(enm);
5051
+ }
4675
5052
  }
4676
5053
 
4677
5054
  function parseEnumValue(parent, token) {
@@ -4685,10 +5062,14 @@ function parse(source, root, options) {
4685
5062
  dummy = {
4686
5063
  options: undefined
4687
5064
  };
5065
+ dummy.getOption = function(name) {
5066
+ return this.options[name];
5067
+ };
4688
5068
  dummy.setOption = function(name, value) {
4689
- if (this.options === undefined)
4690
- this.options = {};
4691
- this.options[name] = value;
5069
+ ReflectionObject.prototype.setOption.call(dummy, name, value);
5070
+ };
5071
+ dummy.setParsedOption = function() {
5072
+ return undefined;
4692
5073
  };
4693
5074
  ifBlock(dummy, function parseEnumValue_block(token) {
4694
5075
 
@@ -4702,34 +5083,42 @@ function parse(source, root, options) {
4702
5083
  }, function parseEnumValue_line() {
4703
5084
  parseInlineOptions(dummy); // skip
4704
5085
  });
4705
- parent.add(token, value, dummy.comment, dummy.options);
5086
+ parent.add(token, value, dummy.comment, dummy.parsedOptions || dummy.options);
4706
5087
  }
4707
5088
 
4708
5089
  function parseOption(parent, token) {
4709
- var isCustom = skip("(", true);
4710
-
4711
- /* istanbul ignore if */
4712
- if (!typeRefRe.test(token = next()))
4713
- throw illegal(token, "name");
4714
-
4715
- var name = token;
4716
- var option = name;
4717
- var propName;
5090
+ var option;
5091
+ var propName;
5092
+ var isOption = true;
5093
+ if (token === "option") {
5094
+ token = next();
5095
+ }
4718
5096
 
4719
- if (isCustom) {
4720
- skip(")");
4721
- name = "(" + name + ")";
4722
- option = name;
4723
- token = peek();
4724
- if (fqTypeRefRe.test(token)) {
4725
- propName = token.slice(1); //remove '.' before property name
4726
- name += token;
4727
- next();
5097
+ while (token !== "=") {
5098
+ if (token === "(") {
5099
+ var parensValue = next();
5100
+ skip(")");
5101
+ token = "(" + parensValue + ")";
5102
+ }
5103
+ if (isOption) {
5104
+ isOption = false;
5105
+ if (token.includes(".") && !token.includes("(")) {
5106
+ var tokens = token.split(".");
5107
+ option = tokens[0] + ".";
5108
+ token = tokens[1];
5109
+ continue;
5110
+ }
5111
+ option = token;
5112
+ } else {
5113
+ propName = propName ? propName += token : token;
5114
+ }
5115
+ token = next();
4728
5116
  }
4729
- }
4730
- skip("=");
4731
- var optionValue = parseOptionValue(parent, name);
4732
- setParsedOption(parent, option, optionValue, propName);
5117
+ var name = propName ? option.concat(propName) : option;
5118
+ var optionValue = parseOptionValue(parent, name);
5119
+ propName = propName && propName[0] === "." ? propName.slice(1) : propName;
5120
+ option = option && option[option.length - 1] === "." ? option.slice(0, -1) : option;
5121
+ setParsedOption(parent, option, optionValue, propName);
4733
5122
  }
4734
5123
 
4735
5124
  function parseOptionValue(parent, name) {
@@ -4751,12 +5140,12 @@ function parse(source, root, options) {
4751
5140
 
4752
5141
  skip(":", true);
4753
5142
 
4754
- if (peek() === "{")
4755
- value = parseOptionValue(parent, name + "." + token);
4756
- else if (peek() === "[") {
5143
+ if (peek() === "{") {
4757
5144
  // option (my_option) = {
4758
5145
  // repeated_value: [ "foo", "bar" ]
4759
5146
  // };
5147
+ value = parseOptionValue(parent, name + "." + token);
5148
+ } else if (peek() === "[") {
4760
5149
  value = [];
4761
5150
  var lastValue;
4762
5151
  if (skip("[", true)) {
@@ -4796,6 +5185,10 @@ function parse(source, root, options) {
4796
5185
  }
4797
5186
 
4798
5187
  function setOption(parent, name, value) {
5188
+ if (ptr === parent && /^features\./.test(name)) {
5189
+ topLevelOptions[name] = value;
5190
+ return;
5191
+ }
4799
5192
  if (parent.setOption)
4800
5193
  parent.setOption(name, value);
4801
5194
  }
@@ -4823,8 +5216,9 @@ function parse(source, root, options) {
4823
5216
 
4824
5217
  var service = new Service(token);
4825
5218
  ifBlock(service, function parseService_block(token) {
4826
- if (parseCommon(service, token))
5219
+ if (parseCommon(service, token)) {
4827
5220
  return;
5221
+ }
4828
5222
 
4829
5223
  /* istanbul ignore else */
4830
5224
  if (token === "rpc")
@@ -4833,6 +5227,9 @@ function parse(source, root, options) {
4833
5227
  throw illegal(token);
4834
5228
  });
4835
5229
  parent.add(service);
5230
+ if (parent === ptr) {
5231
+ topLevelObjects.push(service);
5232
+ }
4836
5233
  }
4837
5234
 
4838
5235
  function parseMethod(parent, token) {
@@ -4902,7 +5299,7 @@ function parse(source, root, options) {
4902
5299
 
4903
5300
  case "optional":
4904
5301
  /* istanbul ignore if */
4905
- if (isProto3) {
5302
+ if (edition === "proto3") {
4906
5303
  parseField(parent, "proto3_optional", reference);
4907
5304
  } else {
4908
5305
  parseField(parent, "optional", reference);
@@ -4911,7 +5308,7 @@ function parse(source, root, options) {
4911
5308
 
4912
5309
  default:
4913
5310
  /* istanbul ignore if */
4914
- if (!isProto3 || !typeRefRe.test(token))
5311
+ if (edition === "proto2" || !typeRefRe.test(token))
4915
5312
  throw illegal(token);
4916
5313
  push(token);
4917
5314
  parseField(parent, "optional", reference);
@@ -4951,10 +5348,16 @@ function parse(source, root, options) {
4951
5348
  parseSyntax();
4952
5349
  break;
4953
5350
 
4954
- case "option":
5351
+ case "edition":
5352
+ /* istanbul ignore if */
5353
+ if (!head)
5354
+ throw illegal(token);
5355
+ parseEdition();
5356
+ break;
4955
5357
 
5358
+ case "option":
4956
5359
  parseOption(ptr, token);
4957
- skip(";");
5360
+ skip(";", true);
4958
5361
  break;
4959
5362
 
4960
5363
  default:
@@ -4970,12 +5373,13 @@ function parse(source, root, options) {
4970
5373
  }
4971
5374
  }
4972
5375
 
5376
+ resolveFileFeatures();
5377
+
4973
5378
  parse.filename = null;
4974
5379
  return {
4975
5380
  "package" : pkg,
4976
5381
  "imports" : imports,
4977
5382
  weakImports : weakImports,
4978
- syntax : syntax,
4979
5383
  root : root
4980
5384
  };
4981
5385
  }
@@ -4992,7 +5396,7 @@ function parse(source, root, options) {
4992
5396
  * @variation 2
4993
5397
  */
4994
5398
 
4995
- },{"15":15,"16":16,"20":20,"22":22,"25":25,"29":29,"33":33,"34":34,"35":35,"36":36,"37":37}],27:[function(require,module,exports){
5399
+ },{"15":15,"16":16,"20":20,"22":22,"24":24,"25":25,"29":29,"33":33,"34":34,"35":35,"36":36,"37":37}],27:[function(require,module,exports){
4996
5400
  "use strict";
4997
5401
  module.exports = Reader;
4998
5402
 
@@ -5501,11 +5905,14 @@ function Root(options) {
5501
5905
  * @type {string[]}
5502
5906
  */
5503
5907
  this.files = [];
5908
+
5909
+ // Default to proto2 if unspecified.
5910
+ this._edition = "proto2";
5504
5911
  }
5505
5912
 
5506
5913
  /**
5507
5914
  * Loads a namespace descriptor into a root namespace.
5508
- * @param {INamespace} json Nameespace descriptor
5915
+ * @param {INamespace} json Namespace descriptor
5509
5916
  * @param {Root} [root] Root namespace, defaults to create a new one if omitted
5510
5917
  * @returns {Root} Root namespace
5511
5918
  */
@@ -5514,7 +5921,7 @@ Root.fromJSON = function fromJSON(json, root) {
5514
5921
  root = new Root();
5515
5922
  if (json.options)
5516
5923
  root.setOptions(json.options);
5517
- return root.addJSON(json.nested);
5924
+ return root.addJSON(json.nested)._resolveFeaturesRecursive();
5518
5925
  };
5519
5926
 
5520
5927
  /**
@@ -5554,18 +5961,24 @@ Root.prototype.load = function load(filename, options, callback) {
5554
5961
  options = undefined;
5555
5962
  }
5556
5963
  var self = this;
5557
- if (!callback)
5964
+ if (!callback) {
5558
5965
  return util.asPromise(load, self, filename, options);
5966
+ }
5559
5967
 
5560
5968
  var sync = callback === SYNC; // undocumented
5561
5969
 
5562
5970
  // Finishes loading by calling the callback (exactly once)
5563
5971
  function finish(err, root) {
5972
+ if (root) {
5973
+ root._resolveFeaturesRecursive();
5974
+ }
5564
5975
  /* istanbul ignore if */
5565
- if (!callback)
5976
+ if (!callback) {
5566
5977
  return;
5567
- if (sync)
5978
+ }
5979
+ if (sync) {
5568
5980
  throw err;
5981
+ }
5569
5982
  var cb = callback;
5570
5983
  callback = null;
5571
5984
  cb(err, root);
@@ -5605,8 +6018,9 @@ Root.prototype.load = function load(filename, options, callback) {
5605
6018
  } catch (err) {
5606
6019
  finish(err);
5607
6020
  }
5608
- if (!sync && !queued)
6021
+ if (!sync && !queued) {
5609
6022
  finish(null, self); // only once anyway
6023
+ }
5610
6024
  }
5611
6025
 
5612
6026
  // Fetches a single file
@@ -5614,15 +6028,16 @@ Root.prototype.load = function load(filename, options, callback) {
5614
6028
  filename = getBundledFileName(filename) || filename;
5615
6029
 
5616
6030
  // Skip if already loaded / attempted
5617
- if (self.files.indexOf(filename) > -1)
6031
+ if (self.files.indexOf(filename) > -1) {
5618
6032
  return;
6033
+ }
5619
6034
  self.files.push(filename);
5620
6035
 
5621
6036
  // Shortcut bundled definitions
5622
6037
  if (filename in common) {
5623
- if (sync)
6038
+ if (sync) {
5624
6039
  process(filename, common[filename]);
5625
- else {
6040
+ } else {
5626
6041
  ++queued;
5627
6042
  setTimeout(function() {
5628
6043
  --queued;
@@ -5648,8 +6063,9 @@ Root.prototype.load = function load(filename, options, callback) {
5648
6063
  self.fetch(filename, function(err, source) {
5649
6064
  --queued;
5650
6065
  /* istanbul ignore if */
5651
- if (!callback)
6066
+ if (!callback) {
5652
6067
  return; // terminated meanwhile
6068
+ }
5653
6069
  if (err) {
5654
6070
  /* istanbul ignore else */
5655
6071
  if (!weak)
@@ -5666,17 +6082,21 @@ Root.prototype.load = function load(filename, options, callback) {
5666
6082
 
5667
6083
  // Assembling the root namespace doesn't require working type
5668
6084
  // references anymore, so we can load everything in parallel
5669
- if (util.isString(filename))
6085
+ if (util.isString(filename)) {
5670
6086
  filename = [ filename ];
6087
+ }
5671
6088
  for (var i = 0, resolved; i < filename.length; ++i)
5672
6089
  if (resolved = self.resolvePath("", filename[i]))
5673
6090
  fetch(resolved);
5674
-
5675
- if (sync)
6091
+ if (sync) {
6092
+ self._resolveFeaturesRecursive();
5676
6093
  return self;
5677
- if (!queued)
6094
+ }
6095
+ if (!queued) {
5678
6096
  finish(null, self);
5679
- return undefined;
6097
+ }
6098
+
6099
+ return self;
5680
6100
  };
5681
6101
  // function load(filename:string, options:IParseOptions, callback:LoadCallback):undefined
5682
6102
 
@@ -5722,6 +6142,7 @@ Root.prototype.resolveAll = function resolveAll() {
5722
6142
  throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
5723
6143
  return "'extend " + field.extend + "' in " + field.parent.fullName;
5724
6144
  }).join(", "));
6145
+ this._resolveFeaturesRecursive(this._edition);
5725
6146
  return Namespace.prototype.resolveAll.call(this);
5726
6147
  };
5727
6148
 
@@ -6095,7 +6516,10 @@ Service.fromJSON = function fromJSON(name, json) {
6095
6516
  service.add(Method.fromJSON(names[i], json.methods[names[i]]));
6096
6517
  if (json.nested)
6097
6518
  service.addJSON(json.nested);
6519
+ if (json.edition)
6520
+ service._edition = json.edition;
6098
6521
  service.comment = json.comment;
6522
+ service._defaultEdition = "proto3"; // For backwards-compatibility.
6099
6523
  return service;
6100
6524
  };
6101
6525
 
@@ -6108,6 +6532,7 @@ Service.prototype.toJSON = function toJSON(toJSONOptions) {
6108
6532
  var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
6109
6533
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
6110
6534
  return util.toObject([
6535
+ "edition" , this._editionToJSON(),
6111
6536
  "options" , inherited && inherited.options || undefined,
6112
6537
  "methods" , Namespace.arrayToJSON(this.methodsArray, toJSONOptions) || /* istanbul ignore next */ {},
6113
6538
  "nested" , inherited && inherited.nested || undefined,
@@ -6144,10 +6569,26 @@ Service.prototype.get = function get(name) {
6144
6569
  * @override
6145
6570
  */
6146
6571
  Service.prototype.resolveAll = function resolveAll() {
6572
+ Namespace.prototype.resolve.call(this);
6147
6573
  var methods = this.methodsArray;
6148
6574
  for (var i = 0; i < methods.length; ++i)
6149
6575
  methods[i].resolve();
6150
- return Namespace.prototype.resolve.call(this);
6576
+ return this;
6577
+ };
6578
+
6579
+ /**
6580
+ * @override
6581
+ */
6582
+ Service.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
6583
+ if (!this._needsRecursiveFeatureResolution) return this;
6584
+
6585
+ edition = this._edition || edition;
6586
+
6587
+ Namespace.prototype._resolveFeaturesRecursive.call(this, edition);
6588
+ this.methodsArray.forEach(method => {
6589
+ method._resolveFeaturesRecursive(edition);
6590
+ });
6591
+ return this;
6151
6592
  };
6152
6593
 
6153
6594
  /**
@@ -6897,6 +7338,9 @@ Type.fromJSON = function fromJSON(name, json) {
6897
7338
  type.group = true;
6898
7339
  if (json.comment)
6899
7340
  type.comment = json.comment;
7341
+ if (json.edition)
7342
+ type._edition = json.edition;
7343
+ type._defaultEdition = "proto3"; // For backwards-compatibility.
6900
7344
  return type;
6901
7345
  };
6902
7346
 
@@ -6909,6 +7353,7 @@ Type.prototype.toJSON = function toJSON(toJSONOptions) {
6909
7353
  var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
6910
7354
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
6911
7355
  return util.toObject([
7356
+ "edition" , this._editionToJSON(),
6912
7357
  "options" , inherited && inherited.options || undefined,
6913
7358
  "oneofs" , Namespace.arrayToJSON(this.oneofsArray, toJSONOptions),
6914
7359
  "fields" , Namespace.arrayToJSON(this.fieldsArray.filter(function(obj) { return !obj.declaringField; }), toJSONOptions) || {},
@@ -6924,13 +7369,32 @@ Type.prototype.toJSON = function toJSON(toJSONOptions) {
6924
7369
  * @override
6925
7370
  */
6926
7371
  Type.prototype.resolveAll = function resolveAll() {
6927
- var fields = this.fieldsArray, i = 0;
6928
- while (i < fields.length)
6929
- fields[i++].resolve();
7372
+ Namespace.prototype.resolveAll.call(this);
6930
7373
  var oneofs = this.oneofsArray; i = 0;
6931
7374
  while (i < oneofs.length)
6932
7375
  oneofs[i++].resolve();
6933
- return Namespace.prototype.resolveAll.call(this);
7376
+ var fields = this.fieldsArray, i = 0;
7377
+ while (i < fields.length)
7378
+ fields[i++].resolve();
7379
+ return this;
7380
+ };
7381
+
7382
+ /**
7383
+ * @override
7384
+ */
7385
+ Type.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
7386
+ if (!this._needsRecursiveFeatureResolution) return this;
7387
+
7388
+ edition = this._edition || edition;
7389
+
7390
+ Namespace.prototype._resolveFeaturesRecursive.call(this, edition);
7391
+ this.oneofsArray.forEach(oneof => {
7392
+ oneof._resolveFeatures(edition);
7393
+ });
7394
+ this.fieldsArray.forEach(field => {
7395
+ field._resolveFeatures(edition);
7396
+ });
7397
+ return this;
6934
7398
  };
6935
7399
 
6936
7400
  /**
@@ -7585,9 +8049,10 @@ util.decorateEnum = function decorateEnum(object) {
7585
8049
  * @param {Object.<string,*>} dst Destination object
7586
8050
  * @param {string} path dot '.' delimited path of the property to set
7587
8051
  * @param {Object} value the value to set
8052
+ * @param {boolean|undefined} [ifNotSet] Sets the option only if it isn't currently set
7588
8053
  * @returns {Object.<string,*>} Destination object
7589
8054
  */
7590
- util.setProperty = function setProperty(dst, path, value) {
8055
+ util.setProperty = function setProperty(dst, path, value, ifNotSet) {
7591
8056
  function setProp(dst, path, value) {
7592
8057
  var part = path.shift();
7593
8058
  if (part === "__proto__" || part === "prototype") {
@@ -7597,6 +8062,8 @@ util.setProperty = function setProperty(dst, path, value) {
7597
8062
  dst[part] = setProp(dst[part] || {}, path, value);
7598
8063
  } else {
7599
8064
  var prevValue = dst[part];
8065
+ if (prevValue && ifNotSet)
8066
+ return dst;
7600
8067
  if (prevValue)
7601
8068
  value = [].concat(prevValue).concat(value);
7602
8069
  dst[part] = value;