@cosmology/ast
Version:
Cosmos TypeScript AST generation
258 lines (257 loc) • 11.9 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCreateProtoType = exports.createProtoInterfaceEncodedType = exports.createProtoTypeType = exports.createProtoType = void 0;
const t = __importStar(require("@babel/types"));
const types_1 = require("@cosmology/types");
const utils_1 = require("../../../utils");
const types_2 = require("../types");
const types_3 = require("../../types");
const amino_1 = require("../../amino");
const getProtoField = (context, field, type = 'Msg') => {
let ast = null;
const fieldRef = (0, types_3.getFieldTypeReference)(context, field, type);
ast = fieldRef.ast;
const isTypeCastableAnyType = fieldRef.isTypeCastableAnyType;
if (field.rule === 'repeated') {
ast = t.tsArrayType(ast);
if (isTypeCastableAnyType) {
ast = t.tsUnionType([
ast,
t.tsArrayType(t.tsTypeReference(t.identifier('Any')))
]);
}
}
if (field.keyType) {
ast = t.tsUnionType([
t.tsTypeLiteral([
t.tsIndexSignature([
(0, utils_1.identifier)('key', t.tsTypeAnnotation((0, types_3.getTSType)(context, field.keyType)))
], t.tsTypeAnnotation(ast))
])
]);
}
return ast;
};
const createProtoType = (context, name, proto, type = 'Msg') => {
const oneOfs = (0, types_2.getOneOfs)(proto);
// MARKED AS COSMOS SDK specific code
const optionalityMap = {};
// if a param is found to be a route parameter, we assume it's required
// if a param is found to be a query parameter, we assume it's optional
if (context.pluginValue('prototypes.optionalQueryParams') && context.store.requests[name]) {
const svc = context.store.requests[name];
if (svc.info) {
svc.info.queryParams.map(param => {
optionalityMap[param] = true;
});
}
}
// hard-code optionality for pagination
if (context.pluginValue('prototypes.optionalPageRequests')) {
if (context.ref.proto.package === 'cosmos.base.query.v1beta1') {
if (name === 'PageRequest') {
optionalityMap['key'] = true;
optionalityMap['offset'] = true;
optionalityMap['limit'] = true;
optionalityMap['count_total'] = true;
optionalityMap['countTotal'] = true;
optionalityMap['reverse'] = true;
}
if (name === 'PageResponse') {
optionalityMap['next_key'] = true;
optionalityMap['nextKey'] = true;
}
}
}
const MsgName = types_3.SymbolNames[type](name);
const fields = [];
if (context.pluginValue('prototypes.addTypeUrlToDecoders') &&
((context.pluginValue('interfaces.enabled') &&
proto.options?.['(cosmos_proto.implements_interface)']) ||
(context.ref.proto.package === 'google.protobuf'
&& name === 'Any'))) {
const typeUrl = (0, amino_1.getTypeUrlWithPkgAndName)(context.ref.proto.package, name);
const typeAnnotation = (context.ref.proto.package === 'google.protobuf'
&& name === 'Any') ? t.tsTypeAnnotation(t.tsUnionType([
t.tsLiteralType(t.stringLiteral(typeUrl)),
t.tsStringKeyword()
])) : t.tsTypeAnnotation(t.tsLiteralType(t.stringLiteral(typeUrl)));
fields.push((0, utils_1.tsPropertySignature)(t.identifier('$typeUrl'), typeAnnotation, true));
}
[].push.apply(fields, Object.keys(proto.fields).reduce((m, fieldName) => {
const isOneOf = oneOfs.includes(fieldName);
const field = proto.fields[fieldName];
const isOptional = (0, types_2.getFieldOptionalityForDefaults)(context, field, isOneOf);
// optionalityMap is coupled to API requests
const orig = field.options?.['(telescope:orig)'] ?? fieldName;
let optional = false;
if (optionalityMap[orig]) {
optional = true;
}
// let fieldNameWithCase = options.useOriginalCase ? orig : fieldName;
let fieldNameWithCase = type === 'SDKType' ? orig : fieldName;
const protoField = getProtoField(context, field, type);
const propSig = (0, utils_1.tsPropertySignature)(t.identifier(fieldNameWithCase), t.tsTypeAnnotation(protoField),
// optional || getFieldOptionality(context, field, isOneOf)
isOptional || optional);
const comments = [];
if (field.comment &&
// no comment for derivative types
(type === 'Msg')) {
comments.push((0, utils_1.makeCommentBlock)(field.comment));
}
if (field.options?.deprecated) {
comments.push((0, utils_1.makeCommentBlock)('@deprecated'));
}
if (comments.length) {
propSig.leadingComments = comments;
}
m.push(propSig);
return m;
}, []));
// declaration
const declaration = t.exportNamedDeclaration(t.tsInterfaceDeclaration(t.identifier(MsgName), null, [], t.tsInterfaceBody(fields)));
const comments = [];
if (proto.comment) {
comments.push((0, utils_1.makeCommentBlock)(proto.comment));
}
if (proto.options?.deprecated) {
comments.push((0, utils_1.makeCommentBlock)('@deprecated'));
}
if (comments.length) {
declaration.leadingComments = comments;
}
return declaration;
};
exports.createProtoType = createProtoType;
const createProtoTypeType = (context, name, proto) => {
const ProtoMsgName = types_3.SymbolNames.ProtoMsg(name);
const typeUrl = (0, amino_1.getTypeUrl)(context.ref.proto, proto);
const typ = typeUrl ? t.tsLiteralType(t.stringLiteral(typeUrl)) : t.tsTypeReference(t.identifier('string'));
return t.exportNamedDeclaration(t.tsInterfaceDeclaration(t.identifier(ProtoMsgName), null, [], t.tsInterfaceBody([
(0, utils_1.tsPropertySignature)(t.identifier(context.options.prototypes.parser.keepCase ? 'type_url' : 'typeUrl'), t.tsTypeAnnotation(typ), false),
(0, utils_1.tsPropertySignature)(t.identifier('value'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Uint8Array'))), false)
])));
};
exports.createProtoTypeType = createProtoTypeType;
const createProtoInterfaceEncodedType = (context, name, proto) => {
const MsgName = types_3.SymbolNames.Msg(name);
const EncodedMsgName = types_3.SymbolNames.Encoded(name);
const oneOfs = (0, types_2.getOneOfs)(proto);
const implementsAcceptsAny = context.pluginValue('interfaces.enabled');
const fieldsWithInfo = Object.keys(proto.fields)
.reduce((m, fieldName) => {
const isOneOf = oneOfs.includes(fieldName);
const field = proto.fields[fieldName];
const lookupInterface = field.options?.['(cosmos_proto.accepts_interface)'];
const isAnyType = field.parsedType?.type === 'Type' && field.parsedType?.name === 'Any';
// MARKED AS NOT DRY (symbols)
let symbols = null;
if (implementsAcceptsAny && lookupInterface) {
symbols = context.store._symbols.filter(s => s.implementsType === lookupInterface && s.ref === context.ref.filename);
if (!symbols.length && context.options.logLevel >= types_1.TelescopeLogLevel.Warn) {
console.warn(`[WARN] ${lookupInterface} is accepted but not implemented`);
}
}
const isAnyInterface = isAnyType && lookupInterface && implementsAcceptsAny && symbols;
if (!isAnyInterface)
return m;
// ONLY INTERFACES!
return [...m, {
isOneOf,
field,
name: fieldName,
lookupInterface,
isAnyType,
symbols
}];
}, []).filter(Boolean);
if (!fieldsWithInfo.length)
return;
const interfaceFields = fieldsWithInfo.map(fieldInfo => {
return t.tsLiteralType(t.stringLiteral(fieldInfo.name));
});
const fields = fieldsWithInfo.map(fieldsInfo => {
const { field, isOneOf, name: fieldName } = fieldsInfo;
let optional = false;
const protoField = getProtoField(context, field, 'ProtoMsg');
const propSig = (0, utils_1.tsPropertySignature)(t.identifier(fieldName), t.tsTypeAnnotation(protoField), optional || (0, types_2.getFieldOptionality)(context, field, isOneOf));
const comments = [];
if (field.comment) {
comments.push((0, utils_1.makeCommentBlock)(field.comment));
}
if (field.options?.deprecated) {
comments.push((0, utils_1.makeCommentBlock)('@deprecated'));
}
if (comments.length) {
propSig.leadingComments = comments;
}
return propSig;
});
return t.exportNamedDeclaration(t.tsTypeAliasDeclaration(t.identifier(EncodedMsgName), null, t.tsIntersectionType([
t.tsTypeReference(t.identifier('Omit'), t.tsTypeParameterInstantiation([
t.tsTypeReference(t.identifier(MsgName)),
interfaceFields.length > 1 ? t.tsUnionType([
...interfaceFields
]) : interfaceFields[0]
])),
t.tsTypeLiteral([
...fields
])
])));
};
exports.createProtoInterfaceEncodedType = createProtoInterfaceEncodedType;
const createCreateProtoType = (context, name, proto) => {
const oneOfs = (0, types_2.getOneOfs)(proto);
const fields = [];
if (context.pluginValue('prototypes.addTypeUrlToDecoders') &&
((context.pluginValue('interfaces.enabled') &&
proto.options?.['(cosmos_proto.implements_interface)']) ||
(context.ref.proto.package === 'google.protobuf'
&& name === 'Any'))) {
const typeUrl = (0, amino_1.getTypeUrlWithPkgAndName)(context.ref.proto.package, name);
fields.push(t.objectProperty(t.identifier('$typeUrl'), t.stringLiteral(typeUrl)));
}
[].push.apply(fields, Object.keys(proto.fields).map(key => {
const isOneOf = oneOfs.includes(key);
const isOptional = (0, types_2.getFieldOptionality)(context, proto.fields[key], isOneOf);
return {
name: key,
...proto.fields[key],
isOneOf,
isOptional
};
})
.map(field => {
return t.objectProperty(t.identifier(field.name), (0, types_3.getDefaultTSTypeFromProtoType)(context, field, field.isOneOf));
}));
return (0, utils_1.functionDeclaration)(t.identifier((0, types_2.getBaseCreateTypeFuncName)(name)), [], t.blockStatement([
t.returnStatement(t.objectExpression([
...fields,
]))
]), false, false, t.tsTypeAnnotation(t.tsTypeReference(t.identifier(name))));
};
exports.createCreateProtoType = createCreateProtoType;
;