@bufbuild/protoc-gen-es 1.7.2 → 1.9.0

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
@@ -118,7 +118,6 @@ Possible values:
118
118
  the default behavior.
119
119
  - `js_import_style=legacy_commonjs` generate CommonJS `require()` calls.
120
120
 
121
-
122
121
  ### `keep_empty_files=true`
123
122
 
124
123
  By default, [protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es)
@@ -127,3 +126,14 @@ omit empty files from the plugin output. This option disables pruning of
127
126
  empty files, to allow for smooth interoperation with Bazel and similar
128
127
  tooling that requires all output files to be declared ahead of time.
129
128
  Unless you use Bazel, it is very unlikely that you need this option.
129
+
130
+ ### `ts_nocheck=false`
131
+
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`.
135
+
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`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bufbuild/protoc-gen-es",
3
- "version": "1.7.2",
3
+ "version": "1.9.0",
4
4
  "description": "Protocol Buffers code generator for ECMAScript",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -16,15 +16,15 @@
16
16
  },
17
17
  "scripts": {
18
18
  "clean": "rm -rf ./dist/cjs/*",
19
- "build": "../../node_modules/typescript/bin/tsc --project tsconfig.json --module commonjs --outDir ./dist/cjs"
19
+ "build": "../../node_modules/typescript/bin/tsc --project tsconfig.json --outDir ./dist/cjs"
20
20
  },
21
21
  "preferUnplugged": true,
22
22
  "dependencies": {
23
- "@bufbuild/protobuf": "^1.7.2",
24
- "@bufbuild/protoplugin": "1.7.2"
23
+ "@bufbuild/protobuf": "^1.9.0",
24
+ "@bufbuild/protoplugin": "1.9.0"
25
25
  },
26
26
  "peerDependencies": {
27
- "@bufbuild/protobuf": "1.7.2"
27
+ "@bufbuild/protobuf": "1.9.0"
28
28
  },
