Skip to content

Commit

Permalink
feat: let user pass package name to the generator (#148)
Browse files Browse the repository at this point in the history
* let user pass package name to generator

* feedback

* use param map for options

* throw error if grpc file does not exist

* make paramMap a member of generator class

* comment
  • Loading branch information
xiaozhenliu-gg5 authored Nov 20, 2019
1 parent 68e8a14 commit 5583523
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 24 deletions.
2 changes: 1 addition & 1 deletion templates/typescript_gapic/package.json.njk
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.
-#}
{
"name": "{{ api.naming.productName.toKebabCase() }}",
"name": "{{ api.publishName }}",
"version": "0.1.0",
"description": "{{ api.naming.productName }} client for Node.js",
"repository": "googleapis/nodejs-{{ api.naming.productName.toKebabCase() }}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ limitations under the License.
{{license.license()}}

/* eslint-disable node/no-missing-require, no-unused-vars */
const {{ api.naming.productName.toKebabCase()}} = require('{{ api.naming.productName.toKebabCase() }}');
const {{ api.naming.productName.toKebabCase()}} = require('{{ api.publishName }}');

function main() {
{%- for service in api.services %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
{{- serviceJoiner() -}}
{{- service.name.toPascalCase() + 'Client' -}}
{%- endfor -%}
} from '{{ api.naming.productName.toKebabCase() }}';
} from '{{ api.publishName }}';

function main() {
{%- for service in api.services %}
Expand Down
55 changes: 40 additions & 15 deletions typescript/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import { API } from './schema/api';
import { processTemplates } from './templater';
import { commonPrefix, duration } from './util';

export interface OptionsMap {
[name: string]: string;
}
const readFile = util.promisify(fs.readFile);

const templateDirectory = path.join(
Expand All @@ -32,18 +35,23 @@ const templateDirectory = path.join(
'templates',
'typescript_gapic'
);

// If needed, we can make it possible to load templates from different locations
// to generate code for other languages.

export class Generator {
request: plugin.google.protobuf.compiler.CodeGeneratorRequest;
response: plugin.google.protobuf.compiler.CodeGeneratorResponse;
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig;
paramMap: OptionsMap;
// This field is for users passing proper publish package name like @google-cloud/text-to-speech.
publishName?: string;

constructor() {
this.request = plugin.google.protobuf.compiler.CodeGeneratorRequest.create();
this.response = plugin.google.protobuf.compiler.CodeGeneratorResponse.create();
this.grpcServiceConfig = plugin.grpc.service_config.ServiceConfig.create();
this.paramMap = {};
}

// Fixes gRPC service config to replace string google.protobuf.Duration
Expand All @@ -65,22 +73,36 @@ export class Generator {
}
}

private async readGrpcServiceConfig(parameter: string) {
const match = parameter.match(/^["']?grpc-service-config=([^"]+)["']?$/);
if (!match) {
throw new Error(`Parameter ${parameter} was not recognized.`);
private getParamMap(parameter: string) {
// Example: "grpc-service-config=texamplejson","package-name=packageName"
const parameters = parameter.split(',');
for (let param of parameters) {
// remove double quote
param = param.substring(1, param.length - 1);
const arr = param.split('=');
this.paramMap[arr[0].toKebabCase()] = arr[1];
}
const filename = match[1];
if (!fs.existsSync(filename)) {
throw new Error(`File ${filename} cannot be opened.`);
}

private async readGrpcServiceConfig(map: OptionsMap) {
if (map && map['grpc-service-config']) {
const filename = map['grpc-service-config'];
if (!fs.existsSync(filename)) {
throw new Error(`File ${filename} cannot be opened.`);
}
const content = await readFile(filename);
const json = JSON.parse(content.toString());
Generator.updateDuration(json);
this.grpcServiceConfig = plugin.grpc.service_config.ServiceConfig.fromObject(
json
);
}
}

const content = await readFile(filename);
const json = JSON.parse(content.toString());
Generator.updateDuration(json);
this.grpcServiceConfig = plugin.grpc.service_config.ServiceConfig.fromObject(
json
);
private async readPublishPackageName(map: OptionsMap) {
if (map && map['package-name']) {
this.publishName = map['package-name'];
}
}

async initializeFromStdin() {
Expand All @@ -89,7 +111,9 @@ export class Generator {
inputBuffer
);
if (this.request.parameter) {
await this.readGrpcServiceConfig(this.request.parameter);
this.getParamMap(this.request.parameter);
await this.readGrpcServiceConfig(this.paramMap);
await this.readPublishPackageName(this.paramMap);
}
}

Expand Down Expand Up @@ -125,7 +149,8 @@ export class Generator {
const api = new API(
this.request.protoFile,
packageName,
this.grpcServiceConfig
this.grpcServiceConfig,
this.publishName
);
return api;
}
Expand Down
7 changes: 6 additions & 1 deletion typescript/src/schema/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,24 @@ export class API {
hostName?: string;
port?: string;
mainServiceName?: string;
// This field is for users passing proper publish package name like @google-cloud/text-to-speech.
publishName: string;
// oauth_scopes: plugin.google.protobuf.IServiceOptions.prototype[".google.api.oauthScopes"];
// TODO: subpackages

constructor(
fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[],
packageName: string,
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig,
publishName?: string
) {
this.naming = new Naming(
fileDescriptors.filter(
fd => fd.package && fd.package.startsWith(packageName)
)
);
// users specify the actual package name, if not, set it to product name.
this.publishName = publishName || this.naming.productName.toKebabCase();
// construct resource map
const resourceMap = getResourceMap(fileDescriptors);
// parse resource map to Proto constructor
Expand Down
6 changes: 6 additions & 0 deletions typescript/src/start_script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const argv = yargs
.describe('output_dir', 'Path to a directory for the generated code')
.alias('grpc-service-config', 'grpc_service_config')
.describe('grpc-service-config', 'Path to gRPC service config JSON')
.alias('package-name', 'package_name')
.describe('package-name', 'Publish package name')
.alias('common-proto-path', 'common_protos_path')
.describe(
'common_proto_path',
Expand All @@ -43,6 +45,7 @@ const argv = yargs
google/example/api/v1/api.proto`).argv;
const outputDir = argv.outputDir as string;
const grpcServiceConfig = argv.grpcServiceConfig as string | undefined;
const packageName = argv.packageName as string | undefined;

const protoDirs: string[] = [];
if (argv.I) {
Expand Down Expand Up @@ -71,6 +74,9 @@ if (grpcServiceConfig) {
`--typescript_gapic_opt="grpc-service-config=${grpcServiceConfig}"`
);
}
if (packageName) {
protocCommand.push(`--typescript_gapic_opt="package-name=${packageName}"`);
}
protocCommand.push(...protoDirsArg);
protocCommand.push(...protoFiles);
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "texttospeech",
"name": "@google-cloud/text-to-speech",
"version": "0.1.0",
"description": "Texttospeech client for Node.js",
"repository": "googleapis/nodejs-texttospeech",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


/* eslint-disable node/no-missing-require, no-unused-vars */
const texttospeech = require('texttospeech');
const texttospeech = require('@google-cloud/text-to-speech');

function main() {
const textToSpeechClient = new texttospeech.TextToSpeechClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// ** https://github.com/googleapis/gapic-generator-typescript **
// ** All changes to this file may be overwritten. **

import {TextToSpeechClient} from 'texttospeech';
import {TextToSpeechClient} from '@google-cloud/text-to-speech';

function main() {
const textToSpeechClient = new TextToSpeechClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ const BASELINE_DIR = path.join(
'texttospeech'
);

const PACKAGE_NAME = '@google-cloud/text-to-speech';
const SRCDIR = path.join(cwd, 'build', 'src');
const CLI = path.join(SRCDIR, 'cli.js');

describe('gRPC Client Config', () => {
describe('Package Name & grpc Config', () => {
describe('Generate Text-to-Speech library', () => {
it('Generated proto list should have same output with baseline.', function() {
it('Generated library name & grpc Config should be same with baseline.', function() {
this.timeout(10000);
if (fs.existsSync(OUTPUT_DIR)) {
rimraf.sync(OUTPUT_DIR);
Expand All @@ -82,6 +83,21 @@ describe('gRPC Client Config', () => {
`-I ${GOOGLE_GAX_PROTOS_DIR} ` +
`-I ${PROTOS_DIR} ` +
`--grpc-service-config=${GRPC_SERVICE_CONFIG} ` +
`--package-name=${PACKAGE_NAME} ` +
TTS_PROTO_FILE
);
assert(equalToBaseline(OUTPUT_DIR, BASELINE_DIR));
});

it('Use alias name should also work.', function() {
this.timeout(10000);
execSync(
`node build/src/start_script.js ` +
`--output-dir=${OUTPUT_DIR} ` +
`-I ${GOOGLE_GAX_PROTOS_DIR} ` +
`-I ${PROTOS_DIR} ` +
`--grpc_service_config=${GRPC_SERVICE_CONFIG} ` +
`--package_name=${PACKAGE_NAME} ` +
TTS_PROTO_FILE
);
assert(equalToBaseline(OUTPUT_DIR, BASELINE_DIR));
Expand Down

0 comments on commit 5583523

Please sign in to comment.