xref: /aosp_15_r20/external/pigweed/pw_protobuf_compiler/ts/codegen/template_replacement.ts (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 * as fs from 'fs';
16import { FileDescriptorSet } from 'google-protobuf/google/protobuf/descriptor_pb';
17
18// Keeping template here is not elegant but let's us avoid issues when bundling via rollup:
19// Previously, we had to keep a copy of this template file alongside this CLI script.
20const template = `
21import { ProtoCollection as Base } from 'pigweedjs/pw_protobuf_compiler';
22import { FileDescriptorSet } from 'google-protobuf/google/protobuf/descriptor_pb';
23import * as base64 from 'base64-js';
24
25// Generated proto imports added during build
26// TEMPLATE_proto_imports
27
28const MODULE_MAP = {
29  // TEMPLATE_module_map
30};
31
32const DESCRIPTOR_BASE64_BINARY = '{TEMPLATE_descriptor_binary}';
33
34/**
35 * A wrapper class of protocol buffer modules to provide convenience methods.
36 */
37export class ProtoCollection extends Base {
38  constructor() {
39    const fileDescriptorSet = FileDescriptorSet.deserializeBinary(
40      base64.toByteArray(DESCRIPTOR_BASE64_BINARY),
41    );
42    super(fileDescriptorSet, MODULE_MAP);
43  }
44}
45`;
46
47function buildModulePath(rootDir: string, fileName: string): string {
48  const name = `${rootDir}/${fileName}`;
49  return name.replace(/\.proto$/, '_pb');
50}
51
52export default function generateTemplate(
53  outputPath: string,
54  descriptorDataPath: string,
55) {
56  const descriptorSetBinary = fs.readFileSync(descriptorDataPath);
57  const base64DescriptorSet = descriptorSetBinary.toString('base64');
58  const fileDescriptorSet = FileDescriptorSet.deserializeBinary(
59    Buffer.from(descriptorSetBinary),
60  );
61
62  const imports = [];
63  const moduleDictionary = [];
64  const fileList = fileDescriptorSet.getFileList();
65  for (let i = 0; i < fileList.length; i++) {
66    const file = fileList[i];
67    const modulePath = buildModulePath('.', file.getName()!);
68    const moduleName = 'proto_' + i;
69    imports.push(`import * as ${moduleName} from '${modulePath}';`);
70    const key = file.getName()!;
71    moduleDictionary.push(`'${key}': ${moduleName},`);
72  }
73
74  let filledTemplate = template.replace(
75    '{TEMPLATE_descriptor_binary}',
76    base64DescriptorSet,
77  );
78  filledTemplate = filledTemplate.replace(
79    '// TEMPLATE_proto_imports',
80    imports.join('\n'),
81  );
82  filledTemplate = filledTemplate.replace(
83    '// TEMPLATE_module_map',
84    moduleDictionary.join('\n'),
85  );
86
87  fs.writeFileSync(outputPath, filledTemplate);
88}
89