@aptre/protobuf-es-lite 0.2.15 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +10 -15
  3. package/dist/binary.d.ts +13 -10
  4. package/dist/binary.js +24 -23
  5. package/dist/codegen-info.d.ts +8 -0
  6. package/dist/codegen-info.js +12 -4
  7. package/dist/descriptor-set.d.ts +8 -9
  8. package/dist/field-wrapper.d.ts +2 -2
  9. package/dist/google/protobuf/any.pb.d.ts +55 -2
  10. package/dist/google/protobuf/any.pb.js +85 -4
  11. package/dist/google/protobuf/api.pb.js +34 -13
  12. package/dist/google/protobuf/descriptor.pb.js +1045 -161
  13. package/dist/google/protobuf/duration.pb.d.ts +7 -2
  14. package/dist/google/protobuf/duration.pb.js +54 -4
  15. package/dist/google/protobuf/empty.pb.js +1 -0
  16. package/dist/google/protobuf/source_context.pb.js +3 -2
  17. package/dist/google/protobuf/struct.pb.d.ts +17 -4
  18. package/dist/google/protobuf/struct.pb.js +162 -12
  19. package/dist/google/protobuf/timestamp.pb.d.ts +8 -2
  20. package/dist/google/protobuf/timestamp.pb.js +68 -4
  21. package/dist/google/protobuf/type.pb.js +62 -21
  22. package/dist/google/protobuf/wrappers.pb.d.ts +47 -10
  23. package/dist/google/protobuf/wrappers.pb.js +280 -19
  24. package/dist/index.d.ts +5 -1
  25. package/dist/index.js +4 -1
  26. package/dist/json.d.ts +30 -4
  27. package/dist/json.js +17 -16
  28. package/dist/message.d.ts +5 -12
  29. package/dist/message.js +75 -77
  30. package/dist/protoc-gen-es-lite/typescript.d.ts +2 -2
  31. package/dist/protoc-gen-es-lite/typescript.js +348 -26
  32. package/dist/protoplugin/ecmascript/reify-wkt.d.ts +1 -5
  33. package/dist/protoplugin/ecmascript/reify-wkt.js +0 -10
  34. package/dist/type-registry.d.ts +43 -0
  35. package/dist/type-registry.js +14 -0
  36. package/example/example.pb.ts +56 -32
  37. package/package.json +3 -1
package/dist/message.d.ts CHANGED
@@ -83,7 +83,7 @@ export interface MessageType<T extends Message<T> = AnyMessage> {
83
83
  */
84
84
  toJsonString(a: Message<T>, options?: Partial<JsonWriteStringOptions>): string;
85
85
  }
86
- export interface MessageTypeParams<T extends Message<T>> extends Pick<MessageType<T>, "typeName" | "fieldWrapper"> {
86
+ export type MessageTypeParams<T extends Message<T>> = Pick<MessageType<T>, "fieldWrapper" | "typeName"> & {
87
87
  /**
88
88
  * Fields contains the list of message fields.
89
89
  */
@@ -98,23 +98,16 @@ export interface MessageTypeParams<T extends Message<T>> extends Pick<MessageTyp
98
98
  * delimited fields (proto3) or with (proto2 legacy).
99
99
  */
100
100
  delimitedMessageEncoding?: boolean;
101
- /**
102
- * Serialize the message to a JSON value, a JavaScript value that can be
103
- * passed to JSON.stringify().
104
- *
105
- * When passed as MessageTypeParams this will override the default serializer behavior.
106
- */
107
- toJson?: MessageType<T>["toJson"];
108
- }
109
- export declare function compareMessages<T extends Message<T>>(fields: FieldList, a: T | undefined | null, b: T | undefined | null): boolean;
110
- export declare function cloneMessage<T extends Message<T>>(message: T, fields: FieldList): T;
101
+ };
111
102
  /**
112
103
  * createMessageType creates a new message type.
113
104
  *
114
105
  * The argument `packedByDefault` specifies whether fields that do not specify
115
106
  * `packed` should be packed (proto3) or unpacked (proto2).
116
107
  */
117
- export declare function createMessageType<T extends Message<T>>(params: MessageTypeParams<T>): MessageType<T>;
108
+ export declare function createMessageType<T extends Message<T>, E extends Record<string, Function> = {}>(params: MessageTypeParams<T>, exts?: E): MessageType<T> & E;
109
+ export declare function compareMessages<T extends Message<T>>(fields: FieldList, a: T | undefined | null, b: T | undefined | null): boolean;
110
+ export declare function cloneMessage<T extends Message<T>>(message: T, fields: FieldList): T;
118
111
  /**
119
112
  * createMessage recursively builds a message filled with zero values based on the given FieldList.
120
113
  */
package/dist/message.js CHANGED
@@ -14,8 +14,81 @@
14
14
  import { newFieldList, resolveMessageType, } from "./field.js";
15
15
  import { applyPartialMessage } from "./partial.js";
16
16
  import { ScalarType, scalarEquals } from "./scalar.js";
