UNPKG

@cosmology/ast

Version:
743 lines (658 loc) 20.9 kB
import * as t from "@babel/types"; import { fromAminoMethod } from "./index"; import { identifier, callExpression, TypeLong, BILLION } from "../../../utils"; import { getFieldsTypeName, getInterfaceFromAminoName } from ".."; import { getDefaultTSTypeFromProtoType, getFieldNames } from "../../types"; import { ProtoType } from "@cosmology/types"; import { ProtoParseContext } from "../../context"; import { camel } from "@cosmology/utils"; const setNotUndefinedAndNotNull = ( args: fromAminoMethod, value?: t.Expression ): t.Statement => { const { propName, origName } = getFieldNames(args.field); return t.ifStatement( t.logicalExpression( "&&", t.binaryExpression( "!==", t.memberExpression(t.identifier("object"), t.identifier(origName)), t.identifier("undefined") ), t.binaryExpression( "!==", t.memberExpression(t.identifier("object"), t.identifier(origName)), t.nullLiteral() ) ), t.blockStatement([ t.expressionStatement( t.assignmentExpression( "=", t.memberExpression(t.identifier("message"), t.identifier(propName)), value ? value : t.memberExpression(t.identifier("object"), t.identifier(origName)) ) ), ]) ); }; export const fromAmino = { // message.sender = object.sender ?? ""; string(args: fromAminoMethod) { return setNotUndefinedAndNotNull(args); }, // message.disableMacros = object.disableMacros ?? false; bool(args: fromAminoMethod) { return setNotUndefinedAndNotNull(args); }, // message.doubleValue = object.doubleValue ?? 0; number(args: fromAminoMethod) { return setNotUndefinedAndNotNull(args); }, int32(args: fromAminoMethod) { return fromAmino.number(args); }, uint32(args: fromAminoMethod) { return fromAmino.number(args); }, sint32(args: fromAminoMethod) { return fromAmino.number(args); }, fixed32(args: fromAminoMethod) { return fromAmino.number(args); }, sfixed32(args: fromAminoMethod) { return fromAmino.number(args); }, double(args: fromAminoMethod) { return fromAmino.number(args); }, float(args: fromAminoMethod) { return fromAmino.number(args); }, // if( object.myInt64Value !== undefined && object.myInt64Value !== null ) { message.myInt64Value = Long.fromValue(object.myInt64Value) } long(args: fromAminoMethod) { const { origName } = getFieldNames(args.field); TypeLong.addUtil(args.context); const callExpr = t.callExpression(TypeLong.getFromString(args.context), [ t.memberExpression(t.identifier("object"), t.identifier(origName)), ]); return setNotUndefinedAndNotNull(args, callExpr); }, int64(args: fromAminoMethod) { return fromAmino.long(args); }, uint64(args: fromAminoMethod) { return fromAmino.long(args); }, sint64(args: fromAminoMethod) { return fromAmino.long(args); }, fixed64(args: fromAminoMethod) { return fromAmino.long(args); }, sfixed64(args: fromAminoMethod) { return fromAmino.long(args); }, protoType(args: fromAminoMethod) { const { origName } = getFieldNames(args.field); const name = args.context.getTypeName(args.field); return setNotUndefinedAndNotNull( args, t.callExpression( t.memberExpression(t.identifier(name), t.identifier("fromAmino")), [t.memberExpression(t.identifier("object"), t.identifier(origName))] ) ); }, anyType(args: fromAminoMethod) { const { origName } = getFieldNames(args.field); const interfaceName = args.field.options["(cosmos_proto.accepts_interface)"]; const interfaceFnName = getInterfaceFromAminoName(interfaceName); let aminoFuncExpr: t.Expression = t.identifier(interfaceFnName); const isGlobalRegistry = args.context.options.interfaces?.useGlobalDecoderRegistry; if (isGlobalRegistry) { aminoFuncExpr = t.memberExpression( t.identifier("GlobalDecoderRegistry"), t.identifier("fromAminoMsg") ); } return setNotUndefinedAndNotNull( args, t.callExpression(aminoFuncExpr, [ t.memberExpression(t.identifier("object"), t.identifier(origName)), ]) ); }, type(args: fromAminoMethod) { if ( !args.context.options.aminoEncoding.useLegacyInlineEncoding && args.context.options.interfaces.enabled && args.field.type === "google.protobuf.Any" && args.field.options["(cosmos_proto.accepts_interface)"] ) { return fromAmino.anyType(args); } return fromAmino.protoType(args); }, enum(args: fromAminoMethod) { return setNotUndefinedAndNotNull(args); }, bytes(args: fromAminoMethod) { // bytes [RawContractMessage] if (args.field.options?.["(gogoproto.casttype)"] === "RawContractMessage") { return fromAmino.rawBytes(args); } // bytes [WASMByteCode] // TODO use a better option for this in proto source // field.options?.["(gogoproto.customname)"] === "WASMByteCode" if (args.field.options?.["(gogoproto.customname)"] === "WASMByteCode") { return fromAmino.wasmByteCode(args); } //default args.context.addUtil("bytesFromBase64"); const { origName } = getFieldNames(args.field); const expr = t.callExpression(t.identifier("bytesFromBase64"), [ t.memberExpression(t.identifier("object"), t.identifier(origName)), ]); return setNotUndefinedAndNotNull(args, expr); }, duration(args: fromAminoMethod) { return fromAmino.type(args); }, durationString(args: fromAminoMethod) { return setNotUndefinedAndNotNull(args, t.identifier("undefined")); }, timestamp(args: fromAminoMethod) { const timestampFormat = args.context.pluginValue( "prototypes.typingsFormat.timestamp" ); switch (timestampFormat) { case "timestamp": return fromAmino.type(args); case "date": default: return fromAmino.timestampDate(args); } }, timestampDate(args: fromAminoMethod) { const { origName } = getFieldNames(args.field); args.context.addUtil("fromTimestamp"); const expr = t.callExpression(t.identifier("fromTimestamp"), [ t.callExpression( t.memberExpression( t.identifier("Timestamp"), t.identifier("fromAmino") ), [t.memberExpression(t.identifier("object"), t.identifier(origName))] ), ]); return setNotUndefinedAndNotNull(args, expr); }, // message.referenceMap = Object.entries(object.referenceMap ?? {}).reduce<{ // [key: Long]: Reference; // }>((acc, [key, value]) => { // if (value !== undefined) { // acc[Number(key)] = Reference.fromAmino(value); // } // return acc; // }, {}); // message.labels = Object.entries(object.typeMap ?? {}).reduce<{ // [key: string]: string; // }>((acc, [key, value]) => { // if (value !== undefined) { // acc[key] = String(value); // } // return acc; // }, {}); keyHash(args: fromAminoMethod) { const { propName, origName } = getFieldNames(args.field); const keyType = args.field.keyType; const valueType = args.field.parsedType.name; let fromAminoWithArgs = null; // valueTypeType: string for identifier let valueTypeType = valueType; switch (valueType) { case "string": fromAminoWithArgs = t.callExpression(t.identifier("String"), [ t.identifier("value"), ]); break; case "int32": case "uint32": valueTypeType = "number"; fromAminoWithArgs = t.callExpression(t.identifier("Number"), [ t.identifier("value"), ]); break; case "int64": case "uint64": case "sint64": case "fixed64": case "sfixed64": TypeLong.addUtil(args.context); valueTypeType = TypeLong.getPropType(args.context); fromAminoWithArgs = TypeLong.getFromValueWithArgs( args.context, t.identifier("value") ); break; default: fromAminoWithArgs = t.callExpression( t.memberExpression( t.identifier(valueType), t.identifier("fromAmino") ), [t.identifier("value")] ); } let wrapKey = null; let keyTypeType = null; switch (keyType) { case "string": wrapKey = (a) => a; keyTypeType = t.tsStringKeyword(); break; case "int64": case "uint64": case "sint64": case "fixed64": case "sfixed64": wrapKey = (a) => t.callExpression(t.identifier("Number"), [a]); TypeLong.addUtil(args.context); keyTypeType = t.tsTypeReference( TypeLong.getPropIdentifier(args.context) ); break; case "int32": case "uint32": wrapKey = (a) => t.callExpression(t.identifier("Number"), [a]); keyTypeType = t.tsNumberKeyword(); break; default: throw new Error("keyHash requires new type. Ask maintainers."); } return t.expressionStatement( t.assignmentExpression( "=", t.memberExpression(t.identifier("message"), t.identifier(propName)), callExpression( t.memberExpression( t.callExpression( t.memberExpression( t.identifier("Object"), t.identifier("entries") ), [ t.logicalExpression( "??", t.memberExpression( t.identifier("object"), t.identifier(origName) ), t.objectExpression([]) ), ] ), t.identifier("reduce") ), [ t.arrowFunctionExpression( [ t.identifier("acc"), t.arrayPattern([t.identifier("key"), t.identifier("value")]), ], t.blockStatement([ t.ifStatement( t.binaryExpression( "!==", t.identifier("value"), t.identifier("undefined") ), t.blockStatement([ t.expressionStatement( t.assignmentExpression( "=", t.memberExpression( t.identifier("acc"), wrapKey(t.identifier("key")), true ), fromAminoWithArgs ) ), ]) ), t.returnStatement(t.identifier("acc")), ]) ), t.objectExpression([]), ], t.tsTypeParameterInstantiation([ t.tsTypeLiteral([ t.tsIndexSignature( [identifier("key", t.tsTypeAnnotation(keyTypeType))], t.tsTypeAnnotation( t.tsTypeReference(t.identifier(valueTypeType)) ) ), ]), ]) ) ) ); }, // message.codeIds = object.codeIds?.map(e => Long.fromValue(e)) || []; array(args: fromAminoMethod, expr: t.Expression) { const { origName, propName } = getFieldNames(args.field); return t.expressionStatement( t.assignmentExpression( "=", t.memberExpression(t.identifier("message"), t.identifier(propName)), t.logicalExpression( "||", t.optionalCallExpression( t.optionalMemberExpression( t.memberExpression( t.identifier("object"), t.identifier(origName) ), t.identifier("map"), false, true ), [t.arrowFunctionExpression([t.identifier("e")], expr)], false ), t.arrayExpression([]) ) ) ); }, pubkey(args: fromAminoMethod) { args.context.addUtil("encodePubkey"); const { origName } = getFieldNames(args.field); const callExpr = t.callExpression(t.identifier("encodePubkey"), [ t.memberExpression(t.identifier("object"), t.identifier(origName)), ]); return setNotUndefinedAndNotNull(args, callExpr); }, rawBytes(args: fromAminoMethod) { args.context.addUtil("toUtf8"); const { origName } = getFieldNames(args.field); const expr = t.callExpression(t.identifier("toUtf8"), [ t.callExpression( t.memberExpression(t.identifier("JSON"), t.identifier("stringify")), [t.memberExpression(t.identifier("object"), t.identifier(origName))] ), ]); return setNotUndefinedAndNotNull(args, expr); }, wasmByteCode(args: fromAminoMethod) { args.context.addUtil("fromBase64"); const { origName } = getFieldNames(args.field); const expr = t.callExpression(t.identifier("fromBase64"), [ t.memberExpression(t.identifier("object"), t.identifier(origName)), ]); return setNotUndefinedAndNotNull(args, expr); }, }; export const arrayTypes = { // message.overloadId = object.overloadId?.map(e => e) || []; identity() { return t.identifier("e"); }, string() { return arrayTypes.identity(); }, bool() { return arrayTypes.identity(); }, rawBytes(args: fromAminoMethod) { args.context.addUtil("toUtf8"); return t.callExpression(t.identifier("toUtf8"), [ t.callExpression( t.memberExpression(t.identifier("JSON"), t.identifier("stringify")), [t.identifier("e")] ), ]); }, wasmByteCode(args: fromAminoMethod) { args.context.addUtil("fromBase64"); const { origName } = getFieldNames(args.field); return t.callExpression(t.identifier("fromBase64"), [t.identifier("e")]); }, bytes(args: fromAminoMethod) { if (args.field.options?.["(gogoproto.casttype)"] === "RawContractMessage") { return arrayTypes.rawBytes(args); } // bytes [WASMByteCode] // field.options?.["(gogoproto.customname)"] === "WASMByteCode" if (args.field.options?.["(gogoproto.customname)"] === "WASMByteCode") { return arrayTypes.wasmByteCode(args); } // default args.context.addUtil("bytesFromBase64"); return t.callExpression(t.identifier("bytesFromBase64"), [ t.identifier("e"), ]); }, double() { return arrayTypes.identity(); }, float() { return arrayTypes.identity(); }, int32() { return arrayTypes.identity(); }, uint32() { return arrayTypes.identity(); }, sint32() { return arrayTypes.identity(); }, fixed32() { return arrayTypes.identity(); }, sfixed32() { return arrayTypes.identity(); }, enum() { return arrayTypes.identity(); }, // message.codeIds = object.codeIds?.map(e => Long.fromValue(e)) || []; long(args: fromAminoMethod) { TypeLong.addUtil(args.context); return TypeLong.getFromStringArray(args.context); }, int64(args: fromAminoMethod) { return arrayTypes.long(args); }, uint64(args: fromAminoMethod) { return arrayTypes.long(args); }, sint64(args: fromAminoMethod) { return arrayTypes.long(args); }, fixed64(args: fromAminoMethod) { return arrayTypes.long(args); }, sfixed64(args: fromAminoMethod) { return arrayTypes.long(args); }, anyType(args: fromAminoMethod) { const interfaceName = args.field.options["(cosmos_proto.accepts_interface)"]; const interfaceFnName = getInterfaceFromAminoName(interfaceName); let aminoFuncExpr: t.Expression = t.identifier(interfaceFnName); const isGlobalRegistry = args.context.options.interfaces?.useGlobalDecoderRegistry; if (isGlobalRegistry) { aminoFuncExpr = t.memberExpression( t.identifier("GlobalDecoderRegistry"), t.identifier("fromAminoMsg") ); } return t.callExpression(aminoFuncExpr, [t.identifier("e")]); }, protoType(args: fromAminoMethod) { const name = args.context.getTypeName(args.field); return t.callExpression( t.memberExpression(t.identifier(name), t.identifier("fromAmino")), [t.identifier("e")] ); }, type(args: fromAminoMethod) { if ( !args.context.options.aminoEncoding.useLegacyInlineEncoding && args.context.options.interfaces.enabled && args.field.type === "google.protobuf.Any" && args.field.options["(cosmos_proto.accepts_interface)"] ) { return arrayTypes.anyType(args); } return arrayTypes.protoType(args); }, }; export const fromAminoMessages = { anyType() { return [ t.returnStatement( t.objectExpression([ t.objectProperty( t.identifier("typeUrl"), t.memberExpression(t.identifier("object"), t.identifier("type")) ), t.objectProperty( t.identifier("value"), t.memberExpression(t.identifier("object"), t.identifier("value")) ), ]) ), ]; }, timestamp(context: ProtoParseContext, name: string, proto: ProtoType) { context.addUtil("fromJsonTimestamp"); return [ t.returnStatement( t.callExpression(t.identifier("fromJsonTimestamp"), [ t.identifier("object"), ]) ), ]; }, height(context: ProtoParseContext, name: string, proto: ProtoType) { TypeLong.addUtil(context); const keepCase = context.options.prototypes.parser.keepCase; const casing = keepCase ? (str) => str : camel; const makeArgs = (fieldName: string) => { let args: t.Expression[] = [ t.logicalExpression( "||", t.memberExpression(t.identifier("object"), t.identifier(fieldName)), t.stringLiteral("0") ), ]; const longType = TypeLong.getType(context); if (longType == "Long") { args.push(t.booleanLiteral(true)); } return args; }; const makeField = (fieldName: string) => t.objectProperty( t.identifier(casing(fieldName)), t.callExpression(TypeLong.getFromString(context), makeArgs(fieldName)) ); return [ // return t.returnStatement( t.objectExpression([ makeField("revision_number"), makeField("revision_height"), ]) ), ]; }, duration(context: ProtoParseContext, name: string, proto: ProtoType) { TypeLong.addUtil(context); const longType = TypeLong.getType(context); switch (longType) { case "BigInt": return [ t.variableDeclaration("const", [ t.variableDeclarator( t.identifier("value"), t.callExpression(t.identifier("BigInt"), [t.identifier("object")]) ), ]), t.returnStatement( t.objectExpression([ t.objectProperty( t.identifier("seconds"), t.binaryExpression( "/", t.identifier("value"), t.callExpression(t.identifier("BigInt"), [ t.stringLiteral("1000000000"), ]) ) ), t.objectProperty( t.identifier("nanos"), t.callExpression(t.identifier("Number"), [ t.binaryExpression( "%", t.identifier("value"), t.callExpression(t.identifier("BigInt"), [ t.stringLiteral("1000000000"), ]) ), ]) ), ]) ), ]; case "Long": default: return [ t.variableDeclaration("const", [ t.variableDeclarator( t.identifier("value"), t.callExpression(t.identifier("parseInt"), [ t.identifier("object"), ]) ), ]), // return t.returnStatement( t.objectExpression([ // seconds t.objectProperty( t.identifier("seconds"), t.callExpression(TypeLong.getFromNumber(context), [ t.callExpression( t.memberExpression( t.identifier("Math"), t.identifier("floor") ), [t.binaryExpression("/", t.identifier("value"), BILLION)] ), ]) ), // nanos t.objectProperty( t.identifier("nanos"), t.binaryExpression("%", t.identifier("value"), BILLION) ), ]) ), ]; } }, };