UNPKG

@cosmology/ast

Version:
529 lines (479 loc) 17.2 kB
import * as t from "@babel/types"; import { BILLION, memberExpressionOrIdentifier, shorthandProperty, TypeLong, } from "../../../utils"; import { protoFieldsToArray } from "../utils"; import { ToAminoParseField, toAminoParseField } from "./index"; import { getFieldOptionality, getOneOfs } from "../../proto"; import { ProtoField } from "@cosmology/types"; export const toAmino = { defaultType(args: ToAminoParseField, omitEmpty?: boolean) { const useOmitEmpty = !!args.context.pluginValue( "aminoEncoding.legacy.useOmitEmpty" ); if ( !(useOmitEmpty && omitEmpty) && args.field.name === args.context.aminoCaseField(args.field) && args.scope.length === 1 ) { return shorthandProperty(args.field.name); } let valueExpr = useOmitEmpty && omitEmpty ? this.omitDefaultMemberExpressionOrIdentifier(args, args.scope) : memberExpressionOrIdentifier(args.scope); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), valueExpr ); }, long(args: ToAminoParseField, omitEmpty?: boolean) { const useOmitEmpty = !!args.context.pluginValue( "aminoEncoding.legacy.useOmitEmpty" ); const useNullHandling = !!args.context.pluginValue( "aminoEncoding.legacy.useNullHandling" ); let valueExpr = useOmitEmpty && omitEmpty ? this.omitDefaultMemberExpressionOrIdentifier(args, args.scope) : memberExpressionOrIdentifier(args.scope); const callExpression = useNullHandling ? t.optionalCallExpression : t.callExpression; return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), callExpression( useNullHandling ? t.optionalMemberExpression( valueExpr, t.identifier("toString"), false, true ) : t.memberExpression(valueExpr, t.identifier("toString")), [], true ) ); }, string(args: ToAminoParseField, omitEmpty?: boolean) { const useCosmosSDKDec = args.context.pluginValue( "aminoEncoding.customTypes.useCosmosSDKDec" ); const goPackage = args.context.ref.proto.options?.["go_package"]; if (useCosmosSDKDec) { const isCosmosSDKDec = (goPackage == "github.com/cosmos/cosmos-sdk/types" && args.field.options?.["(gogoproto.customtype)"] == "Dec") || args.field.options?.["(gogoproto.customtype)"] == "github.com/cosmos/cosmos-sdk/types.Dec" || args.field.options?.["(gogoproto.customtype)"] == "cosmossdk.io/math.LegacyDec"; if (isCosmosSDKDec) { args.context.addUtil("Decimal"); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), t.memberExpression( t.callExpression( t.memberExpression( t.identifier("Decimal"), t.identifier("fromUserInput") ), [ memberExpressionOrIdentifier(args.scope), t.numericLiteral(18), ] ), t.identifier("atomics") ) ); } } if ( args.field.name === args.context.aminoCaseField(args.field) && args.scope.length === 1 ) { return shorthandProperty(args.field.name); } return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), memberExpressionOrIdentifier(args.scope) ); }, stringArray(args: ToAminoParseField) { const useCosmosSDKDec = args.context.pluginValue( "aminoEncoding.customTypes.useCosmosSDKDec" ); if (useCosmosSDKDec) { const goPackage = args.context.ref.proto.options?.["go_package"]; const isCosmosSDKDec = (goPackage == "github.com/cosmos/cosmos-sdk/types" && args.field.options?.["(gogoproto.customtype)"] == "Dec") || args.field.options?.["(gogoproto.customtype)"] == "github.com/cosmos/cosmos-sdk/types.Dec" || args.field.options?.["(gogoproto.customtype)"] == "cosmossdk.io/math.LegacyDec"; if (isCosmosSDKDec) { return toAmino.scalarArray(args, arrayTypes.stringDec); } } if ( args.field.name === args.context.aminoCaseField(args.field) && args.scope.length === 1 ) { return shorthandProperty(args.field.name); } return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), memberExpressionOrIdentifier(args.scope) ); }, rawBytes(args: ToAminoParseField) { args.context.addUtil("fromUtf8"); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), t.callExpression( t.memberExpression(t.identifier("JSON"), t.identifier("parse")), [ t.callExpression(t.identifier("fromUtf8"), [ memberExpressionOrIdentifier(args.scope), ]), ] ) ); }, wasmByteCode(args: ToAminoParseField) { args.context.addUtil("toBase64"); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), t.callExpression(t.identifier("toBase64"), [ memberExpressionOrIdentifier(args.scope), ]) ); }, duration(args: ToAminoParseField) { const durationFormat = args.context.pluginValue( "prototypes.typingsFormat.duration" ); const updatedDuration = args.context.pluginValue( "prototypes.typingsFormat.updatedDuration" ); switch (durationFormat) { case "duration": if (updatedDuration) { return toAmino.durationType(args); } case "string": default: return toAmino.durationString(args); } }, // (duration * 1_000_000_000).toString(), durationString(args: ToAminoParseField) { const exp = t.binaryExpression( "*", memberExpressionOrIdentifier(args.scope), BILLION ); exp.extra = { parenthesized: true }; const value = t.callExpression( t.memberExpression(exp, t.identifier("toString")), [] ); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), value ); }, // (duration.seconds.toInt() * 1_000_000_000).toString(), // what about nanos? durationType(args: ToAminoParseField) { const exp = t.binaryExpression( "*", t.callExpression( t.memberExpression( t.memberExpression( memberExpressionOrIdentifier(args.scope), t.identifier("seconds") ), t.identifier("toInt") ), [] ), BILLION ); exp.extra = { parenthesized: true }; const value = t.callExpression( t.memberExpression(exp, t.identifier("toString")), [] ); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), value ); }, height(args: ToAminoParseField) { args.context.addUtil("omitDefault"); const value = t.objectExpression([ t.objectProperty( t.identifier(args.context.aminoCasingFn("revision_height")), t.optionalCallExpression( t.optionalMemberExpression( t.callExpression(t.identifier("omitDefault"), [ t.memberExpression( memberExpressionOrIdentifier(args.scope), t.identifier("revisionHeight") ), ]), t.identifier("toString"), false, true ), [], false ) ), // t.objectProperty( t.identifier(args.context.aminoCasingFn("revision_number")), t.optionalCallExpression( t.optionalMemberExpression( t.callExpression(t.identifier("omitDefault"), [ t.memberExpression( memberExpressionOrIdentifier(args.scope), t.identifier("revisionNumber") ), ]), t.identifier("toString"), false, true ), [], false ) ), ]); const cond = t.conditionalExpression( memberExpressionOrIdentifier(args.scope), value, t.objectExpression([]) ); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), cond ); }, coinAmount(args: ToAminoParseField) { const longType = TypeLong.getType(args.context); switch (longType) { case "BigInt": return t.memberExpression( memberExpressionOrIdentifier(args.scope), t.identifier("amount") ); case "Long": default: TypeLong.addUtil(args.context); return t.callExpression( t.memberExpression( t.callExpression(TypeLong.getFromValue(args.context), [ t.memberExpression( memberExpressionOrIdentifier(args.scope), t.identifier("amount") ), ]), t.identifier("toString") ), [] ); } }, coin(args: ToAminoParseField) { const value = t.objectExpression([ t.objectProperty( t.identifier("denom"), t.memberExpression( memberExpressionOrIdentifier(args.scope), t.identifier("denom") ) ), t.objectProperty(t.identifier("amount"), toAmino.coinAmount(args)), ]); return t.objectProperty( t.identifier(args.context.aminoCaseField(args.field)), value ); }, type({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }: ToAminoParseField) { /// TODO (can this be refactored out? e.g. no recursive calls in this file?) /// BEGIN const Type = context.getTypeFromCurrentPath(field, currentProtoPath); const parentField = field; const oneOfs = getOneOfs(Type); const properties = protoFieldsToArray(Type).map((field) => { const isOneOf = oneOfs.includes(field.name); const isOptional = getFieldOptionality(context, field, isOneOf); if (parentField.import) currentProtoPath = parentField.import; return toAminoParseField({ context, field, currentProtoPath, scope: [...scope], fieldPath: [...fieldPath], nested, isOptional, // TODO how to handle nested optionality }); }); /// END return t.objectProperty( t.identifier(context.aminoCaseField(field)), t.objectExpression(properties) ); }, typeArray({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }: ToAminoParseField) { ////// const variable = "el" + nested; const f = JSON.parse(JSON.stringify(field)); // clone const varProto: ProtoField = { ...f, }; varProto.name = variable; varProto.options["(telescope:orig)"] = variable; varProto.options["(telescope:name)"] = variable; varProto.options["(telescope:camel)"] = variable; ////// if (field.parsedType.type !== "Type") { throw new Error("Arrays only support types[Type] right now."); } const Type = context.getTypeFromCurrentPath(field, currentProtoPath); const parentField = field; const oneOfs = getOneOfs(Type); const properties = protoFieldsToArray(Type).map((field) => { const isOneOf = oneOfs.includes(field.name); const isOptional = getFieldOptionality(context, field, isOneOf); if (parentField.import) currentProtoPath = parentField.import; return toAminoParseField({ context, field, currentProtoPath, scope: [variable], fieldPath: [varProto], nested: nested + 1, isOptional, // TODO how to handle nested optionality }); }); const expr = t.callExpression( t.memberExpression( memberExpressionOrIdentifier(scope), t.identifier("map") ), [ t.arrowFunctionExpression( [t.identifier(variable)], t.objectExpression(properties) ), ] ); return t.objectProperty( t.identifier(context.aminoCaseField(field)), expr ); }, scalarArray( { context, field, currentProtoPath, scope, nested, isOptional, }: ToAminoParseField, arrayTypeAstFunc: Function ) { const variable = "el" + nested; const expr = t.callExpression( t.memberExpression( memberExpressionOrIdentifier(scope), t.identifier("map") ), [ t.arrowFunctionExpression( [t.identifier(variable)], arrayTypeAstFunc(variable, { context, field, currentProtoPath, scope, nested, isOptional, }) ), ] ); return t.objectProperty( t.identifier(context.aminoCaseField(field)), expr ); }, pubkey(args: ToAminoParseField) { args.context.addUtil("decodePubkey"); return t.objectProperty( t.identifier(args.field.name), t.tsNonNullExpression( t.callExpression(t.identifier("decodePubkey"), [ t.identifier(args.field.name), ]) ) ); }, omitDefaultMemberExpressionOrIdentifier(args: ToAminoParseField, names) { args.context.addUtil("omitDefault"); return t.callExpression(t.identifier("omitDefault"), [ memberExpressionOrIdentifier(names), ]); }, }; export const arrayTypes = { long(varname: string) { return t.callExpression( t.memberExpression( memberExpressionOrIdentifier([varname]), t.identifier("toString") ), [] ); }, stringDec(varname: string, args: ToAminoParseField) { args.context.addUtil("Decimal"); return t.memberExpression( t.callExpression( t.memberExpression( t.identifier("Decimal"), t.identifier("fromUserInput") ), [memberExpressionOrIdentifier([varname]), t.numericLiteral(18)] ), t.identifier("atomics") ); }, };