@bufbuild/protobuf 2.12.0 → 2.13.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 (224) hide show
  1. package/README.md +5 -5
  2. package/dist/commonjs/codegenv1/boot.d.ts +1 -0
  3. package/dist/{cjs/codegenv1/types.js → commonjs/codegenv1/boot.js} +3 -7
  4. package/dist/{cjs → commonjs}/codegenv1/symbols.d.ts +5 -0
  5. package/dist/{cjs → commonjs}/codegenv1/types.d.ts +9 -5
  6. package/dist/commonjs/codegenv2/enum.d.ts +29 -0
  7. package/dist/{cjs → commonjs}/codegenv2/enum.js +18 -0
  8. package/dist/{cjs → commonjs}/codegenv2/symbols.d.ts +10 -0
  9. package/dist/{cjs → commonjs}/codegenv2/symbols.js +2 -0
  10. package/dist/{cjs → commonjs}/codegenv2/types.d.ts +9 -5
  11. package/dist/{cjs → commonjs}/create.js +3 -3
  12. package/dist/{cjs → commonjs}/descriptors.d.ts +2 -2
  13. package/dist/{cjs → commonjs}/equals.d.ts +8 -3
  14. package/dist/{cjs → commonjs}/equals.js +8 -3
  15. package/dist/{cjs → commonjs}/extensions.d.ts +2 -1
  16. package/dist/{cjs → commonjs}/extensions.js +3 -4
  17. package/dist/{cjs → commonjs}/from-binary.d.ts +16 -2
  18. package/dist/{cjs → commonjs}/from-binary.js +30 -24
  19. package/dist/{cjs → commonjs}/from-json.d.ts +19 -2
  20. package/dist/{cjs → commonjs}/from-json.js +174 -54
  21. package/dist/{cjs → commonjs}/index.d.ts +1 -0
  22. package/dist/{cjs → commonjs}/index.js +1 -0
  23. package/dist/commonjs/json-value.js +15 -0
  24. package/dist/commonjs/package.json +4 -0
  25. package/dist/{cjs → commonjs}/proto-int64.js +1 -0
  26. package/dist/{cjs → commonjs}/reflect/reflect-check.js +3 -1
  27. package/dist/{cjs → commonjs}/reflect/reflect.js +3 -2
  28. package/dist/commonjs/reflect/scalar.d.ts +43 -0
  29. package/dist/{cjs → commonjs}/reflect/scalar.js +33 -6
  30. package/dist/{cjs → commonjs}/reflect/unsafe.js +1 -1
  31. package/dist/{cjs → commonjs}/registry.js +20 -20
  32. package/dist/{cjs → commonjs}/to-binary.js +1 -1
  33. package/dist/{cjs → commonjs}/to-json.js +2 -2
  34. package/dist/commonjs/txtpb/from-text.d.ts +35 -0
  35. package/dist/commonjs/txtpb/from-text.js +684 -0
  36. package/dist/commonjs/txtpb/index.d.ts +4 -0
  37. package/dist/commonjs/txtpb/index.js +21 -0
  38. package/dist/commonjs/txtpb/is-group-like.d.ts +19 -0
  39. package/dist/commonjs/txtpb/is-group-like.js +47 -0
  40. package/dist/commonjs/txtpb/reader.d.ts +91 -0
  41. package/dist/commonjs/txtpb/reader.js +481 -0
  42. package/dist/commonjs/txtpb/to-text.d.ts +34 -0
  43. package/dist/commonjs/txtpb/to-text.js +358 -0
  44. package/dist/commonjs/txtpb/writer.d.ts +76 -0
  45. package/dist/commonjs/txtpb/writer.js +220 -0
  46. package/dist/{cjs → commonjs}/types.d.ts +7 -0
  47. package/dist/{cjs/codegenv2 → commonjs}/types.js +0 -7
  48. package/dist/commonjs/unknown-enum.d.ts +10 -0
  49. package/dist/commonjs/unknown-enum.js +26 -0
  50. package/dist/{cjs → commonjs}/wire/binary-encoding.d.ts +4 -2
  51. package/dist/{cjs → commonjs}/wire/binary-encoding.js +8 -3
  52. package/dist/{cjs → commonjs}/wire/size-delimited.d.ts +19 -1
  53. package/dist/{cjs → commonjs}/wire/size-delimited.js +54 -16
  54. package/dist/esm/codegenv1/boot.d.ts +1 -0
  55. package/dist/esm/codegenv1/boot.js +14 -0
  56. package/dist/esm/codegenv1/symbols.d.ts +5 -0
  57. package/dist/esm/codegenv1/types.d.ts +9 -5
  58. package/dist/esm/codegenv1/types.js +0 -7
  59. package/dist/esm/codegenv2/enum.d.ts +15 -4
  60. package/dist/esm/codegenv2/enum.js +17 -0
  61. package/dist/esm/codegenv2/symbols.d.ts +10 -0
  62. package/dist/esm/codegenv2/symbols.js +2 -0
  63. package/dist/esm/codegenv2/types.d.ts +9 -5
  64. package/dist/esm/codegenv2/types.js +0 -7
  65. package/dist/esm/create.js +3 -3
  66. package/dist/esm/descriptors.d.ts +2 -2
  67. package/dist/esm/equals.d.ts +8 -3
  68. package/dist/esm/equals.js +8 -3
  69. package/dist/esm/extensions.d.ts +2 -1
  70. package/dist/esm/extensions.js +4 -5
  71. package/dist/esm/from-binary.d.ts +16 -2
  72. package/dist/esm/from-binary.js +29 -24
  73. package/dist/esm/from-json.d.ts +19 -2
  74. package/dist/esm/from-json.js +174 -54
  75. package/dist/esm/index.d.ts +1 -0
  76. package/dist/esm/index.js +1 -0
  77. package/dist/esm/package.json +4 -0
  78. package/dist/esm/proto-int64.js +1 -0
  79. package/dist/esm/reflect/reflect-check.js +3 -1
  80. package/dist/esm/reflect/reflect.js +3 -2
  81. package/dist/esm/reflect/scalar.d.ts +27 -5
  82. package/dist/esm/reflect/scalar.js +33 -6
  83. package/dist/esm/reflect/unsafe.js +1 -1
  84. package/dist/esm/registry.js +20 -20
  85. package/dist/esm/to-binary.js +1 -1
  86. package/dist/esm/to-json.js +2 -2
  87. package/dist/esm/txtpb/from-text.d.ts +35 -0
  88. package/dist/esm/txtpb/from-text.js +680 -0
  89. package/dist/esm/txtpb/index.d.ts +4 -0
  90. package/dist/esm/txtpb/index.js +15 -0
  91. package/dist/esm/txtpb/is-group-like.d.ts +19 -0
  92. package/dist/esm/txtpb/is-group-like.js +44 -0
  93. package/dist/esm/txtpb/reader.d.ts +91 -0
  94. package/dist/esm/txtpb/reader.js +477 -0
  95. package/dist/esm/txtpb/to-text.d.ts +34 -0
  96. package/dist/esm/txtpb/to-text.js +355 -0
  97. package/dist/esm/txtpb/writer.d.ts +76 -0
  98. package/dist/esm/txtpb/writer.js +214 -0
  99. package/dist/esm/types.d.ts +7 -0
  100. package/dist/esm/unknown-enum.d.ts +10 -0
  101. package/dist/esm/unknown-enum.js +23 -0
  102. package/dist/esm/wire/binary-encoding.d.ts +4 -2
  103. package/dist/esm/wire/binary-encoding.js +8 -3
  104. package/dist/esm/wire/size-delimited.d.ts +19 -1
  105. package/dist/esm/wire/size-delimited.js +54 -16
  106. package/package.json +109 -30
  107. package/dist/cjs/codegenv2/enum.d.ts +0 -18
  108. package/dist/cjs/package.json +0 -1
  109. package/dist/cjs/reflect/scalar.d.ts +0 -21
  110. /package/dist/{cjs → commonjs}/clone.d.ts +0 -0
  111. /package/dist/{cjs → commonjs}/clone.js +0 -0
  112. /package/dist/{cjs → commonjs}/codegenv1/enum.d.ts +0 -0
  113. /package/dist/{cjs → commonjs}/codegenv1/enum.js +0 -0
  114. /package/dist/{cjs → commonjs}/codegenv1/extension.d.ts +0 -0
  115. /package/dist/{cjs → commonjs}/codegenv1/extension.js +0 -0
  116. /package/dist/{cjs → commonjs}/codegenv1/file.d.ts +0 -0
  117. /package/dist/{cjs → commonjs}/codegenv1/file.js +0 -0
  118. /package/dist/{cjs → commonjs}/codegenv1/index.d.ts +0 -0
  119. /package/dist/{cjs → commonjs}/codegenv1/index.js +0 -0
  120. /package/dist/{cjs → commonjs}/codegenv1/message.d.ts +0 -0
  121. /package/dist/{cjs → commonjs}/codegenv1/message.js +0 -0
  122. /package/dist/{cjs → commonjs}/codegenv1/service.d.ts +0 -0
  123. /package/dist/{cjs → commonjs}/codegenv1/service.js +0 -0
  124. /package/dist/{cjs → commonjs}/codegenv1/symbols.js +0 -0
  125. /package/dist/{cjs → commonjs/codegenv1}/types.js +0 -0
  126. /package/dist/{cjs → commonjs}/codegenv2/boot.d.ts +0 -0
  127. /package/dist/{cjs → commonjs}/codegenv2/boot.js +0 -0
  128. /package/dist/{cjs → commonjs}/codegenv2/embed.d.ts +0 -0
  129. /package/dist/{cjs → commonjs}/codegenv2/embed.js +0 -0
  130. /package/dist/{cjs → commonjs}/codegenv2/extension.d.ts +0 -0
  131. /package/dist/{cjs → commonjs}/codegenv2/extension.js +0 -0
  132. /package/dist/{cjs → commonjs}/codegenv2/file.d.ts +0 -0
  133. /package/dist/{cjs → commonjs}/codegenv2/file.js +0 -0
  134. /package/dist/{cjs → commonjs}/codegenv2/index.d.ts +0 -0
  135. /package/dist/{cjs → commonjs}/codegenv2/index.js +0 -0
  136. /package/dist/{cjs → commonjs}/codegenv2/message.d.ts +0 -0
  137. /package/dist/{cjs → commonjs}/codegenv2/message.js +0 -0
  138. /package/dist/{cjs → commonjs}/codegenv2/restore-json-names.d.ts +0 -0
  139. /package/dist/{cjs → commonjs}/codegenv2/restore-json-names.js +0 -0
  140. /package/dist/{cjs → commonjs}/codegenv2/scalar.d.ts +0 -0
  141. /package/dist/{cjs → commonjs}/codegenv2/scalar.js +0 -0
  142. /package/dist/{cjs → commonjs}/codegenv2/service.d.ts +0 -0
  143. /package/dist/{cjs → commonjs}/codegenv2/service.js +0 -0
  144. /package/dist/{cjs/json-value.js → commonjs/codegenv2/types.js} +0 -0
  145. /package/dist/{cjs → commonjs}/create.d.ts +0 -0
  146. /package/dist/{cjs → commonjs}/descriptors.js +0 -0
  147. /package/dist/{cjs → commonjs}/fields.d.ts +0 -0
  148. /package/dist/{cjs → commonjs}/fields.js +0 -0
  149. /package/dist/{cjs → commonjs}/is-message.d.ts +0 -0
  150. /package/dist/{cjs → commonjs}/is-message.js +0 -0
  151. /package/dist/{cjs → commonjs}/json-value.d.ts +0 -0
  152. /package/dist/{cjs → commonjs}/merge.d.ts +0 -0
  153. /package/dist/{cjs → commonjs}/merge.js +0 -0
  154. /package/dist/{cjs → commonjs}/proto-int64.d.ts +0 -0
  155. /package/dist/{cjs → commonjs}/reflect/error.d.ts +0 -0
  156. /package/dist/{cjs → commonjs}/reflect/error.js +0 -0
  157. /package/dist/{cjs → commonjs}/reflect/guard.d.ts +0 -0
  158. /package/dist/{cjs → commonjs}/reflect/guard.js +0 -0
  159. /package/dist/{cjs → commonjs}/reflect/index.d.ts +0 -0
  160. /package/dist/{cjs → commonjs}/reflect/index.js +0 -0
  161. /package/dist/{cjs → commonjs}/reflect/names.d.ts +0 -0
  162. /package/dist/{cjs → commonjs}/reflect/names.js +0 -0
  163. /package/dist/{cjs → commonjs}/reflect/nested-types.d.ts +0 -0
  164. /package/dist/{cjs → commonjs}/reflect/nested-types.js +0 -0
  165. /package/dist/{cjs → commonjs}/reflect/path.d.ts +0 -0
  166. /package/dist/{cjs → commonjs}/reflect/path.js +0 -0
  167. /package/dist/{cjs → commonjs}/reflect/reflect-check.d.ts +0 -0
  168. /package/dist/{cjs → commonjs}/reflect/reflect-types.d.ts +0 -0
  169. /package/dist/{cjs → commonjs}/reflect/reflect-types.js +0 -0
  170. /package/dist/{cjs → commonjs}/reflect/reflect.d.ts +0 -0
  171. /package/dist/{cjs → commonjs}/reflect/unsafe.d.ts +0 -0
  172. /package/dist/{cjs → commonjs}/registry.d.ts +0 -0
  173. /package/dist/{cjs → commonjs}/to-binary.d.ts +0 -0
  174. /package/dist/{cjs → commonjs}/to-json.d.ts +0 -0
  175. /package/dist/{cjs → commonjs}/wire/base64-encoding.d.ts +0 -0
  176. /package/dist/{cjs → commonjs}/wire/base64-encoding.js +0 -0
  177. /package/dist/{cjs → commonjs}/wire/index.d.ts +0 -0
  178. /package/dist/{cjs → commonjs}/wire/index.js +0 -0
  179. /package/dist/{cjs → commonjs}/wire/text-encoding.d.ts +0 -0
  180. /package/dist/{cjs → commonjs}/wire/text-encoding.js +0 -0
  181. /package/dist/{cjs → commonjs}/wire/text-format.d.ts +0 -0
  182. /package/dist/{cjs → commonjs}/wire/text-format.js +0 -0
  183. /package/dist/{cjs → commonjs}/wire/varint.d.ts +0 -0
  184. /package/dist/{cjs → commonjs}/wire/varint.js +0 -0
  185. /package/dist/{cjs → commonjs}/wkt/any.d.ts +0 -0
  186. /package/dist/{cjs → commonjs}/wkt/any.js +0 -0
  187. /package/dist/{cjs → commonjs}/wkt/duration.d.ts +0 -0
  188. /package/dist/{cjs → commonjs}/wkt/duration.js +0 -0
  189. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/any_pb.d.ts +0 -0
  190. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/any_pb.js +0 -0
  191. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/api_pb.d.ts +0 -0
  192. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/api_pb.js +0 -0
  193. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/compiler/plugin_pb.d.ts +0 -0
  194. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/compiler/plugin_pb.js +0 -0
  195. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/cpp_features_pb.d.ts +0 -0
  196. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/cpp_features_pb.js +0 -0
  197. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/descriptor_pb.d.ts +0 -0
  198. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/descriptor_pb.js +0 -0
  199. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/duration_pb.d.ts +0 -0
  200. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/duration_pb.js +0 -0
  201. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/empty_pb.d.ts +0 -0
  202. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/empty_pb.js +0 -0
  203. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/field_mask_pb.d.ts +0 -0
  204. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/field_mask_pb.js +0 -0
  205. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/go_features_pb.d.ts +0 -0
  206. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/go_features_pb.js +0 -0
  207. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/java_features_pb.d.ts +0 -0
  208. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/java_features_pb.js +0 -0
  209. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/source_context_pb.d.ts +0 -0
  210. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/source_context_pb.js +0 -0
  211. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/struct_pb.d.ts +0 -0
  212. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/struct_pb.js +0 -0
  213. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/timestamp_pb.d.ts +0 -0
  214. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/timestamp_pb.js +0 -0
  215. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/type_pb.d.ts +0 -0
  216. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/type_pb.js +0 -0
  217. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/wrappers_pb.d.ts +0 -0
  218. /package/dist/{cjs → commonjs}/wkt/gen/google/protobuf/wrappers_pb.js +0 -0
  219. /package/dist/{cjs → commonjs}/wkt/index.d.ts +0 -0
  220. /package/dist/{cjs → commonjs}/wkt/index.js +0 -0
  221. /package/dist/{cjs → commonjs}/wkt/timestamp.d.ts +0 -0
  222. /package/dist/{cjs → commonjs}/wkt/timestamp.js +0 -0
  223. /package/dist/{cjs → commonjs}/wkt/wrappers.d.ts +0 -0
  224. /package/dist/{cjs → commonjs}/wkt/wrappers.js +0 -0
