ts-proto 2.7.7 → 2.8.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/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,22 @@ 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 => Math.trunc(instant.epochMilliseconds / 1_000),
711
+ } as const;
712
+ const seconds = ${seconds};
713
+ const remainder = ${bytes.globalThis}.Temporal.Instant
714
+ .fromEpochMilliseconds(instant.epochMilliseconds)
715
+ .until(instant);
716
+ const nanos = (remainder.milliseconds * 1_000_000) + (remainder.microseconds * 1_000) + remainder.nanoseconds;
717
+
718
+ return { ${maybeTypeField} seconds, nanos };
719
+ }
720
+ `
721
+ : (0, ts_poet_1.code) `
700
722
  function toTimestamp(date: Date): ${Timestamp} {
701
723
  const seconds = ${seconds};
702
724
  const nanos = (date.getTime() % 1_000) * 1_000_000;
@@ -727,7 +749,16 @@ function makeTimestampMethods(options, longs, bytes) {
727
749
  return nanoDate.toISOStringFull();
728
750
  }
729
751
  `
730
- : (0, ts_poet_1.code) `
752
+ : options.useDate === options_1.DateOption.TEMPORAL
753
+ ? (0, ts_poet_1.code) `
754
+ function fromTimestamp(t: ${Timestamp}): Temporal.Instant {
755
+ const seconds = ${toNumberCode} || 0;
756
+ return ${bytes.globalThis}.Temporal.Instant
757
+ .fromEpochMilliseconds(seconds * 1_000)
758
+ .add(${bytes.globalThis}.Temporal.Duration.from({ nanoseconds: t.nanos }));
759
+ }
760
+ `
761
+ : (0, ts_poet_1.code) `
731
762
  function fromTimestamp(t: ${Timestamp}): Date {
732
763
  let millis = (${toNumberCode} || 0) * 1_000;
733
764
  millis += (t.nanos || 0) / 1_000_000;
@@ -746,7 +777,19 @@ function makeTimestampMethods(options, longs, bytes) {
746
777
  }
747
778
  }
748
779
  `
749
- : (0, ts_poet_1.code) `
780
+ : options.useDate === options_1.DateOption.TEMPORAL
781
+ ? (0, ts_poet_1.code) `
782
+ function fromJsonTimestamp(o: any): Temporal.Instant {
783
+ if (o instanceof ${bytes.globalThis}.Date) {
784
+ return ${bytes.globalThis}.Temporal.Instant.fromEpochMilliseconds(o.getTime());
785
+ } else if (typeof o === "string") {
786
+ return ${bytes.globalThis}.Temporal.Instant.from(o);
787
+ } else {
788
+ return ${fromTimestamp}(${(0, utils_1.wrapTypeName)(options, "Timestamp")}.fromJSON(o));
789
+ }
790
+ }
791
+ `
792
+ : (0, ts_poet_1.code) `
750
793
  function fromJsonTimestamp(o: any): ${(0, utils_1.wrapTypeName)(options, "Timestamp")} {
751
794
  if (o instanceof ${bytes.globalThis}.Date) {
752
795
  return ${toTimestamp}(o);
@@ -987,7 +1030,8 @@ function getDecodeReadSnippet(ctx, field) {
987
1030
  else if ((0, types_1.isTimestamp)(field) &&
988
1031
  (options.useDate === options_1.DateOption.DATE ||
989
1032
  options.useDate === options_1.DateOption.STRING ||
990
- options.useDate === options_1.DateOption.STRING_NANO)) {
1033
+ options.useDate === options_1.DateOption.STRING_NANO ||
1034
+ options.useDate === options_1.DateOption.TEMPORAL)) {
991
1035
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
992
1036
  readSnippet = (0, ts_poet_1.code) `${utils.fromTimestamp}(${type}.decode(reader, reader.uint32()))`;
993
1037
  }
@@ -1249,7 +1293,8 @@ function getEncodeWriteSnippet(ctx, field) {
1249
1293
  else if ((0, types_1.isTimestamp)(field) &&
1250
1294
  (options.useDate === options_1.DateOption.DATE ||
1251
1295
  options.useDate === options_1.DateOption.STRING ||
1252
- options.useDate === options_1.DateOption.STRING_NANO)) {
1296
+ options.useDate === options_1.DateOption.STRING_NANO ||
1297
+ options.useDate === options_1.DateOption.TEMPORAL)) {
1253
1298
  const tag = ((field.number << 3) | 2) >>> 0;
1254
1299
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1255
1300
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.uint32(${tag}).fork()).join()`;
@@ -1616,7 +1661,8 @@ function generateExtension(ctx, message, extension) {
1616
1661
  else if ((0, types_1.isTimestamp)(field) &&
1617
1662
  (options.useDate === options_1.DateOption.DATE ||
1618
1663
  options.useDate === options_1.DateOption.STRING ||
1619
- options.useDate === options_1.DateOption.STRING_NANO)) {
1664
+ options.useDate === options_1.DateOption.STRING_NANO ||
1665
+ options.useDate === options_1.DateOption.TEMPORAL)) {
1620
1666
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1621
1667
  return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.fork()).join()`;
1622
1668
  }
@@ -1827,7 +1873,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1827
1873
  return (0, ts_poet_1.code) `${utils.globalThis}.String(${from})`;
1828
1874
  }
1829
1875
  else if ((0, types_1.isTimestamp)(field) &&
1830
- (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.TIMESTAMP)) {
1876
+ (options.useDate === options_1.DateOption.DATE ||
1877
+ options.useDate === options_1.DateOption.TEMPORAL ||
1878
+ options.useDate === options_1.DateOption.TIMESTAMP)) {
1831
1879
  return (0, ts_poet_1.code) `${utils.fromJsonTimestamp}(${from})`;
1832
1880
  }
1833
1881
  else if ((0, types_1.isAnyValueType)(field) || (0, types_1.isStructType)(field)) {
@@ -1891,7 +1939,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1891
1939
  return (0, ts_poet_1.code) `${utils.globalThis}.String(${from})`;
1892
1940
  }
1893
1941
  else if ((0, types_1.isTimestamp)(valueField) &&
1894
- (options.useDate === options_1.DateOption.DATE || options.useDate === options_1.DateOption.TIMESTAMP)) {
1942
+ (options.useDate === options_1.DateOption.DATE ||
1943
+ options.useDate === options_1.DateOption.TEMPORAL ||
1944
+ options.useDate === options_1.DateOption.TIMESTAMP)) {
1895
1945
  return (0, ts_poet_1.code) `${utils.fromJsonTimestamp}(${from})`;
1896
1946
  }
1897
1947
  else if ((0, types_1.isValueType)(ctx, valueField)) {
@@ -2060,6 +2110,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2060
2110
  else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.DATE) {
2061
2111
  return (0, ts_poet_1.code) `${from}.toISOString()`;
2062
2112
  }
2113
+ else if ((0, types_1.isTimestamp)(field) && options.useDate === options_1.DateOption.TEMPORAL) {
2114
+ return (0, ts_poet_1.code) `${from}.toString()`;
2115
+ }
2063
2116
  else if ((0, types_1.isTimestamp)(field) &&
2064
2117
  (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
2065
2118
  return (0, ts_poet_1.code) `${from}`;
@@ -2086,6 +2139,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2086
2139
  else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.DATE) {
2087
2140
  return (0, ts_poet_1.code) `${from}.toISOString()`;
2088
2141
  }
2142
+ else if ((0, types_1.isTimestamp)(valueType) && options.useDate === options_1.DateOption.TEMPORAL) {
2143
+ return (0, ts_poet_1.code) `${from}.toString()`;
2144
+ }
2089
2145
  else if ((0, types_1.isTimestamp)(valueType) &&
2090
2146
  (options.useDate === options_1.DateOption.STRING || options.useDate === options_1.DateOption.STRING_NANO)) {
2091
2147
  return (0, ts_poet_1.code) `${from}`;
@@ -2273,7 +2329,8 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2273
2329
  ((0, types_1.isTimestamp)(field) &&
2274
2330
  (options.useDate === options_1.DateOption.DATE ||
2275
2331
  options.useDate === options_1.DateOption.STRING ||
2276
- options.useDate === options_1.DateOption.STRING_NANO)) ||
2332
+ options.useDate === options_1.DateOption.STRING_NANO ||
2333
+ options.useDate === options_1.DateOption.TEMPORAL)) ||
2277
2334
  (0, types_1.isValueType)(ctx, field)) {
2278
2335
  return (0, ts_poet_1.code) `${from}`;
2279
2336
  }
@@ -2307,7 +2364,8 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2307
2364
  else if ((0, types_1.isTimestamp)(valueField) &&
2308
2365
  (options.useDate === options_1.DateOption.DATE ||
2309
2366
  options.useDate === options_1.DateOption.STRING ||
2310
- options.useDate === options_1.DateOption.STRING_NANO)) {
2367
+ options.useDate === options_1.DateOption.STRING_NANO ||
2368
+ options.useDate === options_1.DateOption.TEMPORAL)) {
2311
2369
  return (0, ts_poet_1.code) `${from}`;
2312
2370
  }
2313
2371
  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.0",
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",