@bufbuild/protoc-gen-es 1.9.0 → 2.0.0-alpha.2

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
@@ -4,7 +4,7 @@ The code generator plugin for Protocol Buffers for ECMAScript. Learn more about
4
4
 
5
5
  ## Installation
6
6
 
7
- `protoc-gen-es` generates base types - messages and enumerations - from your Protocol Buffer
7
+ `protoc-gen-es` generates base types - messages and enumerations - from your Protocol Buffer
8
8
  schema. The generated code requires the runtime library [@bufbuild/protobuf](https://www.npmjs.com/package/@bufbuild/protobuf). It is compatible with Protocol Buffer compilers like [buf](https://github.com/bufbuild/buf) and [protoc](https://github.com/protocolbuffers/protobuf/releases).
9
9
 
10
10
  To install the plugin and the runtime library, run:
@@ -15,7 +15,7 @@ npm install @bufbuild/protobuf
15
15
  ```
16
16
 
17
17
  We use peer dependencies to ensure that code generator and runtime library are
18
- compatible with each other. Note that npm installs them automatically, but yarn
18
+ compatible with each other. Note that npm installs them automatically, but yarn
19
19
  and pnpm do not.
20
20
 
21
21
 
@@ -37,7 +37,7 @@ plugins:
37
37
  # This will invoke protoc-gen-es and write output to src/gen
38
38
  - plugin: es
39
39
  out: src/gen
40
- opt:
40
+ opt:
41
41
  # Add more plugin options here
42
42
  - target=ts
43
43
  ```
@@ -49,7 +49,7 @@ npx buf generate
49
49
  ```
50
50
 
51
51
  Note that `buf` can generate from various [inputs](https://docs.buf.build/reference/inputs),
52
- not just local protobuf files.
52
+ not just local protobuf files.
53
53
 
54
54
 
55
55
  ### With protoc
@@ -65,7 +65,7 @@ PATH=$PATH:$(pwd)/node_modules/.bin \
65
65
  Note that we are adding `node_modules/.bin` to the `$PATH`, so that the protocol
66
66
  buffer compiler can find them. This happens automatically with npm scripts.
67
67
 
68
- Since yarn v2 and above does not use a `node_modules` directory, you need to
68
+ Since yarn v2 and above does not use a `node_modules` directory, you need to
69
69
  change the variable a bit:
70
70
 
71
71
  ```bash
@@ -88,33 +88,32 @@ Multiple values can be given by separating them with `+`, for example
88
88
  `target=js+dts`.
89
89
 
90
90
  By default, we generate JavaScript and TypeScript declaration files, which
91
- produces the smallest code size and is the most compatible with various
91
+ produces the smallest code size and is the most compatible with various
92
92
  bundler configurations. If you prefer to generate TypeScript, use `target=ts`.
93
93
 
94
- ### `import_extension=.js`
94
+ ### `import_extension`
95
95
 
96
96
  By default, [protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es)
97
97
  (and all other plugins based on [@bufbuild/protoplugin](https://www.npmjs.com/package/@bufbuild/protoplugin))
98
- uses a `.js` file extensions in import paths, even in TypeScript files.
98
+ does not add a file extensions to import paths.
99
99
 
100
- This is unintuitive, but necessary for [ECMAScript modules in Node.js](https://www.typescriptlang.org/docs/handbook/esm-node.html).
101
- Unfortunately, not all bundlers and tools have caught up yet, and Deno
102
- requires `.ts`. With this plugin option, you can replace `.js` extensions
100
+ Some environments require an import extension. For example, using [ECMAScript modules in Node.js](https://www.typescriptlang.org/docs/handbook/esm-node.html) requires the `.js` extension, and Deno requires `.ts`. With this plugin option, you can add `.js`/`.ts` extensions
103
101
  in import paths with the given value. For example, set
104
102
 
105
- - `import_extension=none` to remove the `.js` extension.
106
- - `import_extension=.ts` to replace the `.js` extension with `.ts`.
103
+ - `import_extension=.js` to add the `.js` extension.
104
+ - `import_extension=.ts` to add the `.ts` extension.
105
+ - `import_extension=none` to not add an extension. (Default)
107
106
 
108
107
  ### `js_import_style`
109
108
 
110
109
  By default, [protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es)
111
110
  (and all other plugins based on [@bufbuild/protoplugin](https://www.npmjs.com/package/@bufbuild/protoplugin))
112
- generate ECMAScript `import` and `export` statements. For use cases where
113
- CommonJS is difficult to avoid, this option can be used to generate CommonJS
111
+ generate ECMAScript `import` and `export` statements. For use cases where
112
+ CommonJS is difficult to avoid, this option can be used to generate CommonJS
114
113
  `require()` calls.
115
114
 
116
115
  Possible values:
117
- - `js_import_style=module` generate ECMAScript `import` / `export` statements -
116
+ - `js_import_style=module` generate ECMAScript `import` / `export` statements -
118
117
  the default behavior.
119
118
  - `js_import_style=legacy_commonjs` generate CommonJS `require()` calls.
120
119
 
@@ -127,13 +126,12 @@ empty files, to allow for smooth interoperation with Bazel and similar
127
126
  tooling that requires all output files to be declared ahead of time.
128
127
  Unless you use Bazel, it is very unlikely that you need this option.
129
128
 
130
- ### `ts_nocheck=false`
129
+ ### `ts_nocheck=true`
131
130
 
132
- By default, [protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es)
133
- (and all other plugins based on [@bufbuild/protoplugin](https://www.npmjs.com/package/@bufbuild/protoplugin))
134
- generate an annotation at the top of each file: `// @ts-nocheck`.
131
+ [protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es) generates
132
+ valid TypeScript for current versions of the TypeScript compiler with standard
133
+ settings.
135
134
 
136
- We generate the annotation to support a wide range of compiler configurations and
137
- future changes to the language. But there can be situations where the annotation
138
- shadows an underlying problem, for example an unresolvable import. To remove
139
- the annotation and to enable type checks, set the plugin option `ts_nocheck=false`.
135
+ In case you use compiler settings that yield an error for generated code, you
136
+ can set the plugin option `ts_nocheck=true`. This will generate an annotation at
137
+ the top of each file to skip type checks: `// @ts-nocheck`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bufbuild/protoc-gen-es",
3
- "version": "1.9.0",
3
+ "version": "2.0.0-alpha.2",
4
4
  "description": "Protocol Buffers code generator for ECMAScript",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,15 +20,19 @@
20
20
  },
21
21
  "preferUnplugged": true,
22
22
  "dependencies": {
23
- "@bufbuild/protobuf": "^1.9.0",
24
- "@bufbuild/protoplugin": "1.9.0"
23
+ "@bufbuild/protobuf": "^2.0.0-alpha.2",
24
+ "@bufbuild/protoplugin": "2.0.0-alpha.2"
25
25
  },
26
26
  "peerDependencies": {
27
- "@bufbuild/protobuf": "1.9.0"
27
+ "@bufbuild/protobuf": "2.0.0-alpha.2"
28
28
  },
29
29
  "peerDependenciesMeta": {
30
30
  "@bufbuild/protobuf": {
31
31
  "optional": true
32
32
  }
33
- }
33
+ },
34
+ "files": [
35
+ "dist/**",
36
+ "bin/**"
37
+ ]
34
38
  }
@@ -14,15 +14,329 @@
14
14
  // limitations under the License.
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.protocGenEs = void 0;
17
+ const reflect_1 = require("@bufbuild/protobuf/reflect");
18
+ const codegenv1_1 = require("@bufbuild/protobuf/codegenv1");
17
19
  const protoplugin_1 = require("@bufbuild/protoplugin");
18
- const typescript_js_1 = require("./typescript.js");
19
- const javascript_js_1 = require("./javascript.js");
20
- const declaration_js_1 = require("./declaration.js");
20
+ const util_1 = require("./util");
21
21
  const package_json_1 = require("../package.json");
22
22
  exports.protocGenEs = (0, protoplugin_1.createEcmaScriptPlugin)({
23
23
  name: "protoc-gen-es",
24
24
  version: `v${String(package_json_1.version)}`,
25
- generateTs: typescript_js_1.generateTs,
26
- generateJs: javascript_js_1.generateJs,
27
- generateDts: declaration_js_1.generateDts,
25
+ generateTs,
26
+ generateJs,
27
+ generateDts,
28
28
  });
29
+ // This annotation informs bundlers that the succeeding function call is free of
30
+ // side effects. This means the symbol can be removed from the module during
31
+ // tree-shaking if it is unused.
32
+ // See https://github.com/bufbuild/protobuf-es/pull/470
33
+ const pure = "/*@__PURE__*/";
34
+ // prettier-ignore
35
+ function generateTs(schema) {
36
+ for (const file of schema.files) {
37
+ const f = schema.generateFile(file.name + "_pb.ts");
38
+ f.preamble(file);
39
+ const { GenDescFile } = f.runtime.codegen;
40
+ const fileDesc = f.importDesc(file);
41
+ generateDescDoc(f, file);
42
+ f.print(f.exportDecl("const", fileDesc.name), ": ", GenDescFile, " = ", pure);
43
+ f.print(" ", getFileDescCall(f, file, schema), ";");
44
+ f.print();
45
+ for (const desc of schema.typesInFile(file)) {
46
+ switch (desc.kind) {
47
+ case "message": {
48
+ generateMessageShape(f, desc, "ts");
49
+ const { GenDescMessage, messageDesc } = f.runtime.codegen;
50
+ const MessageShape = f.importShape(desc);
51
+ const name = f.importDesc(desc).name;
52
+ generateDescDoc(f, desc);
53
+ const call = (0, util_1.functionCall)(messageDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
54
+ f.print(f.exportDecl("const", name), ": ", GenDescMessage, "<", MessageShape, ">", " = ", pure);
55
+ f.print(" ", call, ";");
56
+ f.print();
57
+ break;
58
+ }
59
+ case "enum": {
60
+ generateEnumShape(f, desc);
61
+ const { GenDescEnum, enumDesc } = f.runtime.codegen;
62
+ const EnumShape = f.importShape(desc);
63
+ generateDescDoc(f, desc);
64
+ const name = f.importDesc(desc).name;
65
+ const call = (0, util_1.functionCall)(enumDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
66
+ f.print(f.exportDecl("const", name), ": ", GenDescEnum, "<", EnumShape, ">", " = ", pure);
67
+ f.print(" ", call, ";");
68
+ f.print();
69
+ break;
70
+ }
71
+ case "extension": {
72
+ const { GenDescExtension, extDesc } = f.runtime.codegen;
73
+ const name = f.importDesc(desc).name;
74
+ const E = f.importShape(desc.extendee);
75
+ const V = (0, util_1.fieldTypeScriptType)(desc).typing;
76
+ const call = (0, util_1.functionCall)(extDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
77
+ f.print(f.jsDoc(desc));
78
+ f.print(f.exportDecl("const", name), ": ", GenDescExtension, "<", E, ", ", V, ">", " = ", pure);
79
+ f.print(" ", call, ";");
80
+ f.print();
81
+ break;
82
+ }
83
+ case "service": {
84
+ const { GenDescService, serviceDesc } = f.runtime.codegen;
85
+ const name = f.importDesc(desc).name;
86
+ const call = (0, util_1.functionCall)(serviceDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
87
+ f.print(f.jsDoc(desc));
88
+ f.print(f.exportDecl("const", name), ": ", GenDescService, "<", getServiceShapeExpr(f, desc), "> = ", pure);
89
+ f.print(" ", call, ";");
90
+ f.print();
91
+ break;
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ // prettier-ignore
98
+ function generateJs(schema) {
99
+ for (const file of schema.files) {
100
+ const f = schema.generateFile(file.name + "_pb.js");
101
+ f.preamble(file);
102
+ const fileDesc = f.importDesc(file);
103
+ generateDescDoc(f, file);
104
+ f.print(f.exportDecl("const", fileDesc.name), " = ", pure);
105
+ f.print(" ", getFileDescCall(f, file, schema), ";");
106
+ f.print();
107
+ for (const desc of schema.typesInFile(file)) {
108
+ switch (desc.kind) {
109
+ case "message": {
110
+ const { messageDesc } = f.runtime.codegen;
111
+ const name = f.importDesc(desc).name;
112
+ generateDescDoc(f, desc);
113
+ const call = (0, util_1.functionCall)(messageDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
114
+ f.print(f.exportDecl("const", name), " = ", pure);
115
+ f.print(" ", call, ";");
116
+ f.print();
117
+ break;
118
+ }
119
+ case "enum": {
120
+ // generate descriptor
121
+ {
122
+ const { enumDesc } = f.runtime.codegen;
123
+ generateDescDoc(f, desc);
124
+ const name = f.importDesc(desc).name;
125
+ const call = (0, util_1.functionCall)(enumDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
126
+ f.print(f.exportDecl("const", name), " = ", pure);
127
+ f.print(" ", call, ";");
128
+ f.print();
129
+ }
130
+ // declare TypeScript enum
131
+ {
132
+ f.print(f.jsDoc(desc));
133
+ const { tsEnum } = f.runtime.codegen;
134
+ const call = (0, util_1.functionCall)(tsEnum, [f.importDesc(desc)]);
135
+ f.print(f.exportDecl("const", f.importShape(desc).name), " = ", pure);
136
+ f.print(" ", call, ";");
137
+ f.print();
138
+ }
139
+ break;
140
+ }
141
+ case "extension": {
142
+ const { extDesc } = f.runtime.codegen;
143
+ const name = f.importDesc(desc).name;
144
+ const call = (0, util_1.functionCall)(extDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
145
+ f.print(f.jsDoc(desc));
146
+ f.print(f.exportDecl("const", name), " = ", pure);
147
+ f.print(" ", call, ";");
148
+ f.print();
149
+ break;
150
+ }
151
+ case "service": {
152
+ const { serviceDesc } = f.runtime.codegen;
153
+ const name = f.importDesc(desc).name;
154
+ f.print(f.jsDoc(desc));
155
+ const call = (0, util_1.functionCall)(serviceDesc, [fileDesc, ...(0, codegenv1_1.pathInFileDesc)(desc)]);
156
+ f.print(f.exportDecl("const", name), " = ", pure);
157
+ f.print(" ", call, ";");
158
+ f.print();
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+ // prettier-ignore
166
+ function generateDts(schema) {
167
+ for (const file of schema.files) {
168
+ const f = schema.generateFile(file.name + "_pb.d.ts");
169
+ f.preamble(file);
170
+ const { GenDescFile } = f.runtime.codegen;
171
+ const fileDesc = f.importDesc(file);
172
+ generateDescDoc(f, file);
173
+ f.print(f.exportDecl("declare const", fileDesc.name), ": ", GenDescFile, ";");
174
+ f.print();
175
+ for (const desc of schema.typesInFile(file)) {
176
+ switch (desc.kind) {
177
+ case "message": {
178
+ generateMessageShape(f, desc, "dts");
179
+ const { GenDescMessage } = f.runtime.codegen;
180
+ const MessageShape = f.importShape(desc);
181
+ const name = f.importDesc(desc).name;
182
+ generateDescDoc(f, desc);
183
+ f.print(f.exportDecl("declare const", name), ": ", GenDescMessage, "<", MessageShape, ">", ";");
184
+ f.print();
185
+ break;
186
+ }
187
+ case "enum": {
188
+ generateEnumShape(f, desc);
189
+ const { GenDescEnum } = f.runtime.codegen;
190
+ const EnumShape = f.importShape(desc);
191
+ generateDescDoc(f, desc);
192
+ const name = f.importDesc(desc).name;
193
+ f.print(f.exportDecl("declare const", name), ": ", GenDescEnum, "<", EnumShape, ">;");
194
+ f.print();
195
+ break;
196
+ }
197
+ case "extension": {
198
+ const { GenDescExtension } = f.runtime.codegen;
199
+ const name = f.importDesc(desc).name;
200
+ const E = f.importShape(desc.extendee);
201
+ const V = (0, util_1.fieldTypeScriptType)(desc).typing;
202
+ f.print(f.jsDoc(desc));
203
+ f.print(f.exportDecl("declare const", name), ": ", GenDescExtension, "<", E, ", ", V, ">;");
204
+ f.print();
205
+ break;
206
+ }
207
+ case "service": {
208
+ const { GenDescService } = f.runtime.codegen;
209
+ const name = f.importDesc(desc).name;
210
+ f.print(f.jsDoc(desc));
211
+ f.print(f.exportDecl("declare const", name), ": ", GenDescService, "<", getServiceShapeExpr(f, desc), ">;");
212
+ f.print();
213
+ break;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ function generateDescDoc(f, desc) {
220
+ let lines;
221
+ switch (desc.kind) {
222
+ case "file":
223
+ lines = [`Describes the ${desc.toString()}.`];
224
+ break;
225
+ case "message":
226
+ lines = [
227
+ `Describes the ${desc.toString()}.`,
228
+ `Use \`create(${f.importDesc(desc).name})\` to create a new message.`,
229
+ ];
230
+ break;
231
+ case "enum":
232
+ lines = [`Describes the ${desc.toString()}.`];
233
+ break;
234
+ }
235
+ const deprecated = desc.deprecated || (0, reflect_1.parentTypes)(desc).some((d) => d.deprecated);
236
+ if (deprecated) {
237
+ lines.push("@deprecated");
238
+ }
239
+ f.print({
240
+ kind: "es_jsdoc",
241
+ text: lines.join("\n"),
242
+ });
243
+ }
244
+ // prettier-ignore
245
+ function getFileDescCall(f, file, schema) {
246
+ // Schema provides files with source retention options. Since we do not want to
247
+ // embed source retention options in generated code, we use FileDescriptorProto
248
+ // messages from CodeGeneratorRequest.proto_file instead.
249
+ const sourceFile = file.proto;
250
+ const runtimeFile = schema.proto.protoFile.find(f => f.name == sourceFile.name);
251
+ const info = (0, codegenv1_1.embedFileDesc)(runtimeFile !== null && runtimeFile !== void 0 ? runtimeFile : sourceFile);
252
+ if (info.bootable && !f.runtime.create.from.startsWith("@bufbuild/protobuf")) {
253
+ // google/protobuf/descriptor.proto is embedded as a plain object when
254
+ // bootstrapping to avoid recursion
255
+ return (0, util_1.functionCall)(f.runtime.codegen.boot, [JSON.stringify(info.boot())]);
256
+ }
257
+ const { fileDesc } = f.runtime.codegen;
258
+ if (file.dependencies.length > 0) {
259
+ const deps = file.dependencies.map((f) => ({
260
+ kind: "es_desc_ref",
261
+ desc: f,
262
+ }));
263
+ return (0, util_1.functionCall)(fileDesc, [
264
+ f.string(info.base64()),
265
+ (0, util_1.arrayLiteral)(deps),
266
+ ]);
267
+ }
268
+ return (0, util_1.functionCall)(fileDesc, [f.string(info.base64())]);
269
+ }
270
+ // prettier-ignore
271
+ function getServiceShapeExpr(f, service) {
272
+ const p = [];
273
+ function print(...printables) {
274
+ p.push(...printables, "\n");
275
+ }
276
+ print("{");
277
+ for (const method of service.methods) {
278
+ print(f.jsDoc(method, " "));
279
+ print(" ", method.localName, ": {");
280
+ print(" kind: ", f.string(method.methodKind), ";");
281
+ print(" I: ", f.importShape(method.input), ";");
282
+ print(" O: ", f.importShape(method.output), ";");
283
+ print(" },");
284
+ }
285
+ print("}");
286
+ return p;
287
+ }
288
+ // prettier-ignore
289
+ function generateEnumShape(f, enumeration) {
290
+ f.print(f.jsDoc(enumeration));
291
+ f.print(f.exportDecl("enum", f.importShape(enumeration).name), " {");
292
+ for (const value of enumeration.values) {
293
+ if (enumeration.values.indexOf(value) > 0) {
294
+ f.print();
295
+ }
296
+ f.print(f.jsDoc(value, " "));
297
+ f.print(" ", value.localName, " = ", value.number, ",");
298
+ }
299
+ f.print("}");
300
+ f.print();
301
+ }
302
+ // prettier-ignore
303
+ function generateMessageShape(f, message, target) {
304
+ const { Message } = f.runtime;
305
+ const declaration = target == "ts" ? "type" : "declare type";
306
+ f.print(f.jsDoc(message));
307
+ f.print(f.exportDecl(declaration, f.importShape(message).name), " = ", Message, "<", f.string(message.typeName), "> & {");
308
+ for (const member of message.members) {
309
+ switch (member.kind) {
310
+ case "oneof":
311
+ f.print(f.jsDoc(member, " "));
312
+ f.print(" ", member.localName, ": {");
313
+ for (const field of member.fields) {
314
+ if (member.fields.indexOf(field) > 0) {
315
+ f.print(` } | {`);
316
+ }
317
+ f.print(f.jsDoc(field, " "));
318
+ const { typing } = (0, util_1.fieldTypeScriptType)(field);
319
+ f.print(` value: `, typing, `;`);
320
+ f.print(` case: "`, field.localName, `";`);
321
+ }
322
+ f.print(` } | { case: undefined; value?: undefined };`);
323
+ break;
324
+ default: {
325
+ f.print(f.jsDoc(member, " "));
326
+ const { typing, optional } = (0, util_1.fieldTypeScriptType)(member);
327
+ if (optional) {
328
+ f.print(" ", member.localName, "?: ", typing, ";");
329
+ }
330
+ else {
331
+ f.print(" ", member.localName, ": ", typing, ";");
332
+ }
333
+ break;
334
+ }
335
+ }
336
+ if (message.members.indexOf(member) < message.members.length - 1) {
337
+ f.print();
338
+ }
339
+ }
340
+ f.print("};");
341
+ f.print();
342
+ }