@@ -29,38 +29,42 @@ const names_js_1 = require("./reflect/names.js");
29
29
  const base64_encoding_js_1 = require("./wire/base64-encoding.js");
30
30
  const index_js_1 = require("./wkt/index.js");
31
31
  const extensions_js_1 = require("./extensions.js");
32
- // Default options for parsing JSON.
33
- const jsonReadDefaults = {
34
- ignoreUnknownFields: false,
35
- };
36
- function makeReadOptions(options) {
37
- return options ? Object.assign(Object.assign({}, jsonReadDefaults), options) : jsonReadDefaults;
32
+ function makeReadContext(options) {
33
+ return Object.assign(Object.assign({ ignoreUnknownFields: false, recursionLimit: 100 }, options), { depth: 0 });
38
34
  }
39
35
  /**
40
36
  * Parse a message from a JSON string.
37
+ *
38
+ * Duplicate keys are rejected.
41
39
  */
42
40
  function fromJsonString(schema, json, options) {
43
41
  return fromJson(schema, parseJsonString(json, schema.typeName), options);
44
42
  }
45
43
  /**
46
- * Parse a message from a JSON string, merging fields.
44
+ * Parse a message from a JSON string, merging fields into the target.
47
45
  *
48
46
  * Repeated fields are appended. Map entries are added, overwriting
49
47
  * existing keys.
50
48
  *
51
49
  * If a message field is already present, it will be merged with the
52
50
  * new data.
51
+ *
52
+ * Duplicate keys in the JSON are rejected, as in `fromJsonString`.
53
53
  */
54
54
  function mergeFromJsonString(schema, target, json, options) {
55
55
  return mergeFromJson(schema, target, parseJsonString(json, schema.typeName), options);
56
56
  }
57
57
  /**
58
58
  * Parse a message from a JSON value.
59
+ *
60
+ * Duplicate keys are rejected, but a value parsed by JSON.parse has already
61
+ * dropped duplicates (the last one wins). Use `fromJsonString` for strict
62
+ * duplicate-key checking.
59
63
  */
60
64
  function fromJson(schema, json, options) {
61
65
  const msg = (0, reflect_js_1.reflect)(schema);
62
66
  try {
63
- readMessage(msg, json, makeReadOptions(options));
67
+ readMessage(msg, json, makeReadContext(options));
64
68
  }
65
69
  catch (e) {
66
70
  if ((0, error_js_1.isFieldError)(e)) {
@@ -74,17 +78,20 @@ function fromJson(schema, json, options) {
74
78
  return msg.message;
75
79
  }
76
80
  /**
77
- * Parse a message from a JSON value, merging fields.
81
+ * Parse a message from a JSON value, merging fields into the target.
78
82
  *
79
83
  * Repeated fields are appended. Map entries are added, overwriting
80
84
  * existing keys.
81
85
  *
82
86
  * If a message field is already present, it will be merged with the
83
87
  * new data.
88
+ *
89
+ * Duplicate keys are rejected as in `fromJson`; use `mergeFromJsonString`
90
+ * for strict checking.
84
91
  */
85
92
  function mergeFromJson(schema, target, json, options) {
86
93
  try {
87
- readMessage((0, reflect_js_1.reflect)(schema, target), json, makeReadOptions(options));
94
+ readMessage((0, reflect_js_1.reflect)(schema, target), json, makeReadContext(options));
88
95
  }
89
96
  catch (e) {
90
97
  if ((0, error_js_1.isFieldError)(e)) {
@@ -121,82 +128,95 @@ function getJsonField(desc, jsonKey) {
121
128
  }
122
129
  return (_a = messageJsonFields.get(desc)) === null || _a === void 0 ? void 0 : _a.get(jsonKey);
123
130
  }
124
- function readMessage(msg, json, opts) {
131
+ function readMessage(msg, json, ctx) {
125
132
  var _a;
126
- if (tryWktFromJson(msg, json, opts)) {
133
+ if (++ctx.depth > ctx.recursionLimit) {
134
+ throw new Error(`cannot decode ${msg.desc} from JSON: maximum recursion depth of ${ctx.recursionLimit} reached`);
135
+ }
136
+ if (tryWktFromJson(msg, json, ctx)) {
137
+ ctx.depth--;
127
138
  return;
128
139
  }
129
140
  if (json == null || Array.isArray(json) || typeof json != "object") {
130
141
  throw new Error(`cannot decode ${msg.desc} from JSON: ${(0, reflect_check_js_1.formatVal)(json)}`);
131
142
  }
132
143
  const oneofSeen = new Map();
144
+ const fieldSeen = new Set();
133
145
  for (const [jsonKey, jsonValue] of Object.entries(json)) {
134
146
  const field = getJsonField(msg.desc, jsonKey);
135
147
  if (field) {
148
+ if (fieldSeen.has(field)) {
149
+ // The same field may be set by its proto name and its JSON name, or by
150
+ // a duplicate or unicode-escaped key that JSON.parse already collapsed.
151
+ // Checked before the null-skip below so that a null entry still counts.
152
+ throw new error_js_1.FieldError(field, "set multiple times");
153
+ }
154
+ fieldSeen.add(field);
155
+ if (field.oneof && jsonValue === null && field.fieldKind == "scalar") {
156
+ // see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
157
+ continue;
158
+ }
136
159
  if (field.oneof) {
137
- if (jsonValue === null && field.fieldKind == "scalar") {
138
- // see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
139
- continue;
140
- }
141
160
  const seen = oneofSeen.get(field.oneof);
142
161
  if (seen !== undefined) {
143
162
  throw new error_js_1.FieldError(field.oneof, `oneof set multiple times by ${seen.name} and ${field.name}`);
144
163
  }
145
164
  oneofSeen.set(field.oneof, field);
146
165
  }
147
- readField(msg, field, jsonValue, opts);
166
+ readField(msg, field, jsonValue, ctx);
148
167
  }
149
168
  else {
150
169
  let extension = undefined;
151
170
  if (jsonKey.startsWith("[") &&
152
171
  jsonKey.endsWith("]") &&
153
172
  // biome-ignore lint/suspicious/noAssignInExpressions: no
154
- (extension = (_a = opts.registry) === null || _a === void 0 ? void 0 : _a.getExtension(jsonKey.substring(1, jsonKey.length - 1))) &&
173
+ (extension = (_a = ctx.registry) === null || _a === void 0 ? void 0 : _a.getExtension(jsonKey.substring(1, jsonKey.length - 1))) &&
155
174
  extension.extendee.typeName === msg.desc.typeName) {
156
175
  const [container, field, get] = (0, extensions_js_1.createExtensionContainer)(extension);
157
- readField(container, field, jsonValue, opts);
176
+ readField(container, field, jsonValue, ctx);
158
177
  (0, extensions_js_1.setExtension)(msg.message, extension, get());
159
178
  }
160
- if (!extension && !opts.ignoreUnknownFields) {
179
+ if (!extension && !ctx.ignoreUnknownFields) {
161
180
  throw new Error(`cannot decode ${msg.desc} from JSON: key "${jsonKey}" is unknown`);
162
181
  }
163
182
  }
164
183
  }
184
+ ctx.depth--;
165
185
  }
166
- function readField(msg, field, json, opts) {
186
+ function readField(msg, field, json, ctx) {
167
187
  switch (field.fieldKind) {
168
188
  case "scalar":
169
189
  readScalarField(msg, field, json);
170
190
  break;
171
191
  case "enum":
172
- readEnumField(msg, field, json, opts);
192
+ readEnumField(msg, field, json, ctx);
173
193
  break;
174
194
  case "message":
175
- readMessageField(msg, field, json, opts);
195
+ readMessageField(msg, field, json, ctx);
176
196
  break;
177
197
  case "list":
178
- readListField(msg.get(field), json, opts);
198
+ readListField(msg.get(field), json, ctx);
179
199
  break;
180
200
  case "map":
181
- readMapField(msg.get(field), json, opts);
201
+ readMapField(msg.get(field), json, ctx);
182
202
  break;
183
203
  }
184
204
  }
185
- function readListOrMapItem(field, json, opts) {
205
+ function readListOrMapItem(field, json, ctx) {
186
206
  if (field.scalar && json !== null) {
187
207
  return scalarFromJson(field, json);
188
208
  }
189
209
  if (field.message && !isResetSentinelNullValue(field, json)) {
190
210
  const msgValue = (0, reflect_js_1.reflect)(field.message);
191
- readMessage(msgValue, json, opts);
211
+ readMessage(msgValue, json, ctx);
192
212
  return msgValue;
193
213
  }
194
214
  if (field.enum && !isResetSentinelNullValue(field, json)) {
195
- return readEnum(field.enum, json, opts.ignoreUnknownFields);
215
+ return readEnum(field.enum, json, ctx.ignoreUnknownFields);
196
216
  }
197
217
  throw new error_js_1.FieldError(field, `${field.fieldKind === "list" ? "list item" : "map value"} must not be null`);
198
218
  }
199
- function readMapField(map, json, opts) {
219
+ function readMapField(map, json, ctx) {
200
220
  if (json === null) {
201
221
  return;
202
222
  }
@@ -204,15 +224,20 @@ function readMapField(map, json, opts) {
204
224
  if (typeof json != "object" || Array.isArray(json)) {
205
225
  throw new error_js_1.FieldError(field, "expected object, got " + (0, reflect_check_js_1.formatVal)(json));
206
226
  }
227
+ const seen = new Set();
207
228
  for (const [jsonMapKey, jsonMapValue] of Object.entries(json)) {
208
229
  const key = mapKeyFromJson(field.mapKey, jsonMapKey);
209
- const value = readListOrMapItem(field, jsonMapValue, opts);
230
+ if (seen.has(key)) {
231
+ throw new error_js_1.FieldError(field, `duplicate map key "${jsonMapKey}"`);
232
+ }
233
+ seen.add(key);
234
+ const value = readListOrMapItem(field, jsonMapValue, ctx);
210
235
  if (value !== tokenIgnoredUnknownEnum) {
211
236
  map.set(key, value);
212
237
  }
213
238
  }
214
239
  }
215
- function readListField(list, json, opts) {
240
+ function readListField(list, json, ctx) {
216
241
  if (json === null) {
217
242
  return;
218
243
  }
@@ -221,27 +246,27 @@ function readListField(list, json, opts) {
221
246
  throw new error_js_1.FieldError(field, "expected Array, got " + (0, reflect_check_js_1.formatVal)(json));
222
247
  }
223
248
  for (const jsonItem of json) {
224
- const value = readListOrMapItem(field, jsonItem, opts);
249
+ const value = readListOrMapItem(field, jsonItem, ctx);
225
250
  if (value !== tokenIgnoredUnknownEnum) {
226
251
  list.add(value);
227
252
  }
228
253
  }
229
254
  }
230
- function readMessageField(msg, field, json, opts) {
255
+ function readMessageField(msg, field, json, ctx) {
231
256
  if (isResetSentinelNullValue(field, json)) {
232
257
  msg.clear(field);
233
258
  return;
234
259
  }
235
260
  const msgValue = msg.isSet(field) ? msg.get(field) : (0, reflect_js_1.reflect)(field.message);
236
- readMessage(msgValue, json, opts);
261
+ readMessage(msgValue, json, ctx);
237
262
  msg.set(field, msgValue);
238
263
  }
239
- function readEnumField(msg, field, json, opts) {
264
+ function readEnumField(msg, field, json, ctx) {
240
265
  if (isResetSentinelNullValue(field, json)) {
241
266
  msg.clear(field);
242
267
  return;
243
268
  }
244
- const enumValue = readEnum(field.enum, json, opts.ignoreUnknownFields);
269
+ const enumValue = readEnum(field.enum, json, ctx.ignoreUnknownFields);
245
270
  if (enumValue !== tokenIgnoredUnknownEnum) {
246
271
  msg.set(field, enumValue);
247
272
  }
@@ -370,7 +395,8 @@ function scalarFromJson(field, json) {
370
395
  }
371
396
  /**
372
397
  * Try to parse a JSON value to a map key for the reflect API.
373
- *
398
+ * Canonicalizes 64-bit integers given as string, so that "01 and "1" are one
399
+ * key, and duplicates can raise an error.
374
400
  * Returns the input if the JSON value cannot be converted.
375
401
  */
376
402
  function mapKeyFromJson(type, jsonString) {
@@ -389,6 +415,14 @@ function mapKeyFromJson(type, jsonString) {
389
415
  case descriptors_js_1.ScalarType.SFIXED32:
390
416
  case descriptors_js_1.ScalarType.SINT32:
391
417
  return int32FromJson(jsonString);
418
+ case descriptors_js_1.ScalarType.INT64:
419
+ case descriptors_js_1.ScalarType.SINT64:
420
+ case descriptors_js_1.ScalarType.SFIXED64:
421
+ case descriptors_js_1.ScalarType.UINT64:
422
+ case descriptors_js_1.ScalarType.FIXED64:
423
+ return /^-?0+$/.test(jsonString)
424
+ ? "0"
425
+ : jsonString.replace(/^(-?)0+(?=\d)/, "$1");
392
426
  default:
393
427
  return jsonString;
394
428
  }
@@ -417,9 +451,14 @@ function int32FromJson(json) {
417
451
  }
418
452
  return json;
419
453
  }
454
+ /**
455
+ * Parse a JSON string, rejecting duplicate object keys (which JSON.parse would
456
+ * otherwise silently merge).
457
+ */
420
458
  function parseJsonString(jsonString, typeName) {
459
+ let json;
421
460
  try {
422
- return JSON.parse(jsonString);
461
+ json = JSON.parse(jsonString);
423
462
  }
424
463
  catch (e) {
425
464
  const message = e instanceof Error ? e.message : String(e);
@@ -427,14 +466,91 @@ function parseJsonString(jsonString, typeName) {
427
466
  // @ts-expect-error we use the ES2022 error CTOR option "cause" for better stack traces
428
467
  { cause: e });
429
468
  }
469
+ checkDuplicateKeys(jsonString, typeName);
470
+ return json;
430
471
  }
431
- function tryWktFromJson(msg, jsonValue, opts) {
472
+ /**
473
+ * Scan a JSON string for duplicate object member names at any depth, throwing
474
+ * if any are found. JSON.parse() silently keeps the last of duplicate keys, so
475
+ * this raw-string scan is the only way to reject them. It must only be called
476
+ * with a string that JSON.parse() has already accepted, so it can assume the
477
+ * input is well-formed.
478
+ */
479
+ function checkDuplicateKeys(jsonString, typeName) {
480
+ // One Set of seen member names for each open object; arrays push null.
481
+ const stack = [];
482
+ // Whether the next string token is an object member name.
483
+ let expectKey = false;
484
+ let i = 0;
485
+ while (i < jsonString.length) {
486
+ switch (jsonString[i]) {
487
+ case "{":
488
+ stack.push(new Set());
489
+ expectKey = true;
490
+ i++;
491
+ break;
492
+ case "[":
493
+ stack.push(null);
494
+ expectKey = false;
495
+ i++;
496
+ break;
497
+ case "}":
498
+ case "]":
499
+ stack.pop();
500
+ expectKey = false;
501
+ i++;
502
+ break;
503
+ case ",":
504
+ expectKey = stack[stack.length - 1] != null;
505
+ i++;
506
+ break;
507
+ case ":":
508
+ expectKey = false;
509
+ i++;
510
+ break;
511
+ case '"': {
512
+ const open = i++;
513
+ let escaped = false;
514
+ while (i < jsonString.length) {
515
+ if (jsonString[i] == "\\") {
516
+ escaped = true;
517
+ i += 2; // skip the backslash and the character it escapes
518
+ continue;
519
+ }
520
+ if (jsonString[i] == '"') {
521
+ break;
522
+ }
523
+ i++;
524
+ }
525
+ const close = i++;
526
+ const seen = stack[stack.length - 1];
527
+ if (expectKey && seen) {
528
+ // Decode escapes (rare) so that, for example, a key written with a
529
+ // unicode escape collides with the same key written literally.
530
+ const name = escaped
531
+ ? JSON.parse(jsonString.substring(open, close + 1))
532
+ : jsonString.substring(open + 1, close);
533
+ if (seen.has(name)) {
534
+ throw new Error(`cannot decode message ${typeName} from JSON: duplicate object key "${name}"`);
535
+ }
536
+ seen.add(name);
537
+ }
538
+ expectKey = false;
539
+ break;
540
+ }
541
+ default:
542
+ i++;
543
+ break;
544
+ }
545
+ }
546
+ }
547
+ function tryWktFromJson(msg, jsonValue, ctx) {
432
548
  if (!msg.desc.typeName.startsWith("google.protobuf.")) {
433
549
  return false;
434
550
  }
435
551
  switch (msg.desc.typeName) {
436
552
  case "google.protobuf.Any":
437
- anyFromJson(msg.message, jsonValue, opts);
553
+ anyFromJson(msg.message, jsonValue, ctx);
438
554
  return true;
439
555
  case "google.protobuf.Timestamp":
440
556
  timestampFromJson(msg.message, jsonValue);
@@ -446,13 +562,13 @@ function tryWktFromJson(msg, jsonValue, opts) {
446
562
  fieldMaskFromJson(msg.message, jsonValue);
447
563
  return true;
448
564
  case "google.protobuf.Struct":
449
- structFromJson(msg.message, jsonValue);
565
+ structFromJson(msg.message, jsonValue, ctx);
450
566
  return true;
451
567
  case "google.protobuf.Value":
452
- valueFromJson(msg.message, jsonValue);
568
+ valueFromJson(msg.message, jsonValue, ctx);
453
569
  return true;
454
570
  case "google.protobuf.ListValue":
455
- listValueFromJson(msg.message, jsonValue);
571
+ listValueFromJson(msg.message, jsonValue, ctx);
456
572
  return true;
457
573
  default:
458
574
  if ((0, index_js_1.isWrapperDesc)(msg.desc)) {
@@ -468,7 +584,7 @@ function tryWktFromJson(msg, jsonValue, opts) {
468
584
  return false;
469
585
  }
470
586
  }
471
- function anyFromJson(any, json, opts) {
587
+ function anyFromJson(any, json, ctx) {
472
588
  var _a;
473
589
  if (json === null || Array.isArray(json) || typeof json != "object") {
474
590
  throw new Error(`cannot decode message ${any.$typeName} from JSON: expected object but got ${(0, reflect_check_js_1.formatVal)(json)}`);
@@ -486,7 +602,7 @@ function anyFromJson(any, json, opts) {
486
602
  if (!typeName.length) {
487
603
  throw new Error(`cannot decode message ${any.$typeName} from JSON: "@type" is invalid`);
488
604
  }
489
- const desc = (_a = opts.registry) === null || _a === void 0 ? void 0 : _a.getMessage(typeName);
605
+ const desc = (_a = ctx.registry) === null || _a === void 0 ? void 0 : _a.getMessage(typeName);
490
606
  if (!desc) {
491
607
  throw new Error(`cannot decode message ${any.$typeName} from JSON: ${typeUrl} is not in the type registry`);
492
608
  }
@@ -494,13 +610,13 @@ function anyFromJson(any, json, opts) {
494
610
  if ((0, index_js_1.hasCustomJsonRepresentation)(desc) &&
495
611
  Object.prototype.hasOwnProperty.call(json, "value")) {
496
612
  const value = json.value;
497
- readMessage(msg, value, opts);
613
+ readMessage(msg, value, ctx);
498
614
  }
499
615
  else {
500
616
  const copy = Object.assign({}, json);
501
617
  // biome-ignore lint/performance/noDelete: <explanation>
502
618
  delete copy["@type"];
503
- readMessage(msg, copy, opts);
619
+ readMessage(msg, copy, ctx);
504
620
  }
505
621
  (0, index_js_1.anyPack)(msg.desc, msg.message, any);
506
622
  }
@@ -566,17 +682,20 @@ function fieldMaskFromJson(fieldMask, json) {
566
682
  return (0, names_js_1.protoSnakeCase)(path);
567
683
  });
568
684
  }
569
- function structFromJson(struct, json) {
685
+ function structFromJson(struct, json, ctx) {
570
686
  if (typeof json != "object" || json == null || Array.isArray(json)) {
571
687
  throw new Error(`cannot decode message ${struct.$typeName} from JSON ${(0, reflect_check_js_1.formatVal)(json)}`);
572
688
  }
573
689
  for (const [k, v] of Object.entries(json)) {
574
690
  const parsedV = (0, create_js_1.create)(index_js_1.ValueSchema);
575
- valueFromJson(parsedV, v);
691
+ valueFromJson(parsedV, v, ctx);
576
692
  struct.fields[k] = parsedV;
577
693
  }
578
694
  }
579
- function valueFromJson(value, json) {
695
+ function valueFromJson(value, json, ctx) {
696
+ if (++ctx.depth > ctx.recursionLimit) {
697
+ throw new Error(`cannot decode ${value.$typeName} from JSON: maximum recursion depth of ${ctx.recursionLimit} reached`);
698
+ }
580
699
  switch (typeof json) {
581
700
  case "number":
582
701
  value.kind = { case: "numberValue", value: json };
@@ -593,27 +712,28 @@ function valueFromJson(value, json) {
593
712
  }
594
713
  else if (Array.isArray(json)) {
595
714
  const listValue = (0, create_js_1.create)(index_js_1.ListValueSchema);
596
- listValueFromJson(listValue, json);
715
+ listValueFromJson(listValue, json, ctx);
597
716
  value.kind = { case: "listValue", value: listValue };
598
717
  }
599
718
  else {
600
719
  const struct = (0, create_js_1.create)(index_js_1.StructSchema);
601
- structFromJson(struct, json);
720
+ structFromJson(struct, json, ctx);
602
721
  value.kind = { case: "structValue", value: struct };
603
722
  }
604
723
  break;
605
724
  default:
606
725
  throw new Error(`cannot decode message ${value.$typeName} from JSON ${(0, reflect_check_js_1.formatVal)(json)}`);
607
726
  }
727
+ ctx.depth--;
608
728
  return value;
609
729
  }
610
- function listValueFromJson(listValue, json) {
730
+ function listValueFromJson(listValue, json, ctx) {
611
731
  if (!Array.isArray(json)) {
612
732
  throw new Error(`cannot decode message ${listValue.$typeName} from JSON ${(0, reflect_check_js_1.formatVal)(json)}`);
613
733
  }
614
734
  for (const e of json) {
615
735
  const value = (0, create_js_1.create)(index_js_1.ValueSchema);
616
- valueFromJson(value, e);
736
+ valueFromJson(value, e, ctx);
617
737
  listValue.values.push(value);
618
738
  }
619
739
  }
@@ -16,3 +16,4 @@ export * from "./from-json.js";
16
16
  export * from "./merge.js";
17
17
  export { hasExtension, getExtension, setExtension, clearExtension, hasOption, getOption, } from "./extensions.js";
18
18
  export * from "./proto-int64.js";
19
+ export * from "./unknown-enum.js";
@@ -52,3 +52,4 @@ Object.defineProperty(exports, "clearExtension", { enumerable: true, get: functi
52
52
  Object.defineProperty(exports, "hasOption", { enumerable: true, get: function () { return extensions_js_1.hasOption; } });
53
53
  Object.defineProperty(exports, "getOption", { enumerable: true, get: function () { return extensions_js_1.getOption; } });
54
54
  __exportStar(require("./proto-int64.js"), exports);
55
+ __exportStar(require("./unknown-enum.js"), exports);
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ // Copyright 2021-2026 Buf Technologies, Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "commonjs",
3
+ "sideEffects": false
4
+ }
@@ -28,6 +28,7 @@ function makeInt64Support() {
28
28
  typeof dv.setBigInt64 === "function" &&
29
29
  typeof dv.setBigUint64 === "function" &&
30
30
  (!!globalThis.Deno ||
31
+ !!globalThis.Bun ||
31
32
  typeof process != "object" ||
32
33
  typeof process.env != "object" ||
33
34
  process.env.BUF_BIGINT_DISABLE !== "1");
@@ -80,7 +80,9 @@ function checkSingular(field, value) {
80
80
  }
81
81
  if (field.enum !== undefined) {
82
82
  if (field.enum.open) {
83
- return Number.isInteger(value);
83
+ // Open enums accept unrecognized values, but enum values are always
84
+ // int32 (see https://protobuf.dev/programming-guides/proto3/#enum).
85
+ return checkScalarValue(value, descriptors_js_1.ScalarType.INT32);
84
86
  }
85
87
  return field.enum.values.some((v) => v.number === value);
86
88
  }
@@ -25,6 +25,8 @@ const wrappers_js_1 = require("../wkt/wrappers.js");
25
25
  const scalar_js_1 = require("./scalar.js");
26
26
  const proto_int64_js_1 = require("../proto-int64.js");
27
27
  const guard_js_1 = require("./guard.js");
28
+ // google.protobuf.NullValue.NULL_VALUE;
29
+ const NULL_VALUE = 0;
28
30
  /**
29
31
  * Create a ReflectMessage.
30
32
  */
@@ -515,8 +517,7 @@ function wktValueToReflect(json) {
515
517
  break;
516
518
  case "object":
517
519
  if (json === null) {
518
- const nullValue = 0;
519
- value.kind = { case: "nullValue", value: nullValue };
520
+ value.kind = { case: "nullValue", value: NULL_VALUE };
520
521
  }
521
522
  else if (Array.isArray(json)) {
522
523
  const listValue = {
@@ -0,0 +1,43 @@
1
+ import { ScalarType } from "../descriptors.js";
2
+ /**
3
+ * ScalarValue maps from a scalar field type to a TypeScript value type.
4
+ */
5
+ export type ScalarValue<T = ScalarType, LongAsString extends boolean = false> = T extends ScalarType.STRING ? string : T extends ScalarType.INT32 ? number : T extends ScalarType.UINT32 ? number : T extends ScalarType.SINT32 ? number : T extends ScalarType.FIXED32 ? number : T extends ScalarType.SFIXED32 ? number : T extends ScalarType.FLOAT ? number : T extends ScalarType.DOUBLE ? number : T extends ScalarType.INT64 ? LongAsString extends true ? string : bigint : T extends ScalarType.SINT64 ? LongAsString extends true ? string : bigint : T extends ScalarType.SFIXED64 ? LongAsString extends true ? string : bigint : T extends ScalarType.UINT64 ? LongAsString extends true ? string : bigint : T extends ScalarType.FIXED64 ? LongAsString extends true ? string : bigint : T extends ScalarType.BOOL ? boolean : T extends ScalarType.BYTES ? Uint8Array : never;
6
+ /**
7
+ * Returns true if both scalar values are equal.
8
+ *
9
+ * For float and double, values are compared following IEEE semantics: -0
10
+ * equals 0, and NaN does not equal NaN. This is value equality, not identity.
11
+ *
12
+ * It deliberately differs from isScalarZeroValue, which treats -0 as distinct
13
+ * from 0. A value can equal the zero value without being a zero value
14
+ * (scalarEquals(DOUBLE, -0, 0) is true while isScalarZeroValue(DOUBLE, -0) is
15
+ * false) so this function must not be used to derive implicit presence.
16
+ */
17
+ export declare function scalarEquals(type: ScalarType, a: ScalarValue | undefined, b: ScalarValue | undefined): boolean;
18
+ /**
19
+ * Returns the zero value for the given scalar type, the value a field of this
20
+ * type has when unset: 0 for numeric types, "" for strings, false for
21
+ * booleans, and an empty Uint8Array for bytes. For 64-bit integer types, the
22
+ * result is "0" when longAsString is true, otherwise 0n.
23
+ *
24
+ * This is the type's zero value, not a proto2 custom field default. For float
25
+ * and double it is +0; isScalarZeroValue treats only +0, not -0, as this value.
26
+ */
27
+ export declare function scalarZeroValue<T extends ScalarType, LongAsString extends boolean>(type: T, longAsString: LongAsString): ScalarValue<T, LongAsString>;
28
+ /**
29
+ * Returns true if the value is the zero value for the given scalar type: `0`
30
+ * for numeric types, `false` for booleans, `""` for strings, and an empty
31
+ * Uint8Array for bytes.
32
+ *
33
+ * This is the implicit-presence default check. A singular field with implicit
34
+ * presence is treated as unset, and omitted from the wire, when its value is
35
+ * the zero value. With explicit presence, or in repeated and map fields,
36
+ * presence is structural and this function does not apply.
37
+ *
38
+ * Note that -0 is NOT a zero value for float and double: under implicit
39
+ * presence, +0 is omitted from the wire but -0 is written, following the
40
+ * proto3 specification. As a result this can disagree with scalarEquals, which
41
+ * compares by value and treats -0 as equal to 0.
42
+ */
43
+ export declare function isScalarZeroValue(type: ScalarType, value: unknown): boolean;
@@ -20,6 +20,14 @@ const proto_int64_js_1 = require("../proto-int64.js");
20
20
  const descriptors_js_1 = require("../descriptors.js");
21
21
  /**
22
22
  * Returns true if both scalar values are equal.
23
+ *
24
+ * For float and double, values are compared following IEEE semantics: -0
25
+ * equals 0, and NaN does not equal NaN. This is value equality, not identity.
26
+ *
27
+ * It deliberately differs from isScalarZeroValue, which treats -0 as distinct
28
+ * from 0. A value can equal the zero value without being a zero value
29
+ * (scalarEquals(DOUBLE, -0, 0) is true while isScalarZeroValue(DOUBLE, -0) is
30
+ * false) so this function must not be used to derive implicit presence.
23
31
  */
24
32
  function scalarEquals(type, a, b) {
25
33
  if (a === b) {
@@ -56,7 +64,13 @@ function scalarEquals(type, a, b) {
56
64
  return false;
57
65
  }
58
66
  /**
59
- * Returns the zero value for the given scalar type.
67
+ * Returns the zero value for the given scalar type, the value a field of this
68
+ * type has when unset: 0 for numeric types, "" for strings, false for
69
+ * booleans, and an empty Uint8Array for bytes. For 64-bit integer types, the
70
+ * result is "0" when longAsString is true, otherwise 0n.
71
+ *
72
+ * This is the type's zero value, not a proto2 custom field default. For float
73
+ * and double it is +0; isScalarZeroValue treats only +0, not -0, as this value.
60
74
  */
61
75
  function scalarZeroValue(type, longAsString) {
62
76
  switch (type) {
@@ -82,11 +96,19 @@ function scalarZeroValue(type, longAsString) {
82
96
  }
83
97
  }
84
98
  /**
85
- * Returns true for a zero-value. For example, an integer has the zero-value `0`,
86
- * a boolean is `false`, a string is `""`, and bytes is an empty Uint8Array.
99
+ * Returns true if the value is the zero value for the given scalar type: `0`
100
+ * for numeric types, `false` for booleans, `""` for strings, and an empty
101
+ * Uint8Array for bytes.
87
102
  *
88
- * In proto3, zero-values are not written to the wire, unless the field is
89
- * optional or repeated.
103
+ * This is the implicit-presence default check. A singular field with implicit
104
+ * presence is treated as unset, and omitted from the wire, when its value is
105
+ * the zero value. With explicit presence, or in repeated and map fields,
106
+ * presence is structural and this function does not apply.
107
+ *
108
+ * Note that -0 is NOT a zero value for float and double: under implicit
109
+ * presence, +0 is omitted from the wire but -0 is written, following the
110
+ * proto3 specification. As a result this can disagree with scalarEquals, which
111
+ * compares by value and treats -0 as equal to 0.
90
112
  */
91
113
  function isScalarZeroValue(type, value) {
92
114
  switch (type) {
@@ -96,7 +118,12 @@ function isScalarZeroValue(type, value) {
96
118
  return value === "";
97
119
  case descriptors_js_1.ScalarType.BYTES:
98
120
  return value instanceof Uint8Array && !value.byteLength;
121
+ case descriptors_js_1.ScalarType.DOUBLE:
122
+ case descriptors_js_1.ScalarType.FLOAT:
123
+ // Object.is distinguishes -0 from 0.
124
+ return Object.is(value, 0);
99
125
  default:
100
- return value == 0; // Loose comparison matches 0n, 0 and "0"
126
+ // Loose comparison matches 0n, 0 and "0".
127
+ return value == 0;
101
128
  }
102
129
  }