diff --git a/core/packages/tools/src/compileProtos.ts b/core/packages/tools/src/compileProtos.ts index 5505fa8048c0..57a54ecf3dec 100644 --- a/core/packages/tools/src/compileProtos.ts +++ b/core/packages/tools/src/compileProtos.ts @@ -22,6 +22,7 @@ import * as util from 'util'; import * as pbjs from 'protobufjs-cli/pbjs'; import * as pbts from 'protobufjs-cli/pbts'; import * as crypto from 'crypto'; +import * as uglify from 'uglify-js'; import {walkUp} from 'walk-up-path'; export const gaxProtos = path.join( @@ -246,6 +247,7 @@ interface CompileProtosOptions { esm?: boolean; keepCase?: boolean; forceNumber?: boolean; + noComments?: boolean; } /** @@ -349,6 +351,34 @@ async function compileProtos( let tsResult = (await readFile(tsOutput)).toString(); tsResult = fixDtsFile(tsResult); await writeFile(tsOutput, tsResult); + + if (options.noComments) { + const uglifyOptions: uglify.MinifyOptions = { + output: {comments: false, beautify: false}, + compress: false, + mangle: false, + }; + + const minified = uglify.minify( + (await readFile(jsOutput)).toString(), + uglifyOptions, + ); + if (minified.error) { + throw new Error(`UglifyJS failed on ${jsOutput}: ${minified.error}`); + } + await writeFile(jsOutput, minified.code); + + if (options.esm && jsOutputEsm) { + const esmContent = (await readFile(jsOutputEsm)).toString(); + const minifiedEsm = uglify.minify(esmContent, uglifyOptions); + if (minifiedEsm.error) { + throw new Error( + `UglifyJS failed on ${jsOutputEsm}: ${minifiedEsm.error}`, + ); + } + await writeFile(jsOutputEsm, minifiedEsm.code); + } + } } /** @@ -397,6 +427,7 @@ export async function main(parameters: string[]): Promise { let esm = false; let keepCase = false; let forceNumber = false; + let noComments = false; const directories: string[] = []; for (const parameter of parameters) { if (parameter === '--skip-json') { @@ -415,6 +446,10 @@ export async function main(parameters: string[]): Promise { forceNumber = true; continue; } + if (parameter === '--no-comments') { + noComments = true; + continue; + } // it's not an option so it's a directory const directory = parameter; directories.push(directory); @@ -428,10 +463,17 @@ export async function main(parameters: string[]): Promise { esm, keepCase, forceNumber, + noComments, }); } const protos = await buildListOfProtos(protoJsonFiles, esm); - await compileProtos(rootName, protos, {skipJson, esm, keepCase, forceNumber}); + await compileProtos(rootName, protos, { + skipJson, + esm, + keepCase, + forceNumber, + noComments, + }); } /** diff --git a/core/packages/tools/test/compileProtos.ts b/core/packages/tools/test/compileProtos.ts index c40bd587d207..ece37b1b2ef2 100644 --- a/core/packages/tools/test/compileProtos.ts +++ b/core/packages/tools/test/compileProtos.ts @@ -103,7 +103,7 @@ describe('compileProtos tool', () => { assert(!js.toString().includes('require("protobufjs/minimal")')); // check that it uses proper root object; it's taken from fixtures/package.json - assert(js.toString().includes('$protobuf.roots._org_fake_package')); + assert(js.toString().includes('_org_fake_package')); const ts = await readFile(expectedTSResultFile); assert(ts.toString().includes('TestMessage')); @@ -148,7 +148,7 @@ describe('compileProtos tool', () => { assert(!cjs.toString().includes('require("protobufjs/minimal")')); // check that it uses proper root object; it's taken from fixtures/package.json - assert(cjs.toString().includes('$protobuf.roots._org_fake_package')); + assert(cjs.toString().includes('_org_fake_package')); const js = await readFile(expectedJSResultFile); assert(js.toString().includes('TestMessage')); @@ -171,7 +171,7 @@ describe('compileProtos tool', () => { ); // check that it uses proper root object; it's taken from fixtures/package.json - assert(js.toString().includes('$protobuf.roots._org_fake_package')); + assert(js.toString().includes('_org_fake_package')); const ts = await readFile(expectedTSResultFile); assert(ts.toString().includes('TestMessage')); @@ -210,7 +210,7 @@ describe('compileProtos tool', () => { assert(!js.toString().includes('require("protobufjs/minimal")')); // check that it uses proper root object; it's taken from fixtures/package.json - assert(js.toString().includes('$protobuf.roots._org_fake_package')); + assert(js.toString().includes('_org_fake_package')); const ts = await readFile(expectedTSResultFile); assert(ts.toString().includes('TestMessage')); @@ -228,6 +228,38 @@ describe('compileProtos tool', () => { assert(!ts.toString().includes('import * as $protobuf from "protobufjs"')); }); + it('compiles protos to JS without comments if --no-comments is specified', async function () { + this.timeout(20000); + await compileProtos.main(['--no-comments', 'protoLists']); + assert(fs.existsSync(expectedJSResultFile)); + assert(fs.existsSync(expectedTSResultFile)); + + const js = await readFile(expectedJSResultFile); + assert(!js.toString().includes('//')); + assert(!js.toString().includes('/*')); + assert(js.toString().includes('_org_fake_package')); + assert(js.toString().includes('TestMessage')); + }); + + it('compiles protos to CJS and ES6 without comments if --no-comments and --esm are specified', async function () { + this.timeout(20000); + await compileProtos.main(['--no-comments', '--esm', 'esm']); + assert(fs.existsSync(expectedCommonJSResultFile)); + assert(fs.existsSync(expectedJSResultFile)); + + const cjs = await readFile(expectedCommonJSResultFile); + assert(!cjs.toString().includes('//')); + assert(!cjs.toString().includes('/*')); + assert(cjs.toString().includes('_org_fake_package')); + assert(cjs.toString().includes('TestMessage')); + + const js = await readFile(expectedJSResultFile); + assert(!js.toString().includes('//')); + assert(!js.toString().includes('/*')); + assert(js.toString().includes('_org_fake_package')); + assert(js.toString().includes('TestMessage')); + }); + it('writes an empty object if no protos are given', async () => { await compileProtos.main(['protoLists/empty']); assert(fs.existsSync(expectedJsonResultFile));