Skip to content

Commit

Permalink
feat: support proto packages in different namespace (#219)
Browse files Browse the repository at this point in the history
* logic for parsing proto package

* add unit test

* lint fix

* lint

* feedback

* no else if
  • Loading branch information
xiaozhenliu-gg5 committed Jan 31, 2020
1 parent 8e3f9a1 commit 90177c6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 12 deletions.
12 changes: 5 additions & 7 deletions typescript/src/schema/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import * as plugin from '../../../pbjs-genfiles/plugin';
import * as fs from 'fs';
import * as path from 'path';

import { Naming } from './naming';
import { Naming, Options as namingOptions } from './naming';
import { Proto, MessagesMap } from './proto';
import { ResourceDatabase, ResourceDescriptor } from './resourceDatabase';
import { Options } from 'yargs-parser';

const googleGaxLocation = path.dirname(require.resolve('google-gax'));
const gaxProtosLocation = path.join(googleGaxLocation, '..', '..', 'protos');
Expand All @@ -41,16 +42,13 @@ export class API {
constructor(
fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[],
packageName: string,
options: {
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig;
publishName?: string;
mainServiceName?: string;
}
options: namingOptions
) {
this.naming = new Naming(
fileDescriptors.filter(
fd => fd.package && fd.package.startsWith(packageName)
)
),
options
);
// users specify the actual package name, if not, set it to product name.
this.publishName =
Expand Down
35 changes: 32 additions & 3 deletions typescript/src/schema/naming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@
import * as plugin from '../../../pbjs-genfiles/plugin';
import { commonPrefix } from '../util';

export interface Options {
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig;
publishName?: string;
mainServiceName?: string;
}
export class Naming {
name: string;
namespace: string[];
version: string;
productName: string;
protoPackage: string;

constructor(fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[]) {
constructor(
fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[],
options?: Options
) {
let rootPackage = '';
const mainServiceName = options ? options.mainServiceName : '';
const protoPackages = fileDescriptors
.filter(fd => fd.service && fd.service.length > 0)
// LRO is an exception: it's a service but we don't generate any code for it
Expand All @@ -31,10 +41,17 @@ export class Naming {
const prefix = commonPrefix(protoPackages);
// common prefix must either end with `.`, or be equal to at least one of
// the packages' prefix
if (!prefix.endsWith('.') && !protoPackages.some(pkg => pkg === prefix)) {
const invalidPrefix =
!prefix.endsWith('.') && !protoPackages.some(pkg => pkg === prefix);
if (invalidPrefix && mainServiceName) {
rootPackage = this.checkServiceInPackage(protoPackages, mainServiceName);
}
if (invalidPrefix && !mainServiceName) {
throw new Error('Protos provided have different proto packages.');
}
const rootPackage = prefix.replace(/\.$/, '');
if (!invalidPrefix) {
rootPackage = prefix.replace(/\.$/, '');
}
const segments = rootPackage.split('.');
if (!segments || segments.length < 2) {
throw new Error(`Cannot parse package name ${rootPackage}.`);
Expand All @@ -61,4 +78,16 @@ export class Naming {
);
}
}

private checkServiceInPackage(
protoPackages: string[],
mainServiceName: string
) {
for (const packageName of protoPackages) {
if (packageName.indexOf(mainServiceName.toLowerCase()) !== -1) {
return packageName;
}
}
return '';
}
}
26 changes: 24 additions & 2 deletions typescript/test/unit/naming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import * as assert from 'assert';
import { describe, it } from 'mocha';
import * as plugin from '../../../pbjs-genfiles/plugin';
import { Naming } from '../../src/schema/naming';
import { Naming, Options } from '../../src/schema/naming';

describe('schema/naming.ts', () => {
it('parses name correctly', () => {
Expand Down Expand Up @@ -113,7 +113,7 @@ describe('schema/naming.ts', () => {
});
});

it('fails if no common package', () => {
it('fails if no common package, no service-name', () => {
const descriptor1 = new plugin.google.protobuf.FileDescriptorProto();
const descriptor2 = new plugin.google.protobuf.FileDescriptorProto();
descriptor1.package = 'namespace1.service.v1beta1';
Expand All @@ -125,6 +125,28 @@ describe('schema/naming.ts', () => {
});
});

it('parse name correctly if no common package, but service-name specified', () => {
const descriptor1 = new plugin.google.protobuf.FileDescriptorProto();
const descriptor2 = new plugin.google.protobuf.FileDescriptorProto();
descriptor1.package = 'namespace1.service1.v1beta1';
descriptor1.service = [new plugin.google.protobuf.ServiceDescriptorProto()];
descriptor2.package = 'namespace2.service2.v1beta1';
descriptor2.service = [new plugin.google.protobuf.ServiceDescriptorProto()];
const serviceConfig = new plugin.grpc.service_config.ServiceConfig();
const options: Options = {
grpcServiceConfig: serviceConfig,
mainServiceName: 'service1',
};
assert.throws(() => {
const naming = new Naming([descriptor1, descriptor2], options);
assert.strictEqual(naming.name, 'service1');
assert.strictEqual(naming.productName, 'service1');
assert.strictEqual(naming.version, 'v1beta1');
assert.strictEqual(naming.namespace, 'namespace1');
assert.strictEqual(naming.protoPackage, 'namespace1.service1.v1beta1');
});
});

it('fails if different versions', () => {
const descriptor1 = new plugin.google.protobuf.FileDescriptorProto();
const descriptor2 = new plugin.google.protobuf.FileDescriptorProto();
Expand Down

0 comments on commit 90177c6

Please sign in to comment.