protobufjs 7.5.0 → 7.5.2

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/index.d.ts CHANGED
@@ -750,6 +750,12 @@ export abstract class NamespaceBase extends ReflectionObject {
750
750
  /** Nested objects by name. */
751
751
  public nested?: { [k: string]: ReflectionObject };
752
752
 
753
+ /** Whether or not objects contained in this namespace need feature resolution. */
754
+ protected _needsRecursiveFeatureResolution: boolean;
755
+
756
+ /** Whether or not objects contained in this namespace need a resolve. */
757
+ protected _needsRecursiveResolve: boolean;
758
+
753
759
  /** Nested objects of this namespace as an array for iteration. */
754
760
  public readonly nestedArray: ReflectionObject[];
755
761
 
@@ -897,18 +903,6 @@ export abstract class ReflectionObject {
897
903
  /** Unique name within its namespace. */
898
904
  public name: string;
899
905
 
900
- /** The edition specified for this object. Only relevant for top-level objects. */
901
- public _edition: string;
902
-
903
- /**
904
- * The default edition to use for this object if none is specified. For legacy reasons,
905
- * this is proto2 except in the JSON parsing case where it was proto3.
906
- */
907
- public _defaultEdition: string;
908
-
909
- /** Resolved Features. */
910
- public _features: object;
911
-
912
906
  /** Parent namespace. */
913
907
  public parent: (Namespace|null);
914
908
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "protobufjs",
3
- "version": "7.5.0",
3
+ "version": "7.5.2",
4
4
  "versionScheme": "~",
5
5
  "description": "Protocol Buffers for JavaScript (& TypeScript).",
6
6
  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
@@ -33,7 +33,9 @@
33
33
  "build:bundle": "gulp --gulpfile scripts/gulpfile.js",
34
34
  "build:types": "node cli/bin/pbts --main --global protobuf --out index.d.ts src/ lib/aspromise/index.js lib/base64/index.js lib/codegen/index.js lib/eventemitter/index.js lib/float/index.js lib/fetch/index.js lib/inquire/index.js lib/path/index.js lib/pool/index.js lib/utf8/index.js",
35
35
  "changelog": "node scripts/changelog -w",
36
- "coverage": "nyc tape -r ./lib/tape-adapter tests/*.js tests/node/*.js",
36
+ "coverage": "npm run coverage:test && npm run coverage:report",
37
+ "coverage:test": "nyc --silent tape -r ./lib/tape-adapter tests/*.js tests/node/*.js",
38
+ "coverage:report": "nyc report --reporter=lcov --reporter=text",
37
39
  "docs": "jsdoc -c config/jsdoc.json -R README.md --verbose --pedantic",
38
40
  "lint": "npm run lint:sources && npm run lint:types",
39
41
  "lint:sources": "eslint \"**/*.js\" -c config/eslint.json",
package/src/field.js CHANGED
@@ -370,12 +370,18 @@ Field.prototype._inferLegacyProtoFeatures = function _inferLegacyProtoFeatures(e
370
370
  }
371
371
 
372
372
  var features = {};
373
- this.resolve();
373
+
374
374
  if (this.rule === "required") {
375
375
  features.field_presence = "LEGACY_REQUIRED";
376
376
  }
377
- if (this.resolvedType instanceof Type && this.resolvedType.group) {
378
- features.message_encoding = "DELIMITED";
377
+ if (this.parent && types.defaults[this.type] === undefined) {
378
+ // We can't use resolvedType because types may not have been resolved yet. However,
379
+ // legacy groups are always in the same scope as the field so we don't have to do a
380
+ // full scan of the tree.
381
+ var type = this.parent.get(this.type.split(".").pop());
382
+ if (type && type instanceof Type && type.group) {
383
+ features.message_encoding = "DELIMITED";
384
+ }
379
385
  }
380
386
  if (this.getOption("packed") === true) {
381
387
  features.repeated_field_encoding = "PACKED";
package/src/namespace.js CHANGED
@@ -108,10 +108,40 @@ function Namespace(name, options) {
108
108
  * @private
109
109
  */
110
110
  this._nestedArray = null;
111
+
112
+ /**
113
+ * Cache lookup calls for any objects contains anywhere under this namespace.
114
+ * This drastically speeds up resolve for large cross-linked protos where the same
115
+ * types are looked up repeatedly.
116
+ * @type {Object.<string,ReflectionObject|null>}
117
+ * @private
118
+ */
119
+ this._lookupCache = {};
120
+
121
+ /**
122
+ * Whether or not objects contained in this namespace need feature resolution.
123
+ * @type {boolean}
124
+ * @protected
125
+ */
126
+ this._needsRecursiveFeatureResolution = true;
127
+
128
+ /**
129
+ * Whether or not objects contained in this namespace need a resolve.
130
+ * @type {boolean}
131
+ * @protected
132
+ */
133
+ this._needsRecursiveResolve = true;
111
134
  }
112
135
 
113
136
  function clearCache(namespace) {
114
137
  namespace._nestedArray = null;
138
+ namespace._lookupCache = {};
139
+
140
+ // Also clear parent caches, since they include nested lookups.
141
+ var parent = namespace;
142
+ while(parent = parent.parent) {
143
+ parent._lookupCache = {};
144
+ }
115
145
  return namespace;
116
146
  }
117
147
 
@@ -249,6 +279,16 @@ Namespace.prototype.add = function add(object) {
249
279
  }
250
280
  }
251
281
 
282
+ this._needsRecursiveFeatureResolution = true;
283
+ this._needsRecursiveResolve = true;
284
+
285
+ // Also clear parent caches, since they need to recurse down.
286
+ var parent = this;
287
+ while(parent = parent.parent) {
288
+ parent._needsRecursiveFeatureResolution = true;
289
+ parent._needsRecursiveResolve = true;
290
+ }
291
+
252
292
  object.onAdd(this);
253
293
  return clearCache(this);
254
294
  };
@@ -310,6 +350,8 @@ Namespace.prototype.define = function define(path, json) {
310
350
  * @returns {Namespace} `this`
311
351
  */
312
352
  Namespace.prototype.resolveAll = function resolveAll() {
353
+ if (!this._needsRecursiveResolve) return this;
354
+
313
355
  var nested = this.nestedArray, i = 0;
314
356
  this.resolve();
315
357
  while (i < nested.length)
@@ -317,6 +359,7 @@ Namespace.prototype.resolveAll = function resolveAll() {
317
359
  nested[i++].resolveAll();
318
360
  else
319
361
  nested[i++].resolve();
362
+ this._needsRecursiveResolve = false;
320
363
  return this;
321
364
  };
322
365
 
@@ -324,6 +367,9 @@ Namespace.prototype.resolveAll = function resolveAll() {
324
367
  * @override
325
368
  */
326
369
  Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
370
+ if (!this._needsRecursiveFeatureResolution) return this;
371
+ this._needsRecursiveFeatureResolution = false;
372
+
327
373
  edition = this._edition || edition;
328
374
 
329
375
  ReflectionObject.prototype._resolveFeaturesRecursive.call(this, edition);
@@ -341,7 +387,6 @@ Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursi
341
387
  * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
342
388
  */
343
389
  Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
344
-
345
390
  /* istanbul ignore next */
346
391
  if (typeof filterTypes === "boolean") {
347
392
  parentAlreadyChecked = filterTypes;
@@ -356,29 +401,72 @@ Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChe
356
401
  } else if (!path.length)
357
402
  return this;
358
403
 
404
+ var flatPath = path.join(".");
405
+
359
406
  // Start at root if path is absolute
360
407
  if (path[0] === "")
361
408
  return this.root.lookup(path.slice(1), filterTypes);
362
409
 
410
+ // Early bailout for objects with matching absolute paths
411
+ var found = this.root._fullyQualifiedObjects["." + flatPath];
412
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
413
+ return found;
414
+ }
415
+
416
+ // Do a regular lookup at this namespace and below
417
+ found = this._lookupImpl(path, flatPath);
418
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
419
+ return found;
420
+ }
421
+
422
+ if (parentAlreadyChecked)
423
+ return null;
424
+
425
+ // If there hasn't been a match, walk up the tree and look more broadly
426
+ var current = this;
427
+ while (current.parent) {
428
+ found = current.parent._lookupImpl(path, flatPath);
429
+ if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
430
+ return found;
431
+ }
432
+ current = current.parent;
433
+ }
434
+ return null;
435
+ };
436
+
437
+ /**
438
+ * Internal helper for lookup that handles searching just at this namespace and below along with caching.
439
+ * @param {string[]} path Path to look up
440
+ * @param {string} flatPath Flattened version of the path to use as a cache key
441
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
442
+ * @private
443
+ */
444
+ Namespace.prototype._lookupImpl = function lookup(path, flatPath) {
445
+ if(Object.prototype.hasOwnProperty.call(this._lookupCache, flatPath)) {
446
+ return this._lookupCache[flatPath];
447
+ }
448
+
363
449
  // Test if the first part matches any nested object, and if so, traverse if path contains more
364
450
  var found = this.get(path[0]);
451
+ var exact = null;
365
452
  if (found) {
366
453
  if (path.length === 1) {
367
- if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
368
- return found;
369
- } else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
370
- return found;
454
+ exact = found;
455
+ } else if (found instanceof Namespace) {
456
+ path = path.slice(1);
457
+ exact = found._lookupImpl(path, path.join("."));
458
+ }
371
459
 
372
460
  // Otherwise try each nested namespace
373
- } else
461
+ } else {
374
462
  for (var i = 0; i < this.nestedArray.length; ++i)
375
- if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
376
- return found;
463
+ if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i]._lookupImpl(path, flatPath)))
464
+ exact = found;
465
+ }
377
466
 
