UNPKG

@cosmology/ast

Version:
140 lines (139 loc) 5.47 kB
import * as t from '@babel/types'; import { identifier, makeCommentLineWithBlocks, objectProperty, newExpression } from '../../utils'; import { isRefIncluded } from '@cosmology/utils'; import { camel } from '@cosmology/utils'; import { pascal } from 'case'; const makeQueryStoreName = (name) => { return `Query${pascal(name)}Store`; }; /** * Entry for building stores. * @param {Object=} context - context of generating the file * @param {Object=} service - method details */ export const createMobxQueryStores = (context, service) => { const isIncluded = context.pluginValue('mobx.enabled') && isRefIncluded(context.ref, context.pluginValue('mobx.include')); if (isIncluded) { // before this, make sure: // 1. refactor adding getQueryService part into helpers. // 2. add new query store class to helpers. // build whole ast, don't forget to add utils. return buildRpcStores(context, service); } return null; }; /** * Create an AST to generate creating store functions. * eg: * export const createRpcQueryMobxStores = (rpc: ProtobufRpcClient | undefined) => { * const queryService = getQueryService(rpc); * * class QueryCertificatesStore { * ... * } * * return { * QueryCertificatesStore * }; * }; * @param {Object=} context - context of generating the file * @param {Object=} service - method details * @returns {ParseResult} created AST */ export const buildRpcStores = (context, service) => { // add imports context.addUtil('ProtobufRpcClient'); //TODO: add util for getQueryService const isCamelRpcMethods = context.pluginValue('rpcClients.camelCase'); const storeNames = []; const stores = Object.keys(service.methods ?? {}).map((key) => { const method = service.methods[key]; const name = isCamelRpcMethods ? camel(key) : key; storeNames.push({ name, comment: method.comment }); return buildStore(context, name, method); }); return t.exportNamedDeclaration(t.variableDeclaration('const', [ t.variableDeclarator(t.identifier('createRpcQueryMobxStores'), t.arrowFunctionExpression([ identifier('rpc', t.tsTypeAnnotation(t.tsUnionType([ t.tsTypeReference(t.identifier('ProtobufRpcClient')), t.tsUndefinedKeyword() ]))) ], // body t.blockStatement([ // query service t.variableDeclaration('const', [ t.variableDeclarator(t.identifier('queryService'), t.callExpression(t.identifier('getQueryService'), [ t.identifier('rpc') ])) ]), ...stores, // return the methods... t.returnStatement(t.objectExpression(storeNames.map(({ name, comment }) => { const id = t.identifier(makeQueryStoreName(name)); return objectProperty(id, id, false, true, null, makeCommentLineWithBlocks(comment)); }))) ]) // end body )) ])); }; /** * Create an AST of inherited store. * eg: * class QueryCertificatesStore { * store = new QueryStore<QueryCertificatesRequest, QueryCertificatesResponse>(queryService?.certificates); * certificates(request: QueryCertificatesRequest) { * return this.store.getData(request); * } * } * @param {Object=} context - context of generating the file * @param {string} name - name of the store * @param {Object=} serviceMethod - method details * @returns {ParseResult} created AST */ const buildStore = (context, name, serviceMethod) => { //add util for QueryStore context.addUtil('QueryStore'); //add util for MobxResponse context.addUtil('MobxResponse'); //add util for makeObservable context.addUtil('makeObservable'); //add util for override context.addUtil('override'); const requestType = serviceMethod.requestType; const responseType = serviceMethod.responseType; const fieldNames = Object.keys(serviceMethod.fields ?? {}); const hasParams = fieldNames.length > 0; let isOptional = false; // // if no params, then let's default to empty object for cleaner API if (!hasParams) { isOptional = true; } else if (hasParams && fieldNames.length === 1 && fieldNames.includes('pagination')) { // if only argument "required" is pagination // also default to empty isOptional = true; } const storeClassName = makeQueryStoreName(name); const storeQueryClass = t.classDeclaration(t.identifier(storeClassName), null, t.classBody([ t.classProperty(t.identifier('store'), newExpression(t.identifier('QueryStore'), [ t.optionalMemberExpression(t.identifier('queryService'), t.identifier(name), false, true) ], t.tsTypeParameterInstantiation([ t.tsTypeReference(t.identifier(requestType)), t.tsTypeReference(t.identifier(responseType)) ]))), t.classMethod('method', t.identifier(name), [ identifier('request', t.tsTypeAnnotation(t.tsTypeReference(t.identifier(requestType)))) ], t.blockStatement([ t.returnStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('store')), t.identifier('getData')), [t.identifier('request')])) ], [])) ])); return storeQueryClass; };