@bufbuild/protoplugin 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,38 +1,32 @@
1
1
  # @bufbuild/protoplugin
2
2
 
3
- This package helps to create your own code generator plugin.
3
+ This package helps to create your own code generator plugin using the
4
+ Protobuf-ES plugin framework.
4
5
 
5
- ## Protocol Buffers for ECMAScript
6
+ Protobuf-ES is a complete implementation of [Protocol Buffers](https://developers.google.com/protocol-buffers) in TypeScript, suitable for web browsers and Node.js.
6
7
 
7
- A complete implementation of [Protocol Buffers](https://developers.google.com/protocol-buffers)
8
- in TypeScript, suitable for web browsers and Node.js.
9
- Learn more at [github.com/bufbuild/protobuf-es](https://github.com/bufbuild/protobuf-es).
8
+ In addition to a full Protobuf runtime library, it also provides a code generator
9
+ `protoc-gen-es`, which utilizes a plugin framework to generate base types from
10
+ your Protobuf schema. It is fully compatible with both Buf and protoc compilers.
10
11
 
12
+ And now, you can write your own Protobuf-ES compatible plugins using this same
13
+ plugin framework with the `@bufbuild/protoplugin` package.
11
14
 
12
- It is a complete implementation of [Protocol Buffers](https://developers.google.com/protocol-buffers)
13
- in TypeScript, suitable for web browsers and Node.js.
15
+ With `@bufbuild/protoplugin`, you can generate your own TypeScript code tailored
16
+ to your project or needs. You also have various options for producing
17
+ JavaScript and TypeScript declaration files:
14
18
 
15
- For example, the following definition:
19
+ - Exercise full control by writing your own JavaScript and declaration file
20
+ generators in addition to TypeScript.
16
21
 
17
- ```protobuf
18
- message Person {
19
- string name = 1;
20
- int32 id = 2; // Unique ID number for this person.
21
- string email = 3;
22
- }
23
- ```
22
+ - Generate TypeScript files only and let the framework generate JavaScript and
23
+ declaration files automatically using our internal TypeScript compiler.
24
24
 
25
- Is compiled to an ECMAScript class that can be used like this:
25
+ - Generate TypeScript files only and bring your own TypeScript compiler, using
26
+ it to generate JavaScript and declaration files with your own version of
27
+ TypeScript and your own compiler options.
26
28
 
27
- ```typescript
28
- let pete = new Person({
29
- name: "pete",
30
- id: 123
31
- });
29
+ With `protoplugin`, you have all the tools at your disposal to produce ECMAScript-compliant
30
+ code.
32
31
 
33
- let bytes = pete.toBinary();
34
- pete = Person.fromBinary(bytes);
35
- pete = Person.fromJsonString('{"name": "pete", "id": 123}');
36
- ```
37
-
38
- Learn more at [github.com/bufbuild/protobuf-es](https://github.com/bufbuild/protobuf-es).
32
+ Get started now with our [plugin documentation](https://github.com/bufbuild/protobuf-es/blob/main/docs/writing_plugins.md).
@@ -15,24 +15,84 @@
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.createEcmaScriptPlugin = void 0;
17
17
  const schema_js_1 = require("./ecmascript/schema.js");
18
- const protobuf_1 = require("@bufbuild/protobuf");
18
+ const transpile_js_1 = require("./ecmascript/transpile.js");
19
19
  const error_js_1 = require("./error.js");
20
20
  /**
21
21
  * Create a new code generator plugin for ECMAScript.
22
22
  * The plugin can generate JavaScript, TypeScript, or TypeScript declaration
23
23
  * files.
24
24
  */
25
- function createEcmaScriptPlugin(init, generateFn) {
25
+ function createEcmaScriptPlugin(init) {
26
+ let transpileJs = false;
27
+ let transpileDts = false;
26
28
  return {
27
29
  name: init.name,
28
30
  version: init.version,
29
31
  run(req) {
30
- const { targets, tsNocheck, bootstrapWkt, rewriteImports } = parseParameter(req.parameter, init.parseOption);
31
- const { schema, toResponse } = (0, schema_js_1.createSchema)(req, targets, init.name, init.version, tsNocheck, bootstrapWkt, rewriteImports);
32
- generateFn(schema);
33
- const res = new protobuf_1.CodeGeneratorResponse();
34
- toResponse(res);
35
- return res;
32
+ var _a;
33
+ const { targets, tsNocheck, bootstrapWkt, rewriteImports, keepEmptyFiles, } = parseParameter(req.parameter, init.parseOption);
34
+ const { schema, getFileInfo } = (0, schema_js_1.createSchema)(req, targets, init.name, init.version, tsNocheck, bootstrapWkt, rewriteImports, keepEmptyFiles);
35
+ const targetTs = schema.targets.includes("ts");
36
+ const targetJs = schema.targets.includes("js");
37
+ const targetDts = schema.targets.includes("dts");
38
+ // Generate TS files under the following conditions:
39
+ // - if they are explicitly specified as a target.
40
+ // - if js is specified as a target but no js generator is provided.
41
+ // - if dts is specified as a target, but no dts generator is provided.
42
+ // In the latter two cases, it is because we need the generated TS files
43
+ // to use for transpiling js and/or dts.
44
+ let tsFiles = [];
45
+ if (targetTs ||
46
+ (targetJs && !init.generateJs) ||
47
+ (targetDts && !init.generateDts)) {
48
+ init.generateTs(schema, "ts");
49
+ // Save off the generated TypeScript files so that we can pass these
50
+ // to the transpilation process if necessary. We do not want to pass
51
+ // JavaScript files for a few reasons:
52
+ // 1. Our usage of allowJs in the compiler options will cause issues
53
+ // with attempting to transpile .ts and .js files to the same location.
54
+ // 2. There should be no reason to transpile JS because generateTs
55
+ // functions are required, so users would never be able to only specify
56
+ // a generateJs function and expect to transpile declarations.
57
+ // 3. Transpiling is somewhat expensive and situations with an
58
+ // extremely large amount of files could have performance impacts.
59
+ tsFiles = getFileInfo();
60
+ }
61
+ if (targetJs) {
62
+ if (init.generateJs) {
63
+ init.generateJs(schema, "js");
64
+ }
65
+ else {
66
+ transpileJs = true;
67
+ }
68
+ }
69
+ if (targetDts) {
70
+ if (init.generateDts) {
71
+ init.generateDts(schema, "dts");
72
+ }
73
+ else {
74
+ transpileDts = true;
75
+ }
76
+ }
77
+ // Get generated files. If ts was specified as a target, then we want
78
+ // all generated files. If ts was not specified, we still may have
79
+ // generated TypeScript files to assist in transpilation. If they were
80
+ // generated but not specified in the target out, we shouldn't produce
81
+ // these files in the CodeGeneratorResponse.
82
+ let files = getFileInfo();
83
+ if (!targetTs && tsFiles.length > 0) {
84
+ files = files.filter((file) => !tsFiles.some((tsFile) => tsFile.name === file.name));
85
+ }
86
+ // If either boolean is true, it means it was specified in the target out
87
+ // but no generate function was provided. This also means that we will
88
+ // have generated .ts files above.
89
+ if (transpileJs || transpileDts) {
90
+ const transpileFn = (_a = init.transpile) !== null && _a !== void 0 ? _a : transpile_js_1.transpile;
91
+ // Transpile the TypeScript files and add to the master list of files
92
+ const transpiledFiles = transpileFn(tsFiles, transpileJs, transpileDts);
93
+ files.push(...transpiledFiles);
94
+ }
95
+ return (0, schema_js_1.toResponse)(files);
36
96
  },
37
97
  };
38
98
  }
@@ -41,6 +101,7 @@ function parseParameter(parameter, parseOption) {
41
101
  let targets = ["js", "dts"];
42
102
  let tsNocheck = true;
43
103
  let bootstrapWkt = false;
104
+ let keepEmptyFiles = false;
44
105
  const rewriteImports = [];
45
106
  for (const { key, value } of splitParameter(parameter)) {
46
107
  switch (key) {
@@ -98,6 +159,21 @@ function parseParameter(parameter, parseOption) {
98
159
  rewriteImports.push({ pattern, target });
99
160
  break;
100
161
  }
162
+ case "keep_empty_files": {
163
+ switch (value) {
164
+ case "true":
165
+ case "1":
166
+ keepEmptyFiles = true;
167
+ break;
168
+ case "false":
169
+ case "0":
170
+ keepEmptyFiles = false;
171
+ break;
172
+ default:
173
+ throw new error_js_1.PluginOptionError(`${key}=${value}`);
174
+ }
175
+ break;
176
+ }
101
177
  default:
102
178
  if (parseOption === undefined) {
103
179
  throw new error_js_1.PluginOptionError(`${key}=${value}`);
@@ -111,7 +187,7 @@ function parseParameter(parameter, parseOption) {
111
187
  break;
112
188
  }
113
189
  }
114
- return { targets, tsNocheck, bootstrapWkt, rewriteImports };
190
+ return { targets, tsNocheck, bootstrapWkt, rewriteImports, keepEmptyFiles };
115
191
  }
116
192
  function splitParameter(parameter) {
117
193
  if (parameter == undefined) {
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ // Copyright 2021-2022 Buf Technologies, Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.findCustomEnumOption = exports.findCustomMessageOption = exports.findCustomScalarOption = void 0;
17
+ const protobuf_1 = require("@bufbuild/protobuf");
18
+ /**
19
+ * Returns the value of a custom option with a scalar type.
20
+ *
21
+ * If no option is found, returns undefined.
22
+ */
23
+ function findCustomScalarOption(desc, extensionNumber, scalarType) {
24
+ const reader = createBinaryReader(desc, extensionNumber);
25
+ if (reader) {
26
+ switch (scalarType) {
27
+ case protobuf_1.ScalarType.INT32:
28
+ return reader.int32();
29
+ case protobuf_1.ScalarType.UINT32:
30
+ return reader.uint32();
31
+ case protobuf_1.ScalarType.SINT32:
32
+ return reader.sint32();
33
+ case protobuf_1.ScalarType.FIXED32:
34
+ return reader.fixed32();
35
+ case protobuf_1.ScalarType.SFIXED32:
36
+ return reader.sfixed32();
37
+ case protobuf_1.ScalarType.FLOAT:
38
+ return reader.float();
39
+ case protobuf_1.ScalarType.DOUBLE:
40
+ return reader.double();
41
+ case protobuf_1.ScalarType.INT64:
42
+ return reader.int64();
43
+ case protobuf_1.ScalarType.SINT64:
44
+ return reader.sint64();
45
+ case protobuf_1.ScalarType.SFIXED64:
46
+ return reader.sfixed64();
47
+ case protobuf_1.ScalarType.UINT64:
48
+ return reader.uint64();
49
+ case protobuf_1.ScalarType.FIXED64:
50
+ return reader.fixed64();
51
+ case protobuf_1.ScalarType.BOOL:
52
+ return reader.bool();
53
+ case protobuf_1.ScalarType.BYTES:
54
+ return reader.bytes();
55
+ case protobuf_1.ScalarType.STRING:
56
+ return reader.string();
57
+ default: {
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ return undefined;
63
+ }
64
+ exports.findCustomScalarOption = findCustomScalarOption;
65
+ /**
66
+ * Returns the value of a custom message option for the given descriptor and
67
+ * extension number.
68
+ * The msgType param is then used to deserialize the message for returning to
69
+ * the caller.
70
+ *
71
+ * If no options are found, returns undefined.
72
+ *
73
+ * If the message option is unable to be read or deserialized, an error will
74
+ * be thrown.
75
+ */
76
+ function findCustomMessageOption(desc, extensionNumber, msgType) {
77
+ const reader = createBinaryReader(desc, extensionNumber);
78
+ if (reader) {
79
+ try {
80
+ const data = reader.bytes();
81
+ return msgType.fromBinary(data);
82
+ }
83
+ catch (e) {
84
+ const innerMessage = e instanceof Error ? e.message : String(e);
85
+ throw new Error(`failed to access message option: ${innerMessage}`);
86
+ }
87
+ }
88
+ return undefined;
89
+ }
90
+ exports.findCustomMessageOption = findCustomMessageOption;
91
+ /**
92
+ * Returns the value of a custom enum option for the given descriptor and
93
+ * extension number.
94
+ *
95
+ * If no options are found, returns undefined.
96
+ */
97
+ function findCustomEnumOption(desc, extensionNumber) {
98
+ return findCustomScalarOption(desc, extensionNumber, protobuf_1.ScalarType.INT32);
99
+ }
100
+ exports.findCustomEnumOption = findCustomEnumOption;
101
+ /**
102
+ * Returns a binary reader for the given descriptor and extension number.
103
+ */
104
+ function createBinaryReader(desc, extensionNumber) {
105
+ const opt = desc.proto.options;
106
+ let reader = undefined;
107
+ if (opt !== undefined) {
108
+ const unknownFields = protobuf_1.proto3.bin.listUnknownFields(opt);
109
+ const field = unknownFields.find((f) => f.no === extensionNumber);
110
+ if (field) {
111
+ reader = new protobuf_1.BinaryReader(field.data);
112
+ }
113
+ }
114
+ return reader;
115
+ }
@@ -103,10 +103,7 @@ function makeJsDoc(desc, indentation = "") {
103
103
  case "enum_value":
104
104
  text += `@generated from enum value: ${desc.declarationString()};`;
105
105
  break;
106
- case "scalar_field":
107
- case "enum_field":
108
- case "message_field":
109
- case "map_field":
106
+ case "field":
110
107
  text += `@generated from field: ${desc.declarationString()};`;
111
108
  break;
112
109
  default:
@@ -139,12 +136,12 @@ exports.makeJsDoc = makeJsDoc;
139
136
  function getFieldTyping(field, file) {
140
137
  const typing = [];
141
138
  let optional = false;
142
- switch (field.kind) {
143
- case "scalar_field":
139
+ switch (field.fieldKind) {
140
+ case "scalar":
144
141
  typing.push(scalarTypeScriptType(field.scalar));
145
142
  optional = field.optional;
146
143
  break;
147
- case "message_field": {
144
+ case "message": {
148
145
  const baseType = getUnwrappedFieldType(field);
149
146
  if (baseType !== undefined) {
150
147
  typing.push(scalarTypeScriptType(baseType));
@@ -155,11 +152,11 @@ function getFieldTyping(field, file) {
155
152
  optional = true;
156
153
  break;
157
154
  }
158
- case "enum_field":
155
+ case "enum":
159
156
  typing.push(file.import(field.enum).toTypeOnly());
160
157
  optional = field.optional;
161
158
  break;
162
- case "map_field": {
159
+ case "map": {
163
160
  let keyType;
164
161
  switch (field.mapKey) {
165
162
  case protobuf_1.ScalarType.INT32:
@@ -231,15 +228,15 @@ function literalString(value) {
231
228
  }
232
229
  exports.literalString = literalString;
233
230
  function getFieldExplicitDefaultValue(field, protoInt64Symbol) {
234
- switch (field.kind) {
235
- case "enum_field": {
231
+ switch (field.fieldKind) {
232
+ case "enum": {
236
233
  const value = field.enum.values.find((v) => v.number === field.getDefaultValue());
237
234
  if (value !== undefined) {
238
235
  return [value.parent, ".", localName(value)];
239
236
  }
240
237
  break;
241
238
  }
242
- case "scalar_field": {
239
+ case "scalar": {
243
240
  const defaultValue = field.getDefaultValue();
244
241
  if (defaultValue === undefined) {
245
242
  break;
@@ -293,7 +290,7 @@ function getFieldIntrinsicDefaultValue(field) {
293
290
  typingInferrable: false,
294
291
  };
295
292
  }
296
- if (field.kind == "map_field") {
293
+ if (field.fieldKind == "map") {
297
294
  return {
298
295
  defaultValue: "{}",
299
296
  typingInferrable: false,
@@ -302,8 +299,8 @@ function getFieldIntrinsicDefaultValue(field) {
302
299
  let defaultValue = undefined;
303
300
  let typingInferrable = false;
304
301
  if (field.parent.file.syntax == "proto3") {
305
- switch (field.kind) {
306
- case "enum_field": {
302
+ switch (field.fieldKind) {
303
+ case "enum": {
307
304
  if (!field.optional) {
308
305
  const zeroValue = field.enum.values.find((v) => v.number === 0);
309
306
  if (zeroValue === undefined) {
@@ -314,7 +311,7 @@ function getFieldIntrinsicDefaultValue(field) {
314
311
  }
315
312
  break;
316
313
  }
317
- case "scalar_field":
314
+ case "scalar":
318
315
  if (!field.optional) {
319
316
  typingInferrable = true;
320
317
  if (field.scalar === protobuf_1.ScalarType.STRING) {
@@ -14,11 +14,10 @@
14
14
  // limitations under the License.
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.createGeneratedFile = void 0;
17
- const protobuf_1 = require("@bufbuild/protobuf");
18
17
  const import_symbol_js_1 = require("./import-symbol.js");
19
18
  const gencommon_js_1 = require("./gencommon.js");
20
19
  const import_path_js_1 = require("./import-path.js");
21
- function createGeneratedFile(name, importPath, createTypeImport, runtimeImports, preambleSettings) {
20
+ function createGeneratedFile(name, importPath, createTypeImport, runtimeImports, preambleSettings, keepEmpty) {
22
21
  let preamble;
23
22
  const el = [];
24
23
  return {
@@ -35,22 +34,20 @@ function createGeneratedFile(name, importPath, createTypeImport, runtimeImports,
35
34
  import(typeOrName, from) {
36
35
  if (typeof typeOrName == "string") {
37
36
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
38
- return (0, import_symbol_js_1.createImportSymbol)(name, from);
37
+ return (0, import_symbol_js_1.createImportSymbol)(typeOrName, from);
39
38
  }
40
39
  return createTypeImport(typeOrName);
41
40
  },
42
- toResponse(res) {
43
- let content = elToContent(el, importPath);
44
- if (content.length === 0) {
41
+ getFileInfo() {
42
+ const content = elToContent(el, importPath);
43
+ if (!keepEmpty && content.length === 0) {
45
44
  return;
46
45
  }
47
- if (preamble !== undefined) {
48
- content = preamble + "\n" + content;
49
- }
50
- res.file.push(new protobuf_1.CodeGeneratorResponse_File({
51
- name: name,
46
+ return {
47
+ name,
52
48
  content,
53
- }));
49
+ preamble,
50
+ };
54
51
  },
55
52
  };
56
53
  }
@@ -13,14 +13,14 @@
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.literalString = exports.makeJsDoc = exports.getFieldTyping = exports.getFieldIntrinsicDefaultValue = exports.getFieldExplicitDefaultValue = exports.createJsDocBlock = exports.localName = void 0;
16
+ exports.findCustomEnumOption = exports.findCustomMessageOption = exports.findCustomScalarOption = exports.literalString = exports.makeJsDoc = exports.getFieldTyping = exports.getFieldIntrinsicDefaultValue = exports.getFieldExplicitDefaultValue = exports.createJsDocBlock = exports.reifyWkt = exports.localName = void 0;
17
17
  const protobuf_1 = require("@bufbuild/protobuf");
18
18
  var target_js_1 = require("./target.js");
19
19
  var schema_js_1 = require("./schema.js");
20
20
  var runtime_imports_js_1 = require("./runtime-imports.js");
21
21
  var generated_file_js_1 = require("./generated-file.js");
22
22
  var import_symbol_js_1 = require("./import-symbol.js");
23
- exports.localName = protobuf_1.codegenInfo.localName;
23
+ exports.localName = protobuf_1.codegenInfo.localName, exports.reifyWkt = protobuf_1.codegenInfo.reifyWkt;
24
24
  var gencommon_js_1 = require("./gencommon.js");
25
25
  Object.defineProperty(exports, "createJsDocBlock", { enumerable: true, get: function () { return gencommon_js_1.createJsDocBlock; } });
26
26
  Object.defineProperty(exports, "getFieldExplicitDefaultValue", { enumerable: true, get: function () { return gencommon_js_1.getFieldExplicitDefaultValue; } });
@@ -28,3 +28,7 @@ Object.defineProperty(exports, "getFieldIntrinsicDefaultValue", { enumerable: tr
28
28
  Object.defineProperty(exports, "getFieldTyping", { enumerable: true, get: function () { return gencommon_js_1.getFieldTyping; } });
29
29
  Object.defineProperty(exports, "makeJsDoc", { enumerable: true, get: function () { return gencommon_js_1.makeJsDoc; } });
30
30
  Object.defineProperty(exports, "literalString", { enumerable: true, get: function () { return gencommon_js_1.literalString; } });
31
+ var custom_options_js_1 = require("./custom-options.js");
32
+ Object.defineProperty(exports, "findCustomScalarOption", { enumerable: true, get: function () { return custom_options_js_1.findCustomScalarOption; } });
33
+ Object.defineProperty(exports, "findCustomMessageOption", { enumerable: true, get: function () { return custom_options_js_1.findCustomMessageOption; } });
34
+ Object.defineProperty(exports, "findCustomEnumOption", { enumerable: true, get: function () { return custom_options_js_1.findCustomEnumOption; } });
@@ -13,13 +13,13 @@
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.createSchema = void 0;
16
+ exports.toResponse = exports.createSchema = void 0;
17
17
  const protobuf_1 = require("@bufbuild/protobuf");
18
18
  const generated_file_js_1 = require("./generated-file.js");
19
19
  const runtime_imports_js_1 = require("./runtime-imports.js");
20
20
  const import_symbol_js_1 = require("./import-symbol.js");
21
21
  const import_path_js_1 = require("./import-path.js");
22
- function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bootstrapWkt, rewriteImports) {
22
+ function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bootstrapWkt, rewriteImports, keepEmptyFiles) {
23
23
  const descriptorSet = (0, protobuf_1.createDescriptorSet)(request.protoFile);
24
24
  const filesToGenerate = findFilesToGenerate(descriptorSet, request);
25
25
  const runtime = (0, runtime_imports_js_1.createRuntimeImports)(bootstrapWkt);
@@ -42,22 +42,38 @@ function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bo
42
42
  pluginVersion,
43
43
  parameter: request.parameter,
44
44
  tsNocheck,
45
- });
45
+ }, keepEmptyFiles);
46
46
  generatedFiles.push(genFile);
47
47
  return genFile;
48
48
  },
49
49
  };
50
50
  return {
51
51
  schema,
52
- toResponse(res) {
53
- res.supportedFeatures = protobuf_1.protoInt64.parse(protobuf_1.CodeGeneratorResponse_Feature.PROTO3_OPTIONAL);
54
- for (const genFile of generatedFiles) {
55
- genFile.toResponse(res);
56
- }
52
+ getFileInfo() {
53
+ return generatedFiles.flatMap((file) => {
54
+ const fileInfo = file.getFileInfo();
55
+ // undefined is returned if the file has no content
56
+ if (!fileInfo) {
57
+ return [];
58
+ }
59
+ return [fileInfo];
60
+ });
57
61
  },
58
62
  };
59
63
  }
60
64
  exports.createSchema = createSchema;
65
+ function toResponse(files) {
66
+ return new protobuf_1.CodeGeneratorResponse({
67
+ supportedFeatures: protobuf_1.protoInt64.parse(protobuf_1.CodeGeneratorResponse_Feature.PROTO3_OPTIONAL),
68
+ file: files.map((f) => {
69
+ if (f.preamble !== undefined) {
70
+ f.content = f.preamble + "\n" + f.content;
71
+ }
72
+ return f;
73
+ }),
74
+ });
75
+ }
76
+ exports.toResponse = toResponse;
61
77
  function findFilesToGenerate(descriptorSet, request) {
62
78
  const missing = request.fileToGenerate.filter((fileToGenerate) => descriptorSet.files.every((file) => fileToGenerate !== file.name + ".proto"));
63
79
  if (missing.length) {
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ // Copyright 2021-2022 Buf Technologies, Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ var __importDefault = (this && this.__importDefault) || function (mod) {
16
+ return (mod && mod.__esModule) ? mod : { "default": mod };
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.transpile = void 0;
20
+ const typescript_1 = __importDefault(require("typescript"));
21
+ const vfs_1 = require("@typescript/vfs");
22
+ /* eslint-disable import/no-named-as-default-member */
23
+ // The default options used to auto-transpile if needed.
24
+ const defaultOptions = {
25
+ // Type checking
26
+ strict: false,
27
+ // modules
28
+ module: typescript_1.default.ModuleKind.ES2020,
29
+ moduleResolution: typescript_1.default.ModuleResolutionKind.NodeJs,
30
+ noResolve: true,
31
+ resolveJsonModule: false,
32
+ // emit
33
+ emitBOM: false,
34
+ importsNotUsedAsValues: typescript_1.default.ImportsNotUsedAsValues.Preserve,
35
+ newLine: typescript_1.default.NewLineKind.LineFeed,
36
+ preserveValueImports: false,
37
+ // JavaScript Support
38
+ allowJs: true,
39
+ checkJs: false,
40
+ // Language and Environment
41
+ lib: [],
42
+ moduleDetection: "force",
43
+ target: typescript_1.default.ScriptTarget.ES2017,
44
+ // Completeness
45
+ skipLibCheck: true,
46
+ skipDefaultLibCheck: false,
47
+ };
48
+ /**
49
+ * Create a transpiler using the given compiler options, which will compile the
50
+ * content provided in the files array.
51
+ *
52
+ * Note: this library intentionally transpiles with a pinned older version of
53
+ * TypeScript for stability. This version is denoted in this workspace's
54
+ * package.json. For the default set of compiler options, we use a lenient
55
+ * set of options because the general goal is to emit code as best as we can.
56
+ * For a list of the options used, see `defaultOptions` above.
57
+ *
58
+ * If this is not desirable for plugin authors, they are free to provide their
59
+ * own transpile function as part of the plugin initialization. If one is
60
+ * provided, it will be invoked instead and the framework's auto-transpilation
61
+ * will be bypassed.
62
+ *
63
+ * In addition, note that there is a dependency on @typescript/vfs in the
64
+ * top-level package as well as this package. This is to avoid npm hoisting
65
+ * @typescript/vfs to the top-level node_modules directory, which then causes
66
+ * type mismatches when trying to use it with this package's version of
67
+ * TypeScript. Ideally we would use something like Yarn's nohoist here, but
68
+ * npm does not support that yet.
69
+ */
70
+ function createTranspiler(options, files) {
71
+ const fsMap = (0, vfs_1.createDefaultMapFromNodeModules)({
72
+ target: options.target,
73
+ });
74
+ files.forEach((file) => {
75
+ fsMap.set(file.name, file.content);
76
+ });
77
+ const system = (0, vfs_1.createSystem)(fsMap);
78
+ const host = (0, vfs_1.createVirtualCompilerHost)(system, options, typescript_1.default);
79
+ return typescript_1.default.createProgram({
80
+ rootNames: [...fsMap.keys()],
81
+ options,
82
+ host: host.compilerHost,
83
+ });
84
+ }
85
+ function transpile(files, transpileJs, transpileDts) {
86
+ const options = Object.assign(Object.assign({}, defaultOptions), { declaration: transpileDts, emitDeclarationOnly: transpileDts && !transpileJs });
87
+ // Create the transpiler (a ts.Program object)
88
+ const program = createTranspiler(options, files);
89
+ const results = [];
90
+ let err;
91
+ const result = program.emit(undefined, (fileName, data, writeByteOrderMark, onError, sourceFiles) => {
92
+ // We have to go through some hoops here because the header we add to each
93
+ // file is not part of the AST. So we find the TypeScript file we
94
+ // generated for each emitted file and add the header to each output ourselves.
95
+ if (!sourceFiles) {
96
+ err = new Error(`unable to map emitted file "${fileName}" to a source file: missing source files`);
97
+ return;
98
+ }
99
+ if (sourceFiles.length !== 1) {
100
+ err = new Error(`unable to map emitted file "${fileName}" to a source file: expected 1 source file, got ${sourceFiles.length}`);
101
+ return;
102
+ }
103
+ const file = files.find((x) => sourceFiles[0].fileName === x.name);
104
+ if (!file) {
105
+ err = new Error(`unable to map emitted file "${fileName}" to a source file: not found`);
106
+ return;
107
+ }
108
+ results.push({
109
+ name: fileName,
110
+ preamble: file.preamble,
111
+ content: data,
112
+ });
113
+ });
114
+ if (err) {
115
+ throw err;
116
+ }
117
+ if (result.emitSkipped) {
118
+ throw Error("An problem occurred during transpilation and files were not generated. Contact the plugin author for support.");
119
+ }
120
+ return results;
121
+ }
122
+ exports.transpile = transpile;