17
- import { makeReadOptions as makeBinaryReadOptions, readMessage as readBinaryMessage, makeWriteOptions as makeBinaryWriteOptions, writeMessage as writeBinaryMessage, } from "./binary.js";
18
- import { makeReadOptions as makeJsonReadOptions, readMessage as readJsonMessage, makeWriteOptions as makeJsonWriteOptions, writeMessage as writeJsonMessage, } from "./json.js";
17
+ import { binaryReadMessage, binaryWriteMessage, binaryMakeReadOptions, binaryMakeWriteOptions, } from "./binary.js";
18
+ import { jsonReadMessage, jsonWriteMessage, jsonMakeReadOptions, jsonMakeWriteOptions, } from "./json.js";
19
+ /**
20
+ * createMessageType creates a new message type.
21
+ *
22
+ * The argument `packedByDefault` specifies whether fields that do not specify
23
+ * `packed` should be packed (proto3) or unpacked (proto2).
24
+ */
25
+ export function createMessageType(params, exts) {
26
+ const { fields: fieldsSource, typeName, packedByDefault, delimitedMessageEncoding, fieldWrapper, } = params;
27
+ const fields = newFieldList(fieldsSource, packedByDefault);
28
+ const mt = {
29
+ typeName,
30
+ fields,
31
+ fieldWrapper,
32
+ create(partial) {
33
+ const message = createMessage(fields);
34
+ applyPartialMessage(partial, message, fields);
35
+ return message;
36
+ },
37
+ equals(a, b) {
38
+ return compareMessages(fields, a, b);
39
+ },
40
+ clone(a) {
41
+ if (a == null) {
42
+ return a;
43
+ }
44
+ return cloneMessage(a, fields);
45
+ },
46
+ fromBinary(bytes, options) {
47
+ const message = {};
48
+ if (bytes && bytes.length) {
49
+ const opt = binaryMakeReadOptions(options);
50
+ binaryReadMessage(message, fields, opt.readerFactory(bytes), bytes.byteLength, opt, delimitedMessageEncoding);
51
+ }
52
+ return message;
53
+ },
54
+ fromJson(jsonValue, options) {
55
+ const message = {};
56
+ if (jsonValue != null) {
57
+ const opts = jsonMakeReadOptions(options);
58
+ jsonReadMessage(fields, typeName, jsonValue, opts, message);
59
+ }
60
+ return message;
61
+ },
62
+ fromJsonString(jsonString, options) {
63
+ let json = null;
64
+ if (jsonString) {
65
+ try {
66
+ json = JSON.parse(jsonString);
67
+ }
68
+ catch (e) {
69
+ throw new Error(`cannot decode ${typeName} from JSON: ${e instanceof Error ? e.message : String(e)}`);
70
+ }
71
+ }
72
+ return mt.fromJson(json, options);
73
+ },
74
+ toBinary(a, options) {
75
+ const opt = binaryMakeWriteOptions(options);
76
+ const writer = opt.writerFactory();
77
+ binaryWriteMessage(a, fields, writer, opt);
78
+ return writer.finish();
79
+ },
80
+ toJson(a, options) {
81
+ const opt = jsonMakeWriteOptions(options);
82
+ return jsonWriteMessage(a, fields, opt);
83
+ },
84
+ toJsonString(a, options) {
85
+ const value = mt.toJson(a, options);
86
+ return JSON.stringify(value, null, options?.prettySpaces ?? 0);
87
+ },
88
+ ...(exts ?? {}),
89
+ };
90
+ return mt;
91
+ }
19
92
  // compareMessages compares two messages for equality.
