ts-proto 1.90.1 → 1.92.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/CHANGELOG.md CHANGED
@@ -1,3 +1,36 @@
1
+ ## [1.92.2](https://github.com/stephenh/ts-proto/compare/v1.92.1...v1.92.2) (2021-12-08)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * noImplicitReturns error in Value.unwrap ([#436](https://github.com/stephenh/ts-proto/issues/436)) ([2d7a5d0](https://github.com/stephenh/ts-proto/commit/2d7a5d04c72ace58fa3a6745c3857f6cc0468543)), closes [#432](https://github.com/stephenh/ts-proto/issues/432)
7
+
8
+ ## [1.92.1](https://github.com/stephenh/ts-proto/compare/v1.92.0...v1.92.1) (2021-12-02)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Respect stringEnums option in wrap function ([#420](https://github.com/stephenh/ts-proto/issues/420)) ([7adf90c](https://github.com/stephenh/ts-proto/commit/7adf90c23c46950bcf457b317764393ff4af2bf2))
14
+
15
+ # [1.92.0](https://github.com/stephenh/ts-proto/compare/v1.91.0...v1.92.0) (2021-11-28)
16
+
17
+
18
+ ### Features
19
+
20
+ * Use exact types for fromPartial ([#412](https://github.com/stephenh/ts-proto/issues/412)) ([808f8a7](https://github.com/stephenh/ts-proto/commit/808f8a7a77d56f65dd4a4643dd66158f106ab755)), closes [#156](https://github.com/stephenh/ts-proto/issues/156)
21
+
22
+ # [1.91.0](https://github.com/stephenh/ts-proto/compare/v1.90.1...v1.91.0) (2021-11-27)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * use Long.fromValue instead of Long.fromString for improved robustness regarding already parsed objects ([#405](https://github.com/stephenh/ts-proto/issues/405)) ([7bdc3ee](https://github.com/stephenh/ts-proto/commit/7bdc3eee05ed1318e18e27aa7d5bb2680060f8b6))
28
+
29
+
30
+ ### Features
31
+
32
+ * Include dockerized protoc ([#404](https://github.com/stephenh/ts-proto/issues/404)) ([7564a78](https://github.com/stephenh/ts-proto/commit/7564a7887ccd0bb80cac19d313ee9bd8daae778d))
33
+
1
34
  ## [1.90.1](https://github.com/stephenh/ts-proto/compare/v1.90.0...v1.90.1) (2021-11-27)
2
35
 
3
36
 
package/README.markdown CHANGED
@@ -9,25 +9,29 @@
9
9
 
10
10
  ## Table of contents
11
11
 
12
+ - [ts-proto](#ts-proto)
13
+ - [Table of contents](#table-of-contents)
14
+ - [Overview](#overview)
12
15
  - [QuickStart](#quickstart)
13
16
  - [Goals](#goals)
14
17
  - [Example Types](#example-types)
15
18
  - [Highlights](#highlights)
16
19
  - [Auto-Batching / N+1 Prevention](#auto-batching--n1-prevention)
17
20
  - [Usage](#usage)
18
- - [Supported options](#supported-options)
19
- - [Only Types](#only-types)
20
- - [NestJS Support](NESTJS.markdown)
21
- - [Building](#building)
21
+ - [Supported options](#supported-options)
22
+ - [Only Types](#only-types)
23
+ - [NestJS Support](#nestjs-support)
24
+ - [Watch Mode](#watch-mode)
25
+ - [Sponsors](#sponsors)
26
+ - [Development](#development)
22
27
  - [Assumptions](#assumptions)
23
28
  - [Todo](#todo)
24
29
  - [OneOf Handling](#oneof-handling)
25
- - [Default Values and Unset Fields](#default-values-and-unset-fields)
30
+ - [Default values and unset fields](#default-values-and-unset-fields)
26
31
  - [Well-Known Types](#well-known-types)
27
32
  - [Wrapper Types](#wrapper-types)
28
33
  - [JSON Types (Struct Types)](#json-types-struct-types)
29
- - [Timestamps](#timestamp)
30
- - [Wrapper Types](#wrapper-types)
34
+ - [Timestamp](#timestamp)
31
35
  - [Number Types](#number-types)
32
36
  - [Current Status of Optional Values](#current-status-of-optional-values)
33
37
 
@@ -329,7 +333,7 @@ Generated code will be placed in the Gradle build directory.
329
333
 
330
334
  Note that `addGrpcMetadata`, `addNestjsRestParameter` and `returnObservable` will still be false.
331
335
 
332
- - With `--ts_proto_opt=useDate=false`, fields of type `google.protobuf.Timestamp` will not be mapped to type `Date` in the generated types. See [Timestamps](#timestamps) for more details.
336
+ - With `--ts_proto_opt=useDate=false`, fields of type `google.protobuf.Timestamp` will not be mapped to type `Date` in the generated types. See [Timestamp](#timestamp) for more details.
333
337
 
334
338
  - With `--ts_proto_opt=outputSchema=true`, meta typings will be generated that can later be used in other code generators.
335
339
 
@@ -337,7 +341,7 @@ Generated code will be placed in the Gradle build directory.
337
341
 
338
342
  - With `--ts_proto_opt=outputServices=grpc-js`, ts-proto will output service definitions and server / client stubs in [grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) format.
339
343
 
340
- - With `--ts_proto_opt=outputServices=generic-definitions`, ts-proto will output generic (framework-agnostic) service definitions.
344
+ - With `--ts_proto_opt=outputServices=generic-definitions`, ts-proto will output generic (framework-agnostic) service definitions. These definitions contain descriptors for each method with links to request and response types, which allows to generate server and client stubs at runtime, and also generate strong types for them at compile time. An example of a library that uses this approach is [nice-grpc](https://github.com/deeplay-io/nice-grpc).
341
345
 
342
346
  - With `--ts_proto_opt=outputServices=false`, or `=none`, ts-proto will output NO service definitions.
343
347
 
@@ -354,6 +358,15 @@ If you're looking for `ts-proto` to generate only types for your Protobuf types
354
358
 
355
359
  We have a great way of working together with [nestjs](https://docs.nestjs.com/microservices/grpc). `ts-proto` generates `interfaces` and `decorators` for you controller, client. For more information see the [nestjs readme](NESTJS.markdown).
356
360
 
361
+ ### Watch Mode
362
+
363
+ If you want to run `ts-proto` on every change of a proto file, you'll need to use a tool like [chokidar-cli](https://www.npmjs.com/package/chokidar-cli) and use it as a script in `package.json`:
364
+
365
+ ```json
366
+ "proto:generate": "protoc --ts_proto_out=. ./<proto_path>/<proto_name>.proto --ts_proto_opt=esModuleInterop=true",
367
+ "proto:watch": "chokidar \"**/*.proto\" -c \"npm run proto:generate\""
368
+ ```
369
+
357
370
  # Sponsors
358
371
 
359
372
  Kudos to our sponsors:
@@ -362,15 +375,69 @@ Kudos to our sponsors:
362
375
 
363
376
  If you need ts-proto customizations or priority support for your company, you can ping me at [via email](mailto:stephen.haberman@gmail.com).
364
377
 
365
- # Building
378
+ # Development
379
+
380
+ **Requirements**
381
+
382
+ - [Docker](https://www.docker.com) or [protoc](https://github.com/protocolbuffers/protobuf/releases) v3.19.1
383
+ - `yarn` — `npm install -g yarn`
384
+
385
+ **Setup**
386
+
387
+ The commands below assume you have **Docker** installed. To use a **local** copy of `protoc` without docker, use commands suffixed with `:local`
388
+
389
+ - Check out the [repository]() for the latest code.
390
+ - Run `yarn install` to install the dependencies.
391
+ - Run `yarn build:test` or `yarn build:test:local` to generate the test files.
392
+ > _This runs the following commands:_
393
+ > - `proto2bin` — Converts integration test `.proto` files to `.bin`.
394
+ > - `bin2ts` — Runs `ts-proto` on the `.bin` files to generate `.ts` files.
395
+ > - `proto2pbjs` — Generates a reference implementation using `pbjs` for testing compatibility.
396
+ - Run `yarn test`
397
+
398
+ **Workflow**
366
399
 
367
- After running `yarn install`, run `./integration/pbjs.sh` to create the integration test types. These pbjs-generated files are not currently checked in.
400
+ - Modifying the plugin implementation:
401
+ - Run `yarn bin2ts` or `yarn bin2ts:local`.
402
+ _Since the proto files were not changed, you only need to regenerate the typescript files._
403
+ - Run `yarn test` to verify the typescript files are compatible with the reference implementation, and pass other tests.
404
+ - Updating or adding `.proto` files in the integration directory:
405
+ - Run `yarn build:test` to regenerate the integration test files.
406
+ - Run `yarn test` to retest.
368
407
 
369
- After this, the tests should pass.
408
+ **Contributing**
370
409
 
371
- After making changes to `ts-proto`, you can run `cd integration` and `./codegen.sh` to re-generate the test case `*.ts` output files that are in each `integration/<test-case>/` directory.
410
+ - Run `yarn build:test` and `yarn test` to make sure everything works.
411
+ - Run `yarn prettier` to format the typescript files.
412
+ - Commit the changes:
413
+ - Also include the generated `.bin` files for the tests where you added or modified `.proto` files.
414
+ > These are checked into git so that the test suite can run without having to invoke the `protoc` build chain.
415
+ - Also include the generated `.ts` files.
416
+ - Create a pull request
417
+
418
+ **Dockerized Protoc**
419
+
420
+ The repository includes a dockerized version of `protoc`, which is configured in [docker-compose.yml](docker-compose.yml).
421
+
422
+ It can be useful in case you want to manually invoke the plugin with a known version of `protoc`.
423
+
424
+ Usage:
425
+
426
+ ```bash
427
+ # Include the protoc alias in your shell.
428
+ . aliases.sh
429
+
430
+ # Run protoc as usual. The ts-proto directory is available in /ts-proto.
431
+ protoc --plugin=/ts-proto/protoc-gen-ts_proto --ts_proto_out=./output -I=./protos ./protoc/*.proto
432
+
433
+ # Or use the ts-protoc alias which specifies the plugin path for you.
434
+ ts-protoc --ts_proto_out=./output -I=./protos ./protoc/*.proto
435
+ ```
372
436
 
373
- The test suite's proto files (i.e. `simple.proto`, `batching.proto`, etc.) currently have serialized/`.bin` copies checked into git (i.e. `simple.bin`, `batching.bin`, etc.), so that the test suite can run without having to invoke the `protoc` build chain. I.e. if you change the `simple.proto`/etc. files, you'll need to run `./integration/update-bins.sh`, which does require having the `protoc` executable available.
437
+ - All paths must be relative paths _within_ the current working directory of the host. `../` is not allowed
438
+ - Within the docker container, the absolute path to the project root is `/ts-proto`
439
+ - The container mounts the current working directory in `/host`, and sets it as its working directory.
440
+ - Once `aliases.sh` is sourced, you can use the `protoc` command in any folder.
374
441
 
375
442
  # Assumptions
376
443
 
@@ -13,7 +13,7 @@ function generateTypeRegistry(ctx) {
13
13
  chunks.push(ts_poet_1.code `
14
14
  export const messageTypeRegistry = new Map<string, MessageType>();
15
15
  `);
16
- chunks.push(ts_poet_1.code `${ctx.utils.DeepPartial.ifUsed}`);
16
+ chunks.push(ts_poet_1.code ` ${ctx.utils.Builtin.ifUsed} ${ctx.utils.DeepPartial.ifUsed}`);
17
17
  return ts_poet_1.joinCode(chunks, { on: '\n\n' });
18
18
  }
19
19
  exports.generateTypeRegistry = generateTypeRegistry;
package/build/main.js CHANGED
@@ -289,11 +289,20 @@ function makeDeepPartial(options, longs) {
289
289
  const maybeExport = options.exportCommonSymbols ? 'export' : '';
290
290
  // Allow passing longs as numbers or strings, nad we'll convert them
291
291
  const maybeLong = options.forceLong === options_1.LongOption.LONG ? ts_poet_1.code ` : T extends ${longs.Long} ? string | number | Long ` : '';
292
- const keys = options.outputTypeRegistry ? ts_poet_1.code `Exclude<keyof T, '$type'>` : ts_poet_1.code `keyof T`;
292
+ const Builtin = ts_poet_1.conditionalOutput('Builtin', ts_poet_1.code `type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;`);
293
+ // Based on https://github.com/sindresorhus/type-fest/pull/259
294
+ const maybeExcludeType = options.outputTypeRegistry ? `| '$type'` : '';
295
+ const Exact = ts_poet_1.conditionalOutput('Exact', ts_poet_1.code `
296
+ type KeysOfUnion<T> = T extends T ? keyof T : never;
297
+ ${maybeExport} type Exact<P, I extends P> = P extends ${Builtin}
298
+ ? P
299
+ : P &
300
+ { [K in keyof P]: Exact<P[K], I[K]> } & Record<Exclude<keyof I, KeysOfUnion<P> ${maybeExcludeType}>, never>;
301
+ `);
293
302
  // Based on the type from ts-essentials
303
+ const keys = options.outputTypeRegistry ? ts_poet_1.code `Exclude<keyof T, '$type'>` : ts_poet_1.code `keyof T`;
294
304
  const DeepPartial = ts_poet_1.conditionalOutput('DeepPartial', ts_poet_1.code `
295
- type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
296
- ${maybeExport} type DeepPartial<T> = T extends Builtin
305
+ ${maybeExport} type DeepPartial<T> = T extends ${Builtin}
297
306
  ? T
298
307
  ${maybeLong}
299
308
  : T extends Array<infer U>
@@ -304,7 +313,7 @@ function makeDeepPartial(options, longs) {
304
313
  ? { [K in ${keys}]?: DeepPartial<T[K]> }
305
314
  : Partial<T>;
306
315
  `);
307
- return { DeepPartial };
316
+ return { Builtin, DeepPartial, Exact };
308
317
  }
309
318
  function makeTimestampMethods(options, longs) {
310
319
  const Timestamp = ts_poet_1.imp('Timestamp@./google/protobuf/timestamp');
@@ -823,7 +832,7 @@ function generateFromJson(ctx, fullName, messageDesc) {
823
832
  }
824
833
  }
825
834
  else if (types_1.isLong(valueType) && options.forceLong === options_1.LongOption.LONG) {
826
- return ts_poet_1.code `Long.fromString(${from} as string)`;
835
+ return ts_poet_1.code `Long.fromValue(${from} as Long | string)`;
827
836
  }
828
837
  else if (types_1.isEnum(valueType)) {
829
838
  return ts_poet_1.code `${from} as number`;
@@ -1045,8 +1054,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1045
1054
  const chunks = [];
1046
1055
  const Timestamp = ts_poet_1.imp('Timestamp@./google/protobuf/timestamp');
1047
1056
  // create the basic function declaration
1057
+ const paramName = messageDesc.field.length > 0 ? 'object' : '_';
1048
1058
  chunks.push(ts_poet_1.code `
1049
- fromPartial(${messageDesc.field.length > 0 ? 'object' : '_'}: ${utils.DeepPartial}<${fullName}>): ${fullName} {
1059
+ fromPartial<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(${paramName}: I): ${fullName} {
1050
1060
  const message = { ...base${fullName} } as ${fullName};
1051
1061
  `);
1052
1062
  // add a check for each incoming field
@@ -1122,7 +1132,7 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1122
1132
  }
1123
1133
  else {
1124
1134
  chunks.push(ts_poet_1.code `
1125
- message.${fieldName} = (object.${fieldName} ?? []).map((e) => ${readSnippet('e')});
1135
+ message.${fieldName} = object.${fieldName}?.map((e) => ${readSnippet('e')}) || [];
1126
1136
  `);
1127
1137
  }
1128
1138
  }
@@ -1174,7 +1184,7 @@ function generateWrap(fullProtoTypeName) {
1174
1184
  if (types_1.isAnyValueTypeName(fullProtoTypeName)) {
1175
1185
  chunks.push(ts_poet_1.code `wrap(value: any): Value {
1176
1186
  if (value === null) {
1177
- return {nullValue: 0} as Value;
1187
+ return {nullValue: NullValue.NULL_VALUE} as Value;
1178
1188
  } else if (typeof value === 'boolean') {
1179
1189
  return {boolValue: value} as Value;
1180
1190
  } else if (typeof value === 'number') {
@@ -1212,19 +1222,20 @@ function generateUnwrap(fullProtoTypeName) {
1212
1222
  }
1213
1223
  if (types_1.isAnyValueTypeName(fullProtoTypeName)) {
1214
1224
  chunks.push(ts_poet_1.code `unwrap(message: Value): string | number | boolean | Object | null | Array<any> | undefined {
1215
- if (message.stringValue !== undefined) {
1225
+ if (message?.stringValue !== undefined) {
1216
1226
  return message.stringValue;
1217
- } else if (message.numberValue !== undefined) {
1227
+ } else if (message?.numberValue !== undefined) {
1218
1228
  return message.numberValue;
1219
- } else if (message.boolValue !== undefined) {
1229
+ } else if (message?.boolValue !== undefined) {
1220
1230
  return message.boolValue;
1221
- } else if (message.structValue !== undefined) {
1231
+ } else if (message?.structValue !== undefined) {
1222
1232
  return message.structValue;
1223
- } else if (message.listValue !== undefined) {
1233
+ } else if (message?.listValue !== undefined) {
1224
1234
  return message.listValue;
1225
- } else if (message.nullValue !== undefined) {
1235
+ } else if (message?.nullValue !== undefined) {
1226
1236
  return null;
1227
1237
  }
1238
+ return undefined;
1228
1239
  }`);
1229
1240
  }
1230
1241
  if (types_1.isListValueTypeName(fullProtoTypeName)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.90.1",
3
+ "version": "1.92.2",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",
@@ -9,10 +9,19 @@
9
9
  },
10
10
  "scripts": {
11
11
  "build": "yarn tsc",
12
- "setup": "cd ./integration && ./pbjs.sh && ./update-bins.sh && ./codegen.sh",
12
+ "build:test": "yarn proto2bin && yarn proto2pbjs && yarn bin2ts",
13
+ "build:test:local": "yarn proto2bin:local && yarn proto2pbjs:local && yarn bin2ts:local",
14
+ "proto2bin": "docker-compose run --rm protoc update-bins.sh",
15
+ "proto2bin-node": "docker-compose run --rm node update-bins.sh",
16
+ "proto2pbjs": "docker-compose run --rm protoc pbjs.sh",
17
+ "bin2ts": "docker-compose run --rm protoc codegen.sh",
18
+ "proto2bin:local": "integration/update-bins.sh",
19
+ "proto2pbjs:local": "integration/pbjs.sh",
20
+ "bin2ts:local": "integration/codegen.sh",
13
21
  "test": "yarn jest -c jest.config.js --maxWorkers=2",
14
22
  "prettier": "prettier --write {src,tests}/**/*.ts",
15
- "prettier:check": "prettier --list-different {src,tests}/**/*.ts"
23
+ "prettier:check": "prettier --list-different {src,tests}/**/*.ts",
24
+ "setup:docker": "docker-compose build"
16
25
  },
17
26
  "files": [
18
27
  "build"