378
- // If there hasn't been a match, try again at the parent
379
- if (this.parent === null || parentAlreadyChecked)
380
- return null;
381
- return this.parent.lookup(path, filterTypes);
467
+ // Set this even when null, so that when we walk up the tree we can quickly bail on repeated checks back down.
468
+ this._lookupCache[flatPath] = exact;
469
+ return exact;
382
470
  };
383
471
 
384
472
  /**
package/src/object.js CHANGED
@@ -51,6 +51,7 @@ function ReflectionObject(name, options) {
51
51
  /**
52
52
  * The edition specified for this object. Only relevant for top-level objects.
53
53
  * @type {string}
54
+ * @private
54
55
  */
55
56
  this._edition = null;
56
57
 
@@ -58,15 +59,24 @@ function ReflectionObject(name, options) {
58
59
  * The default edition to use for this object if none is specified. For legacy reasons,
59
60
  * this is proto2 except in the JSON parsing case where it was proto3.
60
61
  * @type {string}
62
+ * @private
61
63
  */
62
64
  this._defaultEdition = "proto2";
63
65
 
64
66
  /**
65
67
  * Resolved Features.
66
68
  * @type {object}
69
+ * @private
67
70
  */
68
71
  this._features = {};
69
72
 
73
+ /**
74
+ * Whether or not features have been resolved.
75
+ * @type {boolean}
76
+ * @private
77
+ */
78
+ this._featuresResolved = false;
79
+
70
80
  /**
71
81
  * Parent namespace.
72
82
  * @type {Namespace|null}
@@ -172,10 +182,8 @@ ReflectionObject.prototype.onRemove = function onRemove(parent) {
172
182
  ReflectionObject.prototype.resolve = function resolve() {
173
183
  if (this.resolved)
174
184
  return this;
175
- if (this instanceof Root) {
176
- this._resolveFeaturesRecursive(this._edition);
177
- this.resolved = true;
178
- }
185
+ if (this.root instanceof Root)
186
+ this.resolved = true; // only if part of a root
179
187
  return this;
180
188
  };
181
189
 
@@ -194,6 +202,10 @@ ReflectionObject.prototype._resolveFeaturesRecursive = function _resolveFeatures
194
202
  * @returns {undefined}
195
203
  */
196
204
  ReflectionObject.prototype._resolveFeatures = function _resolveFeatures(edition) {
205
+ if (this._featuresResolved) {
206
+ return;
207
+ }
208
+
197
209
  var defaults = {};
198
210
 
199
211
  /* istanbul ignore if */
@@ -217,6 +229,7 @@ ReflectionObject.prototype._resolveFeatures = function _resolveFeatures(edition)
217
229
  throw new Error("Unknown edition: " + edition);
218
230
  }
219
231
  this._features = Object.assign(defaults, protoFeatures || {});
232
+ this._featuresResolved = true;
220
233
  return;
221
234
  }
