@bufbuild/protobuf 2.0.0-alpha.2 → 2.0.0-alpha.3

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 (143) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/clone.d.ts +1 -1
  3. package/dist/cjs/clone.js +2 -2
  4. package/dist/cjs/codegenv1/boot.d.ts +1 -1
  5. package/dist/cjs/codegenv1/boot.js +3 -5
  6. package/dist/cjs/codegenv1/embed.d.ts +1 -1
  7. package/dist/cjs/codegenv1/embed.js +39 -34
  8. package/dist/cjs/codegenv1/enum.d.ts +1 -1
  9. package/dist/cjs/codegenv1/extension.d.ts +1 -1
  10. package/dist/cjs/codegenv1/file.d.ts +1 -1
  11. package/dist/cjs/codegenv1/file.js +5 -7
  12. package/dist/cjs/codegenv1/index.d.ts +1 -0
  13. package/dist/cjs/codegenv1/index.js +1 -0
  14. package/dist/cjs/codegenv1/message.d.ts +1 -1
  15. package/dist/cjs/codegenv1/scalar.d.ts +5 -0
  16. package/dist/cjs/codegenv1/scalar.js +39 -0
  17. package/dist/cjs/codegenv1/service.d.ts +3 -3
  18. package/dist/cjs/codegenv1/types.d.ts +7 -9
  19. package/dist/cjs/create.d.ts +1 -1
  20. package/dist/cjs/create.js +6 -5
  21. package/dist/cjs/{desc-types.d.ts → descriptors.d.ts} +39 -7
  22. package/dist/cjs/descriptors.js +53 -0
  23. package/dist/cjs/equals.d.ts +1 -1
  24. package/dist/cjs/extensions.d.ts +1 -1
  25. package/dist/cjs/extensions.js +4 -3
  26. package/dist/cjs/fields.d.ts +1 -1
  27. package/dist/cjs/from-binary.d.ts +2 -2
  28. package/dist/cjs/from-binary.js +22 -22
  29. package/dist/cjs/from-json.d.ts +4 -4
  30. package/dist/cjs/from-json.js +200 -181
  31. package/dist/cjs/index.d.ts +2 -1
  32. package/dist/cjs/index.js +2 -1
  33. package/dist/cjs/is-message.d.ts +1 -1
  34. package/dist/cjs/proto-int64.d.ts +4 -1
  35. package/dist/cjs/proto-int64.js +16 -6
  36. package/dist/cjs/reflect/error.d.ts +1 -1
  37. package/dist/cjs/reflect/guard.d.ts +1 -1
  38. package/dist/cjs/reflect/index.d.ts +0 -1
  39. package/dist/cjs/reflect/index.js +0 -1
  40. package/dist/cjs/reflect/names.d.ts +1 -1
  41. package/dist/cjs/reflect/names.js +1 -1
  42. package/dist/cjs/reflect/nested-types.d.ts +1 -1
  43. package/dist/cjs/reflect/reflect-check.d.ts +10 -1
  44. package/dist/cjs/reflect/reflect-check.js +126 -9
  45. package/dist/cjs/reflect/reflect-types.d.ts +4 -4
  46. package/dist/cjs/reflect/reflect.d.ts +1 -1
  47. package/dist/cjs/reflect/reflect.js +28 -27
  48. package/dist/cjs/reflect/scalar.d.ts +3 -55
  49. package/dist/cjs/reflect/scalar.js +26 -220
  50. package/dist/cjs/reflect/unsafe.d.ts +1 -1
  51. package/dist/cjs/reflect/unsafe.js +1 -1
  52. package/dist/cjs/{reflect/registry.d.ts → registry.d.ts} +2 -2
  53. package/dist/cjs/{reflect/registry.js → registry.js} +54 -36
  54. package/dist/cjs/to-binary.d.ts +1 -1
  55. package/dist/cjs/to-binary.js +27 -27
  56. package/dist/cjs/to-json.d.ts +7 -6
  57. package/dist/cjs/to-json.js +57 -44
  58. package/dist/cjs/types.d.ts +1 -1
  59. package/dist/cjs/wire/base64-encoding.js +2 -2
  60. package/dist/cjs/wire/binary-encoding.d.ts +20 -0
  61. package/dist/cjs/wire/binary-encoding.js +54 -8
  62. package/dist/cjs/wire/size-delimited.d.ts +1 -1
  63. package/dist/cjs/wire/text-format.d.ts +1 -2
  64. package/dist/cjs/wire/text-format.js +21 -19
  65. package/dist/cjs/wkt/any.d.ts +3 -3
  66. package/dist/cjs/wkt/gen/google/protobuf/descriptor_pb.d.ts +6 -0
  67. package/dist/cjs/wkt/gen/google/protobuf/descriptor_pb.js +1 -1
  68. package/dist/cjs/wkt/wrappers.d.ts +1 -1
  69. package/dist/esm/clone.d.ts +1 -1
  70. package/dist/esm/clone.js +1 -1
  71. package/dist/esm/codegenv1/boot.d.ts +1 -1
  72. package/dist/esm/codegenv1/boot.js +3 -5
  73. package/dist/esm/codegenv1/embed.d.ts +1 -1
  74. package/dist/esm/codegenv1/embed.js +9 -4
  75. package/dist/esm/codegenv1/enum.d.ts +1 -1
  76. package/dist/esm/codegenv1/extension.d.ts +1 -1
  77. package/dist/esm/codegenv1/file.d.ts +1 -1
  78. package/dist/esm/codegenv1/file.js +4 -6
  79. package/dist/esm/codegenv1/index.d.ts +1 -0
  80. package/dist/esm/codegenv1/index.js +1 -0
  81. package/dist/esm/codegenv1/message.d.ts +1 -1
  82. package/dist/esm/codegenv1/scalar.d.ts +5 -0
  83. package/dist/esm/codegenv1/scalar.js +35 -0
  84. package/dist/esm/codegenv1/service.d.ts +3 -3
  85. package/dist/esm/codegenv1/types.d.ts +7 -9
  86. package/dist/esm/create.d.ts +1 -1
  87. package/dist/esm/create.js +4 -3
  88. package/dist/esm/{desc-types.d.ts → descriptors.d.ts} +39 -7
  89. package/dist/esm/descriptors.js +50 -0
  90. package/dist/esm/equals.d.ts +1 -1
  91. package/dist/esm/extensions.d.ts +1 -1
  92. package/dist/esm/extensions.js +4 -3
  93. package/dist/esm/fields.d.ts +1 -1
  94. package/dist/esm/from-binary.d.ts +2 -2
  95. package/dist/esm/from-binary.js +4 -4
  96. package/dist/esm/from-json.d.ts +4 -4
  97. package/dist/esm/from-json.js +193 -174
  98. package/dist/esm/index.d.ts +2 -1
  99. package/dist/esm/index.js +2 -1
  100. package/dist/esm/is-message.d.ts +1 -1
  101. package/dist/esm/proto-int64.d.ts +4 -1
  102. package/dist/esm/proto-int64.js +16 -6
  103. package/dist/esm/reflect/error.d.ts +1 -1
  104. package/dist/esm/reflect/guard.d.ts +1 -1
  105. package/dist/esm/reflect/index.d.ts +0 -1
  106. package/dist/esm/reflect/index.js +0 -1
  107. package/dist/esm/reflect/names.d.ts +1 -1
  108. package/dist/esm/reflect/names.js +1 -1
  109. package/dist/esm/reflect/nested-types.d.ts +1 -1
  110. package/dist/esm/reflect/reflect-check.d.ts +10 -1
  111. package/dist/esm/reflect/reflect-check.js +119 -2
  112. package/dist/esm/reflect/reflect-types.d.ts +4 -4
  113. package/dist/esm/reflect/reflect-types.js +1 -0
  114. package/dist/esm/reflect/reflect.d.ts +1 -1
  115. package/dist/esm/reflect/reflect.js +10 -9
  116. package/dist/esm/reflect/scalar.d.ts +3 -55
  117. package/dist/esm/reflect/scalar.js +14 -205
  118. package/dist/esm/reflect/unsafe.d.ts +1 -1
  119. package/dist/esm/reflect/unsafe.js +1 -1
  120. package/dist/esm/{reflect/registry.d.ts → registry.d.ts} +2 -2
  121. package/dist/esm/{reflect/registry.js → registry.js} +44 -26
  122. package/dist/esm/to-binary.d.ts +1 -1
  123. package/dist/esm/to-binary.js +1 -1
  124. package/dist/esm/to-json.d.ts +7 -6
  125. package/dist/esm/to-json.js +42 -29
  126. package/dist/esm/types.d.ts +1 -1
  127. package/dist/esm/wire/base64-encoding.js +2 -2
  128. package/dist/esm/wire/binary-encoding.d.ts +20 -0
  129. package/dist/esm/wire/binary-encoding.js +47 -1
  130. package/dist/esm/wire/size-delimited.d.ts +1 -1
  131. package/dist/esm/wire/text-format.d.ts +1 -2
  132. package/dist/esm/wire/text-format.js +5 -3
  133. package/dist/esm/wkt/any.d.ts +3 -3
  134. package/dist/esm/wkt/gen/google/protobuf/descriptor_pb.d.ts +6 -0
  135. package/dist/esm/wkt/gen/google/protobuf/descriptor_pb.js +1 -1
  136. package/dist/esm/wkt/wrappers.d.ts +1 -1
  137. package/package.json +1 -1
  138. package/dist/cjs/desc-types.js +0 -15
  139. package/dist/cjs/reflect/assert.d.ts +0 -16
  140. package/dist/cjs/reflect/assert.js +0 -59
  141. package/dist/esm/desc-types.js +0 -14
  142. package/dist/esm/reflect/assert.d.ts +0 -16
  143. package/dist/esm/reflect/assert.js +0 -52
