ts-proto 2.2.0 → 2.2.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 +13 -13
- package/build/src/generate-services.js +1 -1
- package/build/src/main.js +20 -8
- package/build/src/schema.js +3 -3
- package/build/src/sourceInfo.d.ts +3 -3
- package/build/src/sourceInfo.js +3 -3
- package/package.json +1 -1
package/README.markdown
CHANGED
|
@@ -118,7 +118,7 @@ plugins:
|
|
|
118
118
|
path: ../node_modules/ts-proto/protoc-gen-ts_proto
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
To prevent `buf push` from reading
|
|
121
|
+
To prevent `buf push` from reading irrelevant `.proto` files, configure `buf.yaml` like so:
|
|
122
122
|
|
|
123
123
|
```yaml
|
|
124
124
|
build:
|
|
@@ -150,7 +150,7 @@ In terms of the code that `ts-proto` generates, the general goals are:
|
|
|
150
150
|
|
|
151
151
|
- Idiomatic TypeScript/ES6 types
|
|
152
152
|
- `ts-proto` is a clean break from either the built-in Google/Java-esque JS code of `protoc` or the "make `.d.ts` files the `*.js` comments" approach of `protobufjs`
|
|
153
|
-
- (
|
|
153
|
+
- (Technically the `protobufjs/minimal` package is used for actually reading/writing bytes.)
|
|
154
154
|
- TypeScript-first output
|
|
155
155
|
- Interfaces over classes
|
|
156
156
|
- As much as possible, types are just interfaces, so you can work with messages just like regular hashes/data structures.
|
|
@@ -248,7 +248,7 @@ creating a class and calling the right getters/setters.
|
|
|
248
248
|
|
|
249
249
|
(Note: this is currently only supported by the Twirp clients.)
|
|
250
250
|
|
|
251
|
-
If you're using ts-proto's clients to call backend micro-services, similar to the N+1 problem in SQL applications, it is easy for micro-service clients to (when serving an individual request)
|
|
251
|
+
If you're using ts-proto's clients to call backend micro-services, similar to the N+1 problem in SQL applications, it is easy for micro-service clients to (when serving an individual request) inadvertently trigger multiple separate RPC calls for "get book 1", "get book 2", "get book 3", that should really be batched into a single "get books [1, 2, 3]" (assuming the backend supports a batch-oriented RPC method).
|
|
252
252
|
|
|
253
253
|
ts-proto can help with this, and essentially auto-batch your individual "get book" calls into batched "get books" calls.
|
|
254
254
|
|
|
@@ -262,7 +262,7 @@ For ts-proto to do this, you need to implement your service's RPC methods with t
|
|
|
262
262
|
|
|
263
263
|
When ts-proto recognizes methods of this pattern, it will automatically create a "non-batch" version of `<OperationName>` for the client, i.e. `client.Get<OperationName>`, that takes a single id and returns a single result.
|
|
264
264
|
|
|
265
|
-
This provides the client code with the illusion that it can make individual `Get<OperationName>` calls (which is generally
|
|
265
|
+
This provides the client code with the illusion that it can make individual `Get<OperationName>` calls (which is generally preferable/easier when implementing the client's business logic), but the actual implementation that ts-proto provides will end up making `Batch<OperationName>` calls to the backend service.
|
|
266
266
|
|
|
267
267
|
You also need to enable the `useContext=true` build-time parameter, which gives all client methods a Go-style `ctx` parameter, with a `getDataLoaders` method that lets ts-proto cache/resolve request-scoped [DataLoaders](https://github.com/graphql/dataloader), which provide the fundamental auto-batch detection/flushing behavior.
|
|
268
268
|
|
|
@@ -325,7 +325,7 @@ Generated code will be placed in the Gradle build directory.
|
|
|
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
|
|
|
328
|
-
- With `--ts_proto_opt=useJsTypeOverride`, 64-bit numbers will be
|
|
328
|
+
- With `--ts_proto_opt=useJsTypeOverride`, 64-bit numbers will be output as the [FieldOption.JSType](https://protobuf.dev/reference/java/api-docs/com/google/protobuf/DescriptorProtos.FieldOptions.JSType) specified on the field. This takes precedence over the `forceLong` option provided.
|
|
329
329
|
|
|
330
330
|
- With `--ts_proto_opt=esModuleInterop=true` changes output to be `esModuleInterop` compliant.
|
|
331
331
|
|
|
@@ -438,7 +438,7 @@ Generated code will be placed in the Gradle build directory.
|
|
|
438
438
|
|
|
439
439
|
(Requires `nestJs=true`.)
|
|
440
440
|
|
|
441
|
-
- With`--ts_proto_opt=addNestjsRestParameter=true`, the last argument of service methods will be
|
|
441
|
+
- With`--ts_proto_opt=addNestjsRestParameter=true`, the last argument of service methods will be a rest parameter with type any. This way you can use custom decorators you could normally use in nestjs.
|
|
442
442
|
|
|
443
443
|
(Requires `nestJs=true`.)
|
|
444
444
|
|
|
@@ -476,11 +476,11 @@ Generated code will be placed in the Gradle build directory.
|
|
|
476
476
|
|
|
477
477
|
- With `--ts_proto_opt=outputServices=false`, or `=none`, ts-proto will output NO service definitions.
|
|
478
478
|
|
|
479
|
-
- With `--ts_proto_opt=rpcBeforeRequest=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `beforeRequest(service: string, message: string, request: <RequestType>)`. It will
|
|
479
|
+
- With `--ts_proto_opt=rpcBeforeRequest=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `beforeRequest(service: string, message: string, request: <RequestType>)`. It will also automatically set `outputServices=default`. Each of the Service's methods will call `beforeRequest` before performing its request.
|
|
480
480
|
|
|
481
|
-
- With `--ts_proto_opt=rpcAfterResponse=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `afterResponse(service: string, message: string, response: <ResponseType>)`. It will
|
|
481
|
+
- With `--ts_proto_opt=rpcAfterResponse=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `afterResponse(service: string, message: string, response: <ResponseType>)`. It will also automatically set `outputServices=default`. Each of the Service's methods will call `afterResponse` before returning the response.
|
|
482
482
|
|
|
483
|
-
- With `--ts_proto_opt=rpcErrorHandler=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `handleError(service: string, message: string, error: Error)`. It will
|
|
483
|
+
- With `--ts_proto_opt=rpcErrorHandler=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `handleError(service: string, message: string, error: Error)`. It will also automatically set `outputServices=default`.
|
|
484
484
|
|
|
485
485
|
- With `--ts_proto_opt=useAbortSignal=true`, the generated services will accept an `AbortSignal` to cancel RPC calls.
|
|
486
486
|
|
|
@@ -522,7 +522,7 @@ Generated code will be placed in the Gradle build directory.
|
|
|
522
522
|
|
|
523
523
|
- With `--ts_proto_opt=useNumericEnumForJson=true`, the JSON converter (`toJSON`) will encode enum values as int, rather than a string literal.
|
|
524
524
|
|
|
525
|
-
- With `--ts_proto_opt=initializeFieldsAsUndefined=false`, all optional field initializers will be
|
|
525
|
+
- With `--ts_proto_opt=initializeFieldsAsUndefined=false`, all optional field initializers will be omitted from the generated base instances.
|
|
526
526
|
|
|
527
527
|
- 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.
|
|
528
528
|
|
|
@@ -533,14 +533,14 @@ Generated code will be placed in the Gradle build directory.
|
|
|
533
533
|
- `Mfoo/bar.proto=@myorg/some-lib` will map `foo/bar.proto` imports into `import ... from '@myorg/some-lib'`.
|
|
534
534
|
- `Mfoo/bar.proto=./some/local/lib` will map `foo/bar.proto` imports into `import ... from './some/local/lib'`.
|
|
535
535
|
- `Mfoo/bar.proto=some-modules/some-lib` will map `foo/bar.proto` imports into `import ... from 'some-module/some-lib'`.
|
|
536
|
-
- **Note**: Uses are
|
|
536
|
+
- **Note**: Uses are accumulated, so multiple values are expected in the form of `--ts_proto_opt=M... --ts_proto_opt=M...` (one `ts_proto_opt` per mapping).
|
|
537
537
|
- **Note**: Proto files that match mapped imports **will not be generated**.
|
|
538
538
|
|
|
539
539
|
- With `--ts_proto_opt=useMapType=true`, the generated code for protobuf `map<key_type, value_type>` will become `Map<key_type, value_type>` that uses JavaScript Map type.
|
|
540
540
|
|
|
541
541
|
The default behavior is `useMapType=false`, which makes it generate the code for protobuf `map<key_type, value_type` with the key-value pair like `{[key: key_type]: value_type}`.
|
|
542
542
|
|
|
543
|
-
- With `--ts_proto_opt=useReadonlyTypes=true`, the generated types will be declared as immutable using typescript's `readonly`
|
|
543
|
+
- With `--ts_proto_opt=useReadonlyTypes=true`, the generated types will be declared as immutable using typescript's `readonly` modifier.
|
|
544
544
|
|
|
545
545
|
- With `--ts_proto_opt=useSnakeTypeName=false` will remove snake casing from types.
|
|
546
546
|
|
|
@@ -633,7 +633,7 @@ export interface User {
|
|
|
633
633
|
}
|
|
634
634
|
```
|
|
635
635
|
|
|
636
|
-
- With `--ts_proto_opt=noDefaultsForOptionals=true`, `undefined` primitive values will not be defaulted as per the protobuf spec. Additionally unlike the standard behavior, when a field is set to
|
|
636
|
+
- With `--ts_proto_opt=noDefaultsForOptionals=true`, `undefined` primitive values will not be defaulted as per the protobuf spec. Additionally unlike the standard behavior, when a field is set to its standard default value, it *will* be encoded allowing it to be sent over the wire and distinguished from undefined values. For example if a message does not set a boolean value, ordinarily this would be defaulted to `false` which is different to it being undefined.
|
|
637
637
|
|
|
638
638
|
This option allows the library to act in a compatible way with the [Wire implementation](https://square.github.io/wire/) maintained and used by Square/Block. Note: this option should only be used in combination with other client/server code generated using Wire or ts-proto with this option enabled.
|
|
639
639
|
|
|
@@ -225,7 +225,7 @@ function generateServiceClientImpl(ctx, fileDesc, serviceDesc) {
|
|
|
225
225
|
chunks.push((0, ts_poet_1.code) `}`);
|
|
226
226
|
// Create a method for each FooService method
|
|
227
227
|
for (const methodDesc of serviceDesc.method) {
|
|
228
|
-
// See if this
|
|
228
|
+
// See if this fuzzy matches to a batchable method
|
|
229
229
|
if (options.context) {
|
|
230
230
|
const batchMethod = (0, types_1.detectBatchMethod)(ctx, fileDesc, serviceDesc, methodDesc);
|
|
231
231
|
if (batchMethod) {
|
package/build/src/main.js
CHANGED
|
@@ -1030,7 +1030,7 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
1030
1030
|
messageDesc.field.forEach((field) => {
|
|
1031
1031
|
const fieldName = (0, utils_1.getFieldName)(field, options);
|
|
1032
1032
|
const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
|
|
1033
|
-
chunks.push((0, ts_poet_1.code) `case ${field.number}
|
|
1033
|
+
chunks.push((0, ts_poet_1.code) `case ${field.number}: {`);
|
|
1034
1034
|
const tag = ((field.number << 3) | (0, types_1.basicWireType)(field.type)) >>> 0;
|
|
1035
1035
|
const tagCheck = (0, ts_poet_1.code) `
|
|
1036
1036
|
if (tag !== ${tag}) {
|
|
@@ -1083,11 +1083,23 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
1083
1083
|
}`
|
|
1084
1084
|
: "";
|
|
1085
1085
|
if ((0, types_1.packedType)(field.type) === undefined) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1086
|
+
if (options.useOptionals === "all") {
|
|
1087
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1088
|
+
${tagCheck}
|
|
1089
|
+
${initializerSnippet}
|
|
1090
|
+
const el = ${readSnippet};
|
|
1091
|
+
if (el !== undefined) {
|
|
1092
|
+
${messageProperty}${maybeNonNullAssertion}.push(el);
|
|
1093
|
+
}
|
|
1094
|
+
`);
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1098
|
+
${tagCheck}
|
|
1099
|
+
${initializerSnippet}
|
|
1100
|
+
${messageProperty}${maybeNonNullAssertion}.push(${readSnippet});
|
|
1101
|
+
`);
|
|
1102
|
+
}
|
|
1091
1103
|
}
|
|
1092
1104
|
else {
|
|
1093
1105
|
const packedTag = ((field.number << 3) | 2) >>> 0;
|
|
@@ -1110,7 +1122,7 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
1110
1122
|
}
|
|
1111
1123
|
|
|
1112
1124
|
break;
|
|
1113
|
-
`);
|
|
1125
|
+
}`);
|
|
1114
1126
|
}
|
|
1115
1127
|
}
|
|
1116
1128
|
}
|
|
@@ -1131,7 +1143,7 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
1131
1143
|
`);
|
|
1132
1144
|
}
|
|
1133
1145
|
if (!(0, types_1.isRepeated)(field) || (0, types_1.packedType)(field.type) === undefined) {
|
|
1134
|
-
chunks.push((0, ts_poet_1.code) `continue
|
|
1146
|
+
chunks.push((0, ts_poet_1.code) `continue; }`);
|
|
1135
1147
|
}
|
|
1136
1148
|
});
|
|
1137
1149
|
chunks.push((0, ts_poet_1.code) `}`);
|
package/build/src/schema.js
CHANGED
|
@@ -197,9 +197,9 @@ function encodedOptionsToOptions(ctx, extendee, encodedOptions) {
|
|
|
197
197
|
// getExtensionValue is to decode the encoded value into a message, but this
|
|
198
198
|
// Message.decode(...) method is not always included in the generated code.
|
|
199
199
|
// We should fix this so that we can always create an option definition by
|
|
200
|
-
// somehow
|
|
201
|
-
// the option
|
|
202
|
-
// please refer to
|
|
200
|
+
// somehow preemptively decoding the encoded value and then inserting it into
|
|
201
|
+
// the option definition.
|
|
202
|
+
// please refer to integration/options-types-only to see this in action
|
|
203
203
|
resultOptions.push(getExtensionValue(ctx, extension, value));
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -69,10 +69,10 @@ export default class SourceInfo implements SourceDescription {
|
|
|
69
69
|
get leadingComments(): string;
|
|
70
70
|
/** Documentation is unclear about what exactly this is */
|
|
71
71
|
get trailingComments(): string;
|
|
72
|
-
/** Detached comments are those
|
|
72
|
+
/** Detached comments are those preceding but separated by a blank non-comment line */
|
|
73
73
|
get leadingDetachedComments(): string[];
|
|
74
|
-
/** Return the source info for the field id and index
|
|
74
|
+
/** Return the source info for the field id and index specified */
|
|
75
75
|
lookup(type: FieldID, index?: number): SourceDescription;
|
|
76
|
-
/** Returns a new SourceInfo class representing the field id and index
|
|
76
|
+
/** Returns a new SourceInfo class representing the field id and index specified */
|
|
77
77
|
open(type: FieldID, index: number): SourceInfo;
|
|
78
78
|
}
|
package/build/src/sourceInfo.js
CHANGED
|
@@ -80,18 +80,18 @@ class SourceInfo {
|
|
|
80
80
|
get trailingComments() {
|
|
81
81
|
return this.selfDescription.trailingComments;
|
|
82
82
|
}
|
|
83
|
-
/** Detached comments are those
|
|
83
|
+
/** Detached comments are those preceding but separated by a blank non-comment line */
|
|
84
84
|
get leadingDetachedComments() {
|
|
85
85
|
return this.selfDescription.leadingDetachedComments;
|
|
86
86
|
}
|
|
87
|
-
/** Return the source info for the field id and index
|
|
87
|
+
/** Return the source info for the field id and index specified */
|
|
88
88
|
lookup(type, index) {
|
|
89
89
|
if (index === undefined) {
|
|
90
90
|
return this.sourceCode[`${type}`] || new EmptyDescription();
|
|
91
91
|
}
|
|
92
92
|
return this.sourceCode[`${type}.${index}`] || new EmptyDescription();
|
|
93
93
|
}
|
|
94
|
-
/** Returns a new SourceInfo class representing the field id and index
|
|
94
|
+
/** Returns a new SourceInfo class representing the field id and index specified */
|
|
95
95
|
open(type, index) {
|
|
96
96
|
const prefix = `${type}.${index}.`;
|
|
97
97
|
const map = {};
|