UNPKG

@cosmology/ast

Version:
329 lines (328 loc) 14.6 kB
"use strict"; 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.createGRPCGatewayWrapperClass = exports.createGRPCGatewayQueryClass = void 0; const utils_1 = require("../../../../utils"); const utils_2 = require("@cosmology/utils"); const rpc_1 = require("../utils/rpc"); const utils_3 = require("./utils"); const t = __importStar(require("@babel/types")); const getFetchReqArgsService = (name, packageImport) => { // this hack around shouldn't exist, contact sdk team to modify the path for broadcastTx if (name === 'broadcastTx') { name = 'txs'; } const fetchArgs = []; // first argument of fetchReq const argTemplateLiteral = t.templateLiteral([ t.templateElement({ raw: '/' + packageImport.replace(/\./g, "/") + '/' + name, cooked: '/' + packageImport.replace(/\./g, "/") + '/' + name }, true) ], // quasis []); // adds proto path to fetchReq fetchArgs.push(argTemplateLiteral); // initReqProperties (contains information for initReq parameter in fetchReq) arguments: const initReqProperties = (0, utils_3.getInitReqProperties)(); const fetchArgsInitReqObj = t.objectExpression(initReqProperties); // adds initReq parameter to fetchReq fetchArgs.push(fetchArgsInitReqObj); return fetchArgs; }; const grpcGatewayPOSTServiceMethodDefinition = (name, svc, packageImport, leadingComments) => { const requestType = svc.requestType; const responseType = svc.responseType; const fieldNames = Object.keys(svc.fields ?? {}); const hasParams = fieldNames.length > 0; const optional = (0, rpc_1.optionalBool)(hasParams, fieldNames); // first parameter in method // ex: static Send(request: MsgSend) // paramRequest is an object representing everything in brackets here const paramRequest = (0, utils_1.identifier)('request', t.tsTypeAnnotation(t.tsTypeReference(t.identifier(requestType))), optional); // fetchArgs will be used in method body's return statement expression. // Contains arguments to fm.fetchReq // this one is different from the Msg, especially the package name const fetchArgs = getFetchReqArgsService(name, packageImport); // method's body const body = t.blockStatement([ t.returnStatement(t.callExpression(t.memberExpression(t.identifier('fm'), t.identifier('fetchReq')), fetchArgs)) ]); return (0, utils_1.classMethod)('method', t.identifier(name), [paramRequest, utils_3.initRequest], // params body, (0, rpc_1.returnReponseType)(responseType), leadingComments, false, true); }; const staticExpressionsNoParams = t.callExpression(t.memberExpression(t.identifier('fm'), t.identifier('renderURLSearchParams'), false), [ t.objectExpression([ t.spreadElement(t.identifier('request')) ]), t.arrayExpression([]) ]); // {...initReq, method: "GET"} const staticSecondFetchReqArg = t.objectExpression([ t.spreadElement(t.identifier('initRequest')), t.objectProperty(t.identifier('method'), t.stringLiteral('GET'), false, false) ]); const getQuasisNoParams = (path) => { let quasis = []; // path? // ex: /cosmos/bank/v1beta1/supply? quasis.push(t.templateElement({ raw: path + '?', cooked: path + '?' }, false)); // add empty tail element quasis.push(t.templateElement({ raw: '', cooked: '' }, true)); return quasis; }; // get quasis (string expressions) when there is an Params element const getQuasisParams = (path, indicesLeft, indicesRight) => { let quasis = []; // add left path element to quasis (path before Params element) const firstPath = path.slice(0, indicesLeft[0]); quasis.push(t.templateElement({ raw: firstPath, cooked: firstPath, }, false)); // check if path end with param or quasis, get that quasis if any let lastPath = ''; if (indicesRight[indicesRight.length - 1] != path.length - 1) { lastPath = path.slice(indicesRight[indicesRight.length - 1] + 1, path.length); // console.log(lastPath); } // get paths in between params for (let i = 0; i < indicesLeft.length - 1; i++) { const tempPath = path.slice(indicesRight[i] + 1, indicesLeft[i + 1]); quasis.push(t.templateElement({ raw: tempPath, cooked: tempPath, }, false)); } // add remaining path (if exists) or only '?' sign quasis.push(t.templateElement({ raw: lastPath != '' ? lastPath + '?' : '?', cooked: lastPath != '' ? lastPath + '?' : '?' }, false)); // add empty tail element quasis.push(t.templateElement({ raw: '', cooked: '' }, true)); return quasis; }; const getExpressionsNoParams = () => { return [staticExpressionsNoParams]; }; // Get expressions for a path with Params. // Returning array must be of length 2. // example expressions: ${req["denom"]} AND ${fm.renderURLSearchParams(req, ["denom"])} const getExpressionsParams = (paramsName) => { let expressions = []; let arrParams = []; for (let i = 0; i < paramsName.length; i++) { // ${req["denom"]} expressions.push(t.memberExpression(t.identifier('request'), t.stringLiteral(paramsName[i]), true)); arrParams.push(t.stringLiteral(paramsName[i])); } // ${fm.renderURLSearchParams(req, ["denom"])} expressions.push(t.callExpression(t.memberExpression(t.identifier('fm'), t.identifier('renderURLSearchParams'), false), [ t.objectExpression([ t.spreadElement(t.identifier('request')) ]), t.arrayExpression(arrParams) ])); return expressions; }; // Get fm.fetchReq arguments if there is no Params element // In this case, len of quasis must be 2 and len of expressions must be 1. const getFetchReqArgsNoParams = (path) => { let args = []; const quasis = getQuasisNoParams(path); const expressions = getExpressionsNoParams(); args.push(t.templateLiteral(quasis, expressions)); // {...initReq, method: "GET"} args.push(staticSecondFetchReqArg); return args; }; // Get fm.fetchReq arguments if there is an Params element const getFetchReqArgsParams = (path, indicesLeft, indicesRight) => { let args = []; // first argument // ex: `/cosmos/staking/v1beta1/delegators/${req["delegator_addr"]}/validators/${req["validator_addr"]}? => quasis // ${fm.renderURLSearchParams(req, ["delegator_addr", "validator_addr"])}` => expressions let paramsName = []; for (let i = 0; i < indicesLeft.length; i++) { paramsName.push(path.slice(indicesLeft[i] + 1, indicesRight[i])); } const quasis = getQuasisParams(path, indicesLeft, indicesRight); const expressions = getExpressionsParams(paramsName); args.push(t.templateLiteral(quasis, expressions)); // {...initReq, method: "GET"} args.push(staticSecondFetchReqArg); return args; }; // fetchArgs will be used in method body's return statement expression. // Contains arguments to fm.fetchReq const getFetchReqArgs = (context, svc) => { // getPath ex: // rpc Grants(QueryGrantsRequest) returns (QueryGrantsResponse) { // option (google.api.http).get = "/cosmos/authz/v1beta1/grants"; // } let getPath; try { getPath = svc.options['(google.api.http).get']; } catch { } if ((typeof getPath) === 'undefined') { getPath = context.ref.proto.package + '.' + svc.name; } let args; // check if getPath contains params // ex: "/cosmos/bank/v1beta1/balances/{address}" // NOTE: {address} here is param // contains params if (getPath.indexOf('{') > -1) { // get all indices of '{' and '}' from path. const indicesLeft = [...getPath.matchAll(/{/g)].map(match => match.index); const indicesRight = [...getPath.matchAll(/}/g)].map(match => match.index); args = getFetchReqArgsParams(getPath, indicesLeft, indicesRight); } else { // contains no params args = getFetchReqArgsNoParams(getPath); } return args; }; // function to define a method of grpc-gateway fetch request const grpcGatewayMethodDefinition = (context, name, svc, leadingComments) => { const requestType = svc.requestType; const responseType = svc.responseType; // first parameter in method // ex: static Send(request: MsgSend) // paramRequest is an object representing everything in brackets here const paramRequest = (0, utils_1.identifier)('request', t.tsTypeAnnotation(t.tsTypeReference(t.identifier(requestType))), false); // fm.fetchReq(fetchArgs are here) const fetchArgs = getFetchReqArgs(context, svc); // class method body (only return statement) const body = t.blockStatement([ t.returnStatement(t.callExpression(t.memberExpression(t.identifier('fm'), t.identifier('fetchReq'), false), fetchArgs)) ]); return (0, utils_1.classMethod)('method', t.identifier(name), [paramRequest, utils_3.initRequest], // params body, (0, rpc_1.returnReponseType)(responseType), leadingComments, false, true); }; const createGRPCGatewayQueryClass = (context, service) => { // adds import context.addUtil('fm'); const camelRpcMethods = context.pluginValue('rpcClients.camelCase'); const keys = Object.keys(service.methods ?? {}); //two different ways to generate methods for Query and Service let methods; //case Query if (service.name === "Query") { methods = keys .map(key => { const method = service.methods[key]; const name = camelRpcMethods ? (0, utils_2.camel)(key) : key; const leadingComments = method.comment ? [(0, utils_1.commentBlock)((0, rpc_1.processRpcComment)(method))] : []; return grpcGatewayMethodDefinition(context, name, method, leadingComments); }); } else { //case Service methods = keys .map(key => { const isGet = key.substring(0, 3) === "Get"; const method = service.methods[key]; const name = camelRpcMethods ? (0, utils_2.camel)(key) : key; const leadingComments = method.comment ? [(0, utils_1.commentBlock)((0, rpc_1.processRpcComment)(method))] : []; if (!isGet) { //POST METHOD return grpcGatewayPOSTServiceMethodDefinition(name, method, context.ref.proto.package, leadingComments); } else { return grpcGatewayMethodDefinition(context, name, method, leadingComments); } }); } return t.exportNamedDeclaration(t.classDeclaration(t.identifier(service.name), null, t.classBody([ ...methods, ]), [])); }; exports.createGRPCGatewayQueryClass = createGRPCGatewayQueryClass; // function to define a method of grpc-gateway style const grpcGatewayQuerierMethodDefinition = (serviceName, context, name, svc, leadingComments) => { const requestType = svc.requestType; const responseType = svc.responseType; // first parameter in method // ex: static Send(request: MsgSend) // paramRequest is an object representing everything in brackets here const paramRequest = (0, utils_1.identifier)('req', t.tsTypeAnnotation(t.tsTypeReference(t.identifier(requestType))), false); // class method body (only return statement) const body = t.blockStatement([ t.returnStatement(t.callExpression(t.memberExpression(t.identifier(serviceName), t.identifier(name), false), [ t.identifier('req'), t.objectExpression([ t.objectProperty(t.identifier('headers'), t.identifier('headers'), false, true), t.objectProperty(t.identifier('pathPrefix'), t.memberExpression(t.thisExpression(), t.identifier('url'))) ]) ])) ]); return (0, utils_1.classMethod)('method', t.identifier(name), [paramRequest, utils_3.headersInit], // params body, (0, rpc_1.returnReponseType)(responseType), leadingComments, false, false, // static false, true // async ); }; const createGRPCGatewayWrapperClass = (context, service) => { const serviceName = service.name; let className; if (serviceName === 'Query') { // QueryClientImp for wrapper class className = 'QueryClientImpl'; } else { className = 'ServiceClientImpl'; } const camelRpcMethods = context.pluginValue('rpcClients.camelCase'); const keys = Object.keys(service.methods ?? {}); const methods = keys .map(key => { const method = service.methods[key]; const name = camelRpcMethods ? (0, utils_2.camel)(key) : key; const leadingComments = method.comment ? [(0, utils_1.commentBlock)((0, rpc_1.processRpcComment)(method))] : []; return grpcGatewayQuerierMethodDefinition(serviceName, context, name, method, leadingComments); }); return t.exportNamedDeclaration(t.classDeclaration(t.identifier(className), null, t.classBody([ (0, utils_1.classProperty)(t.identifier('url'), null, t.tsTypeAnnotation(t.tsStringKeyword()), [], false, false, true, "private"), t.classMethod('constructor', t.identifier('constructor'), [ (0, utils_1.identifier)('url', t.tsTypeAnnotation(t.tsStringKeyword())) ], t.blockStatement([ t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier('url')), t.identifier('url'))) ])), ...methods, ]), [])); }; exports.createGRPCGatewayWrapperClass = createGRPCGatewayWrapperClass;