@gulujs/toml
Version:
TOML parser and serializer
120 lines (119 loc) • 4.28 kB
JavaScript
export var DateTimeType;
(function (DateTimeType) {
DateTimeType["OffsetDateTime"] = "OffsetDateTime";
DateTimeType["LocalDateTime"] = "LocalDateTime";
DateTimeType["LocalDate"] = "LocalDate";
DateTimeType["LocalTime"] = "LocalTime";
})(DateTimeType || (DateTimeType = {}));
const KEY_TYPE = Symbol('KEY_TYPE');
const KEY_UTC_OFFSET = Symbol('KEY_UTC_OFFSET');
const RE_MATCH_UTC_OFFSET = /(?:[zZ]|(?:[-+]\d\d:\d\d))$/;
const RE_EXTRACT_OFFSET_PARTS = /([+-])(\d\d):?(\d\d)?/;
export class TomlDate extends Date {
get type() {
return this[KEY_TYPE];
}
get utcOffset() {
return this[KEY_UTC_OFFSET];
}
get isValid() {
return !Number.isNaN(this.getTime());
}
constructor(value) {
super(value);
this[KEY_TYPE] = DateTimeType.LocalDateTime;
this[KEY_UTC_OFFSET] = this.getTimezoneOffset() * -1;
}
static ofOffsetDateTime(value, utcOffset) {
const date = new TomlDate(value);
date[KEY_TYPE] = DateTimeType.OffsetDateTime;
if (typeof utcOffset === 'undefined' && typeof value === 'string') {
const m = value.match(RE_MATCH_UTC_OFFSET);
if (m) {
if (m[0] === 'z' || m[0] === 'Z') {
utcOffset = 0;
}
else {
utcOffset = m[0];
}
}
}
const offset = typeof utcOffset === 'string' ? offsetFromString(utcOffset) : utcOffset;
if (typeof offset === 'number') {
date[KEY_UTC_OFFSET] = Math.abs(offset) <= 16 ? offset * 60 : offset;
}
return date;
}
static ofLocalDateTime(value) {
const date = new TomlDate(value);
date[KEY_TYPE] = DateTimeType.LocalDateTime;
return date;
}
static ofLocalDate(value) {
const date = new TomlDate(value);
date[KEY_TYPE] = DateTimeType.LocalDate;
return date;
}
static ofLocalTime(value) {
if (typeof value === 'string') {
value = `1970-01-01T${value}`;
}
const date = new TomlDate(value);
date[KEY_TYPE] = DateTimeType.LocalTime;
return date;
}
toString() {
switch (this.type) {
case DateTimeType.OffsetDateTime:
return this.toOffsetDateTimeString();
case DateTimeType.LocalDateTime:
return this.toLocalDateTimeString();
case DateTimeType.LocalDate:
return this.toLocalDateString();
case DateTimeType.LocalTime:
return this.toLocalTimeString();
default:
throw new RangeError('The `type` must be a valid value for `DateTimeType`');
}
}
toOffsetDateTimeString() {
return new Date(this.getTime() + (this.utcOffset * 60 * 1000)).toISOString().replace(/Z$/, padZoneStr(this.utcOffset));
}
toLocalDateTimeString() {
return `${this.toLocalDateString()}T${this.toLocalTimeString()}`;
}
toLocalDateString() {
return `${padStart(this.getFullYear(), 4, '0')}-${padStart(this.getMonth() + 1, 2, '0')}-${padStart(this.getDate(), 2, '0')}`;
}
toLocalTimeString() {
return `${padStart(this.getHours(), 2, '0')}:${padStart(this.getMinutes(), 2, '0')}:${padStart(this.getSeconds(), 2, '0')}.${padStart(this.getMilliseconds(), 3, '0')}`;
}
}
function padStart(str, len, pad) {
const s = String(str);
if (s.length >= len) {
return s;
}
return `${Array((len + 1) - s.length).join(pad)}${str}`;
}
function padZoneStr(offset) {
if (offset === 0) {
return 'Z';
}
const negMinutes = -offset;
const minutes = Math.abs(negMinutes);
const hourOffset = Math.floor(minutes / 60);
const minuteOffset = minutes % 60;
return `${negMinutes <= 0 ? '+' : '-'}${padStart(hourOffset, 2, '0')}:${padStart(minuteOffset, 2, '0')}`;
}
function offsetFromString(value) {
const m = value.match(RE_EXTRACT_OFFSET_PARTS);
if (!m) {
return null;
}
const totalOffsetInMinutes = (Number(m[2]) * 60) + Number(m[3] || 0);
if (totalOffsetInMinutes === 0) {
return 0;
}
return m[1] === '-' ? -totalOffsetInMinutes : totalOffsetInMinutes;
}