20
93
  export function compareMessages(fields, a, b) {
21
94
  if (a == null && b == null) {
@@ -144,81 +217,6 @@ export function cloneMessage(message, fields) {
144
217
  }
145
218
  return clone;
146
219
  }
147
- /**
148
- * createMessageType creates a new message type.
149
- *
150
- * The argument `packedByDefault` specifies whether fields that do not specify
151
- * `packed` should be packed (proto3) or unpacked (proto2).
152
- */
153
- export function createMessageType(params) {
154
- const { fields: fieldsSource, typeName, packedByDefault, delimitedMessageEncoding, fieldWrapper, } = params;
155
- const fields = newFieldList(fieldsSource, packedByDefault);
156
- const mt = {
157
- typeName,
158
- fields,
159
- fieldWrapper,
160
- create(partial) {
161
- const message = createMessage(fields);
162
- applyPartialMessage(partial, message, fields);
163
- return message;
164
- },
165
- equals(a, b) {
166
- return compareMessages(fields, a, b);
167
- },
168
- clone(a) {
169
- if (a == null) {
170
- return a;
171
- }
172
- return cloneMessage(a, fields);
173
- },
174
- fromBinary(bytes, options) {
175
- const message = {};
176
- if (bytes && bytes.length) {
177
- const opt = makeBinaryReadOptions(options);
178
- readBinaryMessage(message, fields, opt.readerFactory(bytes), bytes.byteLength, opt, delimitedMessageEncoding);
179
- }
180
- return message;
181
- },
182
- fromJson(jsonValue, options) {
183
- const message = {};
184
- if (jsonValue != null) {
185
- const opts = makeJsonReadOptions(options);
186
- readJsonMessage(fields, typeName, jsonValue, opts, message);
187
- }
188
- return message;
189
- },
190
- fromJsonString(jsonString, options) {
191
- let json = null;
192
- if (jsonString) {
193
- try {
194
- json = JSON.parse(jsonString);
195
- }
196
- catch (e) {
197
- throw new Error(`cannot decode ${typeName} from JSON: ${e instanceof Error ? e.message : String(e)}`);
198
- }
199
- }
200
- return this.fromJson(json, options);
201
- },
202
- toBinary(a, options) {
203
- const opt = makeBinaryWriteOptions(options);
204
- const writer = opt.writerFactory();
205
- writeBinaryMessage(a, fields, writer, opt);
206
- return writer.finish();
207
- },
208
- toJson(a, options) {
209
- const opt = makeJsonWriteOptions(options);
210
- return writeJsonMessage(a, fields, opt);
211
- },
212
- toJsonString(a, options) {
213
- const value = this.toJson(a, options);
214
- return JSON.stringify(value, null, options?.prettySpaces ?? 0);
215
- },
216
- };
217
- if (params.toJson) {
218
- mt.toJson = params.toJson;
219
- }
220
- return mt;
221
- }
222
220
  /**
223
221
  * createMessage recursively builds a message filled with zero values based on the given FieldList.
224
222
  */
@@ -3,6 +3,6 @@ import { DescEnum, DescExtension, DescField, DescFile, DescMessage } from "../de
3
3
  export declare function generateTs(schema: Schema): void;
4
4
  export declare function checkSupportedSyntax(file: DescFile): void;
5
5
  export declare function makeImportPath(file: DescFile): string;
6
- export declare function generateFieldInfo(f: GeneratedFile, field: DescField | DescExtension): void;
6
+ export declare function generateFieldInfo(f: GeneratedFile, schema: Schema, field: DescField | DescExtension): void;
7
7
  export declare const createTypeImport: (desc: DescMessage | DescEnum | DescExtension) => ImportSymbol;
8
- export declare function getFieldInfoLiteral(field: DescField | DescExtension): Printable;
8
+ export declare function getFieldInfoLiteral(schema: Schema, field: DescField | DescExtension): Printable;
@@ -12,7 +12,7 @@
12
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
- import { createImportSymbol } from "../protoplugin/ecmascript/index.js";
15
+ import { createImportSymbol, reifyWkt, } from "../protoplugin/ecmascript/index.js";
16
16
  import { getFieldDefaultValueExpression, getFieldTypeInfo } from "../util.js";
17
17
  import { localName } from "../names.js";
18
18
  import { LongType, ScalarType } from "../scalar.js";
@@ -107,20 +107,9 @@ export function checkSupportedSyntax(file) {
107
107
  }
108
108
  }
