UNPKG

ts-proto

Version:

[![npm](https://img.shields.io/npm/v/ts-proto)](https://www.npmjs.com/package/ts-proto) [![build](https://github.com/stephenh/ts-proto/workflows/Build/badge.svg)](https://github.com/stephenh/ts-proto/actions)

681 lines (680 loc) 34.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = 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 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 ts_poet_1.code `boolean`; case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING: return ts_poet_1.code `string`; case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES: if (options.env === options_1.EnvOption.NODE) { return ts_poet_1.code `Buffer`; } else { return 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 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 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 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 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 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 ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== ${enumType}.${zerothValue.name}`; } else { return 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 ts_poet_1.code `${maybeNotUndefinedAnd} !${place}.isZero()`; } else if (options.forceLong === options_1.LongOption.STRING) { return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== "0"`; } else { return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== 0`; } case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL: return ts_poet_1.code `${place} === true`; case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING: return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== ""`; case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES: return 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]); } 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. 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)) || 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 ts_poet_1.code `string`; case '.google.protobuf.Int32Value': case '.google.protobuf.UInt32Value': case '.google.protobuf.DoubleValue': case '.google.protobuf.FloatValue': return 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 ts_poet_1.code `boolean`; case '.google.protobuf.BytesValue': return ctx.options.env === options_1.EnvOption.NODE ? ts_poet_1.code `Buffer` : ctx.options.useJsonWireFormat ? ts_poet_1.code `string` : ts_poet_1.code `Uint8Array`; case '.google.protobuf.ListValue': return ts_poet_1.code `Array<any>`; case '.google.protobuf.Value': return ts_poet_1.code `any`; case '.google.protobuf.Struct': return ts_poet_1.code `{[key: string]: any}`; case '.google.protobuf.FieldMask': return ctx.options.useJsonWireFormat ? ts_poet_1.code `string` : ts_poet_1.code `string[]`; case '.google.protobuf.Duration': return ctx.options.useJsonWireFormat ? ts_poet_1.code `string` : undefined; case '.google.protobuf.Timestamp': return ctx.options.useJsonWireFormat ? 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 ts_poet_1.code `${utils.Long}`; } else if (options.forceLong === options_1.LongOption.STRING) { return ts_poet_1.code `string`; } else { return 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 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 ts_poet_1.code `Date`; } if (options.useDate == options_1.DateOption.STRING) { return 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 ts_poet_1.code `mongodb.ObjectId`; } const [module, type] = toModuleAndType(typeMap, protoType); return ts_poet_1.code `${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) || utils_1.fail(`No type found for ${protoType}`); } function getEnumMethod(ctx, enumProtoType, methodSuffix) { const [module, type] = toModuleAndType(ctx.typeMap, enumProtoType); return utils_1.impProto(ctx.options, module, `${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; return ts_poet_1.code `{ [key: ${keyType} ]: ${valueType} }`; } return 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 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) { return messageToTypeName(ctx, methodDesc.inputType); } exports.rawRequestType = rawRequestType; function requestType(ctx, methodDesc, partial = false) { let typeName = rawRequestType(ctx, methodDesc); if (partial) { typeName = ts_poet_1.code `${ctx.utils.DeepPartial}<${typeName}>`; } if (methodDesc.clientStreaming) { return ts_poet_1.code `${ts_poet_1.imp('Observable@rxjs')}<${typeName}>`; } return typeName; } exports.requestType = requestType; function responseType(ctx, methodDesc, typeOptions = {}) { return messageToTypeName(ctx, methodDesc.outputType, typeOptions); } exports.responseType = responseType; function responsePromise(ctx, methodDesc) { return ts_poet_1.code `Promise<${responseType(ctx, methodDesc)}>`; } exports.responsePromise = responsePromise; function responseObservable(ctx, methodDesc) { return ts_poet_1.code `${ts_poet_1.imp('Observable@rxjs')}<${responseType(ctx, methodDesc)}>`; } 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 = `${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; }