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