222
235
 
@@ -238,6 +251,7 @@ ReflectionObject.prototype._resolveFeatures = function _resolveFeatures(edition)
238
251
  // Sister fields should have the same features as their extensions.
239
252
  this.extensionField._features = this._features;
240
253
  }
254
+ this._featuresResolved = true;
241
255
  };
242
256
 
243
257
  /**
package/src/parse.js CHANGED
@@ -523,6 +523,10 @@ function parse(source, root, options) {
523
523
  parseEnum(type, token);
524
524
  break;
525
525
 
526
+ case "reserved":
527
+ readRanges(type.reserved || (type.reserved = []), true);
528
+ break;
529
+
526
530
  /* istanbul ignore next */
527
531
  default:
528
532
  throw illegal(token); // there are no groups with proto3 semantics
package/src/root.js CHANGED
@@ -36,8 +36,19 @@ function Root(options) {
36
36
  */
37
37
  this.files = [];
38
38
 
39
- // Default to proto2 if unspecified.
39
+ /**
40
+ * Edition, defaults to proto2 if unspecified.
41
+ * @type {string}
42
+ * @private
43
+ */
40
44
  this._edition = "proto2";
45
+
46
+ /**
47
+ * Global lookup cache of fully qualified names.
48
+ * @type {Object.<string,ReflectionObject>}
49
+ * @private
50
+ */
51
+ this._fullyQualifiedObjects = {};
41
52
  }
