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

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