All files / yaml / _type / timestamp.ts

94.12% Branches 16/17
95.65% Lines 66/69
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
 
 
 
 
 
 
 
x15
x15
x15
x15
 
 
x15
x15
x15
x15
x15
x15
x15
x15
x15
x15
x15
 
 
x492
x492
x492
x492
x958
x492
 
x25
x25
x25
 
 
 
 
 
 
 
x25
x25
x25
 
x25
 
x30
x30
 
 
 
x30
x30
x30
 
x30
x30
x30
x30
 
x36
x36
x30
x30
 
 
 
x30
x25
x29
x29
x29
x29
x29
 
x30
x30
 
 
x25
 
x30
x25
 
x16
x16
x16
 
x15
x15
x15
x15
x393
x15
x15
x15
x15
x15




































I






























































// Ported from js-yaml v3.13.1:
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
// Copyright 2018-2025 the Deno authors. MIT license.

import type { Type } from "../_type.ts";

const YAML_DATE_REGEXP = new RegExp(
  "^([0-9][0-9][0-9][0-9])" + // [1] year
    "-([0-9][0-9])" + // [2] month
    "-([0-9][0-9])$", // [3] day
);

const YAML_TIMESTAMP_REGEXP = new RegExp(
  "^([0-9][0-9][0-9][0-9])" + // [1] year
    "-([0-9][0-9]?)" + // [2] month
    "-([0-9][0-9]?)" + // [3] day
    "(?:[Tt]|[ \\t]+)" + // ...
    "([0-9][0-9]?)" + // [4] hour
    ":([0-9][0-9])" + // [5] minute
    ":([0-9][0-9])" + // [6] second
    "(?:\\.([0-9]*))?" + // [7] fraction
    "(?:[ \\t]*(Z|([-+])([0-9][0-9]?)" + // [8] tz [9] tz_sign [10] tz_hour
    "(?::([0-9][0-9]))?))?$", // [11] tz_minute
);

function resolveYamlTimestamp(data: string): boolean {
  if (data === null) return false;
  if (YAML_DATE_REGEXP.exec(data) !== null) return true;
  if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true;
  return false;
}

function constructYamlTimestamp(data: string): Date {
  let match = YAML_DATE_REGEXP.exec(data);
  if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data);

  if (match === null) {
    throw new Error("Cannot construct YAML timestamp: date resolve error");
  }

  // match: [1] year [2] month [3] day

  const year = +match[1]!;
  const month = +match[2]! - 1; // JS month starts with 0
  const day = +match[3]!;

  if (!match[4]) {
    // no hour
    return new Date(Date.UTC(year, month, day));
  }

  // match: [4] hour [5] minute [6] second [7] fraction

  const hour = +match[4];
  const minute = +match[5]!;
  const second = +match[6]!;

  let fraction = 0;
  if (match[7]) {
    let partFraction = match[7].slice(0, 3);
    while (partFraction.length < 3) {
      // milli-seconds
      partFraction += "0";
    }
    fraction = +partFraction;
  }

  // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute

  let delta = null;
  if (match[9] && match[10]) {
    const tzHour = +match[10];
    const tzMinute = +(match[11] || 0);
    delta = (tzHour * 60 + tzMinute) * 60000; // delta in milli-seconds
    if (match[9] === "-") delta = -delta;
  }

  const date = new Date(
    Date.UTC(year, month, day, hour, minute, second, fraction),
  );

  if (delta) date.setTime(date.getTime() - delta);

  return date;
}

function representYamlTimestamp(date: Date): string {
  return date.toISOString();
}

export const timestamp: Type<"scalar", Date> = {
  tag: "tag:yaml.org,2002:timestamp",
  construct: constructYamlTimestamp,
  predicate(object): object is Date {
    return object instanceof Date;
  },
  kind: "scalar",
  represent: representYamlTimestamp,
  resolve: resolveYamlTimestamp,
};