protobufjs 8.0.3-experimental → 8.0.3

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.
Files changed (98) hide show
  1. package/LICENSE +39 -39
  2. package/README.md +727 -727
  3. package/dist/light/protobuf.js +7724 -7352
  4. package/dist/light/protobuf.js.map +1 -1
  5. package/dist/light/protobuf.min.js +3 -3
  6. package/dist/light/protobuf.min.js.map +1 -1
  7. package/dist/minimal/protobuf.js +2606 -2546
  8. package/dist/minimal/protobuf.js.map +1 -1
  9. package/dist/minimal/protobuf.min.js +3 -3
  10. package/dist/minimal/protobuf.min.js.map +1 -1
  11. package/dist/protobuf.js +9588 -9131
  12. package/dist/protobuf.js.map +1 -1
  13. package/dist/protobuf.min.js +3 -3
  14. package/dist/protobuf.min.js.map +1 -1
  15. package/ext/debug/README.md +4 -4
  16. package/ext/debug/index.js +71 -71
  17. package/ext/descriptor/README.md +72 -72
  18. package/ext/descriptor/index.d.ts +195 -191
  19. package/ext/descriptor/index.js +1181 -1052
  20. package/ext/descriptor/test.js +54 -54
  21. package/google/LICENSE +27 -27
  22. package/google/README.md +1 -1
  23. package/google/api/annotations.json +82 -82
  24. package/google/api/annotations.proto +10 -10
  25. package/google/api/http.json +85 -85
  26. package/google/api/http.proto +30 -30
  27. package/google/protobuf/api.json +117 -117
  28. package/google/protobuf/api.proto +33 -33
  29. package/google/protobuf/descriptor.json +1381 -738
  30. package/google/protobuf/descriptor.proto +535 -286
  31. package/google/protobuf/source_context.json +19 -19
  32. package/google/protobuf/source_context.proto +7 -7
  33. package/google/protobuf/type.json +201 -201
  34. package/google/protobuf/type.proto +89 -89
  35. package/index.d.ts +2817 -2792
  36. package/index.js +4 -4
  37. package/light.d.ts +2 -2
  38. package/light.js +3 -3
  39. package/minimal.d.ts +2 -2
  40. package/minimal.js +4 -4
  41. package/package.json +96 -112
  42. package/scripts/postinstall.js +32 -32
  43. package/src/common.js +399 -399
  44. package/src/converter.js +310 -301
  45. package/src/decoder.js +135 -127
  46. package/src/encoder.js +100 -100
  47. package/src/enum.js +226 -241
  48. package/src/field.js +453 -432
  49. package/src/index-light.js +104 -104
  50. package/src/index-minimal.js +36 -36
  51. package/src/index.js +12 -12
  52. package/src/mapfield.js +126 -126
  53. package/src/message.js +139 -139
  54. package/src/method.js +160 -160
  55. package/src/namespace.js +550 -434
  56. package/src/object.js +385 -330
  57. package/src/oneof.js +222 -222
  58. package/src/parse.js +1024 -944
  59. package/src/reader.js +426 -416
  60. package/src/reader_buffer.js +51 -51
  61. package/src/root.js +404 -384
  62. package/src/roots.js +17 -17
  63. package/src/rpc/service.js +142 -142
  64. package/src/rpc.js +36 -36
  65. package/src/service.js +193 -168
  66. package/src/tokenize.js +421 -416
  67. package/src/type.js +625 -590
  68. package/src/types.js +196 -196
  69. package/src/typescript.jsdoc +15 -15
  70. package/src/util/aspromise.d.ts +13 -0
  71. package/src/util/aspromise.js +52 -0
  72. package/src/util/base64.d.ts +32 -0
  73. package/src/util/base64.js +139 -0
  74. package/src/util/codegen.d.ts +31 -0
  75. package/src/util/codegen.js +113 -0
  76. package/src/util/eventemitter.d.ts +45 -0
  77. package/src/util/eventemitter.js +84 -0
  78. package/src/util/fetch.d.ts +56 -0
  79. package/src/util/fetch.js +114 -0
  80. package/src/util/float.d.ts +83 -0
  81. package/src/util/float.js +335 -0
  82. package/src/util/inquire.d.ts +9 -0
  83. package/src/util/inquire.js +37 -0
  84. package/src/util/longbits.js +200 -200
  85. package/src/util/minimal.js +461 -438
  86. package/src/util/path.d.ts +22 -0
  87. package/src/util/path.js +72 -0
  88. package/src/util/patterns.js +8 -0
  89. package/src/util/pool.d.ts +32 -0
  90. package/src/util/pool.js +48 -0
  91. package/src/util/utf8.d.ts +24 -0
  92. package/src/util/utf8.js +104 -0
  93. package/src/util.js +215 -213
  94. package/src/verifier.js +180 -177
  95. package/src/wrappers.js +103 -102
  96. package/src/writer.js +465 -465
  97. package/src/writer_buffer.js +85 -85
  98. package/tsconfig.json +8 -8
