protobufjs 8.0.1-experimental → 8.0.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.
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * protobuf.js v8.0.1-experimental (c) 2016, daniel wirtz
3
- * compiled mon, 24 mar 2025 19:22:52 utc
2
+ * protobuf.js v8.0.1 (c) 2016, daniel wirtz
3
+ * compiled sat, 04 apr 2026 19:23:15 utc
4
4
  * licensed under the bsd-3-clause license
5
5
  * see: https://github.com/dcodeio/protobuf.js for details
6
6
  */
@@ -1707,12 +1707,6 @@ function Enum(name, values, options, comment, comments, valuesOptions) {
1707
1707
  */
1708
1708
  this._valuesFeatures = {};
1709
1709
 
1710
- /**
1711
- * Unresolved values features, if any
1712
- * @type {Object<string, Object<string, *>>|undefined}
1713
- */
1714
- this._valuesProtoFeatures = {};
1715
-
1716
1710
  /**
1717
1711
  * Reserved ranges, if any.
1718
1712
  * @type {Array.<number[]|string>}
@@ -1730,21 +1724,20 @@ function Enum(name, values, options, comment, comments, valuesOptions) {
1730
1724
  }
1731
1725
 
1732
1726
  /**
1733
- * Resolves value features
1734
- * @returns {Enum} `this`
1727
+ * @override
1735
1728
  */
1736
- Enum.prototype.resolve = function resolve() {
1737
- ReflectionObject.prototype.resolve.call(this);
1729
+ Enum.prototype._resolveFeatures = function _resolveFeatures(edition) {
1730
+ edition = this._edition || edition;
1731
+ ReflectionObject.prototype._resolveFeatures.call(this, edition);
1738
1732
 
1739
- for (var key of Object.keys(this._valuesProtoFeatures)) {
1733
+ Object.keys(this.values).forEach(key => {
1740
1734
  var parentFeaturesCopy = Object.assign({}, this._features);
1741
- this._valuesFeatures[key] = Object.assign(parentFeaturesCopy, this._valuesProtoFeatures[key] || {});
1742
- }
1735
+ this._valuesFeatures[key] = Object.assign(parentFeaturesCopy, this.valuesOptions && this.valuesOptions[key] && this.valuesOptions[key].features);
1736
+ });
1743
1737
 
1744
1738
  return this;
1745
1739
  };
1746
1740
 
1747
-
1748
1741
  /**
1749
1742
  * Enum descriptor.
1750
1743
  * @interface IEnum
@@ -1762,6 +1755,9 @@ Enum.prototype.resolve = function resolve() {
1762
1755
  Enum.fromJSON = function fromJSON(name, json) {
1763
1756
  var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
1764
1757
  enm.reserved = json.reserved;
1758
+ if (json.edition)
1759
+ enm._edition = json.edition;
1760
+ enm._defaultEdition = "proto3"; // For backwards-compatibility.
1765
1761
  return enm;
1766
1762
  };
1767
1763
 
@@ -1773,6 +1769,7 @@ Enum.fromJSON = function fromJSON(name, json) {
1773
1769
  Enum.prototype.toJSON = function toJSON(toJSONOptions) {
1774
1770
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
1775
1771
  return util.toObject([
1772
+ "edition" , this._editionToJSON(),
1776
1773
  "options" , this.options,
1777
1774
  "valuesOptions" , this.valuesOptions,
1778
1775
  "values" , this.values,
@@ -1821,21 +1818,6 @@ Enum.prototype.add = function add(name, id, comment, options) {
1821
1818
  if (this.valuesOptions === undefined)
1822
1819
  this.valuesOptions = {};
1823
1820
  this.valuesOptions[name] = options || null;
1824
-
1825
- for (var key of Object.keys(this.valuesOptions)) {
1826
- var features = Array.isArray(this.valuesOptions[key]) ? this.valuesOptions[key].find(x => {return Object.prototype.hasOwnProperty.call(x, "features");}) : this.valuesOptions[key] === "features";
1827
- if (features) {
1828
- this._valuesProtoFeatures[key] = features.features;
1829
- } else {
1830
- this._valuesProtoFeatures[key] = {};
1831
- }
1832
- }
1833
- }
1834
-
1835
- for (var enumValue of Object.keys(this.values)) {
1836
- if (!this._valuesProtoFeatures[enumValue]) {
1837
- this._valuesProtoFeatures[enumValue] = {};
1838
- }
1839
1821
  }
1840
1822
 
1841
1823
  this.comments[name] = comment || null;
@@ -1923,7 +1905,11 @@ var ruleRe = /^required|optional|repeated$/;
1923
1905
  * @throws {TypeError} If arguments are invalid
1924
1906
  */
1925
1907
  Field.fromJSON = function fromJSON(name, json) {
1926
- return new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
1908
+ var field = new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
1909
+ if (json.edition)
1910
+ field._edition = json.edition;
1911
+ field._defaultEdition = "proto3"; // For backwards-compatibility.
1912
+ return field;
1927
1913
  };
1928
1914
 
1929
1915
  /**
@@ -2164,6 +2150,7 @@ Field.prototype.setOption = function setOption(name, value, ifNotSet) {
2164
2150
  Field.prototype.toJSON = function toJSON(toJSONOptions) {
2165
2151
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
2166
2152
  return util.toObject([
2153
+ "edition" , this._editionToJSON(),
2167
2154
  "rule" , this.rule !== "optional" && this.rule || undefined,
2168
2155
  "type" , this.type,
2169
2156
  "id" , this.id,
@@ -2248,14 +2235,23 @@ Field.prototype.resolve = function resolve() {
2248
2235
  * @returns {object} The feature values to override
2249
2236
  */
2250
2237
  Field.prototype._inferLegacyProtoFeatures = function _inferLegacyProtoFeatures(edition) {
2251
- if (edition) return {};
2238
+ if (edition !== "proto2" && edition !== "proto3") {
2239
+ return {};
2240
+ }
2252
2241
 
2253
2242
  var features = {};
2243
+
2254
2244
  if (this.rule === "required") {
2255
2245
  features.field_presence = "LEGACY_REQUIRED";
2256
2246
  }
2257
- if (this.resolvedType instanceof Type && this.resolvedType.group) {
2258
- features.message_encoding = "DELIMITED";
2247
+ if (this.parent && types.defaults[this.type] === undefined) {
2248
+ // We can't use resolvedType because types may not have been resolved yet. However,
2249
+ // legacy groups are always in the same scope as the field so we don't have to do a
2250
+ // full scan of the tree.
2251
+ var type = this.parent.get(this.type.split(".").pop());
2252
+ if (type && type instanceof Type && type.group) {
2253
+ features.message_encoding = "DELIMITED";
2254
+ }
2259
2255
  }
2260
2256
  if (this.getOption("packed") === true) {
2261
2257
  features.repeated_field_encoding = "PACKED";
@@ -2265,6 +2261,13 @@ Field.prototype._inferLegacyProtoFeatures = function _inferLegacyProtoFeatures(e
2265
2261
  return features;
2266
2262
  };
2267
2263
 
2264
+ /**
2265
+ * @override
2266
+ */
2267
+ Field.prototype._resolveFeatures = function _resolveFeatures(edition) {
2268
+ return ReflectionObject.prototype._resolveFeatures.call(this, this._edition || edition);
2269
+ };
2270
+
2268
2271
  /**
2269
2272
  * Decorator function as returned by {@link Field.d} and {@link MapField.d} (TypeScript).
2270
2273
  * @typedef FieldDecorator
@@ -2420,7 +2423,7 @@ protobuf.types = require(32);
2420
2423
  protobuf.util = require(33);
2421
2424
 
2422
2425
  // Set up possibly cyclic reflection dependencies
2423
- protobuf.ReflectionObject._configure(protobuf.Root, protobuf.Namespace);
2426
+ protobuf.ReflectionObject._configure(protobuf.Root);
2424
2427
  protobuf.Namespace._configure(protobuf.Type, protobuf.Service, protobuf.Enum);
2425
2428
  protobuf.Root._configure(protobuf.Type);
2426
2429
  protobuf.Field._configure(protobuf.Type);
@@ -2607,8 +2610,12 @@ var util = require(35);
2607
2610
  function Message(properties) {
2608
2611
  // not used internally
2609
2612
  if (properties)
2610
- for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
2611
- this[keys[i]] = properties[keys[i]];
2613
+ for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) {
2614
+ var key = keys[i];
2615
+ if (key === "__proto__")
2616
+ continue;
2617
+ this[key] = properties[key];
2618
+ }
2612
2619
  }
2613
2620
 
2614
2621
  /**
@@ -2731,6 +2738,7 @@ Message.prototype.toJSON = function toJSON() {
2731
2738
  };
2732
2739
 
2733
2740
  /*eslint-enable valid-jsdoc*/
2741
+
2734
2742
  },{"35":35}],20:[function(require,module,exports){
2735
2743
  "use strict";
2736
2744
  module.exports = Method;
@@ -3004,10 +3012,40 @@ function Namespace(name, options) {
3004
3012
  * @private
3005
3013
  */
3006
3014
  this._nestedArray = null;
3015
+
3016
+ /**
3017
+ * Cache lookup calls for any objects contains anywhere under this namespace.
3018
+ * This drastically speeds up resolve for large cross-linked protos where the same
3019
+ * types are looked up repeatedly.
3020
+ * @type {Object.<string,ReflectionObject|null>}
3021
+ * @private
3022
+ */
3023
+ this._lookupCache = {};
3024
+
3025
+ /**
3026
+ * Whether or not objects contained in this namespace need feature resolution.
3027
+ * @type {boolean}
3028
+ * @protected
3029
+ */
3030
+ this._needsRecursiveFeatureResolution = true;
3031
+
3032
+ /**
3033
+ * Whether or not objects contained in this namespace need a resolve.
3034
+ * @type {boolean}
3035
+ * @protected
3036
+ */
3037
+ this._needsRecursiveResolve = true;
3007
3038
  }
3008
3039
 
3009
3040
  function clearCache(namespace) {
3010
3041
  namespace._nestedArray = null;
3042
+ namespace._lookupCache = {};
3043
+
3044
+ // Also clear parent caches, since they include nested lookups.
3045
+ var parent = namespace;
3046
+ while(parent = parent.parent) {
3047
+ parent._lookupCache = {};
3048
+ }
3011
3049
  return namespace;
3012
3050
  }
3013
3051
 
@@ -3136,6 +3174,25 @@ Namespace.prototype.add = function add(object) {
3136
3174
  }
3137
3175
  }
3138
3176
  this.nested[object.name] = object;
3177
+
3178
+ if (!(this instanceof Type || this instanceof Service || this instanceof Enum || this instanceof Field)) {
3179
+ // This is a package or a root namespace.
3180
+ if (!object._edition) {
3181
+ // Make sure that some edition is set if it hasn't already been specified.
3182
+ object._edition = object._defaultEdition;
3183
+ }
3184
+ }
3185
+
3186
+ this._needsRecursiveFeatureResolution = true;
3187
+ this._needsRecursiveResolve = true;
3188
+
3189
+ // Also clear parent caches, since they need to recurse down.
3190
+ var parent = this;
3191
+ while(parent = parent.parent) {
3192
+ parent._needsRecursiveFeatureResolution = true;
3193
+ parent._needsRecursiveResolve = true;
3194
+ }
3195
+
3139
3196
  object.onAdd(this);
3140
3197
  return clearCache(this);
3141
3198
  };
@@ -3197,6 +3254,10 @@ Namespace.prototype.define = function define(path, json) {
3197
3254
  * @returns {Namespace} `this`
3198
3255
  */
3199
3256
  Namespace.prototype.resolveAll = function resolveAll() {
3257
+ if (!this._needsRecursiveResolve) return this;
3258
+
3259
+ this._resolveFeaturesRecursive(this._edition);
3260
+
3200
3261
  var nested = this.nestedArray, i = 0;
3201
3262
  this.resolve();
3202
3263
  while (i < nested.length)
@@ -3204,6 +3265,23 @@ Namespace.prototype.resolveAll = function resolveAll() {
3204
3265
  nested[i++].resolveAll();
3205
3266
  else
3206
3267
  nested[i++].resolve();
3268
+ this._needsRecursiveResolve = false;
3269
+ return this;
3270
+ };
3271
+
3272
+ /**
3273
+ * @override
3274
+ */
3275
+ Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
3276
+ if (!this._needsRecursiveFeatureResolution) return this;
3277
+ this._needsRecursiveFeatureResolution = false;
3278
+
3279
+ edition = this._edition || edition;
3280
+
3281
+ ReflectionObject.prototype._resolveFeaturesRecursive.call(this, edition);
3282
+ this.nestedArray.forEach(nested => {
3283
+ nested._resolveFeaturesRecursive(edition);
3284
+ });
3207
3285
  return this;
3208
3286
  };
3209
3287
 
@@ -3215,7 +3293,6 @@ Namespace.prototype.resolveAll = function resolveAll() {
3215
3293
  * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
3216
3294
  */
3217
3295
  Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
3218
-
3219
3296
  /* istanbul ignore next */
3220
3297
  if (typeof filterTypes === "boolean") {
3221
3298
  parentAlreadyChecked = filterTypes;
@@ -3230,29 +3307,72 @@ Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChe
3230
3307
  } else if (!path.length)
3231
3308
  return this;
3232
3309
 
3310
+ var flatPath = path.join(".");
3311
+
3233
3312
  // Start at root if path is absolute
3234
3313
  if (path[0] === "")
3235
3314
  return this.root.lookup(path.slice(1), filterTypes);
3236
3315
 
3316
+ // Early bailout for objects with matching absolute paths
3317
+ var found = this.root._fullyQualifiedObjects && this.root._fullyQualifiedObjects["." + flatPath];
3318
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
3319
+ return found;
3320
+ }
3321
+
3322
+ // Do a regular lookup at this namespace and below
3323
+ found = this._lookupImpl(path, flatPath);
3324
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
3325
+ return found;
3326
+ }
3327
+
3328
+ if (parentAlreadyChecked)
3329
+ return null;
3330
+
3331
+ // If there hasn't been a match, walk up the tree and look more broadly
3332
+ var current = this;
3333
+ while (current.parent) {
3334
+ found = current.parent._lookupImpl(path, flatPath);
3335
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
3336
+ return found;
3337
+ }
3338
+ current = current.parent;
3339
+ }
3340
+ return null;
3341
+ };
3342
+
3343
+ /**
3344
+ * Internal helper for lookup that handles searching just at this namespace and below along with caching.
3345
+ * @param {string[]} path Path to look up
3346
+ * @param {string} flatPath Flattened version of the path to use as a cache key
3347
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
3348
+ * @private
3349
+ */
3350
+ Namespace.prototype._lookupImpl = function lookup(path, flatPath) {
3351
+ if(Object.prototype.hasOwnProperty.call(this._lookupCache, flatPath)) {
3352
+ return this._lookupCache[flatPath];
3353
+ }
3354
+
3237
3355
  // Test if the first part matches any nested object, and if so, traverse if path contains more
3238
3356
  var found = this.get(path[0]);
3357
+ var exact = null;
3239
3358
  if (found) {
3240
3359
  if (path.length === 1) {
3241
- if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
3242
- return found;
3243
- } else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
3244
- return found;
3360
+ exact = found;
3361
+ } else if (found instanceof Namespace) {
3362
+ path = path.slice(1);
3363
+ exact = found._lookupImpl(path, path.join("."));
3364
+ }
3245
3365
 
3246
3366
  // Otherwise try each nested namespace
3247
- } else
3367
+ } else {
3248
3368
  for (var i = 0; i < this.nestedArray.length; ++i)
3249
- if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
3250
- return found;
3369
+ if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i]._lookupImpl(path, flatPath)))
3370
+ exact = found;
3371
+ }
3251
3372
 
