@cosmology/ast
Version:
Cosmos TypeScript AST generation
199 lines (179 loc) • 7.01 kB
text/typescript
import * as t from '@babel/types';
import { InterfaceTypeUrlMap, ProtoRef, TraverseTypeUrlRef, TypeUrlRef } from '@cosmology/types';
import { slugify } from '@cosmology/utils';
import { identifier } from '../../../utils';
import { ProtoParseContext } from "../../context";
const firstUpper = (s: string) => s = s.charAt(0).toUpperCase() + s.slice(1);
export const getInterfaceFromAminoName = (str: string) => {
return firstUpper(slugify(str) + '_FromAmino');
};
const makeFunctionWrapper = (functionName: string, stmt: t.Statement) => {
let arrowFunction = t.arrowFunctionExpression(
[
identifier(
'content',
t.tsTypeAnnotation(
t.tsTypeReference(
t.identifier('AnyAmino')
)
)
)
],
t.blockStatement([
stmt
])
);
arrowFunction.returnType = t.tsTypeAnnotation(
t.tsTypeReference(
t.identifier('Any')
)
);
return t.exportNamedDeclaration(
t.variableDeclaration(
'const',
[
t.variableDeclarator(
t.identifier(functionName),
arrowFunction
)
]
)
);
};
export const createInterfaceFromAmino = (
context: ProtoParseContext,
ref: ProtoRef,
interfaceName: string,
) => {
if (interfaceName === 'cosmos.crypto.PubKey') {
// return a helper!
context.addUtil('encodePubkey');
const functionName = getInterfaceFromAminoName(interfaceName);
return makeFunctionWrapper(functionName, t.returnStatement(
t.callExpression(
t.identifier('encodePubkey'),
[t.identifier('content')]
)
));
}
const typeMap = context.store.getTypeUrlMap(ref);
const typeRefs = typeMap[interfaceName];
return createInterfaceFromAminoHelper(
context,
getInterfaceFromAminoName(interfaceName),
typeRefs
);
};
export const createInterfaceFromAminoHelper = (
context: ProtoParseContext,
functionName: string,
typeRefs: TraverseTypeUrlRef[]
) => {
context.addUtil('DeepPartial');
// MARKED AS NOT DRY
const allTypes: TypeUrlRef[] = typeRefs?.reduce((m, typeRef) => {
return [...m, ...typeRef.types];
}, []) ?? [];
const switchCases = allTypes.map(type => {
if (!type.aminoType) return;
return t.switchCase(
t.stringLiteral(type.aminoType),
[
t.returnStatement(
t.callExpression(
t.memberExpression(
t.identifier('Any'),
t.identifier('fromPartial')
),
[
t.objectExpression([
t.objectProperty(
t.identifier('typeUrl'),
t.stringLiteral(type.typeUrl)
),
t.objectProperty(
t.identifier('value'),
t.callExpression(
t.memberExpression(
t.callExpression(
t.memberExpression(
t.identifier(type.importAs),
t.identifier('encode')
),
[
t.callExpression(
t.memberExpression(
t.identifier(type.importAs),
t.identifier('fromPartial')
),
[
t.callExpression(
t.memberExpression(
t.identifier(type.importAs),
t.identifier('fromAmino')
),
[
t.memberExpression(
t.identifier('content'),
t.identifier('value')
)
]
)
]
)
]
),
t.identifier('finish')
),
[]
)
),
])
]
)
)]
);
}).filter(Boolean);
let ast: t.Statement;
if (!switchCases.length) {
ast = t.returnStatement(
t.callExpression(
t.memberExpression(
t.identifier('Any'),
t.identifier('fromAmino')
),
[
t.identifier('content')
]
)
);
} else {
ast = t.switchStatement(
t.memberExpression(
t.identifier('content'),
t.identifier('type')
),
[
...switchCases,
/// default
t.switchCase(
null,
[
t.returnStatement(
t.callExpression(
t.memberExpression(
t.identifier('Any'),
t.identifier('fromAmino')
),
[
t.identifier('content')
]
)
)
]
)
]
);
}
return makeFunctionWrapper(functionName, ast);
};