Erster Commit
This commit is contained in:
+910
@@ -0,0 +1,910 @@
|
||||
"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.createDescriptorSet = void 0;
|
||||
const descriptor_pb_js_1 = require("./google/protobuf/descriptor_pb.js");
|
||||
const assert_js_1 = require("./private/assert.js");
|
||||
const service_type_js_1 = require("./service-type.js");
|
||||
const names_js_1 = require("./private/names.js");
|
||||
const text_format_js_1 = require("./private/text-format.js");
|
||||
const feature_set_js_1 = require("./private/feature-set.js");
|
||||
const scalar_js_1 = require("./scalar.js");
|
||||
const is_message_js_1 = require("./is-message.js");
|
||||
/**
|
||||
* Create a DescriptorSet, a convenient interface for working with a set of
|
||||
* google.protobuf.FileDescriptorProto.
|
||||
*
|
||||
* Note that files must be given in topological order, so each file appears
|
||||
* before any file that imports it. Protocol buffer compilers always produce
|
||||
* files in topological order.
|
||||
*/
|
||||
function createDescriptorSet(input, options) {
|
||||
var _a;
|
||||
const cart = {
|
||||
files: [],
|
||||
enums: new Map(),
|
||||
messages: new Map(),
|
||||
services: new Map(),
|
||||
extensions: new Map(),
|
||||
mapEntries: new Map(),
|
||||
};
|
||||
const fileDescriptors = (0, is_message_js_1.isMessage)(input, descriptor_pb_js_1.FileDescriptorSet)
|
||||
? input.file
|
||||
: input instanceof Uint8Array
|
||||
? descriptor_pb_js_1.FileDescriptorSet.fromBinary(input).file
|
||||
: input;
|
||||
const resolverByEdition = new Map();
|
||||
for (const proto of fileDescriptors) {
|
||||
const edition = (_a = proto.edition) !== null && _a !== void 0 ? _a : parseFileSyntax(proto.syntax, proto.edition).edition;
|
||||
let resolveFeatures = resolverByEdition.get(edition);
|
||||
if (resolveFeatures === undefined) {
|
||||
resolveFeatures = (0, feature_set_js_1.createFeatureResolver)(edition, options === null || options === void 0 ? void 0 : options.featureSetDefaults, options === null || options === void 0 ? void 0 : options.serializationOptions);
|
||||
resolverByEdition.set(edition, resolveFeatures);
|
||||
}
|
||||
addFile(proto, cart, resolveFeatures);
|
||||
}
|
||||
return cart;
|
||||
}
|
||||
exports.createDescriptorSet = createDescriptorSet;
|
||||
/**
|
||||
* Create a descriptor for a file.
|
||||
*/
|
||||
function addFile(proto, cart, resolveFeatures) {
|
||||
var _a, _b;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid FileDescriptorProto: missing name`);
|
||||
const file = Object.assign(Object.assign({ kind: "file", proto, deprecated: (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) !== null && _b !== void 0 ? _b : false }, parseFileSyntax(proto.syntax, proto.edition)), { name: proto.name.replace(/\.proto/, ""), dependencies: findFileDependencies(proto, cart), enums: [], messages: [], extensions: [], services: [], toString() {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- we asserted above
|
||||
return `file ${this.proto.name}`;
|
||||
},
|
||||
getSyntaxComments() {
|
||||
return findComments(this.proto.sourceCodeInfo, [
|
||||
FieldNumber.FileDescriptorProto_Syntax,
|
||||
]);
|
||||
},
|
||||
getPackageComments() {
|
||||
return findComments(this.proto.sourceCodeInfo, [
|
||||
FieldNumber.FileDescriptorProto_Package,
|
||||
]);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures((_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
} });
|
||||
cart.mapEntries.clear(); // map entries are local to the file, we can safely discard
|
||||
for (const enumProto of proto.enumType) {
|
||||
addEnum(enumProto, file, undefined, cart, resolveFeatures);
|
||||
}
|
||||
for (const messageProto of proto.messageType) {
|
||||
addMessage(messageProto, file, undefined, cart, resolveFeatures);
|
||||
}
|
||||
for (const serviceProto of proto.service) {
|
||||
addService(serviceProto, file, cart, resolveFeatures);
|
||||
}
|
||||
addExtensions(file, cart, resolveFeatures);
|
||||
for (const mapEntry of cart.mapEntries.values()) {
|
||||
addFields(mapEntry, cart, resolveFeatures);
|
||||
}
|
||||
for (const message of file.messages) {
|
||||
addFields(message, cart, resolveFeatures);
|
||||
addExtensions(message, cart, resolveFeatures);
|
||||
}
|
||||
cart.mapEntries.clear(); // map entries are local to the file, we can safely discard
|
||||
cart.files.push(file);
|
||||
}
|
||||
/**
|
||||
* Create descriptors for extensions, and add them to the message / file,
|
||||
* and to our cart.
|
||||
* Recurses into nested types.
|
||||
*/
|
||||
function addExtensions(desc, cart, resolveFeatures) {
|
||||
switch (desc.kind) {
|
||||
case "file":
|
||||
for (const proto of desc.proto.extension) {
|
||||
const ext = newExtension(proto, desc, undefined, cart, resolveFeatures);
|
||||
desc.extensions.push(ext);
|
||||
cart.extensions.set(ext.typeName, ext);
|
||||
}
|
||||
break;
|
||||
case "message":
|
||||
for (const proto of desc.proto.extension) {
|
||||
const ext = newExtension(proto, desc.file, desc, cart, resolveFeatures);
|
||||
desc.nestedExtensions.push(ext);
|
||||
cart.extensions.set(ext.typeName, ext);
|
||||
}
|
||||
for (const message of desc.nestedMessages) {
|
||||
addExtensions(message, cart, resolveFeatures);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create descriptors for fields and oneof groups, and add them to the message.
|
||||
* Recurses into nested types.
|
||||
*/
|
||||
function addFields(message, cart, resolveFeatures) {
|
||||
const allOneofs = message.proto.oneofDecl.map((proto) => newOneof(proto, message, resolveFeatures));
|
||||
const oneofsSeen = new Set();
|
||||
for (const proto of message.proto.field) {
|
||||
const oneof = findOneof(proto, allOneofs);
|
||||
const field = newField(proto, message.file, message, oneof, cart, resolveFeatures);
|
||||
message.fields.push(field);
|
||||
if (oneof === undefined) {
|
||||
message.members.push(field);
|
||||
}
|
||||
else {
|
||||
oneof.fields.push(field);
|
||||
if (!oneofsSeen.has(oneof)) {
|
||||
oneofsSeen.add(oneof);
|
||||
message.members.push(oneof);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const oneof of allOneofs.filter((o) => oneofsSeen.has(o))) {
|
||||
message.oneofs.push(oneof);
|
||||
}
|
||||
for (const child of message.nestedMessages) {
|
||||
addFields(child, cart, resolveFeatures);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for an enumeration, and add it our cart and to the
|
||||
* parent type, if any.
|
||||
*/
|
||||
function addEnum(proto, file, parent, cart, resolveFeatures) {
|
||||
var _a, _b, _c;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid EnumDescriptorProto: missing name`);
|
||||
const desc = {
|
||||
kind: "enum",
|
||||
proto,
|
||||
deprecated: (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) !== null && _b !== void 0 ? _b : false,
|
||||
file,
|
||||
parent,
|
||||
name: proto.name,
|
||||
typeName: makeTypeName(proto, parent, file),
|
||||
values: [],
|
||||
sharedPrefix: (0, names_js_1.findEnumSharedPrefix)(proto.name, proto.value.map((v) => { var _a; return (_a = v.name) !== null && _a !== void 0 ? _a : ""; })),
|
||||
toString() {
|
||||
return `enum ${this.typeName}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = this.parent
|
||||
? [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.DescriptorProto_EnumType,
|
||||
this.parent.proto.enumType.indexOf(this.proto),
|
||||
]
|
||||
: [
|
||||
FieldNumber.FileDescriptorProto_EnumType,
|
||||
this.file.proto.enumType.indexOf(this.proto),
|
||||
];
|
||||
return findComments(file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a, _b;
|
||||
return resolveFeatures((_a = parent === null || parent === void 0 ? void 0 : parent.getFeatures()) !== null && _a !== void 0 ? _a : file.getFeatures(), (_b = proto.options) === null || _b === void 0 ? void 0 : _b.features);
|
||||
},
|
||||
};
|
||||
cart.enums.set(desc.typeName, desc);
|
||||
proto.value.forEach((proto) => {
|
||||
var _a, _b;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid EnumValueDescriptorProto: missing name`);
|
||||
(0, assert_js_1.assert)(proto.number !== undefined, `invalid EnumValueDescriptorProto: missing number`);
|
||||
desc.values.push({
|
||||
kind: "enum_value",
|
||||
proto,
|
||||
deprecated: (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) !== null && _b !== void 0 ? _b : false,
|
||||
parent: desc,
|
||||
name: proto.name,
|
||||
number: proto.number,
|
||||
toString() {
|
||||
return `enum value ${desc.typeName}.${this.name}`;
|
||||
},
|
||||
declarationString() {
|
||||
var _a;
|
||||
let str = `${this.name} = ${this.number}`;
|
||||
if (((_a = this.proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) === true) {
|
||||
str += " [deprecated = true]";
|
||||
}
|
||||
return str;
|
||||
},
|
||||
getComments() {
|
||||
const path = [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.EnumDescriptorProto_Value,
|
||||
this.parent.proto.value.indexOf(this.proto),
|
||||
];
|
||||
return findComments(file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures(desc.getFeatures(), (_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
},
|
||||
});
|
||||
});
|
||||
((_c = parent === null || parent === void 0 ? void 0 : parent.nestedEnums) !== null && _c !== void 0 ? _c : file.enums).push(desc);
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for a message, including nested types, and add it to our
|
||||
* cart. Note that this does not create descriptors fields.
|
||||
*/
|
||||
function addMessage(proto, file, parent, cart, resolveFeatures) {
|
||||
var _a, _b, _c, _d;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid DescriptorProto: missing name`);
|
||||
const desc = {
|
||||
kind: "message",
|
||||
proto,
|
||||
deprecated: (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) !== null && _b !== void 0 ? _b : false,
|
||||
file,
|
||||
parent,
|
||||
name: proto.name,
|
||||
typeName: makeTypeName(proto, parent, file),
|
||||
fields: [],
|
||||
oneofs: [],
|
||||
members: [],
|
||||
nestedEnums: [],
|
||||
nestedMessages: [],
|
||||
nestedExtensions: [],
|
||||
toString() {
|
||||
return `message ${this.typeName}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = this.parent
|
||||
? [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.DescriptorProto_NestedType,
|
||||
this.parent.proto.nestedType.indexOf(this.proto),
|
||||
]
|
||||
: [
|
||||
FieldNumber.FileDescriptorProto_MessageType,
|
||||
this.file.proto.messageType.indexOf(this.proto),
|
||||
];
|
||||
return findComments(file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a, _b;
|
||||
return resolveFeatures((_a = parent === null || parent === void 0 ? void 0 : parent.getFeatures()) !== null && _a !== void 0 ? _a : file.getFeatures(), (_b = proto.options) === null || _b === void 0 ? void 0 : _b.features);
|
||||
},
|
||||
};
|
||||
if (((_c = proto.options) === null || _c === void 0 ? void 0 : _c.mapEntry) === true) {
|
||||
cart.mapEntries.set(desc.typeName, desc);
|
||||
}
|
||||
else {
|
||||
((_d = parent === null || parent === void 0 ? void 0 : parent.nestedMessages) !== null && _d !== void 0 ? _d : file.messages).push(desc);
|
||||
cart.messages.set(desc.typeName, desc);
|
||||
}
|
||||
for (const enumProto of proto.enumType) {
|
||||
addEnum(enumProto, file, desc, cart, resolveFeatures);
|
||||
}
|
||||
for (const messageProto of proto.nestedType) {
|
||||
addMessage(messageProto, file, desc, cart, resolveFeatures);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for a service, including methods, and add it to our
|
||||
* cart.
|
||||
*/
|
||||
function addService(proto, file, cart, resolveFeatures) {
|
||||
var _a, _b;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid ServiceDescriptorProto: missing name`);
|
||||
const desc = {
|
||||
kind: "service",
|
||||
proto,
|
||||
deprecated: (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) !== null && _b !== void 0 ? _b : false,
|
||||
file,
|
||||
name: proto.name,
|
||||
typeName: makeTypeName(proto, undefined, file),
|
||||
methods: [],
|
||||
toString() {
|
||||
return `service ${this.typeName}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = [
|
||||
FieldNumber.FileDescriptorProto_Service,
|
||||
this.file.proto.service.indexOf(this.proto),
|
||||
];
|
||||
return findComments(file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures(file.getFeatures(), (_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
},
|
||||
};
|
||||
file.services.push(desc);
|
||||
cart.services.set(desc.typeName, desc);
|
||||
for (const methodProto of proto.method) {
|
||||
desc.methods.push(newMethod(methodProto, desc, cart, resolveFeatures));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for a method.
|
||||
*/
|
||||
function newMethod(proto, parent, cart, resolveFeatures) {
|
||||
var _a, _b, _c;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid MethodDescriptorProto: missing name`);
|
||||
(0, assert_js_1.assert)(proto.inputType, `invalid MethodDescriptorProto: missing input_type`);
|
||||
(0, assert_js_1.assert)(proto.outputType, `invalid MethodDescriptorProto: missing output_type`);
|
||||
let methodKind;
|
||||
if (proto.clientStreaming === true && proto.serverStreaming === true) {
|
||||
methodKind = service_type_js_1.MethodKind.BiDiStreaming;
|
||||
}
|
||||
else if (proto.clientStreaming === true) {
|
||||
methodKind = service_type_js_1.MethodKind.ClientStreaming;
|
||||
}
|
||||
else if (proto.serverStreaming === true) {
|
||||
methodKind = service_type_js_1.MethodKind.ServerStreaming;
|
||||
}
|
||||
else {
|
||||
methodKind = service_type_js_1.MethodKind.Unary;
|
||||
}
|
||||
let idempotency;
|
||||
switch ((_a = proto.options) === null || _a === void 0 ? void 0 : _a.idempotencyLevel) {
|
||||
case descriptor_pb_js_1.MethodOptions_IdempotencyLevel.IDEMPOTENT:
|
||||
idempotency = service_type_js_1.MethodIdempotency.Idempotent;
|
||||
break;
|
||||
case descriptor_pb_js_1.MethodOptions_IdempotencyLevel.NO_SIDE_EFFECTS:
|
||||
idempotency = service_type_js_1.MethodIdempotency.NoSideEffects;
|
||||
break;
|
||||
case descriptor_pb_js_1.MethodOptions_IdempotencyLevel.IDEMPOTENCY_UNKNOWN:
|
||||
case undefined:
|
||||
idempotency = undefined;
|
||||
break;
|
||||
}
|
||||
const input = cart.messages.get(trimLeadingDot(proto.inputType));
|
||||
const output = cart.messages.get(trimLeadingDot(proto.outputType));
|
||||
(0, assert_js_1.assert)(input, `invalid MethodDescriptorProto: input_type ${proto.inputType} not found`);
|
||||
(0, assert_js_1.assert)(output, `invalid MethodDescriptorProto: output_type ${proto.inputType} not found`);
|
||||
const name = proto.name;
|
||||
return {
|
||||
kind: "rpc",
|
||||
proto,
|
||||
deprecated: (_c = (_b = proto.options) === null || _b === void 0 ? void 0 : _b.deprecated) !== null && _c !== void 0 ? _c : false,
|
||||
parent,
|
||||
name,
|
||||
methodKind,
|
||||
input,
|
||||
output,
|
||||
idempotency,
|
||||
toString() {
|
||||
return `rpc ${parent.typeName}.${name}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.ServiceDescriptorProto_Method,
|
||||
this.parent.proto.method.indexOf(this.proto),
|
||||
];
|
||||
return findComments(parent.file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures(parent.getFeatures(), (_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for a oneof group.
|
||||
*/
|
||||
function newOneof(proto, parent, resolveFeatures) {
|
||||
(0, assert_js_1.assert)(proto.name, `invalid OneofDescriptorProto: missing name`);
|
||||
return {
|
||||
kind: "oneof",
|
||||
proto,
|
||||
deprecated: false,
|
||||
parent,
|
||||
fields: [],
|
||||
name: proto.name,
|
||||
toString() {
|
||||
return `oneof ${parent.typeName}.${this.name}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.DescriptorProto_OneofDecl,
|
||||
this.parent.proto.oneofDecl.indexOf(this.proto),
|
||||
];
|
||||
return findComments(parent.file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures(parent.getFeatures(), (_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for a field.
|
||||
*/
|
||||
function newField(proto, file, parent, oneof, cart, resolveFeatures) {
|
||||
var _a, _b, _c;
|
||||
(0, assert_js_1.assert)(proto.name, `invalid FieldDescriptorProto: missing name`);
|
||||
(0, assert_js_1.assert)(proto.number, `invalid FieldDescriptorProto: missing number`);
|
||||
(0, assert_js_1.assert)(proto.type, `invalid FieldDescriptorProto: missing type`);
|
||||
const common = {
|
||||
proto,
|
||||
deprecated: (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.deprecated) !== null && _b !== void 0 ? _b : false,
|
||||
name: proto.name,
|
||||
number: proto.number,
|
||||
parent,
|
||||
oneof,
|
||||
optional: isOptionalField(proto, file.syntax),
|
||||
packedByDefault: isPackedFieldByDefault(proto, resolveFeatures),
|
||||
packed: isPackedField(file, parent, proto, resolveFeatures),
|
||||
jsonName: proto.jsonName === (0, names_js_1.fieldJsonName)(proto.name) ? undefined : proto.jsonName,
|
||||
scalar: undefined,
|
||||
longType: undefined,
|
||||
message: undefined,
|
||||
enum: undefined,
|
||||
mapKey: undefined,
|
||||
mapValue: undefined,
|
||||
declarationString,
|
||||
// toString, getComments, getFeatures are overridden in newExtension
|
||||
toString() {
|
||||
return `field ${this.parent.typeName}.${this.name}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.DescriptorProto_Field,
|
||||
this.parent.proto.field.indexOf(this.proto),
|
||||
];
|
||||
return findComments(file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures(parent.getFeatures(), (_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
},
|
||||
};
|
||||
const repeated = proto.label === descriptor_pb_js_1.FieldDescriptorProto_Label.REPEATED;
|
||||
switch (proto.type) {
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.MESSAGE:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.GROUP: {
|
||||
(0, assert_js_1.assert)(proto.typeName, `invalid FieldDescriptorProto: missing type_name`);
|
||||
const mapEntry = cart.mapEntries.get(trimLeadingDot(proto.typeName));
|
||||
if (mapEntry !== undefined) {
|
||||
(0, assert_js_1.assert)(repeated, `invalid FieldDescriptorProto: expected map entry to be repeated`);
|
||||
return Object.assign(Object.assign(Object.assign({}, common), { kind: "field", fieldKind: "map", repeated: false }), getMapFieldTypes(mapEntry));
|
||||
}
|
||||
const message = cart.messages.get(trimLeadingDot(proto.typeName));
|
||||
(0, assert_js_1.assert)(message !== undefined, `invalid FieldDescriptorProto: type_name ${proto.typeName} not found`);
|
||||
return Object.assign(Object.assign({}, common), { kind: "field", fieldKind: "message", repeated,
|
||||
message });
|
||||
}
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.ENUM: {
|
||||
(0, assert_js_1.assert)(proto.typeName, `invalid FieldDescriptorProto: missing type_name`);
|
||||
const e = cart.enums.get(trimLeadingDot(proto.typeName));
|
||||
(0, assert_js_1.assert)(e !== undefined, `invalid FieldDescriptorProto: type_name ${proto.typeName} not found`);
|
||||
return Object.assign(Object.assign({}, common), { kind: "field", fieldKind: "enum", getDefaultValue,
|
||||
repeated, enum: e });
|
||||
}
|
||||
default: {
|
||||
const scalar = fieldTypeToScalarType[proto.type];
|
||||
(0, assert_js_1.assert)(scalar, `invalid FieldDescriptorProto: unknown type ${proto.type}`);
|
||||
return Object.assign(Object.assign({}, common), { kind: "field", fieldKind: "scalar", getDefaultValue,
|
||||
repeated,
|
||||
scalar, longType: ((_c = proto.options) === null || _c === void 0 ? void 0 : _c.jstype) == descriptor_pb_js_1.FieldOptions_JSType.JS_STRING
|
||||
? scalar_js_1.LongType.STRING
|
||||
: scalar_js_1.LongType.BIGINT });
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a descriptor for an extension field.
|
||||
*/
|
||||
function newExtension(proto, file, parent, cart, resolveFeatures) {
|
||||
(0, assert_js_1.assert)(proto.extendee, `invalid FieldDescriptorProto: missing extendee`);
|
||||
const field = newField(proto, file, null, // to safe us many lines of duplicated code, we trick the type system
|
||||
undefined, cart, resolveFeatures);
|
||||
const extendee = cart.messages.get(trimLeadingDot(proto.extendee));
|
||||
(0, assert_js_1.assert)(extendee, `invalid FieldDescriptorProto: extendee ${proto.extendee} not found`);
|
||||
return Object.assign(Object.assign({}, field), { kind: "extension", typeName: makeTypeName(proto, parent, file), parent,
|
||||
file,
|
||||
extendee,
|
||||
// Must override toString, getComments, getFeatures from newField, because we
|
||||
// call newField with parent undefined.
|
||||
toString() {
|
||||
return `extension ${this.typeName}`;
|
||||
},
|
||||
getComments() {
|
||||
const path = this.parent
|
||||
? [
|
||||
...this.parent.getComments().sourcePath,
|
||||
FieldNumber.DescriptorProto_Extension,
|
||||
this.parent.proto.extension.indexOf(proto),
|
||||
]
|
||||
: [
|
||||
FieldNumber.FileDescriptorProto_Extension,
|
||||
this.file.proto.extension.indexOf(proto),
|
||||
];
|
||||
return findComments(file.proto.sourceCodeInfo, path);
|
||||
},
|
||||
getFeatures() {
|
||||
var _a;
|
||||
return resolveFeatures((parent !== null && parent !== void 0 ? parent : file).getFeatures(), (_a = proto.options) === null || _a === void 0 ? void 0 : _a.features);
|
||||
} });
|
||||
}
|
||||
/**
|
||||
* Parse the "syntax" and "edition" fields, stripping test editions.
|
||||
*/
|
||||
function parseFileSyntax(syntax, edition) {
|
||||
let e;
|
||||
let s;
|
||||
switch (syntax) {
|
||||
case undefined:
|
||||
case "proto2":
|
||||
s = "proto2";
|
||||
e = descriptor_pb_js_1.Edition.EDITION_PROTO2;
|
||||
break;
|
||||
case "proto3":
|
||||
s = "proto3";
|
||||
e = descriptor_pb_js_1.Edition.EDITION_PROTO3;
|
||||
break;
|
||||
case "editions":
|
||||
s = "editions";
|
||||
switch (edition) {
|
||||
case undefined:
|
||||
case descriptor_pb_js_1.Edition.EDITION_1_TEST_ONLY:
|
||||
case descriptor_pb_js_1.Edition.EDITION_2_TEST_ONLY:
|
||||
case descriptor_pb_js_1.Edition.EDITION_99997_TEST_ONLY:
|
||||
case descriptor_pb_js_1.Edition.EDITION_99998_TEST_ONLY:
|
||||
case descriptor_pb_js_1.Edition.EDITION_99999_TEST_ONLY:
|
||||
case descriptor_pb_js_1.Edition.EDITION_UNKNOWN:
|
||||
e = descriptor_pb_js_1.Edition.EDITION_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
e = edition;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`invalid FileDescriptorProto: unsupported syntax: ${syntax}`);
|
||||
}
|
||||
if (syntax === "editions" && edition === descriptor_pb_js_1.Edition.EDITION_UNKNOWN) {
|
||||
throw new Error(`invalid FileDescriptorProto: syntax ${syntax} cannot have edition ${String(edition)}`);
|
||||
}
|
||||
return {
|
||||
syntax: s,
|
||||
edition: e,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Resolve dependencies of FileDescriptorProto to DescFile.
|
||||
*/
|
||||
function findFileDependencies(proto, cart) {
|
||||
return proto.dependency.map((wantName) => {
|
||||
const dep = cart.files.find((f) => f.proto.name === wantName);
|
||||
(0, assert_js_1.assert)(dep);
|
||||
return dep;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Create a fully qualified name for a protobuf type or extension field.
|
||||
*
|
||||
* The fully qualified name for messages, enumerations, and services is
|
||||
* constructed by concatenating the package name (if present), parent
|
||||
* message names (for nested types), and the type name. We omit the leading
|
||||
* dot added by protobuf compilers. Examples:
|
||||
* - mypackage.MyMessage
|
||||
* - mypackage.MyMessage.NestedMessage
|
||||
*
|
||||
* The fully qualified name for extension fields is constructed by
|
||||
* concatenating the package name (if present), parent message names (for
|
||||
* extensions declared within a message), and the field name. Examples:
|
||||
* - mypackage.extfield
|
||||
* - mypackage.MyMessage.extfield
|
||||
*/
|
||||
function makeTypeName(proto, parent, file) {
|
||||
(0, assert_js_1.assert)(proto.name, `invalid ${proto.getType().typeName}: missing name`);
|
||||
let typeName;
|
||||
if (parent) {
|
||||
typeName = `${parent.typeName}.${proto.name}`;
|
||||
}
|
||||
else if (file.proto.package !== undefined) {
|
||||
typeName = `${file.proto.package}.${proto.name}`;
|
||||
}
|
||||
else {
|
||||
typeName = `${proto.name}`;
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
/**
|
||||
* Remove the leading dot from a fully qualified type name.
|
||||
*/
|
||||
function trimLeadingDot(typeName) {
|
||||
return typeName.startsWith(".") ? typeName.substring(1) : typeName;
|
||||
}
|
||||
function getMapFieldTypes(mapEntry) {
|
||||
var _a, _b;
|
||||
(0, assert_js_1.assert)((_a = mapEntry.proto.options) === null || _a === void 0 ? void 0 : _a.mapEntry, `invalid DescriptorProto: expected ${mapEntry.toString()} to be a map entry`);
|
||||
(0, assert_js_1.assert)(mapEntry.fields.length === 2, `invalid DescriptorProto: map entry ${mapEntry.toString()} has ${mapEntry.fields.length} fields`);
|
||||
const keyField = mapEntry.fields.find((f) => f.proto.number === 1);
|
||||
(0, assert_js_1.assert)(keyField, `invalid DescriptorProto: map entry ${mapEntry.toString()} is missing key field`);
|
||||
const mapKey = keyField.scalar;
|
||||
(0, assert_js_1.assert)(mapKey !== undefined &&
|
||||
mapKey !== scalar_js_1.ScalarType.BYTES &&
|
||||
mapKey !== scalar_js_1.ScalarType.FLOAT &&
|
||||
mapKey !== scalar_js_1.ScalarType.DOUBLE, `invalid DescriptorProto: map entry ${mapEntry.toString()} has unexpected key type ${(_b = keyField.proto.type) !== null && _b !== void 0 ? _b : -1}`);
|
||||
const valueField = mapEntry.fields.find((f) => f.proto.number === 2);
|
||||
(0, assert_js_1.assert)(valueField, `invalid DescriptorProto: map entry ${mapEntry.toString()} is missing value field`);
|
||||
switch (valueField.fieldKind) {
|
||||
case "scalar":
|
||||
return {
|
||||
mapKey,
|
||||
mapValue: Object.assign(Object.assign({}, valueField), { kind: "scalar" }),
|
||||
};
|
||||
case "message":
|
||||
return {
|
||||
mapKey,
|
||||
mapValue: Object.assign(Object.assign({}, valueField), { kind: "message" }),
|
||||
};
|
||||
case "enum":
|
||||
return {
|
||||
mapKey,
|
||||
mapValue: Object.assign(Object.assign({}, valueField), { kind: "enum" }),
|
||||
};
|
||||
default:
|
||||
throw new Error("invalid DescriptorProto: unsupported map entry value field");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Did the user put the field in a oneof group?
|
||||
* This handles proto3 optionals.
|
||||
*/
|
||||
function findOneof(proto, allOneofs) {
|
||||
var _a;
|
||||
const oneofIndex = proto.oneofIndex;
|
||||
if (oneofIndex === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
let oneof;
|
||||
if (proto.proto3Optional !== true) {
|
||||
oneof = allOneofs[oneofIndex];
|
||||
(0, assert_js_1.assert)(oneof, `invalid FieldDescriptorProto: oneof #${oneofIndex} for field #${(_a = proto.number) !== null && _a !== void 0 ? _a : -1} not found`);
|
||||
}
|
||||
return oneof;
|
||||
}
|
||||
/**
|
||||
* Did the user use the `optional` keyword?
|
||||
* This handles proto3 optionals.
|
||||
*/
|
||||
function isOptionalField(proto, syntax) {
|
||||
switch (syntax) {
|
||||
case "proto2":
|
||||
return (proto.oneofIndex === undefined &&
|
||||
proto.label === descriptor_pb_js_1.FieldDescriptorProto_Label.OPTIONAL);
|
||||
case "proto3":
|
||||
return proto.proto3Optional === true;
|
||||
case "editions":
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Is this field packed by default? Only valid for repeated enum fields, and
|
||||
* for repeated scalar fields except BYTES and STRING.
|
||||
*
|
||||
* In proto3 syntax, fields are packed by default. In proto2 syntax, fields
|
||||
* are unpacked by default. With editions, the default is whatever the edition
|
||||
* specifies as a default. In edition 2023, fields are packed by default.
|
||||
*/
|
||||
function isPackedFieldByDefault(proto, resolveFeatures) {
|
||||
const { repeatedFieldEncoding } = resolveFeatures();
|
||||
if (repeatedFieldEncoding != descriptor_pb_js_1.FeatureSet_RepeatedFieldEncoding.PACKED) {
|
||||
return false;
|
||||
}
|
||||
// From the proto3 language guide:
|
||||
// > In proto3, repeated fields of scalar numeric types are packed by default.
|
||||
// This information is incomplete - according to the conformance tests, BOOL
|
||||
// and ENUM are packed by default as well. This means only STRING and BYTES
|
||||
// are not packed by default, which makes sense because they are length-delimited.
|
||||
switch (proto.type) {
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.STRING:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.BYTES:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.GROUP:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.MESSAGE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Pack this repeated field?
|
||||
*
|
||||
* Respects field type, proto2/proto3 defaults and the `packed` option, or
|
||||
* edition defaults and the edition features.repeated_field_encoding options.
|
||||
*/
|
||||
function isPackedField(file, parent, proto, resolveFeatures) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
switch (proto.type) {
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.STRING:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.BYTES:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.GROUP:
|
||||
case descriptor_pb_js_1.FieldDescriptorProto_Type.MESSAGE:
|
||||
// length-delimited types cannot be packed
|
||||
return false;
|
||||
default:
|
||||
switch (file.edition) {
|
||||
case descriptor_pb_js_1.Edition.EDITION_PROTO2:
|
||||
return (_b = (_a = proto.options) === null || _a === void 0 ? void 0 : _a.packed) !== null && _b !== void 0 ? _b : false;
|
||||
case descriptor_pb_js_1.Edition.EDITION_PROTO3:
|
||||
return (_d = (_c = proto.options) === null || _c === void 0 ? void 0 : _c.packed) !== null && _d !== void 0 ? _d : true;
|
||||
default: {
|
||||
const { repeatedFieldEncoding } = resolveFeatures((_e = parent === null || parent === void 0 ? void 0 : parent.getFeatures()) !== null && _e !== void 0 ? _e : file.getFeatures(), (_f = proto.options) === null || _f === void 0 ? void 0 : _f.features);
|
||||
return (repeatedFieldEncoding == descriptor_pb_js_1.FeatureSet_RepeatedFieldEncoding.PACKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Map from a compiler-generated field type to our ScalarType, which is a
|
||||
* subset of field types declared by protobuf enum google.protobuf.FieldDescriptorProto.
|
||||
*/
|
||||
const fieldTypeToScalarType = {
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.DOUBLE]: scalar_js_1.ScalarType.DOUBLE,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.FLOAT]: scalar_js_1.ScalarType.FLOAT,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.INT64]: scalar_js_1.ScalarType.INT64,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.UINT64]: scalar_js_1.ScalarType.UINT64,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.INT32]: scalar_js_1.ScalarType.INT32,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.FIXED64]: scalar_js_1.ScalarType.FIXED64,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.FIXED32]: scalar_js_1.ScalarType.FIXED32,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.BOOL]: scalar_js_1.ScalarType.BOOL,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.STRING]: scalar_js_1.ScalarType.STRING,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.GROUP]: undefined,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.MESSAGE]: undefined,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.BYTES]: scalar_js_1.ScalarType.BYTES,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.UINT32]: scalar_js_1.ScalarType.UINT32,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.ENUM]: undefined,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.SFIXED32]: scalar_js_1.ScalarType.SFIXED32,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.SFIXED64]: scalar_js_1.ScalarType.SFIXED64,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.SINT32]: scalar_js_1.ScalarType.SINT32,
|
||||
[descriptor_pb_js_1.FieldDescriptorProto_Type.SINT64]: scalar_js_1.ScalarType.SINT64,
|
||||
};
|
||||
/**
|
||||
* Find comments.
|
||||
*/
|
||||
function findComments(sourceCodeInfo, sourcePath) {
|
||||
if (!sourceCodeInfo) {
|
||||
return {
|
||||
leadingDetached: [],
|
||||
sourcePath,
|
||||
};
|
||||
}
|
||||
for (const location of sourceCodeInfo.location) {
|
||||
if (location.path.length !== sourcePath.length) {
|
||||
continue;
|
||||
}
|
||||
if (location.path.some((value, index) => sourcePath[index] !== value)) {
|
||||
continue;
|
||||
}
|
||||
return {
|
||||
leadingDetached: location.leadingDetachedComments,
|
||||
leading: location.leadingComments,
|
||||
trailing: location.trailingComments,
|
||||
sourcePath,
|
||||
};
|
||||
}
|
||||
return {
|
||||
leadingDetached: [],
|
||||
sourcePath,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* The following field numbers are used to find comments in
|
||||
* google.protobuf.SourceCodeInfo.
|
||||
*/
|
||||
var FieldNumber;
|
||||
(function (FieldNumber) {
|
||||
FieldNumber[FieldNumber["FileDescriptorProto_Package"] = 2] = "FileDescriptorProto_Package";
|
||||
FieldNumber[FieldNumber["FileDescriptorProto_MessageType"] = 4] = "FileDescriptorProto_MessageType";
|
||||
FieldNumber[FieldNumber["FileDescriptorProto_EnumType"] = 5] = "FileDescriptorProto_EnumType";
|
||||
FieldNumber[FieldNumber["FileDescriptorProto_Service"] = 6] = "FileDescriptorProto_Service";
|
||||
FieldNumber[FieldNumber["FileDescriptorProto_Extension"] = 7] = "FileDescriptorProto_Extension";
|
||||
FieldNumber[FieldNumber["FileDescriptorProto_Syntax"] = 12] = "FileDescriptorProto_Syntax";
|
||||
FieldNumber[FieldNumber["DescriptorProto_Field"] = 2] = "DescriptorProto_Field";
|
||||
FieldNumber[FieldNumber["DescriptorProto_NestedType"] = 3] = "DescriptorProto_NestedType";
|
||||
FieldNumber[FieldNumber["DescriptorProto_EnumType"] = 4] = "DescriptorProto_EnumType";
|
||||
FieldNumber[FieldNumber["DescriptorProto_Extension"] = 6] = "DescriptorProto_Extension";
|
||||
FieldNumber[FieldNumber["DescriptorProto_OneofDecl"] = 8] = "DescriptorProto_OneofDecl";
|
||||
FieldNumber[FieldNumber["EnumDescriptorProto_Value"] = 2] = "EnumDescriptorProto_Value";
|
||||
FieldNumber[FieldNumber["ServiceDescriptorProto_Method"] = 2] = "ServiceDescriptorProto_Method";
|
||||
})(FieldNumber || (FieldNumber = {}));
|
||||
/**
|
||||
* Return a string that matches the definition of a field in the protobuf
|
||||
* source. Does not take custom options into account.
|
||||
*/
|
||||
function declarationString() {
|
||||
var _a, _b, _c;
|
||||
const parts = [];
|
||||
if (this.repeated) {
|
||||
parts.push("repeated");
|
||||
}
|
||||
if (this.optional) {
|
||||
parts.push("optional");
|
||||
}
|
||||
const file = this.kind === "extension" ? this.file : this.parent.file;
|
||||
if (file.syntax == "proto2" &&
|
||||
this.proto.label === descriptor_pb_js_1.FieldDescriptorProto_Label.REQUIRED) {
|
||||
parts.push("required");
|
||||
}
|
||||
let type;
|
||||
switch (this.fieldKind) {
|
||||
case "scalar":
|
||||
type = scalar_js_1.ScalarType[this.scalar].toLowerCase();
|
||||
break;
|
||||
case "enum":
|
||||
type = this.enum.typeName;
|
||||
break;
|
||||
case "message":
|
||||
type = this.message.typeName;
|
||||
break;
|
||||
case "map": {
|
||||
const k = scalar_js_1.ScalarType[this.mapKey].toLowerCase();
|
||||
let v;
|
||||
switch (this.mapValue.kind) {
|
||||
case "scalar":
|
||||
v = scalar_js_1.ScalarType[this.mapValue.scalar].toLowerCase();
|
||||
break;
|
||||
case "enum":
|
||||
v = this.mapValue.enum.typeName;
|
||||
break;
|
||||
case "message":
|
||||
v = this.mapValue.message.typeName;
|
||||
break;
|
||||
}
|
||||
type = `map<${k}, ${v}>`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parts.push(`${type} ${this.name} = ${this.number}`);
|
||||
const options = [];
|
||||
if (((_a = this.proto.options) === null || _a === void 0 ? void 0 : _a.packed) !== undefined) {
|
||||
options.push(`packed = ${this.proto.options.packed.toString()}`);
|
||||
}
|
||||
let defaultValue = this.proto.defaultValue;
|
||||
if (defaultValue !== undefined) {
|
||||
if (this.proto.type == descriptor_pb_js_1.FieldDescriptorProto_Type.BYTES ||
|
||||
this.proto.type == descriptor_pb_js_1.FieldDescriptorProto_Type.STRING) {
|
||||
defaultValue = '"' + defaultValue.replace('"', '\\"') + '"';
|
||||
}
|
||||
options.push(`default = ${defaultValue}`);
|
||||
}
|
||||
if (this.jsonName !== undefined) {
|
||||
options.push(`json_name = "${this.jsonName}"`);
|
||||
}
|
||||
if (((_b = this.proto.options) === null || _b === void 0 ? void 0 : _b.jstype) !== undefined) {
|
||||
options.push(`jstype = ${descriptor_pb_js_1.FieldOptions_JSType[this.proto.options.jstype]}`);
|
||||
}
|
||||
if (((_c = this.proto.options) === null || _c === void 0 ? void 0 : _c.deprecated) === true) {
|
||||
options.push(`deprecated = true`);
|
||||
}
|
||||
if (options.length > 0) {
|
||||
parts.push("[" + options.join(", ") + "]");
|
||||
}
|
||||
return parts.join(" ");
|
||||
}
|
||||
/**
|
||||
* Parses a text-encoded default value (proto2) of a scalar or enum field.
|
||||
*/
|
||||
function getDefaultValue() {
|
||||
const d = this.proto.defaultValue;
|
||||
if (d === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
switch (this.fieldKind) {
|
||||
case "enum":
|
||||
return (0, text_format_js_1.parseTextFormatEnumValue)(this.enum, d);
|
||||
case "scalar":
|
||||
return (0, text_format_js_1.parseTextFormatScalarValue)(this.scalar, d);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user