ts-proto
Version:
[](https://www.npmjs.com/package/ts-proto) [](https://github.com/stephenh/ts-proto/actions)
701 lines (700 loc) • 35.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.observableType = exports.rawRequestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isStructTypeName = exports.isStructType = exports.isListValueTypeName = exports.isListValueType = exports.isFieldMaskTypeName = exports.isFieldMaskType = exports.isBytesValueType = exports.isAnyValueTypeName = exports.isAnyValueType = exports.isValueType = exports.isTimestamp = exports.isObjectId = exports.isMapType = exports.isWholeNumber = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isOptionalProperty = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
const ts_proto_descriptors_1 = require("ts-proto-descriptors");
const ts_poet_1 = require("ts-poet");
const options_1 = require("./options");
const visit_1 = require("./visit");
const utils_1 = require("./utils");
const sourceInfo_1 = require("./sourceInfo");
const case_1 = require("./case");
/** Based on https://github.com/dcodeIO/protobuf.js/blob/master/src/types.js#L37. */
function basicWireType(type) {
switch (type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
return 1;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
return 5;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
return 5;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
return 1;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
return 2;
default:
throw new Error("Invalid type " + type);
}
}
exports.basicWireType = basicWireType;
function basicLongWireType(type) {
switch (type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
return 1;
default:
return undefined;
}
}
exports.basicLongWireType = basicLongWireType;
/** Returns the type name without any repeated/required/etc. labels. */
function basicTypeName(ctx, field, typeOptions = {}) {
const { options } = ctx;
switch (field.type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
return (0, ts_poet_1.code) `number`;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
// this handles 2^53, Long is only needed for 2^64; this is effectively pbjs's forceNumber
return longTypeName(ctx);
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
return (0, ts_poet_1.code) `boolean`;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
return (0, ts_poet_1.code) `string`;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
if (options.env === options_1.EnvOption.NODE) {
return (0, ts_poet_1.code) `Buffer`;
}
else {
return (0, ts_poet_1.code) `Uint8Array`;
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_MESSAGE:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
return messageToTypeName(ctx, field.typeName, { ...typeOptions, repeated: isRepeated(field) });
default:
return (0, ts_poet_1.code) `${field.typeName}`;
}
}
exports.basicTypeName = basicTypeName;
/** Returns the Reader method for the primitive's read/write call. */
function toReaderCall(field) {
switch (field.type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
return "double";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
return "float";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
return "int32";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32:
return "uint32";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
return "sint32";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
return "fixed32";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
return "sfixed32";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
return "int64";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
return "uint64";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
return "sint64";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
return "fixed64";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
return "sfixed64";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
return "bool";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
return "string";
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
return "bytes";
default:
throw new Error(`Not a primitive field ${field}`);
}
}
exports.toReaderCall = toReaderCall;
function packedType(type) {
switch (type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
return 1;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
return 5;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
return 5;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
return 1;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
return 0;
default:
return undefined;
}
}
exports.packedType = packedType;
function defaultValue(ctx, field) {
const { typeMap, options, utils } = ctx;
switch (field.type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
return 0;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
// proto3 enforces enums starting at 0, however proto2 does not, so we have
// to probe and see if zero is an allowed value. If it's not, pick the first one.
// This is probably not great, but it's only used in fromJSON and fromPartial,
// and I believe the semantics of those in the proto2 world are generally undefined.
const enumProto = typeMap.get(field.typeName)[2];
const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
if (options.stringEnums) {
const enumType = messageToTypeName(ctx, field.typeName);
return (0, ts_poet_1.code) `${enumType}.${zerothValue.name}`;
}
else {
return zerothValue.number;
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
if (options.forceLong === options_1.LongOption.LONG) {
return (0, ts_poet_1.code) `${utils.Long}.UZERO`;
}
else if (options.forceLong === options_1.LongOption.STRING) {
return '"0"';
}
else {
return 0;
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
if (options.forceLong === options_1.LongOption.LONG) {
return (0, ts_poet_1.code) `${utils.Long}.ZERO`;
}
else if (options.forceLong === options_1.LongOption.STRING) {
return '"0"';
}
else {
return 0;
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
return false;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
return '""';
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
if (options.env === options_1.EnvOption.NODE) {
return "Buffer.alloc(0)";
}
else {
return "new Uint8Array()";
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_MESSAGE:
default:
return "undefined";
}
}
exports.defaultValue = defaultValue;
/** Creates code that checks that the field is not the default value. Supports scalars and enums. */
function notDefaultCheck(ctx, field, messageOptions, place) {
const { typeMap, options } = ctx;
const isOptional = isOptionalProperty(field, messageOptions, options);
const maybeNotUndefinedAnd = isOptional ? `${place} !== undefined && ` : "";
switch (field.type) {
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== 0`;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
// proto3 enforces enums starting at 0, however proto2 does not, so we have
// to probe and see if zero is an allowed value. If it's not, pick the first one.
// This is probably not great, but it's only used in fromJSON and fromPartial,
// and I believe the semantics of those in the proto2 world are generally undefined.
const enumProto = typeMap.get(field.typeName)[2];
const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
if (options.stringEnums) {
const enumType = messageToTypeName(ctx, field.typeName);
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${enumType}.${zerothValue.name}`;
}
else {
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${zerothValue.number}`;
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
if (options.forceLong === options_1.LongOption.LONG) {
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} !${place}.isZero()`;
}
else if (options.forceLong === options_1.LongOption.STRING) {
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== "0"`;
}
else {
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== 0`;
}
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
return (0, ts_poet_1.code) `${place} === true`;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ""`;
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place}.length !== 0`;
default:
throw new Error("Not implemented for the given type.");
}
}
exports.notDefaultCheck = notDefaultCheck;
/** Scans all of the proto files in `request` and builds a map of proto typeName -> TS module/name. */
function createTypeMap(request, options) {
const typeMap = new Map();
for (const file of request.protoFile) {
// We assume a file.name of google/protobuf/wrappers.proto --> a module path of google/protobuf/wrapper.ts
const moduleName = file.name.replace(".proto", "");
// So given a fullName like FooMessage_InnerMessage, proto will see that as package.name.FooMessage.InnerMessage
function saveMapping(tsFullName, desc, s, protoFullName) {
// package is optional, but make sure we have a dot-prefixed type name either way
const prefix = file.package.length === 0 ? "" : `.${file.package}`;
typeMap.set(`${prefix}.${protoFullName}`, [moduleName, tsFullName, desc]);
}
(0, visit_1.visit)(file, sourceInfo_1.default.empty(), saveMapping, options, saveMapping);
}
return typeMap;
}
exports.createTypeMap = createTypeMap;
/** A "Scalar Value Type" as defined in https://developers.google.com/protocol-buffers/docs/proto3#scalar */
function isScalar(field) {
const scalarTypes = [
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING,
ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES,
];
return scalarTypes.includes(field.type);
}
exports.isScalar = isScalar;
// When useOptionals='messages', non-scalar fields are translated into optional
// properties. When useOptionals='all', all fields are translated into
// optional properties, with the exception of map Entry key/values, which must
// always be present.
// OneOf fields are always optional, whenever oneof=unions option not in use.
function isOptionalProperty(field, messageOptions, options) {
const optionalMessages = options.useOptionals === true || options.useOptionals === "messages" || options.useOptionals === "all";
const optionalAll = options.useOptionals === "all";
return ((optionalMessages && isMessage(field) && !isRepeated(field)) ||
(optionalAll && !(messageOptions === null || messageOptions === void 0 ? void 0 : messageOptions.mapEntry)) ||
// don't bother verifying that oneof is not union. union oneofs generate their own properties.
isWithinOneOf(field) ||
field.proto3Optional);
}
exports.isOptionalProperty = isOptionalProperty;
/** This includes all scalars, enums and the [groups type](https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/DescriptorProtos.FieldDescriptorProto.Type.html#TYPE_GROUP) */
function isPrimitive(field) {
return !isMessage(field);
}
exports.isPrimitive = isPrimitive;
function isBytes(field) {
return field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES;
}
exports.isBytes = isBytes;
function isMessage(field) {
return field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_MESSAGE;
}
exports.isMessage = isMessage;
function isEnum(field) {
return field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM;
}
exports.isEnum = isEnum;
function isWithinOneOf(field) {
return field.hasOwnProperty("oneofIndex");
}
exports.isWithinOneOf = isWithinOneOf;
function isWithinOneOfThatShouldBeUnion(options, field) {
return isWithinOneOf(field) && options.oneof === options_1.OneofOption.UNIONS && !field.proto3Optional;
}
exports.isWithinOneOfThatShouldBeUnion = isWithinOneOfThatShouldBeUnion;
function isRepeated(field) {
return field.label === ts_proto_descriptors_1.FieldDescriptorProto_Label.LABEL_REPEATED;
}
exports.isRepeated = isRepeated;
function isLong(field) {
return basicLongWireType(field.type) !== undefined;
}
exports.isLong = isLong;
function isWholeNumber(field) {
return (field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32 ||
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64);
}
exports.isWholeNumber = isWholeNumber;
function isMapType(ctx, messageDesc, field) {
return detectMapType(ctx, messageDesc, field) !== undefined;
}
exports.isMapType = isMapType;
function isObjectId(field) {
// need to use endsWith instead of === because objectid could be imported from an external proto file
return field.typeName.endsWith(".ObjectId");
}
exports.isObjectId = isObjectId;
function isTimestamp(field) {
return field.typeName === ".google.protobuf.Timestamp";
}
exports.isTimestamp = isTimestamp;
function isValueType(ctx, field) {
return valueTypeName(ctx, field.typeName) !== undefined;
}
exports.isValueType = isValueType;
function isAnyValueType(field) {
return isAnyValueTypeName(field.typeName);
}
exports.isAnyValueType = isAnyValueType;
function isAnyValueTypeName(typeName) {
return typeName === "google.protobuf.Value" || typeName === ".google.protobuf.Value";
}
exports.isAnyValueTypeName = isAnyValueTypeName;
function isBytesValueType(field) {
return field.typeName === ".google.protobuf.BytesValue";
}
exports.isBytesValueType = isBytesValueType;
function isFieldMaskType(field) {
return isFieldMaskTypeName(field.typeName);
}
exports.isFieldMaskType = isFieldMaskType;
function isFieldMaskTypeName(typeName) {
return typeName === "google.protobuf.FieldMask" || typeName === ".google.protobuf.FieldMask";
}
exports.isFieldMaskTypeName = isFieldMaskTypeName;
function isListValueType(field) {
return isListValueTypeName(field.typeName);
}
exports.isListValueType = isListValueType;
function isListValueTypeName(typeName) {
return typeName === "google.protobuf.ListValue" || typeName === ".google.protobuf.ListValue";
}
exports.isListValueTypeName = isListValueTypeName;
function isStructType(field) {
return isStructTypeName(field.typeName);
}
exports.isStructType = isStructType;
function isStructTypeName(typeName) {
return typeName === "google.protobuf.Struct" || typeName === ".google.protobuf.Struct";
}
exports.isStructTypeName = isStructTypeName;
function isLongValueType(field) {
return field.typeName === ".google.protobuf.Int64Value" || field.typeName === ".google.protobuf.UInt64Value";
}
exports.isLongValueType = isLongValueType;
function isEmptyType(typeName) {
return typeName === ".google.protobuf.Empty";
}
exports.isEmptyType = isEmptyType;
function valueTypeName(ctx, typeName) {
switch (typeName) {
case ".google.protobuf.StringValue":
return (0, ts_poet_1.code) `string`;
case ".google.protobuf.Int32Value":
case ".google.protobuf.UInt32Value":
case ".google.protobuf.DoubleValue":
case ".google.protobuf.FloatValue":
return (0, ts_poet_1.code) `number`;
case ".google.protobuf.Int64Value":
case ".google.protobuf.UInt64Value":
// return options ? longTypeName(options) : code`number`;
return longTypeName(ctx);
case ".google.protobuf.BoolValue":
return (0, ts_poet_1.code) `boolean`;
case ".google.protobuf.BytesValue":
return ctx.options.env === options_1.EnvOption.NODE
? (0, ts_poet_1.code) `Buffer`
: ctx.options.useJsonWireFormat
? (0, ts_poet_1.code) `string`
: (0, ts_poet_1.code) `Uint8Array`;
case ".google.protobuf.ListValue":
return ctx.options.useReadonlyTypes ? (0, ts_poet_1.code) `ReadonlyArray<any>` : (0, ts_poet_1.code) `Array<any>`;
case ".google.protobuf.Value":
return (0, ts_poet_1.code) `any`;
case ".google.protobuf.Struct":
return ctx.options.useReadonlyTypes ? (0, ts_poet_1.code) `{readonly [key: string]: any}` : (0, ts_poet_1.code) `{[key: string]: any}`;
case ".google.protobuf.FieldMask":
return ctx.options.useJsonWireFormat
? (0, ts_poet_1.code) `string`
: ctx.options.useReadonlyTypes
? (0, ts_poet_1.code) `readonly string[]`
: (0, ts_poet_1.code) `string[]`;
case ".google.protobuf.Duration":
return ctx.options.useJsonWireFormat ? (0, ts_poet_1.code) `string` : undefined;
case ".google.protobuf.Timestamp":
return ctx.options.useJsonWireFormat ? (0, ts_poet_1.code) `string` : undefined;
default:
return undefined;
}
}
exports.valueTypeName = valueTypeName;
function wrapperTypeName(typeName) {
switch (typeName) {
case ".google.protobuf.StringValue":
case ".google.protobuf.Int32Value":
case ".google.protobuf.UInt32Value":
case ".google.protobuf.DoubleValue":
case ".google.protobuf.FloatValue":
case ".google.protobuf.Int64Value":
case ".google.protobuf.UInt64Value":
case ".google.protobuf.BoolValue":
case ".google.protobuf.BytesValue":
case ".google.protobuf.ListValue":
case ".google.protobuf.Timestamp":
case ".google.protobuf.Struct":
return typeName.split(".")[3];
default:
return undefined;
}
}
exports.wrapperTypeName = wrapperTypeName;
function longTypeName(ctx) {
const { options, utils } = ctx;
if (options.forceLong === options_1.LongOption.LONG) {
return (0, ts_poet_1.code) `${utils.Long}`;
}
else if (options.forceLong === options_1.LongOption.STRING) {
return (0, ts_poet_1.code) `string`;
}
else {
return (0, ts_poet_1.code) `number`;
}
}
/** Maps `.some_proto_namespace.Message` to a TypeName. */
function messageToTypeName(ctx, protoType, typeOptions = {}) {
const { options, typeMap } = ctx;
// Watch for the wrapper types `.google.protobuf.*Value`. If we're mapping
// them to basic built-in types, we union the type with undefined to
// indicate the value is optional. Exceptions:
// - If the field is repeated, values cannot be undefined.
// - If useOptionals='messages' or useOptionals='all', all non-scalar types
// are already optional properties, so there's no need for that union.
let valueType = valueTypeName(ctx, protoType);
if (!typeOptions.keepValueType && valueType) {
if (!!typeOptions.repeated ||
options.useOptionals === true ||
options.useOptionals === "messages" ||
options.useOptionals === "all") {
return valueType;
}
return (0, ts_poet_1.code) `${valueType} | undefined`;
}
// Look for other special prototypes like Timestamp that aren't technically wrapper types
if (!typeOptions.keepValueType && protoType === ".google.protobuf.Timestamp") {
if (options.useDate == options_1.DateOption.DATE) {
return (0, ts_poet_1.code) `Date`;
}
if (options.useDate == options_1.DateOption.STRING) {
return (0, ts_poet_1.code) `string`;
}
}
// need to use endsWith instead of === because objectid could be imported from an external proto file
if (!typeOptions.keepValueType && options.useMongoObjectId && protoType.endsWith(".ObjectId")) {
return (0, ts_poet_1.code) `mongodb.ObjectId`;
}
const [module, type] = toModuleAndType(typeMap, protoType);
return (0, ts_poet_1.code) `${(0, utils_1.impProto)(options, module, type)}`;
}
exports.messageToTypeName = messageToTypeName;
/** Breaks `.some_proto_namespace.Some.Message` into `['some_proto_namespace', 'Some_Message', Descriptor]. */
function toModuleAndType(typeMap, protoType) {
return typeMap.get(protoType) || (0, utils_1.fail)(`No type found for ${protoType}`);
}
function getEnumMethod(ctx, enumProtoType, methodSuffix) {
const [module, type] = toModuleAndType(ctx.typeMap, enumProtoType);
return (0, utils_1.impProto)(ctx.options, module, `${(0, case_1.camelCase)(type)}${methodSuffix}`);
}
exports.getEnumMethod = getEnumMethod;
/** Return the TypeName for any field (primitive/message/etc.) as exposed in the interface. */
function toTypeName(ctx, messageDesc, field) {
let type = basicTypeName(ctx, field, { keepValueType: false });
if (isRepeated(field)) {
const mapType = detectMapType(ctx, messageDesc, field);
if (mapType) {
const { keyType, valueType } = mapType;
if (ctx.options.useMapType) {
return (0, ts_poet_1.code) `Map<${keyType}, ${valueType}>`;
}
return (0, ts_poet_1.code) `{ [key: ${keyType} ]: ${valueType} }`;
}
if (ctx.options.useReadonlyTypes) {
return (0, ts_poet_1.code) `readonly ${type}[]`;
}
return (0, ts_poet_1.code) `${type}[]`;
}
if (isValueType(ctx, field)) {
// google.protobuf.*Value types are already unioned with `undefined`
// in messageToTypeName, so no need to consider them for that here.
return type;
}
// By default (useOptionals='none', oneof=properties), non-scalar fields
// outside oneofs and all fields within a oneof clause need to be unioned
// with `undefined` to indicate the value is optional.
//
// When useOptionals='messages' or useOptionals='all', non-scalar fields are
// translated to optional properties, so no need for the union with
// `undefined` here.
//
// When oneof=unions, we generate a single property for the entire `oneof`
// clause, spelling each option out inside a large type union. No need for
// union with `undefined` here, either.
const { options } = ctx;
if ((!isWithinOneOf(field) &&
isMessage(field) &&
(options.useOptionals === false || options.useOptionals === "none")) ||
(isWithinOneOf(field) && options.oneof === options_1.OneofOption.PROPERTIES) ||
(isWithinOneOf(field) && field.proto3Optional)) {
return (0, ts_poet_1.code) `${type} | undefined`;
}
return type;
}
exports.toTypeName = toTypeName;
function detectMapType(ctx, messageDesc, fieldDesc) {
var _a;
const { typeMap } = ctx;
if (fieldDesc.label === ts_proto_descriptors_1.FieldDescriptorProto_Label.LABEL_REPEATED &&
fieldDesc.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_MESSAGE) {
const mapType = typeMap.get(fieldDesc.typeName)[2];
if (!((_a = mapType.options) === null || _a === void 0 ? void 0 : _a.mapEntry))
return undefined;
const [keyField, valueField] = mapType.field;
const keyType = toTypeName(ctx, messageDesc, keyField);
// use basicTypeName because we don't need the '| undefined'
const valueType = basicTypeName(ctx, valueField);
return { messageDesc: mapType, keyField, keyType, valueField, valueType };
}
return undefined;
}
exports.detectMapType = detectMapType;
function rawRequestType(ctx, methodDesc, typeOptions = {}) {
return messageToTypeName(ctx, methodDesc.inputType, typeOptions);
}
exports.rawRequestType = rawRequestType;
function observableType(ctx) {
if (ctx.options.useAsyncIterable) {
return (0, ts_poet_1.code) `AsyncIterable`;
}
return (0, ts_poet_1.code) `${(0, ts_poet_1.imp)("Observable@rxjs")}`;
}
exports.observableType = observableType;
function requestType(ctx, methodDesc, partial = false) {
let typeName = rawRequestType(ctx, methodDesc, { keepValueType: true });
if (partial) {
typeName = (0, ts_poet_1.code) `${ctx.utils.DeepPartial}<${typeName}>`;
}
if (methodDesc.clientStreaming) {
return (0, ts_poet_1.code) `${observableType(ctx)}<${typeName}>`;
}
return typeName;
}
exports.requestType = requestType;
function responseType(ctx, methodDesc, typeOptions = {}) {
return messageToTypeName(ctx, methodDesc.outputType, { keepValueType: true });
}
exports.responseType = responseType;
function responsePromise(ctx, methodDesc) {
return (0, ts_poet_1.code) `Promise<${responseType(ctx, methodDesc, { keepValueType: true })}>`;
}
exports.responsePromise = responsePromise;
function responseObservable(ctx, methodDesc) {
return (0, ts_poet_1.code) `${observableType(ctx)}<${responseType(ctx, methodDesc, { keepValueType: true })}>`;
}
exports.responseObservable = responseObservable;
function responsePromiseOrObservable(ctx, methodDesc) {
const { options } = ctx;
if (options.returnObservable || methodDesc.serverStreaming) {
return responseObservable(ctx, methodDesc);
}
return responsePromise(ctx, methodDesc);
}
exports.responsePromiseOrObservable = responsePromiseOrObservable;
function detectBatchMethod(ctx, fileDesc, serviceDesc, methodDesc) {
const { typeMap } = ctx;
const nameMatches = methodDesc.name.startsWith("Batch");
const inputType = typeMap.get(methodDesc.inputType);
const outputType = typeMap.get(methodDesc.outputType);
if (nameMatches && inputType && outputType) {
// TODO: This might be enums?
const inputTypeDesc = inputType[2];
const outputTypeDesc = outputType[2];
if (hasSingleRepeatedField(inputTypeDesc) && hasSingleRepeatedField(outputTypeDesc)) {
const singleMethodName = methodDesc.name.replace("Batch", "Get");
const inputFieldName = inputTypeDesc.field[0].name;
const inputType = basicTypeName(ctx, inputTypeDesc.field[0]); // e.g. repeated string -> string
const outputFieldName = outputTypeDesc.field[0].name;
let outputType = basicTypeName(ctx, outputTypeDesc.field[0]); // e.g. repeated Entity -> Entity
const mapType = detectMapType(ctx, outputTypeDesc, outputTypeDesc.field[0]);
if (mapType) {
outputType = mapType.valueType;
}
const uniqueIdentifier = `${(0, utils_1.maybePrefixPackage)(fileDesc, serviceDesc.name)}.${methodDesc.name}`;
return {
methodDesc: methodDesc,
uniqueIdentifier,
singleMethodName: utils_1.FormattedMethodDescriptor.formatName(singleMethodName, ctx.options),
inputFieldName,
inputType,
outputFieldName,
outputType,
mapType: !!mapType,
};
}
}
return undefined;
}
exports.detectBatchMethod = detectBatchMethod;
function hasSingleRepeatedField(messageDesc) {
return messageDesc.field.length == 1 && messageDesc.field[0].label === ts_proto_descriptors_1.FieldDescriptorProto_Label.LABEL_REPEATED;
}