@@ -11,16 +11,16 @@
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import { assertFloat32, assertInt32, assertUInt32 } from "./reflect/assert.js";
14
+ /* eslint-disable no-case-declarations,@typescript-eslint/restrict-template-expressions */
15
+ import { ScalarType, } from "./descriptors.js";
15
16
  import { protoInt64 } from "./proto-int64.js";
16
17
  import { create } from "./create.js";
17
18
  import { reflect } from "./reflect/reflect.js";
19
+ import { FieldError, isFieldError } from "./reflect/error.js";
18
20
  import { formatVal } from "./reflect/reflect-check.js";
19
- import { LongType, ScalarType, scalarZeroValue, } from "./reflect/scalar.js";
21
+ import { scalarZeroValue } from "./reflect/scalar.js";
20
22
  import { base64Decode } from "./wire/base64-encoding.js";
21
- import { getTextEncoding } from "./wire/text-encoding.js";
22
- import { anyPack, ListValueDesc, NullValue, StructDesc, ValueDesc, } from "./wkt/index.js";
23
- import { isWrapperDesc } from "./wkt/wrappers.js";
23
+ import { isWrapperDesc, anyPack, ListValueDesc, NullValue, StructDesc, ValueDesc, } from "./wkt/index.js";
24
24
  import { createExtensionContainer, setExtension } from "./extensions.js";