3252
- // If there hasn't been a match, try again at the parent
3253
- if (this.parent === null || parentAlreadyChecked)
3254
- return null;
3255
- return this.parent.lookup(path, filterTypes);
3373
+ // Set this even when null, so that when we walk up the tree we can quickly bail on repeated checks back down.
3374
+ this._lookupCache[flatPath] = exact;
3375
+ return exact;
3256
3376
  };
3257
3377
 
3258
3378
  /**
@@ -3338,13 +3458,14 @@ ReflectionObject.className = "ReflectionObject";
3338
3458
  const OneOf = require(23);
3339
3459
  var util = require(33);
3340
3460
 
3341
- var Root, Namespace; // cyclic
3461
+ var Root; // cyclic
3342
3462
 
3343
3463
  /* eslint-disable no-warning-comments */
3344
3464
  // TODO: Replace with embedded proto.
3345
- var editions2023Defaults = {enum_type: "OPEN", field_presence: "EXPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY"};
3346
- var proto2Defaults = {enum_type: "CLOSED", field_presence: "EXPLICIT", json_format: "LEGACY_BEST_EFFORT", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "EXPANDED", utf8_validation: "NONE"};
3347
- var proto3Defaults = {enum_type: "OPEN", field_presence: "IMPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY"};
3465
+ var editions2024Defaults = {enum_type: "OPEN", field_presence: "EXPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY", enforce_naming_style: "STYLE2024", default_symbol_visibility: "EXPORT_TOP_LEVEL" };
3466
+ var editions2023Defaults = {enum_type: "OPEN", field_presence: "EXPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY", enforce_naming_style: "STYLE_LEGACY", default_symbol_visibility: "EXPORT_ALL" };
3467
+ var proto2Defaults = {enum_type: "CLOSED", field_presence: "EXPLICIT", json_format: "LEGACY_BEST_EFFORT", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "EXPANDED", utf8_validation: "NONE", enforce_naming_style: "STYLE_LEGACY", default_symbol_visibility: "EXPORT_ALL" };
3468
+ var proto3Defaults = {enum_type: "OPEN", field_presence: "IMPLICIT", json_format: "ALLOW", message_encoding: "LENGTH_PREFIXED", repeated_field_encoding: "PACKED", utf8_validation: "VERIFY", enforce_naming_style: "STYLE_LEGACY", default_symbol_visibility: "EXPORT_ALL" };
3348
3469
 
