ts-proto 2.7.7 → 2.8.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
@@ -1072,14 +1072,16 @@ ExampleMessage.encode({ anything: true });
1072
1072
  The representation of `google.protobuf.Timestamp` is configurable by the `useDate` flag.
1073
1073
  The `useJsonTimestamp` flag controls precision when `useDate` is `false`.
1074
1074
 
1075
- | Protobuf well-known type | Default/`useDate=true` | `useDate=false` | `useDate=string` | `useDate=string-nano` |
1076
- | --------------------------- | ---------------------- | ------------------------------------ | ---------------- | --------------------- |
1077
- | `google.protobuf.Timestamp` | `Date` | `{ seconds: number, nanos: number }` | `string` | `string` |
1075
+ | Protobuf well-known type | Default/`useDate=true` | `useDate=false` | `useDate=string` | `useDate=string-nano` | `useDate=temporal` |
1076
+ | --------------------------- | ---------------------- | ------------------------------------ | ---------------- | --------------------- | ------------------ |
1077
+ | `google.protobuf.Timestamp` | `Date` | `{ seconds: number, nanos: number }` | `string` | `string` | `Temporal.Instant` |
1078
1078
 
1079
1079
  When using `useDate=false` and `useJsonTimestamp=raw` timestamp is represented as `{ seconds: number, nanos: number }`, but has nanosecond precision.
1080
1080
 
1081
1081
  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.
1082
1082
 
