@bufbuild/protobuf 1.6.0 → 1.7.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 (151) hide show
  1. package/dist/cjs/binary-encoding.js +2 -3
  2. package/dist/cjs/binary-format.d.ts +17 -0
  3. package/dist/cjs/binary-format.js +1 -1
  4. package/dist/cjs/codegen-info.d.ts +4 -4
  5. package/dist/cjs/codegen-info.js +2 -1
  6. package/dist/cjs/create-descriptor-set.d.ts +1 -1
  7. package/dist/cjs/create-descriptor-set.js +56 -50
  8. package/dist/cjs/create-registry-from-desc.d.ts +2 -2
  9. package/dist/cjs/create-registry-from-desc.js +53 -9
  10. package/dist/cjs/create-registry.d.ts +3 -2
  11. package/dist/cjs/create-registry.js +56 -37
  12. package/dist/cjs/descriptor-set.js +1 -1
  13. package/dist/cjs/enum.js +1 -1
  14. package/dist/cjs/extension-accessor.d.ts +35 -0
  15. package/dist/cjs/extension-accessor.js +108 -0
  16. package/dist/cjs/extension.d.ts +24 -0
  17. package/dist/cjs/extension.js +15 -0
  18. package/dist/cjs/field-list.js +1 -1
  19. package/dist/cjs/field.js +1 -1
  20. package/dist/cjs/google/protobuf/any_pb.js +1 -1
  21. package/dist/cjs/google/protobuf/api_pb.js +1 -1
  22. package/dist/cjs/google/protobuf/compiler/plugin_pb.js +1 -1
  23. package/dist/cjs/google/protobuf/descriptor_pb.js +2 -2
  24. package/dist/cjs/google/protobuf/duration_pb.js +1 -1
  25. package/dist/cjs/google/protobuf/empty_pb.js +1 -1
  26. package/dist/cjs/google/protobuf/field_mask_pb.js +1 -1
  27. package/dist/cjs/google/protobuf/source_context_pb.js +1 -1
  28. package/dist/cjs/google/protobuf/struct_pb.js +2 -2
  29. package/dist/cjs/google/protobuf/timestamp_pb.js +1 -1
  30. package/dist/cjs/google/protobuf/type_pb.js +2 -2
  31. package/dist/cjs/google/protobuf/wrappers_pb.js +1 -1
  32. package/dist/cjs/index.d.ts +3 -1
  33. package/dist/cjs/index.js +7 -2
  34. package/dist/cjs/json-format.d.ts +5 -5
  35. package/dist/cjs/json-format.js +1 -1
  36. package/dist/cjs/message-type.js +1 -1
  37. package/dist/cjs/message.js +1 -1
  38. package/dist/cjs/private/assert.js +1 -1
  39. package/dist/cjs/private/binary-format-common.d.ts +2 -3
  40. package/dist/cjs/private/binary-format-common.js +80 -78
  41. package/dist/cjs/private/binary-format-proto2.js +59 -64
  42. package/dist/cjs/private/binary-format-proto3.js +44 -40
  43. package/dist/cjs/private/enum.js +1 -1
  44. package/dist/cjs/private/extensions.d.ts +34 -0
  45. package/dist/cjs/private/extensions.js +86 -0
  46. package/dist/cjs/private/feature-set.d.ts +3 -3
  47. package/dist/cjs/private/feature-set.js +27 -32
  48. package/dist/cjs/private/field-list.js +1 -1
  49. package/dist/cjs/private/field-wrapper.d.ts +2 -2
  50. package/dist/cjs/private/field-wrapper.js +1 -1
  51. package/dist/cjs/private/field.js +1 -1
  52. package/dist/cjs/private/json-format-common.js +202 -156
  53. package/dist/cjs/private/json-format-proto2.js +2 -1
  54. package/dist/cjs/private/json-format-proto3.js +7 -5
  55. package/dist/cjs/private/message-type.js +1 -1
  56. package/dist/cjs/private/names.d.ts +2 -2
  57. package/dist/cjs/private/names.js +3 -2
  58. package/dist/cjs/private/options-map.js +1 -1
  59. package/dist/cjs/private/proto-runtime.d.ts +6 -0
  60. package/dist/cjs/private/proto-runtime.js +5 -1
  61. package/dist/cjs/private/reify-wkt.js +1 -1
  62. package/dist/cjs/private/scalars.js +1 -1
  63. package/dist/cjs/private/text-format.js +1 -1
  64. package/dist/cjs/private/util-common.js +1 -1
  65. package/dist/cjs/private/util.js +1 -1
  66. package/dist/cjs/proto-base64.js +1 -1
  67. package/dist/cjs/proto-delimited.js +1 -1
  68. package/dist/cjs/proto-double.js +1 -1
  69. package/dist/cjs/proto-int64.js +1 -1
  70. package/dist/cjs/proto2.js +1 -1
  71. package/dist/cjs/proto3.js +1 -1
  72. package/dist/cjs/service-type.js +1 -1
  73. package/dist/cjs/to-plain-message.js +1 -1
  74. package/dist/cjs/type-registry.d.ts +14 -0
  75. package/dist/cjs/type-registry.js +1 -1
  76. package/dist/esm/binary-encoding.js +2 -3
  77. package/dist/esm/binary-format.d.ts +17 -0
  78. package/dist/esm/binary-format.js +1 -1
  79. package/dist/esm/codegen-info.d.ts +4 -4
  80. package/dist/esm/codegen-info.js +2 -1
  81. package/dist/esm/create-descriptor-set.d.ts +1 -1
  82. package/dist/esm/create-descriptor-set.js +56 -50
  83. package/dist/esm/create-registry-from-desc.d.ts +2 -2
  84. package/dist/esm/create-registry-from-desc.js +53 -9
  85. package/dist/esm/create-registry.d.ts +3 -2
  86. package/dist/esm/create-registry.js +56 -37
  87. package/dist/esm/descriptor-set.js +1 -1
  88. package/dist/esm/enum.js +1 -1
  89. package/dist/esm/extension-accessor.d.ts +35 -0
  90. package/dist/esm/extension-accessor.js +101 -0
  91. package/dist/esm/extension.d.ts +24 -0
  92. package/dist/esm/extension.js +14 -0
  93. package/dist/esm/field-list.js +1 -1
  94. package/dist/esm/field.js +1 -1
  95. package/dist/esm/google/protobuf/any_pb.js +1 -1
  96. package/dist/esm/google/protobuf/api_pb.js +1 -1
  97. package/dist/esm/google/protobuf/compiler/plugin_pb.js +1 -1
  98. package/dist/esm/google/protobuf/descriptor_pb.js +2 -2
  99. package/dist/esm/google/protobuf/duration_pb.js +1 -1
  100. package/dist/esm/google/protobuf/empty_pb.js +1 -1
  101. package/dist/esm/google/protobuf/field_mask_pb.js +1 -1
  102. package/dist/esm/google/protobuf/source_context_pb.js +1 -1
  103. package/dist/esm/google/protobuf/struct_pb.js +2 -2
  104. package/dist/esm/google/protobuf/timestamp_pb.js +1 -1
  105. package/dist/esm/google/protobuf/type_pb.js +2 -2
  106. package/dist/esm/google/protobuf/wrappers_pb.js +1 -1
  107. package/dist/esm/index.d.ts +3 -1
  108. package/dist/esm/index.js +2 -1
  109. package/dist/esm/json-format.d.ts +5 -5
  110. package/dist/esm/json-format.js +1 -1
  111. package/dist/esm/message-type.js +1 -1
  112. package/dist/esm/message.js +1 -1
  113. package/dist/esm/private/assert.js +1 -1
  114. package/dist/esm/private/binary-format-common.d.ts +2 -3
  115. package/dist/esm/private/binary-format-common.js +80 -77
  116. package/dist/esm/private/binary-format-proto2.js +59 -64
  117. package/dist/esm/private/binary-format-proto3.js +44 -40
  118. package/dist/esm/private/enum.js +1 -1
  119. package/dist/esm/private/extensions.d.ts +34 -0
  120. package/dist/esm/private/extensions.js +81 -0
  121. package/dist/esm/private/feature-set.d.ts +3 -3
  122. package/dist/esm/private/feature-set.js +27 -32
  123. package/dist/esm/private/field-list.js +1 -1
  124. package/dist/esm/private/field-wrapper.d.ts +2 -2
  125. package/dist/esm/private/field-wrapper.js +1 -1
  126. package/dist/esm/private/field.js +1 -1
  127. package/dist/esm/private/json-format-common.js +202 -156
  128. package/dist/esm/private/json-format-proto2.js +2 -1
  129. package/dist/esm/private/json-format-proto3.js +7 -5
  130. package/dist/esm/private/message-type.js +1 -1
  131. package/dist/esm/private/names.d.ts +2 -2
  132. package/dist/esm/private/names.js +3 -2
  133. package/dist/esm/private/options-map.js +1 -1
  134. package/dist/esm/private/proto-runtime.d.ts +6 -0
  135. package/dist/esm/private/proto-runtime.js +5 -1
  136. package/dist/esm/private/reify-wkt.js +1 -1
  137. package/dist/esm/private/scalars.js +1 -1
  138. package/dist/esm/private/text-format.js +1 -1
  139. package/dist/esm/private/util-common.js +1 -1
  140. package/dist/esm/private/util.js +1 -1
  141. package/dist/esm/proto-base64.js +1 -1
  142. package/dist/esm/proto-delimited.js +1 -1
  143. package/dist/esm/proto-double.js +1 -1
  144. package/dist/esm/proto-int64.js +1 -1
  145. package/dist/esm/proto2.js +1 -1
  146. package/dist/esm/proto3.js +1 -1
  147. package/dist/esm/service-type.js +1 -1
  148. package/dist/esm/to-plain-message.js +1 -1
  149. package/dist/esm/type-registry.d.ts +14 -0
  150. package/dist/esm/type-registry.js +1 -1
  151. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -24,7 +24,8 @@ exports.featureSetDefaults = descriptor_pb_js_1.FeatureSetDefaults.fromBinary(pr
24
24
  /**
25
25
  * Create an edition feature resolver with the given feature set defaults.
26
26
  */
27
- function createFeatureResolver(compiledFeatureSetDefaults) {
27
+ function createFeatureResolver(compiledFeatureSetDefaults, edition) {
28
+ var _a, _b;
28
29
  const min = compiledFeatureSetDefaults.minimumEdition;
29
30
  const max = compiledFeatureSetDefaults.maximumEdition;
30
31
  if (min === undefined ||
@@ -32,37 +33,31 @@ function createFeatureResolver(compiledFeatureSetDefaults) {
32
33
  compiledFeatureSetDefaults.defaults.some((d) => d.edition === undefined)) {
33
34
  throw new Error("Invalid FeatureSetDefaults");
34
35
  }
35
- const defaultsBinByEdition = new Map();
36
- return (edition, ...rest) => {
37
- var _a, _b;
38
- let defaultsBin = defaultsBinByEdition.get(edition);
39
- if (defaultsBin === undefined) {
40
- if (edition < min) {
41
- throw new Error(`Edition ${descriptor_pb_js_1.Edition[edition]} is earlier than the minimum supported edition ${descriptor_pb_js_1.Edition[min]}`);
42
- }
43
- if (max < edition) {
44
- throw new Error(`Edition ${descriptor_pb_js_1.Edition[edition]} is later than the maximum supported edition ${descriptor_pb_js_1.Edition[max]}`);
45
- }
46
- let highestMatch = undefined;
47
- for (const c of compiledFeatureSetDefaults.defaults) {
48
- const e = (_a = c.edition) !== null && _a !== void 0 ? _a : 0;
49
- if (e > edition) {
50
- continue;
51
- }
52
- if (highestMatch !== undefined && highestMatch.e > e) {
53
- continue;
54
- }
55
- highestMatch = {
56
- e,
57
- f: (_b = c.features) !== null && _b !== void 0 ? _b : new descriptor_pb_js_1.FeatureSet(),
58
- };
59
- }
60
- if (highestMatch === undefined) {
61
- throw new Error(`No valid default found for edition ${descriptor_pb_js_1.Edition[edition]}`);
62
- }
63
- defaultsBin = highestMatch.f.toBinary();
64
- defaultsBinByEdition.set(edition, defaultsBin);
36
+ if (edition < min) {
37
+ throw new Error(`Edition ${descriptor_pb_js_1.Edition[edition]} is earlier than the minimum supported edition ${descriptor_pb_js_1.Edition[min]}`);
38
+ }
39
+ if (max < edition) {
40
+ throw new Error(`Edition ${descriptor_pb_js_1.Edition[edition]} is later than the maximum supported edition ${descriptor_pb_js_1.Edition[max]}`);
41
+ }
42
+ let highestMatch = undefined;
43
+ for (const c of compiledFeatureSetDefaults.defaults) {
44
+ const e = (_a = c.edition) !== null && _a !== void 0 ? _a : 0;
45
+ if (e > edition) {
46
+ continue;
47
+ }
48
+ if (highestMatch !== undefined && highestMatch.e > e) {
49
+ continue;
65
50
  }
51
+ highestMatch = {
52
+ e,
53
+ f: (_b = c.features) !== null && _b !== void 0 ? _b : new descriptor_pb_js_1.FeatureSet(),
54
+ };
55
+ }
56
+ if (highestMatch === undefined) {
57
+ throw new Error(`No valid default found for edition ${descriptor_pb_js_1.Edition[edition]}`);
58
+ }
59
+ const defaultsBin = highestMatch.f.toBinary();
60
+ return (...rest) => {
66
61
  const f = descriptor_pb_js_1.FeatureSet.fromBinary(defaultsBin);
67
62
  for (const c of rest) {
68
63
  if (c !== undefined) {
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -1,6 +1,6 @@
1
1
  import { Message } from "../message.js";
2
2
  import type { MessageType } from "../message-type.js";
3
- import type { DescField } from "../descriptor-set.js";
3
+ import type { DescExtension, DescField } from "../descriptor-set.js";
4
4
  import { ScalarType } from "../field.js";
5
5
  /**
6
6
  * A field wrapper unwraps a message to a primitive value that is more
@@ -22,4 +22,4 @@ export declare function wrapField<T extends Message<T>>(type: MessageType<T>, va
22
22
  * If the given field uses one of the well-known wrapper types, return
23
23
  * the primitive type it wraps.
24
24
  */
25
- export declare function getUnwrappedFieldType(field: DescField): ScalarType | undefined;
25
+ export declare function getUnwrappedFieldType(field: DescField | DescExtension): ScalarType | undefined;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@ const field_js_1 = require("../field.js");
19
19
  const assert_js_1 = require("./assert.js");
20
20
  const proto_int64_js_1 = require("../proto-int64.js");
21
21
  const proto_base64_js_1 = require("../proto-base64.js");
22
+ const extensions_js_1 = require("./extensions.js");
23
+ const extension_accessor_js_1 = require("../extension-accessor.js");
22
24
  /* eslint-disable no-case-declarations, @typescript-eslint/restrict-plus-operands,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument */
23
25
  // Default options for parsing JSON.
24
26
  const jsonReadDefaults = {
@@ -44,164 +46,45 @@ function makeJsonFormatCommon(makeWriteField) {
44
46
  makeWriteOptions,
45
47
  readMessage(type, json, options, message) {
46
48
  if (json == null || Array.isArray(json) || typeof json != "object") {
47
- throw new Error(`cannot decode message ${type.typeName} from JSON: ${this.debug(json)}`);
49
+ throw new Error(`cannot decode message ${type.typeName} from JSON: ${debugJsonValue(json)}`);
48
50
  }
49
51
  message = message !== null && message !== void 0 ? message : new type();
50
- const oneofSeen = {};
52
+ const oneofSeen = new Map();
53
+ const registry = options.typeRegistry;
51
54
  for (const [jsonKey, jsonValue] of Object.entries(json)) {
52
55
  const field = type.fields.findJsonName(jsonKey);
53
- if (!field) {
54
- if (!options.ignoreUnknownFields) {
55
- throw new Error(`cannot decode message ${type.typeName} from JSON: key "${jsonKey}" is unknown`);
56
- }
57
- continue;
58
- }
59
- let localName = field.localName;
60
- let target = message;
61
- if (field.oneof) {
62
- if (jsonValue === null && field.kind == "scalar") {
63
- // see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
64
- continue;
65
- }
66
- const seen = oneofSeen[field.oneof.localName];
67
- if (seen) {
68
- throw new Error(`cannot decode message ${type.typeName} from JSON: multiple keys for oneof "${field.oneof.name}" present: "${seen}", "${jsonKey}"`);
69
- }
70
- oneofSeen[field.oneof.localName] = jsonKey;
71
- target = target[field.oneof.localName] = { case: localName };
72
- localName = "value";
73
- }
74
- if (field.repeated) {
75
- if (jsonValue === null) {
76
- continue;
77
- }
78
- if (!Array.isArray(jsonValue)) {
79
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonValue)}`);
80
- }
81
- const targetArray = target[localName];
82
- for (const jsonItem of jsonValue) {
83
- if (jsonItem === null) {
84
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonItem)}`);
56
+ if (field) {
57
+ if (field.oneof) {
58
+ if (jsonValue === null && field.kind == "scalar") {
59
+ // see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
60
+ continue;
85
61
  }
86
- let val;
87
- // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- "map" is invalid for repeated fields
88
- switch (field.kind) {
89
- case "message":
90
- val = field.T.fromJson(jsonItem, options);
91
- break;
92
- case "enum":
93
- val = readEnum(field.T, jsonItem, options.ignoreUnknownFields);
94
- if (val === undefined)
95
- continue;
96
- break;
97
- case "scalar":
98
- try {
99
- val = readScalar(field.T, jsonItem, field.L);
100
- }
101
- catch (e) {
102
- let m = `cannot decode field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonItem)}`;
103
- if (e instanceof Error && e.message.length > 0) {
104
- m += `: ${e.message}`;
105
- }
106
- throw new Error(m);
107
- }
108
- break;
62
+ const seen = oneofSeen.get(field.oneof);
63
+ if (seen !== undefined) {
64
+ throw new Error(`cannot decode message ${type.typeName} from JSON: multiple keys for oneof "${field.oneof.name}" present: "${seen}", "${jsonKey}"`);
109
65
  }
110
- targetArray.push(val);
66
+ oneofSeen.set(field.oneof, jsonKey);
111
67
  }
68
+ readField(message, jsonValue, field, options, type);
112
69
  }
113
- else if (field.kind == "map") {
114
- if (jsonValue === null) {
115
- continue;
116
- }
117
- if (Array.isArray(jsonValue) || typeof jsonValue != "object") {
118
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonValue)}`);
119
- }
120
- const targetMap = target[localName];
121
- for (const [jsonMapKey, jsonMapValue] of Object.entries(jsonValue)) {
122
- if (jsonMapValue === null) {
123
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: map value null`);
124
- }
125
- let val;
126
- switch (field.V.kind) {
127
- case "message":
128
- val = field.V.T.fromJson(jsonMapValue, options);
129
- break;
130
- case "enum":
131
- val = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields);
132
- if (val === undefined)
133
- continue;
134
- break;
135
- case "scalar":
136
- try {
137
- val = readScalar(field.V.T, jsonMapValue, field_js_1.LongType.BIGINT);
138
- }
139
- catch (e) {
140
- let m = `cannot decode map value for field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonValue)}`;
141
- if (e instanceof Error && e.message.length > 0) {
142
- m += `: ${e.message}`;
143
- }
144
- throw new Error(m);
145
- }
146
- break;
147
- }
148
- try {
149
- targetMap[readScalar(field.K, field.K == field_js_1.ScalarType.BOOL
150
- ? jsonMapKey == "true"
151
- ? true
152
- : jsonMapKey == "false"
153
- ? false
154
- : jsonMapKey
155
- : jsonMapKey, field_js_1.LongType.BIGINT).toString()] = val;
156
- }
157
- catch (e) {
158
- let m = `cannot decode map key for field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonValue)}`;
159
- if (e instanceof Error && e.message.length > 0) {
160
- m += `: ${e.message}`;
161
- }
162
- throw new Error(m);
70
+ else {
71
+ let found = false;
72
+ if ((registry === null || registry === void 0 ? void 0 : registry.findExtension) &&
73
+ jsonKey.startsWith("[") &&
74
+ jsonKey.endsWith("]")) {
75
+ const ext = registry.findExtension(jsonKey.substring(1, jsonKey.length - 1));
76
+ if (ext && ext.extendee.typeName == type.typeName) {
77
+ found = true;
78
+ const [container, get] = (0, extensions_js_1.createExtensionContainer)(ext);
79
+ readField(container, jsonValue, ext.field, options, ext);
80
+ // We pass on the options as BinaryReadOptions/BinaryWriteOptions,
81
+ // so that users can bring their own binary reader and writer factories
82
+ // if necessary.
83
+ (0, extension_accessor_js_1.setExtension)(message, ext, get(), options);
163
84
  }
164
85
  }
165
- }
166
- else {
167
- switch (field.kind) {
168
- case "message":
169
- const messageType = field.T;
170
- if (jsonValue === null &&
171
- messageType.typeName != "google.protobuf.Value") {
172
- if (field.oneof) {
173
- throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: null is invalid for oneof field "${jsonKey}"`);
174
- }
175
- continue;
176
- }
177
- if (target[localName] instanceof message_js_1.Message) {
178
- target[localName].fromJson(jsonValue, options);
179
- }
180
- else {
181
- target[localName] = messageType.fromJson(jsonValue, options);
182
- if (messageType.fieldWrapper && !field.oneof) {
183
- target[localName] = messageType.fieldWrapper.unwrapField(target[localName]);
184
- }
185
- }
186
- break;
187
- case "enum":
188
- const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields);
189
- if (enumValue !== undefined) {
190
- target[localName] = enumValue;
191
- }
192
- break;
193
- case "scalar":
194
- try {
195
- target[localName] = readScalar(field.T, jsonValue, field.L);
196
- }
197
- catch (e) {
198
- let m = `cannot decode field ${type.typeName}.${field.name} from JSON: ${this.debug(jsonValue)}`;
199
- if (e instanceof Error && e.message.length > 0) {
200
- m += `: ${e.message}`;
201
- }
202
- throw new Error(m);
203
- }
204
- break;
86
+ if (!found && !options.ignoreUnknownFields) {
87
+ throw new Error(`cannot decode message ${type.typeName} from JSON: key "${jsonKey}" is unknown`);
205
88
  }
206
89
  }
207
90
  }
@@ -234,6 +117,21 @@ function makeJsonFormatCommon(makeWriteField) {
234
117
  jsonValue;
235
118
  }
236
119
  }
120
+ const registry = options.typeRegistry;
121
+ if (registry === null || registry === void 0 ? void 0 : registry.findExtensionFor) {
122
+ for (const uf of type.runtime.bin.listUnknownFields(message)) {
123
+ const ext = registry.findExtensionFor(type.typeName, uf.no);
124
+ if (ext && (0, extension_accessor_js_1.hasExtension)(message, ext)) {
125
+ // We pass on the options as BinaryReadOptions, so that users can bring their own
126
+ // binary reader factory if necessary.
127
+ const value = (0, extension_accessor_js_1.getExtension)(message, ext, options);
128
+ const jsonValue = writeField(ext.field, value, options);
129
+ if (jsonValue !== undefined) {
130
+ json[ext.field.jsonName] = jsonValue;
131
+ }
132
+ }
133
+ }
134
+ }
237
135
  }
238
136
  catch (e) {
239
137
  const m = field
@@ -263,6 +161,153 @@ function debugJsonValue(json) {
263
161
  return String(json);
264
162
  }
265
163
  }
164
+ // Read a JSON value for a field.
165
+ // The "type" argument is only used to provide context in errors.
166
+ function readField(target, // eslint-disable-line @typescript-eslint/no-explicit-any -- `any` is the best choice for dynamic access
167
+ jsonValue, field, options, type) {
168
+ let localName = field.localName;
169
+ if (field.oneof) {
170
+ if (jsonValue === null && field.kind == "scalar") {
171
+ // see conformance test Required.Proto3.JsonInput.OneofFieldNull{First,Second}
172
+ return;
173
+ }
174
+ target = target[field.oneof.localName] = { case: localName };
175
+ localName = "value";
176
+ }
177
+ if (field.repeated) {
178
+ if (jsonValue === null) {
179
+ return;
180
+ }
181
+ if (!Array.isArray(jsonValue)) {
182
+ throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
183
+ }
184
+ const targetArray = target[localName];
185
+ for (const jsonItem of jsonValue) {
186
+ if (jsonItem === null) {
187
+ throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`);
188
+ }
189
+ let val;
190
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- "map" is invalid for repeated fields
191
+ switch (field.kind) {
192
+ case "message":
193
+ val = field.T.fromJson(jsonItem, options);
194
+ break;
195
+ case "enum":
196
+ val = readEnum(field.T, jsonItem, options.ignoreUnknownFields);
197
+ if (val === undefined)
198
+ continue;
199
+ break;
200
+ case "scalar":
201
+ try {
202
+ val = readScalar(field.T, jsonItem, field.L);
203
+ }
204
+ catch (e) {
205
+ let m = `cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonItem)}`;
206
+ if (e instanceof Error && e.message.length > 0) {
207
+ m += `: ${e.message}`;
208
+ }
209
+ throw new Error(m);
210
+ }
211
+ break;
212
+ }
213
+ targetArray.push(val);
214
+ }
215
+ }
216
+ else if (field.kind == "map") {
217
+ if (jsonValue === null) {
218
+ return;
219
+ }
220
+ if (typeof jsonValue != "object" || Array.isArray(jsonValue)) {
221
+ throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`);
222
+ }
223
+ const targetMap = target[localName];
224
+ for (const [jsonMapKey, jsonMapValue] of Object.entries(jsonValue)) {
225
+ if (jsonMapValue === null) {
226
+ throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: map value null`);
227
+ }
228
+ let val;
229
+ switch (field.V.kind) {
230
+ case "message":
231
+ val = field.V.T.fromJson(jsonMapValue, options);
232
+ break;
233
+ case "enum":
234
+ val = readEnum(field.V.T, jsonMapValue, options.ignoreUnknownFields);
235
+ if (val === undefined)
236
+ continue;
237
+ break;
238
+ case "scalar":
239
+ try {
240
+ val = readScalar(field.V.T, jsonMapValue, field_js_1.LongType.BIGINT);
241
+ }
242
+ catch (e) {
243
+ let m = `cannot decode map value for field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
244
+ if (e instanceof Error && e.message.length > 0) {
245
+ m += `: ${e.message}`;
246
+ }
247
+ throw new Error(m);
248
+ }
249
+ break;
250
+ }
251
+ try {
252
+ targetMap[readScalar(field.K, field.K == field_js_1.ScalarType.BOOL
253
+ ? jsonMapKey == "true"
254
+ ? true
255
+ : jsonMapKey == "false"
256
+ ? false
257
+ : jsonMapKey
258
+ : jsonMapKey, field_js_1.LongType.BIGINT).toString()] = val;
259
+ }
260
+ catch (e) {
261
+ let m = `cannot decode map key for field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
262
+ if (e instanceof Error && e.message.length > 0) {
263
+ m += `: ${e.message}`;
264
+ }
265
+ throw new Error(m);
266
+ }
267
+ }
268
+ }
269
+ else {
270
+ switch (field.kind) {
271
+ case "message":
272
+ const messageType = field.T;
273
+ if (jsonValue === null &&
274
+ messageType.typeName != "google.protobuf.Value") {
275
+ if (field.oneof) {
276
+ throw new Error(`cannot decode field ${type.typeName}.${field.name} from JSON: null is invalid for oneof field`);
277
+ }
278
+ return;
279
+ }
280
+ if (target[localName] instanceof message_js_1.Message) {
281
+ target[localName].fromJson(jsonValue, options);
282
+ }
283
+ else {
284
+ target[localName] = messageType.fromJson(jsonValue, options);
285
+ if (messageType.fieldWrapper && !field.oneof) {
286
+ target[localName] = messageType.fieldWrapper.unwrapField(target[localName]);
287
+ }
288
+ }
289
+ break;
290
+ case "enum":
291
+ const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields);
292
+ if (enumValue !== undefined) {
293
+ target[localName] = enumValue;
294
+ }
295
+ break;
296
+ case "scalar":
297
+ try {
298
+ target[localName] = readScalar(field.T, jsonValue, field.L);
299
+ }
300
+ catch (e) {
301
+ let m = `cannot decode field ${type.typeName}.${field.name} from JSON: ${debugJsonValue(jsonValue)}`;
302
+ if (e instanceof Error && e.message.length > 0) {
303
+ m += `: ${e.message}`;
304
+ }
305
+ throw new Error(m);
306
+ }
307
+ break;
308
+ }
309
+ }
310
+ }
266
311
  // May throw an error. If the error message is non-blank, it should be shown.
267
312
  // It is up to the caller to provide context.
268
313
  function readScalar(type, json, longType) {
@@ -274,7 +319,7 @@ function readScalar(type, json, longType) {
274
319
  case field_js_1.ScalarType.DOUBLE:
275
320
  case field_js_1.ScalarType.FLOAT:
276
321
  if (json === null)
277
- return 0.0;
322
+ return 0.0; // TODO field presence: this should reset the field with explicit presence
278
323
  if (json === "NaN")
279
324
  return Number.NaN;
280
325
  if (json === "Infinity")
@@ -311,7 +356,7 @@ function readScalar(type, json, longType) {
311
356
  case field_js_1.ScalarType.SINT32:
312
357
  case field_js_1.ScalarType.UINT32:
313
358
  if (json === null)
314
- return 0;
359
+ return 0; // TODO field presence: this should reset the field with explicit presence
315
360
  let int32;
316
361
  if (typeof json == "number")
317
362
  int32 = json;
@@ -331,7 +376,7 @@ function readScalar(type, json, longType) {
331
376
  case field_js_1.ScalarType.SFIXED64:
332
377
  case field_js_1.ScalarType.SINT64:
333
378
  if (json === null)
334
- return proto_int64_js_1.protoInt64.zero;
379
+ return proto_int64_js_1.protoInt64.zero; // TODO field presence: this should reset the field with explicit presence
335
380
  if (typeof json != "number" && typeof json != "string")
336
381
  break;
337
382
  const long = proto_int64_js_1.protoInt64.parse(json);
@@ -340,7 +385,7 @@ function readScalar(type, json, longType) {
340
385
  case field_js_1.ScalarType.FIXED64:
341
386
  case field_js_1.ScalarType.UINT64:
342
387
  if (json === null)
343
- return proto_int64_js_1.protoInt64.zero;
388
+ return proto_int64_js_1.protoInt64.zero; // TODO field presence: this should reset the field with explicit presence
344
389
  if (typeof json != "number" && typeof json != "string")
345
390
  break;
346
391
  const uLong = proto_int64_js_1.protoInt64.uParse(json);
@@ -349,14 +394,14 @@ function readScalar(type, json, longType) {
349
394
  // bool:
350
395
  case field_js_1.ScalarType.BOOL:
351
396
  if (json === null)
352
- return false;
397
+ return false; // TODO field presence: this should reset the field with explicit presence
353
398
  if (typeof json !== "boolean")
354
399
  break;
355
400
  return json;
356
401
  // string:
357
402
  case field_js_1.ScalarType.STRING:
358
403
  if (json === null)
359
- return "";
404
+ return ""; // TODO field presence: this should reset the field with explicit presence
360
405
  if (typeof json !== "string") {
361
406
  break;
362
407
  }
@@ -373,7 +418,7 @@ function readScalar(type, json, longType) {
373
418
  // Either standard or URL-safe base64 encoding with/without paddings are accepted.
374
419
  case field_js_1.ScalarType.BYTES:
375
420
  if (json === null || json === "")
376
- return new Uint8Array(0);
421
+ return new Uint8Array(0); // TODO field presence: this should reset the field with explicit presence
377
422
  if (typeof json !== "string")
378
423
  break;
379
424
  return proto_base64_js_1.protoBase64.dec(json);
@@ -383,6 +428,7 @@ function readScalar(type, json, longType) {
383
428
  function readEnum(type, json, ignoreUnknownFields) {
384
429
  if (json === null) {
385
430
  // proto3 requires 0 to be default value for all enums
431
+ // TODO field presence: this should reset the field with explicit presence
386
432
  return 0;
387
433
  }
388
434
  // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ const assert_js_1 = require("./assert.js");
19
19
  const json_format_common_js_1 = require("./json-format-common.js");
20
20
  /* eslint-disable no-case-declarations, @typescript-eslint/restrict-plus-operands,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument */
21
21
  function makeJsonFormatProto2() {
22
+ // TODO field presence: merge this function with proto2
22
23
  return (0, json_format_common_js_1.makeJsonFormatCommon)((writeEnum, writeScalar) => {
23
24
  return function writeField(field, value, options) {
24
25
  if (field.kind == "map") {
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ const assert_js_1 = require("./assert.js");
19
19
  const json_format_common_js_1 = require("./json-format-common.js");
20
20
  /* eslint-disable no-case-declarations, @typescript-eslint/restrict-plus-operands,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument */
21
21
  function makeJsonFormatProto3() {
22
+ // TODO field presence: merge this function with proto2
22
23
  return (0, json_format_common_js_1.makeJsonFormatCommon)((writeEnum, writeScalar) => {
23
24
  return function writeField(field, value, options) {
24
25
  if (field.kind == "map") {
@@ -66,7 +67,7 @@ function makeJsonFormatProto3() {
66
67
  break;
67
68
  case "message":
68
69
  for (let i = 0; i < value.length; i++) {
69
- jsonArr.push((0, field_wrapper_js_1.wrapField)(field.T, value[i]).toJson(options));
70
+ jsonArr.push(value[i].toJson(options));
70
71
  }
71
72
  break;
72
73
  }
@@ -75,15 +76,16 @@ function makeJsonFormatProto3() {
75
76
  : undefined;
76
77
  }
77
78
  else {
79
+ if (value === undefined) {
80
+ return undefined;
81
+ }
78
82
  switch (field.kind) {
79
83
  case "scalar":
80
84
  return writeScalar(field.T, value, !!field.oneof || field.opt || options.emitDefaultValues);
81
85
  case "enum":
82
86
  return writeEnum(field.T, value, !!field.oneof || field.opt || options.emitDefaultValues, options.enumAsInteger);
83
87
  case "message":
84
- return value !== undefined
85
- ? (0, field_wrapper_js_1.wrapField)(field.T, value).toJson(options)
86
- : undefined;
88
+ return (0, field_wrapper_js_1.wrapField)(field.T, value).toJson(options);
87
89
  }
88
90
  }
89
91
  };
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // Copyright 2021-2023 Buf Technologies, Inc.
2
+ // Copyright 2021-2024 Buf Technologies, Inc.
3
3
  //
4
4
  // Licensed under the Apache License, Version 2.0 (the "License");
5
5
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- import type { DescEnum, DescEnumValue, DescField, DescMessage, DescService } from "../descriptor-set.js";
1
+ import type { DescEnum, DescEnumValue, DescExtension, DescField, DescMessage, DescService } from "../descriptor-set.js";
2
2
  import type { DescMethod, DescOneof } from "../descriptor-set.js";
3
3
  /**
4
4
  * Returns the name of a protobuf element in generated code.
@@ -8,7 +8,7 @@ import type { DescMethod, DescOneof } from "../descriptor-set.js";
8
8
  * the type name. For nested messages and enumerations, the names are joined
9
9
  * with an underscore. For methods, the first character is made lowercase.
10
10
  */
11
- export declare function localName(desc: DescEnum | DescEnumValue | DescMessage | DescOneof | DescField | DescService | DescMethod): string;
11
+ export declare function localName(desc: DescEnum | DescEnumValue | DescMessage | DescExtension | DescOneof | DescField | DescService | DescMethod): string;
12
12
  /**
13
13
  * Returns the name of a field in generated code.
14
14
  */