ts-proto 2.11.10 → 2.12.1

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
@@ -7,7 +7,7 @@
7
7
 
8
8
  ## ts-proto 2.x Release Notes
9
9
 
10
- The 2.x release of ts-proto migrated the low-level Protobuf serializing that its `encode` and `decode` method use from the venerable, but aging & stagnant, `protobufjs` package to `@bufbuild/protobuf`.
10
+ The 2.x release of ts-proto migrated the low-level Protobuf serializing that its `encode` and `decode` method use from the venerable `protobufjs` package to `@bufbuild/protobuf`.
11
11
 
12
12
  If you only used the `encode` and `decode` methods, this should largely be a non-breaking change.
13
13
 
@@ -321,7 +321,7 @@ Generated code will be placed in the Gradle build directory.
321
321
 
322
322
  With `--ts_proto_opt=forceLong=string`, all 64-bit numbers will be output as strings.
323
323
 
324
- With `--ts_proto_opt=forceLong=bigint`, all 64-bit numbers will be output as `BigInt`s. This option still uses the `long` library to encode/decode internally within `protobuf.js`, but then converts to/from `BigInt`s in the ts-proto-generated code.
324
+ With `--ts_proto_opt=forceLong=bigint`, all 64-bit numbers will be output as `BigInt`s. This option still uses the `long` library to encode/decode internally within `protobuf.js`, but then converts to/from `BigInt`s in the ts-proto-generated code. As with `forceLong=long`, `DeepPartial` widens 64-bit fields to `string | number | bigint`, and `fromPartial`/`create` coerce those inputs to `BigInt` (matching what `fromJSON` already does), so you can pass a string or number and get a `BigInt` back.
325
325
 
326
326
  The default behavior is `forceLong=number`, which will internally still use the `long` library to encode/decode values on the wire (so you will still see a `util.Long = Long` line in your output), but will convert the `long` values to `number` automatically for you. Note that a runtime error is thrown if, while doing this conversion, a 64-bit value is larger than can be correctly stored as a `number`.
327
327
 