42
53
 
43
54
  /**
@@ -99,6 +110,9 @@ Root.prototype.load = function load(filename, options, callback) {
99
110
 
100
111
  // Finishes loading by calling the callback (exactly once)
101
112
  function finish(err, root) {
113
+ if (root) {
114
+ root.resolveAll();
115
+ }
102
116
  /* istanbul ignore if */
103
117
  if (!callback) {
104
118
  return;
@@ -108,9 +122,6 @@ Root.prototype.load = function load(filename, options, callback) {
108
122
  }
109
123
  var cb = callback;
110
124
  callback = null;
111
- if (root) {
112
- root.resolveAll();
113
- }
114
125
  cb(err, root);
115
126
  }
116
127
 
@@ -218,8 +229,8 @@ Root.prototype.load = function load(filename, options, callback) {
218
229
  for (var i = 0, resolved; i < filename.length; ++i)
219
230
  if (resolved = self.resolvePath("", filename[i]))
220
231
  fetch(resolved);
221
- self.resolveAll();
222
232
  if (sync) {
233
+ self.resolveAll();
223
234
  return self;
224
235
  }
225
236
  if (!queued) {
@@ -268,10 +279,13 @@ Root.prototype.loadSync = function loadSync(filename, options) {
268
279
  * @override
269
280
  */
270
281
  Root.prototype.resolveAll = function resolveAll() {
282
+ if (!this._needsRecursiveResolve) return this;
283
+
271
284
  if (this.deferred.length)
272
285
  throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
273
286
  return "'extend " + field.extend + "' in " + field.parent.fullName;
274
287
  }).join(", "));
288
+ this._resolveFeaturesRecursive(this._edition);
275
289
  return Namespace.prototype.resolveAll.call(this);
276
290
  };
277
291
 
@@ -334,6 +348,11 @@ Root.prototype._handleAdd = function _handleAdd(object) {
334
348
  object.parent[object.name] = object; // expose namespace as property of its parent
335
349
  }
336
350
 
351
+ if (object instanceof Type || object instanceof Enum || object instanceof Field) {
352
+ // Only store types and enums for quick lookup during resolve.
353
+ this._fullyQualifiedObjects[object.fullName] = object;
354
+ }
355
+
337
356
  // The above also adds uppercased (and thus conflict-free) nested types, services and enums as
338
357
  // properties of namespaces just like static code does. This allows using a .d.ts generated for
339
358
  // a static module with reflection-based solutions where the condition is met.
@@ -374,6 +393,8 @@ Root.prototype._handleRemove = function _handleRemove(object) {
374
393
  delete object.parent[object.name]; // unexpose namespaces
375
394
 
376
395
  }
396
+
397
+ delete this._fullyQualifiedObjects[object.fullName];
377
398
  };
378
399
 
379
400
  // Sets up cyclic dependencies (called in index-light)
package/src/service.js CHANGED
@@ -110,6 +110,8 @@ Service.prototype.get = function get(name) {
110
110
  * @override
111
111
  */
112
112
  Service.prototype.resolveAll = function resolveAll() {
113
+ if (!this._needsRecursiveResolve) return this;
114
+
113
115
  Namespace.prototype.resolve.call(this);
114
116
  var methods = this.methodsArray;
115
117
  for (var i = 0; i < methods.length; ++i)
@@ -121,6 +123,8 @@ Service.prototype.resolveAll = function resolveAll() {
121
123
  * @override
122
124
  */
123
125
  Service.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
126
+ if (!this._needsRecursiveFeatureResolution) return this;
127
+
124
128
  edition = this._edition || edition;
125
129
 
126
130
  Namespace.prototype._resolveFeaturesRecursive.call(this, edition);
package/src/type.js CHANGED
@@ -303,6 +303,8 @@ Type.prototype.toJSON = function toJSON(toJSONOptions) {
303
303
  * @override
304
304
  */
305
305
  Type.prototype.resolveAll = function resolveAll() {
306
+ if (!this._needsRecursiveResolve) return this;
307
+
306
308
  Namespace.prototype.resolveAll.call(this);
307
309
  var oneofs = this.oneofsArray; i = 0;
308
310
  while (i < oneofs.length)
@@ -317,6 +319,8 @@ Type.prototype.resolveAll = function resolveAll() {
317
319
  * @override
318
320
  */
319
321
  Type.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {
322
+ if (!this._needsRecursiveFeatureResolution) return this;
323
+
320
324
  edition = this._edition || edition;
321
325
 
322
326
  Namespace.prototype._resolveFeaturesRecursive.call(this, edition);