29
29
  "peerDependenciesMeta": {
30
30
  "@bufbuild/protobuf": {
@@ -16,6 +16,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.generateDts = void 0;
17
17
  const ecmascript_1 = require("@bufbuild/protoplugin/ecmascript");
18
18
  const editions_js_1 = require("./editions.js");
19
+ const util_js_1 = require("./util.js");
19
20
  function generateDts(schema) {
20
21
  for (const file of schema.files) {
21
22
  const f = schema.generateFile(file.name + "_pb.d.ts");
@@ -36,7 +37,7 @@ exports.generateDts = generateDts;
36
37
  // prettier-ignore
37
38
  function generateEnum(schema, f, enumeration) {
38
39
  f.print(f.jsDoc(enumeration));
39
- f.print("export declare enum ", enumeration, " {");
40
+ f.print(f.exportDecl("declare enum", (0, ecmascript_1.localName)(enumeration)), " {");
40
41
  for (const value of enumeration.values) {
41
42
  if (enumeration.values.indexOf(value) > 0) {
42
43
  f.print();
@@ -51,8 +52,9 @@ function generateEnum(schema, f, enumeration) {
51
52
  function generateMessage(schema, f, message) {
52
53
  const protoN = (0, editions_js_1.getNonEditionRuntime)(schema, message.file);
53
54
  const { PartialMessage, FieldList, Message, PlainMessage, BinaryReadOptions, JsonReadOptions, JsonValue } = schema.runtime;
55
+ const m = (0, ecmascript_1.localName)(message);
54
56
  f.print(f.jsDoc(message));
55
- f.print("export declare class ", message, " extends ", Message, "<", message, "> {");
57
+ f.print(f.exportDecl("declare class", m), " extends ", Message, "<", m, "> {");
56
58
  for (const member of message.members) {
57
59
  switch (member.kind) {
58
60
  case "oneof":
@@ -64,7 +66,7 @@ function generateMessage(schema, f, message) {
64
66
  }
65
67
  f.print();
66
68
  }
67
- f.print(" constructor(data?: ", PartialMessage, "<", message, ">);");
69
+ f.print(" constructor(data?: ", PartialMessage, "<", m, ">);");
68
70
  f.print();
69
71
  generateWktMethods(schema, f, message);
70
72
  f.print(" static readonly runtime: typeof ", protoN, ";");
@@ -74,13 +76,13 @@ function generateMessage(schema, f, message) {
74
76
  //f.print(" static readonly options: { readonly [extensionName: string]: ", rt.JsonValue, " } = {};")
75
77
  f.print();
76
78
  generateWktStaticMethods(schema, f, message);
77
- f.print(" static fromBinary(bytes: Uint8Array, options?: Partial<", BinaryReadOptions, ">): ", message, ";");
79
+ f.print(" static fromBinary(bytes: Uint8Array, options?: Partial<", BinaryReadOptions, ">): ", m, ";");
78
80
  f.print();
79
- f.print(" static fromJson(jsonValue: ", JsonValue, ", options?: Partial<", JsonReadOptions, ">): ", message, ";");
81
+ f.print(" static fromJson(jsonValue: ", JsonValue, ", options?: Partial<", JsonReadOptions, ">): ", m, ";");
80
82
  f.print();
81
- f.print(" static fromJsonString(jsonString: string, options?: Partial<", JsonReadOptions, ">): ", message, ";");
83
+ f.print(" static fromJsonString(jsonString: string, options?: Partial<", JsonReadOptions, ">): ", m, ";");
82
84
  f.print();
83
- f.print(" static equals(a: ", message, " | ", PlainMessage, "<", message, "> | undefined, b: ", message, " | ", PlainMessage, "<", message, "> | undefined): boolean;");
85
+ f.print(" static equals(a: ", m, " | ", PlainMessage, "<", m, "> | undefined, b: ", m, " | ", PlainMessage, "<", m, "> | undefined): boolean;");
84
86
  f.print("}");
85
87
  f.print();
86
88
  for (const nestedEnum of message.nestedEnums) {
@@ -102,32 +104,31 @@ function generateOneof(schema, f, oneof) {
102
104
  f.print(` } | {`);
103
105
  }
104
106
  f.print(f.jsDoc(field, " "));
105
- const { typing } = (0, ecmascript_1.getFieldTyping)(field, f);
107
+ const { typing } = (0, util_js_1.getFieldTypeInfo)(field);
106
108
  f.print(` value: `, typing, `;`);
107
109
  f.print(` case: "`, (0, ecmascript_1.localName)(field), `";`);
108
110
  }
109
111
  f.print(` } | { case: undefined; value?: undefined };`);
110
112
  }
113
+ // prettier-ignore
111
114
  function generateField(schema, f, field) {
112
115
  f.print(f.jsDoc(field, " "));
113
116
  const e = [];
114
- e.push(" ", (0, ecmascript_1.localName)(field));
115
- const { defaultValue } = (0, ecmascript_1.getFieldIntrinsicDefaultValue)(field);
116
- const { typing, optional } = (0, ecmascript_1.getFieldTyping)(field, f);
117
- if (optional || defaultValue === undefined) {
118
- e.push("?: ", typing);
117
+ const { typing, optional } = (0, util_js_1.getFieldTypeInfo)(field);
118
+ if (!optional) {
119
+ e.push(" ", (0, ecmascript_1.localName)(field), ": ", typing, ";");
119
120
  }
120
121
  else {
121
- e.push(": ", typing);
122
+ e.push(" ", (0, ecmascript_1.localName)(field), "?: ", typing, ";");
122
123
  }
123
- e.push(";");
124
124
  f.print(e);
125
125
  }
126
126
  // prettier-ignore
127
127
  function generateExtension(schema, f, ext) {
128
- const { typing } = (0, ecmascript_1.getFieldTyping)(ext, f);
128
+ const { typing } = (0, util_js_1.getFieldTypeInfo)(ext);
129
+ const e = f.import(ext.extendee).toTypeOnly();
129
130
  f.print(f.jsDoc(ext));
130
- f.print(f.exportDecl("declare const", ext), ": ", schema.runtime.Extension, "<", ext.extendee, ", ", typing, ">;");
131
+ f.print(f.exportDecl("declare const", (0, ecmascript_1.localName)(ext)), ": ", schema.runtime.Extension, "<", e, ", ", typing, ">;");
131
132
  f.print();
132
133
  }
133
134
  // prettier-ignore
@@ -199,7 +200,7 @@ function generateWktStaticMethods(schema, f, message) {
199
200
  case "google.protobuf.BoolValue":
200
201
  case "google.protobuf.StringValue":
201
202
  case "google.protobuf.BytesValue": {
202
- const { typing } = (0, ecmascript_1.getFieldTyping)(ref.value, f);
203
+ const { typing } = (0, util_js_1.getFieldTypeInfo)(ref.value);
203
204
  f.print(" static readonly fieldWrapper: {");
204
205
  f.print(" wrapField(value: ", typing, "): ", message, ",");
205
206
  f.print(" unwrapField(value: ", message, "): ", typing, ",");
@@ -15,8 +15,10 @@
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.getFieldInfoLiteral = exports.generateFieldInfo = exports.generateJs = void 0;
17
17
  const protobuf_1 = require("@bufbuild/protobuf");
18
+ const protobuf_2 = require("@bufbuild/protobuf");
18
19
  const ecmascript_1 = require("@bufbuild/protoplugin/ecmascript");
19
20
  const editions_js_1 = require("./editions.js");
21
+ const util_js_1 = require("./util.js");
20
22
  function generateJs(schema) {
21
23
  for (const file of schema.files) {
22
24
  const f = schema.generateFile(file.name + "_pb.js");
@@ -38,18 +40,15 @@ exports.generateJs = generateJs;
38
40
  function generateEnum(schema, f, enumeration) {
39
41
  const protoN = (0, editions_js_1.getNonEditionRuntime)(schema, enumeration.file);
40
42
  f.print(f.jsDoc(enumeration));
41
- f.print(f.exportDecl("const", enumeration), " = ", protoN, ".makeEnum(");
43
+ f.print(f.exportDecl("const", enumeration), " = /*@__PURE__*/ ", protoN, ".makeEnum(");
42
44
  f.print(` "`, enumeration.typeName, `",`);
43
45
  f.print(` [`);
44
- if (enumeration.sharedPrefix === undefined) {
45
- for (const value of enumeration.values) {
46
+ for (const value of enumeration.values) {
47
+ if ((0, ecmascript_1.localName)(value) === value.name) {
46
48
  f.print(" {no: ", value.number, ", name: ", f.string(value.name), "},");
47
49
  }
48
- }
49
- else {
50
- for (const value of enumeration.values) {
51
- const localName = value.name.substring(enumeration.sharedPrefix.length);
52
- f.print(" {no: ", value.number, ", name: ", f.string(value.name), ", localName: ", f.string(localName), "},");
50
+ else {
51
+ f.print(" {no: ", value.number, ", name: ", f.string(value.name), ", localName: ", f.string((0, ecmascript_1.localName)(value)), "},");
53
52
  }
54
53
  }
55
54
  f.print(` ],`);
@@ -60,7 +59,7 @@ function generateEnum(schema, f, enumeration) {
60
59
  function generateMessage(schema, f, message) {
61
60
  const protoN = (0, editions_js_1.getNonEditionRuntime)(schema, message.file);
62
61
  f.print(f.jsDoc(message));
63
- f.print(f.exportDecl("const", message), " = ", protoN, ".makeMessageType(");
62
+ f.print(f.exportDecl("const", message), " = /*@__PURE__*/ ", protoN, ".makeMessageType(");
64
63
  f.print(` `, f.string(message.typeName), `,`);
65
64
  if (message.fields.length == 0) {
66
65
  f.print(" [],");
@@ -73,7 +72,7 @@ function generateMessage(schema, f, message) {
73
72
  f.print(" ],");
74
73
  }
75
74
  const needsLocalName = (0, ecmascript_1.localName)(message) !==
76
- (message.file.syntax == "proto3" ? protobuf_1.proto2 : protobuf_1.proto3)
75
+ (message.file.syntax == "proto3" ? protobuf_2.proto2 : protobuf_2.proto3)
77
76
  .makeMessageType(message.typeName, []).name;
78
77
  if (needsLocalName) {
79
78
  // local name is not inferrable from the type name, we need to provide it
@@ -111,16 +110,16 @@ function getFieldInfoLiteral(schema, field) {
111
110
  }
112
111
  switch (field.fieldKind) {
113
112
  case "scalar":
114
- e.push(`kind: "scalar", T: `, field.scalar, ` /* ScalarType.`, protobuf_1.ScalarType[field.scalar], ` */, `);
115
- if (field.longType != protobuf_1.LongType.BIGINT) {
116
- e.push(`L: `, field.longType, ` /* LongType.`, protobuf_1.LongType[field.longType], ` */, `);
113
+ e.push(`kind: "scalar", T: `, field.scalar, ` /* ScalarType.`, protobuf_2.ScalarType[field.scalar], ` */, `);
114
+ if (field.longType != protobuf_2.LongType.BIGINT) {
115
+ e.push(`L: `, field.longType, ` /* LongType.`, protobuf_2.LongType[field.longType], ` */, `);
117
116
  }
118
117
  break;
119
118
  case "map":
120
- e.push(`kind: "map", K: `, field.mapKey, ` /* ScalarType.`, protobuf_1.ScalarType[field.mapKey], ` */, `);
119
+ e.push(`kind: "map", K: `, field.mapKey, ` /* ScalarType.`, protobuf_2.ScalarType[field.mapKey], ` */, `);
121
120
  switch (field.mapValue.kind) {
122
121
  case "scalar":
123
- e.push(`V: {kind: "scalar", T: `, field.mapValue.scalar, ` /* ScalarType.`, protobuf_1.ScalarType[field.mapValue.scalar], ` */}, `);
122
+ e.push(`V: {kind: "scalar", T: `, field.mapValue.scalar, ` /* ScalarType.`, protobuf_2.ScalarType[field.mapValue.scalar], ` */}, `);
124
123
  break;
125
124
  case "message":
126
125
  e.push(`V: {kind: "message", T: `, field.mapValue.message, `}, `);
@@ -132,7 +131,7 @@ function getFieldInfoLiteral(schema, field) {
132
131
  break;
133
132
  case "message":
134
133
  e.push(`kind: "message", T: `, field.message, `, `);
135
- if (field.proto.type === protobuf_1.FieldDescriptorProto_Type.GROUP) {
134
+ if (field.proto.type === protobuf_2.FieldDescriptorProto_Type.GROUP) {
136
135
  e.push(`delimited: true, `);
137
136
  }
138
137
  break;
@@ -149,7 +148,10 @@ function getFieldInfoLiteral(schema, field) {
149
148
  if (field.optional) {
150
149
  e.push(`opt: true, `);
151
150
  }
152
- const defaultValue = (0, ecmascript_1.getFieldExplicitDefaultValue)(field, schema.runtime.protoInt64);
151
+ else if (field.proto.label === protobuf_1.FieldDescriptorProto_Label.REQUIRED) {
152
+ e.push(`req: true, `);
153
+ }
154
+ const defaultValue = (0, util_js_1.getFieldDefaultValueExpression)(field);
153
155
  if (defaultValue !== undefined) {
154
156
  e.push(`default: `, defaultValue, `, `);
155
157
  }
@@ -544,12 +546,12 @@ function generateWktMethods(schema, f, message) {
544
546
  case "google.protobuf.StringValue":
545
547
  case "google.protobuf.BytesValue":
546
548
  f.print(message, ".prototype.toJson = function toJson(options) {");
547
- f.print(" return proto3.json.writeScalar(", rtScalarType, ".", protobuf_1.ScalarType[ref.value.scalar], ", this.value, true);");
549
+ f.print(" return proto3.json.writeScalar(", rtScalarType, ".", protobuf_2.ScalarType[ref.value.scalar], ", this.value, true);");
548
550
  f.print("}");
549
551
  f.print();
550
552
  f.print(message, ".prototype.fromJson = function fromJson(json, options) {");
551
553
  f.print(" try {");
552
- f.print(" this.value = ", protoN, ".json.readScalar(", rtScalarType, ".", protobuf_1.ScalarType[ref.value.scalar], ", json);");
554
+ f.print(" this.value = ", protoN, ".json.readScalar(", rtScalarType, ".", protobuf_2.ScalarType[ref.value.scalar], ", json);");
553
555
  f.print(" } catch (e) {");
554
556
  f.print(" let m = `cannot decode message ", message.typeName, " from JSON\"`;");
555
557
  f.print(" if (e instanceof Error && e.message.length > 0) {");
@@ -18,6 +18,7 @@ const protobuf_1 = require("@bufbuild/protobuf");
18
18
  const ecmascript_1 = require("@bufbuild/protoplugin/ecmascript");
19
19
  const javascript_js_1 = require("./javascript.js");
20
20
  const editions_js_1 = require("./editions.js");
21
+ const util_js_1 = require("./util.js");
21
22
  function generateTs(schema) {
22
23
  for (const file of schema.files) {
23
24
  const f = schema.generateFile(file.name + "_pb.ts");
@@ -126,34 +127,39 @@ function generateOneof(schema, f, oneof) {
126
127
  f.print(` } | {`);
127
128
  }
128
129
  f.print(f.jsDoc(field, " "));
129
- const { typing } = (0, ecmascript_1.getFieldTyping)(field, f);
130
+ const { typing } = (0, util_js_1.getFieldTypeInfo)(field);
130
131
  f.print(` value: `, typing, `;`);
131
132
  f.print(` case: "`, (0, ecmascript_1.localName)(field), `";`);
132
133
  }
133
134
  f.print(` } | { case: undefined; value?: undefined } = { case: undefined };`);
134
135
  }
136
+ // prettier-ignore
135
137
  function generateField(schema, f, field) {
136
138
  f.print(f.jsDoc(field, " "));
137
139
  const e = [];
138
- e.push(" ", (0, ecmascript_1.localName)(field));
139
- const { defaultValue, typingInferrable } = (0, ecmascript_1.getFieldIntrinsicDefaultValue)(field);
140
- const { typing, optional } = (0, ecmascript_1.getFieldTyping)(field, f);
141
- if (optional || defaultValue === undefined) {
142
- e.push("?: ", typing);
143
- }
144
- else if (!typingInferrable) {
145
- e.push(": ", typing);
140
+ const { typing, optional, typingInferrableFromZeroValue } = (0, util_js_1.getFieldTypeInfo)(field);
141
+ if (optional) {
142
+ e.push(" ", (0, ecmascript_1.localName)(field), "?: ", typing, ";");
146
143
  }
147
- if (defaultValue !== undefined) {
148
- e.push(" = ", defaultValue);
144
+ else {
145
+ if (typingInferrableFromZeroValue) {
146
+ e.push(" ", (0, ecmascript_1.localName)(field));
147
+ }
148
+ else {
149
+ e.push(" ", (0, ecmascript_1.localName)(field), ": ", typing);
150
+ }
151
+ const zeroValue = (0, util_js_1.getFieldZeroValueExpression)(field);
152
+ if (zeroValue !== undefined) {
153
+ e.push(" = ", zeroValue);
154
+ }
155
+ e.push(";");
149
156
  }
150
- e.push(";");
151
157
  f.print(e);
152
158
  }
153
159
  // prettier-ignore
154
160
  function generateExtension(schema, f, ext) {
155
161
  const protoN = (0, editions_js_1.getNonEditionRuntime)(schema, ext.file);
156
- const { typing } = (0, ecmascript_1.getFieldTyping)(ext, f);
162
+ const { typing } = (0, util_js_1.getFieldTypeInfo)(ext);
157
163
  f.print(f.jsDoc(ext));
158
164
  f.print(f.exportDecl("const", ext), " = ", protoN, ".makeExtension<", ext.extendee, ", ", typing, ">(");
159
165
  f.print(" ", f.string(ext.typeName), ", ");
@@ -611,7 +617,7 @@ function generateWktStaticMethods(schema, f, message) {
611
617
  case "google.protobuf.BoolValue":
612
618
  case "google.protobuf.StringValue":
613
619
  case "google.protobuf.BytesValue": {
614
- const { typing } = (0, ecmascript_1.getFieldTyping)(ref.value, f);
620
+ const { typing } = (0, util_js_1.getFieldTypeInfo)(ref.value);
615
621
  f.print(" static readonly fieldWrapper = {");
616
622
  f.print(" wrapField(value: ", typing, "): ", message, " {");
617
623
  f.print(" return new ", message, "({value});");
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ // Copyright 2021-2024 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.getFieldZeroValueExpression = exports.getFieldDefaultValueExpression = exports.getFieldTypeInfo = void 0;
17
+ const protobuf_1 = require("@bufbuild/protobuf");
18
+ const ecmascript_1 = require("@bufbuild/protoplugin/ecmascript");
19
+ function getFieldTypeInfo(field) {
20
+ const typing = [];
21
+ let typingInferrableFromZeroValue;
22
+ let optional = false;
23
+ switch (field.fieldKind) {
24
+ case "scalar":
25
+ typing.push(scalarTypeScriptType(field.scalar, field.longType));
26
+ optional =
27
+ field.optional ||
28
+ field.proto.label === protobuf_1.FieldDescriptorProto_Label.REQUIRED;
29
+ typingInferrableFromZeroValue = true;
30
+ break;
31
+ case "message": {
32
+ const baseType = protobuf_1.codegenInfo.getUnwrappedFieldType(field);
33
+ if (baseType !== undefined) {
34
+ typing.push(scalarTypeScriptType(baseType, protobuf_1.LongType.BIGINT));
35
+ }
36
+ else {
37
+ typing.push({
38
+ kind: "es_ref_message",
39
+ type: field.message,
40
+ typeOnly: true,
41
+ });
42
+ }
43
+ optional = true;
44
+ typingInferrableFromZeroValue = true;
45
+ break;
46
+ }
47
+ case "enum":
48
+ typing.push({
49
+ kind: "es_ref_enum",
50
+ type: field.enum,
51
+ typeOnly: true,
52
+ });
53
+ optional =
54
+ field.optional ||
55
+ field.proto.label === protobuf_1.FieldDescriptorProto_Label.REQUIRED;
56
+ typingInferrableFromZeroValue = true;
57
+ break;
58
+ case "map": {
59
+ let keyType;
60
+ switch (field.mapKey) {
61
+ case protobuf_1.ScalarType.INT32:
62
+ case protobuf_1.ScalarType.FIXED32:
63
+ case protobuf_1.ScalarType.UINT32:
64
+ case protobuf_1.ScalarType.SFIXED32:
65
+ case protobuf_1.ScalarType.SINT32:
66
+ keyType = "number";
67
+ break;
68
+ default:
69
+ keyType = "string";
70
+ break;
71
+ }
72
+ let valueType;
73
+ switch (field.mapValue.kind) {
74
+ case "scalar":
75
+ valueType = scalarTypeScriptType(field.mapValue.scalar, protobuf_1.LongType.BIGINT);
76
+ break;
77
+ case "message":
78
+ valueType = {
79
+ kind: "es_ref_message",
80
+ type: field.mapValue.message,
81
+ typeOnly: true,
82
+ };
83
+ break;
84
+ case "enum":
85
+ valueType = {
86
+ kind: "es_ref_enum",
87
+ type: field.mapValue.enum,
88
+ typeOnly: true,
89
+ };
90
+ break;
91
+ }
92
+ typing.push("{ [key: ", keyType, "]: ", valueType, " }");
93
+ typingInferrableFromZeroValue = false;
94
+ optional = false;
95
+ break;
96
+ }
97
+ }
98
+ if (field.repeated) {
99
+ typing.push("[]");
100
+ optional = false;
101
+ typingInferrableFromZeroValue = false;
102
+ }
103
+ return { typing, optional, typingInferrableFromZeroValue };
104
+ }
105
+ exports.getFieldTypeInfo = getFieldTypeInfo;
106
+ /**
107
+ * Return a printable expression for the default value of a field.
108
+ * Only applicable for singular scalar and enum fields.
109
+ */
110
+ function getFieldDefaultValueExpression(field, enumAs = "enum_value_as_is") {
111
+ if (field.repeated) {
112
+ return undefined;
113
+ }
114
+ if (field.fieldKind !== "enum" && field.fieldKind !== "scalar") {
115
+ return undefined;
116
+ }
117
+ const defaultValue = field.getDefaultValue();
118
+ if (defaultValue === undefined) {
119
+ return undefined;
120
+ }
121
+ switch (field.fieldKind) {
122
+ case "enum": {
123
+ const enumValue = field.enum.values.find((value) => value.number === defaultValue);
124
+ if (enumValue === undefined) {
125
+ throw new Error(`invalid enum default value: ${String(defaultValue)} for ${enumValue}`);
126
+ }
127
+ return literalEnumValue(enumValue, enumAs);
128
+ }
129
+ case "scalar":
130
+ return literalScalarValue(defaultValue, field);
131
+ }
132
+ }
133
+ exports.getFieldDefaultValueExpression = getFieldDefaultValueExpression;
134
+ /**
135
+ * Return a printable expression for the zero value of a field.
136
+ *
137
+ * Returns either:
138
+ * - empty array literal for repeated fields
139
+ * - empty object literal for maps
140
+ * - undefined for message fields
141
+ * - an enums first value
142
+ * - scalar zero value
143
+ */
144
+ function getFieldZeroValueExpression(field, enumAs = "enum_value_as_is") {
145
+ if (field.repeated) {
146
+ return "[]";
147
+ }
148
+ switch (field.fieldKind) {
149
+ case "message":
150
+ return undefined;
151
+ case "map":
152
+ return "{}";
153
+ case "enum": {
154
+ // In proto3, the first enum value must be zero.
155
+ // In proto2, protobuf-go returns the first value as the default.
156
+ if (field.enum.values.length < 1) {
157
+ throw new Error("invalid enum: missing at least one value");
158
+ }
159
+ const zeroValue = field.enum.values[0];
160
+ return literalEnumValue(zeroValue, enumAs);
161
+ }
162
+ case "scalar": {
163
+ const defaultValue = protobuf_1.codegenInfo.scalarZeroValue(field.scalar, field.longType);
164
+ return literalScalarValue(defaultValue, field);
165
+ }
166
+ }
167
+ }
168
+ exports.getFieldZeroValueExpression = getFieldZeroValueExpression;
169
+ function literalScalarValue(value, field) {
170
+ switch (field.scalar) {
171
+ case protobuf_1.ScalarType.DOUBLE:
172
+ case protobuf_1.ScalarType.FLOAT:
173
+ case protobuf_1.ScalarType.INT32:
174
+ case protobuf_1.ScalarType.FIXED32:
175
+ case protobuf_1.ScalarType.UINT32:
176
+ case protobuf_1.ScalarType.SFIXED32:
177
+ case protobuf_1.ScalarType.SINT32:
178
+ if (typeof value != "number") {
179
+ throw new Error(`Unexpected value for ${protobuf_1.ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`);
180
+ }
181
+ return value;
182
+ case protobuf_1.ScalarType.BOOL:
183
+ if (typeof value != "boolean") {
184
+ throw new Error(`Unexpected value for ${protobuf_1.ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`);
185
+ }
186
+ return value;
187
+ case protobuf_1.ScalarType.STRING:
188
+ if (typeof value != "string") {
189
+ throw new Error(`Unexpected value for ${protobuf_1.ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`);
190
+ }
191
+ return { kind: "es_string", value };
192
+ case protobuf_1.ScalarType.BYTES:
193
+ if (!(value instanceof Uint8Array)) {
194
+ throw new Error(`Unexpected value for ${protobuf_1.ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`);
195
+ }
196
+ return value;
197
+ case protobuf_1.ScalarType.INT64:
198
+ case protobuf_1.ScalarType.SINT64:
199
+ case protobuf_1.ScalarType.SFIXED64:
200
+ case protobuf_1.ScalarType.UINT64:
201
+ case protobuf_1.ScalarType.FIXED64:
202
+ if (typeof value != "bigint" && typeof value != "string") {
203
+ throw new Error(`Unexpected value for ${protobuf_1.ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`);
204
+ }
205
+ return {
206
+ kind: "es_proto_int64",
207
+ type: field.scalar,
208
+ longType: field.longType,
209
+ value,
210
+ };
211
+ }
212
+ }
213
+ function literalEnumValue(value, enumAs) {
214
+ switch (enumAs) {
215
+ case "enum_value_as_is":
216
+ return [
217
+ { kind: "es_ref_enum", type: value.parent, typeOnly: false },
218
+ ".",
219
+ (0, ecmascript_1.localName)(value),
220
+ ];
221
+ case "enum_value_as_integer":
222
+ return [
223
+ value.number,
224
+ " /* ",
225
+ value.parent.typeName,
226
+ ".",
227
+ value.name,
228
+ " */",
229
+ ];
230
+ case "enum_value_as_cast_integer":
231
+ return [
232
+ value.number,
233
+ " as ",
234
+ { kind: "es_ref_enum", type: value.parent, typeOnly: true },
235
+ ".",
236
+ (0, ecmascript_1.localName)(value),
237
+ ];
238
+ }
239
+ }
240
+ function scalarTypeScriptType(type, longType) {
241
+ switch (type) {
242
+ case protobuf_1.ScalarType.STRING:
243
+ return "string";
244
+ case protobuf_1.ScalarType.BOOL:
245
+ return "boolean";
246
+ case protobuf_1.ScalarType.UINT64:
247
+ case protobuf_1.ScalarType.SFIXED64:
248
+ case protobuf_1.ScalarType.FIXED64:
249
+ case protobuf_1.ScalarType.SINT64:
250
+ case protobuf_1.ScalarType.INT64:
251
+ if (longType === protobuf_1.LongType.STRING) {
252
+ return "string";
253
+ }
254
+ return "bigint";
255
+ case protobuf_1.ScalarType.BYTES:
256
+ return "Uint8Array";
257
+ default:
258
+ return "number";
259
+ }
260
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bufbuild/protoc-gen-es",
3
- "version": "1.7.2",
3
+ "version": "1.9.0",
4
4
  "description": "Protocol Buffers code generator for ECMAScript",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -16,15 +16,15 @@
16
16
  },
17
17
  "scripts": {
18
18
  "clean": "rm -rf ./dist/cjs/*",
19
- "build": "../../node_modules/typescript/bin/tsc --project tsconfig.json --module commonjs --outDir ./dist/cjs"
19
+ "build": "../../node_modules/typescript/bin/tsc --project tsconfig.json --outDir ./dist/cjs"
20
20
  },
21
21
  "preferUnplugged": true,
22
22
  "dependencies": {
23
- "@bufbuild/protobuf": "^1.7.2",
24
- "@bufbuild/protoplugin": "1.7.2"
23
+ "@bufbuild/protobuf": "^1.9.0",
24
+ "@bufbuild/protoplugin": "1.9.0"
25
25
  },
26
26
  "peerDependencies": {
27
- "@bufbuild/protobuf": "1.7.2"
27
+ "@bufbuild/protobuf": "1.9.0"
28
28
  },
29
29
  "peerDependenciesMeta": {
30
30
  "@bufbuild/protobuf": {
@@ -24,13 +24,9 @@ import type {
24
24
  Printable,
25
25
  Schema,
26
26
  } from "@bufbuild/protoplugin/ecmascript";
27
- import {
28
- getFieldTyping,
29
- getFieldIntrinsicDefaultValue,
30
- localName,
31
- reifyWkt,
32
- } from "@bufbuild/protoplugin/ecmascript";
27
+ import { localName, reifyWkt } from "@bufbuild/protoplugin/ecmascript";
33
28
  import { getNonEditionRuntime } from "./editions.js";
29
+ import { getFieldTypeInfo } from "./util.js";
34
30
 
35
31
  export function generateDts(schema: Schema) {
36
32
  for (const file of schema.files) {
@@ -52,7 +48,7 @@ export function generateDts(schema: Schema) {
52
48
  // prettier-ignore
53
49
  function generateEnum(schema: Schema, f: GeneratedFile, enumeration: DescEnum) {
54
50
  f.print(f.jsDoc(enumeration));
55
- f.print("export declare enum ", enumeration, " {");
51
+ f.print(f.exportDecl("declare enum", localName(enumeration)), " {");
56
52
  for (const value of enumeration.values) {
57
53
  if (enumeration.values.indexOf(value) > 0) {
58
54
  f.print();
@@ -76,8 +72,9 @@ function generateMessage(schema: Schema, f: GeneratedFile, message: DescMessage)
76
72
  JsonReadOptions,
77
73
  JsonValue
78
74
  } = schema.runtime;
75
+ const m = localName(message);
79
76
  f.print(f.jsDoc(message));
80
- f.print("export declare class ", message, " extends ", Message, "<", message, "> {");
77
+ f.print(f.exportDecl("declare class", m), " extends ", Message, "<", m, "> {");
81
78
  for (const member of message.members) {
82
79
  switch (member.kind) {
83
80
  case "oneof":
@@ -89,7 +86,7 @@ function generateMessage(schema: Schema, f: GeneratedFile, message: DescMessage)
89
86
  }
90
87
  f.print();
91
88
  }
92
- f.print(" constructor(data?: ", PartialMessage, "<", message, ">);");
89
+ f.print(" constructor(data?: ", PartialMessage, "<", m, ">);");
93
90
  f.print();
94
91
  generateWktMethods(schema, f, message);
95
92
  f.print(" static readonly runtime: typeof ", protoN, ";");
@@ -99,13 +96,13 @@ function generateMessage(schema: Schema, f: GeneratedFile, message: DescMessage)
99
96
  //f.print(" static readonly options: { readonly [extensionName: string]: ", rt.JsonValue, " } = {};")
100
97
  f.print();
101
98
  generateWktStaticMethods(schema, f, message);
102
- f.print(" static fromBinary(bytes: Uint8Array, options?: Partial<", BinaryReadOptions, ">): ", message, ";")
99
+ f.print(" static fromBinary(bytes: Uint8Array, options?: Partial<", BinaryReadOptions, ">): ", m, ";")
103
100
  f.print()
104
- f.print(" static fromJson(jsonValue: ", JsonValue, ", options?: Partial<", JsonReadOptions, ">): ", message, ";")
101
+ f.print(" static fromJson(jsonValue: ", JsonValue, ", options?: Partial<", JsonReadOptions, ">): ", m, ";")
105
102
  f.print()
106
- f.print(" static fromJsonString(jsonString: string, options?: Partial<", JsonReadOptions, ">): ", message, ";")
103
+ f.print(" static fromJsonString(jsonString: string, options?: Partial<", JsonReadOptions, ">): ", m, ";")
107
104
  f.print()
108
- f.print(" static equals(a: ", message, " | ", PlainMessage, "<", message, "> | undefined, b: ", message, " | ", PlainMessage, "<", message, "> | undefined): boolean;")
105
+ f.print(" static equals(a: ", m, " | ", PlainMessage, "<", m, "> | undefined, b: ", m, " | ", PlainMessage, "<", m, "> | undefined): boolean;")
109
106
  f.print("}")
110
107
  f.print()
111
108
  for (const nestedEnum of message.nestedEnums) {
@@ -128,26 +125,24 @@ function generateOneof(schema: Schema, f: GeneratedFile, oneof: DescOneof) {
128
125
  f.print(` } | {`);
129
126
  }
130
127
  f.print(f.jsDoc(field, " "));
131
- const { typing } = getFieldTyping(field, f);
128
+ const { typing } = getFieldTypeInfo(field);
132
129
  f.print(` value: `, typing, `;`);
133
130
  f.print(` case: "`, localName(field), `";`);
134
131
  }
135
132
  f.print(` } | { case: undefined; value?: undefined };`);
136
133
  }
137
134
 
135
+ // prettier-ignore
138
136
  function generateField(schema: Schema, f: GeneratedFile, field: DescField) {
139
- f.print(f.jsDoc(field, " "));
140
- const e: Printable = [];
141
- e.push(" ", localName(field));
142
- const { defaultValue } = getFieldIntrinsicDefaultValue(field);
143
- const { typing, optional } = getFieldTyping(field, f);
144
- if (optional || defaultValue === undefined) {
145
- e.push("?: ", typing);
146
- } else {
147
- e.push(": ", typing);
148
- }
149
- e.push(";");
150
- f.print(e);
137
+ f.print(f.jsDoc(field, " "));
138
+ const e: Printable = [];
139
+ const { typing, optional } = getFieldTypeInfo(field);
140
+ if (!optional) {
141
+ e.push(" ", localName(field), ": ", typing, ";");
142
+ } else {
143
+ e.push(" ", localName(field), "?: ", typing, ";");
144
+ }
145
+ f.print(e);
151
146
  }
152
147
 
153
148
  // prettier-ignore
@@ -156,9 +151,10 @@ function generateExtension(
156
151
  f: GeneratedFile,
157
152
  ext: DescExtension,
158
153
  ) {
159
- const { typing } = getFieldTyping(ext, f);
154
+ const { typing } = getFieldTypeInfo(ext);
155
+ const e = f.import(ext.extendee).toTypeOnly();
160
156
  f.print(f.jsDoc(ext));
161
- f.print(f.exportDecl("declare const", ext), ": ", schema.runtime.Extension, "<", ext.extendee, ", ", typing, ">;");
157
+ f.print(f.exportDecl("declare const", localName(ext)), ": ", schema.runtime.Extension, "<", e, ", ", typing, ">;");
162
158
  f.print();
163
159
  }
164
160
 
@@ -236,7 +232,7 @@ function generateWktStaticMethods(schema: Schema, f: GeneratedFile, message: Des
236
232
  case "google.protobuf.BoolValue":
237
233
  case "google.protobuf.StringValue":
238
234
  case "google.protobuf.BytesValue": {
239
- const {typing} = getFieldTyping(ref.value, f);
235
+ const {typing} = getFieldTypeInfo(ref.value);
240
236
  f.print(" static readonly fieldWrapper: {")
241
237
  f.print(" wrapField(value: ", typing, "): ", message, ",")
242
238
  f.print(" unwrapField(value: ", message, "): ", typing, ",")
package/src/javascript.ts CHANGED
@@ -12,11 +12,12 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
 
15
- import type {
15
+ import {
16
16
  DescEnum,
17
17
  DescExtension,
18
18
  DescField,
19
19
  DescMessage,
20
+ FieldDescriptorProto_Label,
20
21
  } from "@bufbuild/protobuf";
21
22
  import {
22
23
  FieldDescriptorProto_Type,
@@ -30,12 +31,9 @@ import type {
30
31
  Printable,
31
32
  Schema,
32
33
  } from "@bufbuild/protoplugin/ecmascript";
33
- import {
34
- getFieldExplicitDefaultValue,
35
- localName,
36
- reifyWkt,
37
- } from "@bufbuild/protoplugin/ecmascript";
34
+ import { localName, reifyWkt } from "@bufbuild/protoplugin/ecmascript";
38
35
  import { getNonEditionRuntime } from "./editions.js";
36
+ import { getFieldDefaultValueExpression } from "./util.js";
39
37
 
40
38
  export function generateJs(schema: Schema) {
41
39
  for (const file of schema.files) {
@@ -58,17 +56,14 @@ export function generateJs(schema: Schema) {
58
56
  function generateEnum(schema: Schema, f: GeneratedFile, enumeration: DescEnum) {
59
57
  const protoN = getNonEditionRuntime(schema, enumeration.file);
60
58
  f.print(f.jsDoc(enumeration));
61
- f.print(f.exportDecl("const", enumeration), " = ", protoN, ".makeEnum(")
59
+ f.print(f.exportDecl("const", enumeration), " = /*@__PURE__*/ ", protoN, ".makeEnum(")
62
60
  f.print(` "`, enumeration.typeName, `",`)
63
61
  f.print(` [`)
64
- if (enumeration.sharedPrefix === undefined) {
65
- for (const value of enumeration.values) {
62
+ for (const value of enumeration.values) {
63
+ if (localName(value) === value.name) {
66
64
  f.print(" {no: ", value.number, ", name: ", f.string(value.name), "},")
67
- }
68
- } else {
69
- for (const value of enumeration.values) {
70
- const localName = value.name.substring(enumeration.sharedPrefix.length);
71
- f.print(" {no: ", value.number, ", name: ", f.string(value.name), ", localName: ", f.string(localName), "},")
65
+ } else {
66
+ f.print(" {no: ", value.number, ", name: ", f.string(value.name), ", localName: ", f.string(localName(value)), "},")
72
67
  }
73
68
  }
74
69
  f.print(` ],`)
@@ -80,7 +75,7 @@ function generateEnum(schema: Schema, f: GeneratedFile, enumeration: DescEnum) {
80
75
  function generateMessage(schema: Schema, f: GeneratedFile, message: DescMessage) {
81
76
  const protoN = getNonEditionRuntime(schema, message.file);
82
77
  f.print(f.jsDoc(message));
83
- f.print(f.exportDecl("const", message), " = ", protoN, ".makeMessageType(")
78
+ f.print(f.exportDecl("const", message), " = /*@__PURE__*/ ", protoN, ".makeMessageType(")
84
79
  f.print(` `, f.string(message.typeName), `,`)
85
80
  if (message.fields.length == 0) {
86
81
  f.print(" [],")
@@ -168,8 +163,10 @@ export function getFieldInfoLiteral(schema: Schema, field: DescField | DescExten
168
163
  }
169
164
  if (field.optional) {
170
165
  e.push(`opt: true, `);
166
+ } else if (field.proto.label === FieldDescriptorProto_Label.REQUIRED) {
167
+ e.push(`req: true, `);
171
168
  }
172
- const defaultValue = getFieldExplicitDefaultValue(field, schema.runtime.protoInt64);
169
+ const defaultValue = getFieldDefaultValueExpression(field);
173
170
  if (defaultValue !== undefined) {
174
171
  e.push(`default: `, defaultValue, `, `);
175
172
  }
package/src/typescript.ts CHANGED
@@ -25,14 +25,10 @@ import type {
25
25
  Printable,
26
26
  Schema,
27
27
  } from "@bufbuild/protoplugin/ecmascript";
28
- import {
29
- getFieldIntrinsicDefaultValue,
30
- getFieldTyping,
31
- localName,
32
- reifyWkt,
33
- } from "@bufbuild/protoplugin/ecmascript";
28
+ import { localName, reifyWkt } from "@bufbuild/protoplugin/ecmascript";
34
29
  import { generateFieldInfo, getFieldInfoLiteral } from "./javascript.js";
35
30
  import { getNonEditionRuntime } from "./editions.js";
31
+ import { getFieldTypeInfo, getFieldZeroValueExpression } from "./util.js";
36
32
 
37
33
  export function generateTs(schema: Schema) {
38
34
  for (const file of schema.files) {
@@ -152,29 +148,32 @@ function generateOneof(schema: Schema, f: GeneratedFile, oneof: DescOneof) {
152
148
  f.print(` } | {`);
153
149
  }
154
150
  f.print(f.jsDoc(field, " "));
155
- const { typing } = getFieldTyping(field, f);
151
+ const { typing } = getFieldTypeInfo(field);
156
152
  f.print(` value: `, typing, `;`);
157
153
  f.print(` case: "`, localName(field), `";`);
158
154
  }
159
155
  f.print(` } | { case: undefined; value?: undefined } = { case: undefined };`);
160
156
  }
161
157
 
158
+ // prettier-ignore
162
159
  function generateField(schema: Schema, f: GeneratedFile, field: DescField) {
163
160
  f.print(f.jsDoc(field, " "));
164
161
  const e: Printable = [];
165
- e.push(" ", localName(field));
166
- const { defaultValue, typingInferrable } =
167
- getFieldIntrinsicDefaultValue(field);
168
- const { typing, optional } = getFieldTyping(field, f);
169
- if (optional || defaultValue === undefined) {
170
- e.push("?: ", typing);
171
- } else if (!typingInferrable) {
172
- e.push(": ", typing);
173
- }
174
- if (defaultValue !== undefined) {
175
- e.push(" = ", defaultValue);
162
+ const { typing, optional, typingInferrableFromZeroValue } = getFieldTypeInfo(field);
163
+ if (optional) {
164
+ e.push(" ", localName(field), "?: ", typing, ";");
165
+ } else {
166
+ if (typingInferrableFromZeroValue) {
167
+ e.push(" ", localName(field));
168
+ } else {
169
+ e.push(" ", localName(field), ": ", typing);
170
+ }
171
+ const zeroValue = getFieldZeroValueExpression(field);
172
+ if (zeroValue !== undefined) {
173
+ e.push(" = ", zeroValue);
174
+ }
175
+ e.push(";");
176
176
  }
177
- e.push(";");
178
177
  f.print(e);
179
178
  }
180
179
 
@@ -185,7 +184,7 @@ function generateExtension(
185
184
  ext: DescExtension,
186
185
  ) {
187
186
  const protoN = getNonEditionRuntime(schema, ext.file);
188
- const { typing } = getFieldTyping(ext, f);
187
+ const { typing } = getFieldTypeInfo(ext);
189
188
  f.print(f.jsDoc(ext));
190
189
  f.print(f.exportDecl("const", ext), " = ", protoN, ".makeExtension<", ext.extendee, ", ", typing, ">(");
191
190
  f.print(" ", f.string(ext.typeName), ", ");
@@ -652,7 +651,7 @@ function generateWktStaticMethods(schema: Schema, f: GeneratedFile, message: Des
652
651
  case "google.protobuf.BoolValue":
653
652
  case "google.protobuf.StringValue":
654
653
  case "google.protobuf.BytesValue": {
655
- const {typing} = getFieldTyping(ref.value, f);
654
+ const {typing} = getFieldTypeInfo(ref.value);
656
655
  f.print(" static readonly fieldWrapper = {")
657
656
  f.print(" wrapField(value: ", typing, "): ", message, " {")
658
657
  f.print(" return new ", message, "({value});")
package/src/util.ts ADDED
@@ -0,0 +1,315 @@
1
+ // Copyright 2021-2024 Buf Technologies, Inc.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://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,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import {
16
+ codegenInfo,
17
+ DescEnumValue,
18
+ DescExtension,
19
+ DescField,
20
+ FieldDescriptorProto_Label,
21
+ LongType,
22
+ ScalarType,
23
+ ScalarValue,
24
+ } from "@bufbuild/protobuf";
25
+ import type { Printable } from "@bufbuild/protoplugin/ecmascript";
26
+ import { localName } from "@bufbuild/protoplugin/ecmascript";
27
+
28
+ export function getFieldTypeInfo(field: DescField | DescExtension): {
29
+ typing: Printable;
30
+ optional: boolean;
31
+ typingInferrableFromZeroValue: boolean;
32
+ } {
33
+ const typing: Printable = [];
34
+ let typingInferrableFromZeroValue: boolean;
35
+ let optional = false;
36
+ switch (field.fieldKind) {
37
+ case "scalar":
38
+ typing.push(scalarTypeScriptType(field.scalar, field.longType));
39
+ optional =
40
+ field.optional ||
41
+ field.proto.label === FieldDescriptorProto_Label.REQUIRED;
42
+ typingInferrableFromZeroValue = true;
43
+ break;
44
+ case "message": {
45
+ const baseType = codegenInfo.getUnwrappedFieldType(field);
46
+ if (baseType !== undefined) {
47
+ typing.push(scalarTypeScriptType(baseType, LongType.BIGINT));
48
+ } else {
49
+ typing.push({
50
+ kind: "es_ref_message",
51
+ type: field.message,
52
+ typeOnly: true,
53
+ });
54
+ }
55
+ optional = true;
56
+ typingInferrableFromZeroValue = true;
57
+ break;
58
+ }
59
+ case "enum":
60
+ typing.push({
61
+ kind: "es_ref_enum",
62
+ type: field.enum,
63
+ typeOnly: true,
64
+ });
65
+ optional =
66
+ field.optional ||
67
+ field.proto.label === FieldDescriptorProto_Label.REQUIRED;
68
+ typingInferrableFromZeroValue = true;
69
+ break;
70
+ case "map": {
71
+ let keyType: string;
72
+ switch (field.mapKey) {
73
+ case ScalarType.INT32:
74
+ case ScalarType.FIXED32:
75
+ case ScalarType.UINT32:
76
+ case ScalarType.SFIXED32:
77
+ case ScalarType.SINT32:
78
+ keyType = "number";
79
+ break;
80
+ default:
81
+ keyType = "string";
82
+ break;
83
+ }
84
+ let valueType: Printable;
85
+ switch (field.mapValue.kind) {
86
+ case "scalar":
87
+ valueType = scalarTypeScriptType(
88
+ field.mapValue.scalar,
89
+ LongType.BIGINT,
90
+ );
91
+ break;
92
+ case "message":
93
+ valueType = {
94
+ kind: "es_ref_message",
95
+ type: field.mapValue.message,
96
+ typeOnly: true,
97
+ };
98
+ break;
99
+ case "enum":
100
+ valueType = {
101
+ kind: "es_ref_enum",
102
+ type: field.mapValue.enum,
103
+ typeOnly: true,
104
+ };
105
+ break;
106
+ }
107
+ typing.push("{ [key: ", keyType, "]: ", valueType, " }");
108
+ typingInferrableFromZeroValue = false;
109
+ optional = false;
110
+ break;
111
+ }
112
+ }
113
+ if (field.repeated) {
114
+ typing.push("[]");
115
+ optional = false;
116
+ typingInferrableFromZeroValue = false;
117
+ }
118
+ return { typing, optional, typingInferrableFromZeroValue };
119
+ }
120
+
121
+ /**
122
+ * Return a printable expression for the default value of a field.
123
+ * Only applicable for singular scalar and enum fields.
124
+ */
125
+ export function getFieldDefaultValueExpression(
126
+ field: DescField | DescExtension,
127
+ enumAs:
128
+ | "enum_value_as_is"
129
+ | "enum_value_as_integer"
130
+ | "enum_value_as_cast_integer" = "enum_value_as_is",
131
+ ): Printable | undefined {
132
+ if (field.repeated) {
133
+ return undefined;
134
+ }
135
+ if (field.fieldKind !== "enum" && field.fieldKind !== "scalar") {
136
+ return undefined;
137
+ }
138
+ const defaultValue = field.getDefaultValue();
139
+ if (defaultValue === undefined) {
140
+ return undefined;
141
+ }
142
+ switch (field.fieldKind) {
143
+ case "enum": {
144
+ const enumValue = field.enum.values.find(
145
+ (value) => value.number === defaultValue,
146
+ );
147
+ if (enumValue === undefined) {
148
+ throw new Error(
149
+ `invalid enum default value: ${String(defaultValue)} for ${enumValue}`,
150
+ );
151
+ }
152
+ return literalEnumValue(enumValue, enumAs);
153
+ }
154
+ case "scalar":
155
+ return literalScalarValue(defaultValue, field);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Return a printable expression for the zero value of a field.
161
+ *
162
+ * Returns either:
163
+ * - empty array literal for repeated fields
164
+ * - empty object literal for maps
165
+ * - undefined for message fields
166
+ * - an enums first value
167
+ * - scalar zero value
168
+ */
169
+ export function getFieldZeroValueExpression(
170
+ field: DescField | DescExtension,
171
+ enumAs:
172
+ | "enum_value_as_is"
173
+ | "enum_value_as_integer"
174
+ | "enum_value_as_cast_integer" = "enum_value_as_is",
175
+ ): Printable | undefined {
176
+ if (field.repeated) {
177
+ return "[]";
178
+ }
179
+ switch (field.fieldKind) {
180
+ case "message":
181
+ return undefined;
182
+ case "map":
183
+ return "{}";
184
+ case "enum": {
185
+ // In proto3, the first enum value must be zero.
186
+ // In proto2, protobuf-go returns the first value as the default.
187
+ if (field.enum.values.length < 1) {
188
+ throw new Error("invalid enum: missing at least one value");
189
+ }
190
+ const zeroValue = field.enum.values[0];
191
+ return literalEnumValue(zeroValue, enumAs);
192
+ }
193
+ case "scalar": {
194
+ const defaultValue = codegenInfo.scalarZeroValue(
195
+ field.scalar,
196
+ field.longType,
197
+ );
198
+ return literalScalarValue(defaultValue, field);
199
+ }
200
+ }
201
+ }
202
+
203
+ function literalScalarValue(
204
+ value: ScalarValue,
205
+ field: (DescField | DescExtension) & { fieldKind: "scalar" },
206
+ ): Printable {
207
+ switch (field.scalar) {
208
+ case ScalarType.DOUBLE:
209
+ case ScalarType.FLOAT:
210
+ case ScalarType.INT32:
211
+ case ScalarType.FIXED32:
212
+ case ScalarType.UINT32:
213
+ case ScalarType.SFIXED32:
214
+ case ScalarType.SINT32:
215
+ if (typeof value != "number") {
216
+ throw new Error(
217
+ `Unexpected value for ${ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`,
218
+ );
219
+ }
220
+ return value;
221
+ case ScalarType.BOOL:
222
+ if (typeof value != "boolean") {
223
+ throw new Error(
224
+ `Unexpected value for ${ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`,
225
+ );
226
+ }
227
+ return value;
228
+ case ScalarType.STRING:
229
+ if (typeof value != "string") {
230
+ throw new Error(
231
+ `Unexpected value for ${ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`,
232
+ );
233
+ }
234
+ return { kind: "es_string", value };
235
+ case ScalarType.BYTES:
236
+ if (!(value instanceof Uint8Array)) {
237
+ throw new Error(
238
+ `Unexpected value for ${ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`,
239
+ );
240
+ }
241
+ return value;
242
+ case ScalarType.INT64:
243
+ case ScalarType.SINT64:
244
+ case ScalarType.SFIXED64:
245
+ case ScalarType.UINT64:
246
+ case ScalarType.FIXED64:
247
+ if (typeof value != "bigint" && typeof value != "string") {
248
+ throw new Error(
249
+ `Unexpected value for ${ScalarType[field.scalar]} ${field.toString()}: ${String(value)}`,
250
+ );
251
+ }
252
+ return {
253
+ kind: "es_proto_int64",
254
+ type: field.scalar,
255
+ longType: field.longType,
256
+ value,
257
+ };
258
+ }
259
+ }
260
+
261
+ function literalEnumValue(
262
+ value: DescEnumValue,
263
+ enumAs:
264
+ | "enum_value_as_is"
265
+ | "enum_value_as_integer"
266
+ | "enum_value_as_cast_integer",
267
+ ): Printable {
268
+ switch (enumAs) {
269
+ case "enum_value_as_is":
270
+ return [
271
+ { kind: "es_ref_enum", type: value.parent, typeOnly: false },
272
+ ".",
273
+ localName(value),
274
+ ];
275
+ case "enum_value_as_integer":
276
+ return [
277
+ value.number,
278
+ " /* ",
279
+ value.parent.typeName,
280
+ ".",
281
+ value.name,
282
+ " */",
283
+ ];
284
+ case "enum_value_as_cast_integer":
285
+ return [
286
+ value.number,
287
+ " as ",
288
+ { kind: "es_ref_enum", type: value.parent, typeOnly: true },
289
+ ".",
290
+ localName(value),
291
+ ];
292
+ }
293
+ }
294
+
295
+ function scalarTypeScriptType(type: ScalarType, longType: LongType): Printable {
296
+ switch (type) {
297
+ case ScalarType.STRING:
298
+ return "string";
299
+ case ScalarType.BOOL:
300
+ return "boolean";
301
+ case ScalarType.UINT64:
302
+ case ScalarType.SFIXED64:
303
+ case ScalarType.FIXED64:
304
+ case ScalarType.SINT64:
305
+ case ScalarType.INT64:
306
+ if (longType === LongType.STRING) {
307
+ return "string";
308
+ }
309
+ return "bigint";
310
+ case ScalarType.BYTES:
311
+ return "Uint8Array";
312
+ default:
313
+ return "number";
314
+ }
315
+ }
package/tsconfig.json CHANGED
@@ -2,6 +2,11 @@
2
2
  "files": ["src/protoc-gen-es-plugin.ts"],
3
3
  "extends": "../../tsconfig.base.json",
4
4
  "compilerOptions": {
5
+ // We import the plugin's version number from package.json
5
6
  "resolveJsonModule": true,
6
- },
7
+ // This package is CommonJS
8
+ "verbatimModuleSyntax": false,
9
+ "module": "CommonJS",
10
+ "moduleResolution": "Node10"
11
+ }
7
12
  }