diff --git a/.circleci/config.yml b/.circleci/config.yml index d563504c3..0ba05ef46 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,10 +11,17 @@ jobs: sudo apt-get update sudo apt-get install protobuf-compiler - run: - name: Run tests + name: Run npm install command: | npm install + - run: + name: Run tests + command: | npm test + - run: + name: Run linting + command: | + npm run lint workflows: version: 2 tests: diff --git a/package.json b/package.json index f58f0024d..41452414a 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "codecov": "^3.0.4", "espower-typescript": "^9.0.0", "google-gax": "^1.5.0", - "gts": "^0.9.0", + "gts": "^1.0.0", "intelli-espower-loader": "^1.0.1", "mocha": "^6.0.0", "power-assert": "^1.6.0", diff --git a/typescript/src/cli.ts b/typescript/src/cli.ts index 164f3c713..4225cbbdb 100644 --- a/typescript/src/cli.ts +++ b/typescript/src/cli.ts @@ -14,13 +14,13 @@ // See the License for the specific language governing permissions and // limitations under the License. - import * as commandLineArgs from 'command-line-args'; -import {Generator} from './generator'; +import { Generator } from './generator'; async function main() { - const optionDefinitions: commandLineArgs.OptionDefinition[] = - [{name: 'descriptor', type: String}]; + const optionDefinitions: commandLineArgs.OptionDefinition[] = [ + { name: 'descriptor', type: String }, + ]; const options = commandLineArgs(optionDefinitions); if (options.descriptor) { diff --git a/typescript/src/generator.ts b/typescript/src/generator.ts index ed50c4435..c1bb6bf10 100644 --- a/typescript/src/generator.ts +++ b/typescript/src/generator.ts @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. - import * as getStdin from 'get-stdin'; import * as path from 'path'; import * as plugin from '../../pbjs-genfiles/plugin'; -import {API} from './schema/api'; -import {processTemplates} from './templater'; -import {commonPrefix} from './util'; +import { API } from './schema/api'; +import { processTemplates } from './templater'; +import { commonPrefix } from './util'; const templateDirectory = 'templates/typescript_gapic'; // If needed, we can make it possible to load templates from different locations @@ -31,16 +30,15 @@ export class Generator { response: plugin.google.protobuf.compiler.CodeGeneratorResponse; constructor() { - this.request = - plugin.google.protobuf.compiler.CodeGeneratorRequest.create(); - this.response = - plugin.google.protobuf.compiler.CodeGeneratorResponse.create(); + this.request = plugin.google.protobuf.compiler.CodeGeneratorRequest.create(); + this.response = plugin.google.protobuf.compiler.CodeGeneratorResponse.create(); } async initializeFromStdin() { const inputBuffer = await getStdin.buffer(); this.request = plugin.google.protobuf.compiler.CodeGeneratorRequest.decode( - inputBuffer); + inputBuffer + ); } addProtosToResponse() { @@ -50,8 +48,7 @@ export class Generator { protoFilenames.push(proto.name); } } - const protoList = - plugin.google.protobuf.compiler.CodeGeneratorResponse.File.create(); + const protoList = plugin.google.protobuf.compiler.CodeGeneratorResponse.File.create(); protoList.name = 'proto.list'; protoList.content = protoFilenames.join('\n') + '\n'; this.response.file.push(protoList); @@ -59,9 +56,11 @@ export class Generator { buildAPIObject(): API { const protoFilesToGenerate = this.request.protoFile.filter( - pf => pf.name && this.request.fileToGenerate.includes(pf.name)); - const packageNamesToGenerate = - protoFilesToGenerate.map(pf => pf.package || ''); + pf => pf.name && this.request.fileToGenerate.includes(pf.name) + ); + const packageNamesToGenerate = protoFilesToGenerate.map( + pf => pf.package || '' + ); const packageName = commonPrefix(packageNamesToGenerate).replace(/\.$/, ''); if (packageName === '') { throw new Error('Cannot get package name to generate.'); @@ -78,8 +77,7 @@ export class Generator { async generate() { const fileToGenerate = this.request.fileToGenerate; - this.response = - plugin.google.protobuf.compiler.CodeGeneratorResponse.create(); + this.response = plugin.google.protobuf.compiler.CodeGeneratorResponse.create(); this.addProtosToResponse(); const api = this.buildAPIObject(); @@ -88,9 +86,9 @@ export class Generator { // console.warn(JSON.stringify(api.services, null, ' ')); // console.warn(JSON.stringify(api, null, ' ')); - const outputBuffer = plugin.google.protobuf.compiler.CodeGeneratorResponse - .encode(this.response) - .finish(); + const outputBuffer = plugin.google.protobuf.compiler.CodeGeneratorResponse.encode( + this.response + ).finish(); process.stdout.write(outputBuffer); } } diff --git a/typescript/src/schema/api.ts b/typescript/src/schema/api.ts index d5f385fdd..c61324302 100644 --- a/typescript/src/schema/api.ts +++ b/typescript/src/schema/api.ts @@ -1,11 +1,11 @@ import * as plugin from '../../../pbjs-genfiles/plugin'; -import {Naming} from './naming'; -import {Proto} from './proto'; +import { Naming } from './naming'; +import { Proto } from './proto'; -export type ProtosMap = { - [filename: string]: Proto -}; +export interface ProtosMap { + [filename: string]: Proto; +} export class API { naming: Naming; @@ -13,29 +13,43 @@ export class API { // TODO: subpackages constructor( - fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[], - packageName: string) { - this.naming = new Naming(fileDescriptors.filter( - fd => fd.package && fd.package.startsWith(packageName))); - this.protos = fileDescriptors.filter(fd => fd.name).reduce((map, fd) => { - map[fd.name!] = new Proto(fd, packageName); - return map; - }, {} as ProtosMap); + fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[], + packageName: string + ) { + this.naming = new Naming( + fileDescriptors.filter( + fd => fd.package && fd.package.startsWith(packageName) + ) + ); + this.protos = fileDescriptors + .filter(fd => fd.name) + .reduce( + (map, fd) => { + map[fd.name!] = new Proto(fd, packageName); + return map; + }, + {} as ProtosMap + ); } get services() { return Object.keys(this.protos) - .map(filename => this.protos[filename]) - .filter(proto => proto.fileToGenerate) - .reduce((retval, proto) => { + .map(filename => this.protos[filename]) + .filter(proto => proto.fileToGenerate) + .reduce( + (retval, proto) => { retval.push( - ...Object.keys(proto.services).map(name => proto.services[name])); + ...Object.keys(proto.services).map(name => proto.services[name]) + ); return retval; - }, [] as plugin.google.protobuf.IServiceDescriptorProto[]); + }, + [] as plugin.google.protobuf.IServiceDescriptorProto[] + ); } get filesToGenerate() { - return Object.keys(this.protos) - .filter(proto => this.protos[proto].fileToGenerate); + return Object.keys(this.protos).filter( + proto => this.protos[proto].fileToGenerate + ); } } diff --git a/typescript/src/schema/naming.ts b/typescript/src/schema/naming.ts index 6d758443c..a31ca7427 100644 --- a/typescript/src/schema/naming.ts +++ b/typescript/src/schema/naming.ts @@ -1,5 +1,5 @@ import * as plugin from '../../../pbjs-genfiles/plugin'; -import {commonPrefix} from '../util'; +import { commonPrefix } from '../util'; export class Naming { name: string; @@ -20,16 +20,16 @@ export class Naming { // Define the regular expression to match a version component // (e.g. "v1", "v1beta4", etc.). - const pattern = - /^((?:[a-z0-9_.]+?)\.)?([a-z0-9_]+)(?:\.(v[0-9]+(p[0-9]+)?((alpha|beta)[0-9]+)?[^.]*))?$/; + const pattern = /^((?:[a-z0-9_.]+?)\.)?([a-z0-9_]+)(?:\.(v[0-9]+(p[0-9]+)?((alpha|beta)[0-9]+)?[^.]*))?$/; const match = rootPackage.match(pattern); if (!match) { throw new Error(`Cannot parse package name ${rootPackage}.`); } const [, namespaces, name, version] = match; if (!namespaces) { - throw new Error(`Cannot parse package name ${ - rootPackage}: namespace is not defined.`); + throw new Error( + `Cannot parse package name ${rootPackage}: namespace is not defined.` + ); } this.name = name.capitalize(); this.productName = this.name; @@ -39,7 +39,8 @@ export class Naming { if (!this.version && protoPackages.length > 1) { throw new Error( - 'All protos must have the same proto package up to and including the version.'); + 'All protos must have the same proto package up to and including the version.' + ); } } } diff --git a/typescript/src/schema/proto.ts b/typescript/src/schema/proto.ts index 978b0fcc5..a32b8e2a2 100644 --- a/typescript/src/schema/proto.ts +++ b/typescript/src/schema/proto.ts @@ -1,20 +1,24 @@ -import {ENGINE_METHOD_DIGESTS} from 'constants'; -import {NEG_ONE} from 'long'; +import { ENGINE_METHOD_DIGESTS } from 'constants'; +import { NEG_ONE } from 'long'; import * as plugin from '../../../pbjs-genfiles/plugin'; -interface MethodDescriptorProto extends - plugin.google.protobuf.IMethodDescriptorProto { - idempotence: 'idempotent'|'non_idempotent'; +interface MethodDescriptorProto + extends plugin.google.protobuf.IMethodDescriptorProto { + idempotence: 'idempotent' | 'non_idempotent'; longRunning?: plugin.google.longrunning.IOperationInfo; - streaming: 'CLIENT_STREAMING'|'SERVER_STREAMING'|'BIDI_STREAMING'|undefined; - pagingFieldName: string|undefined; + streaming: + | 'CLIENT_STREAMING' + | 'SERVER_STREAMING' + | 'BIDI_STREAMING' + | undefined; + pagingFieldName: string | undefined; inputInterface: string; outputInterface: string; } -interface ServiceDescriptorProto extends - plugin.google.protobuf.IServiceDescriptorProto { +interface ServiceDescriptorProto + extends plugin.google.protobuf.IServiceDescriptorProto { method: MethodDescriptorProto[]; simpleMethods: MethodDescriptorProto[]; longRunning: MethodDescriptorProto[]; @@ -28,24 +32,27 @@ interface ServiceDescriptorProto extends oauthScopes: string[]; } -export type ServicesMap = { - [name: string]: ServiceDescriptorProto -}; -export type MessagesMap = { - [name: string]: plugin.google.protobuf.IDescriptorProto -}; -export type EnumsMap = { - [name: string]: plugin.google.protobuf.IEnumDescriptorProto -}; +export interface ServicesMap { + [name: string]: ServiceDescriptorProto; +} +export interface MessagesMap { + [name: string]: plugin.google.protobuf.IDescriptorProto; +} +export interface EnumsMap { + [name: string]: plugin.google.protobuf.IEnumDescriptorProto; +} // The following functions are used to add some metadata such as idempotence // flag, long running operation info, pagination, and streaming, to all the // methods of the given service, to use in templates. function idempotence(method: MethodDescriptorProto) { - if (method.options && method.options['.google.api.http'] && - (method.options['.google.api.http']['get'] || - method.options['.google.api.http']['put'])) { + if ( + method.options && + method.options['.google.api.http'] && + (method.options['.google.api.http']['get'] || + method.options['.google.api.http']['put']) + ) { return 'idempotent'; } return 'non_idempotent'; @@ -75,17 +82,20 @@ function pagingFieldName(messages: MessagesMap, method: MethodDescriptorProto) { const inputType = messages[method.inputType!]; const outputType = messages[method.outputType!]; const hasPageToken = - inputType && inputType.field!.some(field => field.name === 'page_token'); + inputType && inputType.field!.some(field => field.name === 'page_token'); const hasPageSize = - inputType && inputType.field!.some(field => field.name === 'page_size'); - const hasNextPageToken = outputType && - outputType.field!.some(field => field.name === 'next_page_token'); + inputType && inputType.field!.some(field => field.name === 'page_size'); + const hasNextPageToken = + outputType && + outputType.field!.some(field => field.name === 'next_page_token'); if (!hasPageToken || !hasPageSize || !hasNextPageToken) { return undefined; } const repeatedFields = outputType.field!.filter( - field => field.label === - plugin.google.protobuf.FieldDescriptorProto.Label.LABEL_REPEATED); + field => + field.label === + plugin.google.protobuf.FieldDescriptorProto.Label.LABEL_REPEATED + ); if (repeatedFields.length !== 1) { return undefined; } @@ -98,56 +108,72 @@ function toInterface(type: string) { function augmentMethod(messages: MessagesMap, method: MethodDescriptorProto) { method = Object.assign( - { - idempotence: idempotence(method), - longRunning: longrunning(method), - streaming: streaming(method), - pagingFieldName: pagingFieldName(messages, method), - inputInterface: toInterface(method.inputType!), - outputInterface: toInterface(method.outputType!) - }, - method) as MethodDescriptorProto; + { + idempotence: idempotence(method), + longRunning: longrunning(method), + streaming: streaming(method), + pagingFieldName: pagingFieldName(messages, method), + inputInterface: toInterface(method.inputType!), + outputInterface: toInterface(method.outputType!), + }, + method + ) as MethodDescriptorProto; return method; } function augmentService( - messages: MessagesMap, - service: plugin.google.protobuf.IServiceDescriptorProto) { + messages: MessagesMap, + service: plugin.google.protobuf.IServiceDescriptorProto +) { const augmentedService = service as ServiceDescriptorProto; - augmentedService.method = - augmentedService.method.map(method => augmentMethod(messages, method)); + augmentedService.method = augmentedService.method.map(method => + augmentMethod(messages, method) + ); augmentedService.simpleMethods = augmentedService.method.filter( - method => - !method.longRunning && !method.streaming && !method.pagingFieldName); - augmentedService.longRunning = - augmentedService.method.filter(method => method.longRunning); - augmentedService.streaming = - augmentedService.method.filter(method => method.streaming); + method => + !method.longRunning && !method.streaming && !method.pagingFieldName + ); + augmentedService.longRunning = augmentedService.method.filter( + method => method.longRunning + ); + augmentedService.streaming = augmentedService.method.filter( + method => method.streaming + ); augmentedService.clientStreaming = augmentedService.method.filter( - method => method.streaming === 'CLIENT_STREAMING'); + method => method.streaming === 'CLIENT_STREAMING' + ); augmentedService.serverStreaming = augmentedService.method.filter( - method => method.streaming === 'SERVER_STREAMING'); + method => method.streaming === 'SERVER_STREAMING' + ); augmentedService.bidiStreaming = augmentedService.method.filter( - method => method.streaming === 'BIDI_STREAMING'); - augmentedService.paging = - augmentedService.method.filter(method => method.pagingFieldName); + method => method.streaming === 'BIDI_STREAMING' + ); + augmentedService.paging = augmentedService.method.filter( + method => method.pagingFieldName + ); augmentedService.hostname = ''; augmentedService.port = 0; - if (augmentedService.options && - augmentedService.options['.google.api.defaultHost']) { + if ( + augmentedService.options && + augmentedService.options['.google.api.defaultHost'] + ) { const match = augmentedService.options['.google.api.defaultHost'].match( - /^(.*):(\d+)$/); + /^(.*):(\d+)$/ + ); if (match) { augmentedService.hostname = match[1]; augmentedService.port = Number.parseInt(match[2], 10); } } augmentedService.oauthScopes = []; - if (augmentedService.options && - augmentedService.options['.google.api.oauthScopes']) { - augmentedService.oauthScopes = - augmentedService.options['.google.api.oauthScopes'].split(','); + if ( + augmentedService.options && + augmentedService.options['.google.api.oauthScopes'] + ) { + augmentedService.oauthScopes = augmentedService.options[ + '.google.api.oauthScopes' + ].split(','); } return augmentedService; } @@ -161,34 +187,48 @@ export class Proto { // TODO: need to store metadata? address? constructor( - fd: plugin.google.protobuf.IFileDescriptorProto, packageName: string) { + fd: plugin.google.protobuf.IFileDescriptorProto, + packageName: string + ) { fd.enumType = fd.enumType || []; fd.messageType = fd.messageType || []; fd.service = fd.service || []; this.filePB2 = fd; - this.messages = fd.messageType.filter(message => message.name) - .reduce((map, message) => { - map['.' + fd.package! + '.' + message.name!] = - message; - return map; - }, {} as MessagesMap); - - this.enums = - fd.enumType.filter(enum_ => enum_.name).reduce((map, enum_) => { + this.messages = fd.messageType + .filter(message => message.name) + .reduce( + (map, message) => { + map['.' + fd.package! + '.' + message.name!] = message; + return map; + }, + {} as MessagesMap + ); + + this.enums = fd.enumType + .filter(enum_ => enum_.name) + .reduce( + (map, enum_) => { map[enum_.name!] = enum_; return map; - }, {} as EnumsMap); - - this.fileToGenerate = - fd.package ? fd.package.startsWith(packageName) : false; - - this.services = fd.service.filter(service => service.name) - .map(service => augmentService(this.messages, service)) - .reduce((map, service) => { - map[service.name!] = service; - return map; - }, {} as ServicesMap); + }, + {} as EnumsMap + ); + + this.fileToGenerate = fd.package + ? fd.package.startsWith(packageName) + : false; + + this.services = fd.service + .filter(service => service.name) + .map(service => augmentService(this.messages, service)) + .reduce( + (map, service) => { + map[service.name!] = service; + return map; + }, + {} as ServicesMap + ); } } diff --git a/typescript/src/templater.ts b/typescript/src/templater.ts index 1966d14ca..e995a3459 100644 --- a/typescript/src/templater.ts +++ b/typescript/src/templater.ts @@ -5,9 +5,9 @@ import * as util from 'util'; import * as plugin from '../../pbjs-genfiles/plugin'; -import {API} from './schema/api'; +import { API } from './schema/api'; -const commonParameters: {[name: string]: string} = { +const commonParameters: { [name: string]: string } = { copyrightYear: new Date().getFullYear().toString(), }; @@ -16,7 +16,9 @@ const readDir = util.promisify(fs.readdir); const lstat = util.promisify(fs.lstat); async function recursiveFileList( - basePath: string, nameRegex: RegExp): Promise { + basePath: string, + nameRegex: RegExp +): Promise { const dirQueue: string[] = [basePath]; const result: string[] = []; while (dirQueue.length > 0) { @@ -36,21 +38,26 @@ async function recursiveFileList( } function renderFile( - targetFilename: string, templateFilename: string, renderParameters: {}) { + targetFilename: string, + templateFilename: string, + renderParameters: {} +) { const processed = nunjucks.render(templateFilename, renderParameters); - const output = - plugin.google.protobuf.compiler.CodeGeneratorResponse.File.create(); + const output = plugin.google.protobuf.compiler.CodeGeneratorResponse.File.create(); output.name = targetFilename; output.content = processed; return output; } function processOneTemplate( - basePath: string, templateFilename: string, api: API) { - const result: plugin.google.protobuf.compiler.CodeGeneratorResponse.File[] = - []; - let outputFilename = - templateFilename.substr(basePath.length + 1).replace(/\.njk$/, ''); + basePath: string, + templateFilename: string, + api: API +) { + const result: plugin.google.protobuf.compiler.CodeGeneratorResponse.File[] = []; + let outputFilename = templateFilename + .substr(basePath.length + 1) + .replace(/\.njk$/, ''); // Filename can have one or more variables in it that should be substituted // with their actual values. Currently supported: $service, $version Note: @@ -60,13 +67,18 @@ function processOneTemplate( // {api, commonParameters} if (outputFilename.match(/\$service/)) { for (const service of api.services) { - result.push(renderFile( + result.push( + renderFile( outputFilename.replace(/\$service/, service.name!.toLowerCase()), - templateFilename, {api, commonParameters, service})); + templateFilename, + { api, commonParameters, service } + ) + ); } } else { result.push( - renderFile(outputFilename, templateFilename, {api, commonParameters})); + renderFile(outputFilename, templateFilename, { api, commonParameters }) + ); } return result; @@ -75,8 +87,7 @@ function processOneTemplate( export async function processTemplates(basePath: string, api: API) { basePath = basePath.replace(/\/*$/, ''); const templateFiles = await recursiveFileList(basePath, /^(?!_[^_]).*\.njk$/); - const result: plugin.google.protobuf.compiler.CodeGeneratorResponse.File[] = - []; + const result: plugin.google.protobuf.compiler.CodeGeneratorResponse.File[] = []; for (const templateFilename of templateFiles) { const generatedFiles = processOneTemplate(basePath, templateFilename, api); result.push(...generatedFiles); diff --git a/typescript/src/util.ts b/typescript/src/util.ts index 401c928f9..b0191c89d 100644 --- a/typescript/src/util.ts +++ b/typescript/src/util.ts @@ -25,8 +25,8 @@ String.prototype.capitalize = function(this: string): string { String.prototype.words = function(this: string): string[] { // split on spaces, non-alphanumeric, or capital letters return this.split(/(?=[A-Z])|[\s\W_]+/) - .filter(w => w.length > 0) - .map(w => w.toLowerCase()); + .filter(w => w.length > 0) + .map(w => w.toLowerCase()); }; String.prototype.toCamelCase = function(this: string): string { diff --git a/typescript/test/baseline.ts b/typescript/test/baseline.ts index 34575241e..a4cacfcfd 100644 --- a/typescript/test/baseline.ts +++ b/typescript/test/baseline.ts @@ -13,7 +13,7 @@ // limitations under the License. import * as assert from 'assert'; -import {execSync} from 'child_process'; +import { execSync } from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; import * as rimraf from 'rimraf'; @@ -21,48 +21,68 @@ import * as rimraf from 'rimraf'; const cwd = process.cwd(); const OUTPUT_DIR = path.join(cwd, '.baseline-test-out'); -const GENERATED_CLIENT_FILE = - path.join(OUTPUT_DIR, 'src', 'v1beta1', 'echo_client.ts'); -const GOOGLE_GAX_PROTOS_DIR = - path.join(cwd, 'node_modules', 'google-gax', 'protos'); +const GENERATED_CLIENT_FILE = path.join( + OUTPUT_DIR, + 'src', + 'v1beta1', + 'echo_client.ts' +); +const GOOGLE_GAX_PROTOS_DIR = path.join( + cwd, + 'node_modules', + 'google-gax', + 'protos' +); const PROTOS_DIR = path.join(cwd, 'build', 'test', 'protos'); -const ECHO_PROTO_FILE = - path.join(PROTOS_DIR, 'google', 'showcase', 'v1beta1', 'echo.proto'); +const ECHO_PROTO_FILE = path.join( + PROTOS_DIR, + 'google', + 'showcase', + 'v1beta1', + 'echo.proto' +); const CLIENT_LIBRARY_BASELINE = path.join( - cwd, 'typescript', 'test', 'testdata', 'echo_client_baseline.ts.txt'); + cwd, + 'typescript', + 'test', + 'testdata', + 'echo_client_baseline.ts.txt' +); const SRCDIR = path.join(cwd, 'build', 'src'); const CLI = path.join(SRCDIR, 'cli.js'); const PLUGIN = path.join(SRCDIR, 'protoc-gen-typescript_gapic'); describe('CodeGeneratorTest', () => { describe('Generate client library', () => { - it('Generated client library should have same output with baseline.', - function() { - this.timeout(10000); - if (fs.existsSync(OUTPUT_DIR)) { - rimraf.sync(OUTPUT_DIR); - } - fs.mkdirSync(OUTPUT_DIR); + it('Generated client library should have same output with baseline.', function() { + this.timeout(10000); + if (fs.existsSync(OUTPUT_DIR)) { + rimraf.sync(OUTPUT_DIR); + } + fs.mkdirSync(OUTPUT_DIR); - if (fs.existsSync(PLUGIN)) { - rimraf.sync(PLUGIN); - } - fs.copyFileSync(CLI, PLUGIN); - process.env['PATH'] = SRCDIR + path.delimiter + process.env['PATH']; + if (fs.existsSync(PLUGIN)) { + rimraf.sync(PLUGIN); + } + fs.copyFileSync(CLI, PLUGIN); + process.env['PATH'] = SRCDIR + path.delimiter + process.env['PATH']; - try { - execSync(`chmod +x ${PLUGIN}`); - } catch (err) { - console.warn(`Failed to chmod +x ${PLUGIN}: ${err}. Ignoring...`); - } + try { + execSync(`chmod +x ${PLUGIN}`); + } catch (err) { + console.warn(`Failed to chmod +x ${PLUGIN}: ${err}. Ignoring...`); + } - execSync( - `protoc --typescript_gapic_out=${OUTPUT_DIR} ` + - `-I${GOOGLE_GAX_PROTOS_DIR} ` + - `-I${PROTOS_DIR} ` + ECHO_PROTO_FILE); - assert.strictEqual( - fs.readFileSync(GENERATED_CLIENT_FILE).toString(), - fs.readFileSync(CLIENT_LIBRARY_BASELINE).toString()); - }); + execSync( + `protoc --typescript_gapic_out=${OUTPUT_DIR} ` + + `-I${GOOGLE_GAX_PROTOS_DIR} ` + + `-I${PROTOS_DIR} ` + + ECHO_PROTO_FILE + ); + assert.strictEqual( + fs.readFileSync(GENERATED_CLIENT_FILE).toString(), + fs.readFileSync(CLIENT_LIBRARY_BASELINE).toString() + ); + }); }); }); diff --git a/typescript/test/naming.ts b/typescript/test/naming.ts index 3fb44ea9c..a5c31117e 100644 --- a/typescript/test/naming.ts +++ b/typescript/test/naming.ts @@ -15,7 +15,7 @@ import * as assert from 'assert'; import * as plugin from '../../pbjs-genfiles/plugin'; -import {Naming} from '../src/schema/naming'; +import { Naming } from '../src/schema/naming'; describe('schema/naming.ts', () => { it('parses name correctly', () => { @@ -26,7 +26,7 @@ describe('schema/naming.ts', () => { const naming = new Naming([descriptor1, descriptor2]); assert.strictEqual(naming.name, 'Service'); assert.strictEqual(naming.productName, 'Service'); - assert.deepEqual(naming.namespace, ['google', 'namespace']); + assert.deepStrictEqual(naming.namespace, ['google', 'namespace']); assert.strictEqual(naming.version, 'v1beta1'); assert.strictEqual(naming.protoPackage, 'google.namespace.service.v1beta1'); }); @@ -84,4 +84,4 @@ describe('schema/naming.ts', () => { const naming = new Naming([descriptor1, descriptor2]); }); }); -}); \ No newline at end of file +}); diff --git a/typescript/test/proto.ts b/typescript/test/proto.ts index 7e8e95251..5da1b62b4 100644 --- a/typescript/test/proto.ts +++ b/typescript/test/proto.ts @@ -15,10 +15,8 @@ import * as assert from 'assert'; import * as plugin from '../../pbjs-genfiles/plugin'; -import {Proto} from '../src/schema/proto'; +import { Proto } from '../src/schema/proto'; -describe( - 'schema/proto.ts', - () => { - // TODO: test service augmentation - }); +describe('schema/proto.ts', () => { + // TODO: test service augmentation +}); diff --git a/typescript/test/util.ts b/typescript/test/util.ts index fd96d92be..211afe3ee 100644 --- a/typescript/test/util.ts +++ b/typescript/test/util.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. - import * as assert from 'assert'; -import {commonPrefix} from '../src/util'; - +import { commonPrefix } from '../src/util'; describe('util.ts', () => { describe('CommonPrefix', () => { @@ -43,87 +41,177 @@ describe('util.ts', () => { }); it('should split string into words', () => { - assert.deepEqual(''.words(), []); - assert.deepEqual('test'.words(), ['test']); - assert.deepEqual('camelCaseString'.words(), ['camel', 'case', 'string']); - assert.deepEqual( - 'PascalCaseString'.words(), ['pascal', 'case', 'string']); - assert.deepEqual( - 'snake_case_string'.words(), ['snake', 'case', 'string']); - assert.deepEqual( - 'kebab-case-string'.words(), ['kebab', 'case', 'string']); - assert.deepEqual( - 'random/separators-string'.words(), - ['random', 'separators', 'string']); - assert.deepEqual( - 'mixedType-string.SomewhatWeird'.words(), - ['mixed', 'type', 'string', 'somewhat', 'weird']); - assert.deepEqual( - 'productName.v1p1beta1'.words(), ['product', 'name', 'v1p1beta1']); + assert.deepStrictEqual(''.words(), []); + assert.deepStrictEqual('test'.words(), ['test']); + assert.deepStrictEqual('camelCaseString'.words(), [ + 'camel', + 'case', + 'string', + ]); + assert.deepStrictEqual('PascalCaseString'.words(), [ + 'pascal', + 'case', + 'string', + ]); + assert.deepStrictEqual('snake_case_string'.words(), [ + 'snake', + 'case', + 'string', + ]); + assert.deepStrictEqual('kebab-case-string'.words(), [ + 'kebab', + 'case', + 'string', + ]); + assert.deepStrictEqual('random/separators-string'.words(), [ + 'random', + 'separators', + 'string', + ]); + assert.deepStrictEqual('mixedType-string.SomewhatWeird'.words(), [ + 'mixed', + 'type', + 'string', + 'somewhat', + 'weird', + ]); + assert.deepStrictEqual('productName.v1p1beta1'.words(), [ + 'product', + 'name', + 'v1p1beta1', + ]); }); it('should convert to camelCase', () => { - assert.deepEqual(''.toCamelCase(), ''); - assert.deepEqual('test'.toCamelCase(), 'test'); - assert.deepEqual('camelCaseString'.toCamelCase(), 'camelCaseString'); - assert.deepEqual('PascalCaseString'.toCamelCase(), 'pascalCaseString'); - assert.deepEqual('snake_case_string'.toCamelCase(), 'snakeCaseString'); - assert.deepEqual('kebab-case-string'.toCamelCase(), 'kebabCaseString'); - assert.deepEqual( - 'random/separators-string'.toCamelCase(), 'randomSeparatorsString'); - assert.deepEqual( - 'mixedType-string.SomewhatWeird'.toCamelCase(), - 'mixedTypeStringSomewhatWeird'); - assert.deepEqual( - 'productName.v1p1beta1'.toCamelCase(), 'productNameV1p1beta1'); + assert.deepStrictEqual(''.toCamelCase(), ''); + assert.deepStrictEqual('test'.toCamelCase(), 'test'); + assert.deepStrictEqual( + 'camelCaseString'.toCamelCase(), + 'camelCaseString' + ); + assert.deepStrictEqual( + 'PascalCaseString'.toCamelCase(), + 'pascalCaseString' + ); + assert.deepStrictEqual( + 'snake_case_string'.toCamelCase(), + 'snakeCaseString' + ); + assert.deepStrictEqual( + 'kebab-case-string'.toCamelCase(), + 'kebabCaseString' + ); + assert.deepStrictEqual( + 'random/separators-string'.toCamelCase(), + 'randomSeparatorsString' + ); + assert.deepStrictEqual( + 'mixedType-string.SomewhatWeird'.toCamelCase(), + 'mixedTypeStringSomewhatWeird' + ); + assert.deepStrictEqual( + 'productName.v1p1beta1'.toCamelCase(), + 'productNameV1p1beta1' + ); }); it('should convert to PascalCase', () => { - assert.deepEqual(''.toPascalCase(), ''); - assert.deepEqual('test'.toPascalCase(), 'Test'); - assert.deepEqual('camelCaseString'.toPascalCase(), 'CamelCaseString'); - assert.deepEqual('PascalCaseString'.toPascalCase(), 'PascalCaseString'); - assert.deepEqual('snake_case_string'.toPascalCase(), 'SnakeCaseString'); - assert.deepEqual('kebab-case-string'.toPascalCase(), 'KebabCaseString'); - assert.deepEqual( - 'random/separators-string'.toPascalCase(), 'RandomSeparatorsString'); - assert.deepEqual( - 'mixedType-string.SomewhatWeird'.toPascalCase(), - 'MixedTypeStringSomewhatWeird'); - assert.deepEqual( - 'productName.v1p1beta1'.toPascalCase(), 'ProductNameV1p1beta1'); + assert.deepStrictEqual(''.toPascalCase(), ''); + assert.deepStrictEqual('test'.toPascalCase(), 'Test'); + assert.deepStrictEqual( + 'camelCaseString'.toPascalCase(), + 'CamelCaseString' + ); + assert.deepStrictEqual( + 'PascalCaseString'.toPascalCase(), + 'PascalCaseString' + ); + assert.deepStrictEqual( + 'snake_case_string'.toPascalCase(), + 'SnakeCaseString' + ); + assert.deepStrictEqual( + 'kebab-case-string'.toPascalCase(), + 'KebabCaseString' + ); + assert.deepStrictEqual( + 'random/separators-string'.toPascalCase(), + 'RandomSeparatorsString' + ); + assert.deepStrictEqual( + 'mixedType-string.SomewhatWeird'.toPascalCase(), + 'MixedTypeStringSomewhatWeird' + ); + assert.deepStrictEqual( + 'productName.v1p1beta1'.toPascalCase(), + 'ProductNameV1p1beta1' + ); }); it('should convert to kebab-case', () => { - assert.deepEqual(''.toKebabCase(), ''); - assert.deepEqual('test'.toKebabCase(), 'test'); - assert.deepEqual('camelCaseString'.toKebabCase(), 'camel-case-string'); - assert.deepEqual('PascalCaseString'.toKebabCase(), 'pascal-case-string'); - assert.deepEqual('snake_case_string'.toKebabCase(), 'snake-case-string'); - assert.deepEqual('kebab-case-string'.toKebabCase(), 'kebab-case-string'); - assert.deepEqual( - 'random/separators-string'.toKebabCase(), 'random-separators-string'); - assert.deepEqual( - 'mixedType-string.SomewhatWeird'.toKebabCase(), - 'mixed-type-string-somewhat-weird'); - assert.deepEqual( - 'productName.v1p1beta1'.toKebabCase(), 'product-name-v1p1beta1'); + assert.deepStrictEqual(''.toKebabCase(), ''); + assert.deepStrictEqual('test'.toKebabCase(), 'test'); + assert.deepStrictEqual( + 'camelCaseString'.toKebabCase(), + 'camel-case-string' + ); + assert.deepStrictEqual( + 'PascalCaseString'.toKebabCase(), + 'pascal-case-string' + ); + assert.deepStrictEqual( + 'snake_case_string'.toKebabCase(), + 'snake-case-string' + ); + assert.deepStrictEqual( + 'kebab-case-string'.toKebabCase(), + 'kebab-case-string' + ); + assert.deepStrictEqual( + 'random/separators-string'.toKebabCase(), + 'random-separators-string' + ); + assert.deepStrictEqual( + 'mixedType-string.SomewhatWeird'.toKebabCase(), + 'mixed-type-string-somewhat-weird' + ); + assert.deepStrictEqual( + 'productName.v1p1beta1'.toKebabCase(), + 'product-name-v1p1beta1' + ); }); it('should convert to snake_case', () => { - assert.deepEqual(''.toSnakeCase(), ''); - assert.deepEqual('test'.toSnakeCase(), 'test'); - assert.deepEqual('camelCaseString'.toSnakeCase(), 'camel_case_string'); - assert.deepEqual('PascalCaseString'.toSnakeCase(), 'pascal_case_string'); - assert.deepEqual('snake_case_string'.toSnakeCase(), 'snake_case_string'); - assert.deepEqual('kebab-case-string'.toSnakeCase(), 'kebab_case_string'); - assert.deepEqual( - 'random/separators-string'.toSnakeCase(), 'random_separators_string'); - assert.deepEqual( - 'mixedType-string.SomewhatWeird'.toSnakeCase(), - 'mixed_type_string_somewhat_weird'); - assert.deepEqual( - 'productName.v1p1beta1'.toSnakeCase(), 'product_name_v1p1beta1'); + assert.deepStrictEqual(''.toSnakeCase(), ''); + assert.deepStrictEqual('test'.toSnakeCase(), 'test'); + assert.deepStrictEqual( + 'camelCaseString'.toSnakeCase(), + 'camel_case_string' + ); + assert.deepStrictEqual( + 'PascalCaseString'.toSnakeCase(), + 'pascal_case_string' + ); + assert.deepStrictEqual( + 'snake_case_string'.toSnakeCase(), + 'snake_case_string' + ); + assert.deepStrictEqual( + 'kebab-case-string'.toSnakeCase(), + 'kebab_case_string' + ); + assert.deepStrictEqual( + 'random/separators-string'.toSnakeCase(), + 'random_separators_string' + ); + assert.deepStrictEqual( + 'mixedType-string.SomewhatWeird'.toSnakeCase(), + 'mixed_type_string_somewhat_weird' + ); + assert.deepStrictEqual( + 'productName.v1p1beta1'.toSnakeCase(), + 'product_name_v1p1beta1' + ); }); }); });