ts-proto 1.136.1 → 1.137.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
@@ -5,8 +5,6 @@
5
5
 
6
6
  > `ts-proto` transforms your `.proto` files into strongly-typed, idiomatic TypeScript files!
7
7
 
8
- (Note, if you're a new user of ts-proto and using a modern TS setup with `esModuleInterop`, or want to use ts-proto in ESM / snowpack / vite, you need to also pass that as a `ts_proto_opt`.)
9
-
10
8
  ## Table of contents
11
9
 
12
10
  - [ts-proto](#ts-proto)
@@ -14,6 +12,7 @@
14
12
  - [Overview](#overview)
15
13
  - [QuickStart](#quickstart)
16
14
  - [Buf](#buf)
15
+ - [ESM](#esm)
17
16
  - [Goals](#goals)
18
17
  - [Example Types](#example-types)
19
18
  - [Highlights](#highlights)
@@ -118,6 +117,13 @@ plugins:
118
117
  - useExactTypes=...
119
118
  ```
120
119
 
120
+ ## ESM
121
+
122
+ If you're using a modern TS setup with either `esModuleInterop` or running in an ESM environment, you'll need to pass `ts_proto_opt`s of:
123
+
124
+ * `esModuleInterop=true` if using `esModuleInterop` in your `tsconfig.json`, and
125
+ * `importSuffix=.js` if executing the generated ts-proto code in an ESM environment
126
+
121
127
  # Goals
122
128
 
123
129
  In terms of the code that `ts-proto` generates, the general goals are:
@@ -283,7 +289,9 @@ Generated code will be placed in the Gradle build directory.
283
289
 
284
290
  - With `--ts_proto_opt=forceLong=long`, all 64-bit numbers will be parsed as instances of `Long` (using the [long](https://www.npmjs.com/package/long) library).
285
291
 
286
- Alternatively, if you pass `--ts_proto_opt=forceLong=string`, all 64-bit numbers will be outputted as strings.
292
+ With `--ts_proto_opt=forceLong=string`, all 64-bit numbers will be output as strings.
293
+
294
+ 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.
287
295
 
288
296
  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`.
289
297
 
@@ -567,7 +575,7 @@ The commands below assume you have **Docker** installed. To use a **local** copy
567
575
 
568
576
  - Check out the [repository]() for the latest code.
569
577
  - Run `yarn install` to install the dependencies.
570
- - Run `yarn build:test` or `yarn build:test:local` to generate the test files.
578
+ - Run `yarn build:test` to generate the test files.
571
579
  > _This runs the following commands:_
572
580
  >
573
581
  > - `proto2bin` — Converts integration test `.proto` files to `.bin`.
@@ -577,25 +585,24 @@ The commands below assume you have **Docker** installed. To use a **local** copy
577
585
 
578
586
  **Workflow**
579
587
 
580
- - Modifying the plugin implementation:
581
- - The most important logic is found in [src/main.ts](src/main.ts).
582
- - Run `yarn bin2ts` or `yarn bin2ts:local`.
583
- _Since the proto files were not changed, you only need to regenerate the typescript files._
584
- - Run `yarn test` to verify the typescript files are compatible with the reference implementation, and pass other tests.
585
- - Updating or adding `.proto` files in the integration directory:
586
- - Run `yarn watch` to automatically regenerate test files when proto files change.
587
- - Or run `yarn build:test` to regenerate all integration test files.
588
- - Run `yarn test` to retest.
589
-
590
- **Contributing**
591
-
592
- - Run `yarn build:test` and `yarn test` to make sure everything works.
593
- - Run `yarn format` to format the typescript files.
594
- - Commit the changes:
595
- - Also include the generated `.bin` files for the tests where you added or modified `.proto` files.
596
- > These are checked into git so that the test suite can run without having to invoke the `protoc` build chain.
597
- - Also include the generated `.ts` files.
598
- - Create a pull request
588
+ - Add/update an integration test for your use case
589
+ - Either find an existing `integration/*` test that is close enough to your use case, e.g. has a `parameters.txt` that matches the `ts_proto_opt` params necessary to reproduce your use case
590
+ - If creating a new integration test:
591
+ - Make a new `integration/your-new-test/parameters.txt` with the necessary `ts_proto_opt` params
592
+ - Create a minimal `integration/your-new-test/your-new-test.proto` schema to reproduce your use case
593
+ - After any changes to `your-new-test.proto`, or an existing `integration/*.proto` file, run `yarn proto2bin`
594
+ - You can also leave `yarn watch` running, and it should "just do the right thing"
595
+ - Add/update a `integration/your-new-test/some-test.ts` unit test, even if it's as trivial as just making sure the generated code compiles
596
+ - Modify the `ts-proto` code generation logic:
597
+ - Most important logic is found in [src/main.ts](src/main.ts).
598
+ - After any changes to `src/*.ts` files, run `yarn bin2ts` to re-codegen all integration tests
599
+ - Or `yarn bin2ts your-new-test` to re-codegen a specific test
600
+ - Again leaving `yarn watch` running should "just do the right thing"
601
+ - Run `yarn test` to verify your changes pass all existing tests
602
+ - Commit and submit a PR
603
+ - Run `yarn format` to format the typescript files.
604
+ - Make sure to `git add` all of the `*.proto`, `*.bin`, and `*.ts` files in `integration/your-new-test`
605
+ - Sometimes checking in generated code is frowned upon, but given ts-proto's main job is to generate code, seeing the codegen diffs in PRs is helpful
599
606
 
600
607
  **Dockerized Protoc**
601
608
 
package/build/encode.js CHANGED
@@ -12,7 +12,11 @@ function generateEncoder(ctx, typeName) {
12
12
  }
13
13
  if (name == "Timestamp") {
14
14
  const TimestampValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/timestamp", name);
15
- return (0, ts_poet_1.code) `${TimestampValue}.encode(${ctx.utils.toTimestamp}(value)).finish()`;
15
+ let value = (0, ts_poet_1.code) `value`;
16
+ if (ctx.options.useDate === options_1.DateOption.DATE || ctx.options.useDate === options_1.DateOption.STRING) {
17
+ value = (0, ts_poet_1.code) `${ctx.utils.toTimestamp}(${value})`;
18
+ }
19
+ return (0, ts_poet_1.code) `${TimestampValue}.encode(${value}).finish()`;
16
20
  }
17
21
  if (name == "Struct") {
18
22
  const StructType = (0, utils_1.impProto)(ctx.options, "google/protobuf/struct", name);
@@ -54,7 +58,11 @@ function generateDecoder(ctx, typeName) {
54
58
  let TypeValue;
55
59
  if (name == "Timestamp") {
56
60
  TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/timestamp", name);
57
- return (0, ts_poet_1.code) `${TypeValue}.decode(value)`;
61
+ const decoder = (0, ts_poet_1.code) `${TypeValue}.decode(value)`;
62
+ if (ctx.options.useDate === options_1.DateOption.DATE || ctx.options.useDate === options_1.DateOption.STRING) {
63
+ return (0, ts_poet_1.code) `${ctx.utils.fromTimestamp}(${decoder})`;
64
+ }
65
+ return decoder;
58
66
  }
59
67
  if (name == "Struct" || name == "ListValue") {
60
68
  TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/struct", name);
package/build/main.js CHANGED
@@ -286,6 +286,11 @@ function makeLongUtils(options, bytes) {
286
286
  return long.toString();
287
287
  }
288
288
  `);
289
+ const longToBigint = (0, ts_poet_1.conditionalOutput)("longToBigint", (0, ts_poet_1.code) `
290
+ function longToBigint(long: ${Long}) {
291
+ return BigInt(long.toString());
292
+ }
293
+ `);
289
294
  const longToNumber = (0, ts_poet_1.conditionalOutput)("longToNumber", (0, ts_poet_1.code) `
290
295
  function longToNumber(long: ${Long}): number {
291
296
  if (long.gt(Number.MAX_SAFE_INTEGER)) {
@@ -294,7 +299,7 @@ function makeLongUtils(options, bytes) {
294
299
  return long.toNumber();
295
300
  }
296
301
  `);
297
- return { numberToLong, longToNumber, longToString, Long };
302
+ return { numberToLong, longToNumber, longToString, longToBigint, Long };
298
303
  }
299
304
  function makeByteUtils() {
300
305
  const globalThis = (0, ts_poet_1.conditionalOutput)("tsProtoGlobalThis", (0, ts_poet_1.code) `
@@ -409,6 +414,10 @@ function makeTimestampMethods(options, longs) {
409
414
  toNumberCode = "t.seconds.toNumber()";
410
415
  seconds = (0, ts_poet_1.code) `${longs.numberToLong}(date.getTime() / 1_000)`;
411
416
  }
417
+ else if (options.forceLong === options_1.LongOption.BIGINT) {
418
+ toNumberCode = "Number(t.seconds.toString())";
419
+ seconds = (0, ts_poet_1.code) `BigInt(Math.trunc(date.getTime() / 1_000))`;
420
+ }
412
421
  else if (options.forceLong === options_1.LongOption.STRING) {
413
422
  toNumberCode = "Number(t.seconds)";
414
423
  // Must discard the fractional piece here
@@ -655,6 +664,9 @@ function generateDecode(ctx, fullName, messageDesc) {
655
664
  else if (options.forceLong === options_1.LongOption.STRING) {
656
665
  readSnippet = (0, ts_poet_1.code) `${utils.longToString}(${readSnippet} as Long)`;
657
666
  }
667
+ else if (options.forceLong === options_1.LongOption.BIGINT) {
668
+ readSnippet = (0, ts_poet_1.code) `${utils.longToBigint}(${readSnippet} as Long)`;
669
+ }
658
670
  else {
659
671
  readSnippet = (0, ts_poet_1.code) `${utils.longToNumber}(${readSnippet} as Long)`;
660
672
  }
@@ -781,6 +793,10 @@ function generateEncode(ctx, fullName, messageDesc) {
781
793
  const toNumber = (0, types_1.getEnumMethod)(ctx, field.typeName, "ToNumber");
782
794
  writeSnippet = (place) => (0, ts_poet_1.code) `writer.uint32(${tag}).${(0, types_1.toReaderCall)(field)}(${toNumber}(${place}))`;
783
795
  }
796
+ else if ((0, types_1.isLong)(field) && options.forceLong === options_1.LongOption.BIGINT) {
797
+ const tag = ((field.number << 3) | (0, types_1.basicWireType)(field.type)) >>> 0;
798
+ writeSnippet = (place) => (0, ts_poet_1.code) `writer.uint32(${tag}).${(0, types_1.toReaderCall)(field)}(${place}.toString())`;
799
+ }
784
800
  else if ((0, types_1.isScalar)(field) || (0, types_1.isEnum)(field)) {
785
801
  const tag = ((field.number << 3) | (0, types_1.basicWireType)(field.type)) >>> 0;
786
802
  writeSnippet = (place) => (0, ts_poet_1.code) `writer.uint32(${tag}).${(0, types_1.toReaderCall)(field)}(${place})`;
@@ -1015,6 +1031,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1015
1031
  const cstr = (0, case_1.capitalize)((0, types_1.basicTypeName)(ctx, field, { keepValueType: true }).toCodeString());
1016
1032
  return (0, ts_poet_1.code) `${cstr}.fromValue(${from})`;
1017
1033
  }
1034
+ else if ((0, types_1.isLong)(field) && options.forceLong === options_1.LongOption.BIGINT) {
1035
+ return (0, ts_poet_1.code) `BigInt(${from})`;
1036
+ }
1018
1037
  else {
1019
1038
  const cstr = (0, case_1.capitalize)((0, types_1.basicTypeName)(ctx, field, { keepValueType: true }).toCodeString());
1020
1039
  return (0, ts_poet_1.code) `${cstr}(${from})`;
@@ -1045,6 +1064,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1045
1064
  if ((0, types_1.isLongValueType)(field) && options.forceLong === options_1.LongOption.LONG) {
1046
1065
  return (0, ts_poet_1.code) `${(0, case_1.capitalize)(valueType.toCodeString())}.fromValue(${from})`;
1047
1066
  }
1067
+ else if ((0, types_1.isLongValueType)(field) && options.forceLong === options_1.LongOption.BIGINT) {
1068
+ return (0, ts_poet_1.code) `BigInt(${from})`;
1069
+ }
1048
1070
  else if ((0, types_1.isBytesValueType)(field)) {
1049
1071
  return (0, ts_poet_1.code) `new ${(0, case_1.capitalize)(valueType.toCodeString())}(${from})`;
1050
1072
  }
@@ -1267,6 +1289,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1267
1289
  else if ((0, types_1.isLong)(valueType) && options.forceLong === options_1.LongOption.LONG) {
1268
1290
  return (0, ts_poet_1.code) `${from}.toString()`;
1269
1291
  }
1292
+ else if ((0, types_1.isLong)(valueType) && options.forceLong === options_1.LongOption.BIGINT) {
1293
+ return (0, ts_poet_1.code) `${from}.toString()`;
1294
+ }
1270
1295
  else if ((0, types_1.isWholeNumber)(valueType) && !((0, types_1.isLong)(valueType) && options.forceLong === options_1.LongOption.STRING)) {
1271
1296
  return (0, ts_poet_1.code) `Math.round(${from})`;
1272
1297
  }
@@ -1304,6 +1329,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1304
1329
  const v = (0, types_1.isWithinOneOf)(field) ? "undefined" : (0, types_1.defaultValue)(ctx, field);
1305
1330
  return (0, ts_poet_1.code) `(${from} || ${v}).toString()`;
1306
1331
  }
1332
+ else if ((0, types_1.isLong)(field) && options.forceLong === options_1.LongOption.BIGINT) {
1333
+ return (0, ts_poet_1.code) `${from}.toString()`;
1334
+ }
1307
1335
  else if ((0, types_1.isWholeNumber)(field) && !((0, types_1.isLong)(field) && options.forceLong === options_1.LongOption.STRING)) {
1308
1336
  return (0, ts_poet_1.code) `Math.round(${from})`;
1309
1337
  }
@@ -1512,11 +1540,15 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1512
1540
  function generateWrap(ctx, fullProtoTypeName, fieldNames) {
1513
1541
  const chunks = [];
1514
1542
  if ((0, types_1.isStructTypeName)(fullProtoTypeName)) {
1543
+ let setStatement = "struct.fields[key] = object[key];";
1544
+ if (ctx.options.useMapType) {
1545
+ setStatement = "struct.fields.set(key, object[key]);";
1546
+ }
1515
1547
  chunks.push((0, ts_poet_1.code) `wrap(object: {[key: string]: any} | undefined): Struct {
1516
1548
  const struct = createBaseStruct();
1517
1549
  if (object !== undefined) {
1518
1550
  Object.keys(object).forEach(key => {
1519
- struct.fields[key] = object[key];
1551
+ ${setStatement}
1520
1552
  });
1521
1553
  }
1522
1554
  return struct;
@@ -1593,13 +1625,24 @@ function generateWrap(ctx, fullProtoTypeName, fieldNames) {
1593
1625
  function generateUnwrap(ctx, fullProtoTypeName, fieldNames) {
1594
1626
  const chunks = [];
1595
1627
  if ((0, types_1.isStructTypeName)(fullProtoTypeName)) {
1596
- chunks.push((0, ts_poet_1.code) `unwrap(message: Struct): {[key: string]: any} {
1597
- const object: { [key: string]: any } = {};
1598
- Object.keys(message.fields).forEach(key => {
1599
- object[key] = message.fields[key];
1600
- });
1601
- return object;
1602
- }`);
1628
+ if (ctx.options.useMapType) {
1629
+ chunks.push((0, ts_poet_1.code) `unwrap(message: Struct): {[key: string]: any} {
1630
+ const object: { [key: string]: any } = {};
1631
+ [...message.fields.keys()].forEach((key) => {
1632
+ object[key] = message.fields.get(key);
1633
+ });
1634
+ return object;
1635
+ }`);
1636
+ }
1637
+ else {
1638
+ chunks.push((0, ts_poet_1.code) `unwrap(message: Struct): {[key: string]: any} {
1639
+ const object: { [key: string]: any } = {};
1640
+ Object.keys(message.fields).forEach(key => {
1641
+ object[key] = message.fields[key];
1642
+ });
1643
+ return object;
1644
+ }`);
1645
+ }
1603
1646
  }
1604
1647
  if ((0, types_1.isAnyValueTypeName)(fullProtoTypeName)) {
1605
1648
  if (ctx.options.oneof === options_1.OneofOption.UNIONS) {
@@ -1619,25 +1662,25 @@ function generateUnwrap(ctx, fullProtoTypeName, fieldNames) {
1619
1662
  } else {
1620
1663
  return undefined;
1621
1664
  }
1622
- }`);
1665
+ }`);
1623
1666
  }
1624
1667
  else {
1625
1668
  chunks.push((0, ts_poet_1.code) `unwrap(message: Value): string | number | boolean | Object | null | Array<any> | undefined {
1626
- if (message?.${fieldNames.stringValue} !== undefined) {
1627
- return message.${fieldNames.stringValue};
1628
- } else if (message?.${fieldNames.numberValue} !== undefined) {
1629
- return message.${fieldNames.numberValue};
1630
- } else if (message?.${fieldNames.boolValue} !== undefined) {
1631
- return message.${fieldNames.boolValue};
1632
- } else if (message?.${fieldNames.structValue} !== undefined) {
1633
- return message.${fieldNames.structValue};
1634
- } else if (message?.${fieldNames.listValue} !== undefined) {
1635
- return message.${fieldNames.listValue};
1636
- } else if (message?.${fieldNames.nullValue} !== undefined) {
1637
- return null;
1638
- }
1639
- return undefined;
1640
- }`);
1669
+ if (message?.${fieldNames.stringValue} !== undefined) {
1670
+ return message.${fieldNames.stringValue};
1671
+ } else if (message?.${fieldNames.numberValue} !== undefined) {
1672
+ return message.${fieldNames.numberValue};
1673
+ } else if (message?.${fieldNames.boolValue} !== undefined) {
1674
+ return message.${fieldNames.boolValue};
1675
+ } else if (message?.${fieldNames.structValue} !== undefined) {
1676
+ return message.${fieldNames.structValue};
1677
+ } else if (message?.${fieldNames.listValue} !== undefined) {
1678
+ return message.${fieldNames.listValue};
1679
+ } else if (message?.${fieldNames.nullValue} !== undefined) {
1680
+ return null;
1681
+ }
1682
+ return undefined;
1683
+ }`);
1641
1684
  }
1642
1685
  }
1643
1686
  if ((0, types_1.isListValueTypeName)(fullProtoTypeName)) {
package/build/options.js CHANGED
@@ -6,6 +6,7 @@ var LongOption;
6
6
  LongOption["NUMBER"] = "number";
7
7
  LongOption["LONG"] = "long";
8
8
  LongOption["STRING"] = "string";
9
+ LongOption["BIGINT"] = "bigint";
9
10
  })(LongOption = exports.LongOption || (exports.LongOption = {}));
10
11
  var DateOption;
11
12
  (function (DateOption) {
package/build/types.js CHANGED
@@ -192,6 +192,9 @@ function defaultValue(ctx, field) {
192
192
  else if (options.forceLong === options_1.LongOption.STRING) {
193
193
  return '"0"';
194
194
  }
195
+ else if (options.forceLong === options_1.LongOption.BIGINT) {
196
+ return 'BigInt("0")';
197
+ }
195
198
  else {
196
199
  return 0;
197
200
  }
@@ -204,6 +207,9 @@ function defaultValue(ctx, field) {
204
207
  else if (options.forceLong === options_1.LongOption.STRING) {
205
208
  return '"0"';
206
209
  }
210
+ else if (options.forceLong === options_1.LongOption.BIGINT) {
211
+ return 'BigInt("0")';
212
+ }
207
213
  else {
208
214
  return 0;
209
215
  }
@@ -263,6 +269,9 @@ function notDefaultCheck(ctx, field, messageOptions, place) {
263
269
  else if (options.forceLong === options_1.LongOption.STRING) {
264
270
  return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== "0"`;
265
271
  }
272
+ else if (options.forceLong === options_1.LongOption.BIGINT) {
273
+ return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== BigInt("0")`;
274
+ }
266
275
  else {
267
276
  return (0, ts_poet_1.code) `${maybeNotUndefinedAnd} ${place} !== 0`;
268
277
  }
@@ -508,6 +517,9 @@ function longTypeName(ctx) {
508
517
  else if (options.forceLong === options_1.LongOption.STRING) {
509
518
  return (0, ts_poet_1.code) `string`;
510
519
  }
520
+ else if (options.forceLong === options_1.LongOption.BIGINT) {
521
+ return (0, ts_poet_1.code) `bigint`;
522
+ }
511
523
  else {
512
524
  return (0, ts_poet_1.code) `number`;
513
525
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.136.1",
3
+ "version": "1.137.1",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",