| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925 |
- // Copyright 2021 Google LLC
- // Copyright 2026 The protobuf.js Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- // Derived from proto3-json-serializer v3.0.4 and modified by The protobuf.js Authors.
-
- "use strict";
- var protobuf = require("../light");
-
- /* global BigInt */
-
- var Type = protobuf.Type,
- Enum = protobuf.Enum,
- util = protobuf.util;
-
- var protojson = protobuf.protojson = module.exports = {};
-
- function isExtension(field) {
- return Boolean(field.declaringField) || field.name.charAt(0) === ".";
- }
-
- function extensionName(field) {
- var df = field.declaringField || field,
- full = df.fullName.charAt(0) === "." ? df.fullName.slice(1) : df.fullName;
- return "[" + (df.protoName ? full.replace(/[^.]+$/, df.protoName) : full) + "]";
- }
-
- function indexField(index, key, field, type) {
- var existing = index[key];
- if (existing !== undefined && existing !== field)
- throw Error(type.fullName + ": duplicate ProtoJSON field name " + JSON.stringify(key));
- index[key] = field;
- }
-
- function fieldsByJsonName(type) {
- if (type._fieldsByJsonName)
- return type._fieldsByJsonName;
- var index = Object.create(null),
- fields = type.fieldsArray,
- i = 0;
- for (; i < fields.length; ++i) {
- var field = fields[i].resolve();
- if (isExtension(field))
- indexField(index, extensionName(field), field, type);
- else {
- indexField(index, field.name, field, type);
- indexField(index, field.jsonName, field, type);
- indexField(index, field.protoName, field, type);
- }
- }
- type._fieldsByJsonName = index;
- return index;
- }
-
- // --- reading scalars ---
-
- var INT_RANGE = {
- int32: ["-2147483648", "2147483647"],
- sint32: ["-2147483648", "2147483647"],
- sfixed32: ["-2147483648", "2147483647"],
- uint32: ["0", "4294967295"],
- fixed32: ["0", "4294967295"],
- int64: ["-9223372036854775808", "9223372036854775807"],
- sint64: ["-9223372036854775808", "9223372036854775807"],
- sfixed64: ["-9223372036854775808", "9223372036854775807"],
- uint64: ["0", "18446744073709551615"],
- fixed64: ["0", "18446744073709551615"]
- };
-
- var LONG_TYPE = { int64: 1, uint64: 1, sint64: 1, fixed64: 1, sfixed64: 1 };
-
- var MAX_FLOAT = 3.4028234663852886e38;
- var hasBigInt = typeof BigInt !== "undefined";
-
- var NUMERIC_RE = /^[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.?)(?:[eE][+-]?[0-9]+)?$/;
-
- var SKIP = {};
-
- function invalid(name, value, what) {
- return Error(name + ": " + what + ": " + JSON.stringify(value));
- }
-
- function parseIntegerString(value, type, name) {
- var str;
- if (typeof value === "number") {
- if (!isFinite(value) || Math.floor(value) !== value)
- throw invalid(name, value, "not an integer");
- str = numberToIntString(value);
- } else if (typeof value === "string") {
- if (value.length === 0 || /^\s|\s$/.test(value))
- throw invalid(name, value, "invalid integer");
- if (/^[+-]?[0-9]+$/.test(value))
- str = value;
- else if (NUMERIC_RE.test(value)) {
- var num = Number(value);
- if (!isFinite(num) || Math.floor(num) !== num)
- throw invalid(name, value, "not an integer");
- str = numberToIntString(num);
- } else
- throw invalid(name, value, "invalid integer");
- } else
- throw invalid(name, value, "expected integer (number or string)");
-
- var range = INT_RANGE[type];
- if (LONG_TYPE[type]) {
- if (hasBigInt) {
- var big = BigInt(str);
- if (big < BigInt(range[0]) || big > BigInt(range[1]))
- throw invalid(name, value, "out of range for " + type);
- }
- } else if (Number(str) < Number(range[0]) || Number(str) > Number(range[1]))
- throw invalid(name, value, "out of range for " + type);
- return str;
- }
-
- function parseMapIntegerKey(key, type, name) {
- var unsigned = type === "uint32" || type === "fixed32" || type === "uint64" || type === "fixed64";
- if (!(unsigned ? /^[0-9]+$/ : /^-?[0-9]+$/).test(key))
- throw invalid(name, key, "invalid " + type + " map key");
- if (hasBigInt) {
- var big = BigInt(key),
- range = INT_RANGE[type];
- if (big < BigInt(range[0]) || big > BigInt(range[1]))
- throw invalid(name, key, "out of range for " + type + " map key");
- return big.toString();
- }
- parseIntegerString(key, type, name);
- if (LONG_TYPE[type]) {
- var normalized = key.replace(/^-?0+(?=\d)/, key.charAt(0) === "-" ? "-" : "");
- return normalized === "-0" ? "0" : normalized;
- }
- return String(Number(key));
- }
-
- function numberToIntString(num) {
- if (num >= -9007199254740991 && num <= 9007199254740991)
- return String(num);
- return num.toFixed(0);
- }
-
- function parseFloat32Or64(value, isFloat, name) {
- var num;
- if (typeof value === "number") {
- if (!isFinite(value))
- throw invalid(name, value, "number out of range");
- num = value;
- } else if (value === "NaN")
- return NaN;
- else if (value === "Infinity")
- return Infinity;
- else if (value === "-Infinity")
- return -Infinity;
- else if (typeof value === "string") {
- if (value.length === 0 || /^\s|\s$/.test(value) || !NUMERIC_RE.test(value))
- throw invalid(name, value, "invalid number");
- num = Number(value);
- if (!isFinite(num))
- throw invalid(name, value, "invalid number");
- } else
- throw invalid(name, value, "expected number");
- if (isFloat && Math.abs(num) > MAX_FLOAT)
- throw invalid(name, value, "out of range for float");
- return num;
- }
-
- function validateUtf16(value, name) {
- for (var i = 0; i < value.length; ++i) {
- var c = value.charCodeAt(i);
- if (c >= 0xD800 && c <= 0xDBFF) {
- var next = value.charCodeAt(i + 1);
- if (!(next >= 0xDC00 && next <= 0xDFFF))
- throw invalid(name, value, "unpaired high surrogate");
- ++i;
- } else if (c >= 0xDC00 && c <= 0xDFFF)
- throw invalid(name, value, "unpaired low surrogate");
- }
- }
-
- function parseBytes(value, name) {
- if (typeof value !== "string")
- throw invalid(name, value, "expected base64 string");
- var s = value.replace(/-/g, "+").replace(/_/g, "/");
- while (s.length % 4)
- s += "=";
- var buffer = util.newBuffer(util.base64.length(s));
- util.base64.decode(s, buffer, 0);
- return buffer;
- }
-
- function longFromString(str, unsigned) {
- return util.Long ? util.Long.fromString(str, unsigned) : parseInt(str, 10);
- }
-
- function readScalar(type, value, name) {
- switch (type) {
- case "int32": case "sint32": case "sfixed32":
- case "uint32": case "fixed32":
- return Number(parseIntegerString(value, type, name));
- case "int64": case "sint64": case "sfixed64":
- return longFromString(parseIntegerString(value, type, name), false);
- case "uint64": case "fixed64":
- return longFromString(parseIntegerString(value, type, name), true);
- case "float":
- return parseFloat32Or64(value, true, name);
- case "double":
- return parseFloat32Or64(value, false, name);
- case "bool":
- if (typeof value !== "boolean")
- throw invalid(name, value, "expected boolean");
- return value;
- case "string":
- if (typeof value !== "string")
- throw invalid(name, value, "expected string");
- validateUtf16(value, name);
- return value;
- case "bytes":
- return parseBytes(value, name);
- default:
- throw Error(name + ": unsupported scalar type " + type);
- }
- }
-
- function readEnum(enm, value, name, options) {
- if (typeof value === "string") {
- var num = enm.values[value];
- if (num !== undefined)
- return num;
- if (options.ignoreUnknownFields)
- return SKIP;
- throw invalid(name, value, "unknown enum value");
- }
- if (typeof value === "number") {
- if (!isFinite(value) || Math.floor(value) !== value)
- throw invalid(name, value, "invalid enum number");
- return value;
- }
- if (value === null && enm.fullName === ".google.protobuf.NullValue")
- return 0;
- throw invalid(name, value, "expected enum string or number");
- }
-
- function readMapKey(field, key) {
- switch (field.keyType) {
- case "bool":
- if (key !== "true" && key !== "false")
- throw invalid(field.fullName, key, "invalid bool map key");
- return key;
- case "string":
- validateUtf16(key, field.fullName);
- return key;
- case "int32": case "sint32": case "sfixed32":
- case "uint32": case "fixed32":
- case "int64": case "sint64": case "sfixed64":
- case "uint64": case "fixed64":
- return parseMapIntegerKey(key, field.keyType, field.fullName);
- default:
- throw Error(field.fullName + ": unsupported map key type " + field.keyType);
- }
- }
-
- // --- reading messages ---
-
- function readField(field, value, options, depth) {
- if (field.map) {
- if (value === null || typeof value !== "object" || Array.isArray(value))
- throw invalid(field.fullName, value, "expected object for map");
- var map = Object.create(null), k;
- for (k in value)
- if (hasOwn(value, k)) {
- var mk = readMapKey(field, k),
- mv = readSingular(field, value[k], options, depth);
- if (mv !== SKIP) {
- if (hasOwn(map, mk))
- throw invalid(field.fullName, k, "duplicate map key");
- map[mk] = mv;
- }
- }
- return map;
- }
- if (field.repeated) {
- if (!Array.isArray(value))
- throw invalid(field.fullName, value, "expected array");
- var arr = [], i = 0;
- for (; i < value.length; ++i) {
- if (value[i] === null && !isValueType(field.resolvedType))
- throw invalid(field.fullName, null, "null element");
- var el = readSingular(field, value[i], options, depth);
- if (el !== SKIP)
- arr.push(el);
- }
- return arr;
- }
- return readSingular(field, value, options, depth);
- }
-
- function readSingular(field, value, options, depth) {
- if (field.resolvedType instanceof Type)
- return readMessage(field.resolvedType, value, options, depth + 1);
- if (field.resolvedType instanceof Enum)
- return readEnum(field.resolvedType, value, field.fullName, options);
- return readScalar(field.type, value, field.fullName);
- }
-
- function isValueType(type) {
- return type instanceof Type && type.fullName === ".google.protobuf.Value";
- }
-
- function isImplicitDefault(field, value) {
- if (field.hasPresence || field.repeated || field.map || field.resolvedType instanceof Type)
- return false;
- if (field.resolvedType instanceof Enum)
- return value === 0;
- switch (field.type) {
- case "bool": return value === false;
- case "string": return value === "";
- case "bytes": return value == null || value.length === 0;
- default: return longToNumber(value) === 0;
- }
- }
-
- function readMessage(type, value, options, depth) {
- if (depth > util.recursionLimit)
- throw Error("max depth exceeded");
-
- var wkt = WKT_FROM[type.fullName];
- if (wkt)
- return wkt(type, value, options, depth);
-
- if (value === null || typeof value !== "object" || Array.isArray(value))
- throw invalid(type.fullName, value, "expected object");
-
- var index = fieldsByJsonName(type),
- out = {},
- seenFields = Object.create(null),
- seenOneofs = Object.create(null),
- key;
-
- for (key in value) {
- if (!hasOwn(value, key))
- continue;
- var field = index[key];
- if (field === undefined) {
- if (options.ignoreUnknownFields)
- continue;
- throw invalid(type.fullName, key, "unknown field");
- }
- if (seenFields[field.name])
- throw invalid(type.fullName, key, "duplicate field");
- seenFields[field.name] = true;
- var fv = value[key], fieldValue;
- if (fv === null) {
- if (isValueType(field.resolvedType))
- fieldValue = { nullValue: 0 };
- else if (field.resolvedType instanceof Enum && field.resolvedType.fullName === ".google.protobuf.NullValue")
- fieldValue = 0;
- else
- continue;
- } else
- fieldValue = readField(field, fv, options, depth);
- if (fieldValue === SKIP)
- continue;
- if (field.partOf) {
- if (seenOneofs[field.partOf.name])
- throw Error(type.fullName + ": multiple values for oneof " + field.partOf.name);
- seenOneofs[field.partOf.name] = true;
- }
- if (!isImplicitDefault(field, fieldValue))
- out[field.name] = fieldValue;
- }
- return out;
- }
-
- // --- writing messages ---
-
- function hasOwn(o, k) {
- return o != null && Object.prototype.hasOwnProperty.call(o, k);
- }
-
- function setOwn(o, k, v) {
- if (k === "__proto__")
- util.makeProp(o, k);
- o[k] = v;
- }
-
- function wktFieldName(type, name) {
- var field = fieldsByJsonName(type)[name];
- return field ? field.name : name;
- }
-
- function wktFieldValue(type, message, name) {
- var field = fieldsByJsonName(type)[name];
- if (!field)
- return message && message[name];
- if (hasOwn(message, field.name))
- return message[field.name];
- if (hasOwn(message, field.protoName))
- return message[field.protoName];
- if (hasOwn(message, field.jsonName))
- return message[field.jsonName];
- return undefined;
- }
-
- function writeScalar(type, value) {
- switch (type) {
- case "int64": case "sint64": case "sfixed64":
- case "uint64": case "fixed64":
- return value == null ? "0" : String(value);
- case "float": case "double":
- return typeof value === "number" && !isFinite(value) ? String(value) : value;
- case "bytes":
- return value == null ? "" : util.base64.encode(value, 0, value.length);
- default:
- return value;
- }
- }
-
- function writeSingular(field, value, options, depth) {
- if (field.resolvedType instanceof Type)
- return toJsonValue(field.resolvedType, value, options, depth + 1);
- if (field.resolvedType instanceof Enum) {
- if (field.resolvedType.fullName === ".google.protobuf.NullValue")
- return null;
- var name = field.resolvedType.valuesById[value];
- return name === undefined ? value : name;
- }
- return writeScalar(field.type, value);
- }
-
- function toJsonValue(type, message, options, depth) {
- if (depth > util.recursionLimit)
- throw Error("max depth exceeded");
-
- var wkt = WKT_TO[type.fullName];
- if (wkt)
- return wkt(type, message, options, depth);
-
- var out = {},
- fields = type.fieldsArray,
- i = 0;
- for (; i < fields.length; ++i) {
- var field = fields[i].resolve(),
- value = message[field.name];
- if (value == null)
- continue;
- var key = isExtension(field) ? extensionName(field) : field.jsonName;
- if (field.map) {
- var mk = Object.keys(value);
- if (!mk.length)
- continue;
- var longKey = LONG_TYPE[field.keyType],
- unsignedKey = field.keyType === "uint64" || field.keyType === "fixed64",
- mo = {}, ki = 0;
- for (; ki < mk.length; ++ki) {
- var outKey = longKey ? util.longFromKey(mk[ki], unsignedKey).toString() : mk[ki];
- setOwn(mo, outKey, writeSingular(field, value[mk[ki]], options, depth));
- }
- setOwn(out, key, mo);
- } else if (field.repeated) {
- if (!value.length)
- continue;
- var arr = new Array(value.length), j = 0;
- for (; j < value.length; ++j)
- arr[j] = writeSingular(field, value[j], options, depth);
- setOwn(out, key, arr);
- } else {
- if (!hasOwn(message, field.name) || isImplicitDefault(field, value))
- continue;
- setOwn(out, key, writeSingular(field, value, options, depth));
- }
- }
- return out;
- }
-
- // --- well-known types ---
-
- function longToNumber(value) {
- if (value == null) return 0;
- if (typeof value === "number") return value;
- if (typeof value.toNumber === "function") return value.toNumber();
- return Number(value) || 0;
- }
-
- function nanosToString(nanos) {
- var str = String(nanos < 0 ? -nanos : nanos);
- while (str.length < 9) str = "0" + str;
- while (str.length > 3 && str.slice(str.length - 3) === "000") str = str.slice(0, str.length - 3);
- return str;
- }
-
- function fracToNanos(frac) {
- while (frac.length < 9) frac += "0";
- return parseInt(frac.slice(0, 9), 10);
- }
-
- function daysInMonth(year, month) {
- switch (month) {
- case 2:
- return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28;
- case 4:
- case 6:
- case 9:
- case 11:
- return 30;
- default:
- return 31;
- }
- }
-
- function camelToSnake(path) {
- return path.replace(/[A-Z]/g, function ($0) { return "_" + $0.toLowerCase(); });
- }
-
- var WKT_FROM = {};
- var WKT_TO = {};
-
- WKT_FROM[".google.protobuf.Duration"] = function (type, value) {
- if (typeof value !== "string")
- throw invalid(type.fullName, value, "expected duration string");
- var match = /^(-)?([0-9]+)(?:\.([0-9]{1,9}))?s$/.exec(value);
- if (!match)
- throw invalid(type.fullName, value, "invalid duration");
- var sign = match[1] ? -1 : 1,
- seconds = parseInt(match[2], 10) * sign || 0,
- nanos = match[3] ? fracToNanos(match[3]) * sign || 0 : 0;
- if (seconds > 315576000000 || seconds < -315576000000)
- throw invalid(type.fullName, value, "duration out of range");
- return { seconds: seconds, nanos: nanos };
- };
- WKT_TO[".google.protobuf.Duration"] = function (type, message) {
- var seconds = longToNumber(message.seconds),
- nanos = message.nanos || 0;
- if (seconds > 315576000000 || seconds < -315576000000)
- throw Error("google.protobuf.Duration out of range");
- if (nanos > 999999999 || nanos < -999999999 || seconds && nanos && seconds < 0 !== nanos < 0)
- throw Error("google.protobuf.Duration nanos invalid");
- var result = (seconds < 0 || nanos < 0 ? "-" : "") + Math.abs(seconds);
- if (nanos)
- result += "." + nanosToString(nanos);
- return result + "s";
- };
-
- WKT_FROM[".google.protobuf.Timestamp"] = function (type, value) {
- if (typeof value !== "string")
- throw invalid(type.fullName, value, "expected timestamp string");
- 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);
- if (!match)
- throw invalid(type.fullName, value, "invalid timestamp");
- var year = parseInt(match[1], 10),
- month = parseInt(match[2], 10),
- day = parseInt(match[3], 10);
- if (day > daysInMonth(year, month))
- throw invalid(type.fullName, value, "invalid timestamp date");
- var millis = new Date(value).getTime();
- if (isNaN(millis))
- throw invalid(type.fullName, value, "invalid timestamp");
- var seconds = Math.floor(millis / 1000),
- nanos = match[7] ? fracToNanos(match[7]) : 0;
- if (seconds < -62135596800 || seconds > 253402300799)
- throw invalid(type.fullName, value, "timestamp out of range");
- return { seconds: seconds, nanos: nanos };
- };
- WKT_TO[".google.protobuf.Timestamp"] = function (type, message) {
- var seconds = longToNumber(message.seconds),
- nanos = message.nanos || 0;
- if (seconds < -62135596800 || seconds > 253402300799)
- throw Error("google.protobuf.Timestamp out of range");
- if (nanos < 0 || nanos > 999999999)
- throw Error("google.protobuf.Timestamp nanos out of range");
- var iso = new Date(seconds * 1000).toISOString();
- return nanos
- ? iso.replace(/\.\d+Z$/, "." + nanosToString(nanos) + "Z")
- : iso.replace(/\.\d+Z$/, "Z");
- };
-
- WKT_FROM[".google.protobuf.FieldMask"] = function (type, value) {
- if (typeof value !== "string")
- throw invalid(type.fullName, value, "expected field mask string");
- if (value.indexOf("_") !== -1)
- throw invalid(type.fullName, value, "field mask path must be lowerCamelCase");
- var paths = value.length ? value.split(",") : [],
- i = 0;
- for (; i < paths.length; ++i)
- paths[i] = camelToSnake(paths[i]);
- return { paths: paths };
- };
- WKT_TO[".google.protobuf.FieldMask"] = function (type, message) {
- var paths = message.paths || [],
- out = [],
- i = 0;
- for (; i < paths.length; ++i) {
- var camel = util.jsonName(paths[i]);
- if (camelToSnake(camel) !== paths[i])
- throw Error("google.protobuf.FieldMask path does not round-trip: " + paths[i]);
- out.push(camel);
- }
- return out.join(",");
- };
-
- ["DoubleValue", "FloatValue", "Int64Value", "UInt64Value", "Int32Value",
- "UInt32Value", "BoolValue", "StringValue", "BytesValue"].forEach(function (name) {
- var fullName = ".google.protobuf." + name;
- WKT_FROM[fullName] = function (type, value, options, depth) {
- return { value: readSingular(type.fields.value.resolve(), value, options, depth) };
- };
- WKT_TO[fullName] = function (type, message, options, depth) {
- return writeSingular(type.fields.value.resolve(), message.value, options, depth);
- };
- });
-
- function valueFromJson(json, depth) {
- if (depth > util.recursionLimit)
- throw Error("max depth exceeded");
- if (json === null)
- return { nullValue: 0 };
- switch (typeof json) {
- case "number":
- if (!isFinite(json))
- throw Error("google.protobuf.Value cannot hold a non-finite number");
- return { numberValue: json };
- case "string":
- validateUtf16(json, "google.protobuf.Value.string_value");
- return { stringValue: json };
- case "boolean":
- return { boolValue: json };
- }
- if (Array.isArray(json)) {
- var values = new Array(json.length), i = 0;
- for (; i < json.length; ++i)
- values[i] = valueFromJson(json[i], depth + 1);
- return { listValue: { values: values } };
- }
- return { structValue: { fields: structFieldsFromJson(json, depth + 1) } };
- }
- function structFieldsFromJson(json, depth) {
- var fields = Object.create(null), k;
- for (k in json)
- if (hasOwn(json, k)) {
- validateUtf16(k, "google.protobuf.Struct.fields");
- fields[k] = valueFromJson(json[k], depth);
- }
- return fields;
- }
- WKT_FROM[".google.protobuf.Value"] = function (type, value, options, depth) {
- return valueFromJson(value, depth);
- };
- WKT_FROM[".google.protobuf.Struct"] = function (type, value, options, depth) {
- if (value === null || typeof value !== "object" || Array.isArray(value))
- throw invalid(type.fullName, value, "google.protobuf.Struct must be an object");
- return { fields: structFieldsFromJson(value, depth + 1) };
- };
- WKT_FROM[".google.protobuf.ListValue"] = function (type, value, options, depth) {
- if (!Array.isArray(value))
- throw invalid(type.fullName, value, "google.protobuf.ListValue must be an array");
- var values = new Array(value.length), i = 0;
- for (; i < value.length; ++i)
- values[i] = valueFromJson(value[i], depth + 1);
- return { values: values };
- };
-
- function valueToJson(message, options, depth) {
- if (depth > util.recursionLimit)
- throw Error("max depth exceeded");
- if (message == null || hasOwn(message, "nullValue"))
- return null;
- if (hasOwn(message, "numberValue")) {
- if (typeof message.numberValue === "number" && !isFinite(message.numberValue))
- throw Error("google.protobuf.Value cannot hold a non-finite number");
- return message.numberValue;
- }
- if (hasOwn(message, "stringValue")) return message.stringValue;
- if (hasOwn(message, "boolValue")) return message.boolValue;
- if (hasOwn(message, "structValue")) return structToJson(message.structValue, options, depth + 1);
- if (hasOwn(message, "listValue")) return listToJson(message.listValue, options, depth + 1);
- return null;
- }
- function structToJson(message, options, depth) {
- var out = {}, fields = message && message.fields, k;
- if (fields)
- for (k in fields)
- if (hasOwn(fields, k))
- setOwn(out, k, valueToJson(fields[k], options, depth));
- return out;
- }
- function listToJson(message, options, depth) {
- var values = message && message.values;
- if (!values) return [];
- var arr = new Array(values.length), i = 0;
- for (; i < values.length; ++i)
- arr[i] = valueToJson(values[i], options, depth);
- return arr;
- }
- WKT_TO[".google.protobuf.Value"] = function (type, message, options, depth) {
- return valueToJson(message, options, depth);
- };
- WKT_TO[".google.protobuf.Struct"] = function (type, message, options, depth) {
- return structToJson(message, options, depth);
- };
- WKT_TO[".google.protobuf.ListValue"] = function (type, message, options, depth) {
- return listToJson(message, options, depth);
- };
-
- WKT_FROM[".google.protobuf.Any"] = function (type, value, options, depth) {
- if (value === null || typeof value !== "object" || Array.isArray(value))
- throw invalid(type.fullName, value, "google.protobuf.Any must be an object");
- var typeUrl = value["@type"];
- if (typeUrl === undefined)
- return {};
- if (typeof typeUrl !== "string")
- throw Error("google.protobuf.Any @type must be a string");
- var name = typeUrl.substring(typeUrl.lastIndexOf("/") + 1),
- msgType = type.root.lookupType(name),
- custom = WKT_FROM[msgType.fullName] !== undefined,
- body;
- if (custom)
- body = value.value;
- else {
- body = {};
- for (var k in value)
- if (hasOwn(value, k) && k !== "@type")
- setOwn(body, k, value[k]);
- }
- var inner = readMessage(msgType, body, options, depth + 1);
- var url = typeUrl.charAt(0) === "." ? typeUrl.slice(1) : typeUrl,
- out = {};
- if (url.indexOf("/") === -1)
- url = "/" + url;
- out[wktFieldName(type, "type_url")] = url;
- out[wktFieldName(type, "value")] = msgType.encode(inner).finish();
- return out;
- };
- WKT_TO[".google.protobuf.Any"] = function (type, message, options, depth) {
- var typeUrl = wktFieldValue(type, message, "type_url");
- if (!typeUrl)
- return {};
- var name = typeUrl.substring(typeUrl.lastIndexOf("/") + 1),
- msgType = type.root.lookupType(name),
- decoded = msgType.decode(wktFieldValue(type, message, "value")),
- body = toJsonValue(msgType, decoded, options, depth + 1),
- result;
- if (WKT_TO[msgType.fullName])
- result = { "@type": typeUrl, "value": body };
- else {
- result = { "@type": typeUrl };
- for (var k in body)
- if (hasOwn(body, k))
- setOwn(result, k, body[k]);
- }
- return result;
- };
-
- // --- duplicate keys ---
-
- // JSON.parse keeps the last duplicate key, but ProtoJSON rejects duplicates.
- function checkDuplicateKeys(str) {
- var stack = [],
- expectKey = false,
- i = 0,
- n = str.length;
- while (i < n) {
- var c = str.charAt(i);
- if (c === "{") {
- stack.push(Object.create(null));
- expectKey = true;
- ++i;
- } else if (c === "[") {
- stack.push(null);
- expectKey = false;
- ++i;
- } else if (c === "}" || c === "]") {
- stack.pop();
- expectKey = false;
- ++i;
- } else if (c === ":") {
- expectKey = false;
- ++i;
- } else if (c === ",") {
- expectKey = stack.length > 0 && stack[stack.length - 1] !== null;
- ++i;
- } else if (c === "\"") {
- var start = i++;
- while (i < n) {
- var ch = str.charAt(i++);
- if (ch === "\\") ++i;
- else if (ch === "\"") break;
- }
- if (expectKey) {
- var seen = stack[stack.length - 1],
- name = JSON.parse(str.slice(start, i));
- if (seen[name])
- throw Error("duplicate key in JSON object: " + JSON.stringify(name));
- seen[name] = true;
- expectKey = false;
- }
- } else
- ++i;
- }
- }
-
- // --- public API ---
-
- /**
- * ProtoJSON conversion options.
- * @interface IProtoJsonOptions
- * @property {boolean} [ignoreUnknownFields=false] Ignores unknown object members and unrecognized enum names while parsing.
- */
-
- /**
- * Parses a message from an already-parsed ProtoJSON value using the specified reflected type.
- * @function fromJson
- * @name fromJson
- * @param {$protobuf.Type} type Reflected message type
- * @param {*} json Already-parsed ProtoJSON value
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {$protobuf.Message<{}>} Message instance
- */
- protojson.fromJson = function fromJson(type, json, options) {
- if (!(type instanceof Type))
- throw TypeError("type must be a Type");
- type.root.resolveAll();
- return type.create(readMessage(type, json, options || {}, 0));
- };
-
- /**
- * Parses a message from ProtoJSON text using the specified reflected type.
- * @function fromJsonString
- * @name fromJsonString
- * @param {$protobuf.Type} type Reflected message type
- * @param {string} json ProtoJSON text
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {$protobuf.Message<{}>} Message instance
- */
- protojson.fromJsonString = function fromJsonString(type, json, options) {
- if (typeof json !== "string")
- throw TypeError("json must be a string");
- checkDuplicateKeys(json);
- return protojson.fromJson(type, JSON.parse(json), options);
- };
-
- /**
- * Formats a message as ProtoJSON using the specified reflected type.
- * @function toJson
- * @name toJson
- * @param {$protobuf.Type} type Reflected message type
- * @param {$protobuf.Message<{}>|Object.<string,*>} message Message instance or plain object
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {*} ProtoJSON value (object, array, string, number, boolean or null)
- */
- protojson.toJson = function toJson(type, message, options) {
- if (!(type instanceof Type))
- throw TypeError("type must be a Type");
- type.root.resolveAll();
- return toJsonValue(type, message, options || {}, 0);
- };
-
- /**
- * Formats a message as ProtoJSON text using the specified reflected type.
- * @function toJsonString
- * @name toJsonString
- * @param {$protobuf.Type} type Reflected message type
- * @param {$protobuf.Message<{}>|Object.<string,*>} message Message instance or plain object
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {string} ProtoJSON text
- */
- protojson.toJsonString = function toJsonString(type, message, options) {
- return JSON.stringify(protojson.toJson(type, message, options));
- };
-
- /**
- * Installs reflected {@link Type} convenience methods.
- * @function install
- * @name install
- * @returns {undefined}
- */
- protojson.install = function install() {
- /**
- * Parses a message of this type from an already-parsed ProtoJSON value. Convenience for {@link protojson.fromJson}.
- * @param {*} json Already-parsed ProtoJSON value
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {Message<{}>} Message instance
- */
- Type.prototype.fromJson = function fromJson(json, options) {
- return protojson.fromJson(this, json, options);
- };
-
- /**
- * Parses a message of this type from ProtoJSON text. Convenience for {@link protojson.fromJsonString}.
- * @param {string} json ProtoJSON text
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {Message<{}>} Message instance
- */
- Type.prototype.fromJsonString = function fromJsonString(json, options) {
- return protojson.fromJsonString(this, json, options);
- };
-
- /**
- * Formats a message of this type as ProtoJSON. Convenience for {@link protojson.toJson}.
- * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {*} ProtoJSON value
- */
- Type.prototype.toJson = function toJson(message, options) {
- return protojson.toJson(this, message, options);
- };
-
- /**
- * Formats a message of this type as ProtoJSON text. Convenience for {@link protojson.toJsonString}.
- * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
- * @param {IProtoJsonOptions} [options] Conversion options
- * @returns {string} ProtoJSON text
- */
- Type.prototype.toJsonString = function toJsonString(message, options) {
- return protojson.toJsonString(this, message, options);
- };
- };
|