@cosmology/ast
Version:
Cosmos TypeScript AST generation
166 lines (142 loc) • 4.72 kB
text/typescript
import * as t from '@babel/types';
import { ProtoField, ProtoType } from '@cosmology/types';
import { AminoParseContext } from '../../context';
import { getTypeUrl, protoFieldsToArray, getAminoTypeName } from '../utils';
import { aminoInterface } from './utils';
import { getFieldOptionality, getOneOfs } from '../../proto';
export interface RenderAminoField {
context: AminoParseContext;
field: ProtoField;
currentProtoPath: string;
isOptional: boolean;
};
export const renderAminoField = ({
context,
field,
currentProtoPath,
isOptional
}: RenderAminoField) => {
const args = {
context,
field,
currentProtoPath,
isOptional
}
if (field.rule === 'repeated') {
switch (field.parsedType.type) {
case 'Type':
return aminoInterface.typeArray(args);
case 'Enum':
return aminoInterface.enumArray(args);
default:
return aminoInterface.array(args);
}
}
// special "native" types...
// above Type,Enum since they're Types
switch (field.type) {
// TODO check can we just
// make pieces optional and avoid hard-coding this type?
case 'ibc.core.client.v1.Height':
case 'Height':
return aminoInterface.height(args);
case 'Timestamp':
case 'google.protobuf.Timestamp':
return aminoInterface.timestamp(args);
case 'Duration':
case 'google.protobuf.Duration':
return aminoInterface.duration(args);
case 'Any':
case 'google.protobuf.Any':
switch (field.options?.['(cosmos_proto.accepts_interface)']) {
case 'cosmos.crypto.PubKey':
return aminoInterface.pubkey(args);
}
}
switch (field.parsedType.type) {
case 'Type':
return aminoInterface.type(args);
case 'Enum':
return aminoInterface.enum(args);
}
// scalar types...
switch (field.type) {
case 'string':
return aminoInterface.defaultType(args);
case 'int64':
case 'sint64':
case 'uint64':
case 'fixed64':
case 'sfixed64':
return aminoInterface.long(args);
case 'double':
case 'bool':
case 'bytes':
case 'int32':
case 'sint32':
case 'uint32':
case 'fixed32':
case 'sfixed32':
return aminoInterface.defaultType(args);
// // TODO check can we just
// // make pieces optional and avoid hard-coding this type?
// case 'ibc.core.client.v1.Height':
// case 'Height':
// return aminoInterface.height(args);
// case 'Timestamp':
// case 'google.protobuf.Timestamp':
// return aminoInterface.timestamp(args);
// case 'Duration':
// case 'google.protobuf.Duration':
// return aminoInterface.duration(args);
default:
return aminoInterface.defaultType(args);
}
};
export interface MakeAminoTypeInterface {
context: AminoParseContext;
proto: ProtoType;
};
export const makeAminoTypeInterface = ({
context,
proto
}: MakeAminoTypeInterface) => {
context.addUtil('AminoMsg');
const TypeName = proto.name;
const aminoType = getAminoTypeName(context, context.ref.proto, proto);
const oneOfs = getOneOfs(proto);
const fields = protoFieldsToArray(proto).map((field) => {
const isOneOf = oneOfs.includes(field.name);
const isOptional = getFieldOptionality(context, field, isOneOf);
const aminoField = renderAminoField({
context,
field,
currentProtoPath: context.ref.filename,
isOptional
});
return {
ctx: context,
field: aminoField
}
});
const annotation = !context.options.aminoEncoding.useLegacyInlineEncoding ?
t.tsTypeAnnotation(t.tsTypeReference(
t.identifier(TypeName + 'Amino')
)) :
t.tsTypeAnnotation(t.tsTypeLiteral(
fields.map(({ field }) => field)
));
return t.exportNamedDeclaration(
t.tsInterfaceDeclaration(
t.identifier(TypeName + 'AminoType'),
null,
[t.tsExpressionWithTypeArguments(t.identifier('AminoMsg'))],
t.tSInterfaceBody([
t.tSPropertySignature(t.identifier('type'), t.tsTypeAnnotation(
t.tSLiteralType(t.stringLiteral(aminoType))
)),
t.tSPropertySignature(t.identifier('value'), annotation)
])
)
)
}