109
109
  function generateMessage(schema, f, message) {
110
- // check if we support this runtime
111
110
  checkSupportedSyntax(message.file);
111
+ const { MessageType: rtMessageType, createMessageType, PartialFieldInfo, } = schema.runtime;
112
112
  f.print(f.jsDoc(message));
113
- /*
114
- f.print(
115
- f.exportDecl("interface", message),
116
- " extends ",
117
- schema.runtime.Message,
118
- "<",
119
- message,
120
- ">",
121
- " {",
122
- );
123
- */
124
113
  f.print(f.exportDecl("type", message), " = ", schema.runtime.Message, "<{");
125
114
  for (const field of message.fields) {
126
115
  generateField(f, field);
@@ -131,17 +120,35 @@ function generateMessage(schema, f, message) {
131
120
  f.print();
132
121
  f.print("}>;");
133
122
  f.print();
134
- f.print(f.exportDecl("const", message), ": ", schema.runtime.MessageType, "<", message, "> = ", schema.runtime.createMessageType, "(");
135
- f.print(" {");
123
+ // If we need to extend the message type, do that here.
124
+ const reWkt = reifyWkt(message);
125
+ if (reWkt != null) {
126
+ f.print("// ", message, "_Wkt contains the well-known-type overrides for ", message, ".");
127
+ f.print("const ", message, "_Wkt = {");
128
+ generateWktMethods(schema, f, message, reWkt);
129
+ f.print("};");
130
+ f.print();
131
+ f.print("// ", message, " contains the message type declaration for ", message, ".");
132
+ f.print(f.exportDecl("const", message), `: `, rtMessageType, `<`, message, `> & typeof `, message, `_Wkt = `, createMessageType, "<", message, ", typeof ", message, "_Wkt>({");
133
+ }
134
+ else {
135
+ f.print("// ", message, " contains the message type declaration for ", message, ".");
136
+ f.print(f.exportDecl("const", message), `: `, rtMessageType, `<`, message, `> = `, createMessageType, "({");
137
+ }
136
138
  f.print(" typeName: ", f.string(message.typeName), ",");
137
139
  f.print(" fields: [");
138
140
  for (const field of message.fields) {
139
- generateFieldInfo(f, field);
141
+ generateFieldInfo(f, schema, field);
140
142
  }
141
- f.print(" ] as readonly ", schema.runtime.PartialFieldInfo, "[],");
143
+ f.print(" ] as readonly ", PartialFieldInfo, "[],");
142
144
  f.print(" packedByDefault: ", message.file.proto.syntax === "proto3", ",");
143
- f.print(" },");
144
- f.print(");");
145
+ if (reWkt == null) {
146
+ f.print("});");
147
+ }
148
+ else {
149
+ generateWktFieldWrapper(f, message, reWkt);
150
+ f.print("}, ", message, "_Wkt);");
151
+ }
145
152
  f.print();
146
153
  }
147
154
  function generateField(f, field) {
@@ -175,8 +182,8 @@ function generateOneof(f, oneof) {
175
182
  export function makeImportPath(file) {
176
183
  return "./" + file.name + ".pb.js";
177
184
  }
178
- export function generateFieldInfo(f, field) {
179
- f.print(" ", getFieldInfoLiteral(field), ",");
185
+ export function generateFieldInfo(f, schema, field) {
186
+ f.print(" ", getFieldInfoLiteral(schema, field), ",");
180
187
  }
181
188
  export const createTypeImport = (desc) => {
182
189
  var name = localName(desc);
@@ -186,7 +193,8 @@ export const createTypeImport = (desc) => {
186
193
  const from = makeImportPath(desc.file);
187
194
  return createImportSymbol(name, from);
188
195
  };
189
- export function getFieldInfoLiteral(field) {
196
+ export function getFieldInfoLiteral(schema, field) {
197
+ const { ScalarType: rtScalarType, LongType: rtLongType } = schema.runtime;
190
198
  const e = [];
191
199
  e.push("{ no: ", field.number, `, `);
192
200
  if (field.kind == "field") {
@@ -197,16 +205,16 @@ export function getFieldInfoLiteral(field) {
197
205
  }
198
206
  switch (field.fieldKind) {
199
207
  case "scalar":
200
- e.push(`kind: "scalar", T: `, field.scalar, ` /* ScalarType.`, ScalarType[field.scalar], ` */, `);
208
+ e.push(`kind: "scalar", T: `, rtScalarType, `.`, ScalarType[field.scalar], `, `);
201
209
  if (field.longType != LongType.BIGINT) {
202
- e.push(`L: `, field.longType, ` /* LongType.`, LongType[field.longType], ` */, `);
210
+ e.push(`L: `, rtLongType, `.`, LongType[field.longType], `, `);
203
211
  }
204
212
  break;
205
213
  case "map":
206
- e.push(`kind: "map", K: `, field.mapKey, ` /* ScalarType.`, ScalarType[field.mapKey], ` */, `);
214
+ e.push(`kind: "map", K: `, rtScalarType, `.`, ScalarType[field.mapKey], `, `);
207
215
  switch (field.mapValue.kind) {
208
216
  case "scalar":
209
- e.push(`V: {kind: "scalar", T: `, field.mapValue.scalar, ` /* ScalarType.`, ScalarType[field.mapValue.scalar], ` */}, `);
217
+ e.push(`V: {kind: "scalar", T: `, rtScalarType, `.`, ScalarType[field.mapValue.scalar], `}, `);
210
218
  break;
211
219
  case "message":
212
220
  e.push(`V: {kind: "message", T: () => `, field.mapValue.message, `}, `);
@@ -252,3 +260,317 @@ export function getFieldInfoLiteral(field) {
252
260
  e.push(" }");
253
261
  return e;
254
262
  }
263
+ function generateWktMethods(schema, f, message, ref) {
264
+ const { JsonValue, JsonReadOptions, JsonWriteOptions, JsonObject, jsonReadScalar, jsonWriteScalar, jsonDebugValue, Message, MessageType, IMessageTypeRegistry, ScalarType: rtScalarType, LongType: rtLongType,
265
+ // ScalarValue: rtScalarValue,
266
+ protoInt64, applyPartialMessage, } = schema.runtime;
267
+ switch (ref.typeName) {
268
+ case "google.protobuf.Any":
269
+ f.print(" toJson(msg: ", message, ", options?: Partial<", JsonWriteOptions, ">): ", JsonValue, " {");
270
+ f.print(" const typeName = msg?.", localName(ref.typeUrl), ";");
271
+ f.print(` if (!typeName) {`);
272
+ f.print(" return {};");
273
+ f.print(" }");
274
+ f.print(" const messageType = options?.typeRegistry?.findMessage(typeName);");
275
+ f.print(" if (!messageType) {");
276
+ f.print(" throw new Error(`cannot encode message ", message.typeName, ' to JSON: "${typeName}" is not in the type registry`);');
277
+ f.print(" }");
278
+ f.print(" const message = messageType.fromBinary(msg.", localName(ref.value), ");");
279
+ f.print(" let json = messageType.toJson(message, options);");
280
+ f.print(` if (typeName.startsWith("google.protobuf.") || (json === null || Array.isArray(json) || typeof json !== "object")) {`);
281
+ f.print(" json = {value: json};");
282
+ f.print(" }");
283
+ f.print(` json["@type"] = typeName;`);
284
+ f.print(" return json;");
285
+ f.print(" },");
286
+ f.print();
287
+ f.print(" fromJson(json: ", JsonValue, ", options?: Partial<", JsonReadOptions, ">) {");
288
+ f.print(` if (json === null || Array.isArray(json) || typeof json != "object") {`);
289
+ f.print(" throw new Error(`cannot decode message ", message.typeName, ' from JSON: expected object but got ${json === null ? "null" : Array.isArray(json) ? "array" : typeof json}`);');
290
+ f.print(" }");
291
+ f.print(` if (Object.keys(json).length == 0) {`);
292
+ f.print(` return {} as `, message, `;`);
293
+ f.print(` }`);
294
+ f.print(` const typeUrl = json["@type"];`);
295
+ f.print(` if (typeof typeUrl != "string" || typeUrl == "") {`);
296
+ f.print(" throw new Error(`cannot decode message ", message.typeName, ' from JSON: "@type" is empty`);');
297
+ f.print(" }");
298
+ f.print(" const typeName = typeUrl, messageType = options?.typeRegistry?.findMessage(typeName);");
299
+ f.print(" if (!messageType) {");
300
+ f.print(" throw new Error(`cannot decode message ", message.typeName, " from JSON: ${typeUrl} is not in the type registry`);");
301
+ f.print(" }");
302
+ f.print(" let message;");
303
+ f.print(` if (typeName.startsWith("google.protobuf.") && Object.prototype.hasOwnProperty.call(json, "value")) {`);
304
+ f.print(` message = messageType.fromJson(json["value"], options);`);
305
+ f.print(" } else {");
306
+ f.print(" const copy = Object.assign({}, json);");
307
+ f.print(` delete copy["@type"];`);
308
+ f.print(" message = messageType.fromJson(copy, options);");
309
+ f.print(" }");
310
+ f.print(" const out = {} as ", message, ";");
311
+ f.print(" ", message, ".packFrom(out, message, messageType);");
312
+ f.print(" return out;");
313
+ f.print(" },");
314
+ f.print();
315
+ f.print(" packFrom<T extends ", Message, "<T>>(out: ", message, ", message: ", Message, "<T>, messageType: ", MessageType, "<T>): void {");
316
+ f.print(" out.", localName(ref.value), " = messageType.toBinary(message);");
317
+ f.print(" out.", localName(ref.typeUrl), " = messageType.typeName;");
318
+ f.print(" },");
319
+ f.print();
320
+ f.print(" unpackTo<T extends ", Message, "<T>>(msg: ", message, ", target: ", Message, "<T>, targetMessageType: ", MessageType, "<T>): boolean {");
321
+ f.print(" if (!", message, ".is(msg, targetMessageType)) {");
322
+ f.print(" return false;");
323
+ f.print(" }");
324
+ f.print(" const partial = targetMessageType.fromBinary(msg.", localName(ref.value), ");");
325
+ f.print(" ", applyPartialMessage, "(partial, target, targetMessageType.fields);");
326
+ f.print(" return true;");
327
+ f.print(" },");
328
+ f.print();
329
+ f.print(" unpack<T extends Message<T>>(msg: ", message, ", registry: ", IMessageTypeRegistry, "): {message: ", Message, "<T>, messageType: ", MessageType, "<T>} | undefined {");
330
+ f.print(" const typeUrl = msg.", localName(ref.typeUrl)), ";";
331
+ f.print(" const messageType = !!typeUrl && registry.findMessage<T>(typeUrl);");
332
+ f.print(" return messageType ? {message: messageType.fromBinary(msg.", localName(ref.value), "), messageType} : undefined;");
333
+ f.print(" },");
334
+ f.print();
335
+ f.print(" is(msg: ", message, ", msgType: ", MessageType, " | string): boolean {");
336
+ f.print(" const name = msg.", localName(ref.typeUrl)), ";";
337
+ f.print(" return !!name && (typeof msgType === 'string' ? name === msgType : name === msgType.typeName);");
338
+ f.print(" },");
339
+ break;
340
+ case "google.protobuf.Timestamp":
341
+ f.print(" fromJson(json: ", JsonValue, "): ", message, " {");
342
+ f.print(` if (typeof json !== "string") {`);
343
+ f.print(" throw new Error(`cannot decode ", message.typeName, "(json)}`);");
344
+ f.print(" }");
345
+ f.print(` const matches = json.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:Z|\\.([0-9]{3,9})Z|([+-][0-9][0-9]:[0-9][0-9]))$/);`);
346
+ f.print(" if (!matches) {");
347
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON: invalid RFC 3339 string`);");
348
+ f.print(" }");
349
+ f.print(` const ms = Date.parse(matches[1] + "-" + matches[2] + "-" + matches[3] + "T" + matches[4] + ":" + matches[5] + ":" + matches[6] + (matches[8] ? matches[8] : "Z"));`);
350
+ f.print(" if (Number.isNaN(ms)) {");
351
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON: invalid RFC 3339 string`);");
352
+ f.print(" }");
353
+ f.print(` if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z")) {`);
354
+ f.print(" throw new Error(`cannot decode message ", message.typeName, " from JSON: must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive`);");
355
+ f.print(" }");
356
+ f.print(" return {");
357
+ if (ref.seconds.longType === LongType.STRING) {
358
+ f.print(" ", localName(ref.seconds), ": ", protoInt64, ".parse(ms / 1000).toString(),");
359
+ }
360
+ else {
361
+ f.print(" ", localName(ref.seconds), ": ", protoInt64, ".parse(ms / 1000),");
362
+ }
363
+ f.print(" ", localName(ref.nanos), ": !matches[7] ? 0 : ", `(parseInt("1" + matches[7] + "0".repeat(9 - matches[7].length)) - 1000000000),`);
364
+ f.print(" }");
365
+ f.print(" },");
366
+ f.print(" toJson(msg: ", message, "): JsonValue {");
367
+ f.print(" const ms = Number(msg.", localName(ref.seconds), ") * 1000;");
368
+ f.print(` if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z")) {`);
369
+ f.print(" throw new Error(`cannot encode ", message.typeName, " to JSON: must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive`);");
370
+ f.print(" }");
371
+ f.print(" if (msg.", localName(ref.nanos), " != null && msg.", localName(ref.nanos), " < 0) {");
372
+ f.print(" throw new Error(`cannot encode ", message.typeName, " to JSON: nanos must not be negative`);");
373
+ f.print(" }");
374
+ f.print(` let z = "Z";`);
375
+ f.print(" if (msg.", localName(ref.nanos), " != null && msg.", localName(ref.nanos), " > 0) {");
376
+ f.print(" const nanosStr = (msg.", localName(ref.nanos), " + 1000000000).toString().substring(1);");
377
+ f.print(` if (nanosStr.substring(3) === "000000") {`);
378
+ f.print(` z = "." + nanosStr.substring(0, 3) + "Z";`);
379
+ f.print(` } else if (nanosStr.substring(6) === "000") {`);
380
+ f.print(` z = "." + nanosStr.substring(0, 6) + "Z";`);
381
+ f.print(" } else {");
382
+ f.print(` z = "." + nanosStr + "Z";`);
383
+ f.print(" }");
384
+ f.print(" }");
385
+ f.print(` return new Date(ms).toISOString().replace(".000Z", z);`);
386
+ f.print(" },");
387
+ f.print(" toDate(msg: ", message, "): Date {");
388
+ f.print(" return new Date(Number(msg.", localName(ref.seconds), " ?? 0) * 1000 + Math.ceil((msg.", localName(ref.nanos), " ?? 0) / 1000000));");
389
+ f.print(" },");
390
+ break;
391
+ case "google.protobuf.Duration":
392
+ f.print(" fromJson(json: ", JsonValue, " | null | undefined, _options?: Partial<", JsonReadOptions, ">): ", message, " {");
393
+ f.print(` if (typeof json !== "string") {`);
394
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON: ${", jsonDebugValue, "(json)}`);");
395
+ f.print(" }");
396
+ f.print(` const match = json.match(/^(-?[0-9]+)(?:\\.([0-9]+))?s/);`);
397
+ f.print(" if (match === null) {");
398
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON: ${", jsonDebugValue, "(json)}`);");
399
+ f.print(" }");
400
+ f.print(" const longSeconds = Number(match[1]);");
401
+ f.print(" if (longSeconds > 315576000000 || longSeconds < -315576000000) {");
402
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON: ${", jsonDebugValue, "(json)}`);");
403
+ f.print(" }");
404
+ f.print(" const msg = {} as ", message, ";");
405
+ if (ref.seconds.longType === LongType.STRING) {
406
+ f.print(" msg.", localName(ref.seconds), " = ", protoInt64, ".parse(longSeconds).toString();");
407
+ }
408
+ else {
409
+ f.print(" msg.", localName(ref.seconds), " = ", protoInt64, ".parse(longSeconds);");
410
+ }
411
+ f.print(` if (typeof match[2] == "string") {`);
412
+ f.print(` const nanosStr = match[2] + "0".repeat(9 - match[2].length);`);
413
+ f.print(" msg.", localName(ref.nanos), " = parseInt(nanosStr);");
414
+ f.print(" if (longSeconds < 0 || Object.is(longSeconds, -0)) {");
415
+ f.print(" msg.", localName(ref.nanos), " = -msg.", localName(ref.nanos), ";");
416
+ f.print(" }");
417
+ f.print(" }");
418
+ f.print(" return msg;");
419
+ f.print(" },");
420
+ f.print(" toJson(msg: ", message, "): JsonValue {");
421
+ f.print(" const secs = Number(msg.", localName(ref.seconds), " ?? 0);");
422
+ f.print(" const nanos = Number(msg.", localName(ref.nanos), " ?? 0);");
423
+ f.print(" if (secs > 315576000000 || secs < -315576000000) {");
424
+ f.print(" throw new Error(`cannot encode ", message.typeName, " to JSON: value out of range`);");
425
+ f.print(" }");
426
+ f.print(" let text = secs.toString();");
427
+ f.print(" if (nanos !== 0) {");
428
+ f.print(" let nanosStr = Math.abs(nanos).toString();");
429
+ f.print(` nanosStr = "0".repeat(9 - nanosStr.length) + nanosStr;`);
430
+ f.print(` if (nanosStr.substring(3) === "000000") {`);
431
+ f.print(" nanosStr = nanosStr.substring(0, 3);");
432
+ f.print(` } else if (nanosStr.substring(6) === "000") {`);
433
+ f.print(" nanosStr = nanosStr.substring(0, 6);");
434
+ f.print(` }`);
435
+ f.print(` text += "." + nanosStr;`);
436
+ f.print(" if (nanos < 0 && secs === 0) {");
437
+ f.print(` text = "-" + text;`);
438
+ f.print(` }`);
439
+ f.print(" }");
440
+ f.print(` return text + "s";`);
441
+ f.print(" },");
442
+ break;
443
+ case "google.protobuf.Struct":
444
+ f.print(" toJson(msg: ", message, ", options?: Partial<", JsonWriteOptions, ">): ", JsonValue, " {");
445
+ f.print(" const json: ", JsonObject, " = {}");
446
+ f.print(" if (!msg.", localName(ref.fields), ") { return json; }");
447
+ f.print(" for (const [k, v] of Object.entries(msg.", localName(ref.fields), ")) {");
448
+ f.print(" json[k] = v != null ? ", ref.fields.mapValue.message, ".toJson(v, options) : null;");
449
+ f.print(" }");
450
+ f.print(" return json;");
451
+ f.print(" },");
452
+ f.print(" fromJson(json: ", JsonValue, " | null | undefined, _options?: Partial<", JsonReadOptions, ">): ", message, " {");
453
+ f.print(` if (typeof json != "object" || json == null || Array.isArray(json)) {`);
454
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON ${", jsonDebugValue, "(json)}`);");
455
+ f.print(" }");
456
+ f.print(" const fields = {} as { [key: string]: Value };");
457
+ f.print(" for (const [k, v] of Object.entries(json)) {");
458
+ f.print(" fields[k] = ", ref.fields.mapValue.message ?? "", ".fromJson(v);");
459
+ f.print(" }");
460
+ f.print(" return {", localName(ref.fields), ": fields} as ", message, ";");
461
+ f.print(" },");
462
+ break;
463
+ case "google.protobuf.Value":
464
+ f.print(" toJson(msg: ", message, ", options?: Partial<", JsonWriteOptions, ">): ", JsonValue, " {");
465
+ f.print(" switch (msg.", localName(ref.kind), "?.case) {");
466
+ f.print(` case "`, localName(ref.nullValue), `":`);
467
+ f.print(" return null;");
468
+ f.print(` case "`, localName(ref.numberValue), `":`);
469
+ f.print(` if (!Number.isFinite(msg.`, localName(ref.kind), `.value)) {`);
470
+ f.print(` throw new Error("google.protobuf.Value cannot be NaN or Infinity");`);
471
+ f.print(` }`);
472
+ f.print(` return msg.`, localName(ref.kind), `.value;`);
473
+ f.print(` case "`, localName(ref.boolValue), `":`);
474
+ f.print(` return msg.`, localName(ref.kind), `.value;`);
475
+ f.print(` case "`, localName(ref.stringValue), `":`);
476
+ f.print(" return msg.", localName(ref.kind), ".value;");
477
+ f.print(` case "`, localName(ref.structValue), `":`);
478
+ f.print(` return `, ref.structValue.message, `.toJson(msg.`, localName(ref.kind), `.value, {...options, emitDefaultValues: true});`);
479
+ f.print(` case "`, localName(ref.listValue), `":`);
480
+ f.print(` return `, ref.listValue.message, `.toJson(msg.`, localName(ref.kind), `.value, {...options, emitDefaultValues: true});`);
481
+ f.print(` case null:`);
482
+ f.print(` case undefined:`);
483
+ f.print(` default:`);
484
+ f.print(` return null;`);
485
+ f.print(" }");
486
+ f.print(" },");
487
+ f.print(" fromJson(json: ", JsonValue, " | null | undefined, _options?: Partial<", JsonReadOptions, ">): ", message, " {");
488
+ f.print(" const msg = {} as ", message, ";");
489
+ f.print(" switch (typeof json) {");
490
+ f.print(` case "number":`);
491
+ f.print(` msg.kind = { case: "`, localName(ref.numberValue), `", value: json };`);
492
+ f.print(" break;");
493
+ f.print(` case "string":`);
494
+ f.print(` msg.kind = { case: "`, localName(ref.stringValue), `", value: json };`);
495
+ f.print(" break;");
496
+ f.print(` case "boolean":`);
497
+ f.print(` msg.kind = { case: "`, localName(ref.boolValue), `", value: json };`);
498
+ f.print(" break;");
499
+ f.print(` case "object":`);
500
+ f.print(" if (json == null) {");
501
+ f.print(` msg.kind = { case: "`, localName(ref.nullValue), `", value: `, ref.nullValue.enum, `.`, localName(ref.nullValue.enum.values[0]), ` };`);
502
+ f.print(" } else if (Array.isArray(json)) {");
503
+ f.print(` msg.kind = { case: "`, localName(ref.listValue), `", value: `, ref.listValue.message, `.fromJson(json) };`);
504
+ f.print(" } else {");
505
+ f.print(` msg.kind = { case: "`, localName(ref.structValue), `", value: `, ref.structValue.message, `.fromJson(json) };`);
506
+ f.print(" }");
507
+ f.print(" break;");
508
+ f.print(" default:");
509
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON ${", jsonDebugValue, "(json)}`);");
510
+ f.print(" }");
511
+ f.print(" return msg;");
512
+ f.print(" },");
513
+ break;
514
+ case "google.protobuf.ListValue":
515
+ f.print(` toJson(msg: `, message, `, options?: Partial<`, JsonWriteOptions, `>): `, JsonValue, ` {`);
516
+ f.print(` return msg.`, localName(ref.values), `?.map(v => `, ref.values.message, `.toJson(v, options)) ?? [];`);
517
+ f.print(` },`);
518
+ f.print(` fromJson(json: `, JsonValue, ` | null | undefined, options?: Partial<`, JsonReadOptions, `>): `, message, ` {`);
519
+ f.print(` if (json == null) { return {}; }`);
520
+ f.print(` if (!Array.isArray(json)) {`);
521
+ f.print(" throw new Error(`cannot decode ", message.typeName, " from JSON ${", jsonDebugValue, "(json)}`);");
522
+ f.print(` }`);
523
+ f.print(` const values: `, ref.values.message, `[] = json.map(v => `, ref.values.message, `.fromJson(v, options));`);
524
+ f.print(` return {`, localName(ref.values), `: values} as `, message, `;`);
525
+ f.print(` },`);
526
+ break;
527
+ case "google.protobuf.DoubleValue":
528
+ case "google.protobuf.FloatValue":
529
+ case "google.protobuf.Int64Value":
530
+ case "google.protobuf.UInt64Value":
531
+ case "google.protobuf.Int32Value":
532
+ case "google.protobuf.UInt32Value":
533
+ case "google.protobuf.BoolValue":
534
+ case "google.protobuf.StringValue":
535
+ case "google.protobuf.BytesValue":
536
+ f.print(" toJson(msg: ", message, ", _options?: Partial<", JsonWriteOptions, ">): ", JsonValue, " {");
537
+ f.print(" return ", jsonWriteScalar, "(", rtScalarType, ".", ScalarType[ref.value.scalar], ", msg.value)!;");
538
+ f.print(" },");
539
+ f.print(" fromJson(json: ", JsonValue, " | null | undefined, _options?: Partial<", JsonReadOptions, ">): ", message, " {");
540
+ f.print(" try {");
541
+ f.print(" return {", localName(ref.value), ": ", jsonReadScalar, "(", rtScalarType, ".", ScalarType[ref.value.scalar], ", json, ", rtLongType, ".", LongType[ref.value.longType], ")} as ", message, ";");
542
+ f.print(" } catch (e) {");
543
+ f.print(" let m = `cannot decode message ", message.typeName, ' from JSON"`;');
544
+ f.print(" if (e instanceof Error && e.message.length > 0) {");
545
+ f.print(" m += `: ${e.message}`");
546
+ f.print(" }");
547
+ f.print(" throw new Error(m);");
548
+ f.print(" }");
549
+ f.print(" },");
550
+ break;
551
+ }
552
+ }
553
+ function generateWktFieldWrapper(f, message, ref) {
554
+ switch (ref?.typeName) {
555
+ case "google.protobuf.DoubleValue":
556
+ case "google.protobuf.FloatValue":
557
+ case "google.protobuf.Int64Value":
558
+ case "google.protobuf.UInt64Value":
559
+ case "google.protobuf.Int32Value":
560
+ case "google.protobuf.UInt32Value":
561
+ case "google.protobuf.BoolValue":
562
+ case "google.protobuf.StringValue":
563
+ case "google.protobuf.BytesValue": {
564
+ const { typing } = getFieldTypeInfo(ref.value);
565
+ f.print(" fieldWrapper: {");
566
+ f.print(" wrapField(value: ", typing, " | null | undefined): ", message, " {");
567
+ f.print(" return ", message, ".create({ value: value ?? undefined });");
568
+ f.print(" },");
569
+ f.print(" unwrapField(msg: ", message, "): ", typing, " | null | undefined {");
570
+ f.print(" return msg.", localName(ref.value), ";");
571
+ f.print(" }");
572
+ f.print(" } as const,");
573
+ break;
574
+ }
575
+ }
576
+ }