@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 +11 -1
- package/dist/cjs/package.json +5 -5
- package/dist/cjs/src/declaration.js +19 -18
- package/dist/cjs/src/javascript.js +21 -19
- package/dist/cjs/src/typescript.js +20 -14
- package/dist/cjs/src/util.js +260 -0
- package/package.json +5 -5
- package/src/declaration.ts +25 -29
- package/src/javascript.ts +13 -16
- package/src/typescript.ts +20 -21
- package/src/util.ts +315 -0
- package/tsconfig.json +6 -1
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`.
|
package/dist/cjs/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bufbuild/protoc-gen-es",
|
|
3
|
-
"version": "1.
|
|
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 --
|
|
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.
|
|
24
|
-
"@bufbuild/protoplugin": "1.
|
|
23
|
+
"@bufbuild/protobuf": "^1.9.0",
|
|
24
|
+
"@bufbuild/protoplugin": "1.9.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@bufbuild/protobuf": "1.
|
|
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("
|
|
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("
|
|
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, "<",
|
|
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, ">): ",
|
|
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, ">): ",
|
|
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, ">): ",
|
|
83
|
+
f.print(" static fromJsonString(jsonString: string, options?: Partial<", JsonReadOptions, ">): ", m, ";");
|
|
82
84
|
f.print();
|
|
83
|
-
f.print(" static equals(a: ",
|
|
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,
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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("
|
|
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,
|
|
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, "<",
|
|
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,
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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" ?
|
|
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.`,
|
|
115
|
-
if (field.longType !=
|
|
116
|
-
e.push(`L: `, field.longType, ` /* 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.`,
|
|
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.`,
|
|
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 ===
|
|
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
|
-
|
|
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, ".",
|
|
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, ".",
|
|
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,
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
148
|
-
|
|
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,
|
|
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,
|
|
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.
|
|
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 --
|
|
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.
|
|
24
|
-
"@bufbuild/protoplugin": "1.
|
|
23
|
+
"@bufbuild/protobuf": "^1.9.0",
|
|
24
|
+
"@bufbuild/protoplugin": "1.9.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@bufbuild/protobuf": "1.
|
|
27
|
+
"@bufbuild/protobuf": "1.9.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependenciesMeta": {
|
|
30
30
|
"@bufbuild/protobuf": {
|
package/src/declaration.ts
CHANGED
|
@@ -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("
|
|
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("
|
|
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, "<",
|
|
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, ">): ",
|
|
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, ">): ",
|
|
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, ">): ",
|
|
103
|
+
f.print(" static fromJsonString(jsonString: string, options?: Partial<", JsonReadOptions, ">): ", m, ";")
|
|
107
104
|
f.print()
|
|
108
|
-
f.print(" static equals(a: ",
|
|
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 } =
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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 } =
|
|
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, "<",
|
|
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} =
|
|
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
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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 =
|
|
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 } =
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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 } =
|
|
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} =
|
|
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
|
}
|