@cosmology/ast
Version:
Cosmos TypeScript AST generation
452 lines (451 loc) • 19 kB
JavaScript
import * as t from "@babel/types";
import { identifier, callExpression, TypeLong, BILLION } from "../../../utils";
import { getInterfaceFromAminoName } from "..";
import { getFieldNames } from "../../types";
import { camel } from "@cosmology/utils";
const setNotUndefinedAndNotNull = (args, value) => {
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) {
return setNotUndefinedAndNotNull(args);
},
// message.disableMacros = object.disableMacros ?? false;
bool(args) {
return setNotUndefinedAndNotNull(args);
},
// message.doubleValue = object.doubleValue ?? 0;
number(args) {
return setNotUndefinedAndNotNull(args);
},
int32(args) {
return fromAmino.number(args);
},
uint32(args) {
return fromAmino.number(args);
},
sint32(args) {
return fromAmino.number(args);
},
fixed32(args) {
return fromAmino.number(args);
},
sfixed32(args) {
return fromAmino.number(args);
},
double(args) {
return fromAmino.number(args);
},
float(args) {
return fromAmino.number(args);
},
// if( object.myInt64Value !== undefined && object.myInt64Value !== null ) { message.myInt64Value = Long.fromValue(object.myInt64Value) }
long(args) {
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) {
return fromAmino.long(args);
},
uint64(args) {
return fromAmino.long(args);
},
sint64(args) {
return fromAmino.long(args);
},
fixed64(args) {
return fromAmino.long(args);
},
sfixed64(args) {
return fromAmino.long(args);
},
protoType(args) {
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) {
const { origName } = getFieldNames(args.field);
const interfaceName = args.field.options["(cosmos_proto.accepts_interface)"];
const interfaceFnName = getInterfaceFromAminoName(interfaceName);
let aminoFuncExpr = 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) {
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) {
return setNotUndefinedAndNotNull(args);
},
bytes(args) {
// 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) {
return fromAmino.type(args);
},
durationString(args) {
return setNotUndefinedAndNotNull(args, t.identifier("undefined"));
},
timestamp(args) {
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) {
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) {
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, expr) {
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) {
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) {
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) {
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) {
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) {
args.context.addUtil("fromBase64");
const { origName } = getFieldNames(args.field);
return t.callExpression(t.identifier("fromBase64"), [t.identifier("e")]);
},
bytes(args) {
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) {
TypeLong.addUtil(args.context);
return TypeLong.getFromStringArray(args.context);
},
int64(args) {
return arrayTypes.long(args);
},
uint64(args) {
return arrayTypes.long(args);
},
sint64(args) {
return arrayTypes.long(args);
},
fixed64(args) {
return arrayTypes.long(args);
},
sfixed64(args) {
return arrayTypes.long(args);
},
anyType(args) {
const interfaceName = args.field.options["(cosmos_proto.accepts_interface)"];
const interfaceFnName = getInterfaceFromAminoName(interfaceName);
let aminoFuncExpr = 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) {
const name = args.context.getTypeName(args.field);
return t.callExpression(t.memberExpression(t.identifier(name), t.identifier("fromAmino")), [t.identifier("e")]);
},
type(args) {
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, name, proto) {
context.addUtil("fromJsonTimestamp");
return [
t.returnStatement(t.callExpression(t.identifier("fromJsonTimestamp"), [
t.identifier("object"),
])),
];
},
height(context, name, proto) {
TypeLong.addUtil(context);
const keepCase = context.options.prototypes.parser.keepCase;
const casing = keepCase ? (str) => str : camel;
const makeArgs = (fieldName) => {
let args = [
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) => 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, name, proto) {
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)),
])),
];
}
},
};