1083
+ When using `useDate=temporal` timestamp is represented as a [Temporal.Instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant) object with nanosecond precision. Since the [Temporal](https://github.com/tc39/proposal-temporal) proposal isn't yet fully implemented in all browsers, this will rely on having a polyfilled environment, such as through [temporal-polyfill](https://www.npmjs.com/package/temporal-polyfill). You'll need to install it in your project. Enabling this feature _may_ also require ensuring you have `BigInt` support, either directly or through a polyfill, depending on your choice of `Temporal` library.
1084
+
1083
1085
  # Number Types
1084
1086
 
1085
1087
  Numbers are by default assumed to be plain JavaScript `number`s.
@@ -16,7 +16,8 @@ function generateEncoder(ctx, typeName) {
16
16
  let value = (0, ts_poet_1.code) `value`;
17
17
  if (ctx.options.useDate === options_1.DateOption.DATE ||
18
18
  ctx.options.useDate === options_1.DateOption.STRING ||
19
- ctx.options.useDate === options_1.DateOption.STRING_NANO) {
19
+ ctx.options.useDate === options_1.DateOption.STRING_NANO ||
20
+ ctx.options.useDate === options_1.DateOption.TEMPORAL) {
20
21
  value = (0, ts_poet_1.code) `${ctx.utils.toTimestamp}(${value})`;
21
22
  }
22
23
  return (0, ts_poet_1.code) `${TimestampValue}.encode(${value}).finish()`;
@@ -63,7 +64,8 @@ function generateDecoder(ctx, typeName) {
63
64
  const decoder = (0, ts_poet_1.code) `${TypeValue}.decode(value)`;
64
65
  if (ctx.options.useDate === options_1.DateOption.DATE ||
65
66
  ctx.options.useDate === options_1.DateOption.STRING ||
66
- ctx.options.useDate === options_1.DateOption.STRING_NANO) {
67
+ ctx.options.useDate === options_1.DateOption.STRING_NANO ||
68
+ ctx.options.useDate === options_1.DateOption.TEMPORAL) {
67
69
  return (0, ts_poet_1.code) `${ctx.utils.fromTimestamp}(${decoder})`;
68
70
  }
69
71
  return decoder;
package/build/src/main.js CHANGED
@@ -484,7 +484,14 @@ function makeDeepPartial(options, longs) {
484
484
  const maybeExport = options.exportCommonSymbols ? "export" : "";
485
485
  // Allow passing longs as numbers or strings, nad we'll convert them
486
486
  const maybeLong = options.forceLong === options_1.LongOption.LONG ? (0, ts_poet_1.code) ` : T extends ${longs.Long} ? string | number | Long ` : "";
487
- const Builtin = (0, ts_poet_1.conditionalOutput)("Builtin", (0, ts_poet_1.code) `type Builtin = Date | Function | Uint8Array | string | number | boolean |${options.forceLong === options_1.LongOption.BIGINT ? " bigint |" : ""} undefined;`);
487
+ const optionalBuiltins = [];
488
+ if (options.forceLong === options_1.LongOption.BIGINT) {
489
+ optionalBuiltins.push("bigint");
490
+ }
491
+ if (options.useDate === options_1.DateOption.TEMPORAL) {
492
+ optionalBuiltins.push("Temporal.Instant");
493
+ }
494
+ const Builtin = (0, ts_poet_1.conditionalOutput)("Builtin", (0, ts_poet_1.code) `type Builtin = Date | Function | Uint8Array | string | number | boolean ${optionalBuiltins.length ? `| ${optionalBuiltins.join(" | ")} ` : ""}| undefined;`);
488
495
  // Based on https://github.com/sindresorhus/type-fest/pull/259
489
496
  const maybeExcludeType = (0, options_1.addTypeToMessages)(options) ? `| '$type'` : "";
490
497
  const Exact = (0, ts_poet_1.conditionalOutput)("Exact", (0, ts_poet_1.code) `
@@ -696,7 +703,20 @@ function makeTimestampMethods(options, longs, bytes) {
696
703
  return { ${maybeTypeField} seconds, nanos };
697
704
  }
698
705
  `
699
- : (0, ts_poet_1.code) `
706
+ : options.useDate === options_1.DateOption.TEMPORAL
707
+ ? (0, ts_poet_1.code) `
708
+ function toTimestamp(instant: Temporal.Instant): ${Timestamp} {
709
+ const date = {
710
+ getTime: (): number => instant.epochMilliseconds,
711
+ } as const;
712
+ const seconds = ${seconds};
713
+ const remainder = instant.round({ smallestUnit: "seconds", roundingMode: "floor" }).until(instant);
714
+ const nanos = (remainder.milliseconds * 1_000_000) + (remainder.microseconds * 1_000) + remainder.nanoseconds;
715
+
716
+ return { ${maybeTypeField} seconds, nanos };
717
+ }
718
+ `
719
+ : (0, ts_poet_1.code) `
700
720
  function toTimestamp(date: Date): ${Timestamp} {
701
721
  const seconds = ${seconds};
702
722
  const nanos = (date.getTime() % 1_000) * 1_000_000;
@@ -727,7 +747,16 @@ function makeTimestampMethods(options, longs, bytes) {
727
747
  return nanoDate.toISOStringFull();
728
748
  }
729
749
  `
730
- : (0, ts_poet_1.code) `
750
+ : options.useDate === options_1.DateOption.TEMPORAL
751
+ ? (0, ts_poet_1.code) `
752
+ function fromTimestamp(t: ${Timestamp}): Temporal.Instant {
753
+ const seconds = ${toNumberCode} || 0;
754
+ return ${bytes.globalThis}.Temporal.Instant
755
+ .fromEpochMilliseconds(seconds * 1_000)
756
+ .add(${bytes.globalThis}.Temporal.Duration.from({ nanoseconds: t.nanos }));
757
+ }
758
+ `
759
+ : (0, ts_poet_1.code) `
731
760
  function fromTimestamp(t: ${Timestamp}): Date {
732
761
  let millis = (${toNumberCode} || 0) * 1_000;
733
762
  millis += (t.nanos || 0) / 1_000_000;
@@ -746,7 +775,19 @@ function makeTimestampMethods(options, longs, bytes) {
746
775
  }
747
776
  }
748
777
  `
749
- : (0, ts_poet_1.code) `
778
+ : options.useDate === options_1.DateOption.TEMPORAL
779
+ ? (0, ts_poet_1.code) `
780
+ function fromJsonTimestamp(o: any): Temporal.Instant {
781
+ if (o instanceof ${bytes.globalThis}.Date) {
782
+ return ${bytes.globalThis}.Temporal.Instant.fromEpochMilliseconds(o.getTime());
783
+ } else if (typeof o === "string") {
784
+ return ${bytes.globalThis}.Temporal.Instant.from(o);
785
+ } else {
786
+ return ${fromTimestamp}(${(0, utils_1.wrapTypeName)(options, "Timestamp")}.fromJSON(o));
787
+ }
788
+ }
789
+ `
790
+ : (0, ts_poet_1.code) `
750
791
  function fromJsonTimestamp(o: any): ${(0, utils_1.wrapTypeName)(options, "Timestamp")} {
751
792
  if (o instanceof ${bytes.globalThis}.Date) {
752
793
  return ${toTimestamp}(o);
@@ -987,7 +1028,8 @@ function getDecodeReadSnippet(ctx, field) {
987
1028
  else if ((0, types_1.isTimestamp)(field) &&
988
1029
  (options.useDate === options_1.DateOption.DATE ||
989
1030
  options.useDate === options_1.DateOption.STRING ||
990
- options.useDate === options_1.DateOption.STRING_NANO)) {
1031
+ options.useDate === options_1.DateOption.STRING_NANO ||
1032
+ options.useDate === options_1.DateOption.TEMPORAL)) {
991
1033
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
992
1034
  readSnippet = (0, ts_poet_1.code) `${utils.fromTimestamp}(${type}.decode(reader, reader.uint32()))`;
993
1035
  }
@@ -1249,7 +1291,8 @@ function getEncodeWriteSnippet(ctx, field) {
1249
1291
  else if ((0, types_1.isTimestamp)(field) &&
1250
1292
  (options.useDate === options_1.DateOption.DATE ||
1251
1293
  options.useDate === options_1.DateOption.STRING ||
1252
- options.useDate === options_1.DateOption.STRING_NANO)) {
1294
+ options.useDate === options_1.DateOption.STRING_NANO ||
1295
+ options.useDate === options_1.DateOption.TEMPORAL)) {
1253
1296
  const tag = ((field.number << 3) | 2) >>> 0;
1254
1297
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1255
1298
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.uint32(${tag}).fork()).join()`;
@@ -1616,7 +1659,8 @@ function generateExtension(ctx, message, extension) {
1616
1659
  else if ((0, types_1.isTimestamp)(field) &&
1617
1660
  (options.useDate === options_1.DateOption.DATE ||
1618
1661
  options.useDate === options_1.DateOption.STRING ||
1619
- options.useDate === options_1.DateOption.STRING_NANO)) {
1662
+ options.useDate === options_1.DateOption.STRING_NANO ||
1663
+ options.useDate === options_1.DateOption.TEMPORAL)) {
1620
1664
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1621
1665
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.fork()).join()`;
1622
1666
  }
@@ -1827,7 +1871,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1827
1871
  return (0, ts_poet_1.code) `${utils.globalThis}.String(${from})`;
1828
1872
  }
1829
1873
  else if ((0, types_1.isTimestamp)(field) &&
1830
- (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.TIMESTAMP)) {
1874
+ (options.useDate === options_1.DateOption.DATE ||
1875
+ options.useDate === options_1.DateOption.TEMPORAL ||
1876
+ options.useDate === options_1.DateOption.TIMESTAMP)) {
1831
1877
  return (0, ts_poet_1.code) `${utils.fromJsonTimestamp}(${from})`;
1832
1878
  }
1833
1879
  else if ((0, types_1.isAnyValueType)(field) || (0, types_1.isStructType)(field)) {
@@ -1891,7 +1937,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1891
1937
  return (0, ts_poet_1.code) `${utils.globalThis}.String(${from})`;
1892
1938
  }
1893
1939
  else if ((0, types_1.isTimestamp)(valueField) &&
1894
- (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.TIMESTAMP)) {
1940
+ (options.useDate === options_1.DateOption.DATE ||
1941
+ options.useDate === options_1.DateOption.TEMPORAL ||
1942
+ options.useDate === options_1.DateOption.TIMESTAMP)) {
1895
1943
  return (0, ts_poet_1.code) `${utils.fromJsonTimestamp}(${from})`;
1896
1944
  }
1897
1945
  else if ((0, types_1.isValueType)(ctx, valueField)) {
@@ -2060,6 +2108,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2060
2108
  else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.DATE) {
2061
2109
  return (0, ts_poet_1.code) `${from}.toISOString()`;
2062
2110
  }
2111
+ else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.TEMPORAL) {
2112
+ return (0, ts_poet_1.code) `${from}.toString()`;
2113
+ }
2063
2114
  else if ((0, types_1.isTimestamp)(field) &&
2064
2115
  (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
2065
2116
  return (0, ts_poet_1.code) `${from}`;
@@ -2086,6 +2137,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2086
2137
  else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.DATE) {
2087
2138
  return (0, ts_poet_1.code) `${from}.toISOString()`;
2088
2139
  }
2140
+ else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.TEMPORAL) {
2141
+ return (0, ts_poet_1.code) `${from}.toString()`;
2142
+ }
2089
2143
  else if ((0, types_1.isTimestamp)(valueType) &&
2090
2144
  (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
2091
2145
  return (0, ts_poet_1.code) `${from}`;
@@ -2273,7 +2327,8 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2273
2327
  ((0, types_1.isTimestamp)(field) &&
2274
2328
  (options.useDate === options_1.DateOption.DATE ||
2275
2329
  options.useDate === options_1.DateOption.STRING ||
2276
- options.useDate === options_1.DateOption.STRING_NANO)) ||
2330
+ options.useDate === options_1.DateOption.STRING_NANO ||
2331
+ options.useDate === options_1.DateOption.TEMPORAL)) ||
2277
2332
  (0, types_1.isValueType)(ctx, field)) {
2278
2333
  return (0, ts_poet_1.code) `${from}`;
2279
2334
  }
@@ -2307,7 +2362,8 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2307
2362
  else if ((0, types_1.isTimestamp)(valueField) &&
2308
2363
  (options.useDate === options_1.DateOption.DATE ||
2309
2364
  options.useDate === options_1.DateOption.STRING ||
2310
- options.useDate === options_1.DateOption.STRING_NANO)) {
2365
+ options.useDate === options_1.DateOption.STRING_NANO ||
2366
+ options.useDate === options_1.DateOption.TEMPORAL)) {
2311
2367
  return (0, ts_poet_1.code) `${from}`;
2312
2368
  }
2313
2369
  else if ((0, types_1.isValueType)(ctx, valueField)) {
@@ -9,6 +9,7 @@ export declare enum DateOption {
9
9
  DATE = "date",
10
10
  STRING = "string",
11
11
  STRING_NANO = "string-nano",
12
+ TEMPORAL = "temporal",
12
13
  TIMESTAMP = "timestamp"
13
14
  }
14
15
  export declare enum JsonTimestampOption {
@@ -17,6 +17,7 @@ var DateOption;
17
17
  DateOption["DATE"] = "date";
18
18
  DateOption["STRING"] = "string";
19
19
  DateOption["STRING_NANO"] = "string-nano";
20
+ DateOption["TEMPORAL"] = "temporal";
20
21
  DateOption["TIMESTAMP"] = "timestamp";
21
22
  })(DateOption || (exports.DateOption = DateOption = {}));
22
23
  var JsonTimestampOption;
@@ -616,6 +616,9 @@ function messageToTypeName(ctx, protoType, typeOptions = {}) {
616
616
  if (options.useDate == options_1.DateOption.DATE) {
617
617
  return (0, ts_poet_1.code) `Date`;
618
618
  }
619
+ if (options.useDate === options_1.DateOption.TEMPORAL) {
620
+ return (0, ts_poet_1.code) `Temporal.Instant`;
621
+ }
619
622
  if (options.useDate == options_1.DateOption.STRING || options.useDate == options_1.DateOption.STRING_NANO) {
620
623
  return (0, ts_poet_1.code) `string`;
621
624
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "2.7.7",
3
+ "version": "2.8.1",
4
4
  "description": "",
5
5
  "main": "build/src/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",
@@ -61,6 +61,8 @@
61
61
  "reflect-metadata": "^0.1.13",
62
62
  "rxjs": "^7.8.1",
63
63
  "semantic-release": "^24.0.0",
64
+ "temporal-polyfill": "^0.3.0",
65
+ "temporal-spec": "^0.3.0",
64
66
  "ts-jest": "^29.3.4",
65
67
  "tsx": "^4.19.4",
66
68
  "typescript": "^5.8.3",