// Copyright 2022 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. import { exec, ExecException } from 'child_process'; import fs from 'fs'; import path from 'path'; import generateTemplate from './codegen/template_replacement'; import * as argModule from 'arg'; const arg = argModule.default; const googProtobufPath = require.resolve('google-protobuf'); const googProtobufModule = fs.readFileSync(googProtobufPath, 'utf-8'); const args = arg({ // Types '--proto': [String], '--out': String, // Aliases '-p': '--proto', }); const protos = args['--proto']; const outDir = args['--out'] || 'protos'; fs.mkdirSync(outDir, { recursive: true }); const run = function (executable: string, args: string[]) { return new Promise((resolve) => { exec( `${executable} ${args.join(' ')}`, { cwd: process.cwd() }, (error: ExecException | null, stdout: string | Buffer) => { if (error) { throw error; } console.log(stdout); resolve(); }, ); }); }; const protoc = async function (protos: string[], outDir: string) { const PROTOC_GEN_TS_PATH = path.resolve( path.dirname(require.resolve('ts-protoc-gen/generate.js')), '..', '.bin', 'protoc-gen-ts', ); await run('protoc', [ `--plugin="protoc-gen-ts=${PROTOC_GEN_TS_PATH}"`, `--descriptor_set_out=${outDir}/descriptor.bin`, `--js_out=import_style=commonjs,binary:${outDir}`, `--ts_out=${outDir}`, `--proto_path=${process.cwd()}`, ...protos, ]); // ES6 workaround: Replace google-protobuf imports with entire library. protos.forEach((protoPath) => { const outPath = path.join(outDir, protoPath.replace('.proto', '_pb.js')); if (fs.existsSync(outPath)) { let data = fs.readFileSync(outPath, 'utf8'); data = data.replace( "var jspb = require('google-protobuf');", googProtobufModule, ); data = data.replace('var goog = jspb;', ''); fs.writeFileSync(outPath, data); } }); }; const makeProtoCollection = function ( descriptorBinPath: string, protoPath: string, importPath: string, ) { const outputCollectionName = path.extname(require.resolve('./ts_proto_collection.template')) === '.ts' ? 'collection.ts' : 'collection.js'; generateTemplate( `${protoPath}/${outputCollectionName}`, descriptorBinPath, require.resolve('./ts_proto_collection.template'), importPath, ); }; protoc(protos, outDir).then(() => { makeProtoCollection( path.join(outDir, 'descriptor.bin'), outDir, 'pigweedjs/protos', ); });