ts-proto 1.99.0 → 1.102.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 CHANGED
@@ -1,3 +1,31 @@
1
+ # [1.102.0](https://github.com/stephenh/ts-proto/compare/v1.101.0...v1.102.0) (2022-01-18)
2
+
3
+
4
+ ### Features
5
+
6
+ * enable unknown fields for descriptor protos ([#479](https://github.com/stephenh/ts-proto/issues/479)) ([824c996](https://github.com/stephenh/ts-proto/commit/824c9962cd98dc0f9093e8909e3028d900094c54))
7
+
8
+ # [1.101.0](https://github.com/stephenh/ts-proto/compare/v1.100.1...v1.101.0) (2022-01-15)
9
+
10
+
11
+ ### Features
12
+
13
+ * add support for unknown fields ([#473](https://github.com/stephenh/ts-proto/issues/473)) ([3bb9472](https://github.com/stephenh/ts-proto/commit/3bb9472943cf2e698b013487c7370a76576b68b6))
14
+
15
+ ## [1.100.1](https://github.com/stephenh/ts-proto/compare/v1.100.0...v1.100.1) (2022-01-10)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * 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))
21
+
22
+ # [1.100.0](https://github.com/stephenh/ts-proto/compare/v1.99.0...v1.100.0) (2022-01-09)
23
+
24
+
25
+ ### Features
26
+
27
+ * 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))
28
+
1
29
  # [1.99.0](https://github.com/stephenh/ts-proto/compare/v1.98.0...v1.99.0) (2022-01-07)
2
30
 
3
31
 
package/README.markdown CHANGED
@@ -175,6 +175,10 @@ creating a class and calling the right getters/setters.
175
175
 
176
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).
177
177
 
178
+ - ObjectIds can be mapped as `mongodb.ObjectId`
179
+
180
+ (Configurable with the `useObjectId` parameter.)
181
+
178
182
  # Auto-Batching / N+1 Prevention
179
183
 
180
184
  (Note: this is currently only supported by the Twirp clients.)
@@ -347,6 +351,8 @@ Generated code will be placed in the Gradle build directory.
347
351
 
348
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.
349
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
+
350
356
  - With `--ts_proto_opt=outputSchema=true`, meta typings will be generated that can later be used in other code generators.
351
357
 
352
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.
@@ -368,6 +374,8 @@ Generated code will be placed in the Gradle build directory.
368
374
 
369
375
  The default behavior is `useExactTypes=true`, which makes `fromPartial` use Exact type for its argument to make TypeScript reject any unknown properties.
370
376
 
377
+ - With `--ts_proto_opt=unknownFields=true`, all unknown fields will be parsed and output as arrays of buffers.
378
+
371
379
  ### Only Types
372
380
 
373
381
  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.:
@@ -685,7 +693,6 @@ The representation of `google.protobuf.Timestamp` is configurable by the `useDat
685
693
  | --------------------------- | ---------------------- | ------------------------------------ | ---------------- |
686
694
  | `google.protobuf.Timestamp` | `Date` | `{ seconds: number, nanos: number }` | `string` |
687
695
 
688
-
689
696
  # Number Types
690
697
 
691
698
  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';
@@ -520,6 +547,9 @@ function generateDecode(ctx, fullName, messageDesc) {
520
547
  let end = length === undefined ? reader.len : reader.pos + length;
521
548
  const message = createBase${fullName}();
522
549
  `);
550
+ if (options.unknownFields) {
551
+ chunks.push(ts_poet_1.code `(message as any)._unknownFields = {}`);
552
+ }
523
553
  // start the tag loop
