blob: 9ae903612faf825d918f998e24f495d586c4dec4 [file] [log] [blame]
// 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<void>((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',
);
});