package/build/src/main.js CHANGED
@@ -492,6 +492,8 @@ function makeDeepPartial(options, longs) {
492
492
  const maybeExport = options.exportCommonSymbols ? "export" : "";
493
493
  // Allow passing longs as numbers or strings, nad we'll convert them
494
494
  const maybeLong = options.forceLong === options_1.LongOption.LONG ? (0, ts_poet_1.code) ` : T extends ${longs.Long} ? string | number | Long ` : "";
495
+ // Allow passing bigints as numbers or strings; fromPartial coerces them via BigInt()
496
+ const maybeBigInt = options.forceLong === options_1.LongOption.BIGINT ? (0, ts_poet_1.code) `T extends bigint ? string | number | bigint : ` : "";
495
497
  const optionalBuiltins = [];
496
498
  if (options.forceLong === options_1.LongOption.BIGINT) {
497
499
  optionalBuiltins.push("bigint");
@@ -512,7 +514,7 @@ function makeDeepPartial(options, longs) {
512
514
  // Based on the type from ts-essentials
513
515
  const keys = (0, options_1.addTypeToMessages)(options) ? (0, ts_poet_1.code) `Exclude<keyof T, '$type'>` : (0, ts_poet_1.code) `keyof T`;
514
516
  const DeepPartial = (0, ts_poet_1.conditionalOutput)("DeepPartial", (0, ts_poet_1.code) `
515
- ${maybeExport} type DeepPartial<T> = T extends ${Builtin}
517
+ ${maybeExport} type DeepPartial<T> = ${maybeBigInt} T extends ${Builtin}
516
518
  ? T
517
519
  ${maybeLong}
518
520
  : T extends globalThis.Array<infer U>
@@ -720,7 +722,7 @@ function makeTimestampMethods(options, longs, bytes) {
720
722
  const seconds = ${seconds};
721
723
  const remainder = instant.round({ smallestUnit: "seconds", roundingMode: "floor" }).until(instant);
722
724
  const nanos = (remainder.milliseconds * 1_000_000) + (remainder.microseconds * 1_000) + remainder.nanoseconds;
723
-
725
+
724
726
  return { ${maybeTypeField} seconds, nanos };
725
727
  }
726
728
  `
@@ -1087,7 +1089,13 @@ function generateDecode(ctx, fullName, messageDesc) {
1087
1089
  length?: number,
1088
1090
  ): ${fullName} {
1089
1091
  const reader = input instanceof ${BinaryReader} ? input : new ${BinaryReader}(input);
1090
- const end = length === undefined ? reader.len : reader.pos + length;
1092
+ const previousRecursionDepth = (reader as any).__tsProtoDecodeDepth ?? 0;
1093
+ if (previousRecursionDepth >= 100) {
1094
+ throw new ${ctx.utils.globalThis}.Error("protobuf decode recursion limit exceeded");
1095
+ }
1096
+ (reader as any).__tsProtoDecodeDepth = previousRecursionDepth + 1;
1097
+ try {
1098
+ const end = length === undefined ? reader.len : reader.pos + length;
1091
1099
  `);
1092
1100
  chunks.push((0, ts_poet_1.code) `const message = ${createBase}${maybeAsAny(options)};`);
1093
1101
  // start the tag loop
@@ -1253,7 +1261,12 @@ function generateDecode(ctx, fullName, messageDesc) {
1253
1261
  // and then wrap up the while/return
1254
1262
  chunks.push((0, ts_poet_1.code) `}`);
1255
1263
  chunks.push((0, ts_poet_1.code) `return message;`);
1256
- chunks.push((0, ts_poet_1.code) `}`);
1264
+ chunks.push((0, ts_poet_1.code) `
1265
+ } finally {
1266
+ (reader as any).__tsProtoDecodeDepth = previousRecursionDepth;
1267
+ }
1268
+ }
1269
+ `);
1257
1270
  return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
1258
1271
  }
1259
1272
  /** Returns a generic writer.doSomething based on the basic type */
@@ -2037,7 +2050,10 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2037
2050
  protoJsonComparison = (0, ts_poet_1.code) `
2038
2051
  : ${ctx.utils.isObject}(${protoJsonProperty})
2039
2052
  ? (${ctx.utils.globalThis}.Object.entries(${protoJsonProperty}) as [string, any][]).reduce((acc: ${fieldType}, [key, value]: [string, any]) => {
2040
- acc[${i}] = ${readSnippet("value")};
2053
+ ${ctx.utils.globalThis}.Object.defineProperty(acc, ${i}, {
2054
+ value: ${readSnippet("value")},
2055
+ enumerable: true, configurable: true, writable: true,
2056
+ });
2041
2057
  return acc;
2042
2058
  }, {})
2043
2059
  `;
@@ -2045,7 +2061,10 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2045
2061
  chunks.push((0, ts_poet_1.code) `
2046
2062
  ${fieldKey}: ${ctx.utils.isObject}(${jsonProperty})
2047
2063
  ? (${ctx.utils.globalThis}.Object.entries(${jsonProperty}) as [string, any][]).reduce((acc: ${fieldType}, [key, value]: [string, any]) => {
2048
- acc[${i}] = ${readSnippet("value")};
2064
+ ${ctx.utils.globalThis}.Object.defineProperty(acc, ${i}, {
2065
+ value: ${readSnippet("value")},
2066
+ enumerable: true, configurable: true, writable: true,
2067
+ });
2049
2068
  return acc;
2050
2069
  }, {})
2051
2070
  ${protoJsonComparison}
@@ -2219,6 +2238,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2219
2238
  const jsonName = (0, utils_1.getFieldJsonName)(field, options);
2220
2239
  const jsonProperty = (0, utils_1.getPropertyAccessor)("obj", jsonName);
2221
2240
  const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
2241
+ const setJsonProperty = (value) => jsonName === "__proto__"
2242
+ ? (0, ts_poet_1.code) `${utils.globalThis}.Object.defineProperty(obj, "__proto__", { value: ${value}, enumerable: true });`
2243
+ : (0, ts_poet_1.code) `${jsonProperty} = ${value};`;
2222
2244
  const readSnippet = (from) => {
2223
2245
  if ((0, types_1.isEnum)(field)) {
2224
2246
  const toJson = (0, types_1.getEnumMethod)(ctx, field.typeName, "ToJSON");
@@ -2330,7 +2352,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2330
2352
  if ((0, types_1.shouldGenerateJSMapType)(ctx, messageDesc, field)) {
2331
2353
  chunks.push((0, ts_poet_1.code) `
2332
2354
  if (${messageProperty}?.size) {
2333
- ${jsonProperty} = {};
2355
+ ${setJsonProperty("{}")}
2334
2356
  ${messageProperty}.forEach((v, k) => {
2335
2357
  ${jsonProperty}[${i}] = ${readSnippet("v")};
2336
2358
  });
@@ -2343,7 +2365,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2343
2365
  if (${messageProperty}) {
2344
2366
  const entries = ${utils.globalThis}.Object.entries(${messageProperty}) as [string, ${mapInfo.valueType}][];
2345
2367
  if (entries.length > 0) {
2346
- ${jsonProperty} = {};
2368
+ ${setJsonProperty("{}")}
2347
2369
  entries.forEach(([k, v]) => {
2348
2370
  ${jsonProperty}[${i}] = ${readSnippet("v")};
2349
2371
  });
@@ -2358,7 +2380,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2358
2380
  const maybeMap = needMap ? (0, ts_poet_1.code) `.map(e => ${readSnippet("e")})` : "";
2359
2381
  chunks.push((0, ts_poet_1.code) `
2360
2382
  if (${messageProperty}?.length) {
2361
- ${jsonProperty} = ${messageProperty}${maybeMap};
2383
+ ${setJsonProperty((0, ts_poet_1.code) `${messageProperty}${maybeMap}`)}
2362
2384
  }
2363
2385
  `);
2364
2386
  }
@@ -2370,7 +2392,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2370
2392
  const valueName = (0, utils_1.oneofValueName)(fieldName, options);
2371
2393
  chunks.push((0, ts_poet_1.code) `
2372
2394
  ${currentIfTarget === oneofNameWithMessage ? "else " : ""}if (${oneofNameWithMessage}?.$case === '${fieldName}') {
2373
- ${jsonProperty} = ${readSnippet(`${oneofNameWithMessage}.${valueName}`)};
2395
+ ${setJsonProperty(readSnippet(`${oneofNameWithMessage}.${valueName}`))}
2374
2396
  }
2375
2397
  `);
2376
2398
  currentIfTarget = oneofNameWithMessage;
@@ -2382,7 +2404,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2382
2404
  : `${messageProperty} !== undefined ${(0, utils_1.withAndMaybeCheckIsNotNull)(options, messageProperty)}`;
2383
2405
  chunks.push((0, ts_poet_1.code) `
2384
2406
  if (${check}) {
2385
- ${jsonProperty} = ${readSnippet(`${messageProperty}`)};
2407
+ ${setJsonProperty(readSnippet(`${messageProperty}`))}
2386
2408
  }
2387
2409
  `);
2388
2410
  }
@@ -2443,6 +2465,11 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2443
2465
  !(0, types_1.isJsTypeFieldOption)(options, field)) {
2444
2466
  return (0, ts_poet_1.code) `Long.fromValue(${from})`;
2445
2467
  }
2468
+ else if (((0, types_1.isLong)(field) || (0, types_1.isLongValueType)(field)) &&
2469
+ options.forceLong === options_1.LongOption.BIGINT &&
2470
+ !(0, types_1.isJsTypeFieldOption)(options, field)) {
2471
+ return (0, ts_poet_1.code) `BigInt(${from})`;
2472
+ }
2446
2473
  else if ((0, types_1.isObjectId)(field) && options.useMongoObjectId) {
2447
2474
  return (0, ts_poet_1.code) `${from} as mongodb.ObjectId`;
2448
2475
  }
@@ -296,7 +296,7 @@ function defaultValue(ctx, field) {
296
296
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
297
297
  return useDefaultValue ? field.defaultValue : false;
298
298
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
299
- return useDefaultValue ? `"${field.defaultValue}"` : '""';
299
+ return useDefaultValue ? JSON.stringify(field.defaultValue) : '""';
300
300
  case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
301
301
  // todo(proto2): need to look into all the possible default values for the bytes type, and handle each one
302
302
  if (options.env === options_1.EnvOption.NODE) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "2.11.10",
3
+ "version": "2.12.1",
4
4
  "description": "",
5
5
  "main": "build/src/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",