524
554
  chunks.push(ts_poet_1.code `
525
555
  while (reader.pos < end) {
@@ -575,6 +605,10 @@ function generateDecode(ctx, fullName, messageDesc) {
575
605
  const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
576
606
  readSnippet = ts_poet_1.code `${utils.fromTimestamp}(${type}.decode(reader, reader.uint32()))`;
577
607
  }
608
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
609
+ const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
610
+ readSnippet = ts_poet_1.code `${utils.fromProtoObjectId}(${type}.decode(reader, reader.uint32()))`;
611
+ }
578
612
  else if (types_1.isMessage(field)) {
579
613
  const type = types_1.basicTypeName(ctx, field);
580
614
  readSnippet = ts_poet_1.code `${type}.decode(reader, reader.uint32())`;
@@ -620,11 +654,22 @@ function generateDecode(ctx, fullName, messageDesc) {
620
654
  }
621
655
  chunks.push(ts_poet_1.code `break;`);
622
656
  });
623
- chunks.push(ts_poet_1.code `
624
- default:
625
- reader.skipType(tag & 7);
626
- break;
627
- `);
657
+ if (options.unknownFields) {
658
+ chunks.push(ts_poet_1.code `
659
+ default:
660
+ const startPos = reader.pos;
661
+ reader.skipType(tag & 7);
662
+ (message as any)._unknownFields[tag] = [...((message as any)._unknownFields[tag] || []), reader.buf.slice(startPos, reader.pos)];
663
+ break;
664
+ `);
665
+ }
666
+ else {
667
+ chunks.push(ts_poet_1.code `
668
+ default:
669
+ reader.skipType(tag & 7);
670
+ break;
671
+ `);
672
+ }
628
673
  // and then wrap up the switch/while/return
629
674
  chunks.push(ts_poet_1.code `}`);
630
675
  chunks.push(ts_poet_1.code `}`);
@@ -641,7 +686,7 @@ function generateEncode(ctx, fullName, messageDesc) {
641
686
  // create the basic function declaration
642
687
  chunks.push(ts_poet_1.code `