package/src/parse.js CHANGED
@@ -1,948 +1,1028 @@
1
- "use strict";
2
- module.exports = parse;
3
-
4
- parse.filename = null;
5
- parse.defaults = { keepCase: false };
6
-
7
- var tokenize = require("./tokenize"),
8
- Root = require("./root"),
9
- Type = require("./type"),
10
- Field = require("./field"),
11
- MapField = require("./mapfield"),
12
- OneOf = require("./oneof"),
13
- Enum = require("./enum"),
14
- Service = require("./service"),
15
- Method = require("./method"),
16
- ReflectionObject = require("./object"),
17
- types = require("./types"),
18
- util = require("./util");
19
-
20
- var base10Re = /^[1-9][0-9]*$/,
21
- base10NegRe = /^-?[1-9][0-9]*$/,
22
- base16Re = /^0[x][0-9a-fA-F]+$/,
23
- base16NegRe = /^-?0[x][0-9a-fA-F]+$/,
24
- base8Re = /^0[0-7]+$/,
25
- base8NegRe = /^-?0[0-7]+$/,
26
- numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
27
- nameRe = /^[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
-
30
- /**
31
- * Result object returned from {@link parse}.
32
- * @interface IParserResult
33
- * @property {string|undefined} package Package name, if declared
34
- * @property {string[]|undefined} imports Imports, if any
35
- * @property {string[]|undefined} weakImports Weak imports, if any
36
- * @property {Root} root Populated root instance
37
- */
38
-
39
- /**
40
- * Options modifying the behavior of {@link parse}.
41
- * @interface IParseOptions
42
- * @property {boolean} [keepCase=false] Keeps field casing instead of converting to camel case
43
- * @property {boolean} [alternateCommentMode=false] Recognize double-slash comments in addition to doc-block comments.
44
- * @property {boolean} [preferTrailingComment=false] Use trailing comment when both leading comment and trailing comment exist.
45
- */
46
-
47
- /**
48
- * Options modifying the behavior of JSON serialization.
49
- * @interface IToJSONOptions
50
- * @property {boolean} [keepComments=false] Serializes comments.
51
- */
52
-
53
- /**
54
- * Parses the given .proto source and returns an object with the parsed contents.
55
- * @param {string} source Source contents
56
- * @param {Root} root Root to populate
57
- * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
58
- * @returns {IParserResult} Parser result
59
- * @property {string} filename=null Currently processing file name for error reporting, if known
60
- * @property {IParseOptions} defaults Default {@link IParseOptions}
61
- */
62
- function parse(source, root, options) {
63
- /* eslint-disable callback-return */
64
- if (!(root instanceof Root)) {
65
- options = root;
66
- root = new Root();
67
- }
68
- if (!options)
69
- options = parse.defaults;
70
-
71
- var preferTrailingComment = options.preferTrailingComment || false;
72
- var tn = tokenize(source, options.alternateCommentMode || false),
73
- next = tn.next,
74
- push = tn.push,
75
- peek = tn.peek,
76
- skip = tn.skip,
77
- cmnt = tn.cmnt;
78
-
79
- var head = true,
80
- pkg,
81
- imports,
82
- weakImports,
83
- edition = "proto2",
84
- isProto3 = false,
85
- isProto2 = true;
86
-
87
- var ptr = root;
88
-
89
- var applyCase = options.keepCase ? function(name) { return name; } : util.camelCase;
90
-
91
- /* istanbul ignore next */
92
- function illegal(token, name, insideTryCatch) {
93
- var filename = parse.filename;
94
- if (!insideTryCatch)
95
- parse.filename = null;
96
- return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
97
- }
98
-
99
- function readString() {
100
- var values = [],
101
- token;
102
- do {
103
- /* istanbul ignore if */
104
- if ((token = next()) !== "\"" && token !== "'")
105
- throw illegal(token);
106
-
107
- values.push(next());
108
- skip(token);
109
- token = peek();
110
- } while (token === "\"" || token === "'");
111
- return values.join("");
112
- }
113
-
114
- function readValue(acceptTypeRef) {
115
- var token = next();
116
- switch (token) {
117
- case "'":
118
- case "\"":
119
- push(token);
120
- return readString();
121
- case "true": case "TRUE":
122
- return true;
123
- case "false": case "FALSE":
124
- return false;
125
- }
126
- try {
127
- return parseNumber(token, /* insideTryCatch */ true);
128
- } catch (e) {
129
- /* istanbul ignore else */
130
- if (acceptTypeRef && typeRefRe.test(token))
131
- return token;
132
-
133
- /* istanbul ignore next */
134
- throw illegal(token, "value");
135
- }
136
- }
137
-
138
- function readRanges(target, acceptStrings) {
139
- var token, start;
140
- do {
141
- if (acceptStrings && ((token = peek()) === "\"" || token === "'"))
142
- target.push(readString());
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
- }
154
- } while (skip(",", true));
155
- var dummy = {options: undefined};
156
- dummy.setOption = function(name, value) {
157
- if (this.options === undefined) this.options = {};
158
- this.options[name] = value;
159
- };
160
- ifBlock(
161
- dummy,
162
- function parseRange_block(token) {
163
- /* istanbul ignore else */
164
- if (token === "option") {
165
- parseOption(dummy, token); // skip
166
- skip(";");
167
- } else
168
- throw illegal(token);
169
- },
170
- function parseRange_line() {
171
- parseInlineOptions(dummy); // skip
172
- });
173
- }
174
-
175
- function parseNumber(token, insideTryCatch) {
176
- var sign = 1;
177
- if (token.charAt(0) === "-") {
178
- sign = -1;
179
- token = token.substring(1);
180
- }
181
- switch (token) {
182
- case "inf": case "INF": case "Inf":
183
- return sign * Infinity;
184
- case "nan": case "NAN": case "Nan": case "NaN":
185
- return NaN;
186
- case "0":
187
- return 0;
188
- }
189
- if (base10Re.test(token))
190
- return sign * parseInt(token, 10);
191
- if (base16Re.test(token))
192
- return sign * parseInt(token, 16);
193
- if (base8Re.test(token))
194
- return sign * parseInt(token, 8);
195
-
196
- /* istanbul ignore else */
197
- if (numberRe.test(token))
198
- return sign * parseFloat(token);
199
-
200
- /* istanbul ignore next */
201
- throw illegal(token, "number", insideTryCatch);
202
- }
203
-
204
- function parseId(token, acceptNegative) {
205
- switch (token) {
206
- case "max": case "MAX": case "Max":
207
- return 536870911;
208
- case "0":
209
- return 0;
210
- }
211
-
212
- /* istanbul ignore if */
213
- if (!acceptNegative && token.charAt(0) === "-")
214
- throw illegal(token, "id");
215
-
216
- if (base10NegRe.test(token))
217
- return parseInt(token, 10);
218
- if (base16NegRe.test(token))
219
- return parseInt(token, 16);
220
-
221
- /* istanbul ignore else */
222
- if (base8NegRe.test(token))
223
- return parseInt(token, 8);
224
-
225
- /* istanbul ignore next */
226
- throw illegal(token, "id");
227
- }
228
-
229
- function parsePackage() {
230
- /* istanbul ignore if */
231
- if (pkg !== undefined)
232
- throw illegal("package");
233
-
234
- pkg = next();
235
-
236
- /* istanbul ignore if */
237
- if (!typeRefRe.test(pkg))
238
- throw illegal(pkg, "name");
239
-
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);
247
- skip(";");
248
- }
249
-
250
- function parseImport() {
251
- var token = peek();
252
- var whichImports;
253
- switch (token) {
254
- case "weak":
255
- whichImports = weakImports || (weakImports = []);
256
- next();
257
- break;
258
- case "public":
259
- next();
260
- // eslint-disable-next-line no-fallthrough
261
- default:
262
- whichImports = imports || (imports = []);
263
- break;
264
- }
265
- token = readString();
266
- skip(";");
267
- whichImports.push(token);
268
- }
269
-
270
- function parseSyntax() {
271
- skip("=");
272
- edition = readString();
273
- isProto3 = edition === "proto3";
274
- isProto2 = edition === "proto2";
275
-
276
- /* istanbul ignore if */
277
- if (!isProto3 && !isProto2)
278
- throw illegal(edition, "syntax");
279
-
280
- // Syntax is needed to understand the meaning of the optional field rule
281
- // Otherwise the meaning is ambiguous between proto2 and proto3
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);
299
-
300
- skip(";");
301
- }
302
-
303
-
304
- function parseCommon(parent, token) {
305
- switch (token) {
306
-
307
- case "option":
308
- parseOption(parent, token);
309
- skip(";");
310
- return true;
311
-
312
- case "message":
313
- parseType(parent, token);
314
- return true;
315
-
316
- case "enum":
317
- parseEnum(parent, token);
318
- return true;
319
-
320
- case "service":
321
- parseService(parent, token);
322
- return true;
323
-
324
- case "extend":
325
- parseExtension(parent, token);
326
- return true;
327
- }
328
- return false;
329
- }
330
-
331
- function ifBlock(obj, fnIf, fnElse) {
332
- var trailingLine = tn.line;
333
- if (obj) {
334
- if(typeof obj.comment !== "string") {
335
- obj.comment = cmnt(); // try block-type comment
336
- }
337
- obj.filename = parse.filename;
338
- }
339
- if (skip("{", true)) {
340
- var token;
341
- while ((token = next()) !== "}")
342
- fnIf(token);
343
- skip(";", true);
344
- } else {
345
- if (fnElse)
346
- fnElse();
347
- skip(";");
348
- if (obj && (typeof obj.comment !== "string" || preferTrailingComment))
349
- obj.comment = cmnt(trailingLine) || obj.comment; // try line-type comment
350
- }
351
- }
352
-
353
- function parseType(parent, token) {
354
-
355
- /* istanbul ignore if */
356
- if (!nameRe.test(token = next()))
357
- throw illegal(token, "type name");
358
-
359
- var type = new Type(token);
360
- ifBlock(type, function parseType_block(token) {
361
- if (parseCommon(type, token))
362
- return;
363
-
364
- switch (token) {
365
-
366
- case "map":
367
- parseMapField(type, token);
368
- break;
369
-
370
- case "required":
371
- if (!isProto2)
372
- throw illegal(token);
373
- /* eslint-disable no-fallthrough */
374
- case "repeated":
375
- parseField(type, token);
376
- break;
377
-
378
- case "optional":
379
- /* istanbul ignore if */
380
- if (isProto3) {
381
- parseField(type, "proto3_optional");
382
- } else if (!isProto2) {
383
- throw illegal(token);
384
- } else {
385
- parseField(type, "optional");
386
- }
387
- break;
388
-
389
- case "oneof":
390
- parseOneOf(type, token);
391
- break;
392
-
393
- case "extensions":
394
- readRanges(type.extensions || (type.extensions = []));
395
- break;
396
-
397
- case "reserved":
398
- readRanges(type.reserved || (type.reserved = []), true);
399
- break;
400
-
401
- default:
402
- /* istanbul ignore if */
403
- if (isProto2 || !typeRefRe.test(token)) {
404
- throw illegal(token);
405
- }
406
-
407
- push(token);
408
- parseField(type, "optional");
409
- break;
410
- }
411
- });
412
- parent.add(type);
413
- }
414
-
415
- function parseField(parent, rule, extend) {
416
- var type = next();
417
- if (type === "group") {
418
- parseGroup(parent, rule);
419
- return;
420
- }
421
- // Type names can consume multiple tokens, in multiple variants:
422
- // package.subpackage field tokens: "package.subpackage" [TYPE NAME ENDS HERE] "field"
423
- // package . subpackage field tokens: "package" "." "subpackage" [TYPE NAME ENDS HERE] "field"
424
- // package. subpackage field tokens: "package." "subpackage" [TYPE NAME ENDS HERE] "field"
425
- // package .subpackage field tokens: "package" ".subpackage" [TYPE NAME ENDS HERE] "field"
426
- // Keep reading tokens until we get a type name with no period at the end,
427
- // and the next token does not start with a period.
428
- while (type.endsWith(".") || peek().startsWith(".")) {
429
- type += next();
430
- }
431
-
432
- /* istanbul ignore if */
433
- if (!typeRefRe.test(type))
434
- throw illegal(type, "type");
435
-
436
- var name = next();
437
-
438
- /* istanbul ignore if */
439
-
440
- if (!nameRe.test(name))
441
- throw illegal(name, "name");
442
-
443
- name = applyCase(name);
444
- skip("=");
445
-
446
- var field = new Field(name, parseId(next()), type, rule, extend);
447
-
448
- ifBlock(field, function parseField_block(token) {
449
-
450
- /* istanbul ignore else */
451
- if (token === "option") {
452
- parseOption(field, token);
453
- skip(";");
454
- } else
455
- throw illegal(token);
456
-
457
- }, function parseField_line() {
458
- parseInlineOptions(field);
459
- });
460
-
461
- if (rule === "proto3_optional") {
462
- // for proto3 optional fields, we create a single-member Oneof to mimic "optional" behavior
463
- var oneof = new OneOf("_" + name);
464
- field.setOption("proto3_optional", true);
465
- oneof.add(field);
466
- parent.add(oneof);
467
- } else {
468
- parent.add(field);
469
- }
470
- }
471
-
472
- function parseGroup(parent, rule) {
473
- var name = next();
474
-
475
- /* istanbul ignore if */
476
- if (!nameRe.test(name))
477
- throw illegal(name, "name");
478
-
479
- var fieldName = util.lcFirst(name);
480
- if (name === fieldName)
481
- name = util.ucFirst(name);
482
- skip("=");
483
- var id = parseId(next());
484
- var type = new Type(name);
485
- type.group = true;
486
- var field = new Field(fieldName, id, name, rule);
487
- field.filename = parse.filename;
488
- ifBlock(type, function parseGroup_block(token) {
489
- switch (token) {
490
-
491
- case "option":
492
- parseOption(type, token);
493
- skip(";");
494
- break;
495
- case "required":
496
- case "repeated":
497
- parseField(type, token);
498
- break;
499
-
500
- case "optional":
501
- /* istanbul ignore if */
502
- if (isProto3) {
503
- parseField(type, "proto3_optional");
504
- } else {
505
- parseField(type, "optional");
506
- }
507
- break;
508
-
509
- case "message":
510
- parseType(type, token);
511
- break;
512
-
513
- case "enum":
514
- parseEnum(type, token);
515
- break;
516
-
517
- /* istanbul ignore next */
518
- default:
519
- throw illegal(token); // there are no groups with proto3 semantics
520
- }
521
- });
522
- parent.add(type)
523
- .add(field);
524
- }
525
-
526
- function parseMapField(parent) {
527
- skip("<");
528
- var keyType = next();
529
-
530
- /* istanbul ignore if */
531
- if (types.mapKey[keyType] === undefined)
532
- throw illegal(keyType, "type");
533
-
534
- skip(",");
535
- var valueType = next();
536
-
537
- /* istanbul ignore if */
538
- if (!typeRefRe.test(valueType))
539
- throw illegal(valueType, "type");
540
-
541
- skip(">");
542
- var name = next();
543
-
544
- /* istanbul ignore if */
545
- if (!nameRe.test(name))
546
- throw illegal(name, "name");
547
-
548
- skip("=");
549
- var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
550
- ifBlock(field, function parseMapField_block(token) {
551
-
552
- /* istanbul ignore else */
553
- if (token === "option") {
554
- parseOption(field, token);
555
- skip(";");
556
- } else
557
- throw illegal(token);
558
-
559
- }, function parseMapField_line() {
560
- parseInlineOptions(field);
561
- });
562
- parent.add(field);
563
- }
564
-
565
- function parseOneOf(parent, token) {
566
-
567
- /* istanbul ignore if */
568
- if (!nameRe.test(token = next()))
569
- throw illegal(token, "name");
570
-
571
- var oneof = new OneOf(applyCase(token));
572
- ifBlock(oneof, function parseOneOf_block(token) {
573
- if (token === "option") {
574
- parseOption(oneof, token);
575
- skip(";");
576
- } else {
577
- push(token);
578
- parseField(oneof, "optional");
579
- }
580
- });
581
- parent.add(oneof);
582
- }
583
-
584
- function parseEnum(parent, token) {
585
-
586
- /* istanbul ignore if */
587
- if (!nameRe.test(token = next()))
588
- throw illegal(token, "name");
589
-
590
- var enm = new Enum(token);
591
- ifBlock(enm, function parseEnum_block(token) {
592
- switch(token) {
593
- case "option":
594
- parseOption(enm, token);
595
- skip(";");
596
- break;
597
-
598
- case "reserved":
599
- readRanges(enm.reserved || (enm.reserved = []), true);
600
- break;
601
-
602
- default:
603
- parseEnumValue(enm, token);
604
- }
605
- });
606
- parent.add(enm);
607
- }
608
-
609
- function parseEnumValue(parent, token) {
610
-
611
- /* istanbul ignore if */
612
- if (!nameRe.test(token))
613
- throw illegal(token, "name");
614
-
615
- skip("=");
616
- var value = parseId(next(), true),
617
- dummy = {
618
- options: undefined
619
- };
620
- dummy.setOption = function(name, value) {
621
- if (this.options === undefined)
622
- this.options = {};
623
-
624
- this.options[name] = value;
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
- };
634
- ifBlock(dummy, function parseEnumValue_block(token) {
635
-
636
- /* istanbul ignore else */
637
- if (token === "option") {
638
- parseOption(dummy, token); // skip
639
- skip(";");
640
- } else
641
- throw illegal(token);
642
-
643
- }, function parseEnumValue_line() {
644
- parseInlineOptions(dummy); // skip
645
- });
646
- parent.add(token, value, dummy.comment, dummy.parsedOptions || dummy.options);
647
- }
648
-
649
- function parseOption(parent, token) {
650
- var option;
651
- var propName;
652
- var isOption = true;
653
- if (token === "option") {
654
- token = next();
655
- }
656
-
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();
676
- }
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);
682
- }
683
-
684
- function parseOptionValue(parent, name) {
685
- // { a: "foo" b { c: "bar" } }
686
- if (skip("{", true)) {
687
- var objectResult = {};
688
-
689
- while (!skip("}", true)) {
690
- /* istanbul ignore if */
691
- if (!nameRe.test(token = next())) {
692
- throw illegal(token, "name");
693
- }
694
- if (token === null) {
695
- throw illegal(token, "end of input");
696
- }
697
-
698
- var value;
699
- var propName = token;
700
-
701
- skip(":", true);
702
-
703
- if (peek() === "{") {
704
- // option (my_option) = {
705
- // repeated_value: [ "foo", "bar" ]
706
- // };
707
- value = parseOptionValue(parent, name + "." + token);
708
- } else if (peek() === "[") {
709
- value = [];
710
- var lastValue;
711
- if (skip("[", true)) {
712
- do {
713
- lastValue = readValue(true);
714
- value.push(lastValue);
715
- } while (skip(",", true));
716
- skip("]");
717
- if (typeof lastValue !== "undefined") {
718
- setOption(parent, name + "." + token, lastValue);
719
- }
720
- }
721
- } else {
722
- value = readValue(true);
723
- setOption(parent, name + "." + token, value);
724
- }
725
-
726
- var prevValue = objectResult[propName];
727
-
728
- if (prevValue)
729
- value = [].concat(prevValue).concat(value);
730
-
731
- objectResult[propName] = value;
732
-
733
- // Semicolons and commas can be optional
734
- skip(",", true);
735
- skip(";", true);
736
- }
737
-
738
- return objectResult;
739
- }
740
-
741
- var simpleValue = readValue(true);
742
- setOption(parent, name, simpleValue);
743
- return simpleValue;
744
- // Does not enforce a delimiter to be universal
745
- }
746
-
747
- function setOption(parent, name, value) {
748
- if (parent.setOption)
749
- parent.setOption(name, value);
750
- }
751
-
752
- function setParsedOption(parent, name, value, propName) {
753
- if (parent.setParsedOption)
754
- parent.setParsedOption(name, value, propName);
755
- }
756
-
757
- function parseInlineOptions(parent) {
758
- if (skip("[", true)) {
759
- do {
760
- parseOption(parent, "option");
761
- } while (skip(",", true));
762
- skip("]");
763
- }
764
- return parent;
765
- }
766
-
767
- function parseService(parent, token) {
768
-
769
- /* istanbul ignore if */
770
- if (!nameRe.test(token = next()))
771
- throw illegal(token, "service name");
772
-
773
- var service = new Service(token);
774
- ifBlock(service, function parseService_block(token) {
775
- if (parseCommon(service, token)) {
776
- return;
777
- }
778
-
779
- /* istanbul ignore else */
780
- if (token === "rpc")
781
- parseMethod(service, token);
782
- else
783
- throw illegal(token);
784
- });
785
- parent.add(service);
786
- }
787
-
788
- function parseMethod(parent, token) {
789
- // Get the comment of the preceding line now (if one exists) in case the
790
- // method is defined across multiple lines.
791
- var commentText = cmnt();
792
-
793
- var type = token;
794
-
795
- /* istanbul ignore if */
796
- if (!nameRe.test(token = next()))
797
- throw illegal(token, "name");
798
-
799
- var name = token,
800
- requestType, requestStream,
801
- responseType, responseStream;
802
-
803
- skip("(");
804
- if (skip("stream", true))
805
- requestStream = true;
806
-
807
- /* istanbul ignore if */
808
- if (!typeRefRe.test(token = next()))
809
- throw illegal(token);
810
-
811
- requestType = token;
812
- skip(")"); skip("returns"); skip("(");
813
- if (skip("stream", true))
814
- responseStream = true;
815
-
816
- /* istanbul ignore if */
817
- if (!typeRefRe.test(token = next()))
818
- throw illegal(token);
819
-
820
- responseType = token;
821
- skip(")");
822
-
823
- var method = new Method(name, type, requestType, responseType, requestStream, responseStream);
824
- method.comment = commentText;
825
- ifBlock(method, function parseMethod_block(token) {
826
-
827
- /* istanbul ignore else */
828
- if (token === "option") {
829
- parseOption(method, token);
830
- skip(";");
831
- } else
832
- throw illegal(token);
833
-
834
- });
835
- parent.add(method);
836
- }
837
-
838
- function parseExtension(parent, token) {
839
-
840
- /* istanbul ignore if */
841
- if (!typeRefRe.test(token = next()))
842
- throw illegal(token, "reference");
843
-
844
- var reference = token;
845
- ifBlock(null, function parseExtension_block(token) {
846
- switch (token) {
847
-
848
- case "required":
849
- case "repeated":
850
- parseField(parent, token, reference);
851
- break;
852
-
853
- case "optional":
854
- /* istanbul ignore if */
855
- if (isProto3) {
856
- parseField(parent, "proto3_optional", reference);
857
- } else {
858
- parseField(parent, "optional", reference);
859
- }
860
- break;
861
-
862
- default:
863
- /* istanbul ignore if */
864
- if (isProto2 || !typeRefRe.test(token))
865
- throw illegal(token);
866
- push(token);
867
- parseField(parent, "optional", reference);
868
- break;
869
- }
870
- });
871
- }
872
-
873
- var token;
874
- while ((token = next()) !== null) {
875
- switch (token) {
876
-
877
- case "package":
878
-
879
- /* istanbul ignore if */
880
- if (!head)
881
- throw illegal(token);
882
-
883
- parsePackage();
884
- break;
885
-
1
+ "use strict";
2
+ module.exports = parse;
3
+
4
+ parse.filename = null;
5
+ parse.defaults = { keepCase: false };
6
+
7
+ var tokenize = require("./tokenize"),
8
+ Root = require("./root"),
9
+ Type = require("./type"),
10
+ Field = require("./field"),
11
+ MapField = require("./mapfield"),
12
+ OneOf = require("./oneof"),
13
+ Enum = require("./enum"),
14
+ Service = require("./service"),
15
+ Method = require("./method"),
16
+ ReflectionObject = require("./object"),
17
+ types = require("./types"),
18
+ util = require("./util");
19
+
20
+ var base10Re = /^[1-9][0-9]*$/,
21
+ base10NegRe = /^-?[1-9][0-9]*$/,
22
+ base16Re = /^0[x][0-9a-fA-F]+$/,
23
+ base16NegRe = /^-?0[x][0-9a-fA-F]+$/,
24
+ base8Re = /^0[0-7]+$/,
25
+ base8NegRe = /^-?0[0-7]+$/,
26
+ numberRe = util.patterns.numberRe,
27
+ nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
28
+ typeRefRe = util.patterns.typeRefRe;
29
+
30
+ /**
31
+ * Result object returned from {@link parse}.
32
+ * @interface IParserResult
33
+ * @property {string|undefined} package Package name, if declared
34
+ * @property {string[]|undefined} imports Imports, if any
35
+ * @property {string[]|undefined} weakImports Weak imports, if any
36
+ * @property {Root} root Populated root instance
37
+ */
38
+
39
+ /**
40
+ * Options modifying the behavior of {@link parse}.
41
+ * @interface IParseOptions
42
+ * @property {boolean} [keepCase=false] Keeps field casing instead of converting to camel case
43
+ * @property {boolean} [alternateCommentMode=false] Recognize double-slash comments in addition to doc-block comments.
44
+ * @property {boolean} [preferTrailingComment=false] Use trailing comment when both leading comment and trailing comment exist.
45
+ */
46
+
47
+ /**
48
+ * Options modifying the behavior of JSON serialization.
49
+ * @interface IToJSONOptions
50
+ * @property {boolean} [keepComments=false] Serializes comments.
51
+ */
52
+
53
+ /**
54
+ * Parses the given .proto source and returns an object with the parsed contents.
55
+ * @param {string} source Source contents
56
+ * @param {Root} root Root to populate
57
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
58
+ * @returns {IParserResult} Parser result
59
+ * @property {string} filename=null Currently processing file name for error reporting, if known
60
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
61
+ */
62
+ function parse(source, root, options) {
63
+ /* eslint-disable callback-return */
64
+ if (!(root instanceof Root)) {
65
+ options = root;
66
+ root = new Root();
67
+ }
68
+ if (!options)
69
+ options = parse.defaults;
70
+
71
+ var preferTrailingComment = options.preferTrailingComment || false;
72
+ var tn = tokenize(source, options.alternateCommentMode || false),
73
+ next = tn.next,
74
+ push = tn.push,
75
+ peek = tn.peek,
76
+ skip = tn.skip,
77
+ cmnt = tn.cmnt;
78
+
79
+ var head = true,
80
+ pkg,
81
+ imports,
82
+ weakImports,
83
+ edition = "proto2";
84
+
85
+ var ptr = root;
86
+
87
+ var topLevelObjects = [];
88
+ var topLevelOptions = {};
89
+
90
+ var applyCase = options.keepCase ? function(name) { return name; } : util.camelCase;
91
+
92
+ function resolveFileFeatures() {
93
+ topLevelObjects.forEach(obj => {
94
+ obj._edition = edition;
95
+ Object.keys(topLevelOptions).forEach(opt => {
96
+ if (obj.getOption(opt) !== undefined) return;
97
+ obj.setOption(opt, topLevelOptions[opt], true);
98
+ });
99
+ });
100
+ }
101
+
102
+ /* istanbul ignore next */
103
+ function illegal(token, name, insideTryCatch) {
104
+ var filename = parse.filename;
105
+ if (!insideTryCatch)
106
+ parse.filename = null;
107
+ return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
108
+ }
109
+
110
+ function readString() {
111
+ var values = [],
112
+ token;
113
+ do {
114
+ /* istanbul ignore if */
115
+ if ((token = next()) !== "\"" && token !== "'")
116
+ throw illegal(token);
117
+
118
+ values.push(next());
119
+ skip(token);
120
+ token = peek();
121
+ } while (token === "\"" || token === "'");
122
+ return values.join("");
123
+ }
124
+
125
+ function readValue(acceptTypeRef) {
126
+ var token = next();
127
+ switch (token) {
128
+ case "'":
129
+ case "\"":
130
+ push(token);
131
+ return readString();
132
+ case "true": case "TRUE":
133
+ return true;
134
+ case "false": case "FALSE":
135
+ return false;
136
+ }
137
+ try {
138
+ return parseNumber(token, /* insideTryCatch */ true);
139
+ } catch (e) {
140
+ /* istanbul ignore else */
141
+ if (acceptTypeRef && typeRefRe.test(token))
142
+ return token;
143
+
144
+ /* istanbul ignore next */
145
+ throw illegal(token, "value");
146
+ }
147
+ }
148
+
149
+ function readRanges(target, acceptStrings) {
150
+ var token, start;
151
+ do {
152
+ if (acceptStrings && ((token = peek()) === "\"" || token === "'")) {
153
+ var str = readString();
154
+ target.push(str);
155
+ if (edition >= 2023) {
156
+ throw illegal(str, "id");
157
+ }
158
+ } else {
159
+ try {
160
+ target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
161
+ } catch (err) {
162
+ if (acceptStrings && typeRefRe.test(token) && edition >= 2023) {
163
+ target.push(token);
164
+ } else {
165
+ throw err;
166
+ }
167
+ }
168
+ }
169
+ } while (skip(",", true));
170
+ var dummy = {options: undefined};
171
+ dummy.setOption = function(name, value) {
172
+ if (this.options === undefined) this.options = {};
173
+ this.options[name] = value;
174
+ };
175
+ ifBlock(
176
+ dummy,
177
+ function parseRange_block(token) {
178
+ /* istanbul ignore else */
179
+ if (token === "option") {
180
+ parseOption(dummy, token); // skip
181
+ skip(";");
182
+ } else
183
+ throw illegal(token);
184
+ },
185
+ function parseRange_line() {
186
+ parseInlineOptions(dummy); // skip
187
+ });
188
+ }
189
+
190
+ function parseNumber(token, insideTryCatch) {
191
+ var sign = 1;
192
+ if (token.charAt(0) === "-") {
193
+ sign = -1;
194
+ token = token.substring(1);
195
+ }
196
+ switch (token) {
197
+ case "inf": case "INF": case "Inf":
198
+ return sign * Infinity;
199
+ case "nan": case "NAN": case "Nan": case "NaN":
200
+ return NaN;
201
+ case "0":
202
+ return 0;
203
+ }
204
+ if (base10Re.test(token))
205
+ return sign * parseInt(token, 10);
206
+ if (base16Re.test(token))
207
+ return sign * parseInt(token, 16);
208
+ if (base8Re.test(token))
209
+ return sign * parseInt(token, 8);
210
+
211
+ /* istanbul ignore else */
212
+ if (numberRe.test(token))
213
+ return sign * parseFloat(token);
214
+
215
+ /* istanbul ignore next */
216
+ throw illegal(token, "number", insideTryCatch);
217
+ }
218
+
219
+ function parseId(token, acceptNegative) {
220
+ switch (token) {
221
+ case "max": case "MAX": case "Max":
222
+ return 536870911;
223
+ case "0":
224
+ return 0;
225
+ }
226
+
227
+ /* istanbul ignore if */
228
+ if (!acceptNegative && token.charAt(0) === "-")
229
+ throw illegal(token, "id");
230
+
231
+ if (base10NegRe.test(token))
232
+ return parseInt(token, 10);
233
+ if (base16NegRe.test(token))
234
+ return parseInt(token, 16);
235
+
236
+ /* istanbul ignore else */
237
+ if (base8NegRe.test(token))
238
+ return parseInt(token, 8);
239
+
240
+ /* istanbul ignore next */
241
+ throw illegal(token, "id");
242
+ }
243
+
244
+ function parsePackage() {
245
+ /* istanbul ignore if */
246
+ if (pkg !== undefined)
247
+ throw illegal("package");
248
+
249
+ pkg = next();
250
+
251
+ /* istanbul ignore if */
252
+ if (!typeRefRe.test(pkg))
253
+ throw illegal(pkg, "name");
254
+
255
+ ptr = ptr.define(pkg);
256
+
257
+ skip(";");
258
+ }
259
+
260
+ function parseImport() {
261
+ var token = peek();
262
+ var whichImports;
263
+ switch (token) {
264
+ case "option":
265
+ if (edition < "2024") {
266
+ throw illegal("option");
267
+ }
268
+ // Import options are only used for resolving options, which we don't
269
+ // do. We can just throw them out.
270
+ next();
271
+ readString();
272
+ skip(";");
273
+ return;
274
+ case "weak":
275
+ whichImports = weakImports || (weakImports = []);
276
+ next();
277
+ break;
278
+ case "public":
279
+ next();
280
+ // eslint-disable-next-line no-fallthrough
281
+ default:
282
+ whichImports = imports || (imports = []);
283
+ break;
284
+ }
285
+ token = readString();
286
+ skip(";");
287
+ whichImports.push(token);
288
+ }
289
+
290
+ function parseSyntax() {
291
+ skip("=");
292
+ edition = readString();
293
+
294
+ /* istanbul ignore if */
295
+ if (edition < 2023)
296
+ throw illegal(edition, "syntax");
297
+
298
+ skip(";");
299
+ }
300
+
301
+ function parseEdition() {
302
+ skip("=");
303
+ edition = readString();
304
+ const supportedEditions = ["2023", "2024"];
305
+
306
+ /* istanbul ignore if */
307
+ if (!supportedEditions.includes(edition))
308
+ throw illegal(edition, "edition");
309
+
310
+ skip(";");
311
+ }
312
+
313
+
314
+ function parseCommon(parent, token) {
315
+ switch (token) {
316
+
317
+ case "option":
318
+ parseOption(parent, token);
319
+ skip(";");
320
+ return true;
321
+
322
+ case "message":
323
+ parseType(parent, token);
324
+ return true;
325
+
326
+ case "enum":
327
+ parseEnum(parent, token);
328
+ return true;
329
+
330
+ case "export":
331
+ case "local":
332
+ if (edition < "2024") {
333
+ return false;
334
+ }
335
+ token = next();
336
+ if (token === "export" || token === "local") {
337
+ return false;
338
+ }
339
+ if (token !== "message" && token !== "enum") {
340
+ return false;
341
+ }
342
+ /* eslint-disable no-warning-comments */
343
+ // TODO: actually enforce visiblity modifiers like protoc does.
344
+ return parseCommon(parent, token);
345
+
346
+ case "service":
347
+ parseService(parent, token);
348
+ return true;
349
+
350
+ case "extend":
351
+ parseExtension(parent, token);
352
+ return true;
353
+ }
354
+ return false;
355
+ }
356
+
357
+ function ifBlock(obj, fnIf, fnElse) {
358
+ var trailingLine = tn.line;
359
+ if (obj) {
360
+ if(typeof obj.comment !== "string") {
361
+ obj.comment = cmnt(); // try block-type comment
362
+ }
363
+ obj.filename = parse.filename;
364
+ }
365
+ if (skip("{", true)) {
366
+ var token;
367
+ while ((token = next()) !== "}")
368
+ fnIf(token);
369
+ skip(";", true);
370
+ } else {
371
+ if (fnElse)
372
+ fnElse();
373
+ skip(";");
374
+ if (obj && (typeof obj.comment !== "string" || preferTrailingComment))
375
+ obj.comment = cmnt(trailingLine) || obj.comment; // try line-type comment
376
+ }
377
+ }
378
+
379
+ function parseType(parent, token) {
380
+
381
+ /* istanbul ignore if */
382
+ if (!nameRe.test(token = next()))
383
+ throw illegal(token, "type name");
384
+
385
+ var type = new Type(token);
386
+ ifBlock(type, function parseType_block(token) {
387
+ if (parseCommon(type, token))
388
+ return;
389
+
390
+ switch (token) {
391
+
392
+ case ";":
393
+ break;
394
+
395
+ case "map":
396
+ parseMapField(type, token);
397
+ break;
398
+
399
+ case "required":
400
+ if (edition !== "proto2")
401
+ throw illegal(token);
402
+ /* eslint-disable no-fallthrough */
403
+ case "repeated":
404
+ parseField(type, token);
405
+ break;
406
+
407
+ case "optional":
408
+ /* istanbul ignore if */
409
+ if (edition === "proto3") {
410
+ parseField(type, "proto3_optional");
411
+ } else if (edition !== "proto2") {
412
+ throw illegal(token);
413
+ } else {
414
+ parseField(type, "optional");
415
+ }
416
+ break;
417
+
418
+ case "oneof":
419
+ parseOneOf(type, token);
420
+ break;
421
+
422
+ case "extensions":
423
+ readRanges(type.extensions || (type.extensions = []));
424
+ break;
425
+
426
+ case "reserved":
427
+ readRanges(type.reserved || (type.reserved = []), true);
428
+ break;
429
+
430
+ default:
431
+ /* istanbul ignore if */
432
+ if (edition === "proto2" || !typeRefRe.test(token)) {
433
+ throw illegal(token);
434
+ }
435
+
436
+ push(token);
437
+ parseField(type, "optional");
438
+ break;
439
+ }
440
+ });
441
+ parent.add(type);
442
+ if (parent === ptr) {
443
+ topLevelObjects.push(type);
444
+ }
445
+ }
446
+
447
+ function parseField(parent, rule, extend) {
448
+ var type = next();
449
+ if (type === "group") {
450
+ parseGroup(parent, rule);
451
+ return;
452
+ }
453
+ // Type names can consume multiple tokens, in multiple variants:
454
+ // package.subpackage field tokens: "package.subpackage" [TYPE NAME ENDS HERE] "field"
455
+ // package . subpackage field tokens: "package" "." "subpackage" [TYPE NAME ENDS HERE] "field"
456
+ // package. subpackage field tokens: "package." "subpackage" [TYPE NAME ENDS HERE] "field"
457
+ // package .subpackage field tokens: "package" ".subpackage" [TYPE NAME ENDS HERE] "field"
458
+ // Keep reading tokens until we get a type name with no period at the end,
459
+ // and the next token does not start with a period.
460
+ while (type.endsWith(".") || peek().startsWith(".")) {
461
+ type += next();
462
+ }
463
+
464
+ /* istanbul ignore if */
465
+ if (!typeRefRe.test(type))
466
+ throw illegal(type, "type");
467
+
468
+ var name = next();
469
+
470
+ /* istanbul ignore if */
471
+
472
+ if (!nameRe.test(name))
473
+ throw illegal(name, "name");
474
+
475
+ name = applyCase(name);
476
+ skip("=");
477
+
478
+ var field = new Field(name, parseId(next()), type, rule, extend);
479
+
480
+ ifBlock(field, function parseField_block(token) {
481
+
482
+ /* istanbul ignore else */
483
+ if (token === "option") {
484
+ parseOption(field, token);
485
+ skip(";");
486
+ } else
487
+ throw illegal(token);
488
+
489
+ }, function parseField_line() {
490
+ parseInlineOptions(field);
491
+ });
492
+
493
+ if (rule === "proto3_optional") {
494
+ // for proto3 optional fields, we create a single-member Oneof to mimic "optional" behavior
495
+ var oneof = new OneOf("_" + name);
496
+ field.setOption("proto3_optional", true);
497
+ oneof.add(field);
498
+ parent.add(oneof);
499
+ } else {
500
+ parent.add(field);
501
+ }
502
+ if (parent === ptr) {
503
+ topLevelObjects.push(field);
504
+ }
505
+ }
506
+
507
+ function parseGroup(parent, rule) {
508
+ if (edition >= 2023) {
509
+ throw illegal("group");
510
+ }
511
+ var name = next();
512
+
513
+ /* istanbul ignore if */
514
+ if (!nameRe.test(name))
515
+ throw illegal(name, "name");
516
+
517
+ var fieldName = util.lcFirst(name);
518
+ if (name === fieldName)
519
+ name = util.ucFirst(name);
520
+ skip("=");
521
+ var id = parseId(next());
522
+ var type = new Type(name);
523
+ type.group = true;
524
+ var field = new Field(fieldName, id, name, rule);
525
+ field.filename = parse.filename;
526
+ ifBlock(type, function parseGroup_block(token) {
527
+ switch (token) {
528
+
529
+ case ";":
530
+ break;
531
+
532
+ case "option":
533
+ parseOption(type, token);
534
+ skip(";");
535
+ break;
536
+ case "required":
537
+ case "repeated":
538
+ parseField(type, token);
539
+ break;
540
+
541
+ case "optional":
542
+ /* istanbul ignore if */
543
+ if (edition === "proto3") {
544
+ parseField(type, "proto3_optional");
545
+ } else {
546
+ parseField(type, "optional");
547
+ }
548
+ break;
549
+
550
+ case "message":
551
+ parseType(type, token);
552
+ break;
553
+
554
+ case "enum":
555
+ parseEnum(type, token);
556
+ break;
557
+
558
+ case "reserved":
559
+ readRanges(type.reserved || (type.reserved = []), true);
560
+ break;
561
+
562
+ case "export":
563
+ case "local":
564
+ if (edition < "2024") {
565
+ throw illegal(token);
566
+ }
567
+ token = next();
568
+ switch (token) {
569
+ case "message":
570
+ parseType(type, token);
571
+ break;
572
+ case "enum":
573
+ parseType(type, token);
574
+ break;
575
+ default:
576
+ throw illegal(token);
577
+ }
578
+ break;
579
+
580
+ /* istanbul ignore next */
581
+ default:
582
+ throw illegal(token); // there are no groups with proto3 semantics
583
+ }
584
+ });
585
+ parent.add(type)
586
+ .add(field);
587
+ }
588
+
589
+ function parseMapField(parent) {
590
+ skip("<");
591
+ var keyType = next();
592
+
593
+ /* istanbul ignore if */
594
+ if (types.mapKey[keyType] === undefined)
595
+ throw illegal(keyType, "type");
596
+
597
+ skip(",");
598
+ var valueType = next();
599
+
600
+ /* istanbul ignore if */
601
+ if (!typeRefRe.test(valueType))
602
+ throw illegal(valueType, "type");
603
+
604
+ skip(">");
605
+ var name = next();
606
+
607
+ /* istanbul ignore if */
608
+ if (!nameRe.test(name))
609
+ throw illegal(name, "name");
610
+
611
+ skip("=");
612
+ var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
613
+ ifBlock(field, function parseMapField_block(token) {
614
+
615
+ /* istanbul ignore else */
616
+ if (token === "option") {
617
+ parseOption(field, token);
618
+ skip(";");
619
+ } else
620
+ throw illegal(token);
621
+
622
+ }, function parseMapField_line() {
623
+ parseInlineOptions(field);
624
+ });
625
+ parent.add(field);
626
+ }
627
+
628
+ function parseOneOf(parent, token) {
629
+
630
+ /* istanbul ignore if */
631
+ if (!nameRe.test(token = next()))
632
+ throw illegal(token, "name");
633
+
634
+ var oneof = new OneOf(applyCase(token));
635
+ ifBlock(oneof, function parseOneOf_block(token) {
636
+ if (token === "option") {
637
+ parseOption(oneof, token);
638
+ skip(";");
639
+ } else {
640
+ push(token);
641
+ parseField(oneof, "optional");
642
+ }
643
+ });
644
+ parent.add(oneof);
645
+ }
646
+
647
+ function parseEnum(parent, token) {
648
+
649
+ /* istanbul ignore if */
650
+ if (!nameRe.test(token = next()))
651
+ throw illegal(token, "name");
652
+
653
+ var enm = new Enum(token);
654
+ ifBlock(enm, function parseEnum_block(token) {
655
+ switch(token) {
656
+ case ";":
657
+ break;
658
+
659
+ case "option":
660
+ parseOption(enm, token);
661
+ skip(";");
662
+ break;
663
+
664
+ case "reserved":
665
+ readRanges(enm.reserved || (enm.reserved = []), true);
666
+ if(enm.reserved === undefined) enm.reserved = [];
667
+ break;
668
+
669
+ default:
670
+ parseEnumValue(enm, token);
671
+ }
672
+ });
673
+ parent.add(enm);
674
+ if (parent === ptr) {
675
+ topLevelObjects.push(enm);
676
+ }
677
+ }
678
+
679
+ function parseEnumValue(parent, token) {
680
+
681
+ /* istanbul ignore if */
682
+ if (!nameRe.test(token))
683
+ throw illegal(token, "name");
684
+
685
+ skip("=");
686
+ var value = parseId(next(), true),
687
+ dummy = {
688
+ options: undefined
689
+ };
690
+ dummy.getOption = function(name) {
691
+ return this.options[name];
692
+ };
693
+ dummy.setOption = function(name, value) {
694
+ ReflectionObject.prototype.setOption.call(dummy, name, value);
695
+ };
696
+ dummy.setParsedOption = function() {
697
+ return undefined;
698
+ };
699
+ ifBlock(dummy, function parseEnumValue_block(token) {
700
+
701
+ /* istanbul ignore else */
702
+ if (token === "option") {
703
+ parseOption(dummy, token); // skip
704
+ skip(";");
705
+ } else
706
+ throw illegal(token);
707
+
708
+ }, function parseEnumValue_line() {
709
+ parseInlineOptions(dummy); // skip
710
+ });
711
+ parent.add(token, value, dummy.comment, dummy.parsedOptions || dummy.options);
712
+ }
713
+
714
+ function parseOption(parent, token) {
715
+ var option;
716
+ var propName;
717
+ var isOption = true;
718
+ if (token === "option") {
719
+ token = next();
720
+ }
721
+
722
+ while (token !== "=") {
723
+ if (token === "(") {
724
+ var parensValue = next();
725
+ skip(")");
726
+ token = "(" + parensValue + ")";
727
+ }
728
+ if (isOption) {
729
+ isOption = false;
730
+ if (token.includes(".") && !token.includes("(")) {
731
+ var tokens = token.split(".");
732
+ option = tokens[0] + ".";
733
+ token = tokens[1];
734
+ continue;
735
+ }
736
+ option = token;
737
+ } else {
738
+ propName = propName ? propName += token : token;
739
+ }
740
+ token = next();
741
+ }
742
+ var name = propName ? option.concat(propName) : option;
743
+ var optionValue = parseOptionValue(parent, name);
744
+ propName = propName && propName[0] === "." ? propName.slice(1) : propName;
745
+ option = option && option[option.length - 1] === "." ? option.slice(0, -1) : option;
746
+ setParsedOption(parent, option, optionValue, propName);
747
+ }
748
+
749
+ function parseOptionValue(parent, name) {
750
+ // { a: "foo" b { c: "bar" } }
751
+ if (skip("{", true)) {
752
+ var objectResult = {};
753
+
754
+ while (!skip("}", true)) {
755
+ /* istanbul ignore if */
756
+ if (!nameRe.test(token = next())) {
757
+ throw illegal(token, "name");
758
+ }
759
+ if (token === null) {
760
+ throw illegal(token, "end of input");
761
+ }
762
+
763
+ var value;
764
+ var propName = token;
765
+
766
+ skip(":", true);
767
+
768
+ if (peek() === "{") {
769
+ // option (my_option) = {
770
+ // repeated_value: [ "foo", "bar" ]
771
+ // };
772
+ value = parseOptionValue(parent, name + "." + token);
773
+ } else if (peek() === "[") {
774
+ value = [];
775
+ var lastValue;
776
+ if (skip("[", true)) {
777
+ if (!skip("]", true)) {
778
+ do {
779
+ lastValue = readValue(true);
780
+ value.push(lastValue);
781
+ } while (skip(",", true));
782
+ skip("]");
783
+ if (typeof lastValue !== "undefined") {
784
+ setOption(parent, name + "." + token, lastValue);
785
+ }
786
+ }
787
+ }
788
+ } else {
789
+ value = readValue(true);
790
+ setOption(parent, name + "." + token, value);
791
+ }
792
+
793
+ var prevValue = objectResult[propName];
794
+
795
+ if (prevValue)
796
+ value = [].concat(prevValue).concat(value);
797
+
798
+ if (propName !== "__proto__")
799
+ objectResult[propName] = value;
800
+
801
+ // Semicolons and commas can be optional
802
+ skip(",", true);
803
+ skip(";", true);
804
+ }
805
+
806
+ return objectResult;
807
+ }
808
+
809
+ var simpleValue = readValue(true);
810
+ setOption(parent, name, simpleValue);
811
+ return simpleValue;
812
+ // Does not enforce a delimiter to be universal
813
+ }
814
+
815
+ function setOption(parent, name, value) {
816
+ if (ptr === parent && /^features\./.test(name)) {
817
+ topLevelOptions[name] = value;
818
+ return;
819
+ }
820
+ if (parent.setOption)
821
+ parent.setOption(name, value);
822
+ }
823
+
824
+ function setParsedOption(parent, name, value, propName) {
825
+ if (parent.setParsedOption)
826
+ parent.setParsedOption(name, value, propName);
827
+ }
828
+
829
+ function parseInlineOptions(parent) {
830
+ if (skip("[", true)) {
831
+ do {
832
+ parseOption(parent, "option");
833
+ } while (skip(",", true));
834
+ skip("]");
835
+ }
836
+ return parent;
837
+ }
838
+
839
+ function parseService(parent, token) {
840
+
841
+ /* istanbul ignore if */
842
+ if (!nameRe.test(token = next()))
843
+ throw illegal(token, "service name");
844
+
845
+ var service = new Service(token);
846
+ ifBlock(service, function parseService_block(token) {
847
+ if (parseCommon(service, token)) {
848
+ return;
849
+ }
850
+
851
+ /* istanbul ignore else */
852
+ if (token === ";")
853
+ return;
854
+ if (token === "rpc")
855
+ parseMethod(service, token);
856
+ else
857
+ throw illegal(token);
858
+ });
859
+ parent.add(service);
860
+ if (parent === ptr) {
861
+ topLevelObjects.push(service);
862
+ }
863
+ }
864
+
865
+ function parseMethod(parent, token) {
866
+ // Get the comment of the preceding line now (if one exists) in case the
867
+ // method is defined across multiple lines.
868
+ var commentText = cmnt();
869
+
870
+ var type = token;
871
+
872
+ /* istanbul ignore if */
873
+ if (!nameRe.test(token = next()))
874
+ throw illegal(token, "name");
875
+
876
+ var name = token,
877
+ requestType, requestStream,
878
+ responseType, responseStream;
879
+
880
+ skip("(");
881
+ if (skip("stream", true))
882
+ requestStream = true;
883
+
884
+ /* istanbul ignore if */
885
+ if (!typeRefRe.test(token = next()))
886
+ throw illegal(token);
887
+
888
+ requestType = token;
889
+ skip(")"); skip("returns"); skip("(");
890
+ if (skip("stream", true))
891
+ responseStream = true;
892
+
893
+ /* istanbul ignore if */
894
+ if (!typeRefRe.test(token = next()))
895
+ throw illegal(token);
896
+
897
+ responseType = token;
898
+ skip(")");
899
+
900
+ var method = new Method(name, type, requestType, responseType, requestStream, responseStream);
901
+ method.comment = commentText;
902
+ ifBlock(method, function parseMethod_block(token) {
903
+
904
+ /* istanbul ignore else */
905
+ if (token === ";")
906
+ return;
907
+ if (token === "option") {
908
+ parseOption(method, token);
909
+ skip(";");
910
+ } else
911
+ throw illegal(token);
912
+
913
+ });
914
+ parent.add(method);
915
+ }
916
+
917
+ function parseExtension(parent, token) {
918
+
919
+ /* istanbul ignore if */
920
+ if (!typeRefRe.test(token = next()))
921
+ throw illegal(token, "reference");
922
+
923
+ var reference = token;
924
+ ifBlock(null, function parseExtension_block(token) {
925
+ switch (token) {
926
+
927
+ case "required":
928
+ case "repeated":
929
+ parseField(parent, token, reference);
930
+ break;
931
+
932
+ case "optional":
933
+ /* istanbul ignore if */
934
+ if (edition === "proto3") {
935
+ parseField(parent, "proto3_optional", reference);
936
+ } else {
937
+ parseField(parent, "optional", reference);
938
+ }
939
+ break;
940
+
941
+ default:
942
+ /* istanbul ignore if */
943
+ if (edition === "proto2" || !typeRefRe.test(token))
944
+ throw illegal(token);
945
+ push(token);
946
+ parseField(parent, "optional", reference);
947
+ break;
948
+ }
949
+ });
950
+ }
951
+
952
+ var token;
953
+ while ((token = next()) !== null) {
954
+ switch (token) {
955
+
956
+ case ";":
957
+ break;
958
+
959
+ case "package":
960
+
961
+ /* istanbul ignore if */
962
+ if (!head)
963
+ throw illegal(token);
964
+
965
+ parsePackage();
966
+ break;
967
+
886
968
  case "import":
887
969
 
888
- /* istanbul ignore if */
889
- if (!head)
890
- throw illegal(token);
891
-
892
970
  parseImport();
893
971
  break;
894
-
895
- case "syntax":
896
-
897
- /* istanbul ignore if */
898
- if (!head)
899
- throw illegal(token);
900
-
901
- parseSyntax();
902
- break;
903
-
904
- case "edition":
905
- /* istanbul ignore if */
906
- if (!head)
907
- throw illegal(token);
908
- parseEdition();
909
- break;
910
-
911
- case "option":
912
- parseOption(ptr, token);
913
- skip(";", true);
914
- break;
915
-
916
- default:
917
-
918
- /* istanbul ignore else */
919
- if (parseCommon(ptr, token)) {
920
- head = false;
921
- continue;
922
- }
923
-
924
- /* istanbul ignore next */
925
- throw illegal(token);
926
- }
927
- }
928
-
929
- parse.filename = null;
930
- return {
931
- "package" : pkg,
932
- "imports" : imports,
933
- weakImports : weakImports,
934
- root : root
935
- };
936
- }
937
-
938
- /**
939
- * Parses the given .proto source and returns an object with the parsed contents.
940
- * @name parse
941
- * @function
942
- * @param {string} source Source contents
943
- * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
944
- * @returns {IParserResult} Parser result
945
- * @property {string} filename=null Currently processing file name for error reporting, if known
946
- * @property {IParseOptions} defaults Default {@link IParseOptions}
947
- * @variation 2
948
- */
972
+
973
+ case "syntax":
974
+
975
+ /* istanbul ignore if */
976
+ if (!head)
977
+ throw illegal(token);
978
+
979
+ parseSyntax();
980
+ break;
981
+
982
+ case "edition":
983
+ /* istanbul ignore if */
984
+ if (!head)
985
+ throw illegal(token);
986
+ parseEdition();
987
+ break;
988
+
989
+ case "option":
990
+ parseOption(ptr, token);
991
+ skip(";", true);
992
+ break;
993
+
994
+ default:
995
+
996
+ /* istanbul ignore else */
997
+ if (parseCommon(ptr, token)) {
998
+ head = false;
999
+ continue;
1000
+ }
1001
+
1002
+ /* istanbul ignore next */
1003
+ throw illegal(token);
1004
+ }
1005
+ }
1006
+
1007
+ resolveFileFeatures();
1008
+
1009
+ parse.filename = null;
1010
+ return {
1011
+ "package" : pkg,
1012
+ "imports" : imports,
1013
+ weakImports : weakImports,
1014
+ root : root
1015
+ };
1016
+ }
1017
+
1018
+ /**
1019
+ * Parses the given .proto source and returns an object with the parsed contents.
1020
+ * @name parse
1021
+ * @function
1022
+ * @param {string} source Source contents
1023
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
1024
+ * @returns {IParserResult} Parser result
1025
+ * @property {string} filename=null Currently processing file name for error reporting, if known
1026
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
1027
+ * @variation 2
1028
+ */