ts-proto 1.135.0 → 1.135.2

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
@@ -115,7 +115,7 @@ plugins:
115
115
  out: ../gen/ts
116
116
  opt:
117
117
  - outputServices=...
118
- - useExactTypes=...
118
+ - useExactTypes=...
119
119
  ```
120
120
 
121
121
  # Goals
@@ -300,33 +300,33 @@ Generated code will be placed in the Gradle build directory.
300
300
  - 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`.
301
301
 
302
302
  ts-proto defaults to `useOptionals=none` because it:
303
-
303
+
304
304
  1. Prevents typos when initializing messages, and
305
305
  2. Provides the most consistent API to readers
306
- 3. Ensures production messages are properly initialized with all fields.
306
+ 3. Ensures production messages are properly initialized with all fields.
307
307
 
308
- 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.:
308
+ 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.:
309
309
 
310
- ```typescript
311
- interface SomeMessage {
312
- firstName: string | undefined;
313
- lastName: string | undefined;
314
- }
315
- // Declared with a typo
316
- const data = { firstName: 'a', lastTypo: 'b' };
317
- // With useOptionals=none, this correctly fails to compile; if `lastName` was optional, it would not
318
- const message: SomeMessage = { ...data };
319
- ```
320
-
321
- 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)?
310
+ ```typescript
311
+ interface SomeMessage {
312
+ firstName: string | undefined;
313
+ lastName: string | undefined;
314
+ }
315
+ // Declared with a typo
316
+ const data = { firstName: "a", lastTypo: "b" };
317
+ // With useOptionals=none, this correctly fails to compile; if `lastName` was optional, it would not
318
+ const message: SomeMessage = { ...data };
319
+ ```
322
320
 
323
- 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.
321
+ 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)?
324
322
 
325
- So, between typo-prevention, reader inconsistency, and proper initialization, ts-proto recommends using `useOptionals=none` as the "most safe" option.
323
+ 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.
326
324
 
327
- 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`.
325
+ So, between typo-prevention, reader inconsistency, and proper initialization, ts-proto recommends using `useOptionals=none` as the "most safe" option.
328
326
 
329
- (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`.)
327
+ 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`.
328
+
329
+ (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`.)
330
330
 
331
331
  - With `--ts_proto_opt=exportCommonSymbols=false`, utility types like `DeepPartial` won't be `export`d.
332
332
 
@@ -346,11 +346,11 @@ Generated code will be placed in the Gradle build directory.
346
346
 
347
347
  `snakeToCamel` can also be set as a `_`-delimited list of strings (comma is reserved as the flag delimited), i.e. `--ts_proto_opt=snakeToCamel=keys_json`, where including `keys` will make message keys be camel case and including `json` will make JSON keys be camel case.
348
348
 
349
- Empty string, i.e. `snakeToCamel=`, will keep both messages keys and `JSON` keys as snake case (it is the same as `snakeToCamel=false`).
349
+ Empty string, i.e. `snakeToCamel=`, will keep both messages keys and `JSON` keys as snake case (it is the same as `snakeToCamel=false`).
350
350
 
351
- Note that to use the `json_name` attribute, you'll have to use the `json`.
351
+ Note that to use the `json_name` attribute, you'll have to use the `json`.
352
352
 
353
- The default behavior is `keys_json`, i.e. both will be camel cased, and `json_name` will be used if set.
353
+ The default behavior is `keys_json`, i.e. both will be camel cased, and `json_name` will be used if set.
354
354
 
355
355
  - With `--ts_proto_opt=outputEncodeMethods=false`, the `Message.encode` and `Message.decode` methods for working with protobuf-encoded/binary data will not be output.
356
356
 
@@ -451,7 +451,7 @@ Generated code will be placed in the Gradle build directory.
451
451
  - With `--ts_proto_opt=initializeFieldsAsUndefined=false`, all optional field initializers will be omited from the generated base instances.
452
452
 