643
688
  encode(
644
- ${messageDesc.field.length > 0 ? 'message' : '_'}: ${fullName},
689
+ ${messageDesc.field.length > 0 || options.unknownFields ? 'message' : '_'}: ${fullName},
645
690
  writer: ${Writer} = ${Writer}.create(),
646
691
  ): ${Writer} {
647
692
  `);
@@ -659,6 +704,11 @@ function generateEncode(ctx, fullName, messageDesc) {
659
704
  const tag = ((field.number << 3) | types_1.basicWireType(field.type)) >>> 0;
660
705
  writeSnippet = (place) => ts_poet_1.code `writer.uint32(${tag}).${types_1.toReaderCall(field)}(${place})`;
661
706
  }
707
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
708
+ const tag = ((field.number << 3) | 2) >>> 0;
709
+ const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
710
+ writeSnippet = (place) => ts_poet_1.code `${type}.encode(${utils.toProtoObjectId}(${place}), writer.uint32(${tag}).fork()).ldelim()`;
711
+ }
662
712
  else if (types_1.isTimestamp(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
663
713
  const tag = ((field.number << 3) | 2) >>> 0;
664
714
  const type = types_1.basicTypeName(ctx, field, { keepValueType: true });
@@ -801,6 +851,21 @@ function generateEncode(ctx, fullName, messageDesc) {
801
851
  chunks.push(ts_poet_1.code `${writeSnippet(`message.${fieldName}`)};`);
802
852
  }
803
853
  });
854
+ if (options.unknownFields) {
855
+ chunks.push(ts_poet_1.code `if ('_unknownFields' in message) {
856
+ for (const key of Object.keys(message['_unknownFields'])) {
857
+ const values = message['_unknownFields'][key] as Uint8Array[];
858
+ for (const value of values) {
859
+ writer.uint32(parseInt(key, 10));
860
+ (writer as any)['_push'](
861
+ (val: Uint8Array, buf: Buffer, pos: number) => buf.set(val, pos),
862
+ value.length,
863
+ value
864
+ );
865
+ }
866
+ }
867
+ }`);
868
+ }
804
869
  chunks.push(ts_poet_1.code `return writer;`);
805
870
  chunks.push(ts_poet_1.code `}`);
806
871
  return ts_poet_1.joinCode(chunks, { on: '\n' });
@@ -852,6 +917,9 @@ function generateFromJson(ctx, fullName, messageDesc) {
852
917
  return ts_poet_1.code `${cstr}(${from})`;
853
918
  }
854
919
  }
920
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
921
+ return ts_poet_1.code `${utils.fromJsonObjectId}(${from})`;
922
+ }
855
923
  else if (types_1.isTimestamp(field) && options.useDate === options_1.DateOption.STRING) {
856
924
  return ts_poet_1.code `String(${from})`;
857
925
  }
@@ -901,6 +969,9 @@ function generateFromJson(ctx, fullName, messageDesc) {
901
969
  return ts_poet_1.code `${cstr}(${from})`;
902
970
  }
903
971
  }
972
+ else if (types_1.isObjectId(valueType) && options.useMongoObjectId) {
973
+ return ts_poet_1.code `${utils.fromJsonObjectId}(${from})`;
974
+ }
904
975
  else if (types_1.isTimestamp(valueType) && options.useDate === options_1.DateOption.STRING) {
905
976
  return ts_poet_1.code `String(${from})`;
906
977
  }
@@ -1022,6 +1093,9 @@ function generateToJson(ctx, fullName, messageDesc) {
1022
1093
  ? ts_poet_1.code `${from} !== undefined ? ${toJson}(${from}) : undefined`
1023
1094
  : ts_poet_1.code `${toJson}(${from})`;
1024
1095
  }
1096
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
1097
+ return ts_poet_1.code `${from}.toString()`;
1098
+ }
1025
1099
  else if (types_1.isTimestamp(field) && options.useDate === options_1.DateOption.DATE) {
1026
1100
  return ts_poet_1.code `${from}.toISOString()`;
1027
1101
  }
@@ -1041,6 +1115,9 @@ function generateToJson(ctx, fullName, messageDesc) {
1041
1115
  else if (types_1.isBytes(valueType)) {
1042
1116
  return ts_poet_1.code `${utils.base64FromBytes}(${from})`;
1043
1117
  }
1118
+ else if (types_1.isObjectId(valueType) && options.useMongoObjectId) {
1119
+ return ts_poet_1.code `${from}.toString()`;
1120
+ }
1044
1121
  else if (types_1.isTimestamp(valueType) && options.useDate === options_1.DateOption.DATE) {
1045
1122
  return ts_poet_1.code `${from}.toISOString()`;
1046
1123
  }
@@ -1152,6 +1229,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1152
1229
  if ((types_1.isLong(field) || types_1.isLongValueType(field)) && options.forceLong === options_1.LongOption.LONG) {
1153
1230
  return ts_poet_1.code `Long.fromValue(${from})`;
1154
1231
  }
1232
+ else if (types_1.isObjectId(field) && options.useMongoObjectId) {
1233
+ return ts_poet_1.code `${from} as mongodb.ObjectId`;
1234
+ }
1155
1235
  else if (types_1.isPrimitive(field) ||
1156
1236
  (types_1.isTimestamp(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) ||
1157
1237
  types_1.isValueType(ctx, field)) {
@@ -1178,6 +1258,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1178
1258
  else if (types_1.isAnyValueType(valueType)) {
1179
1259
  return ts_poet_1.code `${from}`;
1180
1260
  }
1261
+ else if (types_1.isObjectId(valueType) && options.useMongoObjectId) {
1262
+ return ts_poet_1.code `${from} as mongodb.ObjectId`;
1263
+ }
1181
1264
  else if (types_1.isTimestamp(valueType) &&
1182
1265
  (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
1183
1266
  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: '',
@@ -62,6 +63,7 @@ function defaultOptions() {
62
63
  onlyTypes: false,
63
64
  emitImportedFiles: true,
64
65
  useExactTypes: true,
66
+ unknownFields: false,
65
67
  };
66
68
  }
67
69
  exports.defaultOptions = defaultOptions;
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.99.0",
3
+ "version": "1.102.0",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",
@@ -48,6 +48,7 @@
48
48
  "@types/node": "^14.14.37",
49
49
  "chokidar": "^3.5.2",
50
50
  "jest": "^26.6.3",
51
+ "mongodb": "^4.3.0",
51
52
  "prettier": "^2.2.1",
52
53
  "reflect-metadata": "^0.1.13",
53
54
  "rxjs": "^7.4.0",