xref: /aosp_15_r20/external/pigweed/pw_protobuf_compiler/ts/build.ts (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker// Copyright 2022 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker//
3*61c4878aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker// use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker// the License at
6*61c4878aSAndroid Build Coastguard Worker//
7*61c4878aSAndroid Build Coastguard Worker//     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker//
9*61c4878aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker// License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker// the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Workerimport { exec, ExecException } from 'child_process';
16*61c4878aSAndroid Build Coastguard Workerimport fs from 'fs';
17*61c4878aSAndroid Build Coastguard Workerimport path from 'path';
18*61c4878aSAndroid Build Coastguard Workerimport generateTemplate from './codegen/template_replacement';
19*61c4878aSAndroid Build Coastguard Workerconst googProtobufPath = require.resolve('google-protobuf');
20*61c4878aSAndroid Build Coastguard Workerconst googProtobufModule = fs.readFileSync(googProtobufPath, 'utf-8');
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Workerconst run = function (
23*61c4878aSAndroid Build Coastguard Worker  executable: string,
24*61c4878aSAndroid Build Coastguard Worker  args: string[],
25*61c4878aSAndroid Build Coastguard Worker  cwd: string = process.cwd(),
26*61c4878aSAndroid Build Coastguard Worker) {
27*61c4878aSAndroid Build Coastguard Worker  return new Promise<void>((resolve) => {
28*61c4878aSAndroid Build Coastguard Worker    exec(
29*61c4878aSAndroid Build Coastguard Worker      `${executable} ${args.join(' ')}`,
30*61c4878aSAndroid Build Coastguard Worker      { cwd },
31*61c4878aSAndroid Build Coastguard Worker      (error: ExecException | null, stdout: string | Buffer) => {
32*61c4878aSAndroid Build Coastguard Worker        if (error) {
33*61c4878aSAndroid Build Coastguard Worker          throw error;
34*61c4878aSAndroid Build Coastguard Worker        }
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker        console.log(stdout);
37*61c4878aSAndroid Build Coastguard Worker        resolve();
38*61c4878aSAndroid Build Coastguard Worker      },
39*61c4878aSAndroid Build Coastguard Worker    );
40*61c4878aSAndroid Build Coastguard Worker  });
41*61c4878aSAndroid Build Coastguard Worker};
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard Workerfunction getRealPathOfSymlink(path: string) {
44*61c4878aSAndroid Build Coastguard Worker  const stats = fs.statSync(path);
45*61c4878aSAndroid Build Coastguard Worker  if (stats.isSymbolicLink()) {
46*61c4878aSAndroid Build Coastguard Worker    return fs.realpathSync(path);
47*61c4878aSAndroid Build Coastguard Worker  } else {
48*61c4878aSAndroid Build Coastguard Worker    return path;
49*61c4878aSAndroid Build Coastguard Worker  }
50*61c4878aSAndroid Build Coastguard Worker}
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Workerconst protoc = async function (
53*61c4878aSAndroid Build Coastguard Worker  protos: string[],
54*61c4878aSAndroid Build Coastguard Worker  outDir: string,
55*61c4878aSAndroid Build Coastguard Worker  cwd: string = process.cwd(),
56*61c4878aSAndroid Build Coastguard Worker) {
57*61c4878aSAndroid Build Coastguard Worker  const PROTOC_GEN_TS_PATH = getRealPathOfSymlink(
58*61c4878aSAndroid Build Coastguard Worker    path.resolve(
59*61c4878aSAndroid Build Coastguard Worker      path.dirname(require.resolve('ts-protoc-gen/generate.js')),
60*61c4878aSAndroid Build Coastguard Worker      'bin',
61*61c4878aSAndroid Build Coastguard Worker      'protoc-gen-ts',
62*61c4878aSAndroid Build Coastguard Worker    ),
63*61c4878aSAndroid Build Coastguard Worker  );
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker  const protocBinary = require.resolve('@protobuf-ts/protoc/protoc.js');
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker  await run(
68*61c4878aSAndroid Build Coastguard Worker    protocBinary,
69*61c4878aSAndroid Build Coastguard Worker    [
70*61c4878aSAndroid Build Coastguard Worker      `--plugin="protoc-gen-ts=${PROTOC_GEN_TS_PATH}"`,
71*61c4878aSAndroid Build Coastguard Worker      `--descriptor_set_out=${path.join(outDir, 'descriptor.bin')}`,
72*61c4878aSAndroid Build Coastguard Worker      `--js_out=import_style=commonjs,binary:${outDir}`,
73*61c4878aSAndroid Build Coastguard Worker      `--ts_out=${outDir}`,
74*61c4878aSAndroid Build Coastguard Worker      `--proto_path=${cwd}`,
75*61c4878aSAndroid Build Coastguard Worker      ...protos,
76*61c4878aSAndroid Build Coastguard Worker    ],
77*61c4878aSAndroid Build Coastguard Worker    cwd,
78*61c4878aSAndroid Build Coastguard Worker  );
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard Worker  // ES6 workaround: Replace google-protobuf imports with entire library.
81*61c4878aSAndroid Build Coastguard Worker  protos.forEach((protoPath) => {
82*61c4878aSAndroid Build Coastguard Worker    const outPath = path.join(outDir, protoPath.replace('.proto', '_pb.js'));
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker    if (fs.existsSync(outPath)) {
85*61c4878aSAndroid Build Coastguard Worker      let data = fs.readFileSync(outPath, 'utf8');
86*61c4878aSAndroid Build Coastguard Worker      data = data.replace(
87*61c4878aSAndroid Build Coastguard Worker        "var jspb = require('google-protobuf');",
88*61c4878aSAndroid Build Coastguard Worker        googProtobufModule,
89*61c4878aSAndroid Build Coastguard Worker      );
90*61c4878aSAndroid Build Coastguard Worker      data = data.replace('var goog = jspb;', '');
91*61c4878aSAndroid Build Coastguard Worker      fs.writeFileSync(outPath, data);
92*61c4878aSAndroid Build Coastguard Worker    }
93*61c4878aSAndroid Build Coastguard Worker  });
94*61c4878aSAndroid Build Coastguard Worker};
95*61c4878aSAndroid Build Coastguard Worker
96*61c4878aSAndroid Build Coastguard Workerconst makeProtoCollection = function (
97*61c4878aSAndroid Build Coastguard Worker  descriptorBinPath: string,
98*61c4878aSAndroid Build Coastguard Worker  protoPath: string,
99*61c4878aSAndroid Build Coastguard Worker  outputCollectionName: string,
100*61c4878aSAndroid Build Coastguard Worker) {
101*61c4878aSAndroid Build Coastguard Worker  generateTemplate(`${protoPath}/${outputCollectionName}`, descriptorBinPath);
102*61c4878aSAndroid Build Coastguard Worker};
103*61c4878aSAndroid Build Coastguard Worker
104*61c4878aSAndroid Build Coastguard Workerexport function buildProtos(
105*61c4878aSAndroid Build Coastguard Worker  protos: string[],
106*61c4878aSAndroid Build Coastguard Worker  outDir: string,
107*61c4878aSAndroid Build Coastguard Worker  outputCollectionName = 'collection.js',
108*61c4878aSAndroid Build Coastguard Worker  cwd: string = process.cwd(),
109*61c4878aSAndroid Build Coastguard Worker) {
110*61c4878aSAndroid Build Coastguard Worker  protoc(protos, outDir, cwd).then(() => {
111*61c4878aSAndroid Build Coastguard Worker    makeProtoCollection(
112*61c4878aSAndroid Build Coastguard Worker      path.join(outDir, 'descriptor.bin'),
113*61c4878aSAndroid Build Coastguard Worker      outDir,
114*61c4878aSAndroid Build Coastguard Worker      outputCollectionName,
115*61c4878aSAndroid Build Coastguard Worker    );
116*61c4878aSAndroid Build Coastguard Worker  });
117*61c4878aSAndroid Build Coastguard Worker}
118