ts-proto 1.167.9 → 1.169.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.
package/README.markdown CHANGED
@@ -432,7 +432,7 @@ Generated code will be placed in the Gradle build directory.
432
432
 
433
433
  - With `--ts_proto_opt=outputSchema=true`, meta typings will be generated that can later be used in other code generators.
434
434
 
435
- - With `--ts_proto_opt=outputTypeAnnotations=true`, each message will be given a `$type` field containing its fully-qualified name. You can use `--ts_proto_opt=outputTypeAnnotations=static-only` to omit it from the `interface` declaration.
435
+ - With `--ts_proto_opt=outputTypeAnnotations=true`, each message will be given a `$type` field containing its fully-qualified name. You can use `--ts_proto_opt=outputTypeAnnotations=static-only` to omit it from the `interface` declaration, or `--ts_proto_opt=outputTypeAnnotations=optional` to make it an optional property on the `interface` definition. The latter option may be useful if you want to use the `$type` field for runtime type checking on responses from a server.
436
436
 
437
437
  - With `--ts_proto_opt=outputTypeRegistry=true`, the type registry will be generated that can be used to resolve message types by fully-qualified name. Also, each message will be given a `$type` field containing its fully-qualified name.
438
438
 
@@ -496,6 +496,10 @@ Generated code will be placed in the Gradle build directory.
496
496
 
497
497
  - With `--ts_proto_opt=initializeFieldsAsUndefined=false`, all optional field initializers will be omited from the generated base instances.
498
498
 
