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 +30 -23
- package/build/encode.js +10 -2
- package/build/main.js +68 -25
- package/build/options.js +1 -0
- package/build/types.js +12 -0
- package/package.json +1 -1
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
|
-
|
|
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`
|
|
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
|
-
-
|
|
581
|
-
-
|
|
582
|
-
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
-
|
|
593
|
-
- Run `yarn
|
|
594
|
-
- Commit
|
|
595
|
-
-
|
|
596
|
-
|
|
597
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
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
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
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
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
|
}
|