1// Copyright 2022 The Pigweed Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may not 4// use this file except in compliance with the License. You may obtain a copy of 5// the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations under 13// the License. 14 15import {exec, ExecException} from 'child_process'; 16import fs from 'fs'; 17import path from 'path'; 18import generateTemplate from './codegen/template_replacement'; 19// eslint-disable-next-line node/no-extraneous-import 20import * as argModule from 'arg'; 21const arg = argModule.default; 22 23const googProtobufPath = require.resolve('google-protobuf'); 24const googProtobufModule = fs.readFileSync(googProtobufPath, 'utf-8'); 25 26const args = arg({ 27 // Types 28 '--proto': [String], 29 '--out': String, 30 31 // Aliases 32 '-p': '--proto', 33}); 34 35const protos = args['--proto']; 36const outDir = args['--out'] || 'protos'; 37 38fs.mkdirSync(outDir, {recursive: true}); 39 40const run = function (executable: string, args: string[]) { 41 return new Promise<void>(resolve => { 42 exec(`${executable} ${args.join(" ")}`, {cwd: process.cwd()}, (error: ExecException | null, stdout: string | Buffer) => { 43 if (error) { 44 throw error; 45 } 46 47 console.log(stdout); 48 resolve(); 49 }); 50 }); 51}; 52 53const protoc = async function (protos: string[], outDir: string) { 54 const PROTOC_GEN_TS_PATH = path.resolve( 55 path.dirname(require.resolve('ts-protoc-gen/generate.js')), 56 '..', 57 '.bin', 58 'protoc-gen-ts' 59 ); 60 61 await run('protoc', [ 62 `--plugin="protoc-gen-ts=${PROTOC_GEN_TS_PATH}"`, 63 `--descriptor_set_out=${outDir}/descriptor.bin`, 64 `--js_out=import_style=commonjs,binary:${outDir}`, 65 `--ts_out=${outDir}`, 66 `--proto_path=${process.cwd()}`, 67 ...protos, 68 ]); 69 70 // ES6 workaround: Replace google-protobuf imports with entire library. 71 protos.forEach(protoPath => { 72 const outPath = path.join(outDir, protoPath.replace('.proto', '_pb.js')); 73 74 if (fs.existsSync(outPath)) { 75 let data = fs.readFileSync(outPath, 'utf8'); 76 data = data.replace("var jspb = require('google-protobuf');", googProtobufModule); 77 data = data.replace('var goog = jspb;', ''); 78 fs.writeFileSync(outPath, data); 79 } 80 }); 81}; 82 83const makeProtoCollection = function ( 84 descriptorBinPath: string, 85 protoPath: string, 86 importPath: string 87) { 88 const outputCollectionName = path.extname(require.resolve("./ts_proto_collection.template")) === ".ts" ? "collection.ts" : "collection.js"; 89 generateTemplate(`${protoPath}/${outputCollectionName}`, descriptorBinPath, require.resolve("./ts_proto_collection.template"), importPath) 90}; 91 92protoc(protos, outDir).then(() => { 93 makeProtoCollection( 94 path.join(outDir, 'descriptor.bin'), 95 outDir, 96 'pigweedjs/protos' 97 ); 98}); 99