ts-proto 2.1.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.d.ts +10 -1
- package/build/src/main.js +172 -12
- 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.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { FileDescriptorProto } from "ts-proto-descriptors";
|
|
|
4
4
|
import { Context } from "./context";
|
|
5
5
|
import { Options } from "./options";
|
|
6
6
|
export declare function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [string, Code];
|
|
7
|
-
export type Utils = ReturnType<typeof makeDeepPartial> & ReturnType<typeof makeObjectIdMethods> & ReturnType<typeof makeTimestampMethods> & ReturnType<typeof makeByteUtils> & ReturnType<typeof makeLongUtils> & ReturnType<typeof makeComparisonUtils> & ReturnType<typeof makeNiceGrpcServerStreamingMethodResult> & ReturnType<typeof makeGrpcWebErrorClass> & ReturnType<typeof makeExtensionClass> & ReturnType<typeof makeAssertionUtils>;
|
|
7
|
+
export type Utils = ReturnType<typeof makeDeepPartial> & ReturnType<typeof makeObjectIdMethods> & ReturnType<typeof makeTimestampMethods> & ReturnType<typeof makeByteUtils> & ReturnType<typeof makeLongUtils> & ReturnType<typeof makeComparisonUtils> & ReturnType<typeof makeNiceGrpcServerStreamingMethodResult> & ReturnType<typeof makeGrpcWebErrorClass> & ReturnType<typeof makeExtensionClass> & ReturnType<typeof makeAssertionUtils> & ReturnType<typeof makeMessageFns>;
|
|
8
8
|
/** These are runtime utility methods used by the generated code. */
|
|
9
9
|
export declare function makeUtils(options: Options): Utils;
|
|
10
10
|
declare function makeLongUtils(options: Options, bytes: ReturnType<typeof makeByteUtils>): {
|
|
@@ -22,6 +22,15 @@ declare function makeDeepPartial(options: Options, longs: ReturnType<typeof make
|
|
|
22
22
|
DeepPartial: ConditionalOutput;
|
|
23
23
|
Exact: ConditionalOutput;
|
|
24
24
|
};
|
|
25
|
+
declare function makeMessageFns(options: Options, deepPartial: ReturnType<typeof makeDeepPartial>, extension: ReturnType<typeof makeExtensionClass>): {
|
|
26
|
+
MessageFns: ConditionalOutput;
|
|
27
|
+
ExtensionFns: ConditionalOutput;
|
|
28
|
+
ExtensionHolder: ConditionalOutput;
|
|
29
|
+
StructWrapperFns: ConditionalOutput;
|
|
30
|
+
AnyValueWrapperFns: ConditionalOutput;
|
|
31
|
+
ListValueWrapperFns: ConditionalOutput;
|
|
32
|
+
FieldMaskWrapperFns: ConditionalOutput;
|
|
33
|
+
};
|
|
25
34
|
declare function makeObjectIdMethods(): {
|
|
26
35
|
fromJsonObjectId: ConditionalOutput;
|
|
27
36
|
fromProtoObjectId: ConditionalOutput;
|
package/build/src/main.js
CHANGED
|
@@ -96,7 +96,8 @@ function generateFile(ctx, fileDesc) {
|
|
|
96
96
|
chunks.push(generateBaseInstanceFactory(ctx, fullName, message, fullTypeName));
|
|
97
97
|
}
|
|
98
98
|
const staticMembers = [];
|
|
99
|
-
|
|
99
|
+
const hasTypeMember = options.outputTypeAnnotations || options.outputTypeRegistry;
|
|
100
|
+
if (hasTypeMember) {
|
|
100
101
|
staticMembers.push((0, ts_poet_1.code) `$type: '${fullTypeName}' as const`);
|
|
101
102
|
}
|
|
102
103
|
if (options.outputExtensions) {
|
|
@@ -153,8 +154,37 @@ function generateFile(ctx, fileDesc) {
|
|
|
153
154
|
staticMembers.push(...(0, generate_struct_wrappers_1.generateUnwrapShallow)(ctx, fullTypeName, structFieldNames));
|
|
154
155
|
}
|
|
155
156
|
if (staticMembers.length > 0) {
|
|
157
|
+
const messageFnsTypeParameters = [fullName, hasTypeMember && `'${fullTypeName}'`]
|
|
158
|
+
.filter((p) => !!p)
|
|
159
|
+
.join(", ");
|
|
160
|
+
const interfaces = [(0, ts_poet_1.code) `${utils.MessageFns}<${messageFnsTypeParameters}>`];
|
|
161
|
+
if (options.outputEncodeMethods &&
|
|
162
|
+
options.outputExtensions &&
|
|
163
|
+
options.unknownFields &&
|
|
164
|
+
message.extensionRange.length) {
|
|
165
|
+
interfaces.push((0, ts_poet_1.code) `${utils.ExtensionFns}<${fullName}>`);
|
|
166
|
+
}
|
|
167
|
+
if ((0, types_1.isStructTypeName)(fullTypeName)) {
|
|
168
|
+
interfaces.push((0, ts_poet_1.code) `${utils.StructWrapperFns}`);
|
|
169
|
+
}
|
|
170
|
+
else if ((0, types_1.isAnyValueTypeName)(fullTypeName)) {
|
|
171
|
+
interfaces.push((0, ts_poet_1.code) `${utils.AnyValueWrapperFns}`);
|
|
172
|
+
}
|
|
173
|
+
else if ((0, types_1.isListValueTypeName)(fullTypeName)) {
|
|
174
|
+
interfaces.push((0, ts_poet_1.code) `${utils.ListValueWrapperFns}`);
|
|
175
|
+
}
|
|
176
|
+
else if ((0, types_1.isFieldMaskTypeName)(fullTypeName)) {
|
|
177
|
+
interfaces.push((0, ts_poet_1.code) `${utils.FieldMaskWrapperFns}`);
|
|
178
|
+
}
|
|
179
|
+
if (options.outputExtensions) {
|
|
180
|
+
for (const extension of message.extension) {
|
|
181
|
+
const name = (0, case_1.maybeSnakeToCamel)(extension.name, ctx.options);
|
|
182
|
+
const type = (0, types_1.toTypeName)(ctx, message, extension);
|
|
183
|
+
interfaces.push((0, ts_poet_1.code) `${utils.ExtensionHolder}<"${name}", ${type}>`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
156
186
|
chunks.push((0, ts_poet_1.code) `
|
|
157
|
-
export const ${(0, ts_poet_1.def)(fullName)} = {
|
|
187
|
+
export const ${(0, ts_poet_1.def)(fullName)}: ${(0, ts_poet_1.joinCode)(interfaces, { on: " & " })} = {
|
|
158
188
|
${(0, ts_poet_1.joinCode)(staticMembers, { on: ",\n\n" })}
|
|
159
189
|
};
|
|
160
190
|
`);
|
|
@@ -281,17 +311,20 @@ function generateFile(ctx, fileDesc) {
|
|
|
281
311
|
function makeUtils(options) {
|
|
282
312
|
const bytes = makeByteUtils(options);
|
|
283
313
|
const longs = makeLongUtils(options, bytes);
|
|
314
|
+
const deepPartial = makeDeepPartial(options, longs);
|
|
315
|
+
const extension = makeExtensionClass(options);
|
|
284
316
|
return {
|
|
285
317
|
...bytes,
|
|
286
|
-
...
|
|
318
|
+
...deepPartial,
|
|
287
319
|
...makeObjectIdMethods(),
|
|
288
320
|
...makeTimestampMethods(options, longs, bytes),
|
|
289
321
|
...longs,
|
|
290
322
|
...makeComparisonUtils(),
|
|
291
323
|
...makeNiceGrpcServerStreamingMethodResult(options),
|
|
292
324
|
...makeGrpcWebErrorClass(bytes),
|
|
293
|
-
...
|
|
325
|
+
...extension,
|
|
294
326
|
...makeAssertionUtils(bytes),
|
|
327
|
+
...makeMessageFns(options, deepPartial, extension),
|
|
295
328
|
};
|
|
296
329
|
}
|
|
297
330
|
function makeProtobufTimestampWrapper() {
|
|
@@ -461,6 +494,121 @@ function makeDeepPartial(options, longs) {
|
|
|
461
494
|
`);
|
|
462
495
|
return { Builtin, DeepPartial, Exact };
|
|
463
496
|
}
|
|
497
|
+
function makeMessageFns(options, deepPartial, extension) {
|
|
498
|
+
const BinaryWriter = (0, ts_poet_1.imp)("BinaryWriter@@bufbuild/protobuf/wire");
|
|
499
|
+
const BinaryReader = (0, ts_poet_1.imp)("BinaryReader@@bufbuild/protobuf/wire");
|
|
500
|
+
const { Exact, DeepPartial } = deepPartial;
|
|
501
|
+
const { Extension } = extension;
|
|
502
|
+
const commonStaticMembers = [];
|
|
503
|
+
const extensionStaticMembers = [];
|
|
504
|
+
const hasTypeMember = options.outputTypeAnnotations || options.outputTypeRegistry;
|
|
505
|
+
if (hasTypeMember) {
|
|
506
|
+
commonStaticMembers.push((0, ts_poet_1.code) `readonly $type: V;`);
|
|
507
|
+
}
|
|
508
|
+
if (options.outputEncodeMethods) {
|
|
509
|
+
if (options.outputEncodeMethods === true ||
|
|
510
|
+
options.outputEncodeMethods === "encode-only" ||
|
|
511
|
+
options.outputEncodeMethods === "encode-no-creation") {
|
|
512
|
+
commonStaticMembers.push((0, ts_poet_1.code) `
|
|
513
|
+
encode(message: T, writer?: ${BinaryWriter}): ${BinaryWriter};
|
|
514
|
+
`);
|
|
515
|
+
if (options.outputExtensions && options.unknownFields) {
|
|
516
|
+
extensionStaticMembers.push((0, ts_poet_1.code) `
|
|
517
|
+
setExtension<E>(message: T, extension: ${Extension}<E>, value: E): void;
|
|
518
|
+
`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (options.outputEncodeMethods === true || options.outputEncodeMethods === "decode-only") {
|
|
522
|
+
commonStaticMembers.push((0, ts_poet_1.code) `
|
|
523
|
+
decode(input: ${BinaryReader} | Uint8Array, length?: number): T;
|
|
524
|
+
`);
|
|
525
|
+
if (options.outputExtensions && options.unknownFields) {
|
|
526
|
+
extensionStaticMembers.push((0, ts_poet_1.code) `
|
|
527
|
+
getExtension<E>(message: T, extension: ${Extension}<E>): E | undefined;
|
|
528
|
+
`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (options.useAsyncIterable) {
|
|
533
|
+
commonStaticMembers.push((0, ts_poet_1.code) `
|
|
534
|
+
encodeTransform(
|
|
535
|
+
source: AsyncIterable<T | T[]> | Iterable<T | T[]>
|
|
536
|
+
): AsyncIterable<Uint8Array>;
|
|
537
|
+
`);
|
|
538
|
+
commonStaticMembers.push((0, ts_poet_1.code) `
|
|
539
|
+
decodeTransform(
|
|
540
|
+
source: AsyncIterable<Uint8Array | Uint8Array[]> | Iterable<Uint8Array | Uint8Array[]>
|
|
541
|
+
): AsyncIterable<T>;
|
|
542
|
+
`);
|
|
543
|
+
}
|
|
544
|
+
if (options.outputJsonMethods) {
|
|
545
|
+
if (options.outputJsonMethods === true || options.outputJsonMethods === "from-only") {
|
|
546
|
+
commonStaticMembers.push((0, ts_poet_1.code) `fromJSON(object: any): T;`);
|
|
547
|
+
}
|
|
548
|
+
if (options.outputJsonMethods === true || options.outputJsonMethods === "to-only") {
|
|
549
|
+
commonStaticMembers.push((0, ts_poet_1.code) `toJSON(message: T): unknown;`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (options.outputPartialMethods) {
|
|
553
|
+
if (options.useExactTypes) {
|
|
554
|
+
commonStaticMembers.push((0, ts_poet_1.code) `create<I extends ${Exact}<${DeepPartial}<T>, I>>(base?: I): T;`);
|
|
555
|
+
commonStaticMembers.push((0, ts_poet_1.code) `fromPartial<I extends ${Exact}<${DeepPartial}<T>, I>>(object: I): T;`);
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
commonStaticMembers.push((0, ts_poet_1.code) `create(base?: DeepPartial<T>): T;`);
|
|
559
|
+
commonStaticMembers.push((0, ts_poet_1.code) `fromPartial(object: DeepPartial<T>): T;`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const maybeExport = options.exportCommonSymbols ? "export" : "";
|
|
563
|
+
const MessageFns = (0, ts_poet_1.conditionalOutput)("MessageFns", (0, ts_poet_1.code) `
|
|
564
|
+
${maybeExport} interface MessageFns<T${hasTypeMember ? ", V extends string" : ""}> {
|
|
565
|
+
${(0, ts_poet_1.joinCode)(commonStaticMembers, { on: "\n" })}
|
|
566
|
+
}
|
|
567
|
+
`);
|
|
568
|
+
const ExtensionFns = (0, ts_poet_1.conditionalOutput)("ExtensionFns", (0, ts_poet_1.code) `
|
|
569
|
+
${maybeExport} interface ExtensionFns<T> {
|
|
570
|
+
${(0, ts_poet_1.joinCode)(extensionStaticMembers, { on: "\n" })}
|
|
571
|
+
}
|
|
572
|
+
`);
|
|
573
|
+
const ExtensionHolder = (0, ts_poet_1.conditionalOutput)("ExtensionHolder", (0, ts_poet_1.code) `
|
|
574
|
+
${maybeExport} type ExtensionHolder<T extends string, V> = {
|
|
575
|
+
[key in T]: Extension<V>;
|
|
576
|
+
}
|
|
577
|
+
`);
|
|
578
|
+
const StructWrapperFns = (0, ts_poet_1.conditionalOutput)("StructWrapperFns", (0, ts_poet_1.code) `
|
|
579
|
+
${maybeExport} interface StructWrapperFns {
|
|
580
|
+
wrap(object: {[key: string]: any} | undefined): Struct;
|
|
581
|
+
unwrap(message: Struct): {[key: string]: any};
|
|
582
|
+
}
|
|
583
|
+
`);
|
|
584
|
+
const AnyValueWrapperFns = (0, ts_poet_1.conditionalOutput)("AnyValueWrapperFns", (0, ts_poet_1.code) `
|
|
585
|
+
${maybeExport} interface AnyValueWrapperFns {
|
|
586
|
+
wrap(value: any): Value;
|
|
587
|
+
unwrap(message: any): string | number | boolean | Object | null | Array<any> | undefined;
|
|
588
|
+
}
|
|
589
|
+
`);
|
|
590
|
+
const ListValueWrapperFns = (0, ts_poet_1.conditionalOutput)("ListValueWrapperFns", (0, ts_poet_1.code) `
|
|
591
|
+
${maybeExport} interface ListValueWrapperFns {
|
|
592
|
+
wrap(array: ${options.useReadonlyTypes ? "Readonly" : ""}Array<any> | undefined): ListValue;
|
|
593
|
+
unwrap(message: ${options.useReadonlyTypes ? "any" : "ListValue"}): Array<any>;
|
|
594
|
+
}
|
|
595
|
+
`);
|
|
596
|
+
const FieldMaskWrapperFns = (0, ts_poet_1.conditionalOutput)("FieldMaskWrapperFns", (0, ts_poet_1.code) `
|
|
597
|
+
${maybeExport} interface FieldMaskWrapperFns {
|
|
598
|
+
wrap(paths: ${options.useReadonlyTypes ? "readonly" : ""} string[]): FieldMask;
|
|
599
|
+
unwrap(message: ${options.useReadonlyTypes ? "any" : "FieldMask"}): string[] ${options.useOptionals === "all" ? "| undefined" : ""};
|
|
600
|
+
}
|
|
601
|
+
`);
|
|
602
|
+
return {
|
|
603
|
+
MessageFns,
|
|
604
|
+
ExtensionFns,
|
|
605
|
+
ExtensionHolder,
|
|
606
|
+
StructWrapperFns,
|
|
607
|
+
AnyValueWrapperFns,
|
|
608
|
+
ListValueWrapperFns,
|
|
609
|
+
FieldMaskWrapperFns,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
464
612
|
function makeObjectIdMethods() {
|
|
465
613
|
const mongodb = (0, ts_poet_1.imp)("mongodb*mongodb");
|
|
466
614
|
const fromProtoObjectId = (0, ts_poet_1.conditionalOutput)("fromProtoObjectId", (0, ts_poet_1.code) `
|
|
@@ -882,7 +1030,7 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
882
1030
|
messageDesc.field.forEach((field) => {
|
|
883
1031
|
const fieldName = (0, utils_1.getFieldName)(field, options);
|
|
884
1032
|
const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
|
|
885
|
-
chunks.push((0, ts_poet_1.code) `case ${field.number}
|
|
1033
|
+
chunks.push((0, ts_poet_1.code) `case ${field.number}: {`);
|
|
886
1034
|
const tag = ((field.number << 3) | (0, types_1.basicWireType)(field.type)) >>> 0;
|
|
887
1035
|
const tagCheck = (0, ts_poet_1.code) `
|
|
888
1036
|
if (tag !== ${tag}) {
|
|
@@ -935,11 +1083,23 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
935
1083
|
}`
|
|
936
1084
|
: "";
|
|
937
1085
|
if ((0, types_1.packedType)(field.type) === undefined) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
+
}
|
|
943
1103
|
}
|
|
944
1104
|
else {
|
|
945
1105
|
const packedTag = ((field.number << 3) | 2) >>> 0;
|
|
@@ -962,7 +1122,7 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
962
1122
|
}
|
|
963
1123
|
|
|
964
1124
|
break;
|
|
965
|
-
`);
|
|
1125
|
+
}`);
|
|
966
1126
|
}
|
|
967
1127
|
}
|
|
968
1128
|
}
|
|
@@ -983,7 +1143,7 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
983
1143
|
`);
|
|
984
1144
|
}
|
|
985
1145
|
if (!(0, types_1.isRepeated)(field) || (0, types_1.packedType)(field.type) === undefined) {
|
|
986
|
-
chunks.push((0, ts_poet_1.code) `continue
|
|
1146
|
+
chunks.push((0, ts_poet_1.code) `continue; }`);
|
|
987
1147
|
}
|
|
988
1148
|
});
|
|
989
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 = {};
|