diff --git a/src/cli.ts b/src/cli.ts index 71cb1ee..bfcf77d 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -123,6 +123,7 @@ function transformTypeScriptSource(source: string) { source = source.replace(/^import.*?$\n?/gm, ''); // Add our imports source = `import { Observable } from 'rxjs';\n${source}`; + source = `import * as grpc from 'grpc';\n${source}`; if (source.includes('$protobuf')) { source = `import * as $protobuf from 'protobufjs';\n${source}`; @@ -242,10 +243,10 @@ function cleanMethodSignatures(ast: Collection) { // The promise variant of service methods are after the method declerations, // so the last method will have its comment followed by a return statement. - ast.find(jscodeshift.ExpressionStatement).forEach(fixReturnType); - ast.find(jscodeshift.ReturnStatement).forEach(fixReturnType); + ast.find(jscodeshift.ExpressionStatement).forEach(fixPromiseMethodSignature); + ast.find(jscodeshift.ReturnStatement).forEach(fixPromiseMethodSignature); - function fixReturnType( + function fixPromiseMethodSignature( path: ASTPath, ) { if (!path.node.comments) { @@ -258,6 +259,11 @@ function cleanMethodSignatures(ast: Collection) { changed = true; comment.value = comment.value.replace(returnsPromiseRe, '$1Observable$2'); comment.value = comment.value.replace(/(@param\s+\{.*?\.)I([^.]+\})/g, '$1$2'); + // Add optional metadata parameter + comment.value = comment.value.replace( + /^([\s\*]+@param\s+)(\{.*)$/gm, + '$1$2$1{grpc.Metadata=} metadata Optional metadata', + ); } }); if (changed) { diff --git a/src/tests/metadata.test.ts b/src/tests/metadata.test.ts new file mode 100644 index 0000000..b6fd49b --- /dev/null +++ b/src/tests/metadata.test.ts @@ -0,0 +1,93 @@ +import * as cli from '../cli'; + +import { compileInMemory } from './utils'; + +describe('metadata test', () => { + let namespaces: string; + + beforeAll(async () => { + namespaces = await cli.buildTypeScriptFromSources([ + ` + syntax = "proto3"; + package test; + + service Service { + rpc Single (Message) returns (Message) {} + } + + message Message { + string field = 1; + } + `, + ]); + }); + + it('should accept metadata object', async () => { + const result = compileInMemory({ + 'grpc-namespaces.ts': namespaces, + 'test.ts': ` + import { Metadata } from 'grpc'; + import { clientFactory } from 'rxjs-grpc'; + + import { test } from './grpc-namespaces'; + + const Services = clientFactory('test.proto', 'test'); + + const services = new Services('localhost:1234'); + const Service = services.getService(); + + Service.single({ field: 'string' }, new Metadata()); + `, + }); + expect(result.errors).toEqual([]); + expect(result.ok).toBe(true); + }); + + it('should not accept invalid metadata object', async () => { + const result = compileInMemory({ + 'grpc-namespaces.ts': namespaces, + 'test.ts': ` + import { Metadata } from 'grpc'; + import { clientFactory } from 'rxjs-grpc'; + + import { test } from './grpc-namespaces'; + + const Services = clientFactory('test.proto', 'test'); + + const services = new Services('localhost:1234'); + const Service = services.getService(); + + Service.single({ field: 'string' }, { NOT_A_METADATA: 'yes' }); + `, + }); + expect(result.errors.length).toBeGreaterThan(0); + expect(result.ok).toBe(false); + }); + + it('should pass metadata object', async () => { + const result = compileInMemory({ + 'grpc-namespaces.ts': namespaces, + 'test.ts': ` + import { of } from 'rxjs'; + import { serverBuilder } from 'rxjs-grpc'; + + import { test } from './grpc-namespaces'; + + const server = serverBuilder('test.proto', 'test'); + + server.addService({ + + single(request, metadata) { + console.log(metadata.get('test')); + return of(); + } + + }); + + server.start('0.0.0.0:1234'); + `, + }); + expect(result.errors).toEqual([]); + expect(result.ok).toBe(true); + }); +});