@bufbuild/protobuf 1.7.2 → 1.8.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.
Files changed (119) hide show
  1. package/dist/cjs/codegen-info.d.ts +6 -1
  2. package/dist/cjs/codegen-info.js +4 -3
  3. package/dist/cjs/create-descriptor-set.js +45 -33
  4. package/dist/cjs/create-registry-from-desc.js +60 -110
  5. package/dist/cjs/descriptor-set.d.ts +13 -9
  6. package/dist/cjs/field.d.ts +25 -51
  7. package/dist/cjs/field.js +0 -66
  8. package/dist/cjs/google/protobuf/compiler/plugin_pb.d.ts +18 -0
  9. package/dist/cjs/google/protobuf/compiler/plugin_pb.js +2 -0
  10. package/dist/cjs/google/protobuf/descriptor_pb.d.ts +33 -33
  11. package/dist/cjs/google/protobuf/descriptor_pb.js +23 -10
  12. package/dist/cjs/google/protobuf/struct_pb.js +1 -1
  13. package/dist/cjs/google/protobuf/type_pb.js +1 -1
  14. package/dist/cjs/google/protobuf/wrappers_pb.js +19 -19
  15. package/dist/cjs/index.d.ts +3 -1
  16. package/dist/cjs/index.js +6 -4
  17. package/dist/cjs/is-message.d.ts +22 -0
  18. package/dist/cjs/is-message.js +52 -0
  19. package/dist/cjs/json-format.d.ts +1 -2
  20. package/dist/cjs/private/binary-format.d.ts +7 -0
  21. package/dist/cjs/private/{binary-format-common.js → binary-format.js} +150 -53
  22. package/dist/cjs/private/extensions.js +1 -1
  23. package/dist/cjs/private/feature-set.js +1 -1
  24. package/dist/cjs/private/field-normalize.d.ts +9 -0
  25. package/dist/cjs/private/field-normalize.js +69 -0
  26. package/dist/cjs/private/field-wrapper.d.ts +1 -1
  27. package/dist/cjs/private/field-wrapper.js +12 -12
  28. package/dist/cjs/private/field.d.ts +1 -0
  29. package/dist/cjs/private/field.js +1 -0
  30. package/dist/cjs/private/json-format.d.ts +2 -0
  31. package/dist/cjs/private/{json-format-common.js → json-format.js} +261 -170
  32. package/dist/cjs/private/proto-runtime.d.ts +1 -1
  33. package/dist/cjs/private/proto-runtime.js +8 -4
  34. package/dist/cjs/private/reflect.d.ts +9 -0
  35. package/dist/cjs/private/reflect.js +79 -0
  36. package/dist/cjs/private/reify-wkt.js +11 -11
  37. package/dist/cjs/private/scalars.d.ts +9 -18
  38. package/dist/cjs/private/scalars.js +36 -80
  39. package/dist/cjs/private/text-format.d.ts +1 -1
  40. package/dist/cjs/private/text-format.js +17 -17
  41. package/dist/cjs/private/util-common.js +17 -14
  42. package/dist/cjs/proto-delimited.js +2 -3
  43. package/dist/cjs/proto2.js +29 -68
  44. package/dist/cjs/proto3.js +30 -77
  45. package/dist/cjs/scalar.d.ts +53 -0
  46. package/dist/cjs/scalar.js +81 -0
  47. package/dist/cjs/to-plain-message.js +3 -4
  48. package/dist/esm/codegen-info.d.ts +6 -1
  49. package/dist/esm/codegen-info.js +6 -5
  50. package/dist/esm/create-descriptor-set.js +22 -10
  51. package/dist/esm/create-registry-from-desc.js +62 -111
  52. package/dist/esm/descriptor-set.d.ts +13 -9
  53. package/dist/esm/descriptor-set.js +1 -1
  54. package/dist/esm/field.d.ts +25 -51
  55. package/dist/esm/field.js +1 -65
  56. package/dist/esm/google/protobuf/compiler/plugin_pb.d.ts +18 -0
  57. package/dist/esm/google/protobuf/compiler/plugin_pb.js +2 -0
  58. package/dist/esm/google/protobuf/descriptor_pb.d.ts +33 -33
  59. package/dist/esm/google/protobuf/descriptor_pb.js +23 -10
  60. package/dist/esm/google/protobuf/struct_pb.js +1 -1
  61. package/dist/esm/google/protobuf/type_pb.js +1 -1
  62. package/dist/esm/google/protobuf/wrappers_pb.js +1 -1
  63. package/dist/esm/index.d.ts +3 -1
  64. package/dist/esm/index.js +2 -1
  65. package/dist/esm/is-message.d.ts +22 -0
  66. package/dist/esm/is-message.js +48 -0
  67. package/dist/esm/json-format.d.ts +1 -2
  68. package/dist/esm/json-format.js +1 -1
  69. package/dist/esm/private/binary-format.d.ts +7 -0
  70. package/dist/esm/private/{binary-format-common.js → binary-format.js} +126 -25
  71. package/dist/esm/private/extensions.js +2 -2
  72. package/dist/esm/private/feature-set.js +1 -1
  73. package/dist/esm/private/field-normalize.d.ts +9 -0
  74. package/dist/esm/private/field-normalize.js +65 -0
  75. package/dist/esm/private/field-wrapper.d.ts +1 -1
  76. package/dist/esm/private/field-wrapper.js +3 -2
  77. package/dist/esm/private/field.d.ts +1 -0
  78. package/dist/esm/private/field.js +1 -0
  79. package/dist/esm/private/json-format.d.ts +2 -0
  80. package/dist/esm/private/{json-format-common.js → json-format.js} +227 -135
  81. package/dist/esm/private/proto-runtime.d.ts +1 -1
  82. package/dist/esm/private/proto-runtime.js +8 -4
  83. package/dist/esm/private/reflect.d.ts +9 -0
  84. package/dist/esm/private/reflect.js +74 -0
  85. package/dist/esm/private/reify-wkt.js +1 -1
  86. package/dist/esm/private/scalars.d.ts +9 -18
  87. package/dist/esm/private/scalars.js +15 -59
  88. package/dist/esm/private/text-format.d.ts +1 -1
  89. package/dist/esm/private/text-format.js +1 -1
  90. package/dist/esm/private/util-common.js +10 -6
  91. package/dist/esm/proto-delimited.js +2 -3
  92. package/dist/esm/proto2.js +29 -68
  93. package/dist/esm/proto3.js +31 -78
  94. package/dist/esm/scalar.d.ts +53 -0
  95. package/dist/esm/scalar.js +78 -0
  96. package/dist/esm/to-plain-message.js +3 -2
  97. package/package.json +2 -8
  98. package/dist/cjs/private/binary-format-common.d.ts +0 -13
  99. package/dist/cjs/private/binary-format-proto2.d.ts +0 -2
  100. package/dist/cjs/private/binary-format-proto2.js +0 -91
  101. package/dist/cjs/private/binary-format-proto3.d.ts +0 -2
  102. package/dist/cjs/private/binary-format-proto3.js +0 -83
  103. package/dist/cjs/private/json-format-common.d.ts +0 -9
  104. package/dist/cjs/private/json-format-proto2.d.ts +0 -2
  105. package/dist/cjs/private/json-format-proto2.js +0 -103
  106. package/dist/cjs/private/json-format-proto3.d.ts +0 -2
  107. package/dist/cjs/private/json-format-proto3.js +0 -94
  108. package/dist/esm/private/binary-format-common.d.ts +0 -13
  109. package/dist/esm/private/binary-format-proto2.d.ts +0 -2
  110. package/dist/esm/private/binary-format-proto2.js +0 -87
  111. package/dist/esm/private/binary-format-proto3.d.ts +0 -2
  112. package/dist/esm/private/binary-format-proto3.js +0 -79
  113. package/dist/esm/private/json-format-common.d.ts +0 -9
  114. package/dist/esm/private/json-format-proto2.d.ts +0 -2
  115. package/dist/esm/private/json-format-proto2.js +0 -99
  116. package/dist/esm/private/json-format-proto3.d.ts +0 -2
  117. package/dist/esm/private/json-format-proto3.js +0 -90
  118. package/dist/proxy/index.d.ts +0 -1
  119. package/dist/proxy/index.js +0 -1
