Erster Commit

This commit is contained in:
2026-08-22 08:40:29 +02:00
commit 875477d425
1961 changed files with 930336 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
/**
* Assert that condition is truthy or throw error (with message)
*/
export declare function assert(condition: unknown, msg?: string): asserts condition;
/**
* Assert a valid signed protobuf 32-bit integer.
*/
export declare function assertInt32(arg: unknown): asserts arg is number;
/**
* Assert a valid unsigned protobuf 32-bit integer.
*/
export declare function assertUInt32(arg: unknown): asserts arg is number;
/**
* Assert a valid protobuf float value.
*/
export declare function assertFloat32(arg: unknown): asserts arg is number;
+59
View File
@@ -0,0 +1,59 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertFloat32 = exports.assertUInt32 = exports.assertInt32 = exports.assert = void 0;
/**
* Assert that condition is truthy or throw error (with message)
*/
function assert(condition, msg) {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions -- we want the implicit conversion to boolean
if (!condition) {
throw new Error(msg);
}
}
exports.assert = assert;
const FLOAT32_MAX = 3.4028234663852886e38, FLOAT32_MIN = -3.4028234663852886e38, UINT32_MAX = 0xffffffff, INT32_MAX = 0x7fffffff, INT32_MIN = -0x80000000;
/**
* Assert a valid signed protobuf 32-bit integer.
*/
function assertInt32(arg) {
if (typeof arg !== "number")
throw new Error("invalid int 32: " + typeof arg);
if (!Number.isInteger(arg) || arg > INT32_MAX || arg < INT32_MIN)
throw new Error("invalid int 32: " + arg); // eslint-disable-line @typescript-eslint/restrict-plus-operands -- we want the implicit conversion to string
}
exports.assertInt32 = assertInt32;
/**
* Assert a valid unsigned protobuf 32-bit integer.
*/
function assertUInt32(arg) {
if (typeof arg !== "number")
throw new Error("invalid uint 32: " + typeof arg);
if (!Number.isInteger(arg) || arg > UINT32_MAX || arg < 0)
throw new Error("invalid uint 32: " + arg); // eslint-disable-line @typescript-eslint/restrict-plus-operands -- we want the implicit conversion to string
}
exports.assertUInt32 = assertUInt32;
/**
* Assert a valid protobuf float value.
*/
function assertFloat32(arg) {
if (typeof arg !== "number")
throw new Error("invalid float 32: " + typeof arg);
if (!Number.isFinite(arg))
return;
if (arg > FLOAT32_MAX || arg < FLOAT32_MIN)
throw new Error("invalid float 32: " + arg); // eslint-disable-line @typescript-eslint/restrict-plus-operands -- we want the implicit conversion to string
}
exports.assertFloat32 = assertFloat32;
+7
View File
@@ -0,0 +1,7 @@
import type { IBinaryWriter } from "../binary-encoding.js";
import type { BinaryFormat, BinaryWriteOptions } from "../binary-format.js";
import type { FieldInfo } from "../field.js";
export declare function makeBinaryFormat(): BinaryFormat;
export declare function writeMapEntry(writer: IBinaryWriter, options: BinaryWriteOptions, field: FieldInfo & {
kind: "map";
}, key: string, value: any): void;
+431
View File
@@ -0,0 +1,431 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeMapEntry = exports.makeBinaryFormat = void 0;
const binary_encoding_js_1 = require("../binary-encoding.js");
const field_wrapper_js_1 = require("./field-wrapper.js");
const scalars_js_1 = require("./scalars.js");
const assert_js_1 = require("./assert.js");
const reflect_js_1 = require("./reflect.js");
const scalar_js_1 = require("../scalar.js");
const is_message_js_1 = require("../is-message.js");
/* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-return */
const unknownFieldsSymbol = Symbol("@bufbuild/protobuf/unknown-fields");
// Default options for parsing binary data.
const readDefaults = {
readUnknownFields: true,
readerFactory: (bytes) => new binary_encoding_js_1.BinaryReader(bytes),
};
// Default options for serializing binary data.
const writeDefaults = {
writeUnknownFields: true,
writerFactory: () => new binary_encoding_js_1.BinaryWriter(),
};
function makeReadOptions(options) {
return options ? Object.assign(Object.assign({}, readDefaults), options) : readDefaults;
}
function makeWriteOptions(options) {
return options ? Object.assign(Object.assign({}, writeDefaults), options) : writeDefaults;
}
function makeBinaryFormat() {
return {
makeReadOptions,
makeWriteOptions,
listUnknownFields(message) {
var _a;
return (_a = message[unknownFieldsSymbol]) !== null && _a !== void 0 ? _a : [];
},
discardUnknownFields(message) {
delete message[unknownFieldsSymbol];
},
writeUnknownFields(message, writer) {
const m = message;
const c = m[unknownFieldsSymbol];
if (c) {
for (const f of c) {
writer.tag(f.no, f.wireType).raw(f.data);
}
}
},
onUnknownField(message, no, wireType, data) {
const m = message;
if (!Array.isArray(m[unknownFieldsSymbol])) {
m[unknownFieldsSymbol] = [];
}
m[unknownFieldsSymbol].push({ no, wireType, data });
},
readMessage(message, reader, lengthOrEndTagFieldNo, options, delimitedMessageEncoding) {
const type = message.getType();
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const end = delimitedMessageEncoding
? reader.len
: reader.pos + lengthOrEndTagFieldNo;
let fieldNo, wireType;
while (reader.pos < end) {
[fieldNo, wireType] = reader.tag();
if (delimitedMessageEncoding === true &&
wireType == binary_encoding_js_1.WireType.EndGroup) {
break;
}
const field = type.fields.find(fieldNo);
if (!field) {
const data = reader.skip(wireType, fieldNo);
if (options.readUnknownFields) {
this.onUnknownField(message, fieldNo, wireType, data);
}
continue;
}
readField(message, reader, field, wireType, options);
}
if (delimitedMessageEncoding && // eslint-disable-line @typescript-eslint/strict-boolean-expressions
(wireType != binary_encoding_js_1.WireType.EndGroup || fieldNo !== lengthOrEndTagFieldNo)) {
throw new Error(`invalid end group tag`);
}
},
readField,
writeMessage(message, writer, options) {
const type = message.getType();
for (const field of type.fields.byNumber()) {
if (!(0, reflect_js_1.isFieldSet)(field, message)) {
if (field.req) {
throw new Error(`cannot encode field ${type.typeName}.${field.name} to binary: required field not set`);
}
continue;
}
const value = field.oneof
? message[field.oneof.localName].value
: message[field.localName];
writeField(field, value, writer, options);
}
if (options.writeUnknownFields) {
this.writeUnknownFields(message, writer);
}
return writer;
},
writeField(field, value, writer, options) {
// The behavior of our internal function has changed, it does no longer
// accept `undefined` values for singular scalar and map.
// For backwards-compatibility, we support the old form that is part of
// the public API through the interface BinaryFormat.
if (value === undefined) {
return undefined;
}
writeField(field, value, writer, options);
},
};
}
exports.makeBinaryFormat = makeBinaryFormat;
function readField(target, // eslint-disable-line @typescript-eslint/no-explicit-any -- `any` is the best choice for dynamic access
reader, field, wireType, options) {
let { repeated, localName } = field;
if (field.oneof) {
target = target[field.oneof.localName];
if (target.case != localName) {
delete target.value;
}
target.case = localName;
localName = "value";
}
switch (field.kind) {
case "scalar":
case "enum":
const scalarType = field.kind == "enum" ? scalar_js_1.ScalarType.INT32 : field.T;
let read = readScalar;
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- acceptable since it's covered by tests
if (field.kind == "scalar" && field.L > 0) {
read = readScalarLTString;
}
if (repeated) {
let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values
const isPacked = wireType == binary_encoding_js_1.WireType.LengthDelimited &&
scalarType != scalar_js_1.ScalarType.STRING &&
scalarType != scalar_js_1.ScalarType.BYTES;
if (isPacked) {
let e = reader.uint32() + reader.pos;
while (reader.pos < e) {
arr.push(read(reader, scalarType));
}
}
else {
arr.push(read(reader, scalarType));
}
}
else {
target[localName] = read(reader, scalarType);
}
break;
case "message":
const messageType = field.T;
if (repeated) {
// safe to assume presence of array, oneof cannot contain repeated values
target[localName].push(readMessageField(reader, new messageType(), options, field));
}
else {
if ((0, is_message_js_1.isMessage)(target[localName])) {
readMessageField(reader, target[localName], options, field);
}
else {
target[localName] = readMessageField(reader, new messageType(), options, field);
if (messageType.fieldWrapper && !field.oneof && !field.repeated) {
target[localName] = messageType.fieldWrapper.unwrapField(target[localName]);
}
}
}
break;
case "map":
let [mapKey, mapVal] = readMapEntry(field, reader, options);
// safe to assume presence of map object, oneof cannot contain repeated values
target[localName][mapKey] = mapVal;
break;
}
}
// Read a message, avoiding MessageType.fromBinary() to re-use the
// BinaryReadOptions and the IBinaryReader.
function readMessageField(reader, message, options, field) {
const format = message.getType().runtime.bin;
const delimited = field === null || field === void 0 ? void 0 : field.delimited;
format.readMessage(message, reader, delimited ? field.no : reader.uint32(), // eslint-disable-line @typescript-eslint/strict-boolean-expressions
options, delimited);
return message;
}
// Read a map field, expecting key field = 1, value field = 2
function readMapEntry(field, reader, options) {
const length = reader.uint32(), end = reader.pos + length;
let key, val;
while (reader.pos < end) {
const [fieldNo] = reader.tag();
switch (fieldNo) {
case 1:
key = readScalar(reader, field.K);
break;
case 2:
switch (field.V.kind) {
case "scalar":
val = readScalar(reader, field.V.T);
break;
case "enum":
val = reader.int32();
break;
case "message":
val = readMessageField(reader, new field.V.T(), options, undefined);
break;
}
break;
}
}
if (key === undefined) {
key = (0, scalars_js_1.scalarZeroValue)(field.K, scalar_js_1.LongType.BIGINT);
}
if (typeof key != "string" && typeof key != "number") {
key = key.toString();
}
if (val === undefined) {
switch (field.V.kind) {
case "scalar":
val = (0, scalars_js_1.scalarZeroValue)(field.V.T, scalar_js_1.LongType.BIGINT);
break;
case "enum":
val = field.V.T.values[0].no;
break;
case "message":
val = new field.V.T();
break;
}
}
return [key, val];
}
// Read a scalar value, but return 64 bit integral types (int64, uint64,
// sint64, fixed64, sfixed64) as string instead of bigint.
function readScalarLTString(reader, type) {
const v = readScalar(reader, type);
return typeof v == "bigint" ? v.toString() : v;
}
// Does not use scalarTypeInfo() for better performance.
function readScalar(reader, type) {
switch (type) {
case scalar_js_1.ScalarType.STRING:
return reader.string();
case scalar_js_1.ScalarType.BOOL:
return reader.bool();
case scalar_js_1.ScalarType.DOUBLE:
return reader.double();
case scalar_js_1.ScalarType.FLOAT:
return reader.float();
case scalar_js_1.ScalarType.INT32:
return reader.int32();
case scalar_js_1.ScalarType.INT64:
return reader.int64();
case scalar_js_1.ScalarType.UINT64:
return reader.uint64();
case scalar_js_1.ScalarType.FIXED64:
return reader.fixed64();
case scalar_js_1.ScalarType.BYTES:
return reader.bytes();
case scalar_js_1.ScalarType.FIXED32:
return reader.fixed32();
case scalar_js_1.ScalarType.SFIXED32:
return reader.sfixed32();
case scalar_js_1.ScalarType.SFIXED64:
return reader.sfixed64();
case scalar_js_1.ScalarType.SINT64:
return reader.sint64();
case scalar_js_1.ScalarType.UINT32:
return reader.uint32();
case scalar_js_1.ScalarType.SINT32:
return reader.sint32();
}
}
function writeField(field, value, writer, options) {
(0, assert_js_1.assert)(value !== undefined);
const repeated = field.repeated;
switch (field.kind) {
case "scalar":
case "enum":
let scalarType = field.kind == "enum" ? scalar_js_1.ScalarType.INT32 : field.T;
if (repeated) {
(0, assert_js_1.assert)(Array.isArray(value));
if (field.packed) {
writePacked(writer, scalarType, field.no, value);
}
else {
for (const item of value) {
writeScalar(writer, scalarType, field.no, item);
}
}
}
else {
writeScalar(writer, scalarType, field.no, value);
}
break;
case "message":
if (repeated) {
(0, assert_js_1.assert)(Array.isArray(value));
for (const item of value) {
writeMessageField(writer, options, field, item);
}
}
else {
writeMessageField(writer, options, field, value);
}
break;
case "map":
(0, assert_js_1.assert)(typeof value == "object" && value != null);
for (const [key, val] of Object.entries(value)) {
writeMapEntry(writer, options, field, key, val);
}
break;
}
}
function writeMapEntry(writer, options, field, key, value) {
writer.tag(field.no, binary_encoding_js_1.WireType.LengthDelimited);
writer.fork();
// javascript only allows number or string for object properties
// we convert from our representation to the protobuf type
let keyValue = key;
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- we deliberately handle just the special cases for map keys
switch (field.K) {
case scalar_js_1.ScalarType.INT32:
case scalar_js_1.ScalarType.FIXED32:
case scalar_js_1.ScalarType.UINT32:
case scalar_js_1.ScalarType.SFIXED32:
case scalar_js_1.ScalarType.SINT32:
keyValue = Number.parseInt(key);
break;
case scalar_js_1.ScalarType.BOOL:
(0, assert_js_1.assert)(key == "true" || key == "false");
keyValue = key == "true";
break;
}
// write key, expecting key field number = 1
writeScalar(writer, field.K, 1, keyValue);
// write value, expecting value field number = 2
switch (field.V.kind) {
case "scalar":
writeScalar(writer, field.V.T, 2, value);
break;
case "enum":
writeScalar(writer, scalar_js_1.ScalarType.INT32, 2, value);
break;
case "message":
(0, assert_js_1.assert)(value !== undefined);
writer.tag(2, binary_encoding_js_1.WireType.LengthDelimited).bytes(value.toBinary(options));
break;
}
writer.join();
}
exports.writeMapEntry = writeMapEntry;
// Value must not be undefined
function writeMessageField(writer, options, field, value) {
const message = (0, field_wrapper_js_1.wrapField)(field.T, value);
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (field.delimited)
writer
.tag(field.no, binary_encoding_js_1.WireType.StartGroup)
.raw(message.toBinary(options))
.tag(field.no, binary_encoding_js_1.WireType.EndGroup);
else
writer
.tag(field.no, binary_encoding_js_1.WireType.LengthDelimited)
.bytes(message.toBinary(options));
}
function writeScalar(writer, type, fieldNo, value) {
(0, assert_js_1.assert)(value !== undefined);
let [wireType, method] = scalarTypeInfo(type);
writer.tag(fieldNo, wireType)[method](value);
}
function writePacked(writer, type, fieldNo, value) {
if (!value.length) {
return;
}
writer.tag(fieldNo, binary_encoding_js_1.WireType.LengthDelimited).fork();
let [, method] = scalarTypeInfo(type);
for (let i = 0; i < value.length; i++) {
writer[method](value[i]);
}
writer.join();
}
/**
* Get information for writing a scalar value.
*
* Returns tuple:
* [0]: appropriate WireType
* [1]: name of the appropriate method of IBinaryWriter
* [2]: whether the given value is a default value for proto3 semantics
*
* If argument `value` is omitted, [2] is always false.
*/
// TODO replace call-sites writeScalar() and writePacked(), then remove
function scalarTypeInfo(type) {
let wireType = binary_encoding_js_1.WireType.Varint;
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- INT32, UINT32, SINT32 are covered by the defaults
switch (type) {
case scalar_js_1.ScalarType.BYTES:
case scalar_js_1.ScalarType.STRING:
wireType = binary_encoding_js_1.WireType.LengthDelimited;
break;
case scalar_js_1.ScalarType.DOUBLE:
case scalar_js_1.ScalarType.FIXED64:
case scalar_js_1.ScalarType.SFIXED64:
wireType = binary_encoding_js_1.WireType.Bit64;
break;
case scalar_js_1.ScalarType.FIXED32:
case scalar_js_1.ScalarType.SFIXED32:
case scalar_js_1.ScalarType.FLOAT:
wireType = binary_encoding_js_1.WireType.Bit32;
break;
}
const method = scalar_js_1.ScalarType[type].toLowerCase();
return [wireType, method];
}
+27
View File
@@ -0,0 +1,27 @@
import type { EnumType, EnumValueInfo } from "../enum.js";
/**
* Represents a generated enum.
*/
export interface EnumObject {
[key: number]: string;
[k: string]: number | string;
}
/**
* Get reflection information from a generated enum.
* If this function is called on something other than a generated
* enum, it raises an error.
*/
export declare function getEnumType(enumObject: EnumObject): EnumType;
/**
* Sets reflection information on a generated enum.
*/
export declare function setEnumType(enumObject: EnumObject, typeName: string, values: Omit<EnumValueInfo, "localName">[], opt?: {}): void;
/**
* Create a new EnumType with the given values.
*/
export declare function makeEnumType(typeName: string, values: (EnumValueInfo | Omit<EnumValueInfo, "localName">)[], _opt?: {}): EnumType;
/**
* Create a new enum object with the given values.
* Sets reflection information.
*/
export declare function makeEnum(typeName: string, values: (EnumValueInfo | Omit<EnumValueInfo, "localName">)[], opt?: {}): EnumObject;
+94
View File
@@ -0,0 +1,94 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeEnum = exports.makeEnumType = exports.setEnumType = exports.getEnumType = void 0;
const assert_js_1 = require("./assert.js");
const enumTypeSymbol = Symbol("@bufbuild/protobuf/enum-type");
/**
* Get reflection information from a generated enum.
* If this function is called on something other than a generated
* enum, it raises an error.
*/
function getEnumType(enumObject) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any
const t = enumObject[enumTypeSymbol];
(0, assert_js_1.assert)(t, "missing enum type on enum object");
return t; // eslint-disable-line @typescript-eslint/no-unsafe-return
}
exports.getEnumType = getEnumType;
/**
* Sets reflection information on a generated enum.
*/
function setEnumType(enumObject, typeName, values, opt) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
enumObject[enumTypeSymbol] = makeEnumType(typeName, values.map((v) => ({
no: v.no,
name: v.name,
localName: enumObject[v.no],
})), opt);
}
exports.setEnumType = setEnumType;
/**
* Create a new EnumType with the given values.
*/
function makeEnumType(typeName, values,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_opt) {
const names = Object.create(null);
const numbers = Object.create(null);
const normalValues = [];
for (const value of values) {
// We do not surface options at this time
// const value: EnumValueInfo = {...v, options: v.options ?? emptyReadonlyObject};
const n = normalizeEnumValue(value);
normalValues.push(n);
names[value.name] = n;
numbers[value.no] = n;
}
return {
typeName,
values: normalValues,
// We do not surface options at this time
// options: opt?.options ?? Object.create(null),
findName(name) {
return names[name];
},
findNumber(no) {
return numbers[no];
},
};
}
exports.makeEnumType = makeEnumType;
/**
* Create a new enum object with the given values.
* Sets reflection information.
*/
function makeEnum(typeName, values, opt) {
const enumObject = {};
for (const value of values) {
const n = normalizeEnumValue(value);
enumObject[n.localName] = n.no;
enumObject[n.no] = n.localName;
}
setEnumType(enumObject, typeName, values, opt);
return enumObject;
}
exports.makeEnum = makeEnum;
function normalizeEnumValue(value) {
if ("localName" in value) {
return value;
}
return Object.assign(Object.assign({}, value), { localName: value.name });
}
+34
View File
@@ -0,0 +1,34 @@
import type { Extension } from "../extension.js";
import type { AnyMessage, Message } from "../message.js";
import type { FieldInfo, OneofInfo, PartialFieldInfo } from "../field.js";
import { WireType } from "../binary-encoding.js";
import type { ProtoRuntime } from "./proto-runtime.js";
import type { MessageType } from "../message-type.js";
export type ExtensionFieldSource = extensionFieldRules<FieldInfo> | extensionFieldRules<PartialFieldInfo> | (() => extensionFieldRules<FieldInfo>) | (() => extensionFieldRules<PartialFieldInfo>);
type extensionFieldRules<T extends FieldInfo | PartialFieldInfo> = T extends {
kind: "map";
} ? never : T extends {
oneof: string;
} ? never : T extends {
oneof: OneofInfo;
} ? never : Omit<T, "name"> & Partial<Pick<T, "name">>;
/**
* Create a new extension using the given runtime.
*/
export declare function makeExtension<E extends Message<E> = AnyMessage, V = unknown>(runtime: ProtoRuntime, typeName: string, extendee: MessageType<E>, field: ExtensionFieldSource): Extension<E, V>;
/**
* Create a container that allows us to read extension fields into it with the
* same logic as regular fields.
*/
export declare function createExtensionContainer<E extends Message<E> = AnyMessage, V = unknown>(extension: Extension<E, V>): [Record<string, V>, () => V];
type UnknownField = {
no: number;
wireType: WireType;
data: Uint8Array;
};
type UnknownFields = ReadonlyArray<UnknownField>;
/**
* Helper to filter unknown fields, optimized based on field type.
*/
export declare function filterUnknownFields(unknownFields: UnknownFields, field: Pick<FieldInfo, "no" | "kind" | "repeated">): UnknownField[];
export {};
+86
View File
@@ -0,0 +1,86 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterUnknownFields = exports.createExtensionContainer = exports.makeExtension = void 0;
const scalars_js_1 = require("./scalars.js");
/**
* Create a new extension using the given runtime.
*/
function makeExtension(runtime, typeName, extendee, field) {
let fi;
return {
typeName,
extendee,
get field() {
if (!fi) {
const i = (typeof field == "function" ? field() : field);
i.name = typeName.split(".").pop();
i.jsonName = `[${typeName}]`;
fi = runtime.util.newFieldList([i]).list()[0];
}
return fi;
},
runtime,
};
}
exports.makeExtension = makeExtension;
/**
* Create a container that allows us to read extension fields into it with the
* same logic as regular fields.
*/
function createExtensionContainer(extension) {
const localName = extension.field.localName;
const container = Object.create(null);
container[localName] = initExtensionField(extension);
return [container, () => container[localName]];
}
exports.createExtensionContainer = createExtensionContainer;
function initExtensionField(ext) {
const field = ext.field;
if (field.repeated) {
return [];
}
if (field.default !== undefined) {
return field.default;
}
switch (field.kind) {
case "enum":
return field.T.values[0].no;
case "scalar":
return (0, scalars_js_1.scalarZeroValue)(field.T, field.L);
case "message":
// eslint-disable-next-line no-case-declarations
const T = field.T, value = new T();
return T.fieldWrapper ? T.fieldWrapper.unwrapField(value) : value;
case "map":
throw "map fields are not allowed to be extensions";
}
}
/**
* Helper to filter unknown fields, optimized based on field type.
*/
function filterUnknownFields(unknownFields, field) {
if (!field.repeated && (field.kind == "enum" || field.kind == "scalar")) {
// singular scalar fields do not merge, we pick the last
for (let i = unknownFields.length - 1; i >= 0; --i) {
if (unknownFields[i].no == field.no) {
return [unknownFields[i]];
}
}
return [];
}
return unknownFields.filter((uf) => uf.no === field.no);
}
exports.filterUnknownFields = filterUnknownFields;
+19
View File
@@ -0,0 +1,19 @@
import { Edition, FeatureSet, FeatureSetDefaults } from "../google/protobuf/descriptor_pb.js";
import type { BinaryReadOptions, BinaryWriteOptions } from "../binary-format.js";
/**
* A merged google.protobuf.FeaturesSet, with all fields guaranteed to be set.
*/
export type MergedFeatureSet = FeatureSet & Required<FeatureSet>;
/**
* A function that resolves features.
*
* If no feature set is provided, the default feature set for the edition is
* returned. If features are provided, they are merged into the edition default
* features.
*/
export type FeatureResolverFn = (a?: FeatureSet, b?: FeatureSet) => MergedFeatureSet;
/**
* Create an edition feature resolver with the given feature set defaults, or
* the feature set defaults supported by @bufbuild/protobuf.
*/
export declare function createFeatureResolver(edition: Edition, compiledFeatureSetDefaults?: FeatureSetDefaults, serializationOptions?: Partial<BinaryReadOptions & BinaryWriteOptions>): FeatureResolverFn;
+120
View File
@@ -0,0 +1,120 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFeatureResolver = void 0;
const descriptor_pb_js_1 = require("../google/protobuf/descriptor_pb.js");
const proto_base64_js_1 = require("../proto-base64.js");
/**
* Return the edition feature defaults supported by @bufbuild/protobuf.
*/
function getFeatureSetDefaults(options) {
return descriptor_pb_js_1.FeatureSetDefaults.fromBinary(proto_base64_js_1.protoBase64.dec(
/*upstream-inject-feature-defaults-start*/ "ChMY5gciACoMCAEQAhgCIAMoATACChMY5wciACoMCAIQARgBIAIoATABChMY6AciDAgBEAEYASACKAEwASoAIOYHKOgH" /*upstream-inject-feature-defaults-end*/), options);
}
/**
* Create an edition feature resolver with the given feature set defaults, or
* the feature set defaults supported by @bufbuild/protobuf.
*/
function createFeatureResolver(edition, compiledFeatureSetDefaults, serializationOptions) {
var _a;
const fds = compiledFeatureSetDefaults !== null && compiledFeatureSetDefaults !== void 0 ? compiledFeatureSetDefaults : getFeatureSetDefaults(serializationOptions);
const min = fds.minimumEdition;
const max = fds.maximumEdition;
if (min === undefined ||
max === undefined ||
fds.defaults.some((d) => d.edition === undefined)) {
throw new Error("Invalid FeatureSetDefaults");
}
if (edition < min) {
throw new Error(`Edition ${descriptor_pb_js_1.Edition[edition]} is earlier than the minimum supported edition ${descriptor_pb_js_1.Edition[min]}`);
}
if (max < edition) {
throw new Error(`Edition ${descriptor_pb_js_1.Edition[edition]} is later than the maximum supported edition ${descriptor_pb_js_1.Edition[max]}`);
}
let highestMatch = undefined;
for (const c of fds.defaults) {
const e = (_a = c.edition) !== null && _a !== void 0 ? _a : 0;
if (e > edition) {
continue;
}
if (highestMatch !== undefined && highestMatch.e > e) {
continue;
}
let f;
if (c.fixedFeatures && c.overridableFeatures) {
f = c.fixedFeatures;
f.fromBinary(c.overridableFeatures.toBinary());
}
else if (c.fixedFeatures) {
f = c.fixedFeatures;
}
else if (c.overridableFeatures) {
f = c.overridableFeatures;
}
else {
f = new descriptor_pb_js_1.FeatureSet();
}
highestMatch = {
e,
f,
};
}
if (highestMatch === undefined) {
throw new Error(`No valid default found for edition ${descriptor_pb_js_1.Edition[edition]}`);
}
const featureSetBin = highestMatch.f.toBinary(serializationOptions);
return (...rest) => {
const f = descriptor_pb_js_1.FeatureSet.fromBinary(featureSetBin, serializationOptions);
for (const c of rest) {
if (c !== undefined) {
f.fromBinary(c.toBinary(serializationOptions), serializationOptions);
}
}
if (!validateMergedFeatures(f)) {
throw new Error(`Invalid FeatureSet for edition ${descriptor_pb_js_1.Edition[edition]}`);
}
return f;
};
}
exports.createFeatureResolver = createFeatureResolver;
// When protoc generates google.protobuf.FeatureSetDefaults, it ensures that
// fields are not repeated or required, do not use oneof, and have a default
// value.
//
// When features for an element are resolved, features of the element and its
// parents are merged into the default FeatureSet for the edition. Because unset
// fields in the FeatureSet of an element do not unset the default FeatureSet
// values, a resolved FeatureSet is guaranteed to have all fields set. This is
// also the case for extensions to FeatureSet that a user might provide, and for
// features from the future.
//
// We cannot exhaustively validate correctness of FeatureSetDefaults at runtime
// without knowing the schema: If no value for a feature is provided, we do not
// know that it exists at all.
//
// As a sanity check, we validate that all fields known to our version of
// FeatureSet are set.
function validateMergedFeatures(featureSet) {
for (const fi of descriptor_pb_js_1.FeatureSet.fields.list()) {
const v = featureSet[fi.localName];
if (v === undefined) {
return false;
}
if (fi.kind == "enum" && v === 0) {
return false;
}
}
return true;
}
+18
View File
@@ -0,0 +1,18 @@
import type { FieldInfo, OneofInfo, PartialFieldInfo } from "../field.js";
import type { FieldList } from "../field-list.js";
export type FieldListSource = readonly PartialFieldInfo[] | readonly FieldInfo[] | (() => readonly PartialFieldInfo[]) | (() => readonly FieldInfo[]);
export declare class InternalFieldList implements FieldList {
private readonly _fields;
private readonly _normalizer;
private all?;
private numbersAsc?;
private jsonNames?;
private numbers?;
private members?;
constructor(fields: FieldListSource, normalizer: (p: FieldListSource) => FieldInfo[]);
findJsonName(jsonName: string): FieldInfo | undefined;
find(fieldNo: number): FieldInfo | undefined;
list(): readonly FieldInfo[];
byNumber(): readonly FieldInfo[];
byMember(): readonly (FieldInfo | OneofInfo)[];
}
+76
View File
@@ -0,0 +1,76 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.InternalFieldList = void 0;
class InternalFieldList {
constructor(fields, normalizer) {
this._fields = fields;
this._normalizer = normalizer;
}
findJsonName(jsonName) {
if (!this.jsonNames) {
const t = {};
for (const f of this.list()) {
t[f.jsonName] = t[f.name] = f;
}
this.jsonNames = t;
}
return this.jsonNames[jsonName];
}
find(fieldNo) {
if (!this.numbers) {
const t = {};
for (const f of this.list()) {
t[f.no] = f;
}
this.numbers = t;
}
return this.numbers[fieldNo];
}
list() {
if (!this.all) {
this.all = this._normalizer(this._fields);
}
return this.all;
}
byNumber() {
if (!this.numbersAsc) {
this.numbersAsc = this.list()
.concat()
.sort((a, b) => a.no - b.no);
}
return this.numbersAsc;
}
byMember() {
if (!this.members) {
this.members = [];
const a = this.members;
let o;
for (const f of this.list()) {
if (f.oneof) {
if (f.oneof !== o) {
o = f.oneof;
a.push(o);
}
}
else {
a.push(f);
}
}
}
return this.members;
}
}
exports.InternalFieldList = InternalFieldList;
@@ -0,0 +1,9 @@
import type { FieldListSource } from "./field-list.js";
import type { FieldInfo } from "../field.js";
/**
* Convert a collection of field info to an array of normalized FieldInfo.
*
* The argument `packedByDefault` specifies whether fields that do not specify
* `packed` should be packed (proto3) or unpacked (proto2).
*/
export declare function normalizeFieldInfos(fieldInfos: FieldListSource, packedByDefault: boolean): FieldInfo[];
+69
View File
@@ -0,0 +1,69 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeFieldInfos = void 0;
const field_js_1 = require("./field.js");
const names_js_1 = require("./names.js");
const scalar_js_1 = require("../scalar.js");
/**
* Convert a collection of field info to an array of normalized FieldInfo.
*
* The argument `packedByDefault` specifies whether fields that do not specify
* `packed` should be packed (proto3) or unpacked (proto2).
*/
function normalizeFieldInfos(fieldInfos, packedByDefault) {
var _a, _b, _c, _d, _e, _f;
const r = [];
let o;
for (const field of typeof fieldInfos == "function"
? fieldInfos()
: fieldInfos) {
const f = field;
f.localName = (0, names_js_1.localFieldName)(field.name, field.oneof !== undefined);
f.jsonName = (_a = field.jsonName) !== null && _a !== void 0 ? _a : (0, names_js_1.fieldJsonName)(field.name);
f.repeated = (_b = field.repeated) !== null && _b !== void 0 ? _b : false;
if (field.kind == "scalar") {
f.L = (_c = field.L) !== null && _c !== void 0 ? _c : scalar_js_1.LongType.BIGINT;
}
f.delimited = (_d = field.delimited) !== null && _d !== void 0 ? _d : false;
f.req = (_e = field.req) !== null && _e !== void 0 ? _e : false;
f.opt = (_f = field.opt) !== null && _f !== void 0 ? _f : false;
if (field.packed === undefined) {
if (packedByDefault) {
f.packed =
field.kind == "enum" ||
(field.kind == "scalar" &&
field.T != scalar_js_1.ScalarType.BYTES &&
field.T != scalar_js_1.ScalarType.STRING);
}
else {
f.packed = false;
}
}
// We do not surface options at this time
// f.options = field.options ?? emptyReadonlyObject;
if (field.oneof !== undefined) {
const ooname = typeof field.oneof == "string" ? field.oneof : field.oneof.name;
if (!o || o.name != ooname) {
o = new field_js_1.InternalOneofInfo(ooname);
}
f.oneof = o;
o.addField(f);
}
r.push(f);
}
return r;
}
exports.normalizeFieldInfos = normalizeFieldInfos;
+25
View File
@@ -0,0 +1,25 @@
import { Message } from "../message.js";
import type { MessageType } from "../message-type.js";
import type { DescExtension, DescField } from "../descriptor-set.js";
import { ScalarType } from "../scalar.js";
/**
* A field wrapper unwraps a message to a primitive value that is more
* ergonomic for use as a message field.
*
* Note that this feature exists for google/protobuf/wrappers.proto
* and cannot be used to arbitrarily modify types in generated code.
*/
export interface FieldWrapper<T extends Message<T> = any, U = any> {
wrapField(value: U): T;
unwrapField(value: T): U;
}
/**
* Wrap a primitive message field value in its corresponding wrapper
* message. This function is idempotent.
*/
export declare function wrapField<T extends Message<T>>(type: MessageType<T>, value: any): T;
/**
* If the given field uses one of the well-known wrapper types, return
* the primitive type it wraps.
*/
export declare function getUnwrappedFieldType(field: DescField | DescExtension): ScalarType | undefined;
+57
View File
@@ -0,0 +1,57 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUnwrappedFieldType = exports.wrapField = void 0;
const scalar_js_1 = require("../scalar.js");
const is_message_js_1 = require("../is-message.js");
/**
* Wrap a primitive message field value in its corresponding wrapper
* message. This function is idempotent.
*/
function wrapField(type, value) {
if ((0, is_message_js_1.isMessage)(value) || !type.fieldWrapper) {
return value;
}
return type.fieldWrapper.wrapField(value);
}
exports.wrapField = wrapField;
/**
* If the given field uses one of the well-known wrapper types, return
* the primitive type it wraps.
*/
function getUnwrappedFieldType(field) {
if (field.fieldKind !== "message") {
return undefined;
}
if (field.repeated) {
return undefined;
}
if (field.oneof != undefined) {
return undefined;
}
return wktWrapperToScalarType[field.message.typeName];
}
exports.getUnwrappedFieldType = getUnwrappedFieldType;
const wktWrapperToScalarType = {
"google.protobuf.DoubleValue": scalar_js_1.ScalarType.DOUBLE,
"google.protobuf.FloatValue": scalar_js_1.ScalarType.FLOAT,
"google.protobuf.Int64Value": scalar_js_1.ScalarType.INT64,
"google.protobuf.UInt64Value": scalar_js_1.ScalarType.UINT64,
"google.protobuf.Int32Value": scalar_js_1.ScalarType.INT32,
"google.protobuf.UInt32Value": scalar_js_1.ScalarType.UINT32,
"google.protobuf.BoolValue": scalar_js_1.ScalarType.BOOL,
"google.protobuf.StringValue": scalar_js_1.ScalarType.STRING,
"google.protobuf.BytesValue": scalar_js_1.ScalarType.BYTES,
};
+16
View File
@@ -0,0 +1,16 @@
import type { FieldInfo, OneofInfo } from "../field.js";
export declare class InternalOneofInfo implements OneofInfo {
readonly kind = "oneof";
readonly name: string;
readonly localName: string;
readonly repeated = false;
readonly packed = false;
readonly opt = false;
readonly req = false;
readonly default: undefined;
readonly fields: FieldInfo[];
private _lookup?;
constructor(name: string);
addField(field: FieldInfo): void;
findField(localName: string): FieldInfo | undefined;
}
+45
View File
@@ -0,0 +1,45 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.InternalOneofInfo = void 0;
const names_js_1 = require("./names.js");
const assert_js_1 = require("./assert.js");
class InternalOneofInfo {
constructor(name) {
this.kind = "oneof";
this.repeated = false;
this.packed = false;
this.opt = false;
this.req = false;
this.default = undefined;
this.fields = [];
this.name = name;
this.localName = (0, names_js_1.localOneofName)(name);
}
addField(field) {
(0, assert_js_1.assert)(field.oneof === this, `field ${field.name} not one of ${this.name}`);
this.fields.push(field);
}
findField(localName) {
if (!this._lookup) {
this._lookup = Object.create(null);
for (let i = 0; i < this.fields.length; i++) {
this._lookup[this.fields[i].localName] = this.fields[i];
}
}
return this._lookup[localName];
}
}
exports.InternalOneofInfo = InternalOneofInfo;
+2
View File
@@ -0,0 +1,2 @@
import type { JsonFormat } from "../json-format.js";
export declare function makeJsonFormat(): JsonFormat;
+626
View File
@@ -0,0 +1,626 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeJsonFormat = void 0;
const assert_js_1 = require("./assert.js");
const proto_int64_js_1 = require("../proto-int64.js");
const proto_base64_js_1 = require("../proto-base64.js");
const extensions_js_1 = require("./extensions.js");
const extension_accessor_js_1 = require("../extension-accessor.js");
const reflect_js_1 = require("./reflect.js");
const field_wrapper_js_1 = require("./field-wrapper.js");
const scalars_js_1 = require("./scalars.js");
const scalars_js_2 = require("./scalars.js");
const scalar_js_1 = require("../scalar.js");
const is_message_js_1 = require("../is-message.js");
/* eslint-disable no-case-declarations,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */
// Default options for parsing JSON.
const jsonReadDefaults = {
ignoreUnknownFields: false,
};
// Default options for serializing to JSON.
const jsonWriteDefaults = {
emitDefaultValues: false,
enumAsInteger: false,
useProtoFieldName: false,
prettySpaces: 0,
};
function makeReadOptions(options) {
return options ? Object.assign(Object.assign({}, jsonReadDefaults), options) : jsonReadDefaults;
}
function makeWriteOptions(options) {
return options ? Object.assign(Object.assign({}, jsonWriteDefaults), options) : jsonWriteDefaults;
}
const tokenNull = Symbol();
const tokenIgnoredUnknownEnum = Symbol();
function makeJsonFormat() {
return {
makeReadOptions,
makeWriteOptions,
readMessage(type, json, options, message) {
if (json == null || Array.isArray(json) || typeof json != "object") {
throw new Error(`cannot decode message ${type.typeName} from JSON: ${debugJsonValue(json)}`);
}
message = message !== null && message !== void 0 ? message : new type();
const oneofSeen = new Map();
const registry = options.typeRegistry;
for (const [jsonKey, jsonValue] of Object.entries(json)) {
const field = type.fields.findJsonName(jsonKey);
if (field) {
if (field.oneof) {
if (jsonValue === null && field.kind == "scalar") {
// see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
continue;
}
const seen = oneofSeen.get(field.oneof);
if (seen !== undefined) {
throw new Error(`cannot decode message ${type.typeName} from JSON: multiple keys for oneof "${field.oneof.name}" present: "${seen}", "${jsonKey}"`);
}
oneofSeen.set(field.oneof, jsonKey);
}
readField(message, jsonValue, field, options, type);
}
else {
let found = false;
if ((registry === null || registry === void 0 ? void 0 : registry.findExtension) &&
jsonKey.startsWith("[") &&
jsonKey.endsWith("]")) {
const ext = registry.findExtension(jsonKey.substring(1, jsonKey.length - 1));
if (ext && ext.extendee.typeName == type.typeName) {
found = true;
const [container, get] = (0, extensions_js_1.createExtensionContainer)(ext);
readField(container, jsonValue, ext.field, options, ext);
// We pass on the options as BinaryReadOptions/BinaryWriteOptions,
// so that users can bring their own binary reader and writer factories
// if necessary.
(0, extension_accessor_js_1.setExtension)(message, ext, get(), options);
}
}
if (!found && !options.ignoreUnknownFields) {
throw new Error(`cannot decode message ${type.typeName} from JSON: key "${jsonKey}" is unknown`);
}
}
}
return message;
},
writeMessage(message, options) {
const type = message.getType();
const json = {};
let field;
try {
for (field of type.fields.byNumber()) {
if (!(0, reflect_js_1.isFieldSet)(field, message)) {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (field.req) {
throw `required field not set`;
}
if (!options.emitDefaultValues) {
continue;
}
if (!canEmitFieldDefaultValue(field)) {
continue;
}
}
const value = field.oneof
? message[field.oneof.localName].value
: message[field.localName];
const jsonValue = writeField(field, value, options);
if (jsonValue !== undefined) {
json[options.useProtoFieldName ? field.name : field.jsonName] =
jsonValue;
}
}
const registry = options.typeRegistry;
if (registry === null || registry === void 0 ? void 0 : registry.findExtensionFor) {
for (const uf of type.runtime.bin.listUnknownFields(message)) {
const ext = registry.findExtensionFor(type.typeName, uf.no);
if (ext && (0, extension_accessor_js_1.hasExtension)(message, ext)) {
// We pass on the options as BinaryReadOptions, so that users can bring their own
// binary reader factory if necessary.
const value = (0, extension_accessor_js_1.getExtension)(message, ext, options);
const jsonValue = writeField(ext.field, value, options);
if (jsonValue !== undefined) {
json[ext.field.jsonName] = jsonValue;
}
}
}
}
}
catch (e) {
const m = field
? `cannot encode field ${type.typeName}.${field.name} to JSON`
: `cannot encode message ${type.typeName} to JSON`;
const r = e instanceof Error ? e.message : String(e);
throw new Error(m + (r.length > 0 ? `: ${r}` : ""));
}
return json;
},
readScalar(type, json, longType) {
// The signature of our internal function has changed. For backwards-
// compatibility, we support the old form that is part of the public API
// through the interface JsonFormat.
return readScalar(type, json, longType !== null && longType !== void 0 ? longType : scalar_js_1.LongType.BIGINT, true);
},
writeScalar(type, value, emitDefaultValues) {
// The signature of our internal function has changed. For backwards-
// compatibility, we support the old form that is part of the public API
// through the interface JsonFormat.
if (value === undefined) {
return undefined;
}
if (emitDefaultValues || (0, scalars_js_2.isScalarZeroValue)(type, value)) {
return writeScalar(type, value);
}
return undefined;
},
debug: debugJsonValue,
};
}
exports.makeJsonFormat = makeJsonFormat;
function debugJsonValue(json) {
if (json === null) {
return "null";
}
switch (typeof json) {
case "object":
return Array.isArray(json) ? "array" : "object";
case "string":
return json.length > 100 ? "string" : `"${json.split('"').join('\\"')}"`;
default:
return String(json);
}
}
// Read a JSON value for a field.
// The "parentType" argument is only used to provide context in errors.
function readField(target, jsonValue, field, options, parentType) {
let localName = field.localName;
if (field.repeated) {
(0, assert_js_1.assert)(field.kind != "map");
if (jsonValue === null) {
return;
}
if (!Array.isArray(jsonValue)) {
throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
}
const targetArray = target[localName];
for (const jsonItem of jsonValue) {
if (jsonItem === null) {
throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`);
}
switch (field.kind) {
case "message":
targetArray.push(field.T.fromJson(jsonItem, options));
break;
case "enum":
const enumValue = readEnum(field.T, jsonItem, options.ignoreUnknownFields, true);
if (enumValue !== tokenIgnoredUnknownEnum) {
targetArray.push(enumValue);
}
break;
case "scalar":
try {
targetArray.push(readScalar(field.T, jsonItem, field.L, true));
}
catch (e) {
let m = `cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`;
if (e instanceof Error && e.message.length > 0) {
m += `: ${e.message}`;
}
throw new Error(m);
}
break;
}
}
}
else if (field.kind == "map") {
if (jsonValue === null) {
return;
}
if (typeof jsonValue != "object" || Array.isArray(jsonValue)) {
throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
}
const targetMap = target[localName];
for (const [jsonMapKey, jsonMapValue] of Object.entries(jsonValue)) {
if (jsonMapValue === null) {
throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: map value null`);
}
let key;
try {
key = readMapKey(field.K, jsonMapKey);
}
catch (e) {
let m = `cannot decode map key for field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
if (e instanceof Error && e.message.length > 0) {
m += `: ${e.message}`;
}
throw new Error(m);
}
switch (field.V.kind) {
case "message":
targetMap[key] = field.V.T.fromJson(jsonMapValue, options);
break;
case "enum":
const enumValue = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields, true);
if (enumValue !== tokenIgnoredUnknownEnum) {
targetMap[key] = enumValue;
}
break;
case "scalar":
try {
targetMap[key] = readScalar(field.V.T, jsonMapValue, scalar_js_1.LongType.BIGINT, true);
}
catch (e) {
let m = `cannot decode map value for field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
if (e instanceof Error && e.message.length > 0) {
m += `: ${e.message}`;
}
throw new Error(m);
}
break;
}
}
}
else {
if (field.oneof) {
target = target[field.oneof.localName] = { case: localName };
localName = "value";
}
switch (field.kind) {
case "message":
const messageType = field.T;
if (jsonValue === null &&
messageType.typeName != "google.protobuf.Value") {
return;
}
let currentValue = target[localName];
if ((0, is_message_js_1.isMessage)(currentValue)) {
currentValue.fromJson(jsonValue, options);
}
else {
target[localName] = currentValue = messageType.fromJson(jsonValue, options);
if (messageType.fieldWrapper && !field.oneof) {
target[localName] =
messageType.fieldWrapper.unwrapField(currentValue);
}
}
break;
case "enum":
const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields, false);
switch (enumValue) {
case tokenNull:
(0, reflect_js_1.clearField)(field, target);
break;
case tokenIgnoredUnknownEnum:
break;
default:
target[localName] = enumValue;
break;
}
break;
case "scalar":
try {
const scalarValue = readScalar(field.T, jsonValue, field.L, false);
switch (scalarValue) {
case tokenNull:
(0, reflect_js_1.clearField)(field, target);
break;
default:
target[localName] = scalarValue;
break;
}
}
catch (e) {
let m = `cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
if (e instanceof Error && e.message.length > 0) {
m += `: ${e.message}`;
}
throw new Error(m);
}
break;
}
}
}
function readMapKey(type, json) {
if (type === scalar_js_1.ScalarType.BOOL) {
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (json) {
case "true":
json = true;
break;
case "false":
json = false;
break;
}
}
return readScalar(type, json, scalar_js_1.LongType.BIGINT, true).toString();
}
function readScalar(type, json, longType, nullAsZeroValue) {
if (json === null) {
if (nullAsZeroValue) {
return (0, scalars_js_1.scalarZeroValue)(type, longType);
}
return tokenNull;
}
// every valid case in the switch below returns, and every fall
// through is regarded as a failure.
switch (type) {
// 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 scalar_js_1.ScalarType.DOUBLE:
case scalar_js_1.ScalarType.FLOAT:
if (json === "NaN")
return Number.NaN;
if (json === "Infinity")
return Number.POSITIVE_INFINITY;
if (json === "-Infinity")
return Number.NEGATIVE_INFINITY;
if (json === "") {
// empty string is not a number
break;
}
if (typeof json == "string" && json.trim().length !== json.length) {
// extra whitespace
break;
}
if (typeof json != "string" && typeof json != "number") {
break;
}
const float = Number(json);
if (Number.isNaN(float)) {
// not a number
break;
}
if (!Number.isFinite(float)) {
// infinity and -infinity are handled by string representation above, so this is an error
break;
}
if (type == scalar_js_1.ScalarType.FLOAT)
(0, assert_js_1.assertFloat32)(float);
return float;
// int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
case scalar_js_1.ScalarType.INT32:
case scalar_js_1.ScalarType.FIXED32:
case scalar_js_1.ScalarType.SFIXED32:
case scalar_js_1.ScalarType.SINT32:
case scalar_js_1.ScalarType.UINT32:
let int32;
if (typeof json == "number")
int32 = json;
else if (typeof json == "string" && json.length > 0) {
if (json.trim().length === json.length)
int32 = Number(json);
}
if (int32 === undefined)
break;
if (type == scalar_js_1.ScalarType.UINT32 || type == scalar_js_1.ScalarType.FIXED32)
(0, assert_js_1.assertUInt32)(int32);
else
(0, assert_js_1.assertInt32)(int32);
return int32;
// int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted.
case scalar_js_1.ScalarType.INT64:
case scalar_js_1.ScalarType.SFIXED64:
case scalar_js_1.ScalarType.SINT64:
if (typeof json != "number" && typeof json != "string")
break;
const long = proto_int64_js_1.protoInt64.parse(json);
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
return longType ? long.toString() : long;
case scalar_js_1.ScalarType.FIXED64:
case scalar_js_1.ScalarType.UINT64:
if (typeof json != "number" && typeof json != "string")
break;
const uLong = proto_int64_js_1.protoInt64.uParse(json);
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
return longType ? uLong.toString() : uLong;
// bool:
case scalar_js_1.ScalarType.BOOL:
if (typeof json !== "boolean")
break;
return json;
// string:
case scalar_js_1.ScalarType.STRING:
if (typeof json !== "string") {
break;
}
// A string must always contain UTF-8 encoded or 7-bit ASCII.
// We validate with encodeURIComponent, which appears to be the fastest widely available option.
try {
encodeURIComponent(json);
}
catch (e) {
throw new Error("invalid UTF8");
}
return json;
// 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 scalar_js_1.ScalarType.BYTES:
if (json === "")
return new Uint8Array(0);
if (typeof json !== "string")
break;
return proto_base64_js_1.protoBase64.dec(json);
}
throw new Error();
}
function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
if (json === null) {
if (type.typeName == "google.protobuf.NullValue") {
return 0; // google.protobuf.NullValue.NULL_VALUE = 0
}
return nullAsZeroValue ? type.values[0].no : tokenNull;
}
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (typeof json) {
case "number":
if (Number.isInteger(json)) {
return json;
}
break;
case "string":
const value = type.findName(json);
if (value !== undefined) {
return value.no;
}
if (ignoreUnknownFields) {
return tokenIgnoredUnknownEnum;
}
break;
}
throw new Error(`cannot decode enum ${type.typeName} from JSON: ${debugJsonValue(json)}`);
}
// Decide whether an unset field should be emitted with JSON write option `emitDefaultValues`
function canEmitFieldDefaultValue(field) {
if (field.repeated || field.kind == "map") {
// maps are {}, repeated fields are []
return true;
}
if (field.oneof) {
// oneof fields are never emitted
return false;
}
if (field.kind == "message") {
// singular message field are allowed to emit JSON null, but we do not
return false;
}
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (field.opt || field.req) {
// the field uses explicit presence, so we cannot emit a zero value
return false;
}
return true;
}
function writeField(field, value, options) {
if (field.kind == "map") {
(0, assert_js_1.assert)(typeof value == "object" && value != null);
const jsonObj = {};
const entries = Object.entries(value);
switch (field.V.kind) {
case "scalar":
for (const [entryKey, entryValue] of entries) {
jsonObj[entryKey.toString()] = writeScalar(field.V.T, entryValue); // JSON standard allows only (double quoted) string as property key
}
break;
case "message":
for (const [entryKey, entryValue] of entries) {
// JSON standard allows only (double quoted) string as property key
jsonObj[entryKey.toString()] = entryValue.toJson(options);
}
break;
case "enum":
const enumType = field.V.T;
for (const [entryKey, entryValue] of entries) {
// JSON standard allows only (double quoted) string as property key
jsonObj[entryKey.toString()] = writeEnum(enumType, entryValue, options.enumAsInteger);
}
break;
}
return options.emitDefaultValues || entries.length > 0
? jsonObj
: undefined;
}
if (field.repeated) {
(0, assert_js_1.assert)(Array.isArray(value));
const jsonArr = [];
switch (field.kind) {
case "scalar":
for (let i = 0; i < value.length; i++) {
jsonArr.push(writeScalar(field.T, value[i]));
}
break;
case "enum":
for (let i = 0; i < value.length; i++) {
jsonArr.push(writeEnum(field.T, value[i], options.enumAsInteger));
}
break;
case "message":
for (let i = 0; i < value.length; i++) {
jsonArr.push(value[i].toJson(options));
}
break;
}
return options.emitDefaultValues || jsonArr.length > 0
? jsonArr
: undefined;
}
switch (field.kind) {
case "scalar":
return writeScalar(field.T, value);
case "enum":
return writeEnum(field.T, value, options.enumAsInteger);
case "message":
return (0, field_wrapper_js_1.wrapField)(field.T, value).toJson(options);
}
}
function writeEnum(type, value, enumAsInteger) {
var _a;
(0, assert_js_1.assert)(typeof value == "number");
if (type.typeName == "google.protobuf.NullValue") {
return null;
}
if (enumAsInteger) {
return value;
}
const val = type.findNumber(value);
return (_a = val === null || val === void 0 ? void 0 : val.name) !== null && _a !== void 0 ? _a : value; // if we don't know the enum value, just return the number
}
function writeScalar(type, value) {
switch (type) {
// int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
case scalar_js_1.ScalarType.INT32:
case scalar_js_1.ScalarType.SFIXED32:
case scalar_js_1.ScalarType.SINT32:
case scalar_js_1.ScalarType.FIXED32:
case scalar_js_1.ScalarType.UINT32:
(0, assert_js_1.assert)(typeof value == "number");
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 scalar_js_1.ScalarType.FLOAT:
// assertFloat32(value);
case scalar_js_1.ScalarType.DOUBLE: // eslint-disable-line no-fallthrough
(0, assert_js_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 scalar_js_1.ScalarType.STRING:
(0, assert_js_1.assert)(typeof value == "string");
return value;
// bool:
case scalar_js_1.ScalarType.BOOL:
(0, assert_js_1.assert)(typeof value == "boolean");
return value;
// JSON value will be a decimal string. Either numbers or strings are accepted.
case scalar_js_1.ScalarType.UINT64:
case scalar_js_1.ScalarType.FIXED64:
case scalar_js_1.ScalarType.INT64:
case scalar_js_1.ScalarType.SFIXED64:
case scalar_js_1.ScalarType.SINT64:
(0, assert_js_1.assert)(typeof value == "bigint" ||
typeof value == "string" ||
typeof value == "number");
return value.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 scalar_js_1.ScalarType.BYTES:
(0, assert_js_1.assert)(value instanceof Uint8Array);
return proto_base64_js_1.protoBase64.enc(value);
}
}
+18
View File
@@ -0,0 +1,18 @@
import { Message } from "../message.js";
import type { AnyMessage } from "../message.js";
import type { FieldListSource } from "./field-list.js";
import type { MessageType } from "../message-type.js";
import type { ProtoRuntime } from "./proto-runtime.js";
/**
* Create a new message type using the given runtime.
*/
export declare function makeMessageType<T extends Message<T> = AnyMessage>(runtime: ProtoRuntime, typeName: string, fields: FieldListSource, opt?: {
/**
* localName is the "name" property of the constructed function.
* It is useful in stack traces, debuggers and test frameworks,
* but has no other implications.
*
* If omitted, the last part of the typeName is used.
*/
localName?: string;
}): MessageType<T>;
+50
View File
@@ -0,0 +1,50 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeMessageType = void 0;
const message_js_1 = require("../message.js");
/**
* Create a new message type using the given runtime.
*/
function makeMessageType(runtime, typeName, fields, opt) {
var _a;
const localName = (_a = opt === null || opt === void 0 ? void 0 : opt.localName) !== null && _a !== void 0 ? _a : typeName.substring(typeName.lastIndexOf(".") + 1);
const type = {
[localName]: function (data) {
runtime.util.initFields(this);
runtime.util.initPartial(data, this);
},
}[localName];
Object.setPrototypeOf(type.prototype, new message_js_1.Message());
Object.assign(type, {
runtime,
typeName,
fields: runtime.util.newFieldList(fields),
fromBinary(bytes, options) {
return new type().fromBinary(bytes, options);
},
fromJson(jsonValue, options) {
return new type().fromJson(jsonValue, options);
},
fromJsonString(jsonString, options) {
return new type().fromJsonString(jsonString, options);
},
equals(a, b) {
return runtime.util.equals(type, a, b);
},
});
return type;
}
exports.makeMessageType = makeMessageType;
+43
View File
@@ -0,0 +1,43 @@
import type { DescEnum, DescEnumValue, DescExtension, DescField, DescMessage, DescService } from "../descriptor-set.js";
import type { DescMethod, DescOneof } from "../descriptor-set.js";
/**
* Returns the name of a protobuf element in generated code.
*
* Field names - including oneofs - are converted to lowerCamelCase. For
* messages, enumerations and services, the package name is stripped from
* the type name. For nested messages and enumerations, the names are joined
* with an underscore. For methods, the first character is made lowercase.
*/
export declare function localName(desc: DescEnum | DescEnumValue | DescMessage | DescExtension | DescOneof | DescField | DescService | DescMethod): string;
/**
* Returns the name of a field in generated code.
*/
export declare function localFieldName(protoName: string, inOneof: boolean): string;
/**
* Returns the name of a oneof group in generated code.
*/
export declare function localOneofName(protoName: string): string;
/**
* Returns the JSON name for a protobuf field, exactly like protoc does.
*/
export declare const fieldJsonName: typeof protoCamelCase;
/**
* Finds a prefix shared by enum values, for example `MY_ENUM_` for
* `enum MyEnum {MY_ENUM_A=0; MY_ENUM_B=1;}`.
*/
export declare function findEnumSharedPrefix(enumName: string, valueNames: string[]): string | undefined;
/**
* Converts snake_case to protoCamelCase according to the convention
* used by protoc to convert a field name to a JSON name.
*/
declare function protoCamelCase(snakeCase: string): string;
/**
* Names that cannot be used for object properties because they are reserved
* by built-in JavaScript properties.
*/
export declare const safeObjectProperty: (name: string) => string;
/**
* Names that can be used for identifiers or class properties
*/
export declare const safeIdentifier: (name: string) => string;
export {};
+278
View File
@@ -0,0 +1,278 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeIdentifier = exports.safeObjectProperty = exports.findEnumSharedPrefix = exports.fieldJsonName = exports.localOneofName = exports.localFieldName = exports.localName = void 0;
/**
* Returns the name of a protobuf element in generated code.
*
* Field names - including oneofs - are converted to lowerCamelCase. For
* messages, enumerations and services, the package name is stripped from
* the type name. For nested messages and enumerations, the names are joined
* with an underscore. For methods, the first character is made lowercase.
*/
function localName(desc) {
switch (desc.kind) {
case "field":
return localFieldName(desc.name, desc.oneof !== undefined);
case "oneof":
return localOneofName(desc.name);
case "enum":
case "message":
case "service":
case "extension": {
const pkg = desc.file.proto.package;
const offset = pkg === undefined ? 0 : pkg.length + 1;
const name = desc.typeName.substring(offset).replace(/\./g, "_");
// For services, we only care about safe identifiers, not safe object properties,
// but we have shipped v1 with a bug that respected object properties, and we
// do not want to introduce a breaking change, so we continue to escape for
// safe object properties.
// See https://github.com/bufbuild/protobuf-es/pull/391
return (0, exports.safeObjectProperty)((0, exports.safeIdentifier)(name));
}
case "enum_value": {
let name = desc.name;
const sharedPrefix = desc.parent.sharedPrefix;
if (sharedPrefix !== undefined) {
name = name.substring(sharedPrefix.length);
}
return (0, exports.safeObjectProperty)(name);
}
case "rpc": {
let name = desc.name;
if (name.length == 0) {
return name;
}
name = name[0].toLowerCase() + name.substring(1);
return (0, exports.safeObjectProperty)(name);
}
}
}
exports.localName = localName;
/**
* Returns the name of a field in generated code.
*/
function localFieldName(protoName, inOneof) {
const name = protoCamelCase(protoName);
if (inOneof) {
// oneof member names are not properties, but values of the `case` property.
return name;
}
return (0, exports.safeObjectProperty)(safeMessageProperty(name));
}
exports.localFieldName = localFieldName;
/**
* Returns the name of a oneof group in generated code.
*/
function localOneofName(protoName) {
return localFieldName(protoName, false);
}
exports.localOneofName = localOneofName;
/**
* Returns the JSON name for a protobuf field, exactly like protoc does.
*/
exports.fieldJsonName = protoCamelCase;
/**
* Finds a prefix shared by enum values, for example `MY_ENUM_` for
* `enum MyEnum {MY_ENUM_A=0; MY_ENUM_B=1;}`.
*/
function findEnumSharedPrefix(enumName, valueNames) {
const prefix = camelToSnakeCase(enumName) + "_";
for (const name of valueNames) {
if (!name.toLowerCase().startsWith(prefix)) {
return undefined;
}
const shortName = name.substring(prefix.length);
if (shortName.length == 0) {
return undefined;
}
if (/^\d/.test(shortName)) {
// identifiers must not start with numbers
return undefined;
}
}
return prefix;
}
exports.findEnumSharedPrefix = findEnumSharedPrefix;
/**
* Converts lowerCamelCase or UpperCamelCase into lower_snake_case.
* This is used to find shared prefixes in an enum.
*/
function camelToSnakeCase(camel) {
return (camel.substring(0, 1) + camel.substring(1).replace(/[A-Z]/g, (c) => "_" + c)).toLowerCase();
}
/**
* Converts snake_case to protoCamelCase according to the convention
* used by protoc to convert a field name to a JSON name.
*/
function protoCamelCase(snakeCase) {
let capNext = false;
const b = [];
for (let i = 0; i < snakeCase.length; i++) {
let c = snakeCase.charAt(i);
switch (c) {
case "_":
capNext = true;
break;
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
b.push(c);
capNext = false;
break;
default:
if (capNext) {
capNext = false;
c = c.toUpperCase();
}
b.push(c);
break;
}
}
return b.join("");
}
/**
* Names that cannot be used for identifiers, such as class names,
* but _can_ be used for object properties.
*/
const reservedIdentifiers = new Set([
// ECMAScript 2015 keywords
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"export",
"extends",
"false",
"finally",
"for",
"function",
"if",
"import",
"in",
"instanceof",
"new",
"null",
"return",
"super",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
"yield",
// ECMAScript 2015 future reserved keywords
"enum",
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
// Class name cannot be 'Object' when targeting ES5 with module CommonJS
"Object",
// TypeScript keywords that cannot be used for types (as opposed to variables)
"bigint",
"number",
"boolean",
"string",
"object",
// Identifiers reserved for the runtime, so we can generate legible code
"globalThis",
"Uint8Array",
"Partial",
]);
/**
* Names that cannot be used for object properties because they are reserved
* by built-in JavaScript properties.
*/
const reservedObjectProperties = new Set([
// names reserved by JavaScript
"constructor",
"toString",
"toJSON",
"valueOf",
]);
/**
* Names that cannot be used for object properties because they are reserved
* by the runtime.
*/
const reservedMessageProperties = new Set([
// names reserved by the runtime
"getType",
"clone",
"equals",
"fromBinary",
"fromJson",
"fromJsonString",
"toBinary",
"toJson",
"toJsonString",
// names reserved by the runtime for the future
"toObject",
]);
const fallback = (name) => `${name}$`;
/**
* Will wrap names that are Object prototype properties or names reserved
* for `Message`s.
*/
const safeMessageProperty = (name) => {
if (reservedMessageProperties.has(name)) {
return fallback(name);
}
return name;
};
/**
* Names that cannot be used for object properties because they are reserved
* by built-in JavaScript properties.
*/
const safeObjectProperty = (name) => {
if (reservedObjectProperties.has(name)) {
return fallback(name);
}
return name;
};
exports.safeObjectProperty = safeObjectProperty;
/**
* Names that can be used for identifiers or class properties
*/
const safeIdentifier = (name) => {
if (reservedIdentifiers.has(name)) {
return fallback(name);
}
return name;
};
exports.safeIdentifier = safeIdentifier;
+7
View File
@@ -0,0 +1,7 @@
import type { JsonValue } from "../json-format.js";
/**
*
*/
export type OptionsMap = {
readonly [extensionName: string]: JsonValue;
};
+15
View File
@@ -0,0 +1,15 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
+53
View File
@@ -0,0 +1,53 @@
import type { JsonFormat } from "../json-format.js";
import type { BinaryFormat } from "../binary-format.js";
import type { AnyMessage } from "../message.js";
import type { Message } from "../message.js";
import type { EnumType, EnumValueInfo } from "../enum.js";
import type { MessageType } from "../message-type.js";
import type { FieldListSource } from "./field-list.js";
import type { EnumObject } from "./enum.js";
import type { Util } from "./util.js";
import type { Extension } from "../extension.js";
import type { ExtensionFieldSource } from "./extensions.js";
/**
* A facade that provides serialization and other internal functionality.
*/
export interface ProtoRuntime {
readonly syntax: string;
readonly json: JsonFormat;
readonly bin: BinaryFormat;
readonly util: Util;
/**
* Create a message type at runtime, without generating code.
*/
makeMessageType<T extends Message<T> = AnyMessage>(typeName: string, fields: FieldListSource, opt?: {
localName?: string;
}): MessageType<T>;
/**
* Create an enum object at runtime, without generating code.
*
* The object conforms to TypeScript enums, and comes with
* mapping from name to value, and from value to name.
*
* The type name and other reflection information is accessible
* via getEnumType().
*/
makeEnum(typeName: string, values: (EnumValueInfo | Omit<EnumValueInfo, "localName">)[], opt?: {}): EnumObject;
/**
* Create an enum type at runtime, without generating code.
* Note that this only creates the reflection information, not an
* actual enum object.
*/
makeEnumType(typeName: string, values: (EnumValueInfo | Omit<EnumValueInfo, "localName">)[], opt?: {}): EnumType;
/**
* Get reflection information - the EnumType - from an enum object.
* If this function is called on something other than a generated
* enum, or an enum constructed with makeEnum(), it raises an error.
*/
getEnumType(enumObject: EnumObject): EnumType;
/**
* Create an extension at runtime, without generating code.
*/
makeExtension<E extends Message<E> = AnyMessage, V = unknown>(typeName: string, extendee: MessageType<E>, field: ExtensionFieldSource): Extension<E, V>;
}
export declare function makeProtoRuntime(syntax: string, newFieldList: Util["newFieldList"], initFields: Util["initFields"]): ProtoRuntime;
+41
View File
@@ -0,0 +1,41 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeProtoRuntime = void 0;
const enum_js_1 = require("./enum.js");
const message_type_js_1 = require("./message-type.js");
const extensions_js_1 = require("./extensions.js");
const json_format_js_1 = require("./json-format.js");
const binary_format_js_1 = require("./binary-format.js");
const util_common_js_1 = require("./util-common.js");
function makeProtoRuntime(syntax, newFieldList, initFields) {
return {
syntax,
json: (0, json_format_js_1.makeJsonFormat)(),
bin: (0, binary_format_js_1.makeBinaryFormat)(),
util: Object.assign(Object.assign({}, (0, util_common_js_1.makeUtilCommon)()), { newFieldList,
initFields }),
makeMessageType(typeName, fields, opt) {
return (0, message_type_js_1.makeMessageType)(this, typeName, fields, opt);
},
makeEnum: enum_js_1.makeEnum,
makeEnumType: enum_js_1.makeEnumType,
getEnumType: enum_js_1.getEnumType,
makeExtension(typeName, extendee, field) {
return (0, extensions_js_1.makeExtension)(this, typeName, extendee, field);
},
};
}
exports.makeProtoRuntime = makeProtoRuntime;
+9
View File
@@ -0,0 +1,9 @@
import type { FieldInfo } from "../field.js";
/**
* Returns true if the field is set.
*/
export declare function isFieldSet(field: FieldInfo, target: Record<string, any>): boolean;
/**
* Resets the field, so that isFieldSet() will return false.
*/
export declare function clearField(field: FieldInfo, target: Record<string, any>): void;
+79
View File
@@ -0,0 +1,79 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearField = exports.isFieldSet = void 0;
const scalars_js_1 = require("./scalars.js");
/**
* Returns true if the field is set.
*/
function isFieldSet(field, target) {
const localName = field.localName;
if (field.repeated) {
return target[localName].length > 0;
}
if (field.oneof) {
return target[field.oneof.localName].case === localName; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
}
switch (field.kind) {
case "enum":
case "scalar":
if (field.opt || field.req) {
// explicit presence
return target[localName] !== undefined;
}
// implicit presence
if (field.kind == "enum") {
return target[localName] !== field.T.values[0].no;
}
return !(0, scalars_js_1.isScalarZeroValue)(field.T, target[localName]);
case "message":
return target[localName] !== undefined;
case "map":
return Object.keys(target[localName]).length > 0; // eslint-disable-line @typescript-eslint/no-unsafe-argument
}
}
exports.isFieldSet = isFieldSet;
/**
* Resets the field, so that isFieldSet() will return false.
*/
function clearField(field, target) {
const localName = field.localName;
const implicitPresence = !field.opt && !field.req;
if (field.repeated) {
target[localName] = [];
}
else if (field.oneof) {
target[field.oneof.localName] = { case: undefined };
}
else {
switch (field.kind) {
case "map":
target[localName] = {};
break;
case "enum":
target[localName] = implicitPresence ? field.T.values[0].no : undefined;
break;
case "scalar":
target[localName] = implicitPresence
? (0, scalars_js_1.scalarZeroValue)(field.T, field.L)
: undefined;
break;
case "message":
target[localName] = undefined;
break;
}
}
}
exports.clearField = clearField;
+102
View File
@@ -0,0 +1,102 @@
import type { DescField, DescMessage, DescOneof } from "../descriptor-set.js";
type DescWkt = {
typeName: "google.protobuf.Any";
typeUrl: DescField;
value: DescField;
} | {
typeName: "google.protobuf.Timestamp";
seconds: DescField;
nanos: DescField;
} | {
typeName: "google.protobuf.Duration";
seconds: DescField;
nanos: DescField;
} | {
typeName: "google.protobuf.Struct";
fields: DescField & {
fieldKind: "map";
};
} | {
typeName: "google.protobuf.Value";
kind: DescOneof;
nullValue: DescField & {
fieldKind: "enum";
};
numberValue: DescField;
stringValue: DescField;
boolValue: DescField;
structValue: DescField & {
fieldKind: "message";
};
listValue: DescField & {
fieldKind: "message";
};
} | {
typeName: "google.protobuf.ListValue";
values: DescField & {
fieldKind: "message";
};
} | {
typeName: "google.protobuf.FieldMask";
paths: DescField;
} | {
typeName: "google.protobuf.DoubleValue";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.FloatValue";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.Int64Value";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.UInt64Value";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.Int32Value";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.UInt32Value";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.BoolValue";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.StringValue";
value: DescField & {
fieldKind: "scalar";
};
} | {
typeName: "google.protobuf.BytesValue";
value: DescField & {
fieldKind: "scalar";
};
};
/**
* @deprecated please use reifyWkt from @bufbuild/protoplugin/ecmascript instead
*
* Reifies a given DescMessage into a more concrete object representing its
* respective well-known type. The returned object will contain properties
* representing the WKT's defined fields.
*
* Useful during code generation when immediate access to a particular field
* is needed without having to search the object's typename and DescField list.
*
* Returns undefined if the WKT cannot be completely constructed via the
* DescMessage.
*/
export declare function reifyWkt(message: DescMessage): DescWkt | undefined;
export {};
+172
View File
@@ -0,0 +1,172 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.reifyWkt = void 0;
const scalar_js_1 = require("../scalar.js");
/**
* @deprecated please use reifyWkt from @bufbuild/protoplugin/ecmascript instead
*
* Reifies a given DescMessage into a more concrete object representing its
* respective well-known type. The returned object will contain properties
* representing the WKT's defined fields.
*
* Useful during code generation when immediate access to a particular field
* is needed without having to search the object's typename and DescField list.
*
* Returns undefined if the WKT cannot be completely constructed via the
* DescMessage.
*/
function reifyWkt(message) {
switch (message.typeName) {
case "google.protobuf.Any": {
const typeUrl = message.fields.find((f) => f.number == 1 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.STRING);
const value = message.fields.find((f) => f.number == 2 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.BYTES);
if (typeUrl && value) {
return {
typeName: message.typeName,
typeUrl,
value,
};
}
break;
}
case "google.protobuf.Timestamp": {
const seconds = message.fields.find((f) => f.number == 1 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.INT64);
const nanos = message.fields.find((f) => f.number == 2 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.INT32);
if (seconds && nanos) {
return {
typeName: message.typeName,
seconds,
nanos,
};
}
break;
}
case "google.protobuf.Duration": {
const seconds = message.fields.find((f) => f.number == 1 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.INT64);
const nanos = message.fields.find((f) => f.number == 2 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.INT32);
if (seconds && nanos) {
return {
typeName: message.typeName,
seconds,
nanos,
};
}
break;
}
case "google.protobuf.Struct": {
const fields = message.fields.find((f) => f.number == 1 && !f.repeated);
if ((fields === null || fields === void 0 ? void 0 : fields.fieldKind) !== "map" ||
fields.mapValue.kind !== "message" ||
fields.mapValue.message.typeName !== "google.protobuf.Value") {
break;
}
return { typeName: message.typeName, fields };
}
case "google.protobuf.Value": {
const kind = message.oneofs.find((o) => o.name === "kind");
const nullValue = message.fields.find((f) => f.number == 1 && f.oneof === kind);
if ((nullValue === null || nullValue === void 0 ? void 0 : nullValue.fieldKind) !== "enum" ||
nullValue.enum.typeName !== "google.protobuf.NullValue") {
return undefined;
}
const numberValue = message.fields.find((f) => f.number == 2 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.DOUBLE &&
f.oneof === kind);
const stringValue = message.fields.find((f) => f.number == 3 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.STRING &&
f.oneof === kind);
const boolValue = message.fields.find((f) => f.number == 4 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.BOOL &&
f.oneof === kind);
const structValue = message.fields.find((f) => f.number == 5 && f.oneof === kind);
if ((structValue === null || structValue === void 0 ? void 0 : structValue.fieldKind) !== "message" ||
structValue.message.typeName !== "google.protobuf.Struct") {
return undefined;
}
const listValue = message.fields.find((f) => f.number == 6 && f.oneof === kind);
if ((listValue === null || listValue === void 0 ? void 0 : listValue.fieldKind) !== "message" ||
listValue.message.typeName !== "google.protobuf.ListValue") {
return undefined;
}
if (kind && numberValue && stringValue && boolValue) {
return {
typeName: message.typeName,
kind,
nullValue,
numberValue,
stringValue,
boolValue,
structValue,
listValue,
};
}
break;
}
case "google.protobuf.ListValue": {
const values = message.fields.find((f) => f.number == 1 && f.repeated);
if ((values === null || values === void 0 ? void 0 : values.fieldKind) != "message" ||
values.message.typeName !== "google.protobuf.Value") {
break;
}
return { typeName: message.typeName, values };
}
case "google.protobuf.FieldMask": {
const paths = message.fields.find((f) => f.number == 1 &&
f.fieldKind == "scalar" &&
f.scalar === scalar_js_1.ScalarType.STRING &&
f.repeated);
if (paths) {
return { typeName: message.typeName, paths };
}
break;
}
case "google.protobuf.DoubleValue":
case "google.protobuf.FloatValue":
case "google.protobuf.Int64Value":
case "google.protobuf.UInt64Value":
case "google.protobuf.Int32Value":
case "google.protobuf.UInt32Value":
case "google.protobuf.BoolValue":
case "google.protobuf.StringValue":
case "google.protobuf.BytesValue": {
const value = message.fields.find((f) => f.number == 1 && f.name == "value");
if (!value) {
break;
}
if (value.fieldKind !== "scalar") {
break;
}
return { typeName: message.typeName, value };
}
}
return undefined;
}
exports.reifyWkt = reifyWkt;
+18
View File
@@ -0,0 +1,18 @@
import { LongType, ScalarType } from "../scalar.js";
import type { ScalarValue } from "../scalar.js";
/**
* Returns true if both scalar values are equal.
*/
export declare function scalarEquals(type: ScalarType, a: string | boolean | number | bigint | Uint8Array | undefined, b: string | boolean | number | bigint | Uint8Array | undefined): boolean;
/**
* Returns the zero value for the given scalar type.
*/
export declare function scalarZeroValue<T extends ScalarType, L extends LongType>(type: T, longType: L): ScalarValue<T, L>;
/**
* Returns true for a zero-value. For example, an integer has the zero-value `0`,
* a boolean is `false`, a string is `""`, and bytes is an empty Uint8Array.
*
* In proto3, zero-values are not written to the wire, unless the field is
* optional or repeated.
*/
export declare function isScalarZeroValue(type: ScalarType, value: unknown): boolean;
+105
View File
@@ -0,0 +1,105 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.isScalarZeroValue = exports.scalarZeroValue = exports.scalarEquals = void 0;
const proto_int64_js_1 = require("../proto-int64.js");
const scalar_js_1 = require("../scalar.js");
/**
* Returns true if both scalar values are equal.
*/
function scalarEquals(type, a, b) {
if (a === b) {
// This correctly matches equal values except BYTES and (possibly) 64-bit integers.
return true;
}
// Special case BYTES - we need to compare each byte individually
if (type == scalar_js_1.ScalarType.BYTES) {
if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) {
return false;
}
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
// Special case 64-bit integers - we support number, string and bigint representation.
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (type) {
case scalar_js_1.ScalarType.UINT64:
case scalar_js_1.ScalarType.FIXED64:
case scalar_js_1.ScalarType.INT64:
case scalar_js_1.ScalarType.SFIXED64:
case scalar_js_1.ScalarType.SINT64:
// Loose comparison will match between 0n, 0 and "0".
return a == b;
}
// Anything that hasn't been caught by strict comparison or special cased
// BYTES and 64-bit integers is not equal.
return false;
}
exports.scalarEquals = scalarEquals;
/**
* Returns the zero value for the given scalar type.
*/
function scalarZeroValue(type, longType) {
switch (type) {
case scalar_js_1.ScalarType.BOOL:
return false;
case scalar_js_1.ScalarType.UINT64:
case scalar_js_1.ScalarType.FIXED64:
case scalar_js_1.ScalarType.INT64:
case scalar_js_1.ScalarType.SFIXED64:
case scalar_js_1.ScalarType.SINT64:
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison -- acceptable since it's covered by tests
return (longType == 0 ? proto_int64_js_1.protoInt64.zero : "0");
case scalar_js_1.ScalarType.DOUBLE:
case scalar_js_1.ScalarType.FLOAT:
return 0.0;
case scalar_js_1.ScalarType.BYTES:
return new Uint8Array(0);
case scalar_js_1.ScalarType.STRING:
return "";
default:
// Handles INT32, UINT32, SINT32, FIXED32, SFIXED32.
// We do not use individual cases to save a few bytes code size.
return 0;
}
}
exports.scalarZeroValue = scalarZeroValue;
/**
* Returns true for a zero-value. For example, an integer has the zero-value `0`,
* a boolean is `false`, a string is `""`, and bytes is an empty Uint8Array.
*
* In proto3, zero-values are not written to the wire, unless the field is
* optional or repeated.
*/
function isScalarZeroValue(type, value) {
switch (type) {
case scalar_js_1.ScalarType.BOOL:
return value === false;
case scalar_js_1.ScalarType.STRING:
return value === "";
case scalar_js_1.ScalarType.BYTES:
return value instanceof Uint8Array && !value.byteLength;
default:
return value == 0; // Loose comparison matches 0n, 0 and "0"
}
}
exports.isScalarZeroValue = isScalarZeroValue;
+4
View File
@@ -0,0 +1,4 @@
import type { DescEnum } from "../descriptor-set.js";
import { ScalarType } from "../scalar.js";
export declare function parseTextFormatEnumValue(descEnum: DescEnum, value: string): number;
export declare function parseTextFormatScalarValue(type: ScalarType, value: string): number | boolean | string | bigint | Uint8Array;
+189
View File
@@ -0,0 +1,189 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseTextFormatScalarValue = exports.parseTextFormatEnumValue = void 0;
const assert_js_1 = require("./assert.js");
const proto_int64_js_1 = require("../proto-int64.js");
const scalar_js_1 = require("../scalar.js");
function parseTextFormatEnumValue(descEnum, value) {
const enumValue = descEnum.values.find((v) => v.name === value);
(0, assert_js_1.assert)(enumValue, `cannot parse ${descEnum.name} default value: ${value}`);
return enumValue.number;
}
exports.parseTextFormatEnumValue = parseTextFormatEnumValue;
function parseTextFormatScalarValue(type, value) {
switch (type) {
case scalar_js_1.ScalarType.STRING:
return value;
case scalar_js_1.ScalarType.BYTES: {
const u = unescapeBytesDefaultValue(value);
if (u === false) {
throw new Error(`cannot parse ${scalar_js_1.ScalarType[type]} default value: ${value}`);
}
return u;
}
case scalar_js_1.ScalarType.INT64:
case scalar_js_1.ScalarType.SFIXED64:
case scalar_js_1.ScalarType.SINT64:
return proto_int64_js_1.protoInt64.parse(value);
case scalar_js_1.ScalarType.UINT64:
case scalar_js_1.ScalarType.FIXED64:
return proto_int64_js_1.protoInt64.uParse(value);
case scalar_js_1.ScalarType.DOUBLE:
case scalar_js_1.ScalarType.FLOAT:
switch (value) {
case "inf":
return Number.POSITIVE_INFINITY;
case "-inf":
return Number.NEGATIVE_INFINITY;
case "nan":
return Number.NaN;
default:
return parseFloat(value);
}
case scalar_js_1.ScalarType.BOOL:
return value === "true";
case scalar_js_1.ScalarType.INT32:
case scalar_js_1.ScalarType.UINT32:
case scalar_js_1.ScalarType.SINT32:
case scalar_js_1.ScalarType.FIXED32:
case scalar_js_1.ScalarType.SFIXED32:
return parseInt(value, 10);
}
}
exports.parseTextFormatScalarValue = parseTextFormatScalarValue;
/**
* Parses a text-encoded default value (proto2) of a BYTES field.
*/
function unescapeBytesDefaultValue(str) {
const b = [];
const input = {
tail: str,
c: "",
next() {
if (this.tail.length == 0) {
return false;
}
this.c = this.tail[0];
this.tail = this.tail.substring(1);
return true;
},
take(n) {
if (this.tail.length >= n) {
const r = this.tail.substring(0, n);
this.tail = this.tail.substring(n);
return r;
}
return false;
},
};
while (input.next()) {
switch (input.c) {
case "\\":
if (input.next()) {
switch (input.c) {
case "\\":
b.push(input.c.charCodeAt(0));
break;
case "b":
b.push(0x08);
break;
case "f":
b.push(0x0c);
break;
case "n":
b.push(0x0a);
break;
case "r":
b.push(0x0d);
break;
case "t":
b.push(0x09);
break;
case "v":
b.push(0x0b);
break;
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7": {
const s = input.c;
const t = input.take(2);
if (t === false) {
return false;
}
const n = parseInt(s + t, 8);
if (isNaN(n)) {
return false;
}
b.push(n);
break;
}
case "x": {
const s = input.c;
const t = input.take(2);
if (t === false) {
return false;
}
const n = parseInt(s + t, 16);
if (isNaN(n)) {
return false;
}
b.push(n);
break;
}
case "u": {
const s = input.c;
const t = input.take(4);
if (t === false) {
return false;
}
const n = parseInt(s + t, 16);
if (isNaN(n)) {
return false;
}
const chunk = new Uint8Array(4);
const view = new DataView(chunk.buffer);
view.setInt32(0, n, true);
b.push(chunk[0], chunk[1], chunk[2], chunk[3]);
break;
}
case "U": {
const s = input.c;
const t = input.take(8);
if (t === false) {
return false;
}
const tc = proto_int64_js_1.protoInt64.uEnc(s + t);
const chunk = new Uint8Array(8);
const view = new DataView(chunk.buffer);
view.setInt32(0, tc.lo, true);
view.setInt32(4, tc.hi, true);
b.push(chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6], chunk[7]);
break;
}
}
}
break;
default:
b.push(input.c.charCodeAt(0));
}
}
return new Uint8Array(b);
}
+2
View File
@@ -0,0 +1,2 @@
import type { Util } from "./util.js";
export declare function makeUtilCommon(): Omit<Util, "newFieldList" | "initFields">;
+247
View File
@@ -0,0 +1,247 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeUtilCommon = void 0;
const enum_js_1 = require("./enum.js");
const scalars_js_1 = require("./scalars.js");
const scalar_js_1 = require("../scalar.js");
const is_message_js_1 = require("../is-message.js");
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-argument,no-case-declarations */
function makeUtilCommon() {
return {
setEnumType: enum_js_1.setEnumType,
initPartial(source, target) {
if (source === undefined) {
return;
}
const type = target.getType();
for (const member of type.fields.byMember()) {
const localName = member.localName, t = target, s = source;
if (s[localName] == null) {
// TODO if source is a Message instance, we should use isFieldSet() here to support future field presence
continue;
}
switch (member.kind) {
case "oneof":
const sk = s[localName].case;
if (sk === undefined) {
continue;
}
const sourceField = member.findField(sk);
let val = s[localName].value;
if (sourceField &&
sourceField.kind == "message" &&
!(0, is_message_js_1.isMessage)(val, sourceField.T)) {
val = new sourceField.T(val);
}
else if (sourceField &&
sourceField.kind === "scalar" &&
sourceField.T === scalar_js_1.ScalarType.BYTES) {
val = toU8Arr(val);
}
t[localName] = { case: sk, value: val };
break;
case "scalar":
case "enum":
let copy = s[localName];
if (member.T === scalar_js_1.ScalarType.BYTES) {
copy = member.repeated
? copy.map(toU8Arr)
: toU8Arr(copy);
}
t[localName] = copy;
break;
case "map":
switch (member.V.kind) {
case "scalar":
case "enum":
if (member.V.T === scalar_js_1.ScalarType.BYTES) {
for (const [k, v] of Object.entries(s[localName])) {
t[localName][k] = toU8Arr(v);
}
}
else {
Object.assign(t[localName], s[localName]);
}
break;
case "message":
const messageType = member.V.T;
for (const k of Object.keys(s[localName])) {
let val = s[localName][k];
if (!messageType.fieldWrapper) {
// We only take partial input for messages that are not a wrapper type.
// For those messages, we recursively normalize the partial input.
val = new messageType(val);
}
t[localName][k] = val;
}
break;
}
break;
case "message":
const mt = member.T;
if (member.repeated) {
t[localName] = s[localName].map((val) => (0, is_message_js_1.isMessage)(val, mt) ? val : new mt(val));
}
else {
const val = s[localName];
if (mt.fieldWrapper) {
if (
// We can't use BytesValue.typeName as that will create a circular import
mt.typeName === "google.protobuf.BytesValue") {
t[localName] = toU8Arr(val);
}
else {
t[localName] = val;
}
}
else {
t[localName] = (0, is_message_js_1.isMessage)(val, mt) ? val : new mt(val);
}
}
break;
}
}
},
// TODO use isFieldSet() here to support future field presence
equals(type, a, b) {
if (a === b) {
return true;
}
if (!a || !b) {
return false;
}
return type.fields.byMember().every((m) => {
const va = a[m.localName];
const vb = b[m.localName];
if (m.repeated) {
if (va.length !== vb.length) {
return false;
}
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- repeated fields are never "map"
switch (m.kind) {
case "message":
return va.every((a, i) => m.T.equals(a, vb[i]));
case "scalar":
return va.every((a, i) => (0, scalars_js_1.scalarEquals)(m.T, a, vb[i]));
case "enum":
return va.every((a, i) => (0, scalars_js_1.scalarEquals)(scalar_js_1.ScalarType.INT32, a, vb[i]));
}
throw new Error(`repeated cannot contain ${m.kind}`);
}
switch (m.kind) {
case "message":
let a = va;
let b = vb;
if (m.T.fieldWrapper) {
if (a !== undefined && !(0, is_message_js_1.isMessage)(a)) {
a = m.T.fieldWrapper.wrapField(a);
}
if (b !== undefined && !(0, is_message_js_1.isMessage)(b)) {
b = m.T.fieldWrapper.wrapField(b);
}
}
return m.T.equals(a, b);
case "enum":
return (0, scalars_js_1.scalarEquals)(scalar_js_1.ScalarType.INT32, va, vb);
case "scalar":
return (0, scalars_js_1.scalarEquals)(m.T, va, vb);
case "oneof":
if (va.case !== vb.case) {
return false;
}
const s = m.findField(va.case);
if (s === undefined) {
return true;
}
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- oneof fields are never "map"
switch (s.kind) {
case "message":
return s.T.equals(va.value, vb.value);
case "enum":
return (0, scalars_js_1.scalarEquals)(scalar_js_1.ScalarType.INT32, va.value, vb.value);
case "scalar":
return (0, scalars_js_1.scalarEquals)(s.T, va.value, vb.value);
}
throw new Error(`oneof cannot contain ${s.kind}`);
case "map":
const keys = Object.keys(va).concat(Object.keys(vb));
switch (m.V.kind) {
case "message":
const messageType = m.V.T;
return keys.every((k) => messageType.equals(va[k], vb[k]));
case "enum":
return keys.every((k) => (0, scalars_js_1.scalarEquals)(scalar_js_1.ScalarType.INT32, va[k], vb[k]));
case "scalar":
const scalarType = m.V.T;
return keys.every((k) => (0, scalars_js_1.scalarEquals)(scalarType, va[k], vb[k]));
}
break;
}
});
},
// TODO use isFieldSet() here to support future field presence
clone(message) {
const type = message.getType(), target = new type(), any = target;
for (const member of type.fields.byMember()) {
const source = message[member.localName];
let copy;
if (member.repeated) {
copy = source.map(cloneSingularField);
}
else if (member.kind == "map") {
copy = any[member.localName];
for (const [key, v] of Object.entries(source)) {
copy[key] = cloneSingularField(v);
}
}
else if (member.kind == "oneof") {
const f = member.findField(source.case);
copy = f
? { case: source.case, value: cloneSingularField(source.value) }
: { case: undefined };
}
else {
copy = cloneSingularField(source);
}
any[member.localName] = copy;
}
for (const uf of type.runtime.bin.listUnknownFields(message)) {
type.runtime.bin.onUnknownField(any, uf.no, uf.wireType, uf.data);
}
return target;
},
};
}
exports.makeUtilCommon = makeUtilCommon;
// clone a single field value - i.e. the element type of repeated fields, the value type of maps
function cloneSingularField(value) {
if (value === undefined) {
return value;
}
if ((0, is_message_js_1.isMessage)(value)) {
return value.clone();
}
if (value instanceof Uint8Array) {
const c = new Uint8Array(value.byteLength);
c.set(value);
return c;
}
return value;
}
// converts any ArrayLike<number> to Uint8Array if necessary.
function toU8Arr(input) {
return input instanceof Uint8Array ? input : new Uint8Array(input);
}
+38
View File
@@ -0,0 +1,38 @@
import type { FieldListSource } from "./field-list.js";
import type { FieldList } from "../field-list.js";
import type { EnumObject } from "./enum.js";
import type { Message, PartialMessage, PlainMessage } from "../message.js";
import type { MessageType } from "../message-type.js";
import type { EnumValueInfo } from "../enum.js";
/**
* Provides utilities used by generated code.
* All methods are internal and are not safe to use, they may break with a
* future release.
*/
export interface Util {
/**
* Create a field list
*/
newFieldList(fields: FieldListSource): FieldList;
/**
* Sets reflection information on a generated enum.
*/
setEnumType(enumObject: EnumObject, typeName: string, values: Omit<EnumValueInfo, "localName">[], opt?: {}): void;
/**
* Set default field values on the target message.
*/
initFields(target: Message): void;
/**
* Set specified field values on the target message, recursively.
*/
initPartial<T extends Message<T>>(source: PartialMessage<T> | undefined, target: T): void;
/**
* Compares two messages of the same type recursively.
* Will also return true if both messages are `undefined` or `null`.
*/
equals<T extends Message<T>>(type: MessageType<T>, a: T | PlainMessage<T> | undefined | null, b: T | PlainMessage<T> | undefined | null): boolean;
/**
* Create a deep copy.
*/
clone<T extends Message<T>>(message: T): T;
}
+15
View File
@@ -0,0 +1,15 @@
"use strict";
// Copyright 2021-2024 Buf Technologies, Inc.
//
// 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.
Object.defineProperty(exports, "__esModule", { value: true });