3349
3470
  /**
3350
3471
  * Constructs a new reflection object instance.
@@ -3380,15 +3501,34 @@ function ReflectionObject(name, options) {
3380
3501
  */
3381
3502
  this.name = name;
3382
3503
 
3504
+ /**
3505
+ * The edition specified for this object. Only relevant for top-level objects.
3506
+ * @type {string}
3507
+ * @private
3508
+ */
3509
+ this._edition = null;
3510
+
3511
+ /**
3512
+ * The default edition to use for this object if none is specified. For legacy reasons,
3513
+ * this is proto2 except in the JSON parsing case where it was proto3.
3514
+ * @type {string}
3515
+ * @private
3516
+ */
3517
+ this._defaultEdition = "proto2";
3518
+
3383
3519
  /**
3384
3520
  * Resolved Features.
3521
+ * @type {object}
3522
+ * @private
3385
3523
  */
3386
3524
  this._features = {};
3387
3525
 
3388
3526
  /**
3389
- * Unresolved Features.
3527
+ * Whether or not features have been resolved.
3528
+ * @type {boolean}
3529
+ * @private
3390
3530
  */
3391
- this._protoFeatures = null;
3531
+ this._featuresResolved = false;
3392
3532
 
3393
3533
  /**
3394
3534
  * Parent namespace.
@@ -3495,41 +3635,62 @@ ReflectionObject.prototype.onRemove = function onRemove(parent) {
3495
3635
  ReflectionObject.prototype.resolve = function resolve() {
3496
3636
  if (this.resolved)
3497
3637
  return this;
3498
- var edition = this.getOption("edition");
3499
- if ((this instanceof Namespace && edition) || (this.parent && this.parent.resolved)) {
3500
- this._resolveFeatures();
3501
- this.resolved = true;
3502
- }
3638
+ if (this.root instanceof Root)
3639
+ this.resolved = true; // only if part of a root
3503
3640
  return this;
3504
3641
  };
3505
3642
 
3643
+ /**
3644
+ * Resolves this objects editions features.
3645
+ * @param {string} edition The edition we're currently resolving for.
3646
+ * @returns {ReflectionObject} `this`
3647
+ */
3648
+ ReflectionObject.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
3649
+ return this._resolveFeatures(this._edition || edition);
3650
+ };
3651
+
3506
3652
  /**
3507
3653
  * Resolves child features from parent features
3654
+ * @param {string} edition The edition we're currently resolving for.
3508
3655
  * @returns {undefined}
3509
3656
  */