499
+ - With `--ts_proto_opt=disableProto2Optionals=true`, all optional fields on proto2 files will not be set to be optional. Please note that this flag is primarily for preserving ts-proto's legacy handling of proto2 files, to avoid breaking changes, and as a result, it is not intended to be used moving forward.
500
+
501
+ - With `--ts_proto_opt=disableProto2DefaultValues=true`, all fields in proto2 files that specify a default value will not actually use that default value. Please note that this flag is primarily for preserving ts-proto's legacy handling of proto2 files, to avoid breaking changes, and as a result, it is not intended to be used moving forward.
502
+
499
503
  - With `--ts_proto_opt=Mgoogle/protobuf/empty.proto=./google3/protobuf/empty`, ('M' means 'importMapping', similar to [protoc-gen-go](https://developers.google.com/protocol-buffers/docs/reference/go-generated#package)), the generated code import path for `./google/protobuf/empty.ts` will reflect the overridden value:
500
504
 
501
505
  - `Mfoo/bar.proto=@myorg/some-lib` will map `foo/bar.proto` imports into `import ... from '@myorg/some-lib'`.
package/build/context.js CHANGED
@@ -1,2 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFileContext = void 0;
4
+ function createFileContext(file) {
5
+ return { isProto3Syntax: file.syntax === "proto3" };
6
+ }
7
+ exports.createFileContext = createFileContext;
package/build/main.js CHANGED
@@ -672,13 +672,13 @@ function makeAssertionUtils(bytes) {
672
672
  // Create the interface with properties
673
673
  function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fullTypeName) {
674
674
  var _a;
675
- const { options } = ctx;
675
+ const { options, currentFile } = ctx;
676
676
  const chunks = [];
677
677
  (0, utils_1.maybeAddComment)(options, sourceInfo, chunks, (_a = messageDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated);
678
678
  // interface name should be defined to avoid import collisions
679
679
  chunks.push((0, ts_poet_1.code) `export interface ${(0, ts_poet_1.def)(fullName)} {`);
680
680
  if ((0, options_1.addTypeToMessages)(options)) {
681
- chunks.push((0, ts_poet_1.code) `$type: '${fullTypeName}',`);
681
+ chunks.push((0, ts_poet_1.code) `$type${options.outputTypeAnnotations === "optional" ? "?" : ""}: '${fullTypeName}',`);
682
682
  }
683
683
  // When oneof=unions, we generate a single property with an ADT per `oneof` clause.
684
684
  const processedOneofs = new Set();
@@ -695,7 +695,7 @@ function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fu
695
695
  const info = sourceInfo.lookup(sourceInfo_1.Fields.message.field, index);
696
696
  (0, utils_1.maybeAddComment)(options, info, chunks, (_a = fieldDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated);
697
697
  const fieldKey = (0, utils_1.safeAccessor)((0, utils_1.getFieldName)(fieldDesc, options));
698
- const isOptional = (0, types_1.isOptionalProperty)(fieldDesc, messageDesc.options, options);
698
+ const isOptional = (0, types_1.isOptionalProperty)(fieldDesc, messageDesc.options, options, currentFile.isProto3Syntax);
699
699
  const type = (0, types_1.toTypeName)(ctx, messageDesc, fieldDesc, isOptional);
700
700
  chunks.push((0, ts_poet_1.code) `${maybeReadonly(options)}${fieldKey}${isOptional ? "?" : ""}: ${type}, `);
701
701
  });
@@ -739,7 +739,7 @@ function generateOneofProperty(ctx, messageDesc, oneofIndex, sourceInfo) {
739
739
  }
740
740
  // Create a function that constructs 'base' instance with default values for decode to use as a prototype
741
741
  function generateBaseInstanceFactory(ctx, fullName, messageDesc, fullTypeName) {
742
- const { options } = ctx;
742
+ const { options, currentFile } = ctx;
743
743
  const fields = [];
744
744
  // When oneof=unions, we generate a single property with an ADT per `oneof` clause.
745
745
  const processedOneofs = new Set();
@@ -755,7 +755,8 @@ function generateBaseInstanceFactory(ctx, fullName, messageDesc, fullTypeName) {
755
755
  }
756
756
  continue;
757
757
  }
758
- if (!options.initializeFieldsAsUndefined && (0, types_1.isOptionalProperty)(field, messageDesc.options, options)) {
758
+ if (!options.initializeFieldsAsUndefined &&
759
+ (0, types_1.isOptionalProperty)(field, messageDesc.options, options, currentFile.isProto3Syntax)) {
759
760
  continue;
760
761
  }
761
762
  const fieldKey = (0, utils_1.safeAccessor)((0, utils_1.getFieldName)(field, options));
@@ -854,7 +855,7 @@ function getDecodeReadSnippet(ctx, field) {
854
855
  }
855
856
  /** Creates a function to decode a message by loop overing the tags. */
856
857
  function generateDecode(ctx, fullName, messageDesc) {
857
- const { options, utils, typeMap } = ctx;
858
+ const { options, currentFile } = ctx;
858
859
  const chunks = [];
859
860
  let createBase = (0, ts_poet_1.code) `createBase${fullName}()`;
860
861
  if (options.usePrototypeForDefaults) {
@@ -891,7 +892,8 @@ function generateDecode(ctx, fullName, messageDesc) {
891
892
  // get a generic 'reader.doSomething' bit that is specific to the basic type
892
893
  const readSnippet = getDecodeReadSnippet(ctx, field);
893
894
  // and then use the snippet to handle repeated fields if necessary
894
- const initializerNecessary = !options.initializeFieldsAsUndefined && (0, types_1.isOptionalProperty)(field, messageDesc.options, options);
895
+ const initializerNecessary = !options.initializeFieldsAsUndefined &&
896
+ (0, types_1.isOptionalProperty)(field, messageDesc.options, options, currentFile.isProto3Syntax);
895
897
  if ((0, types_1.isRepeated)(field)) {
896
898
  const maybeNonNullAssertion = ctx.options.useOptionals === "all" ? "!" : "";
897
899
  const mapType = (0, types_1.detectMapType)(ctx, messageDesc, field);
@@ -1094,7 +1096,7 @@ function getEncodeWriteSnippet(ctx, field) {
1094
1096
  }
1095
1097
  /** Creates a function to encode a message by loop overing the tags. */
1096
1098
  function generateEncode(ctx, fullName, messageDesc) {
1097
- const { options, utils, typeMap } = ctx;
1099
+ const { options, utils, typeMap, currentFile } = ctx;
1098
1100
  const chunks = [];
1099
1101
  const Writer = (0, utils_1.impFile)(ctx.options, "Writer@protobufjs/minimal");
1100
1102
  // create the basic function declaration
@@ -1114,7 +1116,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1114
1116
  const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
1115
1117
  // get a generic writer.doSomething based on the basic type
1116
1118
  const writeSnippet = getEncodeWriteSnippet(ctx, field);
1117
- const isOptional = (0, types_1.isOptionalProperty)(field, messageDesc.options, options);
1119
+ const isOptional = (0, types_1.isOptionalProperty)(field, messageDesc.options, options, currentFile.isProto3Syntax);
1118
1120
  if ((0, types_1.isRepeated)(field)) {
1119
1121
  if ((0, types_1.isMapType)(ctx, messageDesc, field)) {
1120
1122
  const valueType = typeMap.get(field.typeName)[2].field[1];
@@ -1534,7 +1536,7 @@ function generateExtension(ctx, message, extension) {
1534
1536
  * a few special cases for https://developers.google.com/protocol-buffers/docs/proto3#json.
1535
1537
  * */
1536
1538
  function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1537
- const { options, utils, typeMap } = ctx;
1539
+ const { options, utils, currentFile } = ctx;
1538
1540
  const chunks = [];
1539
1541
  // create the basic function declaration
1540
1542
  chunks.push((0, ts_poet_1.code) `
@@ -1684,7 +1686,8 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1684
1686
  throw new Error(`Unhandled field ${field}`);
1685
1687
  }
1686
1688
  };
1687
- const noDefaultValue = !options.initializeFieldsAsUndefined && (0, types_1.isOptionalProperty)(field, messageDesc.options, options);
1689
+ const noDefaultValue = !options.initializeFieldsAsUndefined &&
1690
+ (0, types_1.isOptionalProperty)(field, messageDesc.options, options, currentFile.isProto3Syntax);
1688
1691
  // and then use the snippet to handle repeated fields if necessary
1689
1692
  if ((_a = canonicalFromJson[fullTypeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) {
1690
1693
  chunks.push((0, ts_poet_1.code) `${fieldName}: ${canonicalFromJson[fullTypeName][fieldName]("object")},`);
@@ -2071,7 +2074,7 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2071
2074
  throw new Error(`Unhandled field ${field}`);
2072
2075
  }
2073
2076
  };
2074
- const noDefaultValue = !options.initializeFieldsAsUndefined && (0, types_1.isOptionalProperty)(field, messageDesc.options, options);
2077
+ const noDefaultValue = !options.initializeFieldsAsUndefined && (0, types_1.isOptionalProperty)(field, messageDesc.options, options, true);
2075
2078
  // and then use the snippet to handle repeated fields if necessary
2076
2079
  if ((0, types_1.isRepeated)(field)) {
2077
2080
  if ((0, types_1.isMapType)(ctx, messageDesc, field)) {
package/build/options.js CHANGED
@@ -98,6 +98,8 @@ function defaultOptions() {
98
98
  rpcAfterResponse: false,
99
99
  rpcErrorHandler: false,
100
100
  comments: true,
101
+ disableProto2Optionals: false,
102
+ disableProto2DefaultValues: false,
101
103
  };
102
104
  }
103
105
  exports.defaultOptions = defaultOptions;
package/build/plugin.js CHANGED
@@ -5,6 +5,7 @@ const util_1 = require("util");
5
5
  const utils_1 = require("./utils");
6
6
  const main_1 = require("./main");
7
7
  const types_1 = require("./types");
8
+ const context_1 = require("./context");
8
9
  const options_1 = require("./options");
9
10
  const generate_type_registry_1 = require("./generate-type-registry");
10
11
  // this would be the plugin called by the protoc compiler
@@ -40,7 +41,7 @@ async function main() {
40
41
  filesToGenerate = (0, utils_1.protoFilesToGenerate)(request).filter((file) => !options.M[file.name]);
41
42
  }
42
43
  const files = await Promise.all(filesToGenerate.map(async (file) => {
43
- const [path, code] = (0, main_1.generateFile)(ctx, file);
44
+ const [path, code] = (0, main_1.generateFile)({ ...ctx, currentFile: (0, context_1.createFileContext)(file) }, file);
44
45
  const content = code.toString({ ...(0, options_1.getTsPoetOpts)(options), path });
45
46
  return { name: path, content };
46
47
  }));
package/build/types.js CHANGED
@@ -165,7 +165,9 @@ function packedType(type) {
165
165
  }
166
166
  exports.packedType = packedType;
167
167
  function defaultValue(ctx, field) {
168
- const { typeMap, options, utils } = ctx;
168
+ const { typeMap, options, utils, currentFile } = ctx;
169
+ const useDefaultValue = !currentFile.isProto3Syntax && !options.disableProto2DefaultValues && field.defaultValue;
170
+ const numbericDefaultVal = useDefaultValue ? field.defaultValue : 0;
169
171
  switch (field.type) {
170
172
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
171
173
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
@@ -174,7 +176,7 @@ function defaultValue(ctx, field) {
174
176
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
175
177
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
176
178
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
177
- return 0;
179
+ return numbericDefaultVal;
178
180
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
179
181
  // proto3 enforces enums starting at 0, however proto2 does not, so we have
180
182
  // to probe and see if zero is an allowed value. If it's not, pick the first one.
@@ -182,54 +184,54 @@ function defaultValue(ctx, field) {
182
184
  // and I believe the semantics of those in the proto2 world are generally undefined.
183
185
  const typeInfo = typeMap.get(field.typeName);
184
186
  const enumProto = typeInfo[2];
185
- const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
187
+ const defaultEnum = enumProto.value.find((v) => (useDefaultValue ? v.name === field.defaultValue : v.number === 0)) ||
188
+ enumProto.value[0];
186
189
  if (options.stringEnums) {
187
190
  const enumType = messageToTypeName(ctx, field.typeName);
188
- return (0, ts_poet_1.code) `${enumType}.${(0, enums_1.getMemberName)(ctx, enumProto, zerothValue)}`;
191
+ return (0, ts_poet_1.code) `${enumType}.${(0, enums_1.getMemberName)(ctx, enumProto, defaultEnum)}`;
189
192
  }
190
193
  else {
191
- return zerothValue.number;
194
+ return defaultEnum.number;
192
195
  }
193
196
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
194
197
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
195
198
  if (options.forceLong === options_1.LongOption.LONG) {
196
- return (0, ts_poet_1.code) `${utils.Long}.UZERO`;
199
+ return (0, ts_poet_1.code) `${utils.Long}.${useDefaultValue ? "fromNumber" : "UZERO"}${useDefaultValue ? `(${numbericDefaultVal})` : ""}`;
197
200
  }
198
201
  else if (options.forceLong === options_1.LongOption.STRING) {
199
- return '"0"';
202
+ return `"${numbericDefaultVal}"`;
200
203
  }
201
204
  else if (options.forceLong === options_1.LongOption.BIGINT) {
202
- return 'BigInt("0")';
205
+ return `BigInt("${numbericDefaultVal}")`;
203
206
  }
204
207
  else {
205
- return 0;
208
+ return numbericDefaultVal;
206
209
  }
207
210
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64:
208
211
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
209
212
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
210
213
  if (options.forceLong === options_1.LongOption.LONG) {
211
- return (0, ts_poet_1.code) `${utils.Long}.ZERO`;
214
+ return (0, ts_poet_1.code) `${utils.Long}.${useDefaultValue ? "fromNumber" : "ZERO"}${useDefaultValue ? `(${numbericDefaultVal})` : ""}`;
212
215
  }
213
216
  else if (options.forceLong === options_1.LongOption.STRING) {
214
- return '"0"';
217
+ return `"${numbericDefaultVal}"`;
215
218
  }
216
219
  else if (options.forceLong === options_1.LongOption.BIGINT) {
217
- return 'BigInt("0")';
220
+ return `BigInt("${numbericDefaultVal}")`;
218
221
  }
219
222
  else {
220
- return 0;
223
+ return numbericDefaultVal;
221
224
  }
222
225
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
223
- return false;
226
+ return useDefaultValue ? field.defaultValue : false;
224
227
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
225
- return '""';
228
+ return useDefaultValue ? `"${field.defaultValue}"` : '""';
226
229
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
230
+ // todo(proto2): need to look into all the possible default values for the bytes type, and handle each one
227
231
  if (options.env === options_1.EnvOption.NODE) {
228
232
  return "Buffer.alloc(0)";
229
233
  }
230
- else {
231
- return "new Uint8Array(0)";
232
- }
234
+ return "new Uint8Array(0)";
233
235
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_MESSAGE:
234
236
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP:
235
237
  default:
@@ -239,8 +241,8 @@ function defaultValue(ctx, field) {
239
241
  exports.defaultValue = defaultValue;
240
242
  /** Creates code that checks that the field is not the default value. Supports scalars and enums. */
241
243
  function notDefaultCheck(ctx, field, messageOptions, place) {
242
- const { typeMap, options } = ctx;
243
- const isOptional = isOptionalProperty(field, messageOptions, options);
244
+ const { typeMap, options, currentFile } = ctx;
245
+ const isOptional = isOptionalProperty(field, messageOptions, options, currentFile.isProto3Syntax);
244
246
  const maybeNotUndefinedAnd = isOptional ? `${place} !== undefined && ` : "";
245
247
  switch (field.type) {
246
248
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
@@ -250,7 +252,9 @@ function notDefaultCheck(ctx, field, messageOptions, place) {
250
252
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
251
253
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
252
254
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
253
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== 0`;
255
+ case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
256
+ case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
257
+ return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${defaultValue(ctx, field)}`;
254
258
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
255
259
  // proto3 enforces enums starting at 0, however proto2 does not, so we have
256
260
  // to probe and see if zero is an allowed value. If it's not, pick the first one.
@@ -258,14 +262,14 @@ function notDefaultCheck(ctx, field, messageOptions, place) {
258
262
  // and I believe the semantics of those in the proto2 world are generally undefined.
259
263
  const typeInfo = typeMap.get(field.typeName);
260
264
  const enumProto = typeInfo[2];
261
- const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
265
+ const defaultEnum = enumProto.value.find((v) => v.number === defaultValue(ctx, field)) || enumProto.value[0];
262
266
  if (options.stringEnums) {
263
267
  const enumType = messageToTypeName(ctx, field.typeName);
264
- const enumValue = (0, enums_1.getMemberName)(ctx, enumProto, zerothValue);
268
+ const enumValue = (0, enums_1.getMemberName)(ctx, enumProto, defaultEnum);
265
269
  return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${enumType}.${enumValue}`;
266
270
  }
267
271
  else {
268
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${zerothValue.number}`;
272
+ return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${defaultEnum.number}`;
269
273
  }
270
274
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
271
275
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
@@ -273,22 +277,13 @@ function notDefaultCheck(ctx, field, messageOptions, place) {
273
277
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
274
278
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
275
279
  if (options.forceLong === options_1.LongOption.LONG) {
276
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} !${place}.isZero()`;
277
- }
278
- else if (options.forceLong === options_1.LongOption.STRING) {
279
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== "0"`;
280
- }
281
- else if (options.forceLong === options_1.LongOption.BIGINT) {
282
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== BigInt("0")`;
280
+ return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} !${place}.equals(${defaultValue(ctx, field)})`;
283
281
  }
284
282
  else {
285
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== 0`;
283
+ return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ${defaultValue(ctx, field)}`;
286
284
  }
287
- case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
288
- return (0, ts_poet_1.code) `${place} === true`;
289
- case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
290
- return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== ""`;
291
285
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
286
+ // todo(proto2): need to look into all the possible default values for the bytes type, and handle each one
292
287
  return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place}.length !== 0`;
293
288
  default:
294
289
  throw new Error("Not implemented for the given type.");
@@ -339,11 +334,16 @@ exports.isScalar = isScalar;
339
334
  // optional properties, with the exception of map Entry key/values, which must
340
335
  // always be present.
341
336
  // OneOf fields are always optional, whenever oneof=unions option not in use.
342
- function isOptionalProperty(field, messageOptions, options) {
337
+ function isOptionalProperty(field, messageOptions, options, isProto3Syntax) {
343
338
  const optionalMessages = options.useOptionals === true || options.useOptionals === "messages" || options.useOptionals === "all";
344
339
  const optionalAll = options.useOptionals === "all";
345
340
  return ((optionalMessages && isMessage(field) && !isRepeated(field)) ||
346
341
  (optionalAll && !(messageOptions === null || messageOptions === void 0 ? void 0 : messageOptions.mapEntry)) ||
342
+ // file is proto2, we have enabled proto2 optionals, and the field itself is optional
343
+ (!isProto3Syntax &&
344
+ field.label === ts_proto_descriptors_1.FieldDescriptorProto_Label.LABEL_OPTIONAL &&
345
+ !(messageOptions === null || messageOptions === void 0 ? void 0 : messageOptions.mapEntry) &&
346
+ !options.disableProto2Optionals) ||
347
347
  // don't bother verifying that oneof is not union. union oneofs generate their own properties.
348
348
  isWithinOneOf(field) ||
349
349
  field.proto3Optional);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.167.9",
3
+ "version": "1.169.0",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",