25
25
  // Default options for parsing JSON.
26
26
  const jsonReadDefaults = {
@@ -45,14 +45,25 @@ export function fromJsonString(messageDesc, json, options) {
45
45
  * new data.
46
46
  */
47
47
  export function mergeFromJsonString(messageDesc, target, json, options) {
48
- return mergeFromJson(messageDesc, target, parseJsonString(json, messageDesc.typeName), options);
48
+ mergeFromJson(messageDesc, target, parseJsonString(json, messageDesc.typeName), options);
49
49
  }
50
50
  /**
51
51
  * Parse a message from a JSON value.
52
52
  */
53
53
  export function fromJson(messageDesc, json, options) {
54
54
  const msg = reflect(messageDesc);
55
- readMessage(msg, json, makeReadOptions(options));
55
+ try {
56
+ readMessage(msg, json, makeReadOptions(options));
57
+ }
58
+ catch (e) {
59
+ if (isFieldError(e)) {
60
+ // @ts-expect-error we use the ES2022 error CTOR option "cause" for better stack traces
61
+ throw new Error(`cannot decode ${e.field()} from JSON: ${e.message}`, {
62
+ cause: e,
63
+ });
64
+ }
65
+ throw e;
66
+ }
56
67
  return msg.message;
57
68
  }
58
69
  /**
@@ -65,8 +76,18 @@ export function fromJson(messageDesc, json, options) {
65
76
  * new data.
66
77
  */
67
78
  export function mergeFromJson(messageDesc, target, json, options) {
68
- readMessage(reflect(messageDesc, target), json, makeReadOptions(options));
69
- return target;
79
+ try {
80
+ readMessage(reflect(messageDesc, target), json, makeReadOptions(options));
81
+ }
82
+ catch (e) {
83
+ if (isFieldError(e)) {
84
+ // @ts-expect-error we use the ES2022 error CTOR option "cause" for better stack traces
85
+ throw new Error(`cannot decode ${e.field()} from JSON: ${e.message}`, {
86
+ cause: e,
87
+ });
88
+ }
89
+ throw e;
90
+ }
70
91
  }
71
92
  function readMessage(msg, json, opts) {
72
93
  var _a;
@@ -74,7 +95,7 @@ function readMessage(msg, json, opts) {
74
95
  return;
75
96
  }
76
97
  if (json == null || Array.isArray(json) || typeof json != "object") {
77
- throw new Error(`cannot decode message ${msg.desc.typeName} from JSON: ${formatVal(json)}`);
98
+ throw new Error(`cannot decode ${msg.desc} from JSON: ${formatVal(json)}`);
78
99
  }
79
100
  const oneofSeen = new Map();
80
101
  const jsonNames = new Map();
@@ -91,9 +112,9 @@ function readMessage(msg, json, opts) {
91
112
  }
92
113
  const seen = oneofSeen.get(field.oneof);
93
114
  if (seen !== undefined) {
94
- throw new Error(`cannot decode message ${msg.desc.typeName} from JSON: multiple keys for oneof "${field.oneof.name}" present: "${seen}", "${jsonKey}"`);
115
+ throw new FieldError(field.oneof, `oneof set multiple times by ${seen.name} and ${field.name}`);
95
116
  }
96
- oneofSeen.set(field.oneof, jsonKey);
117
+ oneofSeen.set(field.oneof, field);
97
118
  }
98
119
  readField(msg, field, jsonValue, opts);
99
120
  }
@@ -108,7 +129,7 @@ function readMessage(msg, json, opts) {
108
129
  setExtension(msg.message, extension, get());
109
130
  }
110
131
  if (!extension && !opts.ignoreUnknownFields) {
111
- throw new Error(`cannot decode message ${msg.desc.typeName} from JSON: key "${jsonKey}" is unknown`);
132
+ throw new Error(`cannot decode ${msg.desc} from JSON: key "${jsonKey}" is unknown`);
112
133
  }
113
134
  }
