ts-proto 1.165.3 → 1.166.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/README.markdown CHANGED
@@ -899,12 +899,14 @@ ExampleMessage.encode({ anything: true });
899
899
  The representation of `google.protobuf.Timestamp` is configurable by the `useDate` flag.
900
900
  The `useJsonTimestamp` flag controls precision when `useDate` is `false`.
901
901
 
902
- | Protobuf well-known type | Default/`useDate=true` | `useDate=false` | `useDate=string` |
903
- | --------------------------- | ---------------------- | ------------------------------------ | ---------------- |
904
- | `google.protobuf.Timestamp` | `Date` | `{ seconds: number, nanos: number }` | `string` |
902
+ | Protobuf well-known type | Default/`useDate=true` | `useDate=false` | `useDate=string` | `useDate=string-nano` |
903
+ | --------------------------- | ---------------------- | ------------------------------------ | ---------------- | --------------------- |
904
+ | `google.protobuf.Timestamp` | `Date` | `{ seconds: number, nanos: number }` | `string` | `string` |
905
905
 
906
906
  When using `useDate=false` and `useJsonTimestamp=raw` timestamp is represented as `{ seconds: number, nanos: number }`, but has nanosecond precision.
907
907
 
908
+ When using `useDate=string-nano` timestamp is represented as an ISO string with nanosecond precision `1970-01-01T14:27:59.987654321Z` and relies on [nano-date](https://www.npmjs.com/package/nano-date) library for conversion. You'll need to install it in your project.
909
+
908
910
  # Number Types
909
911
 
910
912
  Numbers are by default assumed to be plain JavaScript `number`s.
package/build/encode.js CHANGED
@@ -13,7 +13,9 @@ function generateEncoder(ctx, typeName) {
13
13
  if (name == "Timestamp") {
14
14
  const TimestampValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/timestamp", name);
15
15
  let value = (0, ts_poet_1.code) `value`;
16
- if (ctx.options.useDate === options_1.DateOption.DATE || ctx.options.useDate === options_1.DateOption.STRING) {
16
+ if (ctx.options.useDate === options_1.DateOption.DATE ||
17
+ ctx.options.useDate === options_1.DateOption.STRING ||
18
+ ctx.options.useDate === options_1.DateOption.STRING_NANO) {
17
19
  value = (0, ts_poet_1.code) `${ctx.utils.toTimestamp}(${value})`;
18
20
  }
19
21
  return (0, ts_poet_1.code) `${TimestampValue}.encode(${value}).finish()`;
@@ -59,7 +61,9 @@ function generateDecoder(ctx, typeName) {
59
61
  if (name == "Timestamp") {
60
62
  TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/timestamp", name);
61
63
  const decoder = (0, ts_poet_1.code) `${TypeValue}.decode(value)`;
62
- if (ctx.options.useDate === options_1.DateOption.DATE || ctx.options.useDate === options_1.DateOption.STRING) {
64
+ if (ctx.options.useDate === options_1.DateOption.DATE ||
65
+ ctx.options.useDate === options_1.DateOption.STRING ||
66
+ ctx.options.useDate === options_1.DateOption.STRING_NANO) {
63
67
  return (0, ts_poet_1.code) `${ctx.utils.fromTimestamp}(${decoder})`;
64
68
  }
65
69
  return decoder;
package/build/main.js CHANGED
@@ -181,7 +181,7 @@ function generateFile(ctx, fileDesc) {
181
181
  let hasStreamingMethods = false;
182
182
  (0, visit_1.visitServices)(fileDesc, sourceInfo, (serviceDesc, sInfo) => {
183
183
  if (options.nestJs) {
184
- // NestJS is sufficiently different that we special case all of the client/server interfaces
184
+ // NestJS is sufficiently different that we special case the client/server interfaces
185
185
  // generate nestjs grpc client interface
186
186
  chunks.push((0, generate_nestjs_1.generateNestjsServiceClient)(ctx, fileDesc, sInfo, serviceDesc));
187
187
  // and the service controller interface
@@ -194,40 +194,38 @@ function generateFile(ctx, fileDesc) {
194
194
  }
195
195
  chunks.push((0, ts_poet_1.code) `export const ${serviceConstName} = "${serviceDesc.name}";`);
196
196
  }
197
- else {
198
- const uniqueServices = [...new Set(options.outputServices)].sort();
199
- uniqueServices.forEach((outputService) => {
200
- if (outputService === options_1.ServiceOption.GRPC) {
201
- chunks.push((0, generate_grpc_js_1.generateGrpcJsService)(ctx, fileDesc, sInfo, serviceDesc));
202
- }
203
- else if (outputService === options_1.ServiceOption.NICE_GRPC) {
204
- chunks.push((0, generate_nice_grpc_1.generateNiceGrpcService)(ctx, fileDesc, sInfo, serviceDesc));
205
- }
206
- else if (outputService === options_1.ServiceOption.GENERIC) {
207
- chunks.push((0, generate_generic_service_definition_1.generateGenericServiceDefinition)(ctx, fileDesc, sInfo, serviceDesc));
197
+ const uniqueServices = [...new Set(options.outputServices)].sort();
198
+ uniqueServices.forEach((outputService) => {
199
+ if (outputService === options_1.ServiceOption.GRPC) {
200
+ chunks.push((0, generate_grpc_js_1.generateGrpcJsService)(ctx, fileDesc, sInfo, serviceDesc));
201
+ }
202
+ else if (outputService === options_1.ServiceOption.NICE_GRPC) {
203
+ chunks.push((0, generate_nice_grpc_1.generateNiceGrpcService)(ctx, fileDesc, sInfo, serviceDesc));
204
+ }
205
+ else if (outputService === options_1.ServiceOption.GENERIC) {
206
+ chunks.push((0, generate_generic_service_definition_1.generateGenericServiceDefinition)(ctx, fileDesc, sInfo, serviceDesc));
207
+ }
208
+ else if (outputService === options_1.ServiceOption.DEFAULT) {
209
+ // This service could be Twirp or grpc-web or JSON (maybe). So far all of their
210
+ // interfaces are fairly similar so we share the same service interface.
211
+ chunks.push((0, generate_services_1.generateService)(ctx, fileDesc, sInfo, serviceDesc));
212
+ if (options.outputClientImpl === true) {
213
+ chunks.push((0, generate_services_1.generateServiceClientImpl)(ctx, fileDesc, serviceDesc));
208
214
  }
209
- else if (outputService === options_1.ServiceOption.DEFAULT) {
210
- // This service could be Twirp or grpc-web or JSON (maybe). So far all of their
211
- // interfaces are fairly similar so we share the same service interface.
212
- chunks.push((0, generate_services_1.generateService)(ctx, fileDesc, sInfo, serviceDesc));
213
- if (options.outputClientImpl === true) {
214
- chunks.push((0, generate_services_1.generateServiceClientImpl)(ctx, fileDesc, serviceDesc));
215
- }
216
- else if (options.outputClientImpl === "grpc-web") {
217
- chunks.push((0, generate_grpc_web_1.generateGrpcClientImpl)(ctx, fileDesc, serviceDesc));
218
- chunks.push((0, generate_grpc_web_1.generateGrpcServiceDesc)(fileDesc, serviceDesc));
219
- serviceDesc.method.forEach((method) => {
220
- if (!method.clientStreaming) {
221
- chunks.push((0, generate_grpc_web_1.generateGrpcMethodDesc)(ctx, serviceDesc, method));
222
- }
223
- if (method.serverStreaming) {
224
- hasServerStreamingMethods = true;
225
- }
226
- });
227
- }
215
+ else if (options.outputClientImpl === "grpc-web") {
216
+ chunks.push((0, generate_grpc_web_1.generateGrpcClientImpl)(ctx, fileDesc, serviceDesc));
217
+ chunks.push((0, generate_grpc_web_1.generateGrpcServiceDesc)(fileDesc, serviceDesc));
218
+ serviceDesc.method.forEach((method) => {
219
+ if (!method.clientStreaming) {
220
+ chunks.push((0, generate_grpc_web_1.generateGrpcMethodDesc)(ctx, serviceDesc, method));
221
+ }
222
+ if (method.serverStreaming) {
223
+ hasServerStreamingMethods = true;
224
+ }
225
+ });
228
226
  }
229
- });
230
- }
227
+ }
228
+ });
231
229
  serviceDesc.method.forEach((methodDesc, _index) => {
232
230
  if (methodDesc.serverStreaming || methodDesc.clientStreaming) {
233
231
  hasStreamingMethods = true;
@@ -462,23 +460,21 @@ function makeObjectIdMethods() {
462
460
  }
463
461
  function makeTimestampMethods(options, longs, bytes) {
464
462
  const Timestamp = (0, utils_1.impProto)(options, "google/protobuf/timestamp", "Timestamp");
465
- let seconds = "date.getTime() / 1_000";
463
+ const NanoDate = (0, ts_poet_1.imp)("NanoDate=nano-date");
464
+ let seconds = "Math.trunc(date.getTime() / 1_000)";
466
465
  let toNumberCode = "t.seconds";
467
466
  const makeToNumberCode = (methodCall) => `t.seconds${options.useOptionals === "all" ? "?" : ""}.${methodCall}`;
468
467
  if (options.forceLong === options_1.LongOption.LONG) {
469
468
  toNumberCode = makeToNumberCode("toNumber()");
470
- seconds = (0, ts_poet_1.code) `${longs.numberToLong}(date.getTime() / 1_000)`;
469
+ seconds = (0, ts_poet_1.code) `${longs.numberToLong}(${seconds})`;
471
470
  }
472
471
  else if (options.forceLong === options_1.LongOption.BIGINT) {
473
472
  toNumberCode = (0, ts_poet_1.code) `${bytes.globalThis}.Number(${makeToNumberCode("toString()")})`;
474
- seconds = (0, ts_poet_1.code) `BigInt(Math.trunc(date.getTime() / 1_000))`;
473
+ seconds = (0, ts_poet_1.code) `BigInt(${seconds})`;
475
474
  }
476
475
  else if (options.forceLong === options_1.LongOption.STRING) {
477
476
  toNumberCode = (0, ts_poet_1.code) `${bytes.globalThis}.Number(t.seconds)`;
478
- // Must discard the fractional piece here
479
- // Otherwise the fraction ends up on the seconds when parsed as a Long
480
- // (note this only occurs when the string is > 8 characters)
481
- seconds = "Math.trunc(date.getTime() / 1_000).toString()";
477
+ seconds = (0, ts_poet_1.code) `${seconds}.toString()`;
482
478
  }
483
479
  const maybeTypeField = (0, options_1.addTypeToMessages)(options) ? `$type: 'google.protobuf.Timestamp',` : "";
484
480
  const toTimestamp = (0, ts_poet_1.conditionalOutput)("toTimestamp", options.useDate === options_1.DateOption.STRING
@@ -490,7 +486,24 @@ function makeTimestampMethods(options, longs, bytes) {
490
486
  return { ${maybeTypeField} seconds, nanos };
491
487
  }
492
488
  `
493
- : (0, ts_poet_1.code) `
489
+ : options.useDate === options_1.DateOption.STRING_NANO
490
+ ? (0, ts_poet_1.code) `
491
+ function toTimestamp(dateStr: string): ${Timestamp} {
492
+ const nanoDate = new ${NanoDate}(dateStr);
493
+
494
+ const date = {
495
+ getTime: (): number => nanoDate.valueOf(),
496
+ } as const;
497
+ const seconds = ${seconds};
498
+
499
+ let nanos = nanoDate.getMilliseconds() * 1_000_000;
500
+ nanos += nanoDate.getMicroseconds() * 1_000;
501
+ nanos += nanoDate.getNanoseconds();
502
+
503
+ return { ${maybeTypeField} seconds, nanos };
504
+ }
505
+ `
506
+ : (0, ts_poet_1.code) `
494
507
  function toTimestamp(date: Date): ${Timestamp} {
495
508
  const seconds = ${seconds};
496
509
  const nanos = (date.getTime() % 1_000) * 1_000_000;
@@ -505,7 +518,23 @@ function makeTimestampMethods(options, longs, bytes) {
505
518
  return new ${bytes.globalThis}.Date(millis).toISOString();
506
519
  }
507
520
  `
508
- : (0, ts_poet_1.code) `
521
+ : options.useDate === options_1.DateOption.STRING_NANO
522
+ ? (0, ts_poet_1.code) `
523
+ function fromTimestamp(t: ${Timestamp}): string {
524
+ const seconds = ${toNumberCode} || 0;
525
+ const nanos = (t.nanos || 0) % 1_000;
526
+ const micros = Math.trunc(((t.nanos || 0) % 1_000_000) / 1_000)
527
+ let millis = seconds * 1_000;
528
+ millis += Math.trunc((t.nanos || 0) / 1_000_000);
529
+
530
+ const nanoDate = new ${NanoDate}(millis);
531
+ nanoDate.setMicroseconds(micros);
532
+ nanoDate.setNanoseconds(nanos);
533
+
534
+ return nanoDate.toISOStringFull();
535
+ }
536
+ `
537
+ : (0, ts_poet_1.code) `
509
538
  function fromTimestamp(t: ${Timestamp}): Date {
510
539
  let millis = (${toNumberCode} || 0) * 1_000;
511
540
  millis += (t.nanos || 0) / 1_000_000;
@@ -748,7 +777,10 @@ function getDecodeReadSnippet(ctx, field) {
748
777
  const decoder = (0, ts_poet_1.code) `${type}.decode(reader, reader.uint32())`;
749
778
  readSnippet = (0, ts_poet_1.code) `${unwrap(decoder)}`;
750
779
  }
751
- else if ((0, types_1.isTimestamp)(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
780
+ else if ((0, types_1.isTimestamp)(field) &&
781
+ (options.useDate === options_1.DateOption.DATE ||
782
+ options.useDate === options_1.DateOption.STRING ||
783
+ options.useDate === options_1.DateOption.STRING_NANO)) {
752
784
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
753
785
  readSnippet = (0, ts_poet_1.code) `${utils.fromTimestamp}(${type}.decode(reader, reader.uint32()))`;
754
786
  }
@@ -977,7 +1009,10 @@ function getEncodeWriteSnippet(ctx, field) {
977
1009
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
978
1010
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toProtoObjectId}(${place}), writer.uint32(${tag}).fork()).ldelim()`;
979
1011
  }
980
- else if ((0, types_1.isTimestamp)(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
1012
+ else if ((0, types_1.isTimestamp)(field) &&
1013
+ (options.useDate === options_1.DateOption.DATE ||
1014
+ options.useDate === options_1.DateOption.STRING ||
1015
+ options.useDate === options_1.DateOption.STRING_NANO)) {
981
1016
  const tag = ((field.number << 3) | 2) >>> 0;
982
1017
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
983
1018
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.uint32(${tag}).fork()).ldelim()`;
@@ -1316,7 +1351,10 @@ function generateExtension(ctx, message, extension) {
1316
1351
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1317
1352
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toProtoObjectId}(${place}), writer.fork()).ldelim()`;
1318
1353
  }
1319
- else if ((0, types_1.isTimestamp)(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
1354
+ else if ((0, types_1.isTimestamp)(field) &&
1355
+ (options.useDate === options_1.DateOption.DATE ||
1356
+ options.useDate === options_1.DateOption.STRING ||
1357
+ options.useDate === options_1.DateOption.STRING_NANO)) {
1320
1358
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1321
1359
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.fork()).ldelim()`;
1322
1360
  }
@@ -1505,7 +1543,8 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1505
1543
  else if ((0, types_1.isObjectId)(field) && options.useMongoObjectId) {
1506
1544
  return (0, ts_poet_1.code) `${utils.fromJsonObjectId}(${from})`;
1507
1545
  }
1508
- else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.STRING) {
1546
+ else if ((0, types_1.isTimestamp)(field) &&
1547
+ (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
1509
1548
  return (0, ts_poet_1.code) `${utils.globalThis}.String(${from})`;
1510
1549
  }
1511
1550
  else if ((0, types_1.isTimestamp)(field) &&
@@ -1568,7 +1607,8 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1568
1607
  else if ((0, types_1.isObjectId)(valueField) && options.useMongoObjectId) {
1569
1608
  return (0, ts_poet_1.code) `${utils.fromJsonObjectId}(${from})`;
1570
1609
  }
1571
- else if ((0, types_1.isTimestamp)(valueField) && options.useDate === options_1.DateOption.STRING) {
1610
+ else if ((0, types_1.isTimestamp)(valueField) &&
1611
+ (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
1572
1612
  return (0, ts_poet_1.code) `${utils.globalThis}.String(${from})`;
1573
1613
  }
1574
1614
  else if ((0, types_1.isTimestamp)(valueField) &&
@@ -1729,7 +1769,8 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1729
1769
  else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.DATE) {
1730
1770
  return (0, ts_poet_1.code) `${from}.toISOString()`;
1731
1771
  }
1732
- else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.STRING) {
1772
+ else if ((0, types_1.isTimestamp)(field) &&
1773
+ (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
1733
1774
  return (0, ts_poet_1.code) `${from}`;
1734
1775
  }
1735
1776
  else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.TIMESTAMP) {
@@ -1754,7 +1795,8 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1754
1795
  else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.DATE) {
1755
1796
  return (0, ts_poet_1.code) `${from}.toISOString()`;
1756
1797
  }
1757
- else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.STRING) {
1798
+ else if ((0, types_1.isTimestamp)(valueType) &&
1799
+ (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
1758
1800
  return (0, ts_poet_1.code) `${from}`;
1759
1801
  }
1760
1802
  else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.TIMESTAMP) {
@@ -1919,7 +1961,10 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1919
1961
  return (0, ts_poet_1.code) `${from} as mongodb.ObjectId`;
1920
1962
  }
1921
1963
  else if ((0, types_1.isPrimitive)(field) ||
1922
- ((0, types_1.isTimestamp)(field) && (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) ||
1964
+ ((0, types_1.isTimestamp)(field) &&
1965
+ (options.useDate === options_1.DateOption.DATE ||
1966
+ options.useDate === options_1.DateOption.STRING ||
1967
+ options.useDate === options_1.DateOption.STRING_NANO)) ||
1923
1968
  (0, types_1.isValueType)(ctx, field)) {
1924
1969
  return (0, ts_poet_1.code) `${from}`;
1925
1970
  }
@@ -1951,7 +1996,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1951
1996
  return (0, ts_poet_1.code) `${from} as mongodb.ObjectId`;
1952
1997
  }
1953
1998
  else if ((0, types_1.isTimestamp)(valueField) &&
1954
- (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.STRING)) {
1999
+ (options.useDate === options_1.DateOption.DATE ||
2000
+ options.useDate === options_1.DateOption.STRING ||
2001
+ options.useDate === options_1.DateOption.STRING_NANO)) {
1955
2002
  return (0, ts_poet_1.code) `${from}`;
1956
2003
  }
1957
2004
  else if ((0, types_1.isValueType)(ctx, valueField)) {
package/build/options.js CHANGED
@@ -12,6 +12,7 @@ var DateOption;
12
12
  (function (DateOption) {
13
13
  DateOption["DATE"] = "date";
14
14
  DateOption["STRING"] = "string";
15
+ DateOption["STRING_NANO"] = "string-nano";
15
16
  DateOption["TIMESTAMP"] = "timestamp";
16
17
  })(DateOption || (exports.DateOption = DateOption = {}));
17
18
  var JsonTimestampOption;
@@ -141,9 +142,15 @@ function optionsFromParameter(parameter) {
141
142
  if (typeof options.outputServices == "string") {
142
143
  options.outputServices = [options.outputServices];
143
144
  }
144
- if (options.outputServices.length == 0) {
145
+ // Assume the user wants the default service output, unless they're using nestJs, which has
146
+ // its own controllers output (although nestjs users can ask for other services too).
147
+ if (options.outputServices.length == 0 && !options.nestJs) {
145
148
  options.outputServices = [ServiceOption.DEFAULT];
146
149
  }
150
+ // If using nestJs + other services, add the encode methods back
151
+ if (options.nestJs && options.outputServices.length > 0) {
152
+ options.outputEncodeMethods = true;
153
+ }
147
154
  if (options.useDate === true) {
148
155
  // Treat useDate=true as DATE
149
156
  options.useDate = DateOption.DATE;
package/build/types.js CHANGED
@@ -554,7 +554,7 @@ function messageToTypeName(ctx, protoType, typeOptions = {}) {
554
554
  if (options.useDate == options_1.DateOption.DATE) {
555
555
  return (0, ts_poet_1.code) `Date`;
556
556
  }
557
- if (options.useDate == options_1.DateOption.STRING) {
557
+ if (options.useDate == options_1.DateOption.STRING || options.useDate == options_1.DateOption.STRING_NANO) {
558
558
  return (0, ts_poet_1.code) `string`;
559
559
  }
560
560
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.165.3",
3
+ "version": "1.166.1",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",
@@ -52,6 +52,7 @@
52
52
  "jest": "^29.6.1",
53
53
  "jest-ts-webcompat-resolver": "^1.0.0",
54
54
  "mongodb": "^5.7.0",
55
+ "nano-date": "^4.1.0",
55
56
  "nice-grpc": "^2.1.4",
56
57
  "object-hash": "^3.0.0",
57
58
  "prettier": "^2.8.8",