• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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