UNPKG

@cosmology/ast

Version:
292 lines (255 loc) 7.3 kB
import { ProtoType, ProtoField } from '@cosmology/types'; import { pascal } from 'case'; import { AminoParseContext, ProtoParseContext } from '../context'; import { shouldOmitEmpty } from '@cosmology/utils'; export const SCALAR_TYPES = [ 'string', 'double', 'float', 'int32', 'uint32', 'sint32', 'fixed32', 'sfixed32', 'int64', 'uint64', 'sint64', 'fixed64', 'sfixed64', 'bytes', 'bool' ]; export const GOOGLE_TYPES = [ 'google.protobuf.Timestamp', 'google.protobuf.Duration', 'google.protobuf.Any' ]; // https://github.com/protobufjs/protobuf.js/blob/master/src/types.js#L38-L54 export const types = { basic: { double: 1, float: 5, int32: 0, uint32: 0, sint32: 0, fixed32: 5, sfixed32: 5, int64: 0, uint64: 0, sint64: 0, fixed64: 1, sfixed64: 1, bool: 0, string: 2, bytes: 2 }, defaults: { double: 0, float: 0, int32: 0, uint32: 0, sint32: 0, fixed32: 0, sfixed32: 0, int64: 0, uint64: 0, sint64: 0, fixed64: 0, sfixed64: 0, bool: false, string: '', bytes: [], undefined: null }, long: { int64: 0, uint64: 0, sint64: 0, fixed64: 1, sfixed64: 1 }, mapKey: { int32: 0, uint32: 0, sint32: 0, fixed32: 5, sfixed32: 5, int64: 0, uint64: 0, sint64: 0, fixed64: 1, sfixed64: 1, bool: 0, string: 2 }, packed: { double: 1, float: 5, int32: 0, uint32: 0, sint32: 0, fixed32: 5, sfixed32: 5, int64: 0, uint64: 0, sint64: 0, fixed64: 1, sfixed64: 1, bool: 0 } }; export const getWireNumber = (type) => { if (types.basic.hasOwnProperty(type)) { return types.basic[type]; } return 2; }; export const getPackedWireNumber = (type) => { if (types.packed.hasOwnProperty(type)) { return types.packed[type]; } return 2; }; export const getTagNumber = (field: ProtoField) => { let wire = getWireNumber(field.type); if (field.parsedType.type === 'Enum') { wire = 0; } if (field.rule === 'repeated') { wire = 2; } return ((field.id << 3) | wire) >>> 0; }; const lowerFirst = (str: string) => { return str.charAt(0).toLowerCase() + str.substring(1); }; const upperFirst = (str: string) => { return str.charAt(0).toUpperCase() + str.substring(1); }; export const getEnumToJsonName = (name) => { return lowerFirst(name) + 'ToJSON'; }; export const getEnumFromJsonName = (name) => { return lowerFirst(name) + 'FromJSON'; }; export const getFieldsTypeName = (field: ProtoField) => { if (!field?.scope || field?.scope.length <= 1) { if(field.parsedType){ return field.parsedType.name; } else { const temp = field.type.split("."); return temp[temp.length - 1]; } } const [_pkg, ...scopes] = field.scope; return [...scopes, field.parsedType.name].join('_'); }; export const getKeyTypeEntryName = (typeName: string, prop: string) => { return `${typeName}_${pascal(prop)}Entry`; }; export const getBaseCreateTypeFuncName = (name) => { return `createBase${upperFirst(name)}`; }; export const getOneOfs = (type: ProtoType) => { const keys = Object.keys(type.oneofs ?? {}); if (!keys.length) return []; if (keys.length !== 1) throw new Error('getOneOfs() oneofs cardinality not known!'); return type.oneofs[keys[0]].oneof; }; export const getFieldOptionality = ( context: ProtoParseContext | AminoParseContext, field: ProtoField, isOneOf: boolean ) => { const isScalarDefaultToNullable = context.pluginValue('prototypes.isScalarDefaultToNullable'); if(field?.options?.['(gogoproto.moretags)'] && getOptionDeprecated(field?.options?.['(gogoproto.moretags)']) === 'true'){ return true } if (isArrayField(field) || isEnumField(field) || (!isScalarDefaultToNullable && isScalarField(field))) { // these field types are required by default! if (isOneOf) { return true; } return false; } return true; }; export const getFieldOptionalityForAmino = ( context: ProtoParseContext | AminoParseContext, field: ProtoField, isOneOf: boolean ) => { const useProtoOptionality = context.pluginValue('aminoEncoding.useProtoOptionality'); if(field?.options?.['(gogoproto.moretags)'] && getOptionDeprecated(field?.options?.['(gogoproto.moretags)']) === 'true'){ return true } if(useProtoOptionality){ return getFieldOptionalityForDefaults(context, field, isOneOf); } if (isOneOf) { return true; } return shouldOmitEmpty(context, field) }; export const isScalarField = ( field: ProtoField ) => { return SCALAR_TYPES.includes(field.type); }; export const isArrayField = ( field: ProtoField ) => { return field.rule === 'repeated'; }; export const isEnumField = ( field: ProtoField ) => { return field.parsedType?.type === 'Enum' }; export const isMapField = ( field: ProtoField ) => { return field.keyType; }; export const getFieldOptionalityForDefaults = ( context: ProtoParseContext | AminoParseContext, field: ProtoField, isOneOf: boolean ) => { const fieldDefaultIsOptional = context.pluginValue('prototypes.fieldDefaultIsOptional'); const useOptionalNullable = context.pluginValue('prototypes.useOptionalNullable'); const isScalarDefaultToNullable = !field?.options?.['(gogoproto.nullable)'] && context.pluginValue('prototypes.isScalarDefaultToNullable'); if(field?.options?.['(gogoproto.moretags)'] && getOptionDeprecated(field?.options?.['(gogoproto.moretags)']) === 'true'){ return true } if (isArrayField(field) || isEnumField(field) || !isScalarDefaultToNullable && isScalarField(field) || isMapField(field)) { // these field types are required by default! if (isOneOf || (useOptionalNullable && field?.options?.['(gogoproto.nullable)'])) { return true; } return false; } const gogoprotoNullable = field?.options?.['(gogoproto.nullable)'] ?? true; return isOneOf || ( useOptionalNullable && gogoprotoNullable ) || ( // this would only happen if previous predicate is false, // so lets ensure not to override required properties when gogoproto.nullable=false !useOptionalNullable && fieldDefaultIsOptional ); }; /** * get deprecated option from string, return true/false as string * @param input * @returns string */ export const getOptionDeprecated = (input: string) =>{ // Regular expression to match deprecated value with optional spaces const deprecatedRegex = /\s*deprecated:\s*(true|false)\s*/; // Extract the deprecated value const match = input.match(deprecatedRegex); if(match && match[1]) { return match[1] } return null }