UNPKG

@cosmology/ast

Version:
287 lines (286 loc) 17.5 kB
import { arrowFunctionExpression, classDeclaration, classMethod, classProperty, commentBlock, identifier, tsMethodSignature } from '../../../../utils'; import { camel } from '@cosmology/utils'; import { processRpcComment, returnReponseType, optionalBool } from '../utils/rpc'; import { metadata, bindThis, makeComment, getRpcClassName } from './utils'; import * as t from '@babel/types'; const gRPCWebMethodDefinition = (name, svc, trailingComments, leadingComments) => { const requestType = svc.requestType; const responseType = svc.responseType; const fieldNames = Object.keys(svc.fields ?? {}); const hasParams = fieldNames.length > 0; const optional = optionalBool(hasParams, fieldNames); const methodArgs = identifier('request', t.tsTypeAnnotation(t.tsTypeReference(t.identifier('DeepPartial'), t.tsTypeParameterInstantiation([ t.tsTypeReference(t.identifier(requestType)) ]))), optional); const metadataArgs = metadata; return tsMethodSignature(t.identifier(name), null, [ methodArgs, metadataArgs ], returnReponseType(responseType), trailingComments, leadingComments); }; export const createGrpcWebMsgInterface = (context, service) => { 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 ? camel(key) : key; const leadingComments = method.comment ? [commentBlock(processRpcComment(method))] : []; let trailingComments = []; return gRPCWebMethodDefinition(name, method, trailingComments, leadingComments); }); const obj = t.exportNamedDeclaration(t.tsInterfaceDeclaration(t.identifier(service.name), null, [], t.tsInterfaceBody([ ...methods ]))); if (service.comment) { obj.leadingComments = [commentBlock(`* ${service.comment} `)]; } return obj; }; const rpcClassConstructor = (context, methods) => { let bound = []; if (!context.pluginValue('classesUseArrowFunctions')) { bound = methods.map(method => bindThis(method)); } return classMethod('constructor', t.identifier('constructor'), [ identifier('rpc', t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Rpc')))) ], t.blockStatement([ t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier('rpc')), t.identifier('rpc'))), /// methods ...bound ])); }; const rpcClassMethod = (context, name, msg, svc, packageImport) => { let partialName = 'DeepPartial'; let optional = false; const requestType = svc.requestType; const responseType = svc.responseType; const comment = svc.comment ?? svc.name; let methodArgs = identifier('request', t.tsTypeAnnotation(t.tsTypeReference(t.identifier(partialName), t.tsTypeParameterInstantiation([ t.tsTypeReference(t.identifier(requestType)) ])))); const metadataArgs = metadata; const fieldNames = Object.keys(svc.fields ?? {}); const hasParams = fieldNames.length > 0; // if no params, then let's default to empty object for cleaner API if (!hasParams) { methodArgs = t.assignmentPattern(methodArgs, t.objectExpression([])); } else if (hasParams && fieldNames.length === 1 && fieldNames.includes('pagination')) { const paginationDefaultFromPartial = context.pluginValue('prototypes.paginationDefaultFromPartial'); // if only argument "required" is pagination // also default to empty methodArgs = t.assignmentPattern(methodArgs, t.objectExpression([ t.objectProperty(t.identifier('pagination'), paginationDefaultFromPartial ? t.callExpression(t.memberExpression(t.identifier("PageRequest"), t.identifier("fromPartial")), [t.objectExpression([])]) : t.identifier('undefined'), false, false) ])); } const body = t.blockStatement([ t.returnStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('rpc')), t.identifier('unary')), [ //No Desc field so we need to modify it t.identifier(requestType.concat('Desc')), t.callExpression(t.memberExpression(t.identifier(requestType), t.identifier('fromPartial')), [ t.identifier('request') ]), t.identifier('metadata') ])) ]); if (context.pluginValue('classesUseArrowFunctions')) { return classProperty(t.identifier(name), arrowFunctionExpression([methodArgs], body, returnReponseType(responseType), true), undefined, undefined, undefined, undefined, undefined, undefined, makeComment(comment)); } return classMethod('method', t.identifier(name), [ methodArgs, metadataArgs ], body, returnReponseType(responseType)); }; export const createGrpcWebMsgClass = (context, service) => { context.addUtil('UnaryMethodDefinitionish'); context.addUtil('_m0'); context.addUtil('DeepPartial'); context.addUtil('grpc'); const camelRpcMethods = context.pluginValue('rpcClients.camelCase'); const name = getRpcClassName(service); const implementsName = service.name; const methodNames = Object.keys(service.methods ?? {}) .map(key => { return camelRpcMethods ? camel(key) : key; }); const methods = Object.keys(service.methods ?? {}) .map(key => { const method = service.methods[key]; const name = camelRpcMethods ? camel(key) : key; return rpcClassMethod(context, name, key, method, context.ref.proto.package + '.' + service.name); }); return t.exportNamedDeclaration(classDeclaration(t.identifier(name), null, t.classBody([ classProperty(t.identifier('rpc'), null, t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Rpc'))), null, false, false, true, 'private'), // CONSTRUCTOR rpcClassConstructor(context, methodNames), // METHODS ...methods ]), null, [ t.tsExpressionWithTypeArguments(t.identifier(implementsName)) ])); }; const rpcMethodDef = (svc) => { const requestType = svc.requestType; const responseType = svc.responseType; const methodName = svc.name; return { methodName, requestType, responseType }; }; //return array of method Desc export const getMethodDesc = (context, service) => { //get all method that need Desc const methods = Object.keys(service.methods ?? {}) .map(key => { return rpcMethodDef(service.methods[key]); }); const methodsDesc = []; //check if service name is 'service' if it is then ommit it because proto method doesn't contain service prefix in it methods let service_name = service.name; if (service_name == 'Service') { service_name = ''; } for (let i = 0; i < methods.length; i++) { const methodName = methods[i].methodName; const requestType = methods[i].requestType; const responseType = methods[i].responseType; const methodDesc = t.exportNamedDeclaration(t.variableDeclaration('const', [ t.variableDeclarator(t.identifier(service_name + methodName + 'Desc: UnaryMethodDefinitionish'), t.objectExpression([ t.objectProperty(t.identifier('methodName'), t.stringLiteral(methodName)), t.objectProperty(t.identifier('service'), t.identifier(service.name + 'Desc')), t.objectProperty(t.identifier('requestStream'), t.booleanLiteral(false)), t.objectProperty(t.identifier('responseStream'), t.booleanLiteral(false)), t.objectProperty(t.identifier('requestType'), t.tsAsExpression(t.objectExpression([ t.objectMethod('method', t.identifier('serializeBinary'), [], t.blockStatement([ t.returnStatement(t.callExpression(t.memberExpression(t.callExpression(t.memberExpression(t.identifier(requestType), t.identifier('encode')), [ t.thisExpression() ]), t.identifier('finish')), [])) ])) ]), t.tsAnyKeyword())), t.objectProperty(t.identifier('responseType'), t.tsAsExpression(t.objectExpression([ t.objectMethod('method', t.identifier('deserializeBinary'), [ identifier('data', t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Uint8Array')))) ], t.blockStatement([ t.returnStatement(t.objectExpression([ t.spreadElement(t.callExpression(t.memberExpression(t.identifier(responseType), t.identifier('decode')), [t.identifier('data')])), t.objectMethod('method', t.identifier('toObject'), [], t.blockStatement([ t.returnStatement(t.thisExpression()) ])) ])) ])) ]), t.tsAnyKeyword())), ])) ])); methodsDesc.push(methodDesc); } return methodsDesc; }; export const GetDesc = (context, service) => { const descName = service.name + 'Desc'; const serviceName = context.ref.proto.package + '.' + service.name; return t.exportNamedDeclaration(t.variableDeclaration('const', [ t.variableDeclarator(t.identifier(descName), t.objectExpression([ t.objectProperty(t.identifier('serviceName'), t.stringLiteral(serviceName)) ])) ])); }; export const grpcWebRpcInterface = () => { return t.exportNamedDeclaration(t.tsInterfaceDeclaration(t.identifier('Rpc'), null, [], t.tsInterfaceBody([ t.tsMethodSignature(t.identifier('unary'), t.tsTypeParameterDeclaration([ t.tsTypeParameter(t.tsTypeReference(t.identifier('UnaryMethodDefinitionish')), null, 'T') ]), [ identifier('methodDesc', t.tsTypeAnnotation(t.tsTypeReference(t.identifier('T')))), identifier('request', t.tsTypeAnnotation(t.tsAnyKeyword())), identifier('metadata', t.tsTypeAnnotation(t.tSUnionType([ t.tsTypeReference(t.tsQualifiedName(t.identifier('grpc'), t.identifier('Metadata'))), t.tsUndefinedKeyword() ]))), ], t.tsTypeAnnotation(t.tSTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([ t.tsAnyKeyword() ])))) ]))); }; //you might not want to look at this export const getGrpcWebImpl = (context) => { context.addUtil('BrowserHeaders'); return t.exportNamedDeclaration(t.classDeclaration(t.identifier('GrpcWebImpl'), null, t.classBody([ t.classProperty(t.identifier('host'), null, t.tsTypeAnnotation(t.tsStringKeyword())), t.classProperty(t.identifier('options'), null, t.tsTypeAnnotation(t.tsTypeLiteral([ t.tsPropertySignature(t.identifier('transport?'), t.tsTypeAnnotation(t.tsTypeReference(t.tsQualifiedName(t.identifier('grpc'), t.identifier('TransportFactory'))))), t.tsPropertySignature(t.identifier('debug?'), t.tsTypeAnnotation(t.tsBooleanKeyword())), t.tsPropertySignature(t.identifier('metadata?'), t.tsTypeAnnotation(t.tsTypeReference(t.tsQualifiedName(t.identifier('grpc'), t.identifier('Metadata'))))) ]))), t.classMethod("constructor", t.identifier('constructor'), [ identifier("host", t.tsTypeAnnotation(t.tsStringKeyword())), identifier("options", t.tsTypeAnnotation(t.tsTypeLiteral([ t.tsPropertySignature(t.identifier('transport?'), t.tsTypeAnnotation(t.tsTypeReference(t.tsQualifiedName(t.identifier('grpc'), t.identifier('TransportFactory'))))), t.tsPropertySignature(t.identifier('debug?'), t.tsTypeAnnotation(t.tsBooleanKeyword())), t.tsPropertySignature(t.identifier('metadata?'), t.tsTypeAnnotation(t.tsTypeReference(t.tsQualifiedName(t.identifier('grpc'), t.identifier('Metadata'))))) ]))) ], t.blockStatement([ t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.thisExpression(), t.identifier('host')), t.identifier('host'))), t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.thisExpression(), t.identifier('options')), t.identifier('options'))), ])), t.classMethod("method", t.identifier('unary<T extends UnaryMethodDefinitionish>'), [ identifier('methodDesc', t.tsTypeAnnotation(t.tsTypeReference(t.identifier('T')))), identifier('_request', t.tsTypeAnnotation(t.tsAnyKeyword())), identifier('metadata', t.tsTypeAnnotation(t.tsUnionType([t.tsTypeReference(t.tsQualifiedName(t.identifier('grpc'), t.identifier('Metadata'))), t.tsUndefinedKeyword()]))) ], t.blockStatement([ t.variableDeclaration("const", [ t.variableDeclarator(t.identifier('request'), t.objectExpression([ t.spreadElement(t.identifier('_request')), t.spreadElement(t.memberExpression(t.identifier('methodDesc'), t.identifier('requestType'))) ])) ]), t.variableDeclaration("const", [ t.variableDeclarator(t.identifier('maybeCombinedMetadata'), t.conditionalExpression(t.logicalExpression("&&", t.identifier('metadata'), t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('options')), t.identifier('metadata'))), t.newExpression(t.identifier('BrowserHeaders'), [ t.objectExpression([ t.spreadElement(t.optionalMemberExpression(t.optionalMemberExpression(t.memberExpression(t.thisExpression(), t.identifier('options'), false), t.identifier('metadata'), false, true), t.identifier('headersMap'), false, false)), t.spreadElement(t.optionalMemberExpression(t.identifier('metadata'), t.identifier('headersMap'), false, true)) ]) ]), t.logicalExpression("||", t.identifier('metadata'), t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('options')), t.identifier('metadata'))))) ]), t.returnStatement(t.newExpression(t.identifier('Promise'), [ t.arrowFunctionExpression([ t.identifier('resolve'), t.identifier('reject') ], t.blockStatement([ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('grpc'), t.identifier('unary')), [ t.identifier('methodDesc'), t.objectExpression([ t.objectProperty(t.identifier('request'), t.identifier('request'), false, true), t.objectProperty(t.identifier('host'), t.memberExpression(t.thisExpression(), t.identifier('host'))), t.objectProperty(t.identifier('metadata'), t.identifier('maybeCombinedMetadata')), t.objectProperty(t.identifier('transport'), t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('options')), t.identifier('transport'))), t.objectProperty(t.identifier('debug'), t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('options')), t.identifier('debug'))), t.objectProperty(t.identifier('onEnd'), t.functionExpression(null, [ t.identifier('response') ], t.blockStatement([ t.ifStatement(t.binaryExpression("===", t.memberExpression(t.identifier('response'), t.identifier('status')), t.memberExpression(t.memberExpression(t.identifier('grpc'), t.identifier('Code')), t.identifier('OK'))), t.blockStatement([ t.expressionStatement(t.callExpression(t.identifier('resolve'), [ t.memberExpression(t.identifier('response'), t.identifier('message')) ])) ]), t.blockStatement([ t.variableDeclaration("const", [ t.variableDeclarator(t.identifier('err'), t.tsAsExpression(t.newExpression(t.identifier('Error'), [ t.memberExpression(t.identifier('response'), t.identifier('statusMessage')) ]), t.tsAnyKeyword())) ]), t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.identifier('err'), t.identifier('code')), t.memberExpression(t.identifier('response'), t.identifier('status')))), t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.identifier('err'), t.identifier('metadata')), t.memberExpression(t.identifier('response'), t.identifier('trailers')))), t.expressionStatement(t.callExpression(t.identifier('reject'), [ t.identifier('err') ])) ])) ]))) ]) ])) ])) ])) ])) ]))); };