@@ -12,13 +12,18 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { Message } from "../message.js";
15
- import { LongType, ScalarType } from "../field.js";
16
15
  import { assert, assertFloat32, assertInt32, assertUInt32 } from "./assert.js";
17
16
  import { protoInt64 } from "../proto-int64.js";
18
17
  import { protoBase64 } from "../proto-base64.js";
19
18
  import { createExtensionContainer } from "./extensions.js";
20
19
  import { getExtension, hasExtension, setExtension, } from "../extension-accessor.js";
21
- /* eslint-disable no-case-declarations, @typescript-eslint/restrict-plus-operands,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument */
20
+ import { clearField, isFieldSet } from "./reflect.js";
21
+ import { wrapField } from "./field-wrapper.js";
22
+ import { scalarZeroValue } from "./scalars.js";
23
+ import { isScalarZeroValue } from "./scalars.js";
24
+ import { LongType, ScalarType } from "../scalar.js";
25
+ import { isMessage } from "../is-message.js";
26
+ /* eslint-disable no-case-declarations,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */
22
27
  // Default options for parsing JSON.
23
28
  const jsonReadDefaults = {
24
29
  ignoreUnknownFields: false,
@@ -36,8 +41,9 @@ function makeReadOptions(options) {
36
41
  function makeWriteOptions(options) {
37
42
  return options ? Object.assign(Object.assign({}, jsonWriteDefaults), options) : jsonWriteDefaults;
38
43
  }
39
- export function makeJsonFormatCommon(nullAsZeroValue, makeWriteField) {
40
- const writeField = makeWriteField(writeEnum, writeScalar);
44
+ const tokenNull = Symbol();
45
+ const tokenIgnoredUnknownEnum = Symbol();
46
+ export function makeJsonFormat() {
41
47
  return {
42
48
  makeReadOptions,
43
49
  makeWriteOptions,
@@ -62,7 +68,7 @@ export function makeJsonFormatCommon(nullAsZeroValue, makeWriteField) {
62
68
  }
63
69
  oneofSeen.set(field.oneof, jsonKey);
64
70
  }
65
- readField(message, jsonValue, field, options, type, nullAsZeroValue);
71
+ readField(message, jsonValue, field, options, type);
66
72
  }
67
73
  else {
68
74
  let found = false;
@@ -73,7 +79,7 @@ export function makeJsonFormatCommon(nullAsZeroValue, makeWriteField) {
73
79
  if (ext && ext.extendee.typeName == type.typeName) {
74
80
  found = true;
75
81
  const [container, get] = createExtensionContainer(ext);
76
- readField(container, jsonValue, ext.field, options, ext, true);
82
+ readField(container, jsonValue, ext.field, options, ext);
77
83
  // We pass on the options as BinaryReadOptions/BinaryWriteOptions,
78
84
  // so that users can bring their own binary reader and writer factories
79
85
  // if necessary.
@@ -92,23 +98,23 @@ export function makeJsonFormatCommon(nullAsZeroValue, makeWriteField) {
92
98
  const json = {};
93
99
  let field;
94
100
  try {
95
- for (const member of type.fields.byMember()) {
96
- let jsonValue;
97
- if (member.kind == "oneof") {
98
- const oneof = message[member.localName];
99
- if (oneof.value === undefined) {
101
+ for (field of type.fields.byNumber()) {
102
+ if (!isFieldSet(field, message)) {
103
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
104
+ if (field.req) {
105
+ throw `required field not set`;
106
+ }
107
+ if (!options.emitDefaultValues) {
100
108
  continue;
101
109
  }
102
- field = member.findField(oneof.case);
103
- if (!field) {
104
- throw "oneof case not found: " + oneof.case;
110
+ if (!canEmitFieldDefaultValue(field)) {
111
+ continue;
105
112
  }
106
- jsonValue = writeField(field, oneof.value, options);
107
- }
108
- else {
109
- field = member;
110
- jsonValue = writeField(field, message[field.localName], options);
111
113
  }
114
+ const value = field.oneof
115
+ ? message[field.oneof.localName].value
116
+ : message[field.localName];
117
+ const jsonValue = writeField(field, value, options);
112
118
  if (jsonValue !== undefined) {
113
119
  json[options.useProtoFieldName ? field.name : field.jsonName] =
114
120
  jsonValue;
@@ -139,8 +145,24 @@ export function makeJsonFormatCommon(nullAsZeroValue, makeWriteField) {
139
145
  }
140
146
  return json;
141
147
  },
142
- readScalar: (type, json, longType) => readScalar(type, json, longType, nullAsZeroValue), // eslint-disable-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return
143
- writeScalar,
148
+ readScalar(type, json, longType) {
149
+ // The signature of our internal function has changed. For backwards-
150
+ // compatibility, we support the old form that is part of the public API
151
+ // through the interface JsonFormat.
152
+ return readScalar(type, json, longType !== null && longType !== void 0 ? longType : LongType.BIGINT, true);
153
+ },
154
+ writeScalar(type, value, emitDefaultValues) {
155
+ // The signature of our internal function has changed. For backwards-
156
+ // compatibility, we support the old form that is part of the public API
157
+ // through the interface JsonFormat.
158
+ if (value === undefined) {
159
+ return undefined;
160
+ }
161
+ if (emitDefaultValues || isScalarZeroValue(type, value)) {
162
+ return writeScalar(type, value);
163
+ }
164
+ return undefined;
165
+ },
144
166
  debug: debugJsonValue,
145
167
  };
146
168
  }
@@ -158,50 +180,38 @@ function debugJsonValue(json) {
158
180
  }
159
181
  }
160
182
  // Read a JSON value for a field.
161
- // The "type" argument is only used to provide context in errors.
162
- // The argument "nullAsZeroValue" applies to singular fields (not repeated, map,
163
- // or oneof). If the argument is `true`, JSON null is parsed as the fields
164
- // zero-value. If the argument is false, JSON null sets the field to `undefined`.
165
- function readField(target, // eslint-disable-line @typescript-eslint/no-explicit-any -- `any` is the best choice for dynamic access
166
- jsonValue, field, options, type, nullAsZeroValue) {
183
+ // The "parentType" argument is only used to provide context in errors.
184
+ function readField(target, jsonValue, field, options, parentType) {
167
185
  let localName = field.localName;
168
- if (field.oneof) {
169
- if (jsonValue === null && field.kind == "scalar") {
170
- // see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
171
- return;
172
- }
173
- target = target[field.oneof.localName] = { case: localName };
174
- localName = "value";
175
- }
176
186
  if (field.repeated) {
187
+ assert(field.kind != "map");
177
188
  if (jsonValue === null) {
178
189
  return;
179
190
  }
180
191
  if (!Array.isArray(jsonValue)) {
181
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
192
+ throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
182
193
  }
183
194
  const targetArray = target[localName];
184
195
  for (const jsonItem of jsonValue) {
185
196
  if (jsonItem === null) {
186
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`);
197
+ throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`);
187
198
  }
188
- let val;
189
- // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- "map" is invalid for repeated fields
190
199
  switch (field.kind) {
191
200
  case "message":
192
- val = field.T.fromJson(jsonItem, options);
201
+ targetArray.push(field.T.fromJson(jsonItem, options));
193
202
  break;
194
203
  case "enum":
195
- val = readEnum(field.T, jsonItem, options.ignoreUnknownFields, true);
196
- if (val === undefined)
197
- continue;
204
+ const enumValue = readEnum(field.T, jsonItem, options.ignoreUnknownFields, true);
205
+ if (enumValue !== tokenIgnoredUnknownEnum) {
206
+ targetArray.push(enumValue);
207
+ }
198
208
  break;
199
209
  case "scalar":
200
210
  try {
201
- val = readScalar(field.T, jsonItem, field.L, true);
211
+ targetArray.push(readScalar(field.T, jsonItem, field.L, true));
202
212
  }
203
213
  catch (e) {
204
- let m = `cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`;
214
+ let m = `cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`;
205
215
  if (e instanceof Error && e.message.length > 0) {
206
216
  m += `: ${e.message}`;
207
217
  }
@@ -209,7 +219,6 @@ jsonValue, field, options, type, nullAsZeroValue) {
209
219
  }
210
220
  break;
211
221
  }
212
- targetArray.push(val);
213
222
  }
214
223
  }
215
224
  else if (field.kind == "map") {
@@ -217,29 +226,40 @@ jsonValue, field, options, type, nullAsZeroValue) {
217
226
  return;
218
227
  }
219
228
  if (typeof jsonValue != "object" || Array.isArray(jsonValue)) {
220
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
229
+ throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
221
230
  }
222
231
  const targetMap = target[localName];
223
232
  for (const [jsonMapKey, jsonMapValue] of Object.entries(jsonValue)) {
224
233
  if (jsonMapValue === null) {
225
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: map value null`);
234
+ throw new Error(`cannot decode field ${parentType.typeName}.${field.name} from JSON: map value null`);
235
+ }
236
+ let key;
237
+ try {
238
+ key = readMapKey(field.K, jsonMapKey);
239
+ }
240
+ catch (e) {
241
+ let m = `cannot decode map key for field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
242
+ if (e instanceof Error && e.message.length > 0) {
243
+ m += `: ${e.message}`;
244
+ }
245
+ throw new Error(m);
226
246
  }
227
- let val;
228
247
  switch (field.V.kind) {
229
248
  case "message":
230
- val = field.V.T.fromJson(jsonMapValue, options);
249
+ targetMap[key] = field.V.T.fromJson(jsonMapValue, options);
231
250
  break;
232
251
  case "enum":
233
- val = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields, true);
234
- if (val === undefined)
235
- continue;
252
+ const enumValue = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields, true);
253
+ if (enumValue !== tokenIgnoredUnknownEnum) {
254
+ targetMap[key] = enumValue;
255
+ }
236
256
  break;
237
257
  case "scalar":
238
258
  try {
239
- val = readScalar(field.V.T, jsonMapValue, LongType.BIGINT, true);
259
+ targetMap[key] = readScalar(field.V.T, jsonMapValue, LongType.BIGINT, true);
240
260
  }
241
261
  catch (e) {
242
- let m = `cannot decode map value for field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
262
+ let m = `cannot decode map value for field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
243
263
  if (e instanceof Error && e.message.length > 0) {
244
264
  m += `: ${e.message}`;
245
265
  }
@@ -247,57 +267,59 @@ jsonValue, field, options, type, nullAsZeroValue) {
247
267
  }
248
268
  break;
249
269
  }
250
- try {
251
- targetMap[readScalar(field.K, field.K == ScalarType.BOOL
252
- ? jsonMapKey == "true"
253
- ? true
254
- : jsonMapKey == "false"
255
- ? false
256
- : jsonMapKey
257
- : jsonMapKey, LongType.BIGINT, true).toString()] = val;
258
- }
259
- catch (e) {
260
- let m = `cannot decode map key for field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
261
- if (e instanceof Error && e.message.length > 0) {
262
- m += `: ${e.message}`;
263
- }
264
- throw new Error(m);
265
- }
266
270
  }
267
271
  }
268
272
  else {
273
+ if (field.oneof) {
274
+ target = target[field.oneof.localName] = { case: localName };
275
+ localName = "value";
276
+ }
269
277
  switch (field.kind) {
270
278
  case "message":
271
279
  const messageType = field.T;
272
280
  if (jsonValue === null &&
273
281
  messageType.typeName != "google.protobuf.Value") {
274
- if (field.oneof) {
275
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: null is invalid for oneof field`);
276
- }
277
282
  return;
278
283
  }
279
- if (target[localName] instanceof Message) {
280
- target[localName].fromJson(jsonValue, options);
284
+ let currentValue = target[localName];
285
+ if (isMessage(currentValue)) {
286
+ currentValue.fromJson(jsonValue, options);
281
287
  }
282
288
  else {
283
- target[localName] = messageType.fromJson(jsonValue, options);
289
+ target[localName] = currentValue = messageType.fromJson(jsonValue, options);
284
290
  if (messageType.fieldWrapper && !field.oneof) {
285
- target[localName] = messageType.fieldWrapper.unwrapField(target[localName]);
291
+ target[localName] =
292
+ messageType.fieldWrapper.unwrapField(currentValue);
286
293
  }
287
294
  }
288
295
  break;
289
296
  case "enum":
290
- const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields, nullAsZeroValue);
291
- if (enumValue !== undefined) {
292
- target[localName] = enumValue;
297
+ const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields, false);
298
+ switch (enumValue) {
299
+ case tokenNull:
300
+ clearField(field, target);
301
+ break;
302
+ case tokenIgnoredUnknownEnum:
303
+ break;
304
+ default:
305
+ target[localName] = enumValue;
306
+ break;
293
307
  }
294
308
  break;
295
309
  case "scalar":
296
310
  try {
297
- target[localName] = readScalar(field.T, jsonValue, field.L, nullAsZeroValue);
311
+ const scalarValue = readScalar(field.T, jsonValue, field.L, false);
312
+ switch (scalarValue) {
313
+ case tokenNull:
314
+ clearField(field, target);
315
+ break;
316
+ default:
317
+ target[localName] = scalarValue;
318
+ break;
319
+ }
298
320
  }
299
321
  catch (e) {
300
- let m = `cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
322
+ let m = `cannot decode field ${parentType.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
301
323
  if (e instanceof Error && e.message.length > 0) {
302
324
  m += `: ${e.message}`;
303
325
  }
@@ -307,12 +329,27 @@ jsonValue, field, options, type, nullAsZeroValue) {
307
329
  }
308
330
  }
309
331
  }
310
- // May throw an error. If the error message is non-blank, it should be shown.
311
- // It is up to the caller to provide context.
312
- // If the argument "nullAsZeroValue" is `true`, this function returns the zero-value
313
- // for JSON null. If the argument is `false`, this function returns `undefined`
314
- // for JSON null.
332
+ function readMapKey(type, json) {
333
+ if (type === ScalarType.BOOL) {
334
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
335
+ switch (json) {
336
+ case "true":
337
+ json = true;
338
+ break;
339
+ case "false":
340
+ json = false;
341
+ break;
342
+ }
343
+ }
344
+ return readScalar(type, json, LongType.BIGINT, true).toString();
345
+ }
315
346
  function readScalar(type, json, longType, nullAsZeroValue) {
347
+ if (json === null) {
348
+ if (nullAsZeroValue) {
349
+ return scalarZeroValue(type, longType);
350
+ }
351
+ return tokenNull;
352
+ }
316
353
  // every valid case in the switch below returns, and every fall
317
354
  // through is regarded as a failure.
318
355
  switch (type) {
@@ -320,8 +357,6 @@ function readScalar(type, json, longType, nullAsZeroValue) {
320
357
  // Either numbers or strings are accepted. Exponent notation is also accepted.
321
358
  case ScalarType.DOUBLE:
322
359
  case ScalarType.FLOAT:
323
- if (json === null)
324
- return nullAsZeroValue ? 0.0 : undefined;
325
360
  if (json === "NaN")
326
361
  return Number.NaN;
327
362
  if (json === "Infinity")
@@ -357,8 +392,6 @@ function readScalar(type, json, longType, nullAsZeroValue) {
357
392
  case ScalarType.SFIXED32:
358
393
  case ScalarType.SINT32:
359
394
  case ScalarType.UINT32:
360
- if (json === null)
361
- return nullAsZeroValue ? 0 : undefined;
362
395
  let int32;
363
396
  if (typeof json == "number")
364
397
  int32 = json;
@@ -377,8 +410,6 @@ function readScalar(type, json, longType, nullAsZeroValue) {
377
410
  case ScalarType.INT64:
378
411
  case ScalarType.SFIXED64:
379
412
  case ScalarType.SINT64:
380
- if (json === null)
381
- return nullAsZeroValue ? protoInt64.zero : undefined;
382
413
  if (typeof json != "number" && typeof json != "string")
383
414
  break;
384
415
  const long = protoInt64.parse(json);
@@ -386,8 +417,6 @@ function readScalar(type, json, longType, nullAsZeroValue) {
386
417
  return longType ? long.toString() : long;
387
418
  case ScalarType.FIXED64:
388
419
  case ScalarType.UINT64:
389
- if (json === null)
390
- return nullAsZeroValue ? protoInt64.zero : undefined;
391
420
  if (typeof json != "number" && typeof json != "string")
392
421
  break;
393
422
  const uLong = protoInt64.uParse(json);
@@ -395,15 +424,11 @@ function readScalar(type, json, longType, nullAsZeroValue) {
395
424
  return longType ? uLong.toString() : uLong;
396
425
  // bool:
397
426
  case ScalarType.BOOL:
398
- if (json === null)
399
- return nullAsZeroValue ? false : undefined;
400
427
  if (typeof json !== "boolean")
401
428
  break;
402
429
  return json;
403
430
  // string:
404
431
  case ScalarType.STRING:
405
- if (json === null)
406
- return nullAsZeroValue ? "" : undefined;
407
432
  if (typeof json !== "string") {
408
433
  break;
409
434
  }
@@ -419,8 +444,6 @@ function readScalar(type, json, longType, nullAsZeroValue) {
419
444
  // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
420
445
  // Either standard or URL-safe base64 encoding with/without paddings are accepted.
421
446
  case ScalarType.BYTES:
422
- if (json === null)
423
- return nullAsZeroValue ? new Uint8Array(0) : undefined;
424
447
  if (json === "")
425
448
  return new Uint8Array(0);
426
449
  if (typeof json !== "string")
@@ -429,14 +452,12 @@ function readScalar(type, json, longType, nullAsZeroValue) {
429
452
  }
430
453
  throw new Error();
431
454
  }
432
- // If the argument "nullAsZeroValue" is `true`, this function returns the first
433
- // enum value for JSON null. If the argument is `false`, this function returns
434
- // `undefined`.
435
455
  function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
436
456
  if (json === null) {
437
- // proto3 requires 0 to be default value for all enums (which is required to be the first value).
438
- // proto2 uses the first value (at least with protoc-gen-go).
439
- return nullAsZeroValue ? type.values[0].no : undefined;
457
+ if (type.typeName == "google.protobuf.NullValue") {
458
+ return 0; // google.protobuf.NullValue.NULL_VALUE = 0
459
+ }
460
+ return nullAsZeroValue ? type.values[0].no : tokenNull;
440
461
  }
441
462
  // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
442
463
  switch (typeof json) {
@@ -447,36 +468,112 @@ function readEnum(type, json, ignoreUnknownFields, nullAsZeroValue) {
447
468
  break;
448
469
  case "string":
449
470
  const value = type.findName(json);
450
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
451
- if (value || ignoreUnknownFields) {
452
- return value === null || value === void 0 ? void 0 : value.no;
471
+ if (value !== undefined) {
472
+ return value.no;
473
+ }
474
+ if (ignoreUnknownFields) {
475
+ return tokenIgnoredUnknownEnum;
453
476
  }
454
477
  break;
455
478
  }
456
479
  throw new Error(`cannot decode enum ${type.typeName} from JSON: ${debugJsonValue(json)}`);
457
480
  }
458
- function writeEnum(type, value, emitZeroValue, enumAsInteger) {
459
- var _a;
460
- if (value === undefined) {
461
- return value;
481
+ // Decide whether an unset field should be emitted with JSON write option `emitDefaultValues`
482
+ function canEmitFieldDefaultValue(field) {
483
+ if (field.repeated || field.kind == "map") {
484
+ // maps are {}, repeated fields are []
485
+ return true;
486
+ }
487
+ if (field.oneof) {
488
+ // oneof fields are never emitted
489
+ return false;
462
490
  }
463
- if (!emitZeroValue && type.values[0].no === value) {
464
- // proto3 requires 0 to be default value for all enums
465
- return undefined;
491
+ if (field.kind == "message") {
492
+ // singular message field are allowed to emit JSON null, but we do not
493
+ return false;
466
494
  }
467
- if (enumAsInteger) {
468
- return value;
495
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
496
+ if (field.opt || field.req) {
497
+ // the field uses explicit presence, so we cannot emit a zero value
498
+ return false;
499
+ }
500
+ return true;
501
+ }
502
+ function writeField(field, value, options) {
503
+ if (field.kind == "map") {
504
+ assert(typeof value == "object" && value != null);
505
+ const jsonObj = {};
506
+ const entries = Object.entries(value);
507
+ switch (field.V.kind) {
508
+ case "scalar":
509
+ for (const [entryKey, entryValue] of entries) {
510
+ jsonObj[entryKey.toString()] = writeScalar(field.V.T, entryValue); // JSON standard allows only (double quoted) string as property key
511
+ }
512
+ break;
513
+ case "message":
514
+ for (const [entryKey, entryValue] of entries) {
515
+ // JSON standard allows only (double quoted) string as property key
516
+ jsonObj[entryKey.toString()] = entryValue.toJson(options);
517
+ }
518
+ break;
519
+ case "enum":
520
+ const enumType = field.V.T;
521
+ for (const [entryKey, entryValue] of entries) {
522
+ // JSON standard allows only (double quoted) string as property key
523
+ jsonObj[entryKey.toString()] = writeEnum(enumType, entryValue, options.enumAsInteger);
524
+ }
525
+ break;
526
+ }
527
+ return options.emitDefaultValues || entries.length > 0
528
+ ? jsonObj
529
+ : undefined;
469
530
  }
531
+ if (field.repeated) {
532
+ assert(Array.isArray(value));
533
+ const jsonArr = [];
534
+ switch (field.kind) {
535
+ case "scalar":
536
+ for (let i = 0; i < value.length; i++) {
537
+ jsonArr.push(writeScalar(field.T, value[i]));
538
+ }
539
+ break;
540
+ case "enum":
541
+ for (let i = 0; i < value.length; i++) {
542
+ jsonArr.push(writeEnum(field.T, value[i], options.enumAsInteger));
543
+ }
544
+ break;
545
+ case "message":
546
+ for (let i = 0; i < value.length; i++) {
547
+ jsonArr.push(value[i].toJson(options));
548
+ }
549
+ break;
550
+ }
551
+ return options.emitDefaultValues || jsonArr.length > 0
552
+ ? jsonArr
553
+ : undefined;
554
+ }
555
+ switch (field.kind) {
556
+ case "scalar":
557
+ return writeScalar(field.T, value);
558
+ case "enum":
559
+ return writeEnum(field.T, value, options.enumAsInteger);
560
+ case "message":
561
+ return wrapField(field.T, value).toJson(options);
562
+ }
563
+ }
564
+ function writeEnum(type, value, enumAsInteger) {
565
+ var _a;
566
+ assert(typeof value == "number");
470
567
  if (type.typeName == "google.protobuf.NullValue") {
471
568
  return null;
472
569
  }
570
+ if (enumAsInteger) {
571
+ return value;
572
+ }
473
573
  const val = type.findNumber(value);
474
574
  return (_a = val === null || val === void 0 ? void 0 : val.name) !== null && _a !== void 0 ? _a : value; // if we don't know the enum value, just return the number
475
575
  }
476
- function writeScalar(type, value, emitZeroValue) {
477
- if (value === undefined) {
478
- return undefined;
479
- }
576
+ function writeScalar(type, value) {
480
577
  switch (type) {
481
578
  // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
482
579
  case ScalarType.INT32:
@@ -485,7 +582,7 @@ function writeScalar(type, value, emitZeroValue) {
485
582
  case ScalarType.FIXED32:
486
583
  case ScalarType.UINT32:
487
584
  assert(typeof value == "number");
488
- return value != 0 || emitZeroValue ? value : undefined;
585
+ return value;
489
586
  // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
490
587
  // Either numbers or strings are accepted. Exponent notation is also accepted.
491
588
  case ScalarType.FLOAT:
@@ -498,15 +595,15 @@ function writeScalar(type, value, emitZeroValue) {
498
595
  return "Infinity";
499
596
  if (value === Number.NEGATIVE_INFINITY)
500
597
  return "-Infinity";
501
- return value !== 0 || emitZeroValue ? value : undefined;
598
+ return value;
502
599
  // string:
503
600
  case ScalarType.STRING:
504
601
  assert(typeof value == "string");
505
- return value.length > 0 || emitZeroValue ? value : undefined;
602
+ return value;
506
603
  // bool:
507
604
  case ScalarType.BOOL:
508
605
  assert(typeof value == "boolean");
509
- return value || emitZeroValue ? value : undefined;
606
+ return value;
510
607
  // JSON value will be a decimal string. Either numbers or strings are accepted.
511
608
  case ScalarType.UINT64:
512
609
  case ScalarType.FIXED64:
@@ -516,16 +613,11 @@ function writeScalar(type, value, emitZeroValue) {
516
613
  assert(typeof value == "bigint" ||
517
614
  typeof value == "string" ||
518
615
  typeof value == "number");
519
- // We use implicit conversion with `value != 0` to catch both 0n and "0"
520
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
521
- // @ts-ignore
522
- return emitZeroValue || value != 0 ? value.toString(10) : undefined;
616
+ return value.toString();
523
617
  // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
524
618
  // Either standard or URL-safe base64 encoding with/without paddings are accepted.
525
619
  case ScalarType.BYTES:
526
620
  assert(value instanceof Uint8Array);
527
- return emitZeroValue || value.byteLength > 0
528
- ? protoBase64.enc(value)
529
- : undefined;
621
+ return protoBase64.enc(value);
530
622
  }
531
623
  }
@@ -50,4 +50,4 @@ export interface ProtoRuntime {
50
50
  */
51
51
  makeExtension<E extends Message<E> = AnyMessage, V = unknown>(typeName: string, extendee: MessageType<E>, field: ExtensionFieldSource): Extension<E, V>;
52
52
  }
53
- export declare function makeProtoRuntime(syntax: string, json: JsonFormat, bin: BinaryFormat, util: Util): ProtoRuntime;
53
+ export declare function makeProtoRuntime(syntax: string, newFieldList: Util["newFieldList"], initFields: Util["initFields"]): ProtoRuntime;
@@ -14,12 +14,16 @@
14
14
  import { getEnumType, makeEnum, makeEnumType } from "./enum.js";
15
15
  import { makeMessageType } from "./message-type.js";
16
16
  import { makeExtension } from "./extensions.js";
17
- export function makeProtoRuntime(syntax, json, bin, util) {
17
+ import { makeJsonFormat } from "./json-format.js";
18
+ import { makeBinaryFormat } from "./binary-format.js";
19
+ import { makeUtilCommon } from "./util-common.js";
20
+ export function makeProtoRuntime(syntax, newFieldList, initFields) {
18
21
  return {
19
22
  syntax,
20
- json,
21
- bin,
22
- util,
23
+ json: makeJsonFormat(),
24
+ bin: makeBinaryFormat(),
25
+ util: Object.assign(Object.assign({}, makeUtilCommon()), { newFieldList,
26
+ initFields }),
23
27
  makeMessageType(typeName, fields, opt) {
24
28
  return makeMessageType(this, typeName, fields, opt);
25
29
  },
@@ -0,0 +1,9 @@
1
+ import type { FieldInfo } from "../field.js";
2
+ /**
3
+ * Returns true if the field is set.
4
+ */
5
+ export declare function isFieldSet(field: FieldInfo, target: Record<string, any>): boolean;
6
+ /**
7
+ * Resets the field, so that isFieldSet() will return false.
8
+ */
9
+ export declare function clearField(field: FieldInfo, target: Record<string, any>): void;