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
 
 
 
 
 
 
 
x16
x16
x16
x16
 
 
x16
x16
x16
x16
x16
x16
x16
x16
x16
x16
x16
 
 
x498
x498
x498
x498
x969
x498
 
x26
x26
x26
 
 
 
 
 
 
 
x26
x26
x26
 
x26
 
x31
x31
 
 
 
x31
x31
x31
 
x31
x31
x31
x31
 
x37
x37
x31
x31
 
 
 
x31
x26
x30
x30
x30
x30
x30
 
x31
x31
 
 
x26
 
x31
x26
 
x17
x17
x17
 
x16
x16
x16
x16
x405
x16
x16
x16
x16
x16




































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,
};