3510
- ReflectionObject.prototype._resolveFeatures = function _resolveFeatures() {
3657
+ ReflectionObject.prototype._resolveFeatures = function _resolveFeatures(edition) {
3658
+ if (this._featuresResolved) {
3659
+ return;
3660
+ }
3661
+
3511
3662
  var defaults = {};
3512
3663
 
3513
- var protoFeatures = Object.assign(Object.assign({}, this._protoFeatures), this._inferLegacyProtoFeatures(edition));
3664
+ /* istanbul ignore if */
3665
+ if (!edition) {
3666
+ throw new Error("Unknown edition for " + this.fullName);
3667
+ }
3514
3668
 
3515
- var edition = this.getOption("edition");
3516
- if (this instanceof Namespace && edition) {
3669
+ var protoFeatures = Object.assign(this.options ? Object.assign({}, this.options.features) : {},
3670
+ this._inferLegacyProtoFeatures(edition));
3671
+
3672
+ if (this._edition) {
3517
3673
  // For a namespace marked with a specific edition, reset defaults.
3674
+ /* istanbul ignore else */
3518
3675
  if (edition === "proto2") {
3519
3676
  defaults = Object.assign({}, proto2Defaults);
3520
3677
  } else if (edition === "proto3") {
3521
3678
  defaults = Object.assign({}, proto3Defaults);
3522
3679
  } else if (edition === "2023") {
3523
3680
  defaults = Object.assign({}, editions2023Defaults);
3681
+ } else if (edition === "2024") {
3682
+ defaults = Object.assign({}, editions2024Defaults);
3524
3683
  } else {
3525
3684
  throw new Error("Unknown edition: " + edition);
3526
3685
  }
3527
3686
  this._features = Object.assign(defaults, protoFeatures || {});
3687
+ this._featuresResolved = true;
3528
3688
  return;
3529
3689
  }
3530
3690
 
3531
3691
  // fields in Oneofs aren't actually children of them, so we have to
3532
3692
  // special-case it
3693
+ /* istanbul ignore else */
3533
3694
  if (this.partOf instanceof OneOf) {
3534
3695
  var lexicalParentFeaturesCopy = Object.assign({}, this.partOf._features);
3535
3696
  this._features = Object.assign(lexicalParentFeaturesCopy, protoFeatures || {});
@@ -3539,12 +3700,13 @@ ReflectionObject.prototype._resolveFeatures = function _resolveFeatures() {
3539
3700
  var parentFeaturesCopy = Object.assign({}, this.parent._features);
3540
3701
  this._features = Object.assign(parentFeaturesCopy, protoFeatures || {});
3541
3702
  } else {
3542
- this._features = Object.assign({}, protoFeatures);
3703
+ throw new Error("Unable to find a parent for " + this.fullName);
3543
3704
  }
3544
3705
  if (this.extensionField) {
3545
3706
  // Sister fields should have the same features as their extensions.
3546
3707
  this.extensionField._features = this._features;
3547
3708
  }
3709
+ this._featuresResolved = true;
3548
3710
  };
3549
3711
 
3550
3712
  /**
@@ -3552,7 +3714,6 @@ ReflectionObject.prototype._resolveFeatures = function _resolveFeatures() {
3552
3714
  * in older editions.
3553
3715
  * @param {string|undefined} edition The edition this proto is on, or undefined if pre-editions
3554
3716
  * @returns {object} The feature values to override
3555
- * @abstract
3556
3717
  */
3557
3718
  ReflectionObject.prototype._inferLegacyProtoFeatures = function _inferLegacyProtoFeatures(/*edition*/) {
3558
3719
  return {};
@@ -3573,14 +3734,19 @@ ReflectionObject.prototype.getOption = function getOption(name) {
3573
3734
  * Sets an option.
3574
3735
  * @param {string} name Option name
3575
3736
  * @param {*} value Option value
3576
- * @param {boolean} [ifNotSet] Sets the option only if it isn't currently set
3737
+ * @param {boolean|undefined} [ifNotSet] Sets the option only if it isn't currently set
3577
3738
  * @returns {ReflectionObject} `this`
3578
3739
  */
3579
3740
  ReflectionObject.prototype.setOption = function setOption(name, value, ifNotSet) {
3580
- if (!ifNotSet || !this.options || this.options[name] === undefined) {
3741
+ if (!this.options)
3742
+ this.options = {};
3743
+ if (/^features\./.test(name)) {
3744
+ util.setProperty(this.options, name, value, ifNotSet);
3745
+ } else if (!ifNotSet || this.options[name] === undefined) {
3581
3746
  if (this.getOption(name) !== value) this.resolved = false;
3582
- (this.options || (this.options = {}))[name] = value;
3747
+ this.options[name] = value;
3583
3748
  }
3749
+
3584
3750
  return this;
3585
3751
  };
3586
3752
 
@@ -3595,7 +3761,6 @@ ReflectionObject.prototype.setParsedOption = function setParsedOption(name, valu
3595
3761
  if (!this.parsedOptions) {
3596
3762
  this.parsedOptions = [];
3597
3763
  }
3598
- var isFeature = /^features$/.test(name);
3599
3764
  var parsedOptions = this.parsedOptions;
3600
3765
  if (propName) {
3601
3766
  // If setting a sub property of an option then try to merge it
@@ -3621,12 +3786,6 @@ ReflectionObject.prototype.setParsedOption = function setParsedOption(name, valu
3621
3786
  parsedOptions.push(newOpt);
3622
3787
  }
3623
3788
 
3624
-
3625
- if (isFeature) {
3626
- var features = parsedOptions.find(x => {return Object.prototype.hasOwnProperty.call(x, "features");});
3627
- this._protoFeatures = features.features || {};
3628
- }
3629
-
3630
3789
  return this;
3631
3790
  };
3632
3791
 
@@ -3655,10 +3814,22 @@ ReflectionObject.prototype.toString = function toString() {
3655
3814
  return className;
3656
3815
  };
3657
3816
 
3817
+ /**
3818
+ * Converts the edition this object is pinned to for JSON format.
3819
+ * @returns {string|undefined} The edition string for JSON representation
3820
+ */
3821
+ ReflectionObject.prototype._editionToJSON = function _editionToJSON() {
3822
+ if (!this._edition || this._edition === "proto3") {
3823
+ // Avoid emitting proto3 since we need to default to it for backwards
3824
+ // compatibility anyway.
3825
+ return undefined;
3826
+ }
3827
+ return this._edition;
3828
+ };
3829
+
3658
3830
  // Sets up cyclic dependencies (called in index-light)
3659
- ReflectionObject._configure = function(Root_, Namespace_) {
3831
+ ReflectionObject._configure = function(Root_) {
3660
3832
  Root = Root_;
3661
- Namespace = Namespace_;
3662
3833
  };
3663
3834
 
3664
3835
  },{"23":23,"33":33}],23:[function(require,module,exports){
@@ -4395,8 +4566,19 @@ function Root(options) {
4395
4566
  */
4396
4567
  this.files = [];
4397
4568
 
4398
- // Default to proto2 if not specified.
4399
- this.setOption("edition", "proto2", true);
4569
+ /**
4570
+ * Edition, defaults to proto2 if unspecified.
4571
+ * @type {string}
4572
+ * @private
4573
+ */
4574
+ this._edition = "proto2";
4575
+
4576
+ /**
4577
+ * Global lookup cache of fully qualified names.
4578
+ * @type {Object.<string,ReflectionObject>}
4579
+ * @private
4580
+ */
4581
+ this._fullyQualifiedObjects = {};
4400
4582
  }
4401
4583
 
4402
4584
  /**
@@ -4410,7 +4592,7 @@ Root.fromJSON = function fromJSON(json, root) {
4410
4592
  root = new Root();
4411
4593
  if (json.options)
4412
4594
  root.setOptions(json.options);
4413
- return root.addJSON(json.nested);
4595
+ return root.addJSON(json.nested).resolveAll();
4414
4596
  };
4415
4597
 
4416
4598
  /**
@@ -4465,11 +4647,11 @@ Root.prototype.load = function load(filename, options, callback) {
4465
4647
  if (sync) {
4466
4648
  throw err;
4467
4649
  }
4468
- var cb = callback;
4469
- callback = null;
4470
4650
  if (root) {
4471
4651
  root.resolveAll();
4472
4652
  }
4653
+ var cb = callback;
4654
+ callback = null;
4473
4655
  cb(err, root);
4474
4656
  }
4475
4657
 
@@ -4577,8 +4759,8 @@ Root.prototype.load = function load(filename, options, callback) {
4577
4759
  for (var i = 0, resolved; i < filename.length; ++i)
4578
4760
  if (resolved = self.resolvePath("", filename[i]))
4579
4761
  fetch(resolved);
4580
- self.resolveAll();
4581
4762
  if (sync) {
4763
+ self.resolveAll();
4582
4764
  return self;
4583
4765
  }
4584
4766
  if (!queued) {
@@ -4627,6 +4809,8 @@ Root.prototype.loadSync = function loadSync(filename, options) {
4627
4809
  * @override
4628
4810
  */
4629
4811
  Root.prototype.resolveAll = function resolveAll() {
4812
+ if (!this._needsRecursiveResolve) return this;
4813
+
4630
4814
  if (this.deferred.length)
4631
4815
  throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
4632
4816
  return "'extend " + field.extend + "' in " + field.parent.fullName;
@@ -4693,6 +4877,11 @@ Root.prototype._handleAdd = function _handleAdd(object) {
4693
4877
  object.parent[object.name] = object; // expose namespace as property of its parent
4694
4878
  }
4695
4879
 
4880
+ if (object instanceof Type || object instanceof Enum || object instanceof Field) {
4881
+ // Only store types and enums for quick lookup during resolve.
4882
+ this._fullyQualifiedObjects[object.fullName] = object;
4883
+ }
4884
+
4696
4885
  // The above also adds uppercased (and thus conflict-free) nested types, services and enums as
4697
4886
  // properties of namespaces just like static code does. This allows using a .d.ts generated for
4698
4887
  // a static module with reflection-based solutions where the condition is met.
@@ -4733,6 +4922,8 @@ Root.prototype._handleRemove = function _handleRemove(object) {
4733
4922
  delete object.parent[object.name]; // unexpose namespaces
4734
4923
 
4735
4924
  }
4925
+
4926
+ delete this._fullyQualifiedObjects[object.fullName];
4736
4927
  };
4737
4928
 
4738
4929
  // Sets up cyclic dependencies (called in index-light)
@@ -5004,7 +5195,10 @@ Service.fromJSON = function fromJSON(name, json) {
5004
5195
  service.add(Method.fromJSON(names[i], json.methods[names[i]]));
5005
5196
  if (json.nested)
5006
5197
  service.addJSON(json.nested);
5198
+ if (json.edition)
5199
+ service._edition = json.edition;
5007
5200
  service.comment = json.comment;
5201
+ service._defaultEdition = "proto3"; // For backwards-compatibility.
5008
5202
  return service;
5009
5203
  };
5010
5204
 
@@ -5017,6 +5211,7 @@ Service.prototype.toJSON = function toJSON(toJSONOptions) {
5017
5211
  var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
5018
5212
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
5019
5213
  return util.toObject([
5214
+ "edition" , this._editionToJSON(),
5020
5215
  "options" , inherited && inherited.options || undefined,
5021
5216
  "methods" , Namespace.arrayToJSON(this.methodsArray, toJSONOptions) || /* istanbul ignore next */ {},
5022
5217
  "nested" , inherited && inherited.nested || undefined,
@@ -5053,6 +5248,8 @@ Service.prototype.get = function get(name) {
5053
5248
  * @override
5054
5249
  */
5055
5250
  Service.prototype.resolveAll = function resolveAll() {
5251
+ if (!this._needsRecursiveResolve) return this;
5252
+
5056
5253
  Namespace.prototype.resolve.call(this);
5057
5254
  var methods = this.methodsArray;
5058
5255
  for (var i = 0; i < methods.length; ++i)
@@ -5060,6 +5257,21 @@ Service.prototype.resolveAll = function resolveAll() {
5060
5257
  return this;
5061
5258
  };
5062
5259
 
5260
+ /**
5261
+ * @override
5262
+ */
5263
+ Service.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
5264
+ if (!this._needsRecursiveFeatureResolution) return this;
5265
+
5266
+ edition = this._edition || edition;
5267
+
5268
+ Namespace.prototype._resolveFeaturesRecursive.call(this, edition);
5269
+ this.methodsArray.forEach(method => {
5270
+ method._resolveFeaturesRecursive(edition);
5271
+ });
5272
+ return this;
5273
+ };
5274
+
5063
5275
  /**
5064
5276
  * @override
5065
5277
  */
@@ -5146,6 +5358,7 @@ var Enum = require(14),
5146
5358
  * @param {Object.<string,*>} [options] Declared options
5147
5359
  */
5148
5360
  function Type(name, options) {
5361
+ name = name.replace(/\W/g, "");
5149
5362
  Namespace.call(this, name, options);
5150
5363
 
5151
5364
  /**
@@ -5389,6 +5602,9 @@ Type.fromJSON = function fromJSON(name, json) {
5389
5602
  type.group = true;
5390
5603
  if (json.comment)
5391
5604
  type.comment = json.comment;
5605
+ if (json.edition)
5606
+ type._edition = json.edition;
5607
+ type._defaultEdition = "proto3"; // For backwards-compatibility.
5392
5608
  return type;
5393
5609
  };
5394
5610
 
@@ -5401,6 +5617,7 @@ Type.prototype.toJSON = function toJSON(toJSONOptions) {
5401
5617
  var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
5402
5618
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
5403
5619
  return util.toObject([
5620
+ "edition" , this._editionToJSON(),
5404
5621
  "options" , inherited && inherited.options || undefined,
5405
5622
  "oneofs" , Namespace.arrayToJSON(this.oneofsArray, toJSONOptions),
5406
5623
  "fields" , Namespace.arrayToJSON(this.fieldsArray.filter(function(obj) { return !obj.declaringField; }), toJSONOptions) || {},
@@ -5416,6 +5633,8 @@ Type.prototype.toJSON = function toJSON(toJSONOptions) {
5416
5633
  * @override
5417
5634
  */
5418
5635
  Type.prototype.resolveAll = function resolveAll() {
5636
+ if (!this._needsRecursiveResolve) return this;
5637
+
5419
5638
  Namespace.prototype.resolveAll.call(this);
5420
5639
  var oneofs = this.oneofsArray; i = 0;
5421
5640
  while (i < oneofs.length)
@@ -5426,6 +5645,24 @@ Type.prototype.resolveAll = function resolveAll() {
5426
5645
  return this;
5427
5646
  };
5428
5647
 
5648
+ /**
5649
+ * @override
5650
+ */
5651
+ Type.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
5652
+ if (!this._needsRecursiveFeatureResolution) return this;
5653
+
5654
+ edition = this._edition || edition;
5655
+
5656
+ Namespace.prototype._resolveFeaturesRecursive.call(this, edition);
5657
+ this.oneofsArray.forEach(oneof => {
5658
+ oneof._resolveFeatures(edition);
5659
+ });
5660
+ this.fieldsArray.forEach(field => {
5661
+ field._resolveFeatures(edition);
5662
+ });
5663
+ return this;
5664
+ };
5665
+
5429
5666
  /**
5430
5667
  * @override
5431
5668
  */
@@ -6078,10 +6315,10 @@ util.decorateEnum = function decorateEnum(object) {
6078
6315
  * @param {Object.<string,*>} dst Destination object
6079
6316
  * @param {string} path dot '.' delimited path of the property to set
6080
6317
  * @param {Object} value the value to set
6081
- * @param {boolean} overWrite whether or not to concatenate the values into an array or overwrite; defaults to false.
6318
+ * @param {boolean|undefined} [ifNotSet] Sets the option only if it isn't currently set
6082
6319
  * @returns {Object.<string,*>} Destination object
6083
6320
  */
6084
- util.setProperty = function setProperty(dst, path, value) {
6321
+ util.setProperty = function setProperty(dst, path, value, ifNotSet) {
6085
6322
  function setProp(dst, path, value) {
6086
6323
  var part = path.shift();
6087
6324
  if (part === "__proto__" || part === "prototype") {
@@ -6091,6 +6328,8 @@ util.setProperty = function setProperty(dst, path, value) {
6091
6328
  dst[part] = setProp(dst[part] || {}, path, value);
6092
6329
  } else {
6093
6330
  var prevValue = dst[part];
6331
+ if (prevValue && ifNotSet)
6332
+ return dst;
6094
6333
  if (prevValue)
6095
6334
  value = [].concat(prevValue).concat(value);
6096
6335
  dst[part] = value;