protobufjs 7.4.0 → 8.0.1-experimental

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/src/parse.js CHANGED
@@ -13,6 +13,7 @@ var tokenize = require("./tokenize"),
13
13
  Enum = require("./enum"),
14
14
  Service = require("./service"),
15
15
  Method = require("./method"),
16
+ ReflectionObject = require("./object"),
16
17
  types = require("./types"),
17
18
  util = require("./util");
18
19
 
@@ -24,8 +25,7 @@ var base10Re = /^[1-9][0-9]*$/,
24
25
  base8NegRe = /^-?0[0-7]+$/,
25
26
  numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
26
27
  nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
27
- typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/,
28
- fqTypeRefRe = /^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/;
28
+ typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/;
29
29
 
30
30
  /**
31
31
  * Result object returned from {@link parse}.
@@ -33,7 +33,6 @@ var base10Re = /^[1-9][0-9]*$/,
33
33
  * @property {string|undefined} package Package name, if declared
34
34
  * @property {string[]|undefined} imports Imports, if any
35
35
  * @property {string[]|undefined} weakImports Weak imports, if any
36
- * @property {string|undefined} syntax Syntax, if specified (either `"proto2"` or `"proto3"`)
37
36
  * @property {Root} root Populated root instance
38
37
  */
39
38
 
