protobufjs 8.4.2 → 8.6.0

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.
@@ -0,0 +1,903 @@
1
+ // Copyright 2021 Google LLC
2
+ // Copyright 2026 The protobuf.js Authors
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+
16
+ // Derived from proto3-json-serializer v3.0.4 and modified by The protobuf.js Authors.
17
+
18
+ "use strict";
19
+ var protobuf = require("../light");
20
+
21
+ /* global BigInt */
22
+
23
+ var Type = protobuf.Type,
24
+ Enum = protobuf.Enum,
25
+ util = protobuf.util;
26
+
27
+ var protojson = protobuf.protojson = module.exports = {};
28
+
29
+ function isExtension(field) {
30
+ return Boolean(field.declaringField) || field.name.charAt(0) === ".";
31
+ }
32
+
33
+ function extensionName(field) {
34
+ var df = field.declaringField || field,
35
+ full = df.fullName.charAt(0) === "." ? df.fullName.slice(1) : df.fullName;
36
+ return "[" + (df.protoName ? full.replace(/[^.]+$/, df.protoName) : full) + "]";
37
+ }
38
+
39
+ function indexField(index, key, field, type) {
40
+ var existing = index[key];
41
+ if (existing !== undefined && existing !== field)
42
+ throw Error(type.fullName + ": duplicate ProtoJSON field name " + JSON.stringify(key));
43
+ index[key] = field;
44
+ }
45
+
46
+ function fieldsByJsonName(type) {
47
+ if (type._fieldsByJsonName)
48
+ return type._fieldsByJsonName;
49
+ var index = Object.create(null),
50
+ fields = type.fieldsArray,
51
+ i = 0;
52
+ for (; i < fields.length; ++i) {
53
+ var field = fields[i].resolve();
54
+ if (isExtension(field))
55
+ indexField(index, extensionName(field), field, type);
56
+ else {
57
+ indexField(index, field.name, field, type);
58
+ indexField(index, field.jsonName, field, type);
59
+ indexField(index, field.protoName, field, type);
60
+ }
61
+ }
62
+ type._fieldsByJsonName = index;
63
+ return index;
64
+ }
65
+
66
+ // --- reading scalars ---
67
+
68
+ var INT_RANGE = {
69
+ int32: ["-2147483648", "2147483647"],
70
+ sint32: ["-2147483648", "2147483647"],
71
+ sfixed32: ["-2147483648", "2147483647"],
72
+ uint32: ["0", "4294967295"],
73
+ fixed32: ["0", "4294967295"],
74
+ int64: ["-9223372036854775808", "9223372036854775807"],
75
+ sint64: ["-9223372036854775808", "9223372036854775807"],
76
+ sfixed64: ["-9223372036854775808", "9223372036854775807"],
77
+ uint64: ["0", "18446744073709551615"],
78
+ fixed64: ["0", "18446744073709551615"]
79
+ };
80
+
81
+ var LONG_TYPE = { int64: 1, uint64: 1, sint64: 1, fixed64: 1, sfixed64: 1 };
82
+
83
+ var MAX_FLOAT = 3.4028234663852886e38;
84
+ var hasBigInt = typeof BigInt !== "undefined";
85
+
86
+ var NUMERIC_RE = /^[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.?)(?:[eE][+-]?[0-9]+)?$/;
87
+
88
+ var SKIP = {};
89
+
90
+ function invalid(name, value, what) {
91
+ return Error(name + ": " + what + ": " + JSON.stringify(value));
92
+ }
93
+
94
+ function parseIntegerString(value, type, name) {
95
+ var str;
96
+ if (typeof value === "number") {
97
+ if (!isFinite(value) || Math.floor(value) !== value)
98
+ throw invalid(name, value, "not an integer");
99
+ str = numberToIntString(value);
100
+ } else if (typeof value === "string") {
101
+ if (value.length === 0 || /^\s|\s$/.test(value))
102
+ throw invalid(name, value, "invalid integer");
103
+ if (/^[+-]?[0-9]+$/.test(value))
104
+ str = value;
105
+ else if (NUMERIC_RE.test(value)) {
106
+ var num = Number(value);
107
+ if (!isFinite(num) || Math.floor(num) !== num)
108
+ throw invalid(name, value, "not an integer");
109
+ str = numberToIntString(num);
110
+ } else
111
+ throw invalid(name, value, "invalid integer");
112
+ } else
113
+ throw invalid(name, value, "expected integer (number or string)");
114
+
115
+ var range = INT_RANGE[type];
116
+ if (LONG_TYPE[type]) {
117
+ if (hasBigInt) {
118
+ var big = BigInt(str);
119
+ if (big < BigInt(range[0]) || big > BigInt(range[1]))
120
+ throw invalid(name, value, "out of range for " + type);
121
+ }
122
+ } else if (Number(str) < Number(range[0]) || Number(str) > Number(range[1]))
123
+ throw invalid(name, value, "out of range for " + type);
124
+ return str;
125
+ }
126
+
127
+ function parseMapIntegerKey(key, type, name) {
128
+ var unsigned = type === "uint32" || type === "fixed32" || type === "uint64" || type === "fixed64";
129
+ if (!(unsigned ? /^[0-9]+$/ : /^-?[0-9]+$/).test(key))
130
+ throw invalid(name, key, "invalid " + type + " map key");
131
+ if (hasBigInt) {
132
+ var big = BigInt(key),
133
+ range = INT_RANGE[type];
134
+ if (big < BigInt(range[0]) || big > BigInt(range[1]))
135
+ throw invalid(name, key, "out of range for " + type + " map key");
136
+ return big.toString();
137
+ }
138
+ parseIntegerString(key, type, name);
139
+ if (LONG_TYPE[type]) {
140
+ var normalized = key.replace(/^-?0+(?=\d)/, key.charAt(0) === "-" ? "-" : "");
141
+ return normalized === "-0" ? "0" : normalized;
142
+ }
143
+ return String(Number(key));
144
+ }
145
+
146
+ function numberToIntString(num) {
147
+ if (num >= -9007199254740991 && num <= 9007199254740991)
148
+ return String(num);
149
+ return num.toFixed(0);
150
+ }
151
+
152
+ function parseFloat32Or64(value, isFloat, name) {
153
+ var num;
154
+ if (typeof value === "number") {
155
+ if (!isFinite(value))
156
+ throw invalid(name, value, "number out of range");
157
+ num = value;
158
+ } else if (value === "NaN")
159
+ return NaN;
160
+ else if (value === "Infinity")
161
+ return Infinity;
162
+ else if (value === "-Infinity")
163
+ return -Infinity;
164
+ else if (typeof value === "string") {
165
+ if (value.length === 0 || /^\s|\s$/.test(value) || !NUMERIC_RE.test(value))
166
+ throw invalid(name, value, "invalid number");
167
+ num = Number(value);
168
+ if (!isFinite(num))
169
+ throw invalid(name, value, "invalid number");
170
+ } else
171
+ throw invalid(name, value, "expected number");
172
+ if (isFloat && Math.abs(num) > MAX_FLOAT)
173
+ throw invalid(name, value, "out of range for float");
174
+ return num;
175
+ }
176
+
177
+ function validateUtf16(value, name) {
178
+ for (var i = 0; i < value.length; ++i) {
179
+ var c = value.charCodeAt(i);
180
+ if (c >= 0xD800 && c <= 0xDBFF) {
181
+ var next = value.charCodeAt(i + 1);
182
+ if (!(next >= 0xDC00 && next <= 0xDFFF))
183
+ throw invalid(name, value, "unpaired high surrogate");
184
+ ++i;
185
+ } else if (c >= 0xDC00 && c <= 0xDFFF)
186
+ throw invalid(name, value, "unpaired low surrogate");
187
+ }
188
+ }
189
+
190
+ function parseBytes(value, name) {
191
+ if (typeof value !== "string")
192
+ throw invalid(name, value, "expected base64 string");
193
+ var s = value.replace(/-/g, "+").replace(/_/g, "/");
194
+ while (s.length % 4)
195
+ s += "=";
196
+ var buffer = util.newBuffer(util.base64.length(s));
197
+ util.base64.decode(s, buffer, 0);
198
+ return buffer;
199
+ }
200
+
201
+ function longFromString(str, unsigned) {
202
+ return util.Long ? util.Long.fromString(str, unsigned) : parseInt(str, 10);
203
+ }
204
+
205
+ function readScalar(type, value, name) {
206
+ switch (type) {
207
+ case "int32": case "sint32": case "sfixed32":
208
+ case "uint32": case "fixed32":
209
+ return Number(parseIntegerString(value, type, name));
210
+ case "int64": case "sint64": case "sfixed64":
211
+ return longFromString(parseIntegerString(value, type, name), false);
212
+ case "uint64": case "fixed64":
213
+ return longFromString(parseIntegerString(value, type, name), true);
214
+ case "float":
215
+ return parseFloat32Or64(value, true, name);
216
+ case "double":
217
+ return parseFloat32Or64(value, false, name);
218
+ case "bool":
219
+ if (typeof value !== "boolean")
220
+ throw invalid(name, value, "expected boolean");
221
+ return value;
222
+ case "string":
223
+ if (typeof value !== "string")
224
+ throw invalid(name, value, "expected string");
225
+ validateUtf16(value, name);
226
+ return value;
227
+ case "bytes":
228
+ return parseBytes(value, name);
229
+ default:
230
+ throw Error(name + ": unsupported scalar type " + type);
231
+ }
232
+ }
233
+
234
+ function readEnum(enm, value, name, options) {
235
+ if (typeof value === "string") {
236
+ var num = enm.values[value];
237
+ if (num !== undefined)
238
+ return num;
239
+ if (options.ignoreUnknownFields)
240
+ return SKIP;
241
+ throw invalid(name, value, "unknown enum value");
242
+ }
243
+ if (typeof value === "number") {
244
+ if (!isFinite(value) || Math.floor(value) !== value)
245
+ throw invalid(name, value, "invalid enum number");
246
+ return value;
247
+ }
248
+ if (value === null && enm.fullName === ".google.protobuf.NullValue")
249
+ return 0;
250
+ throw invalid(name, value, "expected enum string or number");
251
+ }
252
+
253
+ function readMapKey(field, key) {
254
+ switch (field.keyType) {
255
+ case "bool":
256
+ if (key !== "true" && key !== "false")
257
+ throw invalid(field.fullName, key, "invalid bool map key");
258
+ return key;
259
+ case "string":
260
+ validateUtf16(key, field.fullName);
261
+ return key;
262
+ case "int32": case "sint32": case "sfixed32":
263
+ case "uint32": case "fixed32":
264
+ case "int64": case "sint64": case "sfixed64":
265
+ case "uint64": case "fixed64":
266
+ return parseMapIntegerKey(key, field.keyType, field.fullName);
267
+ default:
268
+ throw Error(field.fullName + ": unsupported map key type " + field.keyType);
269
+ }
270
+ }
271
+
272
+ // --- reading messages ---
273
+
274
+ function readField(field, value, options, depth) {
275
+ if (field.map) {
276
+ if (value === null || typeof value !== "object" || Array.isArray(value))
277
+ throw invalid(field.fullName, value, "expected object for map");
278
+ var map = Object.create(null), k;
279
+ for (k in value)
280
+ if (hasOwn(value, k)) {
281
+ var mk = readMapKey(field, k),
282
+ mv = readSingular(field, value[k], options, depth);
283
+ if (mv !== SKIP) {
284
+ if (hasOwn(map, mk))
285
+ throw invalid(field.fullName, k, "duplicate map key");
286
+ map[mk] = mv;
287
+ }
288
+ }
289
+ return map;
290
+ }
291
+ if (field.repeated) {
292
+ if (!Array.isArray(value))
293
+ throw invalid(field.fullName, value, "expected array");
294
+ var arr = [], i = 0;
295
+ for (; i < value.length; ++i) {
296
+ if (value[i] === null && !isValueType(field.resolvedType))
297
+ throw invalid(field.fullName, null, "null element");
298
+ var el = readSingular(field, value[i], options, depth);
299
+ if (el !== SKIP)
300
+ arr.push(el);
301
+ }
302
+ return arr;
303
+ }
304
+ return readSingular(field, value, options, depth);
305
+ }
306
+
307
+ function readSingular(field, value, options, depth) {
308
+ if (field.resolvedType instanceof Type)
309
+ return readMessage(field.resolvedType, value, options, depth + 1);
310
+ if (field.resolvedType instanceof Enum)
311
+ return readEnum(field.resolvedType, value, field.fullName, options);
312
+ return readScalar(field.type, value, field.fullName);
313
+ }
314
+
315
+ function isValueType(type) {
316
+ return type instanceof Type && type.fullName === ".google.protobuf.Value";
317
+ }
318
+
319
+ function isImplicitDefault(field, value) {
320
+ if (field.hasPresence || field.repeated || field.map || field.resolvedType instanceof Type)
321
+ return false;
322
+ if (field.resolvedType instanceof Enum)
323
+ return value === 0;
324
+ switch (field.type) {
325
+ case "bool": return value === false;
326
+ case "string": return value === "";
327
+ case "bytes": return value == null || value.length === 0;
328
+ default: return longToNumber(value) === 0;
329
+ }
330
+ }
331
+
332
+ function readMessage(type, value, options, depth) {
333
+ if (depth > util.recursionLimit)
334
+ throw Error("max depth exceeded");
335
+
336
+ var wkt = WKT_FROM[type.fullName];
337
+ if (wkt)
338
+ return wkt(type, value, options, depth);
339
+
340
+ if (value === null || typeof value !== "object" || Array.isArray(value))
341
+ throw invalid(type.fullName, value, "expected object");
342
+
343
+ var index = fieldsByJsonName(type),
344
+ out = {},
345
+ seenFields = Object.create(null),
346
+ seenOneofs = Object.create(null),
347
+ key;
348
+
349
+ for (key in value) {
350
+ if (!hasOwn(value, key))
351
+ continue;
352
+ var field = index[key];
353
+ if (field === undefined) {
354
+ if (options.ignoreUnknownFields)
355
+ continue;
356
+ throw invalid(type.fullName, key, "unknown field");
357
+ }
358
+ if (seenFields[field.name])
359
+ throw invalid(type.fullName, key, "duplicate field");
360
+ seenFields[field.name] = true;
361
+ var fv = value[key], fieldValue;
362
+ if (fv === null) {
363
+ if (isValueType(field.resolvedType))
364
+ fieldValue = { nullValue: 0 };
365
+ else if (field.resolvedType instanceof Enum && field.resolvedType.fullName === ".google.protobuf.NullValue")
366
+ fieldValue = 0;
367
+ else
368
+ continue;
369
+ } else
370
+ fieldValue = readField(field, fv, options, depth);
371
+ if (fieldValue === SKIP)
372
+ continue;
373
+ if (field.partOf) {
374
+ if (seenOneofs[field.partOf.name])
375
+ throw Error(type.fullName + ": multiple values for oneof " + field.partOf.name);
376
+ seenOneofs[field.partOf.name] = true;
377
+ }
378
+ if (!isImplicitDefault(field, fieldValue))
379
+ out[field.name] = fieldValue;
380
+ }
381
+ return out;
382
+ }
383
+
384
+ // --- writing messages ---
385
+
386
+ function hasOwn(o, k) {
387
+ return o != null && Object.prototype.hasOwnProperty.call(o, k);
388
+ }
389
+
390
+ function setOwn(o, k, v) {
391
+ if (k === "__proto__")
392
+ util.makeProp(o, k);
393
+ o[k] = v;
394
+ }
395
+
396
+ function writeScalar(type, value) {
397
+ switch (type) {
398
+ case "int64": case "sint64": case "sfixed64":
399
+ case "uint64": case "fixed64":
400
+ return value == null ? "0" : String(value);
401
+ case "float": case "double":
402
+ return typeof value === "number" && !isFinite(value) ? String(value) : value;
403
+ case "bytes":
404
+ return value == null ? "" : util.base64.encode(value, 0, value.length);
405
+ default:
406
+ return value;
407
+ }
408
+ }
409
+
410
+ function writeSingular(field, value, options, depth) {
411
+ if (field.resolvedType instanceof Type)
412
+ return toJsonValue(field.resolvedType, value, options, depth + 1);
413
+ if (field.resolvedType instanceof Enum) {
414
+ if (field.resolvedType.fullName === ".google.protobuf.NullValue")
415
+ return null;
416
+ var name = field.resolvedType.valuesById[value];
417
+ return name === undefined ? value : name;
418
+ }
419
+ return writeScalar(field.type, value);
420
+ }
421
+
422
+ function toJsonValue(type, message, options, depth) {
423
+ if (depth > util.recursionLimit)
424
+ throw Error("max depth exceeded");
425
+
426
+ var wkt = WKT_TO[type.fullName];
427
+ if (wkt)
428
+ return wkt(type, message, options, depth);
429
+
430
+ var out = {},
431
+ fields = type.fieldsArray,
432
+ i = 0;
433
+ for (; i < fields.length; ++i) {
434
+ var field = fields[i].resolve(),
435
+ value = message[field.name];
436
+ if (value == null)
437
+ continue;
438
+ var key = isExtension(field) ? extensionName(field) : field.jsonName;
439
+ if (field.map) {
440
+ var mk = Object.keys(value);
441
+ if (!mk.length)
442
+ continue;
443
+ var longKey = LONG_TYPE[field.keyType],
444
+ unsignedKey = field.keyType === "uint64" || field.keyType === "fixed64",
445
+ mo = {}, ki = 0;
446
+ for (; ki < mk.length; ++ki) {
447
+ var outKey = longKey ? util.longFromKey(mk[ki], unsignedKey).toString() : mk[ki];
448
+ setOwn(mo, outKey, writeSingular(field, value[mk[ki]], options, depth));
449
+ }
450
+ setOwn(out, key, mo);
451
+ } else if (field.repeated) {
452
+ if (!value.length)
453
+ continue;
454
+ var arr = new Array(value.length), j = 0;
455
+ for (; j < value.length; ++j)
456
+ arr[j] = writeSingular(field, value[j], options, depth);
457
+ setOwn(out, key, arr);
458
+ } else {
459
+ if (!hasOwn(message, field.name) || isImplicitDefault(field, value))
460
+ continue;
461
+ setOwn(out, key, writeSingular(field, value, options, depth));
462
+ }
463
+ }
464
+ return out;
465
+ }
466
+
467
+ // --- well-known types ---
468
+
469
+ function longToNumber(value) {
470
+ if (value == null) return 0;
471
+ if (typeof value === "number") return value;
472
+ if (typeof value.toNumber === "function") return value.toNumber();
473
+ return Number(value) || 0;
474
+ }
475
+
476
+ function nanosToString(nanos) {
477
+ var str = String(nanos < 0 ? -nanos : nanos);
478
+ while (str.length < 9) str = "0" + str;
479
+ while (str.length > 3 && str.slice(str.length - 3) === "000") str = str.slice(0, str.length - 3);
480
+ return str;
481
+ }
482
+
483
+ function fracToNanos(frac) {
484
+ while (frac.length < 9) frac += "0";
485
+ return parseInt(frac.slice(0, 9), 10);
486
+ }
487
+
488
+ function daysInMonth(year, month) {
489
+ switch (month) {
490
+ case 2:
491
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28;
492
+ case 4:
493
+ case 6:
494
+ case 9:
495
+ case 11:
496
+ return 30;
497
+ default:
498
+ return 31;
499
+ }
500
+ }
501
+
502
+ function camelToSnake(path) {
503
+ return path.replace(/[A-Z]/g, function ($0) { return "_" + $0.toLowerCase(); });
504
+ }
505
+
506
+ var WKT_FROM = {};
507
+ var WKT_TO = {};
508
+
509
+ WKT_FROM[".google.protobuf.Duration"] = function (type, value) {
510
+ if (typeof value !== "string")
511
+ throw invalid(type.fullName, value, "expected duration string");
512
+ var match = /^(-)?([0-9]+)(?:\.([0-9]{1,9}))?s$/.exec(value);
513
+ if (!match)
514
+ throw invalid(type.fullName, value, "invalid duration");
515
+ var sign = match[1] ? -1 : 1,
516
+ seconds = parseInt(match[2], 10) * sign || 0,
517
+ nanos = match[3] ? fracToNanos(match[3]) * sign || 0 : 0;
518
+ if (seconds > 315576000000 || seconds < -315576000000)
519
+ throw invalid(type.fullName, value, "duration out of range");
520
+ return { seconds: seconds, nanos: nanos };
521
+ };
522
+ WKT_TO[".google.protobuf.Duration"] = function (type, message) {
523
+ var seconds = longToNumber(message.seconds),
524
+ nanos = message.nanos || 0;
525
+ if (seconds > 315576000000 || seconds < -315576000000)
526
+ throw Error("google.protobuf.Duration out of range");
527
+ if (nanos > 999999999 || nanos < -999999999 || seconds && nanos && seconds < 0 !== nanos < 0)
528
+ throw Error("google.protobuf.Duration nanos invalid");
529
+ var result = (seconds < 0 || nanos < 0 ? "-" : "") + Math.abs(seconds);
530
+ if (nanos)
531
+ result += "." + nanosToString(nanos);
532
+ return result + "s";
533
+ };
534
+
535
+ WKT_FROM[".google.protobuf.Timestamp"] = function (type, value) {
536
+ if (typeof value !== "string")
537
+ throw invalid(type.fullName, value, "expected timestamp string");
538
+ var match = /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(?:\.(\d{1,9}))?(Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.exec(value);
539
+ if (!match)
540
+ throw invalid(type.fullName, value, "invalid timestamp");
541
+ var year = parseInt(match[1], 10),
542
+ month = parseInt(match[2], 10),
543
+ day = parseInt(match[3], 10);
544
+ if (day > daysInMonth(year, month))
545
+ throw invalid(type.fullName, value, "invalid timestamp date");
546
+ var millis = new Date(value).getTime();
547
+ if (isNaN(millis))
548
+ throw invalid(type.fullName, value, "invalid timestamp");
549
+ var seconds = Math.floor(millis / 1000),
550
+ nanos = match[7] ? fracToNanos(match[7]) : 0;
551
+ if (seconds < -62135596800 || seconds > 253402300799)
552
+ throw invalid(type.fullName, value, "timestamp out of range");
553
+ return { seconds: seconds, nanos: nanos };
554
+ };
555
+ WKT_TO[".google.protobuf.Timestamp"] = function (type, message) {
556
+ var seconds = longToNumber(message.seconds),
557
+ nanos = message.nanos || 0;
558
+ if (seconds < -62135596800 || seconds > 253402300799)
559
+ throw Error("google.protobuf.Timestamp out of range");
560
+ if (nanos < 0 || nanos > 999999999)
561
+ throw Error("google.protobuf.Timestamp nanos out of range");
562
+ var iso = new Date(seconds * 1000).toISOString();
563
+ return nanos
564
+ ? iso.replace(/\.\d+Z$/, "." + nanosToString(nanos) + "Z")
565
+ : iso.replace(/\.\d+Z$/, "Z");
566
+ };
567
+
568
+ WKT_FROM[".google.protobuf.FieldMask"] = function (type, value) {
569
+ if (typeof value !== "string")
570
+ throw invalid(type.fullName, value, "expected field mask string");
571
+ if (value.indexOf("_") !== -1)
572
+ throw invalid(type.fullName, value, "field mask path must be lowerCamelCase");
573
+ var paths = value.length ? value.split(",") : [],
574
+ i = 0;
575
+ for (; i < paths.length; ++i)
576
+ paths[i] = camelToSnake(paths[i]);
577
+ return { paths: paths };
578
+ };
579
+ WKT_TO[".google.protobuf.FieldMask"] = function (type, message) {
580
+ var paths = message.paths || [],
581
+ out = [],
582
+ i = 0;
583
+ for (; i < paths.length; ++i) {
584
+ var camel = util.jsonName(paths[i]);
585
+ if (camelToSnake(camel) !== paths[i])
586
+ throw Error("google.protobuf.FieldMask path does not round-trip: " + paths[i]);
587
+ out.push(camel);
588
+ }
589
+ return out.join(",");
590
+ };
591
+
592
+ ["DoubleValue", "FloatValue", "Int64Value", "UInt64Value", "Int32Value",
593
+ "UInt32Value", "BoolValue", "StringValue", "BytesValue"].forEach(function (name) {
594
+ var fullName = ".google.protobuf." + name;
595
+ WKT_FROM[fullName] = function (type, value, options, depth) {
596
+ return { value: readSingular(type.fields.value.resolve(), value, options, depth) };
597
+ };
598
+ WKT_TO[fullName] = function (type, message, options, depth) {
599
+ return writeSingular(type.fields.value.resolve(), message.value, options, depth);
600
+ };
601
+ });
602
+
603
+ function valueFromJson(json, depth) {
604
+ if (depth > util.recursionLimit)
605
+ throw Error("max depth exceeded");
606
+ if (json === null)
607
+ return { nullValue: 0 };
608
+ switch (typeof json) {
609
+ case "number":
610
+ if (!isFinite(json))
611
+ throw Error("google.protobuf.Value cannot hold a non-finite number");
612
+ return { numberValue: json };
613
+ case "string":
614
+ validateUtf16(json, "google.protobuf.Value.string_value");
615
+ return { stringValue: json };
616
+ case "boolean":
617
+ return { boolValue: json };
618
+ }
619
+ if (Array.isArray(json)) {
620
+ var values = new Array(json.length), i = 0;
621
+ for (; i < json.length; ++i)
622
+ values[i] = valueFromJson(json[i], depth + 1);
623
+ return { listValue: { values: values } };
624
+ }
625
+ return { structValue: { fields: structFieldsFromJson(json, depth + 1) } };
626
+ }
627
+ function structFieldsFromJson(json, depth) {
628
+ var fields = Object.create(null), k;
629
+ for (k in json)
630
+ if (hasOwn(json, k)) {
631
+ validateUtf16(k, "google.protobuf.Struct.fields");
632
+ fields[k] = valueFromJson(json[k], depth);
633
+ }
634
+ return fields;
635
+ }
636
+ WKT_FROM[".google.protobuf.Value"] = function (type, value, options, depth) {
637
+ return valueFromJson(value, depth);
638
+ };
639
+ WKT_FROM[".google.protobuf.Struct"] = function (type, value, options, depth) {
640
+ if (value === null || typeof value !== "object" || Array.isArray(value))
641
+ throw invalid(type.fullName, value, "google.protobuf.Struct must be an object");
642
+ return { fields: structFieldsFromJson(value, depth + 1) };
643
+ };
644
+ WKT_FROM[".google.protobuf.ListValue"] = function (type, value, options, depth) {
645
+ if (!Array.isArray(value))
646
+ throw invalid(type.fullName, value, "google.protobuf.ListValue must be an array");
647
+ var values = new Array(value.length), i = 0;
648
+ for (; i < value.length; ++i)
649
+ values[i] = valueFromJson(value[i], depth + 1);
650
+ return { values: values };
651
+ };
652
+
653
+ function valueToJson(message, options, depth) {
654
+ if (depth > util.recursionLimit)
655
+ throw Error("max depth exceeded");
656
+ if (message == null || hasOwn(message, "nullValue"))
657
+ return null;
658
+ if (hasOwn(message, "numberValue")) {
659
+ if (typeof message.numberValue === "number" && !isFinite(message.numberValue))
660
+ throw Error("google.protobuf.Value cannot hold a non-finite number");
661
+ return message.numberValue;
662
+ }
663
+ if (hasOwn(message, "stringValue")) return message.stringValue;
664
+ if (hasOwn(message, "boolValue")) return message.boolValue;
665
+ if (hasOwn(message, "structValue")) return structToJson(message.structValue, options, depth + 1);
666
+ if (hasOwn(message, "listValue")) return listToJson(message.listValue, options, depth + 1);
667
+ return null;
668
+ }
669
+ function structToJson(message, options, depth) {
670
+ var out = {}, fields = message && message.fields, k;
671
+ if (fields)
672
+ for (k in fields)
673
+ if (hasOwn(fields, k))
674
+ setOwn(out, k, valueToJson(fields[k], options, depth));
675
+ return out;
676
+ }
677
+ function listToJson(message, options, depth) {
678
+ var values = message && message.values;
679
+ if (!values) return [];
680
+ var arr = new Array(values.length), i = 0;
681
+ for (; i < values.length; ++i)
682
+ arr[i] = valueToJson(values[i], options, depth);
683
+ return arr;
684
+ }
685
+ WKT_TO[".google.protobuf.Value"] = function (type, message, options, depth) {
686
+ return valueToJson(message, options, depth);
687
+ };
688
+ WKT_TO[".google.protobuf.Struct"] = function (type, message, options, depth) {
689
+ return structToJson(message, options, depth);
690
+ };
691
+ WKT_TO[".google.protobuf.ListValue"] = function (type, message, options, depth) {
692
+ return listToJson(message, options, depth);
693
+ };
694
+
695
+ WKT_FROM[".google.protobuf.Any"] = function (type, value, options, depth) {
696
+ if (value === null || typeof value !== "object" || Array.isArray(value))
697
+ throw invalid(type.fullName, value, "google.protobuf.Any must be an object");
698
+ var typeUrl = value["@type"];
699
+ if (typeUrl === undefined)
700
+ return {};
701
+ if (typeof typeUrl !== "string")
702
+ throw Error("google.protobuf.Any @type must be a string");
703
+ var name = typeUrl.substring(typeUrl.lastIndexOf("/") + 1),
704
+ msgType = type.root.lookupType(name),
705
+ custom = WKT_FROM[msgType.fullName] !== undefined,
706
+ body;
707
+ if (custom)
708
+ body = value.value;
709
+ else {
710
+ body = {};
711
+ for (var k in value)
712
+ if (hasOwn(value, k) && k !== "@type")
713
+ setOwn(body, k, value[k]);
714
+ }
715
+ var inner = readMessage(msgType, body, options, depth + 1);
716
+ var url = typeUrl.charAt(0) === "." ? typeUrl.slice(1) : typeUrl;
717
+ if (url.indexOf("/") === -1)
718
+ url = "/" + url;
719
+ return { type_url: url, value: msgType.encode(inner).finish() };
720
+ };
721
+ WKT_TO[".google.protobuf.Any"] = function (type, message, options, depth) {
722
+ if (!message.type_url)
723
+ return {};
724
+ var name = message.type_url.substring(message.type_url.lastIndexOf("/") + 1),
725
+ msgType = type.root.lookupType(name),
726
+ decoded = msgType.decode(message.value),
727
+ body = toJsonValue(msgType, decoded, options, depth + 1),
728
+ result;
729
+ if (WKT_TO[msgType.fullName])
730
+ result = { "@type": message.type_url, "value": body };
731
+ else {
732
+ result = { "@type": message.type_url };
733
+ for (var k in body)
734
+ if (hasOwn(body, k))
735
+ setOwn(result, k, body[k]);
736
+ }
737
+ return result;
738
+ };
739
+
740
+ // --- duplicate keys ---
741
+
742
+ // JSON.parse keeps the last duplicate key, but ProtoJSON rejects duplicates.
743
+ function checkDuplicateKeys(str) {
744
+ var stack = [],
745
+ expectKey = false,
746
+ i = 0,
747
+ n = str.length;
748
+ while (i < n) {
749
+ var c = str.charAt(i);
750
+ if (c === "{") {
751
+ stack.push(Object.create(null));
752
+ expectKey = true;
753
+ ++i;
754
+ } else if (c === "[") {
755
+ stack.push(null);
756
+ expectKey = false;
757
+ ++i;
758
+ } else if (c === "}" || c === "]") {
759
+ stack.pop();
760
+ expectKey = false;
761
+ ++i;
762
+ } else if (c === ":") {
763
+ expectKey = false;
764
+ ++i;
765
+ } else if (c === ",") {
766
+ expectKey = stack.length > 0 && stack[stack.length - 1] !== null;
767
+ ++i;
768
+ } else if (c === "\"") {
769
+ var start = i++;
770
+ while (i < n) {
771
+ var ch = str.charAt(i++);
772
+ if (ch === "\\") ++i;
773
+ else if (ch === "\"") break;
774
+ }
775
+ if (expectKey) {
776
+ var seen = stack[stack.length - 1],
777
+ name = JSON.parse(str.slice(start, i));
778
+ if (seen[name])
779
+ throw Error("duplicate key in JSON object: " + JSON.stringify(name));
780
+ seen[name] = true;
781
+ expectKey = false;
782
+ }
783
+ } else
784
+ ++i;
785
+ }
786
+ }
787
+
788
+ // --- public API ---
789
+
790
+ /**
791
+ * ProtoJSON conversion options.
792
+ * @interface IProtoJsonOptions
793
+ * @property {boolean} [ignoreUnknownFields=false] Ignores unknown object members and unrecognized enum names while parsing.
794
+ */
795
+
796
+ /**
797
+ * Parses a message from an already-parsed ProtoJSON value using the specified reflected type.
798
+ * @function fromJson
799
+ * @name fromJson
800
+ * @param {$protobuf.Type} type Reflected message type
801
+ * @param {*} json Already-parsed ProtoJSON value
802
+ * @param {IProtoJsonOptions} [options] Conversion options
803
+ * @returns {$protobuf.Message<{}>} Message instance
804
+ */
805
+ protojson.fromJson = function fromJson(type, json, options) {
806
+ if (!(type instanceof Type))
807
+ throw TypeError("type must be a Type");
808
+ type.root.resolveAll();
809
+ return type.create(readMessage(type, json, options || {}, 0));
810
+ };
811
+
812
+ /**
813
+ * Parses a message from ProtoJSON text using the specified reflected type.
814
+ * @function fromJsonString
815
+ * @name fromJsonString
816
+ * @param {$protobuf.Type} type Reflected message type
817
+ * @param {string} json ProtoJSON text
818
+ * @param {IProtoJsonOptions} [options] Conversion options
819
+ * @returns {$protobuf.Message<{}>} Message instance
820
+ */
821
+ protojson.fromJsonString = function fromJsonString(type, json, options) {
822
+ if (typeof json !== "string")
823
+ throw TypeError("json must be a string");
824
+ checkDuplicateKeys(json);
825
+ return protojson.fromJson(type, JSON.parse(json), options);
826
+ };
827
+
828
+ /**
829
+ * Formats a message as ProtoJSON using the specified reflected type.
830
+ * @function toJson
831
+ * @name toJson
832
+ * @param {$protobuf.Type} type Reflected message type
833
+ * @param {$protobuf.Message<{}>|Object.<string,*>} message Message instance or plain object
834
+ * @param {IProtoJsonOptions} [options] Conversion options
835
+ * @returns {*} ProtoJSON value (object, array, string, number, boolean or null)
836
+ */
837
+ protojson.toJson = function toJson(type, message, options) {
838
+ if (!(type instanceof Type))
839
+ throw TypeError("type must be a Type");
840
+ type.root.resolveAll();
841
+ return toJsonValue(type, message, options || {}, 0);
842
+ };
843
+
844
+ /**
845
+ * Formats a message as ProtoJSON text using the specified reflected type.
846
+ * @function toJsonString
847
+ * @name toJsonString
848
+ * @param {$protobuf.Type} type Reflected message type
849
+ * @param {$protobuf.Message<{}>|Object.<string,*>} message Message instance or plain object
850
+ * @param {IProtoJsonOptions} [options] Conversion options
851
+ * @returns {string} ProtoJSON text
852
+ */
853
+ protojson.toJsonString = function toJsonString(type, message, options) {
854
+ return JSON.stringify(protojson.toJson(type, message, options));
855
+ };
856
+
857
+ /**
858
+ * Installs reflected {@link Type} convenience methods.
859
+ * @function install
860
+ * @name install
861
+ * @returns {undefined}
862
+ */
863
+ protojson.install = function install() {
864
+ /**
865
+ * Parses a message of this type from an already-parsed ProtoJSON value. Convenience for {@link protojson.fromJson}.
866
+ * @param {*} json Already-parsed ProtoJSON value
867
+ * @param {IProtoJsonOptions} [options] Conversion options
868
+ * @returns {Message<{}>} Message instance
869
+ */
870
+ Type.prototype.fromJson = function fromJson(json, options) {
871
+ return protojson.fromJson(this, json, options);
872
+ };
873
+
874
+ /**
875
+ * Parses a message of this type from ProtoJSON text. Convenience for {@link protojson.fromJsonString}.
876
+ * @param {string} json ProtoJSON text
877
+ * @param {IProtoJsonOptions} [options] Conversion options
878
+ * @returns {Message<{}>} Message instance
879
+ */
880
+ Type.prototype.fromJsonString = function fromJsonString(json, options) {
881
+ return protojson.fromJsonString(this, json, options);
882
+ };
883
+
884
+ /**
885
+ * Formats a message of this type as ProtoJSON. Convenience for {@link protojson.toJson}.
886
+ * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
887
+ * @param {IProtoJsonOptions} [options] Conversion options
888
+ * @returns {*} ProtoJSON value
889
+ */
890
+ Type.prototype.toJson = function toJson(message, options) {
891
+ return protojson.toJson(this, message, options);
892
+ };
893
+
894
+ /**
895
+ * Formats a message of this type as ProtoJSON text. Convenience for {@link protojson.toJsonString}.
896
+ * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
897
+ * @param {IProtoJsonOptions} [options] Conversion options
898
+ * @returns {string} ProtoJSON text
899
+ */
900
+ Type.prototype.toJsonString = function toJsonString(message, options) {
901
+ return protojson.toJsonString(this, message, options);
902
+ };
903
+ };