@cosmology/ast
Version:
Cosmos TypeScript AST generation
204 lines (203 loc) • 12.2 kB
JavaScript
import * as t from "@babel/types";
import { BILLION, memberExpressionOrIdentifierAminoCaseField, shorthandProperty, TypeLong, } from "../../../utils";
import { fromAminoParseField } from "./index";
import { protoFieldsToArray } from "../utils";
import { getFieldOptionality, getOneOfs } from "../../proto";
export const fromAmino = {
defaultType(args) {
if (args.field.name === args.context.aminoCaseField(args.field) &&
args.scope.length === 1) {
return shorthandProperty(args.field.name);
}
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
return t.objectProperty(t.identifier(args.field.name), memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling));
},
string(args) {
if (args.field.name === args.context.aminoCaseField(args.field) &&
args.scope.length === 1) {
return shorthandProperty(args.field.name);
}
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
return t.objectProperty(t.identifier(args.field.name), memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling));
},
rawBytes(args) {
args.context.addUtil("toUtf8");
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
let prop = memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling);
let value = t.callExpression(t.identifier("toUtf8"), [
t.callExpression(t.memberExpression(t.identifier("JSON"), t.identifier("stringify")), [prop]),
]);
return t.objectProperty(t.identifier(args.field.name), this.nullCheckCondition(prop, prop, value, useNullHandling));
},
wasmByteCode(args) {
args.context.addUtil("fromBase64");
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
let prop = memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling);
let value = t.callExpression(t.identifier("fromBase64"), [prop]);
return t.objectProperty(t.identifier(args.field.name), this.nullCheckCondition(prop, prop, value, useNullHandling));
},
long(args) {
TypeLong.addUtil(args.context);
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
const prop = memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling);
return t.objectProperty(t.identifier(args.field.name), this.nullCheckCondition(prop, prop, t.callExpression(TypeLong.getFromString(args.context), [prop]), useNullHandling));
},
duration(args) {
const durationFormat = args.context.pluginValue("prototypes.typingsFormat.duration");
switch (durationFormat) {
case "duration":
// TODO duration amino type
case "string":
default:
return fromAmino.durationString(args);
}
},
durationString(args) {
TypeLong.addUtil(args.context);
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
let property = memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling);
const value = t.objectExpression([
t.objectProperty(t.identifier("seconds"), t.callExpression(TypeLong.getFromNumber(args.context), [
t.callExpression(t.memberExpression(t.identifier("Math"), t.identifier("floor")), [
t.binaryExpression("/", t.callExpression(t.identifier("parseInt"), [
property,
]), BILLION),
]),
])),
t.objectProperty(t.identifier("nanos"), t.binaryExpression("%", t.callExpression(t.identifier("parseInt"), [property]), BILLION)),
]);
return t.objectProperty(t.identifier(args.field.name), this.nullCheckCondition(property, property, value, useNullHandling));
},
height(args) {
TypeLong.addUtil(args.context);
const longType = TypeLong.getType(args.context);
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
let revisionHeightArgs = [
t.logicalExpression("||", t.memberExpression(memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling), t.identifier(args.context.aminoCasingFn("revision_height")), false, true), t.stringLiteral("0")),
];
let revisionNumberArgs = [
t.logicalExpression("||", t.memberExpression(memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling), t.identifier(args.context.aminoCasingFn("revision_number")), false, true), t.stringLiteral("0")),
];
if (longType == "Long") {
revisionHeightArgs.push(t.booleanLiteral(true));
revisionNumberArgs.push(t.booleanLiteral(true));
}
return t.objectProperty(t.identifier(args.field.name), t.conditionalExpression(memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling), t.objectExpression([
t.objectProperty(t.identifier("revisionHeight"), t.callExpression(TypeLong.getFromString(args.context), revisionHeightArgs)),
t.objectProperty(t.identifier("revisionNumber"), t.callExpression(TypeLong.getFromString(args.context), revisionNumberArgs)),
]), t.identifier("undefined")));
},
enum({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }) {
const enumFunction = context.lookupEnumFromJson(field, currentProtoPath);
const useNullHandling = !!context.pluginValue('aminoEncoding.legacy.useNullHandling');
let prop = memberExpressionOrIdentifierAminoCaseField(fieldPath, context.aminoCaseField, useNullHandling);
const value = t.callExpression(t.identifier(enumFunction), [prop]);
return t.objectProperty(t.identifier(field.name), this.nullCheckCondition(prop, prop, value, useNullHandling));
},
enumArray({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }) {
const useNullHandling = !!context.pluginValue('aminoEncoding.legacy.useNullHandling');
const enumFunction = context.lookupEnumFromJson(field, currentProtoPath);
const callExpression = useNullHandling ? t.optionalCallExpression : t.callExpression;
const value = callExpression(t.memberExpression(memberExpressionOrIdentifierAminoCaseField(fieldPath, context.aminoCaseField, useNullHandling), t.identifier("map"), false, true), [
t.arrowFunctionExpression([t.identifier("el")], t.callExpression(t.identifier(enumFunction), [
t.identifier("el"),
])),
], true);
return t.objectProperty(t.identifier(field.name), value);
},
type({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }) {
const parentField = field;
const Type = context.getTypeFromCurrentPath(field, currentProtoPath);
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 fromAminoParseField({
context,
field,
currentProtoPath,
scope: [...scope],
fieldPath: [...fieldPath],
nested: nested + 1,
isOptional, // TODO how to handle nested optionality?
});
});
const useNullHandling = !!context.pluginValue('aminoEncoding.legacy.useNullHandling');
let prop = memberExpressionOrIdentifierAminoCaseField(fieldPath, context.aminoCaseField, useNullHandling);
return t.objectProperty(t.identifier(field.name), this.nullCheckCondition(prop, prop, t.objectExpression(properties), useNullHandling));
},
arrayFrom(args) {
const useNullHandling = !!args.context.pluginValue("aminoEncoding.legacy.useNullHandling");
let prop = memberExpressionOrIdentifierAminoCaseField(args.fieldPath, args.context.aminoCaseField, useNullHandling);
let value = t.callExpression(t.memberExpression(t.identifier("Array"), t.identifier("from")), [prop]);
return t.objectProperty(t.identifier(args.field.name), this.nullCheckCondition(prop, prop, value, useNullHandling));
},
typeArray({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }) {
//////
const variable = "el" + nested;
const f = JSON.parse(JSON.stringify(field)); // clone
const varProto = {
...f,
};
varProto.name = variable;
varProto.options["(telescope:orig)"] = variable;
varProto.options["(telescope:name)"] = variable;
varProto.options["(telescope:camel)"] = variable;
//////
const parentField = field;
const Type = context.getTypeFromCurrentPath(field, currentProtoPath);
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 fromAminoParseField({
context,
field,
currentProtoPath,
scope: [variable],
fieldPath: [varProto],
nested: nested + 1,
isOptional, // TODO how to handle nested optionality?
});
});
const useNullHandling = !!context.pluginValue('aminoEncoding.legacy.useNullHandling');
const callExpression = useNullHandling ? t.optionalCallExpression : t.callExpression;
const expr = callExpression(t.memberExpression(memberExpressionOrIdentifierAminoCaseField(fieldPath, context.aminoCaseField, useNullHandling), t.identifier("map"), false, true), [
t.arrowFunctionExpression([t.identifier(variable)], t.objectExpression(properties)),
], true);
return t.objectProperty(t.identifier(field.name), expr);
},
scalarArray({ context, field, currentProtoPath, scope, fieldPath, nested, isOptional, }, arrayTypeAstFunc) {
const variable = "el" + nested;
const useNullHandling = !!context.pluginValue('aminoEncoding.legacy.useNullHandling');
const callExpression = useNullHandling ? t.optionalCallExpression : t.callExpression;
const expr = callExpression(t.memberExpression(memberExpressionOrIdentifierAminoCaseField(fieldPath, context.aminoCaseField, useNullHandling), t.identifier("map"), false, true), [
t.arrowFunctionExpression([t.identifier(variable)], arrayTypeAstFunc(variable, context)),
], true);
return t.objectProperty(t.identifier(field.name), expr);
},
pubkey(args) {
args.context.addUtil("encodePubkey");
return t.objectProperty(t.identifier(args.field.name), t.callExpression(t.identifier("encodePubkey"), [
t.identifier("pubkey"),
]));
},
/**
* value == null ? nullExpr : nonNullExpr
*/
nullCheckCondition(value, nullExpr, nonNullExpr, useNullHandling = false) {
return useNullHandling ? t.conditionalExpression(t.binaryExpression("==", value, t.nullLiteral()), nullExpr, nonNullExpr) : nonNullExpr;
},
};
export const arrayTypes = {
long(varname, ctx) {
TypeLong.addUtil(ctx);
return t.callExpression(TypeLong.getFromString(ctx), [
t.identifier(varname),
]);
},
};