@@ -81,8 +80,9 @@ function parse(source, root, options) {
81
80
  pkg,
82
81
  imports,
83
82
  weakImports,
84
- syntax,
85
- isProto3 = false;
83
+ edition = "proto2",
84
+ isProto3 = false,
85
+ isProto2 = true;
86
86
 
87
87
  var ptr = root;
88
88
 
@@ -126,7 +126,6 @@ function parse(source, root, options) {
126
126
  try {
127
127
  return parseNumber(token, /* insideTryCatch */ true);
128
128
  } catch (e) {
129
-
130
129
  /* istanbul ignore else */
131
130
  if (acceptTypeRef && typeRefRe.test(token))
132
131
  return token;
@@ -141,8 +140,17 @@ function parse(source, root, options) {
141
140
  do {
142
141
  if (acceptStrings && ((token = peek()) === "\"" || token === "'"))
143
142
  target.push(readString());
144
- else
145
- target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
143
+ else {
144
+ try {
145
+ target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
146
+ } catch (err) {
147
+ if (typeRefRe.test(token) && (!isProto2 && !isProto3)) {
148
+ target.push(token);
149
+ } else {
150
+ throw err;
151
+ }
152
+ }
153
+ }
146
154
  } while (skip(",", true));
147
155
  var dummy = {options: undefined};
148
156
  dummy.setOption = function(name, value) {
@@ -219,7 +227,6 @@ function parse(source, root, options) {
219
227
  }
220
228
 
221
229
  function parsePackage() {
222
-
223
230
  /* istanbul ignore if */
224
231
  if (pkg !== undefined)
225
232
  throw illegal("package");
@@ -231,6 +238,12 @@ function parse(source, root, options) {
231
238
  throw illegal(pkg, "name");
232
239
 
233
240
  ptr = ptr.define(pkg);
241
+
242
+ var oldEdition = ptr.getOption("edition");
243
+ if (oldEdition && oldEdition !== edition) {
244
+ throw new Error("incompatible editions detected in package " + pkg + ": " + edition + " vs " + oldEdition);
245
+ }
246
+ ptr.setOption("edition", edition);
234
247
  skip(";");
235
248
  }
236
249
 
@@ -256,20 +269,38 @@ function parse(source, root, options) {
256
269
 
257
270
  function parseSyntax() {
258
271
  skip("=");
259
- syntax = readString();
260
- isProto3 = syntax === "proto3";
272
+ edition = readString();
273
+ isProto3 = edition === "proto3";
274
+ isProto2 = edition === "proto2";
261
275
 
262
276
  /* istanbul ignore if */
263
- if (!isProto3 && syntax !== "proto2")
264
- throw illegal(syntax, "syntax");
277
+ if (!isProto3 && !isProto2)
278
+ throw illegal(edition, "syntax");
265
279
 
266
280
  // Syntax is needed to understand the meaning of the optional field rule
267
281
  // Otherwise the meaning is ambiguous between proto2 and proto3
268
- root.setOption("syntax", syntax);
282
+ root.setOption("edition", edition);
283
+
284
+ skip(";");
285
+ }
286
+
287
+ function parseEdition() {
288
+ skip("=");
289
+ edition = readString();
290
+ isProto3 = false;
291
+ isProto2 = false;
292
+ const supportedEditions = ["2023"];
293
+
294
+ /* istanbul ignore if */
295
+ if (!supportedEditions.includes(edition))
296
+ throw illegal(edition, "edition");
297
+
298
+ root.setOption("edition", edition);
269
299
 
270
300
  skip(";");
271
301
  }
272
302
 
303
+
273
304
  function parseCommon(parent, token) {
274
305
  switch (token) {
275
306
 
@@ -337,6 +368,9 @@ function parse(source, root, options) {
337
368
  break;
338
369
 
339
370
  case "required":
371
+ if (!isProto2)
372
+ throw illegal(token);
373
+ /* eslint-disable no-fallthrough */
340
374
  case "repeated":
341
375
  parseField(type, token);
342
376
  break;
@@ -345,6 +379,8 @@ function parse(source, root, options) {
345
379
  /* istanbul ignore if */
346
380
  if (isProto3) {
347
381
  parseField(type, "proto3_optional");
382
+ } else if (!isProto2) {
383
+ throw illegal(token);
348
384
  } else {
349
385
  parseField(type, "optional");
350
386
  }
@@ -364,8 +400,9 @@ function parse(source, root, options) {
364
400
 
365
401
  default:
366
402
  /* istanbul ignore if */
367
- if (!isProto3 || !typeRefRe.test(token))
403
+ if (isProto2 || !typeRefRe.test(token)) {
368
404
  throw illegal(token);
405
+ }
369
406
 
370
407
  push(token);
371
408
  parseField(type, "optional");
@@ -399,6 +436,7 @@ function parse(source, root, options) {
399
436
  var name = next();
400
437
 
401
438
  /* istanbul ignore if */
439
+
402
440
  if (!nameRe.test(name))
403
441
  throw illegal(name, "name");
404
442
 
@@ -406,6 +444,7 @@ function parse(source, root, options) {
406
444
  skip("=");
407
445
 
408
446
  var field = new Field(name, parseId(next()), type, rule, extend);
447
+
409
448
  ifBlock(field, function parseField_block(token) {
410
449
 
411
450
  /* istanbul ignore else */
@@ -428,12 +467,6 @@ function parse(source, root, options) {
428
467
  } else {
429
468
  parent.add(field);
430
469
  }
431
-
432
- // JSON defaults to packed=true if not set so we have to set packed=false explicity when
433
- // parsing proto2 descriptors without the option, where applicable. This must be done for
434
- // all known packable types and anything that could be an enum (= is not a basic type).
435
- if (!isProto3 && field.repeated && (types.packed[type] !== undefined || types.basic[type] === undefined))
436
- field.setOption("packed", false, /* ifNotSet */ true);
437
470
  }
438
471
 
439
472
  function parseGroup(parent, rule) {
@@ -459,7 +492,6 @@ function parse(source, root, options) {
459
492
  parseOption(type, token);
460
493
  skip(";");
461
494
  break;
462
-
463
495
  case "required":
464
496
  case "repeated":
465
497
  parseField(type, token);
@@ -588,8 +620,17 @@ function parse(source, root, options) {
588
620
  dummy.setOption = function(name, value) {
589
621
  if (this.options === undefined)
590
622
  this.options = {};
623
+
591
624
  this.options[name] = value;
592
625
  };
626
+ dummy.setParsedOption = function(name, value, propName) {
627
+ // In order to not change existing behavior, only calling
628
+ // this for features
629
+ if (/^features$/.test(name)) {
630
+ return ReflectionObject.prototype.setParsedOption.call(dummy, name, value, propName);
631
+ }
632
+ return undefined;
633
+ };
593
634
  ifBlock(dummy, function parseEnumValue_block(token) {
594
635
 
595
636
  /* istanbul ignore else */
@@ -602,34 +643,42 @@ function parse(source, root, options) {
602
643
  }, function parseEnumValue_line() {
603
644
  parseInlineOptions(dummy); // skip
604
645
  });
605
- parent.add(token, value, dummy.comment, dummy.options);
646
+ parent.add(token, value, dummy.comment, dummy.parsedOptions || dummy.options);
606
647
  }
607
648
 
608
649
  function parseOption(parent, token) {
609
- var isCustom = skip("(", true);
610
-
611
- /* istanbul ignore if */
612
- if (!typeRefRe.test(token = next()))
613
- throw illegal(token, "name");
614
-
615
- var name = token;
616
- var option = name;
617
- var propName;
650
+ var option;
651
+ var propName;
652
+ var isOption = true;
653
+ if (token === "option") {
654
+ token = next();
655
+ }
618
656
 
619
- if (isCustom) {
620
- skip(")");
621
- name = "(" + name + ")";
622
- option = name;
623
- token = peek();
624
- if (fqTypeRefRe.test(token)) {
625
- propName = token.slice(1); //remove '.' before property name
626
- name += token;
627
- next();
657
+ while (token !== "=") {
658
+ if (token === "(") {
659
+ var parensValue = next();
660
+ skip(")");
661
+ token = "(" + parensValue + ")";
662
+ }
663
+ if (isOption) {
664
+ isOption = false;
665
+ if (token.includes(".") && !token.includes("(")) {
666
+ var tokens = token.split(".");
667
+ option = tokens[0] + ".";
668
+ token = tokens[1];
669
+ continue;
670
+ }
671
+ option = token;
672
+ } else {
673
+ propName = propName ? propName += token : token;
674
+ }
675
+ token = next();
628
676
  }
629
- }
630
- skip("=");
631
- var optionValue = parseOptionValue(parent, name);
632
- setParsedOption(parent, option, optionValue, propName);
677
+ var name = propName ? option.concat(propName) : option;
678
+ var optionValue = parseOptionValue(parent, name);
679
+ propName = propName && propName[0] === "." ? propName.slice(1) : propName;
680
+ option = option && option[option.length - 1] === "." ? option.slice(0, -1) : option;
681
+ setParsedOption(parent, option, optionValue, propName);
633
682
  }
634
683
 
635
684
  function parseOptionValue(parent, name) {
@@ -651,12 +700,12 @@ function parse(source, root, options) {
651
700
 
652
701
  skip(":", true);
653
702
 
654
- if (peek() === "{")
655
- value = parseOptionValue(parent, name + "." + token);
656
- else if (peek() === "[") {
703
+ if (peek() === "{") {
657
704
  // option (my_option) = {
658
705
  // repeated_value: [ "foo", "bar" ]
659
706
  // };
707
+ value = parseOptionValue(parent, name + "." + token);
708
+ } else if (peek() === "[") {
660
709
  value = [];
661
710
  var lastValue;
662
711
  if (skip("[", true)) {
@@ -723,8 +772,9 @@ function parse(source, root, options) {
723
772
 
724
773
  var service = new Service(token);
725
774
  ifBlock(service, function parseService_block(token) {
726
- if (parseCommon(service, token))
775
+ if (parseCommon(service, token)) {
727
776
  return;
777
+ }
728
778
 
729
779
  /* istanbul ignore else */
730
780
  if (token === "rpc")
@@ -811,7 +861,7 @@ function parse(source, root, options) {
811
861
 
812
862
  default:
813
863
  /* istanbul ignore if */
814
- if (!isProto3 || !typeRefRe.test(token))
864
+ if (isProto2 || !typeRefRe.test(token))
815
865
  throw illegal(token);
816
866
  push(token);
817
867
  parseField(parent, "optional", reference);
@@ -851,10 +901,16 @@ function parse(source, root, options) {
851
901
  parseSyntax();
852
902
  break;
853
903
 
854
- case "option":
904
+ case "edition":
905
+ /* istanbul ignore if */
906
+ if (!head)
907
+ throw illegal(token);
908
+ parseEdition();
909
+ break;
855
910
 
911
+ case "option":
856
912
  parseOption(ptr, token);
857
- skip(";");
913
+ skip(";", true);
858
914
  break;
859
915
 
860
916
  default:
@@ -875,7 +931,6 @@ function parse(source, root, options) {
875
931
  "package" : pkg,
876
932
  "imports" : imports,
877
933
  weakImports : weakImports,
878
- syntax : syntax,
879
934
  root : root
880
935
  };
881
936
  }
package/src/root.js CHANGED
@@ -35,11 +35,14 @@ function Root(options) {
35
35
  * @type {string[]}
36
36
  */
37
37
  this.files = [];
38
+
39
+ // Default to proto2 if not specified.
40
+ this.setOption("edition", "proto2", true);
38
41
  }
39
42
 
40
43
  /**
41
44
  * Loads a namespace descriptor into a root namespace.
42
- * @param {INamespace} json Nameespace descriptor
45
+ * @param {INamespace} json Namespace descriptor
43
46
  * @param {Root} [root] Root namespace, defaults to create a new one if omitted
44
47
  * @returns {Root} Root namespace
45
48
  */
@@ -88,20 +91,26 @@ Root.prototype.load = function load(filename, options, callback) {
88
91
  options = undefined;
89
92
  }
90
93
  var self = this;
91
- if (!callback)
94
+ if (!callback) {
92
95
  return util.asPromise(load, self, filename, options);
96
+ }
93
97
 
94
98
  var sync = callback === SYNC; // undocumented
95
99
 
96
100
  // Finishes loading by calling the callback (exactly once)
97
101
  function finish(err, root) {
98
102
  /* istanbul ignore if */
99
- if (!callback)
103
+ if (!callback) {
100
104
  return;
101
- if (sync)
105
+ }
106
+ if (sync) {
102
107
  throw err;
108
+ }
103
109
  var cb = callback;
104
110
  callback = null;
111
+ if (root) {
112
+ root.resolveAll();
113
+ }
105
114
  cb(err, root);
106
115
  }
107
116
 
@@ -139,8 +148,9 @@ Root.prototype.load = function load(filename, options, callback) {
139
148
  } catch (err) {
140
149
  finish(err);
141
150
  }
142
- if (!sync && !queued)
151
+ if (!sync && !queued) {
143
152
  finish(null, self); // only once anyway
153
+ }
144
154
  }
145
155
 
146
156
  // Fetches a single file
@@ -148,15 +158,16 @@ Root.prototype.load = function load(filename, options, callback) {
148
158
  filename = getBundledFileName(filename) || filename;
149
159
 
150
160
  // Skip if already loaded / attempted
151
- if (self.files.indexOf(filename) > -1)
161
+ if (self.files.indexOf(filename) > -1) {
152
162
  return;
163
+ }
153
164
  self.files.push(filename);
154
165
 
155
166
  // Shortcut bundled definitions
156
167
  if (filename in common) {
157
- if (sync)
168
+ if (sync) {
158
169
  process(filename, common[filename]);
159
- else {
170
+ } else {
160
171
  ++queued;
161
172
  setTimeout(function() {
162
173
  --queued;
@@ -182,8 +193,9 @@ Root.prototype.load = function load(filename, options, callback) {
182
193
  self.fetch(filename, function(err, source) {
183
194
  --queued;
184
195
  /* istanbul ignore if */
185
- if (!callback)
196
+ if (!callback) {
186
197
  return; // terminated meanwhile
198
+ }
187
199
  if (err) {
188
200
  /* istanbul ignore else */
189
201
  if (!weak)
@@ -200,17 +212,21 @@ Root.prototype.load = function load(filename, options, callback) {
200
212
 
201
213
  // Assembling the root namespace doesn't require working type
202
214
  // references anymore, so we can load everything in parallel
203
- if (util.isString(filename))
215
+ if (util.isString(filename)) {
204
216
  filename = [ filename ];
217
+ }
205
218
  for (var i = 0, resolved; i < filename.length; ++i)
206
219
  if (resolved = self.resolvePath("", filename[i]))
207
220
  fetch(resolved);
208
-
209
- if (sync)
221
+ self.resolveAll();
222
+ if (sync) {
210
223
  return self;
211
- if (!queued)
224
+ }
225
+ if (!queued) {
212
226
  finish(null, self);
213
- return undefined;
227
+ }
228
+
229
+ return self;
214
230
  };
215
231
  // function load(filename:string, options:IParseOptions, callback:LoadCallback):undefined
216
232
 
package/src/service.js CHANGED
@@ -106,10 +106,11 @@ Service.prototype.get = function get(name) {
106
106
  * @override
107
107
  */
108
108
  Service.prototype.resolveAll = function resolveAll() {
109
+ Namespace.prototype.resolve.call(this);
109
110
  var methods = this.methodsArray;
110
111
  for (var i = 0; i < methods.length; ++i)
111
112
  methods[i].resolve();
112
- return Namespace.prototype.resolve.call(this);
113
+ return this;
113
114
  };
114
115
 
115
116
  /**
package/src/type.js CHANGED
@@ -299,13 +299,14 @@ Type.prototype.toJSON = function toJSON(toJSONOptions) {
299
299
  * @override
300
300
  */
301
301
  Type.prototype.resolveAll = function resolveAll() {
302
- var fields = this.fieldsArray, i = 0;
303
- while (i < fields.length)
304
- fields[i++].resolve();
302
+ Namespace.prototype.resolveAll.call(this);
305
303
  var oneofs = this.oneofsArray; i = 0;
306
304
  while (i < oneofs.length)
307
305
  oneofs[i++].resolve();
308
- return Namespace.prototype.resolveAll.call(this);
306
+ var fields = this.fieldsArray, i = 0;
307
+ while (i < fields.length)
308
+ fields[i++].resolve();
309
+ return this;
309
310
  };
310
311
 
311
312
  /**
package/src/util.js CHANGED
@@ -171,6 +171,7 @@ util.decorateEnum = function decorateEnum(object) {
171
171
  * @param {Object.<string,*>} dst Destination object
172
172
  * @param {string} path dot '.' delimited path of the property to set
173
173
  * @param {Object} value the value to set
174
+ * @param {boolean} overWrite whether or not to concatenate the values into an array or overwrite; defaults to false.
174
175
  * @returns {Object.<string,*>} Destination object
175
176
  */
176
177
  util.setProperty = function setProperty(dst, path, value) {