453
453
  - With `--ts_proto_opt=Mgoogle/protobuf/empty.proto=./google3/protobuf/empty`, ('M' means 'importMapping', similar to [protoc-gen-go](https://developers.google.com/protocol-buffers/docs/reference/go-generated#package)), the generated code import path for `./google/protobuf/empty.ts` will reflect the overridden value:
454
-
454
+
455
455
  - `Mfoo/bar.proto=@myorg/some-lib` will map `foo/bar.proto` imports into `import ... from '@myorg/some-lib'`.
456
456
  - `Mfoo/bar.proto=./some/local/lib` will map `foo/bar.proto` imports into `import ... from './some/local/lib'`.
457
457
  - `Mfoo/bar.proto=some-modules/some-lib` will map `foo/bar.proto` imports into `import ... from 'some-module/some-lib'`.
@@ -464,9 +464,10 @@ Generated code will be placed in the Gradle build directory.
464
464
 
465
465
  - With `--ts_proto_opt=useReadonlyTypes=true`, the generated types will be declared as immutable using typescript's `readonly` modifer.
466
466
 
467
- - With `--ts_proto_opt=useSnakeTypeName=false` will remove snake casing from types.
468
-
467
+ - With `--ts_proto_opt=useSnakeTypeName=false` will remove snake casing from types.
468
+
469
469
  Example Protobuf
470
+
470
471
  ```protobuf
471
472
  message Box {
472
473
  message Element {
@@ -480,7 +481,8 @@ Generated code will be placed in the Gradle build directory.
480
481
  }
481
482
  }
482
483
  ```
483
- by default this is enabled which would generate a type of `Box_Element_Image_Alignment`. By disabling this option the type that is generated would be `BoxElementImageAlignment`.
484
+
485
+ by default this is enabled which would generate a type of `Box_Element_Image_Alignment`. By disabling this option the type that is generated would be `BoxElementImageAlignment`.
484
486
 
485
487
  ### NestJS Support
486
488
 
@@ -630,27 +632,41 @@ ts-protoc --ts_proto_out=./output -I=./protos ./protoc/*.proto
630
632
 
631
633
  # OneOf Handling
632
634
 
633
- By default, `oneof` fields are modeled "flatly" in the message, i.e. `oneof either_field { string field_a; string field_b }` means that the message will have `field_a: string | undefined; field_b: string | undefined`.
635
+ By default, ts-proto models `oneof` fields "flatly" in the message, e.g. a message like:
636
+
637
+ ```protobuf
638
+ message Foo {
639
+ oneof either_field { string field_a = 1; string field_b = 2; }
640
+ }
641
+ ```
642
+
643
+ Will generate a `Foo` type with two fields: `field_a: string | undefined;` and `field_b: string | undefined`.
634
644
 
635
645
  With this output, you'll have to check both `if object.field_a` and `if object.field_b`, and if you set one, you'll have to remember to unset the other.
636
646
 
637
- We recommend using the `oneof=unions` option, which will change the output to be an Abstract Data Type/ADT like:
647
+ Instead, we recommend using the `oneof=unions` option, which will change the output to be an Abstract Data Type/ADT like:
638
648
 
639
649
  ```typescript
640
650
  interface YourMessage {
641
- eitherField: { $case: 'field_a'; field_a: string } | { $case: 'field_b'; field_b: string };
651
+ eitherField?: { $case: "field_a"; field_a: string } | { $case: "field_b"; field_b: string };
642
652
  }
643
653
  ```
644
654
 
645
655
  As this will automatically enforce only one of `field_a` or `field_b` "being set" at a time, because the values are stored in the `eitherField` field that can only have a single value at a time.
646
656
 
657
+ (Note that `eitherField` is optional b/c `oneof` in Protobuf means "at most one field" is set, and does not mean one of the fields _must_ be set.)
658
+
647
659
  In ts-proto's currently-unscheduled 2.x release, `oneof=unions` will become the default behavior.
648
660
 
649
661
  # Default values and unset fields
650
662
 
651
- In core Protobuf, values that are _unset_ or equal to the default value are not sent over the wire.
652
- The default value of a message is `undefined`. Primitive types take their natural default value, i.e. `string` is `''`, `number` is `0`, etc.
653
- This behavior enables forward compatibility, as primitive fields will always have a value, even when omitted by outdated agents, but it also means _default_ and _unset_ values cannot be distinguished.
663
+ In core Protobuf (and so also `ts-proto`), values that are _unset_ or equal to the default value are not sent over the wire.
664
+
665
+ For example, the default value of a message is `undefined`. Primitive types take their natural default value, e.g. `string` is `''`, `number` is `0`, etc.
666
+
667
+ Protobuf chose/enforces this behavior because it enables forward compatibility, as primitive fields will always have a value, even when omitted by outdated agents.
668
+
669
+ This is good, but it also means _default_ and _unset_ values cannot be distinguished in `ts-proto` fields; it's just fundamentally how Protobuf works.
654
670
 
655
671
  If you need primitive fields where you can detect set/unset, see [Wrapper Types](#wrapper-types).
656
672
 
@@ -671,7 +687,7 @@ Foo.decode(protobufBytes); // => { bar: '' }
671
687
  ```
672
688
 
673
689
  ```typescript
674
- Foo.encode({ bar: '' }); // => { }, writes an empty Foo object, in protobuf binary format
690
+ Foo.encode({ bar: "" }); // => { }, writes an empty Foo object, in protobuf binary format
675
691
  ```
676
692
 
677
693
  **fromJSON / toJSON**
@@ -680,8 +696,8 @@ Reading JSON will also initialize the default values. Since senders may either o
680
696
 
681
697
  ```typescript
682
698
  Foo.fromJSON({}); // => { bar: '' }
683
- Foo.fromJSON({ bar: '' }); // => { bar: '' }
684
- Foo.fromJSON({ bar: 'baz' }); // => { bar: 'baz' }
699
+ Foo.fromJSON({ bar: "" }); // => { bar: '' }
700
+ Foo.fromJSON({ bar: "baz" }); // => { bar: 'baz' }
685
701
  ```
686
702
 
687
703
  When writing JSON, `ts-proto` currently does **not** normalize message when converting to JSON, other than omitting unset fields, but it may do so in the future.
@@ -690,16 +706,16 @@ When writing JSON, `ts-proto` currently does **not** normalize message when conv
690
706
  // Current ts-proto behavior
691
707
  Foo.toJSON({}); // => { }
692
708
  Foo.toJSON({ bar: undefined }); // => { }
693
- Foo.toJSON({ bar: '' }); // => { bar: '' } - note: this is the default value, but it's not omitted
694
- Foo.toJSON({ bar: 'baz' }); // => { bar: 'baz' }
709
+ Foo.toJSON({ bar: "" }); // => { bar: '' } - note: this is the default value, but it's not omitted
710
+ Foo.toJSON({ bar: "baz" }); // => { bar: 'baz' }
695
711
  ```
696
712
 
697
713
  ```typescript
698
714
  // Possible future behavior, where ts-proto would normalize message
699
715
  Foo.toJSON({}); // => { }
700
716
  Foo.toJSON({ bar: undefined }); // => { }
701
- Foo.toJSON({ bar: '' }); // => { } - note: omitting the default value, as expected
702
- Foo.toJSON({ bar: 'baz' }); // => { bar: 'baz' }
717
+ Foo.toJSON({ bar: "" }); // => { } - note: omitting the default value, as expected
718
+ Foo.toJSON({ bar: "baz" }); // => { bar: 'baz' }
703
719
  ```
704
720
 
705
721
  - Please open an issue if you need this behavior.
@@ -755,13 +771,13 @@ interface ExampleMessage {
755
771
  When encoding a message the primitive value is converted back to its corresponding wrapper type:
756
772
 
757
773
  ```typescript
758
- ExampleMessage.encode({ name: 'foo' }); // => { name: { value: 'foo' } }, in binary
774
+ ExampleMessage.encode({ name: "foo" }); // => { name: { value: 'foo' } }, in binary
759
775
  ```
760
776
 
761
777
  When calling toJSON, the value is not converted, because wrapper types are idiomatic in JSON.
762
778
 
763
779
  ```typescript
764
- ExampleMessage.toJSON({ name: 'foo' }); // => { name: 'foo' }
780
+ ExampleMessage.toJSON({ name: "foo" }); // => { name: 'foo' }
765
781
  ```
766
782
 
767
783
  ## JSON Types (Struct Types)
@@ -803,7 +819,7 @@ interface ExampleMessage {
803
819
  Encoding a JSON value embedded in a message, converts it to a Struct Type:
804
820
 
805
821
  ```typescript
806
- ExampleMessage.encode({ anything: { name: 'hello' } });
822
+ ExampleMessage.encode({ anything: { name: "hello" } });
807
823
  /* Outputs the following structure, encoded in protobuf binary format:
808
824
  {
809
825
  anything: Value {
package/build/case.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.camelCase = exports.capitalize = exports.camelToSnake = exports.snakeToCamel = exports.maybeSnakeToCamel = void 0;
3
+ exports.camelCaseGrpc = exports.camelCase = exports.capitalize = exports.camelToSnake = exports.snakeToCamel = exports.maybeSnakeToCamel = void 0;
4
+ const case_anything_1 = require("case-anything");
4
5
  /** Converts `key` to TS/JS camel-case idiom, unless overridden not to. */
5
6
  function maybeSnakeToCamel(key, options) {
6
7
  if (options.snakeToCamel.includes("keys") && key.includes("_")) {
@@ -35,3 +36,12 @@ function camelCase(s) {
35
36
  return s.substring(0, 1).toLowerCase() + s.substring(1);
36
37
  }
37
38
  exports.camelCase = camelCase;
39
+ function camelCaseGrpc(s) {
40
+ /* This function uses the exact same semantics found inside the grpc
41
+ * nodejs library. Camel case splitting must be done by word i.e
42
+ * GetAPIValue must become getApiValue (notice the API becomes Api).
43
+ * This needs to be followed otherwise it will not succeed in the grpc nodejs module.
44
+ */
45
+ return (0, case_anything_1.camelCase)(s);
46
+ }
47
+ exports.camelCaseGrpc = camelCaseGrpc;
package/build/main.js CHANGED
@@ -538,13 +538,14 @@ function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fu
538
538
  function generateOneofProperty(ctx, messageDesc, oneofIndex, sourceInfo) {
539
539
  const { options } = ctx;
540
540
  const fields = messageDesc.field.filter((field) => (0, types_1.isWithinOneOf)(field) && field.oneofIndex === oneofIndex);
541
+ const mbReadonly = maybeReadonly(options);
541
542
  const unionType = (0, ts_poet_1.joinCode)(fields.map((f) => {
542
543
  let fieldName = (0, case_1.maybeSnakeToCamel)(f.name, options);
543
544
  let typeName = (0, types_1.toTypeName)(ctx, messageDesc, f);
544
- return (0, ts_poet_1.code) `{ ${maybeReadonly(options)}$case: '${fieldName}', ${maybeReadonly(options)}${fieldName}: ${typeName} }`;
545
+ return (0, ts_poet_1.code) `{ ${mbReadonly}$case: '${fieldName}', ${mbReadonly}${fieldName}: ${typeName} }`;
545
546
  }), { on: " | " });
546
547
  const name = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[oneofIndex].name, options);
547
- return (0, ts_poet_1.code) `${maybeReadonly(options)}${name}?: ${unionType},`;
548
+ return (0, ts_poet_1.code) `${mbReadonly}${name}?: ${unionType},`;
548
549
  /*
549
550
  // Ideally we'd put the comments for each oneof field next to the anonymous
550
551
  // type we've created in the type union above, but ts-poet currently lacks
package/build/utils.js CHANGED
@@ -138,7 +138,7 @@ class FormattedMethodDescriptor {
138
138
  static formatName(methodName, options) {
139
139
  let result = methodName;
140
140
  if (options.lowerCaseServiceMethods || options.outputServices.includes(options_1.ServiceOption.GRPC)) {
141
- result = (0, case_1.camelCase)(result);
141
+ result = (0, case_1.camelCaseGrpc)(result);
142
142
  }
143
143
  return result;
144
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.135.0",
3
+ "version": "1.135.2",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",
@@ -60,10 +60,12 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "@types/object-hash": "^1.3.0",
63
+ "case-anything": "^2.1.10",
63
64
  "dataloader": "^1.4.0",
64
65
  "object-hash": "^1.3.1",
65
66
  "protobufjs": "^6.11.3",
66
67
  "ts-poet": "^6.2.0",
67
68
  "ts-proto-descriptors": "1.7.1"
68
- }
69
+ },
70
+ "packageManager": "yarn@3.3.0"
69
71
  }