114
135
  }
@@ -137,45 +158,42 @@ function readMapField(msg, field, json, opts) {
137
158
  return;
138
159
  }
139
160
  if (typeof json != "object" || Array.isArray(json)) {
140
- throw new Error(`cannot decode field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(json)}`);
161
+ throw new FieldError(field, "expected object, got " + formatVal(json));
141
162
  }
142
163
  for (const [jsonMapKey, jsonMapValue] of Object.entries(json)) {
143
164
  if (jsonMapValue === null) {
144
- throw new Error(`cannot decode field ${msg.desc.typeName}.${field.name} from JSON: map value null`);
145
- }
146
- let key;
147
- try {
148
- key = readMapKey(field.mapKey, jsonMapKey);
149
- }
150
- catch (e) {
151
- let m = `cannot decode map key for field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(jsonMapKey)}`;
152
- if (e instanceof Error && e.message.length > 0) {
153
- m += `: ${e.message}`;
154
- }
155
- throw new Error(m);
165
+ throw new FieldError(field, "map value must not be null");
156
166
  }
167
+ const key = mapKeyFromJson(field.mapKey, jsonMapKey);
157
168
  switch (field.mapKind) {
158
169
  case "message":
159
170
  const msgValue = reflect(field.message);
160
171
  readMessage(msgValue, jsonMapValue, opts);
161
- msg.setMapEntry(field, key, msgValue);
172
+ // TODO fix types
173
+ // @ts-expect-error TODO
174
+ const err = msg.setMapEntry(field, key, msgValue);
175
+ if (err) {
176
+ throw err;
177
+ }
162
178
  break;
163
179
  case "enum":
164
180
  const enumValue = readEnum(field.enum, jsonMapValue, opts.ignoreUnknownFields, true);
165
181
  if (enumValue !== tokenIgnoredUnknownEnum) {
166
- msg.setMapEntry(field, key, enumValue);
182
+ // TODO fix types
183
+ // @ts-expect-error TODO
184
+ const err = msg.setMapEntry(field, key, enumValue);
185
+ if (err) {
186
+ throw err;
187
+ }
167
188
  }
168
189
  break;
169
190
  case "scalar":
170
- try {
171
- msg.setMapEntry(field, key, readScalar(field.scalar, jsonMapValue, true));
172
- }
173
- catch (e) {
174
- let m = `cannot decode map value for field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(jsonMapValue)}`;
175
- if (e instanceof Error && e.message.length > 0) {
176
- m += `: ${e.message}`;
177
- }
178
- throw new Error(m);
191
+ const err2 = msg.setMapEntry(field,
192
+ // TODO fix types
193
+ // @ts-expect-error TODO
194
+ key, scalarFromJson(field, jsonMapValue, true));
195
+ if (err2) {
196
+ throw err2;
179
197
  }
180
198
  break;
181
199
  }
@@ -186,11 +204,11 @@ function readListField(msg, field, json, opts) {
186
204
  return;
187
205
  }
188
206
  if (!Array.isArray(json)) {
189
- throw new Error(`cannot decode field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(json)}`);
207
+ throw new FieldError(field, "expected Array, got " + formatVal(json));
190
208
  }
191
209
  for (const jsonItem of json) {
192
210
  if (jsonItem === null) {
193
- throw new Error(`cannot decode field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(jsonItem)}`);
211
+ throw new FieldError(field, "list item must not be null");
194
212
  }
195
213
  switch (field.listKind) {
196
214
  case "message":
@@ -205,15 +223,9 @@ function readListField(msg, field, json, opts) {
205
223
  }
206
224
  break;
207
225
  case "scalar":
208
- try {
209
- msg.addListItem(field, readScalar(field.scalar, jsonItem, true));
210
- }
211
- catch (e) {
212
- let m = `cannot decode field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(jsonItem)}`;
213
- if (e instanceof Error && e.message.length > 0) {
214
- m += `: ${e.message}`;
215
- }
216
- throw new Error(m);
226
+ const err = msg.addListItem(field, scalarFromJson(field, jsonItem, true));
227
+ if (err) {
228
+ throw err;
217
229
  }
218
230
  break;
219
231
  }
@@ -238,36 +250,18 @@ function readEnumField(msg, field, json, opts) {
238
250
  }
239
251
  }
240
252
  function readScalarField(msg, field, json) {
241
- try {
242
- const scalarValue = readScalar(field.scalar, json, false);
243
- if (scalarValue === tokenNull) {
244
- msg.clear(field);
245
- }
246
- else {
247
- msg.set(field, scalarValue);
248
- }
249
- }
250
- catch (e) {
251
- let m = `cannot decode field ${msg.desc.typeName}.${field.name} from JSON: ${formatVal(json)}`;
252
- if (e instanceof Error && e.message.length > 0) {
253
- m += `: ${e.message}`;
254
- }
255
- throw new Error(m);
253
+ const scalarValue = scalarFromJson(field, json, false);
254
+ if (scalarValue === tokenNull) {
255
+ msg.clear(field);
256
256
  }
257
- }
258
- function readMapKey(type, json) {
259
- if (type === ScalarType.BOOL) {
260
- // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
261
- switch (json) {
262
- case "true":
263
- json = true;
264
- break;
265
- case "false":
266
- json = false;
267
- break;
257
+ else {
258
+ // TODO fix type error
259
+ // @ts-expect-error TODO
260
+ const err = msg.set(field, scalarValue);
261
+ if (err) {
262
+ throw err;
268
263
  }
269
264
  }
270
- return readScalar(type, json, true);
271
265
  }
272
266
  const tokenIgnoredUnknownEnum = Symbol();
273
267
  function readEnum(desc, json, ignoreUnknownFields, nullAsZeroValue) {
@@ -294,116 +288,143 @@ function readEnum(desc, json, ignoreUnknownFields, nullAsZeroValue) {
294
288
  }
295
289
  break;
296
290
  }
297
- throw new Error(`cannot decode enum ${desc.typeName} from JSON: ${formatVal(json)}`);
291
+ throw new Error(`cannot decode ${desc} from JSON: ${formatVal(json)}`);
298
292
  }
299
293
  const tokenNull = Symbol();
300
- function readScalar(type, json, nullAsZeroValue) {
294
+ function scalarFromJson(field, json, nullAsZeroValue) {
301
295
  if (json === null) {
302
296
  if (nullAsZeroValue) {
303
- return scalarZeroValue(type, LongType.BIGINT);
297
+ return scalarZeroValue(field.scalar, false);
304
298
  }
305
299
  return tokenNull;
306
300
  }
307
- // every valid case in the switch below returns, and every fall
308
- // through is regarded as a failure.
309
- switch (type) {
301
+ // int64, sfixed64, sint64, fixed64, uint64: Reflect supports string and number.
302
+ // string, bool: Supported by reflect.
303
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
304
+ switch (field.scalar) {
310
305
  // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity".
311
306
  // Either numbers or strings are accepted. Exponent notation is also accepted.
312
307
  case ScalarType.DOUBLE:
313
308
  case ScalarType.FLOAT:
314
309
  if (json === "NaN")
315
- return Number.NaN;
310
+ return NaN;
316
311
  if (json === "Infinity")
317
312
  return Number.POSITIVE_INFINITY;
318
313
  if (json === "-Infinity")
319
314
  return Number.NEGATIVE_INFINITY;
320
- if (json === "") {
321
- // empty string is not a number
322
- break;
323
- }
324
- if (typeof json == "string" && json.trim().length !== json.length) {
325
- // extra whitespace
326
- break;
327
- }
328
- if (typeof json != "string" && typeof json != "number") {
329
- break;
330
- }
331
- const float = Number(json);
332
- if (Number.isNaN(float)) {
333
- // not a number
315
+ if (typeof json == "number") {
316
+ if (isNaN(json)) {
317
+ // NaN must be encoded with string constants
318
+ throw new FieldError(field, "unexpected NaN number");
319
+ }
320
+ if (!isFinite(json)) {
321
+ // Infinity must be encoded with string constants
322
+ throw new FieldError(field, "unexpected infinite number");
323
+ }
334
324
  break;
335
325
  }
336
- if (!Number.isFinite(float)) {
337
- // infinity and -infinity are handled by string representation above, so this is an error
338
- break;
326
+ if (typeof json == "string") {
327
+ if (json === "") {
328
+ // empty string is not a number
329
+ break;
330
+ }
331
+ if (json.trim().length !== json.length) {
332
+ // extra whitespace
333
+ break;
334
+ }
335
+ const float = Number(json);
336
+ if (!isFinite(float)) {
337
+ // Infinity and NaN must be encoded with string constants
338
+ break;
339
+ }
340
+ return float;
339
341
  }
340
- if (type == ScalarType.FLOAT)
341
- assertFloat32(float);
342
- return float;
342
+ break;
343
343
  // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted.
344
344
  case ScalarType.INT32:
345
345
  case ScalarType.FIXED32:
346
346
  case ScalarType.SFIXED32:
347
347
  case ScalarType.SINT32:
348
348
  case ScalarType.UINT32:
349
- let int32;
350
- if (typeof json == "number")
351
- int32 = json;
352
- else if (typeof json == "string" && json.length > 0) {
353
- if (json.trim().length === json.length)
354
- int32 = Number(json);
349
+ return int32FromJson(json);
350
+ // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
351
+ // Either standard or URL-safe base64 encoding with/without paddings are accepted.
352
+ case ScalarType.BYTES:
353
+ if (typeof json == "string") {
354
+ if (json === "") {
355
+ return new Uint8Array(0);
356
+ }
357
+ try {
358
+ return base64Decode(json);
359
+ }
360
+ catch (e) {
361
+ const message = e instanceof Error ? e.message : String(e);
362
+ throw new FieldError(field, message);
363
+ }
355
364
  }
356
- if (int32 === undefined)
357
- break;
358
- if (type == ScalarType.UINT32 || type == ScalarType.FIXED32)
359
- assertUInt32(int32);
360
- else
361
- assertInt32(int32);
362
- return int32;
363
- // int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted.
364
- case ScalarType.INT64:
365
- case ScalarType.SFIXED64:
366
- case ScalarType.SINT64:
367
- if (typeof json != "number" && typeof json != "string")
368
- break;
369
- return protoInt64.parse(json);
370
- case ScalarType.FIXED64:
371
- case ScalarType.UINT64:
372
- if (typeof json != "number" && typeof json != "string")
373
- break;
374
- return protoInt64.uParse(json);
375
- // bool:
365
+ break;
366
+ }
367
+ return json;
368
+ }
369
+ /**
370
+ * Try to parse a JSON value to a map key for the reflect API.
371
+ *
372
+ * Returns the input if the JSON value cannot be converted.
373
+ */
374
+ function mapKeyFromJson(type, json) {
375
+ switch (type) {
376
376
  case ScalarType.BOOL:
377
- if (typeof json !== "boolean")
378
- break;
379
- return json;
380
- // string:
381
- case ScalarType.STRING:
382
- if (typeof json !== "string") {
383
- break;
384
- }
385
- // A string must always contain UTF-8 encoded or 7-bit ASCII.
386
- if (!getTextEncoding().checkUtf8(json)) {
387
- throw new Error("invalid UTF8");
377
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
378
+ switch (json) {
379
+ case "true":
380
+ return true;
381
+ case "false":
382
+ return false;
388
383
  }
389
384
  return json;
390
- // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings.
391
- // Either standard or URL-safe base64 encoding with/without paddings are accepted.
392
- case ScalarType.BYTES:
393
- if (json === "")
394
- return new Uint8Array(0);
395
- if (typeof json !== "string")
396
- break;
397
- return base64Decode(json);
385
+ case ScalarType.INT32:
386
+ case ScalarType.FIXED32:
387
+ case ScalarType.UINT32:
388
+ case ScalarType.SFIXED32:
389
+ case ScalarType.SINT32:
390
+ return int32FromJson(json);
391
+ default:
392
+ return json;
393
+ }
394
+ }
395
+ /**
396
+ * Try to parse a JSON value to a 32-bit integer for the reflect API.
397
+ *
398
+ * Returns the input if the JSON value cannot be converted.
399
+ */
400
+ function int32FromJson(json) {
401
+ if (typeof json == "string") {
402
+ if (json === "") {
403
+ // empty string is not a number
404
+ return json;
405
+ }
406
+ if (json.trim().length !== json.length) {
407
+ // extra whitespace
408
+ return json;
409
+ }
410
+ const num = Number(json);
411
+ if (Number.isNaN(num)) {
412
+ // not a number
413
+ return json;
414
+ }
415
+ return num;
398
416
  }
399
- throw new Error();
417
+ return json;
400
418
  }
401
419
  function parseJsonString(jsonString, typeName) {
402
420
  try {
403
421
  return JSON.parse(jsonString);
404
422
  }
405
423
  catch (e) {
406
- throw new Error(`cannot decode ${typeName} from JSON: ${e instanceof Error ? e.message : String(e)}`);
424
+ const message = e instanceof Error ? e.message : String(e);
425
+ throw new Error(`cannot decode message ${typeName} from JSON: ${message}`,
426
+ // @ts-expect-error we use the ES2022 error CTOR option "cause" for better stack traces
427
+ { cause: e });
407
428
  }
408
429
  }
409
430
  function tryWktFromJson(msg, jsonValue, opts) {
@@ -439,7 +460,10 @@ function tryWktFromJson(msg, jsonValue, opts) {
439
460
  msg.clear(valueField);
440
461
  }
441
462
  else {
442
- msg.set(valueField, readScalar(valueField.scalar, jsonValue, true));
463
+ const err = msg.set(valueField, scalarFromJson(valueField, jsonValue, true));
464
+ if (err) {
465
+ throw err;
466
+ }
443
467
  }
444
468
  return true;
445
469
  }
@@ -449,7 +473,7 @@ function tryWktFromJson(msg, jsonValue, opts) {
449
473
  function anyFromJson(any, json, opts) {
450
474
  var _a;
451
475
  if (json === null || Array.isArray(json) || typeof json != "object") {
452
- throw new Error(`cannot decode message ${any.$typeName} from JSON: expected object but got ${json === null ? "null" : Array.isArray(json) ? "array" : typeof json}`);
476
+ throw new Error(`cannot decode message ${any.$typeName} from JSON: expected object but got ${formatVal(json)}`);
453
477
  }
454
478
  if (Object.keys(json).length == 0) {
455
479
  return;
@@ -458,7 +482,13 @@ function anyFromJson(any, json, opts) {
458
482
  if (typeof typeUrl != "string" || typeUrl == "") {
459
483
  throw new Error(`cannot decode message ${any.$typeName} from JSON: "@type" is empty`);
460
484
  }
461
- const typeName = typeUrlToName(typeUrl), desc = (_a = opts.registry) === null || _a === void 0 ? void 0 : _a.getMessage(typeName);
485
+ const typeName = typeUrl.includes("/")
486
+ ? typeUrl.substring(typeUrl.lastIndexOf("/") + 1)
487
+ : typeUrl;
488
+ if (!typeName.length) {
489
+ throw new Error(`cannot decode message ${any.$typeName} from JSON: "@type" is invalid`);
490
+ }
491
+ const desc = (_a = opts.registry) === null || _a === void 0 ? void 0 : _a.getMessage(typeName);
462
492
  if (!desc) {
463
493
  throw new Error(`cannot decode message ${any.$typeName} from JSON: ${typeUrl} is not in the type registry`);
464
494
  }
@@ -477,17 +507,17 @@ function anyFromJson(any, json, opts) {
477
507
  }
478
508
  function timestampFromJson(timestamp, json) {
479
509
  if (typeof json !== "string") {
480
- throw new Error(`cannot decode ${timestamp.$typeName} from JSON: ${formatVal(json)}`);
510
+ throw new Error(`cannot decode message ${timestamp.$typeName} from JSON: ${formatVal(json)}`);
481
511
  }
482
512
  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]))$/);
483
513
  if (!matches) {
484
- throw new Error(`cannot decode ${timestamp.$typeName} from JSON: invalid RFC 3339 string`);
514
+ throw new Error(`cannot decode message ${timestamp.$typeName} from JSON: invalid RFC 3339 string`);
485
515
  }
486
516
  const ms = Date.parse(
487
517
  //prettier-ignore
488
518
  matches[1] + "-" + matches[2] + "-" + matches[3] + "T" + matches[4] + ":" + matches[5] + ":" + matches[6] + (matches[8] ? matches[8] : "Z"));
489
519
  if (Number.isNaN(ms)) {
490
- throw new Error(`cannot decode ${timestamp.$typeName} from JSON: invalid RFC 3339 string`);
520
+ throw new Error(`cannot decode message ${timestamp.$typeName} from JSON: invalid RFC 3339 string`);
491
521
  }
492
522
  if (ms < Date.parse("0001-01-01T00:00:00Z") ||
493
523
  ms > Date.parse("9999-12-31T23:59:59Z")) {
@@ -503,15 +533,15 @@ function timestampFromJson(timestamp, json) {
503
533
  }
504
534
  function durationFromJson(duration, json) {
505
535
  if (typeof json !== "string") {
506
- throw new Error(`cannot decode ${duration.$typeName} from JSON: ${formatVal(json)}`);
536
+ throw new Error(`cannot decode message ${duration.$typeName} from JSON: ${formatVal(json)}`);
507
537
  }
508
538
  const match = json.match(/^(-?[0-9]+)(?:\.([0-9]+))?s/);
509
539
  if (match === null) {
510
- throw new Error(`cannot decode ${duration.$typeName} from JSON: ${formatVal(json)}`);
540
+ throw new Error(`cannot decode message ${duration.$typeName} from JSON: ${formatVal(json)}`);
511
541
  }
512
542
  const longSeconds = Number(match[1]);
513
543
  if (longSeconds > 315576000000 || longSeconds < -315576000000) {
514
- throw new Error(`cannot decode ${duration.$typeName} from JSON: ${formatVal(json)}`);
544
+ throw new Error(`cannot decode message ${duration.$typeName} from JSON: ${formatVal(json)}`);
515
545
  }
516
546
  duration.seconds = protoInt64.parse(longSeconds);
517
547
  if (typeof match[2] !== "string") {
@@ -525,14 +555,14 @@ function durationFromJson(duration, json) {
525
555
  }
526
556
  function fieldMaskFromJson(fieldMask, json) {
527
557
  if (typeof json !== "string") {
528
- throw new Error(`cannot decode ${fieldMask.$typeName} from JSON: ${formatVal(json)}`);
558
+ throw new Error(`cannot decode message ${fieldMask.$typeName} from JSON: ${formatVal(json)}`);
529
559
  }
530
560
  if (json === "") {
531
561
  return;
532
562
  }
533
563
  function camelToSnake(str) {
534
564
  if (str.includes("_")) {
535
- throw new Error(`cannot decode ${fieldMask.$typeName} from JSON: path names must be lowerCamelCase`);
565
+ throw new Error(`cannot decode message ${fieldMask.$typeName} from JSON: path names must be lowerCamelCase`);
536
566
  }
537
567
  const sc = str.replace(/[A-Z]/g, (letter) => "_" + letter.toLowerCase());
538
568
  return sc[0] === "_" ? sc.substring(1) : sc;
@@ -541,7 +571,7 @@ function fieldMaskFromJson(fieldMask, json) {
541
571
  }
542
572
  function structFromJson(struct, json) {
543
573
  if (typeof json != "object" || json == null || Array.isArray(json)) {
544
- throw new Error(`cannot decode ${struct.$typeName} from JSON ${formatVal(json)}`);
574
+ throw new Error(`cannot decode message ${struct.$typeName} from JSON ${formatVal(json)}`);
545
575
  }
546
576
  for (const [k, v] of Object.entries(json)) {
547
577
  const parsedV = create(ValueDesc);
@@ -576,13 +606,13 @@ function valueFromJson(value, json) {
576
606
  }
577
607
  break;
578
608
  default:
579
- throw new Error(`cannot decode ${value.$typeName} from JSON ${formatVal(json)}`);
609
+ throw new Error(`cannot decode message ${value.$typeName} from JSON ${formatVal(json)}`);
580
610
  }
581
611
  return value;
582
612
  }
583
613
  function listValueFromJson(listValue, json) {
584
614
  if (!Array.isArray(json)) {
585
- throw new Error(`cannot decode ${listValue.$typeName} from JSON ${formatVal(json)}`);
615
+ throw new Error(`cannot decode message ${listValue.$typeName} from JSON ${formatVal(json)}`);
586
616
  }
587
617
  for (const e of json) {
588
618
  const value = create(ValueDesc);
@@ -590,14 +620,3 @@ function listValueFromJson(listValue, json) {
590
620
  listValue.values.push(value);
591
621
  }
592
622
  }
593
- function typeUrlToName(url) {
594
- if (!url.length) {
595
- throw new Error(`invalid type url: ${url}`);
596
- }
597
- const slash = url.lastIndexOf("/");
598
- const name = slash >= 0 ? url.substring(slash + 1) : url;
599
- if (!name.length) {
600
- throw new Error(`invalid type url: ${url}`);
601
- }
602
- return name;
603
- }
@@ -2,9 +2,10 @@ export * from "./types.js";
2
2
  export * from "./is-message.js";
3
3
  export * from "./create.js";
4
4
  export * from "./clone.js";
5
- export * from "./desc-types.js";
5
+ export * from "./descriptors.js";
6
6
  export * from "./equals.js";
7
7
  export * from "./fields.js";
8
+ export * from "./registry.js";
8
9
  export type { JsonValue, JsonObject } from "./json-value.js";
9
10
  export { toBinary } from "./to-binary.js";
10
11
  export type { BinaryWriteOptions } from "./to-binary.js";
package/dist/esm/index.js CHANGED
@@ -15,9 +15,10 @@ export * from "./types.js";
15
15
  export * from "./is-message.js";
16
16
  export * from "./create.js";
17
17
  export * from "./clone.js";
18
- export * from "./desc-types.js";
18
+ export * from "./descriptors.js";
19
19
  export * from "./equals.js";
20
20
  export * from "./fields.js";
21
+ export * from "./registry.js";
21
22
  export { toBinary } from "./to-binary.js";
22
23
  export { fromBinary, mergeFromBinary } from "./from-binary.js";
23
24
  export * from "./to-json.js";
@@ -1,5 +1,5 @@
1
1
  import type { MessageShape } from "./types.js";
2
- import type { DescMessage } from "./desc-types.js";
2
+ import type { DescMessage } from "./descriptors.js";
3
3
  /**
4
4
  * Determine whether the given `arg` is a message.
5
5
  * If `desc` is set, determine whether `arg` is this specific message.
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Int64Support for the current environment.
3
+ */
4
+ export declare const protoInt64: Int64Support;
1
5
  /**
2
6
  * We use the `bigint` primitive to represent 64-bit integral types. If bigint
3
7
  * is unavailable, we fall back to a string representation, which means that
@@ -91,5 +95,4 @@ interface Int64Support {
91
95
  */
92
96
  uDec(lo: number, hi: number): bigint;
93
97
  }
94
- export declare const protoInt64: Int64Support;
95
98
  export {};