ts-proto 1.114.5 → 1.115.0
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/CHANGELOG.md +21 -0
- package/README.markdown +29 -22
- package/build/enums.js +5 -4
- package/build/options.js +1 -0
- package/build/types.js +7 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [1.115.0](https://github.com/stephenh/ts-proto/compare/v1.114.7...v1.115.0) (2022-06-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* added option 'useJsonWireFormat' ([#576](https://github.com/stephenh/ts-proto/issues/576)) ([a71b145](https://github.com/stephenh/ts-proto/commit/a71b145c81136b8d8e3681b6753146d3ceeff179)), closes [#571](https://github.com/stephenh/ts-proto/issues/571)
|
|
7
|
+
|
|
8
|
+
## [1.114.7](https://github.com/stephenh/ts-proto/compare/v1.114.6...v1.114.7) (2022-05-28)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Fix version number for Buf plugin. ([dc1fb7e](https://github.com/stephenh/ts-proto/commit/dc1fb7e766ed4115d026e7ff0e9a9480c1e42380))
|
|
14
|
+
|
|
15
|
+
## [1.114.6](https://github.com/stephenh/ts-proto/compare/v1.114.5...v1.114.6) (2022-05-28)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* Bump node in ts-proto.Dockerfile. ([42f3cea](https://github.com/stephenh/ts-proto/commit/42f3ceac5323056b1b845b51919ecddaa32bf258))
|
|
21
|
+
|
|
1
22
|
## [1.114.5](https://github.com/stephenh/ts-proto/compare/v1.114.4...v1.114.5) (2022-05-28)
|
|
2
23
|
|
|
3
24
|
|
package/README.markdown
CHANGED
|
@@ -104,7 +104,7 @@ You can also use the official plugin published to the Buf Registry.
|
|
|
104
104
|
```yaml
|
|
105
105
|
version: v1
|
|
106
106
|
plugins:
|
|
107
|
-
- remote: buf.build/
|
|
107
|
+
- remote: buf.build/stephenh/plugins/ts-proto
|
|
108
108
|
out: ../gen/ts
|
|
109
109
|
```
|
|
110
110
|
|
|
@@ -274,34 +274,36 @@ Generated code will be placed in the Gradle build directory.
|
|
|
274
274
|
|
|
275
275
|
Currently `browser` doesn't have any specific behavior other than being "not `node`". It probably will soon/at some point.
|
|
276
276
|
|
|
277
|
-
- With `--ts_proto_opt=useOptionals=
|
|
277
|
+
- With `--ts_proto_opt=useOptionals=messages` (for message fields) or `--ts_proto_opt=useOptionals=all` (for message and scalar fields), fields are declared as optional keys, e.g. `field?: Message` instead of the default `field: Message | undefined`.
|
|
278
278
|
|
|
279
|
-
ts-proto defaults to `useOptionals=
|
|
279
|
+
ts-proto defaults to `useOptionals=none` because it:
|
|
280
|
+
|
|
281
|
+
1. Prevents typos when initializing messages, and
|
|
282
|
+
2. Provides the most consistent API to readers
|
|
283
|
+
3. Ensures production messages are properly initialized with all fields.
|
|
280
284
|
|
|
281
|
-
|
|
282
|
-
interface SomeMessage {
|
|
283
|
-
firstName: string | undefined;
|
|
284
|
-
lastName: string | undefined;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const data = { firstName: 'a', lastTypo: 'b' };
|
|
288
|
-
|
|
289
|
-
// This would compile if `lastName` was `lastName?`, even though the
|
|
290
|
-
// `lastTypo` key above means that `lastName` is not assigned.
|
|
291
|
-
const message: SomeMessage = {
|
|
292
|
-
...data,
|
|
293
|
-
};
|
|
294
|
-
```
|
|
285
|
+
For typo prevention, optional fields make it easy for extra fields to slip into a message (until we get [Exact Types](https://github.com/microsoft/TypeScript/issues/12936)), i.e.:
|
|
295
286
|
|
|
296
|
-
|
|
287
|
+
```typescript
|
|
288
|
+
interface SomeMessage {
|
|
289
|
+
firstName: string | undefined;
|
|
290
|
+
lastName: string | undefined;
|
|
291
|
+
}
|
|
292
|
+
// Declared with a typo
|
|
293
|
+
const data = { firstName: 'a', lastTypo: 'b' };
|
|
294
|
+
// With useOptionals=none, this correctly fails to compile; if `lastName` was optional, it would not
|
|
295
|
+
const message: SomeMessage = { ...data };
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
For a consistent API, if `SomeMessage.lastName` is optional `lastName?`, then readers have to check _two_ empty conditions: a) is `lastName` `undefined` (b/c it was created in-memory and left unset), or b) is `lastName` empty string (b/c we read `SomeMessage` off the wire and correctly set `lastName` to empty string)?
|
|
297
299
|
|
|
298
|
-
|
|
300
|
+
For ensuring proper initialization, if later `SomeMessage.middleInitial` is added, but it's marked as optional `middleInitial?`, you may have many call sites in production code that _should_ now be passing `middleInitial` to create a valid `SomeMessage`, but are not.
|
|
299
301
|
|
|
300
|
-
|
|
302
|
+
So, between typo-prevention, reader inconsistency, and proper initialization, ts-proto recommends using `useOptionals=none` as the "most safe" option.
|
|
301
303
|
|
|
302
|
-
|
|
304
|
+
All that said, this approach does require writers/creators to set every field (although `fromPartial` is meant to address this), so if you still want to have optional fields, you can set `useOptionals=messages` or `useOptionals=all`.
|
|
303
305
|
|
|
304
|
-
|
|
306
|
+
(See [this issue](https://github.com/stephenh/ts-proto/issues/120#issuecomment-678375833) and [this issue](https://github.com/stephenh/ts-proto/issues/397#issuecomment-977259118) for discussions on `useOptional`.)
|
|
305
307
|
|
|
306
308
|
- With `--ts_proto_opt=exportCommonSymbols=false`, utility types like `DeepPartial` won't be `export`d.
|
|
307
309
|
|
|
@@ -404,6 +406,11 @@ Generated code will be placed in the Gradle build directory.
|
|
|
404
406
|
|
|
405
407
|
Note that, as indicated, this means Object.keys will not include set-by-default fields, so if you have code that iterates over messages keys in a generic fashion, it will have to also iterate over keys inherited from the prototype.
|
|
406
408
|
|
|
409
|
+
- With `--ts_proto_opt=useJsonWireFormat=true`, the generated code will reflect the JSON representation of Protobuf messages.
|
|
410
|
+
|
|
411
|
+
Requires `onlyTypes=true`. Implies `useDate=string` and `stringEnums=true`. This option is to generate types that can be directly used with marshalling/unmarshalling Protobuf messages serialized as JSON.
|
|
412
|
+
You may also want to set `useOptionals=all`, as gRPC gateways are not required to send default value for scalar values.
|
|
413
|
+
|
|
407
414
|
### Only Types
|
|
408
415
|
|
|
409
416
|
If you're looking for `ts-proto` to generate only types for your Protobuf types then passing all three of `outputEncodeMethods`, `outputJsonMethods`, and `outputClientImpl` as `false` is probably what you want, i.e.:
|
package/build/enums.js
CHANGED
|
@@ -20,15 +20,16 @@ function generateEnum(ctx, fullName, enumDesc, sourceInfo) {
|
|
|
20
20
|
chunks.push(ts_poet_1.code `export ${options.constEnums ? 'const ' : ''}enum ${ts_poet_1.def(fullName)} {`);
|
|
21
21
|
}
|
|
22
22
|
const delimiter = options.enumsAsLiterals ? ':' : '=';
|
|
23
|
+
const stringEnums = options.stringEnums || (options.onlyTypes && options.useJsonWireFormat);
|
|
23
24
|
enumDesc.value.forEach((valueDesc, index) => {
|
|
24
25
|
var _a;
|
|
25
26
|
const info = sourceInfo.lookup(sourceInfo_1.Fields.enum.value, index);
|
|
26
27
|
utils_1.maybeAddComment(info, chunks, (_a = valueDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated, `${valueDesc.name} - `);
|
|
27
|
-
chunks.push(ts_poet_1.code `${valueDesc.name} ${delimiter} ${
|
|
28
|
+
chunks.push(ts_poet_1.code `${valueDesc.name} ${delimiter} ${stringEnums ? `"${valueDesc.name}"` : valueDesc.number.toString()},`);
|
|
28
29
|
});
|
|
29
30
|
if (options.unrecognizedEnum)
|
|
30
31
|
chunks.push(ts_poet_1.code `
|
|
31
|
-
${UNRECOGNIZED_ENUM_NAME} ${delimiter} ${
|
|
32
|
+
${UNRECOGNIZED_ENUM_NAME} ${delimiter} ${stringEnums ? `"${UNRECOGNIZED_ENUM_NAME}"` : UNRECOGNIZED_ENUM_VALUE.toString()},`);
|
|
32
33
|
if (options.enumsAsLiterals) {
|
|
33
34
|
chunks.push(ts_poet_1.code `} as const`);
|
|
34
35
|
chunks.push(ts_poet_1.code `\n`);
|
|
@@ -37,7 +38,7 @@ function generateEnum(ctx, fullName, enumDesc, sourceInfo) {
|
|
|
37
38
|
else {
|
|
38
39
|
chunks.push(ts_poet_1.code `}`);
|
|
39
40
|
}
|
|
40
|
-
if (options.outputJsonMethods || (
|
|
41
|
+
if (options.outputJsonMethods || (stringEnums && options.outputEncodeMethods)) {
|
|
41
42
|
chunks.push(ts_poet_1.code `\n`);
|
|
42
43
|
chunks.push(generateEnumFromJson(ctx, fullName, enumDesc));
|
|
43
44
|
}
|
|
@@ -45,7 +46,7 @@ function generateEnum(ctx, fullName, enumDesc, sourceInfo) {
|
|
|
45
46
|
chunks.push(ts_poet_1.code `\n`);
|
|
46
47
|
chunks.push(generateEnumToJson(ctx, fullName, enumDesc));
|
|
47
48
|
}
|
|
48
|
-
if (
|
|
49
|
+
if (stringEnums && options.outputEncodeMethods) {
|
|
49
50
|
chunks.push(ts_poet_1.code `\n`);
|
|
50
51
|
chunks.push(generateEnumToNumber(ctx, fullName, enumDesc));
|
|
51
52
|
}
|
package/build/options.js
CHANGED
package/build/types.js
CHANGED
|
@@ -436,6 +436,7 @@ function isEmptyType(typeName) {
|
|
|
436
436
|
}
|
|
437
437
|
exports.isEmptyType = isEmptyType;
|
|
438
438
|
function valueTypeName(ctx, typeName) {
|
|
439
|
+
const useJsonWireFormat = ctx.options.onlyTypes && ctx.options.useJsonWireFormat;
|
|
439
440
|
switch (typeName) {
|
|
440
441
|
case '.google.protobuf.StringValue':
|
|
441
442
|
return ts_poet_1.code `string`;
|
|
@@ -451,7 +452,7 @@ function valueTypeName(ctx, typeName) {
|
|
|
451
452
|
case '.google.protobuf.BoolValue':
|
|
452
453
|
return ts_poet_1.code `boolean`;
|
|
453
454
|
case '.google.protobuf.BytesValue':
|
|
454
|
-
return ctx.options.env === options_1.EnvOption.NODE ? ts_poet_1.code `Buffer` : ts_poet_1.code `Uint8Array`;
|
|
455
|
+
return ctx.options.env === options_1.EnvOption.NODE ? ts_poet_1.code `Buffer` : useJsonWireFormat ? ts_poet_1.code `string` : ts_poet_1.code `Uint8Array`;
|
|
455
456
|
case '.google.protobuf.ListValue':
|
|
456
457
|
return ts_poet_1.code `Array<any>`;
|
|
457
458
|
case '.google.protobuf.Value':
|
|
@@ -459,7 +460,11 @@ function valueTypeName(ctx, typeName) {
|
|
|
459
460
|
case '.google.protobuf.Struct':
|
|
460
461
|
return ts_poet_1.code `{[key: string]: any}`;
|
|
461
462
|
case '.google.protobuf.FieldMask':
|
|
462
|
-
return ts_poet_1.code `string[]`;
|
|
463
|
+
return useJsonWireFormat ? ts_poet_1.code `string` : ts_poet_1.code `string[]`;
|
|
464
|
+
case '.google.protobuf.Duration':
|
|
465
|
+
return useJsonWireFormat ? ts_poet_1.code `string` : undefined;
|
|
466
|
+
case '.google.protobuf.Timestamp':
|
|
467
|
+
return useJsonWireFormat ? ts_poet_1.code `string` : undefined;
|
|
463
468
|
default:
|
|
464
469
|
return undefined;
|
|
465
470
|
}
|