mirror of
https://github.com/github/codeql-action.git
synced 2025-12-30 03:00:13 +08:00
Co-authored-by: Andrew Eisenberg <aeisenberg@github.com> Co-authored-by: Henry Mercer <henrymercer@github.com>
231 lines
11 KiB
JavaScript
231 lines
11 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ReflectionJsonWriter = void 0;
|
|
const base64_1 = require("./base64");
|
|
const pb_long_1 = require("./pb-long");
|
|
const reflection_info_1 = require("./reflection-info");
|
|
const assert_1 = require("./assert");
|
|
/**
|
|
* Writes proto3 messages in canonical JSON format using reflection
|
|
* information.
|
|
*
|
|
* https://developers.google.com/protocol-buffers/docs/proto3#json
|
|
*/
|
|
class ReflectionJsonWriter {
|
|
constructor(info) {
|
|
var _a;
|
|
this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : [];
|
|
}
|
|
/**
|
|
* Converts the message to a JSON object, based on the field descriptors.
|
|
*/
|
|
write(message, options) {
|
|
const json = {}, source = message;
|
|
for (const field of this.fields) {
|
|
// field is not part of a oneof, simply write as is
|
|
if (!field.oneof) {
|
|
let jsonValue = this.field(field, source[field.localName], options);
|
|
if (jsonValue !== undefined)
|
|
json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue;
|
|
continue;
|
|
}
|
|
// field is part of a oneof
|
|
const group = source[field.oneof];
|
|
if (group.oneofKind !== field.localName)
|
|
continue; // not selected, skip
|
|
const opt = field.kind == 'scalar' || field.kind == 'enum'
|
|
? Object.assign(Object.assign({}, options), { emitDefaultValues: true }) : options;
|
|
let jsonValue = this.field(field, group[field.localName], opt);
|
|
assert_1.assert(jsonValue !== undefined);
|
|
json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue;
|
|
}
|
|
return json;
|
|
}
|
|
field(field, value, options) {
|
|
let jsonValue = undefined;
|
|
if (field.kind == 'map') {
|
|
assert_1.assert(typeof value == "object" && value !== null);
|
|
const jsonObj = {};
|
|
switch (field.V.kind) {
|
|
case "scalar":
|
|
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
const val = this.scalar(field.V.T, entryValue, field.name, false, true);
|
|
assert_1.assert(val !== undefined);
|
|
jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
|
|
}
|
|
break;
|
|
case "message":
|
|
const messageType = field.V.T();
|
|
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
const val = this.message(messageType, entryValue, field.name, options);
|
|
assert_1.assert(val !== undefined);
|
|
jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
|
|
}
|
|
break;
|
|
case "enum":
|
|
const enumInfo = field.V.T();
|
|
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
assert_1.assert(entryValue === undefined || typeof entryValue == 'number');
|
|
const val = this.enum(enumInfo, entryValue, field.name, false, true, options.enumAsInteger);
|
|
assert_1.assert(val !== undefined);
|
|
jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key
|
|
}
|
|
break;
|
|
}
|
|
if (options.emitDefaultValues || Object.keys(jsonObj).length > 0)
|
|
jsonValue = jsonObj;
|
|
}
|
|
else if (field.repeat) {
|
|
assert_1.assert(Array.isArray(value));
|
|
const jsonArr = [];
|
|
switch (field.kind) {
|
|
case "scalar":
|
|
for (let i = 0; i < value.length; i++) {
|
|
const val = this.scalar(field.T, value[i], field.name, field.opt, true);
|
|
assert_1.assert(val !== undefined);
|
|
jsonArr.push(val);
|
|
}
|
|
break;
|
|
case "enum":
|
|
const enumInfo = field.T();
|
|
for (let i = 0; i < value.length; i++) {
|
|
assert_1.assert(value[i] === undefined || typeof value[i] == 'number');
|
|
const val = this.enum(enumInfo, value[i], field.name, field.opt, true, options.enumAsInteger);
|
|
assert_1.assert(val !== undefined);
|
|
jsonArr.push(val);
|
|
}
|
|
break;
|
|
case "message":
|
|
const messageType = field.T();
|
|
for (let i = 0; i < value.length; i++) {
|
|
const val = this.message(messageType, value[i], field.name, options);
|
|
assert_1.assert(val !== undefined);
|
|
jsonArr.push(val);
|
|
}
|
|
break;
|
|
}
|
|
// add converted array to json output
|
|
if (options.emitDefaultValues || jsonArr.length > 0 || options.emitDefaultValues)
|
|
jsonValue = jsonArr;
|
|
}
|
|
else {
|
|
switch (field.kind) {
|
|
case "scalar":
|
|
jsonValue = this.scalar(field.T, value, field.name, field.opt, options.emitDefaultValues);
|
|
break;
|
|
case "enum":
|
|
jsonValue = this.enum(field.T(), value, field.name, field.opt, options.emitDefaultValues, options.enumAsInteger);
|
|
break;
|
|
case "message":
|
|
jsonValue = this.message(field.T(), value, field.name, options);
|
|
break;
|
|
}
|
|
}
|
|
return jsonValue;
|
|
}
|
|
/**
|
|
* Returns `null` as the default for google.protobuf.NullValue.
|
|
*/
|
|
enum(type, value, fieldName, optional, emitDefaultValues, enumAsInteger) {
|
|
if (type[0] == 'google.protobuf.NullValue')
|
|
return !emitDefaultValues && !optional ? undefined : null;
|
|
if (value === undefined) {
|
|
assert_1.assert(optional);
|
|
return undefined;
|
|
}
|
|
if (value === 0 && !emitDefaultValues && !optional)
|
|
// we require 0 to be default value for all enums
|
|
return undefined;
|
|
assert_1.assert(typeof value == 'number');
|
|
assert_1.assert(Number.isInteger(value));
|
|
if (enumAsInteger || !type[1].hasOwnProperty(value))
|
|
// if we don't now the enum value, just return the number
|
|
return value;
|
|
if (type[2])
|
|
// restore the dropped prefix
|
|
return type[2] + type[1][value];
|
|
return type[1][value];
|
|
}
|
|
message(type, value, fieldName, options) {
|
|
if (value === undefined)
|
|
return options.emitDefaultValues ? null : undefined;
|
|
return type.internalJsonWrite(value, options);
|
|
}
|
|
scalar(type, value, fieldName, optional, emitDefaultValues) {
|
|
if (value === undefined) {
|
|
assert_1.assert(optional);
|
|
return undefined;
|
|
}
|
|
const ed = emitDefaultValues || optional;
|
|
// noinspection FallThroughInSwitchStatementJS
|
|
switch (type) {
|
|
// int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
|
|
case reflection_info_1.ScalarType.INT32:
|
|
case reflection_info_1.ScalarType.SFIXED32:
|
|
case reflection_info_1.ScalarType.SINT32:
|
|
if (value === 0)
|
|
return ed ? 0 : undefined;
|
|
assert_1.assertInt32(value);
|
|
return value;
|
|
case reflection_info_1.ScalarType.FIXED32:
|
|
case reflection_info_1.ScalarType.UINT32:
|
|
if (value === 0)
|
|
return ed ? 0 : undefined;
|
|
assert_1.assertUInt32(value);
|
|
return value;
|
|
// float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
|
|
// Either numbers or strings are accepted. Exponent notation is also accepted.
|
|
case reflection_info_1.ScalarType.FLOAT:
|
|
assert_1.assertFloat32(value);
|
|
case reflection_info_1.ScalarType.DOUBLE:
|
|
if (value === 0)
|
|
return ed ? 0 : undefined;
|
|
assert_1.assert(typeof value == 'number');
|
|
if (Number.isNaN(value))
|
|
return 'NaN';
|
|
if (value === Number.POSITIVE_INFINITY)
|
|
return 'Infinity';
|
|
if (value === Number.NEGATIVE_INFINITY)
|
|
return '-Infinity';
|
|
return value;
|
|
// string:
|
|
case reflection_info_1.ScalarType.STRING:
|
|
if (value === "")
|
|
return ed ? '' : undefined;
|
|
assert_1.assert(typeof value == 'string');
|
|
return value;
|
|
// bool:
|
|
case reflection_info_1.ScalarType.BOOL:
|
|
if (value === false)
|
|
return ed ? false : undefined;
|
|
assert_1.assert(typeof value == 'boolean');
|
|
return value;
|
|
// JSON value will be a decimal string. Either numbers or strings are accepted.
|
|
case reflection_info_1.ScalarType.UINT64:
|
|
case reflection_info_1.ScalarType.FIXED64:
|
|
assert_1.assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint');
|
|
let ulong = pb_long_1.PbULong.from(value);
|
|
if (ulong.isZero() && !ed)
|
|
return undefined;
|
|
return ulong.toString();
|
|
// JSON value will be a decimal string. Either numbers or strings are accepted.
|
|
case reflection_info_1.ScalarType.INT64:
|
|
case reflection_info_1.ScalarType.SFIXED64:
|
|
case reflection_info_1.ScalarType.SINT64:
|
|
assert_1.assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint');
|
|
let long = pb_long_1.PbLong.from(value);
|
|
if (long.isZero() && !ed)
|
|
return undefined;
|
|
return long.toString();
|
|
// bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
|
|
// Either standard or URL-safe base64 encoding with/without paddings are accepted.
|
|
case reflection_info_1.ScalarType.BYTES:
|
|
assert_1.assert(value instanceof Uint8Array);
|
|
if (!value.byteLength)
|
|
return ed ? "" : undefined;
|
|
return base64_1.base64encode(value);
|
|
}
|
|
}
|
|
}
|
|
exports.ReflectionJsonWriter = ReflectionJsonWriter;
|