All files / yaml / _type / timestamp.ts

95.65% Branches 22/23
100.00% Functions 4/4
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
 
 
 
 
 
 
 
x18
x18
x18
x18
 
 
x18
x18
x18
x18
x18
x18
x18
x18
x18
x18
x18
 
 
x504
x504
x504
x504
x493
x504
 
x10
x10
x10
 
 
 
 
 
 
 
x10
x10
x10
 
x10
 
x5
x5
 
 
 
x5
x5
x5
 
x5
x5
x5
x5
 
x6
x6
x5
x5
 
 
 
x5
x10
x4
x4
x4
x4
x4
 
x5
x5
 
 
x10
 
x5
x10
 
x1
x1
x1
 
x18
x18
x18
x18
x394
x18
x18
x18
x18
x18




































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