ts-proto 2.15.0 → 2.15.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.
@@ -42,6 +42,9 @@ declare function makeTimestampMethods(options: Options, longs: ReturnType<typeof
42
42
  fromTimestamp: ConditionalOutput;
43
43
  timestampFractionRegex: ConditionalOutput;
44
44
  fromJsonTimestamp: ConditionalOutput;
45
+ timestampJsonRegex: ConditionalOutput;
46
+ timestampFromJson: ConditionalOutput;
47
+ timestampToJson: ConditionalOutput;
45
48
  };
46
49
  declare function makeAnyJsonUtils(): {
47
50
  anyJsonValueTypes: ConditionalOutput;
package/build/src/main.js CHANGED
@@ -829,7 +829,43 @@ function makeTimestampMethods(options, longs, bytes) {
829
829
  }
830
830
  }
831
831
  `);
832
- return { toTimestamp, fromTimestamp, timestampFractionRegex, fromJsonTimestamp };
832
+ // Declared once per file, so the regex isn't compiled on each timestampFromJson call
833
+ const timestampJsonRegex = (0, ts_poet_1.conditionalOutput)("timestampJsonRegex", (0, ts_poet_1.code) `const timestampJsonRegex = /^.+T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/;`);
834
+ // Parses the canonical JSON of a Timestamp, an RFC 3339 string
835
+ const timestampFromJson = (0, ts_poet_1.conditionalOutput)("timestampFromJson", (0, ts_poet_1.code) `
836
+ function timestampFromJson(value: string): { seconds: number; nanos: number } {
837
+ const match = ${timestampJsonRegex}.exec(value);
838
+ // Date only keeps milliseconds, so it parses the string without the fractional seconds
839
+ const fraction = match?.[1];
840
+ const millis = match
841
+ ? new ${bytes.globalThis}.Date(fraction === undefined ? value : value.replace(fraction, "")).getTime()
842
+ : NaN;
843
+ if (!match || ${bytes.globalThis}.Number.isNaN(millis)) {
844
+ throw new ${bytes.globalThis}.Error(\`Invalid timestamp: \${value}\`);
845
+ }
846
+ const nanos = fraction === undefined ? 0 : ${bytes.globalThis}.Number(fraction.slice(1, 10).padEnd(9, "0"));
847
+ return { seconds: millis / 1_000, nanos };
848
+ }
849
+ `);
850
+ // Writes the canonical JSON of a Timestamp, an RFC 3339 string
851
+ const timestampToJson = (0, ts_poet_1.conditionalOutput)("timestampToJson", (0, ts_poet_1.code) `
852
+ function timestampToJson(seconds: number, nanos: number): string {
853
+ const date = new ${bytes.globalThis}.Date(seconds * 1_000).toISOString().slice(0, 19);
854
+ if (nanos === 0) return \`\${date}Z\`;
855
+ const padded = nanos.toString().padStart(9, "0");
856
+ const len = nanos % 1_000_000 === 0 ? 3 : nanos % 1_000 === 0 ? 6 : 9;
857
+ return \`\${date}.\${padded.slice(0, len)}Z\`;
858
+ }
859
+ `);
860
+ return {
861
+ toTimestamp,
862
+ fromTimestamp,
863
+ timestampFractionRegex,
864
+ fromJsonTimestamp,
865
+ timestampJsonRegex,
866
+ timestampFromJson,
867
+ timestampToJson,
868
+ };
833
869
  }
834
870
  function makeAnyJsonUtils() {
835
871
  // Well-known types whose JSON is not an object of their fields. Packed in an Any, that
@@ -1905,10 +1941,22 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1905
1941
  `;
1906
1942
  }
1907
1943
  // create the basic function declaration
1908
- chunks.push((0, ts_poet_1.code) `
1909
- fromJSON(${messageDesc.field.length > 0 ? "object" : "_"}: any): ${fullName} {
1910
- return {
1911
- `);
1944
+ if (fullTypeName === "google.protobuf.Timestamp") {
1945
+ // The canonical JSON of a Timestamp is an RFC 3339 string; the object form is still accepted.
1946
+ chunks.push((0, ts_poet_1.code) `
1947
+ fromJSON(object: any): ${fullName} {
1948
+ if (typeof object === "string") {
1949
+ return ${fullName}.fromJSON(${utils.timestampFromJson}(object));
1950
+ }
1951
+ return {
1952
+ `);
1953
+ }
1954
+ else {
1955
+ chunks.push((0, ts_poet_1.code) `
1956
+ fromJSON(${messageDesc.field.length > 0 ? "object" : "_"}: any): ${fullName} {
1957
+ return {
1958
+ `);
1959
+ }
1912
1960
  if ((0, options_1.addTypeToMessages)(options)) {
1913
1961
  chunks.push((0, ts_poet_1.code) `$type: ${fullName}.$type,`);
1914
1962
  }
@@ -2223,7 +2271,7 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2223
2271
  chunks.push((0, ts_poet_1.code) `}`);
2224
2272
  return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
2225
2273
  }
2226
- function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals, useNullAsOptional, useDuration, forceLong }) {
2274
+ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals, useNullAsOptional, useDuration, useJsonTimestamp, forceLong }, utils) {
2227
2275
  if ((0, types_1.isFieldMaskTypeName)(fullProtobufTypeName)) {
2228
2276
  const returnType = useOptionals === "all" ? `string | ${(0, utils_1.nullOrUndefined)({ useNullAsOptional })}` : "string";
2229
2277
  const pathModifier = useOptionals === "all" ? "?" : "";
@@ -2269,6 +2317,16 @@ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals,
2269
2317
  }
2270
2318
  `;
2271
2319
  }
2320
+ if (fullProtobufTypeName === "google.protobuf.Timestamp" && useJsonTimestamp === options_1.JsonTimestampOption.RFC3339) {
2321
+ const seconds = forceLong === options_1.LongOption.LONG
2322
+ ? (0, ts_poet_1.code) `message.seconds?.toNumber() ?? 0`
2323
+ : (0, ts_poet_1.code) `${utils.globalThis}.Number(message.seconds ?? 0)`;
2324
+ return (0, ts_poet_1.code) `
2325
+ toJSON(message: ${fullName}): string {
2326
+ return ${utils.timestampToJson}(${seconds}, message.nanos ?? 0);
2327
+ }
2328
+ `;
2329
+ }
2272
2330
  return undefined;
2273
2331
  }
2274
2332
  /** Whether `google.protobuf.Any` gets its canonical `@type` JSON form, see the `anyType` option. */
@@ -2348,7 +2406,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2348
2406
  chunks.push(generateCanonicalAnyToJson(ctx, fullName, messageDesc));
2349
2407
  return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
2350
2408
  }
2351
- const canonicalToJson = generateCanonicalToJson(fullName, fullProtobufTypeName, options);
2409
+ const canonicalToJson = generateCanonicalToJson(fullName, fullProtobufTypeName, options, utils);
2352
2410
  if (canonicalToJson) {
2353
2411
  chunks.push(canonicalToJson);
2354
2412
  return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "2.15.0",
3
+ "version": "2.15.1",
4
4
  "description": "",
5
5
  "main": "build/src/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",