ts-proto 1.97.2 → 1.100.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/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## [1.100.1](https://github.com/stephenh/ts-proto/compare/v1.100.0...v1.100.1) (2022-01-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * respect generateClientImpl=false in grpc-js ([#471](https://github.com/stephenh/ts-proto/issues/471)) ([#472](https://github.com/stephenh/ts-proto/issues/472)) ([2f389f2](https://github.com/stephenh/ts-proto/commit/2f389f243ef11d8d58c32ce37c371aba2cdf294e))
7
+
8
+ # [1.100.0](https://github.com/stephenh/ts-proto/compare/v1.99.0...v1.100.0) (2022-01-09)
9
+
10
+
11
+ ### Features
12
+
13
+ * support mapping ObjectId message as mongodb.ObjectId ([#467](https://github.com/stephenh/ts-proto/issues/467)) ([8b23897](https://github.com/stephenh/ts-proto/commit/8b2389715ecfd5d51b1b24f5a9332e4ff9f09a27))
14
+
15
+ # [1.99.0](https://github.com/stephenh/ts-proto/compare/v1.98.0...v1.99.0) (2022-01-07)
16
+
17
+
18
+ ### Features
19
+
20
+ * yarn watch updates (specified) tests when source files change ([#465](https://github.com/stephenh/ts-proto/issues/465)) ([275d0e7](https://github.com/stephenh/ts-proto/commit/275d0e7c61f3acb2b1fd670b1974e64dd49d6ff4))
21
+
22
+ # [1.98.0](https://github.com/stephenh/ts-proto/compare/v1.97.2...v1.98.0) (2022-01-06)
23
+
24
+
25
+ ### Features
26
+
27
+ * watch for changed integration test files ([#464](https://github.com/stephenh/ts-proto/issues/464)) ([988cd7e](https://github.com/stephenh/ts-proto/commit/988cd7eb84bc3b8b72d6b4d59c38aa794c16c638))
28
+
1
29
  ## [1.97.2](https://github.com/stephenh/ts-proto/compare/v1.97.1...v1.97.2) (2022-01-06)
2
30
 
3
31
 
package/README.markdown CHANGED
@@ -13,6 +13,7 @@
13
13
  - [Table of contents](#table-of-contents)
14
14
  - [Overview](#overview)
15
15
  - [QuickStart](#quickstart)
16
+ - [Buf](#buf)
16
17
  - [Goals](#goals)
17
18
  - [Example Types](#example-types)
18
19
  - [Highlights](#highlights)
@@ -84,6 +85,19 @@ This will generate `*.ts` source files for the given `*.proto` types.
84
85
 
85
86
  If you want to package these source files into an npm package to distribute to clients, just run `tsc` on them as usual to generate the `.js`/`.d.ts` files, and deploy the output as a regular npm package.
86
87
 
88
+ ## Buf
89
+
90
+ If you're using Buf, pass `strategy: all` in your `buf.gen.yaml` file ([docs](https://docs.buf.build/configuration/v1/buf-gen-yaml#strategy)).
91
+
92
+ ```yaml
93
+ version: v1
94
+ plugins:
95
+ - name: ts
96
+ out: ../gen/ts
97
+ strategy: all
98
+ path: ../node_modules/ts-proto/protoc-gen-ts_proto
99
+ ```
100
+
87
101
  # Goals
88
102
 
89
103
  - Idiomatic TypeScript/ES6 types
@@ -161,6 +175,10 @@ creating a class and calling the right getters/setters.
161
175
 
162
176
  - `fromJSON`/`toJSON` use the [proto3 canonical JSON encoding format](https://developers.google.com/protocol-buffers/docs/proto3#json) (e.g. timestamps are ISO strings), unlike [`protobufjs`](https://github.com/protobufjs/protobuf.js/issues/1304).
163
177
 
178
+ - ObjectIds can be mapped as `mongodb.ObjectId`
179
+
180
+ (Configurable with the `useObjectId` parameter.)
181
+
164
182
  # Auto-Batching / N+1 Prevention
165
183
 
166
184
  (Note: this is currently only supported by the Twirp clients.)
@@ -333,6 +351,8 @@ Generated code will be placed in the Gradle build directory.
333
351
 
334
352
  - 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.
335
353
 
354
+ - With `--ts_proto_opt=useObjectId=true`, fields of a type called ObjectId where the message is constructed to have on field called value that is a string will be mapped to type `mongodb.ObjectId` in the generated types. This will require your project to install the mongodb npm package. See [ObjectId](#objectid) for more details.
355
+
336
356
  - With `--ts_proto_opt=outputSchema=true`, meta typings will be generated that can later be used in other code generators.
337
357
 
338
358
  - With `--ts_proto_opt=outputTypeRegistry=true`, the type registry will be generated that can be used to resolve message types by fully-qualified name. Also, each message will get extra `$type` field containing fully-qualified name.
@@ -404,11 +424,13 @@ The commands below assume you have **Docker** installed. To use a **local** copy
404
424
  **Workflow**
405
425
 
406
426
  - Modifying the plugin implementation:
427
+ - The most important logic is found in [src/main.ts](src/main.ts).
407
428
  - Run `yarn bin2ts` or `yarn bin2ts:local`.
408
429
  _Since the proto files were not changed, you only need to regenerate the typescript files._
409
430
  - Run `yarn test` to verify the typescript files are compatible with the reference implementation, and pass other tests.
410
431
  - Updating or adding `.proto` files in the integration directory:
411
- - Run `yarn build:test` to regenerate the integration test files.
432
+ - Run `yarn watch` to automatically regenerate test files when proto files change.
433
+ - Or run `yarn build:test` to regenerate all integration test files.
412
434
  - Run `yarn test` to retest.
413
435
 
414
436
  **Contributing**
@@ -669,7 +691,6 @@ The representation of `google.protobuf.Timestamp` is configurable by the `useDat
669
691
  | --------------------------- | ---------------------- | ------------------------------------ | ---------------- |
670
692
  | `google.protobuf.Timestamp` | `Date` | `{ seconds: number, nanos: number }` | `string` |
671
693
 
672
-
673
694
  # Number Types
674
695
 
675
696
  Numbers are by default assumed to be plain JavaScript `number`s.
@@ -27,11 +27,14 @@ const ServiceError = ts_poet_1.imp('ServiceError@@grpc/grpc-js');
27
27
  * `@grpc/grpc-js` library.
28
28
  */
29
29
  function generateGrpcJsService(ctx, fileDesc, sourceInfo, serviceDesc) {
30
+ const { options } = ctx;
30
31
  const chunks = [];
31
32
  chunks.push(generateServiceDefinition(ctx, fileDesc, sourceInfo, serviceDesc));
32
33
  chunks.push(generateServerStub(ctx, sourceInfo, serviceDesc));
33
- chunks.push(generateClientStub(ctx, sourceInfo, serviceDesc));
34
- chunks.push(generateClientConstructor(fileDesc, serviceDesc));
34
+ if (options.outputClientImpl) {
35
+ chunks.push(generateClientStub(ctx, sourceInfo, serviceDesc));
36
+ chunks.push(generateClientConstructor(fileDesc, serviceDesc));
37
+ }
35
38
  return ts_poet_1.joinCode(chunks, { on: '\n\n' });
36
39
  }
37
40
  exports.generateGrpcJsService = generateGrpcJsService;
package/build/main.js CHANGED
@@ -193,6 +193,7 @@ function makeUtils(options) {
193
193
  return {
194
194
  ...bytes,
195
195
  ...makeDeepPartial(options, longs),
196
+ ...makeObjectIdMethods(options),
196
197
  ...makeTimestampMethods(options, longs),
197
198
  ...longs,
198
199
  ...makeComparisonUtils(),
@@ -325,6 +326,32 @@ function makeDeepPartial(options, longs) {
325
326
  `);
326
327
  return { Builtin, DeepPartial, Exact };
327
328
  }
329
+ function makeObjectIdMethods(options) {
330
+ const mongodb = ts_poet_1.imp('mongodb*mongodb');
331
+ const fromProtoObjectId = ts_poet_1.conditionalOutput('fromProtoObjectId', ts_poet_1.code `
332
+ function fromProtoObjectId(oid: ObjectId): ${mongodb}.ObjectId {
333
+ return new ${mongodb}.ObjectId(oid.value);
334
+ }
335
+ `);
336
+ const fromJsonObjectId = ts_poet_1.conditionalOutput('fromJsonObjectId', ts_poet_1.code `
337
+ function fromJsonObjectId(o: any): ${mongodb}.ObjectId {
338
+ if (o instanceof ${mongodb}.ObjectId) {
339
+ return o;
340
+ } else if (typeof o === "string") {
341
+ return new ${mongodb}.ObjectId(o);
342
+ } else {
343
+ return ${fromProtoObjectId}(ObjectId.fromJSON(o));
344
+ }
345
+ }
346
+ `);
347
+ const toProtoObjectId = ts_poet_1.conditionalOutput('toProtoObjectId', ts_poet_1.code `
348
+ function toProtoObjectId(oid: ${mongodb}.ObjectId): ObjectId {
349
+ const value = oid.toString();
350
+ return { value };
351
+ }
352
+ `);
353
+ return { fromJsonObjectId, fromProtoObjectId, toProtoObjectId };
354
+ }
328
355
  function makeTimestampMethods(options, longs) {
329
356
  const Timestamp = utils_1.impProto(options, 'google/protobuf/timestamp', 'Timestamp');
330
357
  let seconds = 'date.getTime() / 1_000';
@@ -575,6 +602,10 @@ function generateDecode(ctx, fullName, messageDesc) {
575
602
  const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
576
603
  readSnippet = ts_poet_1.code `${utils.fromTimestamp}(${type}.decode(reader, reader.uint32()))`;
577
604
  }
605
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
606
+ const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
607
+ readSnippet = ts_poet_1.code `${utils.fromProtoObjectId}(${type}.decode(reader, reader.uint32()))`;
608
+ }
578
609
  else if (types_1.isMessage(field)) {
579
610
  const type = types_1.basicTypeName(ctx, field);
580
611
  readSnippet = ts_poet_1.code `${type}.decode(reader, reader.uint32())`;
@@ -659,6 +690,11 @@ function generateEncode(ctx, fullName, messageDesc) {
659
690
  const tag = ((field.number << 3) | types_1.basicWireType(field.type)) >>> 0;
660
691
  writeSnippet = (place) => ts_poet_1.code `writer.uint32(${tag}).${types_1.toReaderCall(field)}(${place})`;
661
692
  }
693
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
694
+ const tag = ((field.number << 3) | 2) >>> 0;
695
+ const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
696
+ writeSnippet = (place) => ts_poet_1.code `${type}.encode(${utils.toProtoObjectId}(${place}), writer.uint32(${tag}).fork()).ldelim()`;
697
+ }
662
698
  else if (types_1.isTimestamp(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
663
699
  const tag = ((field.number << 3) | 2) >>> 0;
664
700
  const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
@@ -814,7 +850,6 @@ function generateEncode(ctx, fullName, messageDesc) {
814
850
  function generateFromJson(ctx, fullName, messageDesc) {
815
851
  const { options, utils, typeMap } = ctx;
816
852
  const chunks = [];
817
- const choiceFieldChunks = [];
818
853
  // create the basic function declaration
819
854
  chunks.push(ts_poet_1.code `
820
855
  fromJSON(${messageDesc.field.length > 0 ? 'object' : '_'}: any): ${fullName} {
@@ -853,6 +888,9 @@ function generateFromJson(ctx, fullName, messageDesc) {
853
888
  return ts_poet_1.code `${cstr}(${from})`;
854
889
  }
855
890
  }
891
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
892
+ return ts_poet_1.code `${utils.fromJsonObjectId}(${from})`;
893
+ }
856
894
  else if (types_1.isTimestamp(field) && options.useDate === options_1.DateOption.STRING) {
857
895
  return ts_poet_1.code `String(${from})`;
858
896
  }
@@ -902,6 +940,9 @@ function generateFromJson(ctx, fullName, messageDesc) {
902
940
  return ts_poet_1.code `${cstr}(${from})`;
903
941
  }
904
942
  }
943
+ else if (types_1.isObjectId(valueType) && options.useMongoObjectId) {
944
+ return ts_poet_1.code `${utils.fromJsonObjectId}(${from})`;
945
+ }
905
946
  else if (types_1.isTimestamp(valueType) && options.useDate === options_1.DateOption.STRING) {
906
947
  return ts_poet_1.code `String(${from})`;
907
948
  }
@@ -1023,6 +1064,9 @@ function generateToJson(ctx, fullName, messageDesc) {
1023
1064
  ? ts_poet_1.code `${from} !== undefined ? ${toJson}(${from}) : undefined`
1024
1065
  : ts_poet_1.code `${toJson}(${from})`;
1025
1066
  }
1067
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
1068
+ return ts_poet_1.code `${from}.toString()`;
1069
+ }
1026
1070
  else if (types_1.isTimestamp(field) && options.useDate === options_1.DateOption.DATE) {
1027
1071
  return ts_poet_1.code `${from}.toISOString()`;
1028
1072
  }
@@ -1042,6 +1086,9 @@ function generateToJson(ctx, fullName, messageDesc) {
1042
1086
  else if (types_1.isBytes(valueType)) {
1043
1087
  return ts_poet_1.code `${utils.base64FromBytes}(${from})`;
1044
1088
  }
1089
+ else if (types_1.isObjectId(valueType) && options.useMongoObjectId) {
1090
+ return ts_poet_1.code `${from}.toString()`;
1091
+ }
1045
1092
  else if (types_1.isTimestamp(valueType) && options.useDate === options_1.DateOption.DATE) {
1046
1093
  return ts_poet_1.code `${from}.toISOString()`;
1047
1094
  }
@@ -1153,6 +1200,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1153
1200
  if ((types_1.isLong(field) || types_1.isLongValueType(field)) && options.forceLong === options_1.LongOption.LONG) {
1154
1201
  return ts_poet_1.code `Long.fromValue(${from})`;
1155
1202
  }
1203
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
1204
+ return ts_poet_1.code `${from} as mongodb.ObjectId`;
1205
+ }
1156
1206
  else if (types_1.isPrimitive(field) ||
1157
1207
  (types_1.isTimestamp(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) ||
1158
1208
  types_1.isValueType(ctx, field)) {
@@ -1179,6 +1229,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1179
1229
  else if (types_1.isAnyValueType(valueType)) {
1180
1230
  return ts_poet_1.code `${from}`;
1181
1231
  }
1232
+ else if (types_1.isObjectId(valueType) && options.useMongoObjectId) {
1233
+ return ts_poet_1.code `${from} as mongodb.ObjectId`;
1234
+ }
1182
1235
  else if (types_1.isTimestamp(valueType) &&
1183
1236
  (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
1184
1237
  return ts_poet_1.code `${from}`;
package/build/options.js CHANGED
@@ -38,6 +38,7 @@ function defaultOptions() {
38
38
  forceLong: LongOption.NUMBER,
39
39
  useOptionals: 'none',
40
40
  useDate: DateOption.DATE,
41
+ useMongoObjectId: false,
41
42
  oneof: OneofOption.PROPERTIES,
42
43
  esModuleInterop: false,
43
44
  fileSuffix: '',
package/build/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.rawRequestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isStructTypeName = exports.isStructType = exports.isListValueTypeName = exports.isListValueType = exports.isBytesValueType = exports.isAnyValueTypeName = exports.isAnyValueType = exports.isValueType = exports.isTimestamp = exports.isMapType = exports.isWholeNumber = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isOptionalProperty = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
3
+ exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.rawRequestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isStructTypeName = exports.isStructType = exports.isListValueTypeName = exports.isListValueType = exports.isBytesValueType = exports.isAnyValueTypeName = exports.isAnyValueType = exports.isValueType = exports.isTimestamp = exports.isObjectId = exports.isMapType = exports.isWholeNumber = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isOptionalProperty = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
4
4
  const ts_proto_descriptors_1 = require("ts-proto-descriptors");
5
5
  const ts_poet_1 = require("ts-poet");
6
6
  const options_1 = require("./options");
@@ -378,6 +378,11 @@ function isMapType(ctx, messageDesc, field) {
378
378
  return detectMapType(ctx, messageDesc, field) !== undefined;
379
379
  }
380
380
  exports.isMapType = isMapType;
381
+ function isObjectId(field) {
382
+ // need to use endsWith instead of === because objectid could be imported from an external proto file
383
+ return field.typeName.endsWith('.ObjectId');
384
+ }
385
+ exports.isObjectId = isObjectId;
381
386
  function isTimestamp(field) {
382
387
  return field.typeName === '.google.protobuf.Timestamp';
383
388
  }
@@ -510,6 +515,10 @@ function messageToTypeName(ctx, protoType, typeOptions = {}) {
510
515
  return ts_poet_1.code `string`;
511
516
  }
512
517
  }
518
+ // need to use endsWith instead of === because objectid could be imported from an external proto file
519
+ if (!typeOptions.keepValueType && options.useMongoObjectId && protoType.endsWith('.ObjectId')) {
520
+ return ts_poet_1.code `mongodb.ObjectId`;
521
+ }
513
522
  const [module, type] = toModuleAndType(typeMap, protoType);
514
523
  return ts_poet_1.code `${utils_1.impProto(options, module, type)}`;
515
524
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.97.2",
3
+ "version": "1.100.1",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",
@@ -19,9 +19,10 @@
19
19
  "proto2pbjs:local": "integration/pbjs.sh",
20
20
  "bin2ts:local": "integration/codegen.sh",
21
21
  "test": "yarn jest -c jest.config.js --maxWorkers=2",
22
- "prettier": "prettier --write {src,tests}/**/*.ts",
22
+ "prettier": "prettier --write {src,tests}/**/*.ts integration/*.ts",
23
23
  "prettier:check": "prettier --list-different {src,tests}/**/*.ts",
24
- "setup:docker": "docker-compose build"
24
+ "setup:docker": "docker-compose build",
25
+ "watch": "ts-node integration/watch.ts"
25
26
  },
26
27
  "files": [
27
28
  "build"
@@ -45,7 +46,9 @@
45
46
  "@semantic-release/release-notes-generator": "^9.0.2",
46
47
  "@types/jest": "^26.0.22",
47
48
  "@types/node": "^14.14.37",
49
+ "chokidar": "^3.5.2",
48
50
  "jest": "^26.6.3",
51
+ "mongodb": "^4.3.0",
49
52
  "prettier": "^2.2.1",
50
53
  "reflect-metadata": "^0.1.13",
51
54
  "rxjs": "^7.4.0",