Initial commit: 11ty website with Fire/Frost branding
This commit is contained in:
206
node_modules/luxon/src/impl/conversions.js
generated
vendored
Normal file
206
node_modules/luxon/src/impl/conversions.js
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
import {
|
||||
integerBetween,
|
||||
isLeapYear,
|
||||
timeObject,
|
||||
daysInYear,
|
||||
daysInMonth,
|
||||
weeksInWeekYear,
|
||||
isInteger,
|
||||
isUndefined,
|
||||
} from "./util.js";
|
||||
import Invalid from "./invalid.js";
|
||||
import { ConflictingSpecificationError } from "../errors.js";
|
||||
|
||||
const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
|
||||
leapLadder = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
|
||||
|
||||
function unitOutOfRange(unit, value) {
|
||||
return new Invalid(
|
||||
"unit out of range",
|
||||
`you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid`
|
||||
);
|
||||
}
|
||||
|
||||
export function dayOfWeek(year, month, day) {
|
||||
const d = new Date(Date.UTC(year, month - 1, day));
|
||||
|
||||
if (year < 100 && year >= 0) {
|
||||
d.setUTCFullYear(d.getUTCFullYear() - 1900);
|
||||
}
|
||||
|
||||
const js = d.getUTCDay();
|
||||
|
||||
return js === 0 ? 7 : js;
|
||||
}
|
||||
|
||||
function computeOrdinal(year, month, day) {
|
||||
return day + (isLeapYear(year) ? leapLadder : nonLeapLadder)[month - 1];
|
||||
}
|
||||
|
||||
function uncomputeOrdinal(year, ordinal) {
|
||||
const table = isLeapYear(year) ? leapLadder : nonLeapLadder,
|
||||
month0 = table.findIndex((i) => i < ordinal),
|
||||
day = ordinal - table[month0];
|
||||
return { month: month0 + 1, day };
|
||||
}
|
||||
|
||||
export function isoWeekdayToLocal(isoWeekday, startOfWeek) {
|
||||
return ((isoWeekday - startOfWeek + 7) % 7) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
export function gregorianToWeek(gregObj, minDaysInFirstWeek = 4, startOfWeek = 1) {
|
||||
const { year, month, day } = gregObj,
|
||||
ordinal = computeOrdinal(year, month, day),
|
||||
weekday = isoWeekdayToLocal(dayOfWeek(year, month, day), startOfWeek);
|
||||
|
||||
let weekNumber = Math.floor((ordinal - weekday + 14 - minDaysInFirstWeek) / 7),
|
||||
weekYear;
|
||||
|
||||
if (weekNumber < 1) {
|
||||
weekYear = year - 1;
|
||||
weekNumber = weeksInWeekYear(weekYear, minDaysInFirstWeek, startOfWeek);
|
||||
} else if (weekNumber > weeksInWeekYear(year, minDaysInFirstWeek, startOfWeek)) {
|
||||
weekYear = year + 1;
|
||||
weekNumber = 1;
|
||||
} else {
|
||||
weekYear = year;
|
||||
}
|
||||
|
||||
return { weekYear, weekNumber, weekday, ...timeObject(gregObj) };
|
||||
}
|
||||
|
||||
export function weekToGregorian(weekData, minDaysInFirstWeek = 4, startOfWeek = 1) {
|
||||
const { weekYear, weekNumber, weekday } = weekData,
|
||||
weekdayOfJan4 = isoWeekdayToLocal(dayOfWeek(weekYear, 1, minDaysInFirstWeek), startOfWeek),
|
||||
yearInDays = daysInYear(weekYear);
|
||||
|
||||
let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 7 + minDaysInFirstWeek,
|
||||
year;
|
||||
|
||||
if (ordinal < 1) {
|
||||
year = weekYear - 1;
|
||||
ordinal += daysInYear(year);
|
||||
} else if (ordinal > yearInDays) {
|
||||
year = weekYear + 1;
|
||||
ordinal -= daysInYear(weekYear);
|
||||
} else {
|
||||
year = weekYear;
|
||||
}
|
||||
|
||||
const { month, day } = uncomputeOrdinal(year, ordinal);
|
||||
return { year, month, day, ...timeObject(weekData) };
|
||||
}
|
||||
|
||||
export function gregorianToOrdinal(gregData) {
|
||||
const { year, month, day } = gregData;
|
||||
const ordinal = computeOrdinal(year, month, day);
|
||||
return { year, ordinal, ...timeObject(gregData) };
|
||||
}
|
||||
|
||||
export function ordinalToGregorian(ordinalData) {
|
||||
const { year, ordinal } = ordinalData;
|
||||
const { month, day } = uncomputeOrdinal(year, ordinal);
|
||||
return { year, month, day, ...timeObject(ordinalData) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if local week units like localWeekday are used in obj.
|
||||
* If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties.
|
||||
* Modifies obj in-place!
|
||||
* @param obj the object values
|
||||
*/
|
||||
export function usesLocalWeekValues(obj, loc) {
|
||||
const hasLocaleWeekData =
|
||||
!isUndefined(obj.localWeekday) ||
|
||||
!isUndefined(obj.localWeekNumber) ||
|
||||
!isUndefined(obj.localWeekYear);
|
||||
if (hasLocaleWeekData) {
|
||||
const hasIsoWeekData =
|
||||
!isUndefined(obj.weekday) || !isUndefined(obj.weekNumber) || !isUndefined(obj.weekYear);
|
||||
|
||||
if (hasIsoWeekData) {
|
||||
throw new ConflictingSpecificationError(
|
||||
"Cannot mix locale-based week fields with ISO-based week fields"
|
||||
);
|
||||
}
|
||||
if (!isUndefined(obj.localWeekday)) obj.weekday = obj.localWeekday;
|
||||
if (!isUndefined(obj.localWeekNumber)) obj.weekNumber = obj.localWeekNumber;
|
||||
if (!isUndefined(obj.localWeekYear)) obj.weekYear = obj.localWeekYear;
|
||||
delete obj.localWeekday;
|
||||
delete obj.localWeekNumber;
|
||||
delete obj.localWeekYear;
|
||||
return {
|
||||
minDaysInFirstWeek: loc.getMinDaysInFirstWeek(),
|
||||
startOfWeek: loc.getStartOfWeek(),
|
||||
};
|
||||
} else {
|
||||
return { minDaysInFirstWeek: 4, startOfWeek: 1 };
|
||||
}
|
||||
}
|
||||
|
||||
export function hasInvalidWeekData(obj, minDaysInFirstWeek = 4, startOfWeek = 1) {
|
||||
const validYear = isInteger(obj.weekYear),
|
||||
validWeek = integerBetween(
|
||||
obj.weekNumber,
|
||||
1,
|
||||
weeksInWeekYear(obj.weekYear, minDaysInFirstWeek, startOfWeek)
|
||||
),
|
||||
validWeekday = integerBetween(obj.weekday, 1, 7);
|
||||
|
||||
if (!validYear) {
|
||||
return unitOutOfRange("weekYear", obj.weekYear);
|
||||
} else if (!validWeek) {
|
||||
return unitOutOfRange("week", obj.weekNumber);
|
||||
} else if (!validWeekday) {
|
||||
return unitOutOfRange("weekday", obj.weekday);
|
||||
} else return false;
|
||||
}
|
||||
|
||||
export function hasInvalidOrdinalData(obj) {
|
||||
const validYear = isInteger(obj.year),
|
||||
validOrdinal = integerBetween(obj.ordinal, 1, daysInYear(obj.year));
|
||||
|
||||
if (!validYear) {
|
||||
return unitOutOfRange("year", obj.year);
|
||||
} else if (!validOrdinal) {
|
||||
return unitOutOfRange("ordinal", obj.ordinal);
|
||||
} else return false;
|
||||
}
|
||||
|
||||
export function hasInvalidGregorianData(obj) {
|
||||
const validYear = isInteger(obj.year),
|
||||
validMonth = integerBetween(obj.month, 1, 12),
|
||||
validDay = integerBetween(obj.day, 1, daysInMonth(obj.year, obj.month));
|
||||
|
||||
if (!validYear) {
|
||||
return unitOutOfRange("year", obj.year);
|
||||
} else if (!validMonth) {
|
||||
return unitOutOfRange("month", obj.month);
|
||||
} else if (!validDay) {
|
||||
return unitOutOfRange("day", obj.day);
|
||||
} else return false;
|
||||
}
|
||||
|
||||
export function hasInvalidTimeData(obj) {
|
||||
const { hour, minute, second, millisecond } = obj;
|
||||
const validHour =
|
||||
integerBetween(hour, 0, 23) ||
|
||||
(hour === 24 && minute === 0 && second === 0 && millisecond === 0),
|
||||
validMinute = integerBetween(minute, 0, 59),
|
||||
validSecond = integerBetween(second, 0, 59),
|
||||
validMillisecond = integerBetween(millisecond, 0, 999);
|
||||
|
||||
if (!validHour) {
|
||||
return unitOutOfRange("hour", hour);
|
||||
} else if (!validMinute) {
|
||||
return unitOutOfRange("minute", minute);
|
||||
} else if (!validSecond) {
|
||||
return unitOutOfRange("second", second);
|
||||
} else if (!validMillisecond) {
|
||||
return unitOutOfRange("millisecond", millisecond);
|
||||
} else return false;
|
||||
}
|
||||
95
node_modules/luxon/src/impl/diff.js
generated
vendored
Normal file
95
node_modules/luxon/src/impl/diff.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import Duration from "../duration.js";
|
||||
|
||||
function dayDiff(earlier, later) {
|
||||
const utcDayStart = (dt) => dt.toUTC(0, { keepLocalTime: true }).startOf("day").valueOf(),
|
||||
ms = utcDayStart(later) - utcDayStart(earlier);
|
||||
return Math.floor(Duration.fromMillis(ms).as("days"));
|
||||
}
|
||||
|
||||
function highOrderDiffs(cursor, later, units) {
|
||||
const differs = [
|
||||
["years", (a, b) => b.year - a.year],
|
||||
["quarters", (a, b) => b.quarter - a.quarter + (b.year - a.year) * 4],
|
||||
["months", (a, b) => b.month - a.month + (b.year - a.year) * 12],
|
||||
[
|
||||
"weeks",
|
||||
(a, b) => {
|
||||
const days = dayDiff(a, b);
|
||||
return (days - (days % 7)) / 7;
|
||||
},
|
||||
],
|
||||
["days", dayDiff],
|
||||
];
|
||||
|
||||
const results = {};
|
||||
const earlier = cursor;
|
||||
let lowestOrder, highWater;
|
||||
|
||||
/* This loop tries to diff using larger units first.
|
||||
If we overshoot, we backtrack and try the next smaller unit.
|
||||
"cursor" starts out at the earlier timestamp and moves closer and closer to "later"
|
||||
as we use smaller and smaller units.
|
||||
highWater keeps track of where we would be if we added one more of the smallest unit,
|
||||
this is used later to potentially convert any difference smaller than the smallest higher order unit
|
||||
into a fraction of that smallest higher order unit
|
||||
*/
|
||||
for (const [unit, differ] of differs) {
|
||||
if (units.indexOf(unit) >= 0) {
|
||||
lowestOrder = unit;
|
||||
|
||||
results[unit] = differ(cursor, later);
|
||||
highWater = earlier.plus(results);
|
||||
|
||||
if (highWater > later) {
|
||||
// we overshot the end point, backtrack cursor by 1
|
||||
results[unit]--;
|
||||
cursor = earlier.plus(results);
|
||||
|
||||
// if we are still overshooting now, we need to backtrack again
|
||||
// this happens in certain situations when diffing times in different zones,
|
||||
// because this calculation ignores time zones
|
||||
if (cursor > later) {
|
||||
// keep the "overshot by 1" around as highWater
|
||||
highWater = cursor;
|
||||
// backtrack cursor by 1
|
||||
results[unit]--;
|
||||
cursor = earlier.plus(results);
|
||||
}
|
||||
} else {
|
||||
cursor = highWater;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [cursor, results, highWater, lowestOrder];
|
||||
}
|
||||
|
||||
export default function (earlier, later, units, opts) {
|
||||
let [cursor, results, highWater, lowestOrder] = highOrderDiffs(earlier, later, units);
|
||||
|
||||
const remainingMillis = later - cursor;
|
||||
|
||||
const lowerOrderUnits = units.filter(
|
||||
(u) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0
|
||||
);
|
||||
|
||||
if (lowerOrderUnits.length === 0) {
|
||||
if (highWater < later) {
|
||||
highWater = cursor.plus({ [lowestOrder]: 1 });
|
||||
}
|
||||
|
||||
if (highWater !== cursor) {
|
||||
results[lowestOrder] = (results[lowestOrder] || 0) + remainingMillis / (highWater - cursor);
|
||||
}
|
||||
}
|
||||
|
||||
const duration = Duration.fromObject(results, opts);
|
||||
|
||||
if (lowerOrderUnits.length > 0) {
|
||||
return Duration.fromMillis(remainingMillis, opts)
|
||||
.shiftTo(...lowerOrderUnits)
|
||||
.plus(duration);
|
||||
} else {
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
94
node_modules/luxon/src/impl/digits.js
generated
vendored
Normal file
94
node_modules/luxon/src/impl/digits.js
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
const numberingSystems = {
|
||||
arab: "[\u0660-\u0669]",
|
||||
arabext: "[\u06F0-\u06F9]",
|
||||
bali: "[\u1B50-\u1B59]",
|
||||
beng: "[\u09E6-\u09EF]",
|
||||
deva: "[\u0966-\u096F]",
|
||||
fullwide: "[\uFF10-\uFF19]",
|
||||
gujr: "[\u0AE6-\u0AEF]",
|
||||
hanidec: "[〇|一|二|三|四|五|六|七|八|九]",
|
||||
khmr: "[\u17E0-\u17E9]",
|
||||
knda: "[\u0CE6-\u0CEF]",
|
||||
laoo: "[\u0ED0-\u0ED9]",
|
||||
limb: "[\u1946-\u194F]",
|
||||
mlym: "[\u0D66-\u0D6F]",
|
||||
mong: "[\u1810-\u1819]",
|
||||
mymr: "[\u1040-\u1049]",
|
||||
orya: "[\u0B66-\u0B6F]",
|
||||
tamldec: "[\u0BE6-\u0BEF]",
|
||||
telu: "[\u0C66-\u0C6F]",
|
||||
thai: "[\u0E50-\u0E59]",
|
||||
tibt: "[\u0F20-\u0F29]",
|
||||
latn: "\\d",
|
||||
};
|
||||
|
||||
const numberingSystemsUTF16 = {
|
||||
arab: [1632, 1641],
|
||||
arabext: [1776, 1785],
|
||||
bali: [6992, 7001],
|
||||
beng: [2534, 2543],
|
||||
deva: [2406, 2415],
|
||||
fullwide: [65296, 65303],
|
||||
gujr: [2790, 2799],
|
||||
khmr: [6112, 6121],
|
||||
knda: [3302, 3311],
|
||||
laoo: [3792, 3801],
|
||||
limb: [6470, 6479],
|
||||
mlym: [3430, 3439],
|
||||
mong: [6160, 6169],
|
||||
mymr: [4160, 4169],
|
||||
orya: [2918, 2927],
|
||||
tamldec: [3046, 3055],
|
||||
telu: [3174, 3183],
|
||||
thai: [3664, 3673],
|
||||
tibt: [3872, 3881],
|
||||
};
|
||||
|
||||
const hanidecChars = numberingSystems.hanidec.replace(/[\[|\]]/g, "").split("");
|
||||
|
||||
export function parseDigits(str) {
|
||||
let value = parseInt(str, 10);
|
||||
if (isNaN(value)) {
|
||||
value = "";
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const code = str.charCodeAt(i);
|
||||
|
||||
if (str[i].search(numberingSystems.hanidec) !== -1) {
|
||||
value += hanidecChars.indexOf(str[i]);
|
||||
} else {
|
||||
for (const key in numberingSystemsUTF16) {
|
||||
const [min, max] = numberingSystemsUTF16[key];
|
||||
if (code >= min && code <= max) {
|
||||
value += code - min;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return parseInt(value, 10);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// cache of {numberingSystem: {append: regex}}
|
||||
const digitRegexCache = new Map();
|
||||
export function resetDigitRegexCache() {
|
||||
digitRegexCache.clear();
|
||||
}
|
||||
|
||||
export function digitRegex({ numberingSystem }, append = "") {
|
||||
const ns = numberingSystem || "latn";
|
||||
|
||||
let appendCache = digitRegexCache.get(ns);
|
||||
if (appendCache === undefined) {
|
||||
appendCache = new Map();
|
||||
digitRegexCache.set(ns, appendCache);
|
||||
}
|
||||
let regex = appendCache.get(append);
|
||||
if (regex === undefined) {
|
||||
regex = new RegExp(`${numberingSystems[ns]}${append}`);
|
||||
appendCache.set(append, regex);
|
||||
}
|
||||
|
||||
return regex;
|
||||
}
|
||||
233
node_modules/luxon/src/impl/english.js
generated
vendored
Normal file
233
node_modules/luxon/src/impl/english.js
generated
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
import * as Formats from "./formats.js";
|
||||
import { pick } from "./util.js";
|
||||
|
||||
function stringify(obj) {
|
||||
return JSON.stringify(obj, Object.keys(obj).sort());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
export const monthsLong = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
export const monthsShort = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
|
||||
export const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
|
||||
|
||||
export function months(length) {
|
||||
switch (length) {
|
||||
case "narrow":
|
||||
return [...monthsNarrow];
|
||||
case "short":
|
||||
return [...monthsShort];
|
||||
case "long":
|
||||
return [...monthsLong];
|
||||
case "numeric":
|
||||
return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
|
||||
case "2-digit":
|
||||
return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const weekdaysLong = [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday",
|
||||
];
|
||||
|
||||
export const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
|
||||
export const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
|
||||
|
||||
export function weekdays(length) {
|
||||
switch (length) {
|
||||
case "narrow":
|
||||
return [...weekdaysNarrow];
|
||||
case "short":
|
||||
return [...weekdaysShort];
|
||||
case "long":
|
||||
return [...weekdaysLong];
|
||||
case "numeric":
|
||||
return ["1", "2", "3", "4", "5", "6", "7"];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const meridiems = ["AM", "PM"];
|
||||
|
||||
export const erasLong = ["Before Christ", "Anno Domini"];
|
||||
|
||||
export const erasShort = ["BC", "AD"];
|
||||
|
||||
export const erasNarrow = ["B", "A"];
|
||||
|
||||
export function eras(length) {
|
||||
switch (length) {
|
||||
case "narrow":
|
||||
return [...erasNarrow];
|
||||
case "short":
|
||||
return [...erasShort];
|
||||
case "long":
|
||||
return [...erasLong];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function meridiemForDateTime(dt) {
|
||||
return meridiems[dt.hour < 12 ? 0 : 1];
|
||||
}
|
||||
|
||||
export function weekdayForDateTime(dt, length) {
|
||||
return weekdays(length)[dt.weekday - 1];
|
||||
}
|
||||
|
||||
export function monthForDateTime(dt, length) {
|
||||
return months(length)[dt.month - 1];
|
||||
}
|
||||
|
||||
export function eraForDateTime(dt, length) {
|
||||
return eras(length)[dt.year < 0 ? 0 : 1];
|
||||
}
|
||||
|
||||
export function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
|
||||
const units = {
|
||||
years: ["year", "yr."],
|
||||
quarters: ["quarter", "qtr."],
|
||||
months: ["month", "mo."],
|
||||
weeks: ["week", "wk."],
|
||||
days: ["day", "day", "days"],
|
||||
hours: ["hour", "hr."],
|
||||
minutes: ["minute", "min."],
|
||||
seconds: ["second", "sec."],
|
||||
};
|
||||
|
||||
const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
|
||||
|
||||
if (numeric === "auto" && lastable) {
|
||||
const isDay = unit === "days";
|
||||
switch (count) {
|
||||
case 1:
|
||||
return isDay ? "tomorrow" : `next ${units[unit][0]}`;
|
||||
case -1:
|
||||
return isDay ? "yesterday" : `last ${units[unit][0]}`;
|
||||
case 0:
|
||||
return isDay ? "today" : `this ${units[unit][0]}`;
|
||||
default: // fall through
|
||||
}
|
||||
}
|
||||
|
||||
const isInPast = Object.is(count, -0) || count < 0,
|
||||
fmtValue = Math.abs(count),
|
||||
singular = fmtValue === 1,
|
||||
lilUnits = units[unit],
|
||||
fmtUnit = narrow
|
||||
? singular
|
||||
? lilUnits[1]
|
||||
: lilUnits[2] || lilUnits[1]
|
||||
: singular
|
||||
? units[unit][0]
|
||||
: unit;
|
||||
return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
|
||||
}
|
||||
|
||||
export function formatString(knownFormat) {
|
||||
// these all have the offsets removed because we don't have access to them
|
||||
// without all the intl stuff this is backfilling
|
||||
const filtered = pick(knownFormat, [
|
||||
"weekday",
|
||||
"era",
|
||||
"year",
|
||||
"month",
|
||||
"day",
|
||||
"hour",
|
||||
"minute",
|
||||
"second",
|
||||
"timeZoneName",
|
||||
"hourCycle",
|
||||
]),
|
||||
key = stringify(filtered),
|
||||
dateTimeHuge = "EEEE, LLLL d, yyyy, h:mm a";
|
||||
switch (key) {
|
||||
case stringify(Formats.DATE_SHORT):
|
||||
return "M/d/yyyy";
|
||||
case stringify(Formats.DATE_MED):
|
||||
return "LLL d, yyyy";
|
||||
case stringify(Formats.DATE_MED_WITH_WEEKDAY):
|
||||
return "EEE, LLL d, yyyy";
|
||||
case stringify(Formats.DATE_FULL):
|
||||
return "LLLL d, yyyy";
|
||||
case stringify(Formats.DATE_HUGE):
|
||||
return "EEEE, LLLL d, yyyy";
|
||||
case stringify(Formats.TIME_SIMPLE):
|
||||
return "h:mm a";
|
||||
case stringify(Formats.TIME_WITH_SECONDS):
|
||||
return "h:mm:ss a";
|
||||
case stringify(Formats.TIME_WITH_SHORT_OFFSET):
|
||||
return "h:mm a";
|
||||
case stringify(Formats.TIME_WITH_LONG_OFFSET):
|
||||
return "h:mm a";
|
||||
case stringify(Formats.TIME_24_SIMPLE):
|
||||
return "HH:mm";
|
||||
case stringify(Formats.TIME_24_WITH_SECONDS):
|
||||
return "HH:mm:ss";
|
||||
case stringify(Formats.TIME_24_WITH_SHORT_OFFSET):
|
||||
return "HH:mm";
|
||||
case stringify(Formats.TIME_24_WITH_LONG_OFFSET):
|
||||
return "HH:mm";
|
||||
case stringify(Formats.DATETIME_SHORT):
|
||||
return "M/d/yyyy, h:mm a";
|
||||
case stringify(Formats.DATETIME_MED):
|
||||
return "LLL d, yyyy, h:mm a";
|
||||
case stringify(Formats.DATETIME_FULL):
|
||||
return "LLLL d, yyyy, h:mm a";
|
||||
case stringify(Formats.DATETIME_HUGE):
|
||||
return dateTimeHuge;
|
||||
case stringify(Formats.DATETIME_SHORT_WITH_SECONDS):
|
||||
return "M/d/yyyy, h:mm:ss a";
|
||||
case stringify(Formats.DATETIME_MED_WITH_SECONDS):
|
||||
return "LLL d, yyyy, h:mm:ss a";
|
||||
case stringify(Formats.DATETIME_MED_WITH_WEEKDAY):
|
||||
return "EEE, d LLL yyyy, h:mm a";
|
||||
case stringify(Formats.DATETIME_FULL_WITH_SECONDS):
|
||||
return "LLLL d, yyyy, h:mm:ss a";
|
||||
case stringify(Formats.DATETIME_HUGE_WITH_SECONDS):
|
||||
return "EEEE, LLLL d, yyyy, h:mm:ss a";
|
||||
default:
|
||||
return dateTimeHuge;
|
||||
}
|
||||
}
|
||||
176
node_modules/luxon/src/impl/formats.js
generated
vendored
Normal file
176
node_modules/luxon/src/impl/formats.js
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
const n = "numeric",
|
||||
s = "short",
|
||||
l = "long";
|
||||
|
||||
export const DATE_SHORT = {
|
||||
year: n,
|
||||
month: n,
|
||||
day: n,
|
||||
};
|
||||
|
||||
export const DATE_MED = {
|
||||
year: n,
|
||||
month: s,
|
||||
day: n,
|
||||
};
|
||||
|
||||
export const DATE_MED_WITH_WEEKDAY = {
|
||||
year: n,
|
||||
month: s,
|
||||
day: n,
|
||||
weekday: s,
|
||||
};
|
||||
|
||||
export const DATE_FULL = {
|
||||
year: n,
|
||||
month: l,
|
||||
day: n,
|
||||
};
|
||||
|
||||
export const DATE_HUGE = {
|
||||
year: n,
|
||||
month: l,
|
||||
day: n,
|
||||
weekday: l,
|
||||
};
|
||||
|
||||
export const TIME_SIMPLE = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
};
|
||||
|
||||
export const TIME_WITH_SECONDS = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
};
|
||||
|
||||
export const TIME_WITH_SHORT_OFFSET = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
timeZoneName: s,
|
||||
};
|
||||
|
||||
export const TIME_WITH_LONG_OFFSET = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
timeZoneName: l,
|
||||
};
|
||||
|
||||
export const TIME_24_SIMPLE = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
hourCycle: "h23",
|
||||
};
|
||||
|
||||
export const TIME_24_WITH_SECONDS = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
hourCycle: "h23",
|
||||
};
|
||||
|
||||
export const TIME_24_WITH_SHORT_OFFSET = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
hourCycle: "h23",
|
||||
timeZoneName: s,
|
||||
};
|
||||
|
||||
export const TIME_24_WITH_LONG_OFFSET = {
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
hourCycle: "h23",
|
||||
timeZoneName: l,
|
||||
};
|
||||
|
||||
export const DATETIME_SHORT = {
|
||||
year: n,
|
||||
month: n,
|
||||
day: n,
|
||||
hour: n,
|
||||
minute: n,
|
||||
};
|
||||
|
||||
export const DATETIME_SHORT_WITH_SECONDS = {
|
||||
year: n,
|
||||
month: n,
|
||||
day: n,
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
};
|
||||
|
||||
export const DATETIME_MED = {
|
||||
year: n,
|
||||
month: s,
|
||||
day: n,
|
||||
hour: n,
|
||||
minute: n,
|
||||
};
|
||||
|
||||
export const DATETIME_MED_WITH_SECONDS = {
|
||||
year: n,
|
||||
month: s,
|
||||
day: n,
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
};
|
||||
|
||||
export const DATETIME_MED_WITH_WEEKDAY = {
|
||||
year: n,
|
||||
month: s,
|
||||
day: n,
|
||||
weekday: s,
|
||||
hour: n,
|
||||
minute: n,
|
||||
};
|
||||
|
||||
export const DATETIME_FULL = {
|
||||
year: n,
|
||||
month: l,
|
||||
day: n,
|
||||
hour: n,
|
||||
minute: n,
|
||||
timeZoneName: s,
|
||||
};
|
||||
|
||||
export const DATETIME_FULL_WITH_SECONDS = {
|
||||
year: n,
|
||||
month: l,
|
||||
day: n,
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
timeZoneName: s,
|
||||
};
|
||||
|
||||
export const DATETIME_HUGE = {
|
||||
year: n,
|
||||
month: l,
|
||||
day: n,
|
||||
weekday: l,
|
||||
hour: n,
|
||||
minute: n,
|
||||
timeZoneName: l,
|
||||
};
|
||||
|
||||
export const DATETIME_HUGE_WITH_SECONDS = {
|
||||
year: n,
|
||||
month: l,
|
||||
day: n,
|
||||
weekday: l,
|
||||
hour: n,
|
||||
minute: n,
|
||||
second: n,
|
||||
timeZoneName: l,
|
||||
};
|
||||
434
node_modules/luxon/src/impl/formatter.js
generated
vendored
Normal file
434
node_modules/luxon/src/impl/formatter.js
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
import * as English from "./english.js";
|
||||
import * as Formats from "./formats.js";
|
||||
import { padStart } from "./util.js";
|
||||
|
||||
function stringifyTokens(splits, tokenToString) {
|
||||
let s = "";
|
||||
for (const token of splits) {
|
||||
if (token.literal) {
|
||||
s += token.val;
|
||||
} else {
|
||||
s += tokenToString(token.val);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
const macroTokenToFormatOpts = {
|
||||
D: Formats.DATE_SHORT,
|
||||
DD: Formats.DATE_MED,
|
||||
DDD: Formats.DATE_FULL,
|
||||
DDDD: Formats.DATE_HUGE,
|
||||
t: Formats.TIME_SIMPLE,
|
||||
tt: Formats.TIME_WITH_SECONDS,
|
||||
ttt: Formats.TIME_WITH_SHORT_OFFSET,
|
||||
tttt: Formats.TIME_WITH_LONG_OFFSET,
|
||||
T: Formats.TIME_24_SIMPLE,
|
||||
TT: Formats.TIME_24_WITH_SECONDS,
|
||||
TTT: Formats.TIME_24_WITH_SHORT_OFFSET,
|
||||
TTTT: Formats.TIME_24_WITH_LONG_OFFSET,
|
||||
f: Formats.DATETIME_SHORT,
|
||||
ff: Formats.DATETIME_MED,
|
||||
fff: Formats.DATETIME_FULL,
|
||||
ffff: Formats.DATETIME_HUGE,
|
||||
F: Formats.DATETIME_SHORT_WITH_SECONDS,
|
||||
FF: Formats.DATETIME_MED_WITH_SECONDS,
|
||||
FFF: Formats.DATETIME_FULL_WITH_SECONDS,
|
||||
FFFF: Formats.DATETIME_HUGE_WITH_SECONDS,
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
export default class Formatter {
|
||||
static create(locale, opts = {}) {
|
||||
return new Formatter(locale, opts);
|
||||
}
|
||||
|
||||
static parseFormat(fmt) {
|
||||
// white-space is always considered a literal in user-provided formats
|
||||
// the " " token has a special meaning (see unitForToken)
|
||||
|
||||
let current = null,
|
||||
currentFull = "",
|
||||
bracketed = false;
|
||||
const splits = [];
|
||||
for (let i = 0; i < fmt.length; i++) {
|
||||
const c = fmt.charAt(i);
|
||||
if (c === "'") {
|
||||
// turn '' into a literal signal quote instead of just skipping the empty literal
|
||||
if (currentFull.length > 0 || bracketed) {
|
||||
splits.push({
|
||||
literal: bracketed || /^\s+$/.test(currentFull),
|
||||
val: currentFull === "" ? "'" : currentFull,
|
||||
});
|
||||
}
|
||||
current = null;
|
||||
currentFull = "";
|
||||
bracketed = !bracketed;
|
||||
} else if (bracketed) {
|
||||
currentFull += c;
|
||||
} else if (c === current) {
|
||||
currentFull += c;
|
||||
} else {
|
||||
if (currentFull.length > 0) {
|
||||
splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull });
|
||||
}
|
||||
currentFull = c;
|
||||
current = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFull.length > 0) {
|
||||
splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
|
||||
}
|
||||
|
||||
return splits;
|
||||
}
|
||||
|
||||
static macroTokenToFormatOpts(token) {
|
||||
return macroTokenToFormatOpts[token];
|
||||
}
|
||||
|
||||
constructor(locale, formatOpts) {
|
||||
this.opts = formatOpts;
|
||||
this.loc = locale;
|
||||
this.systemLoc = null;
|
||||
}
|
||||
|
||||
formatWithSystemDefault(dt, opts) {
|
||||
if (this.systemLoc === null) {
|
||||
this.systemLoc = this.loc.redefaultToSystem();
|
||||
}
|
||||
const df = this.systemLoc.dtFormatter(dt, { ...this.opts, ...opts });
|
||||
return df.format();
|
||||
}
|
||||
|
||||
dtFormatter(dt, opts = {}) {
|
||||
return this.loc.dtFormatter(dt, { ...this.opts, ...opts });
|
||||
}
|
||||
|
||||
formatDateTime(dt, opts) {
|
||||
return this.dtFormatter(dt, opts).format();
|
||||
}
|
||||
|
||||
formatDateTimeParts(dt, opts) {
|
||||
return this.dtFormatter(dt, opts).formatToParts();
|
||||
}
|
||||
|
||||
formatInterval(interval, opts) {
|
||||
const df = this.dtFormatter(interval.start, opts);
|
||||
return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate());
|
||||
}
|
||||
|
||||
resolvedOptions(dt, opts) {
|
||||
return this.dtFormatter(dt, opts).resolvedOptions();
|
||||
}
|
||||
|
||||
num(n, p = 0, signDisplay = undefined) {
|
||||
// we get some perf out of doing this here, annoyingly
|
||||
if (this.opts.forceSimple) {
|
||||
return padStart(n, p);
|
||||
}
|
||||
|
||||
const opts = { ...this.opts };
|
||||
|
||||
if (p > 0) {
|
||||
opts.padTo = p;
|
||||
}
|
||||
if (signDisplay) {
|
||||
opts.signDisplay = signDisplay;
|
||||
}
|
||||
|
||||
return this.loc.numberFormatter(opts).format(n);
|
||||
}
|
||||
|
||||
formatDateTimeFromString(dt, fmt) {
|
||||
const knownEnglish = this.loc.listingMode() === "en",
|
||||
useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
|
||||
string = (opts, extract) => this.loc.extract(dt, opts, extract),
|
||||
formatOffset = (opts) => {
|
||||
if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
|
||||
return "Z";
|
||||
}
|
||||
|
||||
return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
|
||||
},
|
||||
meridiem = () =>
|
||||
knownEnglish
|
||||
? English.meridiemForDateTime(dt)
|
||||
: string({ hour: "numeric", hourCycle: "h12" }, "dayperiod"),
|
||||
month = (length, standalone) =>
|
||||
knownEnglish
|
||||
? English.monthForDateTime(dt, length)
|
||||
: string(standalone ? { month: length } : { month: length, day: "numeric" }, "month"),
|
||||
weekday = (length, standalone) =>
|
||||
knownEnglish
|
||||
? English.weekdayForDateTime(dt, length)
|
||||
: string(
|
||||
standalone ? { weekday: length } : { weekday: length, month: "long", day: "numeric" },
|
||||
"weekday"
|
||||
),
|
||||
maybeMacro = (token) => {
|
||||
const formatOpts = Formatter.macroTokenToFormatOpts(token);
|
||||
if (formatOpts) {
|
||||
return this.formatWithSystemDefault(dt, formatOpts);
|
||||
} else {
|
||||
return token;
|
||||
}
|
||||
},
|
||||
era = (length) =>
|
||||
knownEnglish ? English.eraForDateTime(dt, length) : string({ era: length }, "era"),
|
||||
tokenToString = (token) => {
|
||||
// Where possible: https://cldr.unicode.org/translation/date-time/date-time-symbols
|
||||
switch (token) {
|
||||
// ms
|
||||
case "S":
|
||||
return this.num(dt.millisecond);
|
||||
case "u":
|
||||
// falls through
|
||||
case "SSS":
|
||||
return this.num(dt.millisecond, 3);
|
||||
// seconds
|
||||
case "s":
|
||||
return this.num(dt.second);
|
||||
case "ss":
|
||||
return this.num(dt.second, 2);
|
||||
// fractional seconds
|
||||
case "uu":
|
||||
return this.num(Math.floor(dt.millisecond / 10), 2);
|
||||
case "uuu":
|
||||
return this.num(Math.floor(dt.millisecond / 100));
|
||||
// minutes
|
||||
case "m":
|
||||
return this.num(dt.minute);
|
||||
case "mm":
|
||||
return this.num(dt.minute, 2);
|
||||
// hours
|
||||
case "h":
|
||||
return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
|
||||
case "hh":
|
||||
return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
|
||||
case "H":
|
||||
return this.num(dt.hour);
|
||||
case "HH":
|
||||
return this.num(dt.hour, 2);
|
||||
// offset
|
||||
case "Z":
|
||||
// like +6
|
||||
return formatOffset({ format: "narrow", allowZ: this.opts.allowZ });
|
||||
case "ZZ":
|
||||
// like +06:00
|
||||
return formatOffset({ format: "short", allowZ: this.opts.allowZ });
|
||||
case "ZZZ":
|
||||
// like +0600
|
||||
return formatOffset({ format: "techie", allowZ: this.opts.allowZ });
|
||||
case "ZZZZ":
|
||||
// like EST
|
||||
return dt.zone.offsetName(dt.ts, { format: "short", locale: this.loc.locale });
|
||||
case "ZZZZZ":
|
||||
// like Eastern Standard Time
|
||||
return dt.zone.offsetName(dt.ts, { format: "long", locale: this.loc.locale });
|
||||
// zone
|
||||
case "z":
|
||||
// like America/New_York
|
||||
return dt.zoneName;
|
||||
// meridiems
|
||||
case "a":
|
||||
return meridiem();
|
||||
// dates
|
||||
case "d":
|
||||
return useDateTimeFormatter ? string({ day: "numeric" }, "day") : this.num(dt.day);
|
||||
case "dd":
|
||||
return useDateTimeFormatter ? string({ day: "2-digit" }, "day") : this.num(dt.day, 2);
|
||||
// weekdays - standalone
|
||||
case "c":
|
||||
// like 1
|
||||
return this.num(dt.weekday);
|
||||
case "ccc":
|
||||
// like 'Tues'
|
||||
return weekday("short", true);
|
||||
case "cccc":
|
||||
// like 'Tuesday'
|
||||
return weekday("long", true);
|
||||
case "ccccc":
|
||||
// like 'T'
|
||||
return weekday("narrow", true);
|
||||
// weekdays - format
|
||||
case "E":
|
||||
// like 1
|
||||
return this.num(dt.weekday);
|
||||
case "EEE":
|
||||
// like 'Tues'
|
||||
return weekday("short", false);
|
||||
case "EEEE":
|
||||
// like 'Tuesday'
|
||||
return weekday("long", false);
|
||||
case "EEEEE":
|
||||
// like 'T'
|
||||
return weekday("narrow", false);
|
||||
// months - standalone
|
||||
case "L":
|
||||
// like 1
|
||||
return useDateTimeFormatter
|
||||
? string({ month: "numeric", day: "numeric" }, "month")
|
||||
: this.num(dt.month);
|
||||
case "LL":
|
||||
// like 01, doesn't seem to work
|
||||
return useDateTimeFormatter
|
||||
? string({ month: "2-digit", day: "numeric" }, "month")
|
||||
: this.num(dt.month, 2);
|
||||
case "LLL":
|
||||
// like Jan
|
||||
return month("short", true);
|
||||
case "LLLL":
|
||||
// like January
|
||||
return month("long", true);
|
||||
case "LLLLL":
|
||||
// like J
|
||||
return month("narrow", true);
|
||||
// months - format
|
||||
case "M":
|
||||
// like 1
|
||||
return useDateTimeFormatter
|
||||
? string({ month: "numeric" }, "month")
|
||||
: this.num(dt.month);
|
||||
case "MM":
|
||||
// like 01
|
||||
return useDateTimeFormatter
|
||||
? string({ month: "2-digit" }, "month")
|
||||
: this.num(dt.month, 2);
|
||||
case "MMM":
|
||||
// like Jan
|
||||
return month("short", false);
|
||||
case "MMMM":
|
||||
// like January
|
||||
return month("long", false);
|
||||
case "MMMMM":
|
||||
// like J
|
||||
return month("narrow", false);
|
||||
// years
|
||||
case "y":
|
||||
// like 2014
|
||||
return useDateTimeFormatter ? string({ year: "numeric" }, "year") : this.num(dt.year);
|
||||
case "yy":
|
||||
// like 14
|
||||
return useDateTimeFormatter
|
||||
? string({ year: "2-digit" }, "year")
|
||||
: this.num(dt.year.toString().slice(-2), 2);
|
||||
case "yyyy":
|
||||
// like 0012
|
||||
return useDateTimeFormatter
|
||||
? string({ year: "numeric" }, "year")
|
||||
: this.num(dt.year, 4);
|
||||
case "yyyyyy":
|
||||
// like 000012
|
||||
return useDateTimeFormatter
|
||||
? string({ year: "numeric" }, "year")
|
||||
: this.num(dt.year, 6);
|
||||
// eras
|
||||
case "G":
|
||||
// like AD
|
||||
return era("short");
|
||||
case "GG":
|
||||
// like Anno Domini
|
||||
return era("long");
|
||||
case "GGGGG":
|
||||
return era("narrow");
|
||||
case "kk":
|
||||
return this.num(dt.weekYear.toString().slice(-2), 2);
|
||||
case "kkkk":
|
||||
return this.num(dt.weekYear, 4);
|
||||
case "W":
|
||||
return this.num(dt.weekNumber);
|
||||
case "WW":
|
||||
return this.num(dt.weekNumber, 2);
|
||||
case "n":
|
||||
return this.num(dt.localWeekNumber);
|
||||
case "nn":
|
||||
return this.num(dt.localWeekNumber, 2);
|
||||
case "ii":
|
||||
return this.num(dt.localWeekYear.toString().slice(-2), 2);
|
||||
case "iiii":
|
||||
return this.num(dt.localWeekYear, 4);
|
||||
case "o":
|
||||
return this.num(dt.ordinal);
|
||||
case "ooo":
|
||||
return this.num(dt.ordinal, 3);
|
||||
case "q":
|
||||
// like 1
|
||||
return this.num(dt.quarter);
|
||||
case "qq":
|
||||
// like 01
|
||||
return this.num(dt.quarter, 2);
|
||||
case "X":
|
||||
return this.num(Math.floor(dt.ts / 1000));
|
||||
case "x":
|
||||
return this.num(dt.ts);
|
||||
default:
|
||||
return maybeMacro(token);
|
||||
}
|
||||
};
|
||||
|
||||
return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
|
||||
}
|
||||
|
||||
formatDurationFromString(dur, fmt) {
|
||||
const invertLargest = this.opts.signMode === "negativeLargestOnly" ? -1 : 1;
|
||||
const tokenToField = (token) => {
|
||||
switch (token[0]) {
|
||||
case "S":
|
||||
return "milliseconds";
|
||||
case "s":
|
||||
return "seconds";
|
||||
case "m":
|
||||
return "minutes";
|
||||
case "h":
|
||||
return "hours";
|
||||
case "d":
|
||||
return "days";
|
||||
case "w":
|
||||
return "weeks";
|
||||
case "M":
|
||||
return "months";
|
||||
case "y":
|
||||
return "years";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
tokenToString = (lildur, info) => (token) => {
|
||||
const mapped = tokenToField(token);
|
||||
if (mapped) {
|
||||
const inversionFactor =
|
||||
info.isNegativeDuration && mapped !== info.largestUnit ? invertLargest : 1;
|
||||
let signDisplay;
|
||||
if (this.opts.signMode === "negativeLargestOnly" && mapped !== info.largestUnit) {
|
||||
signDisplay = "never";
|
||||
} else if (this.opts.signMode === "all") {
|
||||
signDisplay = "always";
|
||||
} else {
|
||||
// "auto" and "negative" are the same, but "auto" has better support
|
||||
signDisplay = "auto";
|
||||
}
|
||||
return this.num(lildur.get(mapped) * inversionFactor, token.length, signDisplay);
|
||||
} else {
|
||||
return token;
|
||||
}
|
||||
},
|
||||
tokens = Formatter.parseFormat(fmt),
|
||||
realTokens = tokens.reduce(
|
||||
(found, { literal, val }) => (literal ? found : found.concat(val)),
|
||||
[]
|
||||
),
|
||||
collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t)),
|
||||
durationInfo = {
|
||||
isNegativeDuration: collapsed < 0,
|
||||
// this relies on "collapsed" being based on "shiftTo", which builds up the object
|
||||
// in order
|
||||
largestUnit: Object.keys(collapsed.values)[0],
|
||||
};
|
||||
return stringifyTokens(tokens, tokenToString(collapsed, durationInfo));
|
||||
}
|
||||
}
|
||||
14
node_modules/luxon/src/impl/invalid.js
generated
vendored
Normal file
14
node_modules/luxon/src/impl/invalid.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
export default class Invalid {
|
||||
constructor(reason, explanation) {
|
||||
this.reason = reason;
|
||||
this.explanation = explanation;
|
||||
}
|
||||
|
||||
toMessage() {
|
||||
if (this.explanation) {
|
||||
return `${this.reason}: ${this.explanation}`;
|
||||
} else {
|
||||
return this.reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
569
node_modules/luxon/src/impl/locale.js
generated
vendored
Normal file
569
node_modules/luxon/src/impl/locale.js
generated
vendored
Normal file
@@ -0,0 +1,569 @@
|
||||
import { hasLocaleWeekInfo, hasRelative, padStart, roundTo, validateWeekSettings } from "./util.js";
|
||||
import * as English from "./english.js";
|
||||
import Settings from "../settings.js";
|
||||
import DateTime from "../datetime.js";
|
||||
import IANAZone from "../zones/IANAZone.js";
|
||||
|
||||
// todo - remap caching
|
||||
|
||||
let intlLFCache = {};
|
||||
function getCachedLF(locString, opts = {}) {
|
||||
const key = JSON.stringify([locString, opts]);
|
||||
let dtf = intlLFCache[key];
|
||||
if (!dtf) {
|
||||
dtf = new Intl.ListFormat(locString, opts);
|
||||
intlLFCache[key] = dtf;
|
||||
}
|
||||
return dtf;
|
||||
}
|
||||
|
||||
const intlDTCache = new Map();
|
||||
function getCachedDTF(locString, opts = {}) {
|
||||
const key = JSON.stringify([locString, opts]);
|
||||
let dtf = intlDTCache.get(key);
|
||||
if (dtf === undefined) {
|
||||
dtf = new Intl.DateTimeFormat(locString, opts);
|
||||
intlDTCache.set(key, dtf);
|
||||
}
|
||||
return dtf;
|
||||
}
|
||||
|
||||
const intlNumCache = new Map();
|
||||
function getCachedINF(locString, opts = {}) {
|
||||
const key = JSON.stringify([locString, opts]);
|
||||
let inf = intlNumCache.get(key);
|
||||
if (inf === undefined) {
|
||||
inf = new Intl.NumberFormat(locString, opts);
|
||||
intlNumCache.set(key, inf);
|
||||
}
|
||||
return inf;
|
||||
}
|
||||
|
||||
const intlRelCache = new Map();
|
||||
function getCachedRTF(locString, opts = {}) {
|
||||
const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options
|
||||
const key = JSON.stringify([locString, cacheKeyOpts]);
|
||||
let inf = intlRelCache.get(key);
|
||||
if (inf === undefined) {
|
||||
inf = new Intl.RelativeTimeFormat(locString, opts);
|
||||
intlRelCache.set(key, inf);
|
||||
}
|
||||
return inf;
|
||||
}
|
||||
|
||||
let sysLocaleCache = null;
|
||||
function systemLocale() {
|
||||
if (sysLocaleCache) {
|
||||
return sysLocaleCache;
|
||||
} else {
|
||||
sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
|
||||
return sysLocaleCache;
|
||||
}
|
||||
}
|
||||
|
||||
const intlResolvedOptionsCache = new Map();
|
||||
function getCachedIntResolvedOptions(locString) {
|
||||
let opts = intlResolvedOptionsCache.get(locString);
|
||||
if (opts === undefined) {
|
||||
opts = new Intl.DateTimeFormat(locString).resolvedOptions();
|
||||
intlResolvedOptionsCache.set(locString, opts);
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
const weekInfoCache = new Map();
|
||||
function getCachedWeekInfo(locString) {
|
||||
let data = weekInfoCache.get(locString);
|
||||
if (!data) {
|
||||
const locale = new Intl.Locale(locString);
|
||||
// browsers currently implement this as a property, but spec says it should be a getter function
|
||||
data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo;
|
||||
// minimalDays was removed from WeekInfo: https://github.com/tc39/proposal-intl-locale-info/issues/86
|
||||
if (!("minimalDays" in data)) {
|
||||
data = { ...fallbackWeekSettings, ...data };
|
||||
}
|
||||
weekInfoCache.set(locString, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseLocaleString(localeStr) {
|
||||
// I really want to avoid writing a BCP 47 parser
|
||||
// see, e.g. https://github.com/wooorm/bcp-47
|
||||
// Instead, we'll do this:
|
||||
|
||||
// a) if the string has no -u extensions, just leave it alone
|
||||
// b) if it does, use Intl to resolve everything
|
||||
// c) if Intl fails, try again without the -u
|
||||
|
||||
// private subtags and unicode subtags have ordering requirements,
|
||||
// and we're not properly parsing this, so just strip out the
|
||||
// private ones if they exist.
|
||||
const xIndex = localeStr.indexOf("-x-");
|
||||
if (xIndex !== -1) {
|
||||
localeStr = localeStr.substring(0, xIndex);
|
||||
}
|
||||
|
||||
const uIndex = localeStr.indexOf("-u-");
|
||||
if (uIndex === -1) {
|
||||
return [localeStr];
|
||||
} else {
|
||||
let options;
|
||||
let selectedStr;
|
||||
try {
|
||||
options = getCachedDTF(localeStr).resolvedOptions();
|
||||
selectedStr = localeStr;
|
||||
} catch (e) {
|
||||
const smaller = localeStr.substring(0, uIndex);
|
||||
options = getCachedDTF(smaller).resolvedOptions();
|
||||
selectedStr = smaller;
|
||||
}
|
||||
|
||||
const { numberingSystem, calendar } = options;
|
||||
return [selectedStr, numberingSystem, calendar];
|
||||
}
|
||||
}
|
||||
|
||||
function intlConfigString(localeStr, numberingSystem, outputCalendar) {
|
||||
if (outputCalendar || numberingSystem) {
|
||||
if (!localeStr.includes("-u-")) {
|
||||
localeStr += "-u";
|
||||
}
|
||||
|
||||
if (outputCalendar) {
|
||||
localeStr += `-ca-${outputCalendar}`;
|
||||
}
|
||||
|
||||
if (numberingSystem) {
|
||||
localeStr += `-nu-${numberingSystem}`;
|
||||
}
|
||||
return localeStr;
|
||||
} else {
|
||||
return localeStr;
|
||||
}
|
||||
}
|
||||
|
||||
function mapMonths(f) {
|
||||
const ms = [];
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
const dt = DateTime.utc(2009, i, 1);
|
||||
ms.push(f(dt));
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
|
||||
function mapWeekdays(f) {
|
||||
const ms = [];
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
const dt = DateTime.utc(2016, 11, 13 + i);
|
||||
ms.push(f(dt));
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
|
||||
function listStuff(loc, length, englishFn, intlFn) {
|
||||
const mode = loc.listingMode();
|
||||
|
||||
if (mode === "error") {
|
||||
return null;
|
||||
} else if (mode === "en") {
|
||||
return englishFn(length);
|
||||
} else {
|
||||
return intlFn(length);
|
||||
}
|
||||
}
|
||||
|
||||
function supportsFastNumbers(loc) {
|
||||
if (loc.numberingSystem && loc.numberingSystem !== "latn") {
|
||||
return false;
|
||||
} else {
|
||||
return (
|
||||
loc.numberingSystem === "latn" ||
|
||||
!loc.locale ||
|
||||
loc.locale.startsWith("en") ||
|
||||
getCachedIntResolvedOptions(loc.locale).numberingSystem === "latn"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
class PolyNumberFormatter {
|
||||
constructor(intl, forceSimple, opts) {
|
||||
this.padTo = opts.padTo || 0;
|
||||
this.floor = opts.floor || false;
|
||||
|
||||
const { padTo, floor, ...otherOpts } = opts;
|
||||
|
||||
if (!forceSimple || Object.keys(otherOpts).length > 0) {
|
||||
const intlOpts = { useGrouping: false, ...opts };
|
||||
if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
|
||||
this.inf = getCachedINF(intl, intlOpts);
|
||||
}
|
||||
}
|
||||
|
||||
format(i) {
|
||||
if (this.inf) {
|
||||
const fixed = this.floor ? Math.floor(i) : i;
|
||||
return this.inf.format(fixed);
|
||||
} else {
|
||||
// to match the browser's numberformatter defaults
|
||||
const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
|
||||
return padStart(fixed, this.padTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
class PolyDateFormatter {
|
||||
constructor(dt, intl, opts) {
|
||||
this.opts = opts;
|
||||
this.originalZone = undefined;
|
||||
|
||||
let z = undefined;
|
||||
if (this.opts.timeZone) {
|
||||
// Don't apply any workarounds if a timeZone is explicitly provided in opts
|
||||
this.dt = dt;
|
||||
} else if (dt.zone.type === "fixed") {
|
||||
// UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
|
||||
// That is why fixed-offset TZ is set to that unless it is:
|
||||
// 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
|
||||
// 2. Unsupported by the browser:
|
||||
// - some do not support Etc/
|
||||
// - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
|
||||
const gmtOffset = -1 * (dt.offset / 60);
|
||||
const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
|
||||
if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
|
||||
z = offsetZ;
|
||||
this.dt = dt;
|
||||
} else {
|
||||
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata so
|
||||
// we manually apply the offset and substitute the zone as needed.
|
||||
z = "UTC";
|
||||
this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
|
||||
this.originalZone = dt.zone;
|
||||
}
|
||||
} else if (dt.zone.type === "system") {
|
||||
this.dt = dt;
|
||||
} else if (dt.zone.type === "iana") {
|
||||
this.dt = dt;
|
||||
z = dt.zone.name;
|
||||
} else {
|
||||
// Custom zones can have any offset / offsetName so we just manually
|
||||
// apply the offset and substitute the zone as needed.
|
||||
z = "UTC";
|
||||
this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
|
||||
this.originalZone = dt.zone;
|
||||
}
|
||||
|
||||
const intlOpts = { ...this.opts };
|
||||
intlOpts.timeZone = intlOpts.timeZone || z;
|
||||
this.dtf = getCachedDTF(intl, intlOpts);
|
||||
}
|
||||
|
||||
format() {
|
||||
if (this.originalZone) {
|
||||
// If we have to substitute in the actual zone name, we have to use
|
||||
// formatToParts so that the timezone can be replaced.
|
||||
return this.formatToParts()
|
||||
.map(({ value }) => value)
|
||||
.join("");
|
||||
}
|
||||
return this.dtf.format(this.dt.toJSDate());
|
||||
}
|
||||
|
||||
formatToParts() {
|
||||
const parts = this.dtf.formatToParts(this.dt.toJSDate());
|
||||
if (this.originalZone) {
|
||||
return parts.map((part) => {
|
||||
if (part.type === "timeZoneName") {
|
||||
const offsetName = this.originalZone.offsetName(this.dt.ts, {
|
||||
locale: this.dt.locale,
|
||||
format: this.opts.timeZoneName,
|
||||
});
|
||||
return {
|
||||
...part,
|
||||
value: offsetName,
|
||||
};
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
resolvedOptions() {
|
||||
return this.dtf.resolvedOptions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
class PolyRelFormatter {
|
||||
constructor(intl, isEnglish, opts) {
|
||||
this.opts = { style: "long", ...opts };
|
||||
if (!isEnglish && hasRelative()) {
|
||||
this.rtf = getCachedRTF(intl, opts);
|
||||
}
|
||||
}
|
||||
|
||||
format(count, unit) {
|
||||
if (this.rtf) {
|
||||
return this.rtf.format(count, unit);
|
||||
} else {
|
||||
return English.formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
|
||||
}
|
||||
}
|
||||
|
||||
formatToParts(count, unit) {
|
||||
if (this.rtf) {
|
||||
return this.rtf.formatToParts(count, unit);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackWeekSettings = {
|
||||
firstDay: 1,
|
||||
minimalDays: 4,
|
||||
weekend: [6, 7],
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export default class Locale {
|
||||
static fromOpts(opts) {
|
||||
return Locale.create(
|
||||
opts.locale,
|
||||
opts.numberingSystem,
|
||||
opts.outputCalendar,
|
||||
opts.weekSettings,
|
||||
opts.defaultToEN
|
||||
);
|
||||
}
|
||||
|
||||
static create(locale, numberingSystem, outputCalendar, weekSettings, defaultToEN = false) {
|
||||
const specifiedLocale = locale || Settings.defaultLocale;
|
||||
// the system locale is useful for human-readable strings but annoying for parsing/formatting known formats
|
||||
const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
|
||||
const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
|
||||
const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
|
||||
const weekSettingsR = validateWeekSettings(weekSettings) || Settings.defaultWeekSettings;
|
||||
return new Locale(localeR, numberingSystemR, outputCalendarR, weekSettingsR, specifiedLocale);
|
||||
}
|
||||
|
||||
static resetCache() {
|
||||
sysLocaleCache = null;
|
||||
intlDTCache.clear();
|
||||
intlNumCache.clear();
|
||||
intlRelCache.clear();
|
||||
intlResolvedOptionsCache.clear();
|
||||
weekInfoCache.clear();
|
||||
}
|
||||
|
||||
static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
|
||||
return Locale.create(locale, numberingSystem, outputCalendar, weekSettings);
|
||||
}
|
||||
|
||||
constructor(locale, numbering, outputCalendar, weekSettings, specifiedLocale) {
|
||||
const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
|
||||
|
||||
this.locale = parsedLocale;
|
||||
this.numberingSystem = numbering || parsedNumberingSystem || null;
|
||||
this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
|
||||
this.weekSettings = weekSettings;
|
||||
this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
|
||||
|
||||
this.weekdaysCache = { format: {}, standalone: {} };
|
||||
this.monthsCache = { format: {}, standalone: {} };
|
||||
this.meridiemCache = null;
|
||||
this.eraCache = {};
|
||||
|
||||
this.specifiedLocale = specifiedLocale;
|
||||
this.fastNumbersCached = null;
|
||||
}
|
||||
|
||||
get fastNumbers() {
|
||||
if (this.fastNumbersCached == null) {
|
||||
this.fastNumbersCached = supportsFastNumbers(this);
|
||||
}
|
||||
|
||||
return this.fastNumbersCached;
|
||||
}
|
||||
|
||||
listingMode() {
|
||||
const isActuallyEn = this.isEnglish();
|
||||
const hasNoWeirdness =
|
||||
(this.numberingSystem === null || this.numberingSystem === "latn") &&
|
||||
(this.outputCalendar === null || this.outputCalendar === "gregory");
|
||||
return isActuallyEn && hasNoWeirdness ? "en" : "intl";
|
||||
}
|
||||
|
||||
clone(alts) {
|
||||
if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
|
||||
return this;
|
||||
} else {
|
||||
return Locale.create(
|
||||
alts.locale || this.specifiedLocale,
|
||||
alts.numberingSystem || this.numberingSystem,
|
||||
alts.outputCalendar || this.outputCalendar,
|
||||
validateWeekSettings(alts.weekSettings) || this.weekSettings,
|
||||
alts.defaultToEN || false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
redefaultToEN(alts = {}) {
|
||||
return this.clone({ ...alts, defaultToEN: true });
|
||||
}
|
||||
|
||||
redefaultToSystem(alts = {}) {
|
||||
return this.clone({ ...alts, defaultToEN: false });
|
||||
}
|
||||
|
||||
months(length, format = false) {
|
||||
return listStuff(this, length, English.months, () => {
|
||||
// Workaround for "ja" locale: formatToParts does not label all parts of the month
|
||||
// as "month" and for this locale there is no difference between "format" and "non-format".
|
||||
// As such, just use format() instead of formatToParts() and take the whole string
|
||||
const monthSpecialCase = this.intl === "ja" || this.intl.startsWith("ja-");
|
||||
format &= !monthSpecialCase;
|
||||
const intl = format ? { month: length, day: "numeric" } : { month: length },
|
||||
formatStr = format ? "format" : "standalone";
|
||||
if (!this.monthsCache[formatStr][length]) {
|
||||
const mapper = !monthSpecialCase
|
||||
? (dt) => this.extract(dt, intl, "month")
|
||||
: (dt) => this.dtFormatter(dt, intl).format();
|
||||
this.monthsCache[formatStr][length] = mapMonths(mapper);
|
||||
}
|
||||
return this.monthsCache[formatStr][length];
|
||||
});
|
||||
}
|
||||
|
||||
weekdays(length, format = false) {
|
||||
return listStuff(this, length, English.weekdays, () => {
|
||||
const intl = format
|
||||
? { weekday: length, year: "numeric", month: "long", day: "numeric" }
|
||||
: { weekday: length },
|
||||
formatStr = format ? "format" : "standalone";
|
||||
if (!this.weekdaysCache[formatStr][length]) {
|
||||
this.weekdaysCache[formatStr][length] = mapWeekdays((dt) =>
|
||||
this.extract(dt, intl, "weekday")
|
||||
);
|
||||
}
|
||||
return this.weekdaysCache[formatStr][length];
|
||||
});
|
||||
}
|
||||
|
||||
meridiems() {
|
||||
return listStuff(
|
||||
this,
|
||||
undefined,
|
||||
() => English.meridiems,
|
||||
() => {
|
||||
// In theory there could be aribitrary day periods. We're gonna assume there are exactly two
|
||||
// for AM and PM. This is probably wrong, but it's makes parsing way easier.
|
||||
if (!this.meridiemCache) {
|
||||
const intl = { hour: "numeric", hourCycle: "h12" };
|
||||
this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(
|
||||
(dt) => this.extract(dt, intl, "dayperiod")
|
||||
);
|
||||
}
|
||||
|
||||
return this.meridiemCache;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
eras(length) {
|
||||
return listStuff(this, length, English.eras, () => {
|
||||
const intl = { era: length };
|
||||
|
||||
// This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
|
||||
// to definitely enumerate them.
|
||||
if (!this.eraCache[length]) {
|
||||
this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map((dt) =>
|
||||
this.extract(dt, intl, "era")
|
||||
);
|
||||
}
|
||||
|
||||
return this.eraCache[length];
|
||||
});
|
||||
}
|
||||
|
||||
extract(dt, intlOpts, field) {
|
||||
const df = this.dtFormatter(dt, intlOpts),
|
||||
results = df.formatToParts(),
|
||||
matching = results.find((m) => m.type.toLowerCase() === field);
|
||||
return matching ? matching.value : null;
|
||||
}
|
||||
|
||||
numberFormatter(opts = {}) {
|
||||
// this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
|
||||
// (in contrast, the rest of the condition is used heavily)
|
||||
return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
|
||||
}
|
||||
|
||||
dtFormatter(dt, intlOpts = {}) {
|
||||
return new PolyDateFormatter(dt, this.intl, intlOpts);
|
||||
}
|
||||
|
||||
relFormatter(opts = {}) {
|
||||
return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
|
||||
}
|
||||
|
||||
listFormatter(opts = {}) {
|
||||
return getCachedLF(this.intl, opts);
|
||||
}
|
||||
|
||||
isEnglish() {
|
||||
return (
|
||||
this.locale === "en" ||
|
||||
this.locale.toLowerCase() === "en-us" ||
|
||||
getCachedIntResolvedOptions(this.intl).locale.startsWith("en-us")
|
||||
);
|
||||
}
|
||||
|
||||
getWeekSettings() {
|
||||
if (this.weekSettings) {
|
||||
return this.weekSettings;
|
||||
} else if (!hasLocaleWeekInfo()) {
|
||||
return fallbackWeekSettings;
|
||||
} else {
|
||||
return getCachedWeekInfo(this.locale);
|
||||
}
|
||||
}
|
||||
|
||||
getStartOfWeek() {
|
||||
return this.getWeekSettings().firstDay;
|
||||
}
|
||||
|
||||
getMinDaysInFirstWeek() {
|
||||
return this.getWeekSettings().minimalDays;
|
||||
}
|
||||
|
||||
getWeekendDays() {
|
||||
return this.getWeekSettings().weekend;
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
return (
|
||||
this.locale === other.locale &&
|
||||
this.numberingSystem === other.numberingSystem &&
|
||||
this.outputCalendar === other.outputCalendar
|
||||
);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`;
|
||||
}
|
||||
}
|
||||
335
node_modules/luxon/src/impl/regexParser.js
generated
vendored
Normal file
335
node_modules/luxon/src/impl/regexParser.js
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
import {
|
||||
untruncateYear,
|
||||
signedOffset,
|
||||
parseInteger,
|
||||
parseMillis,
|
||||
isUndefined,
|
||||
parseFloating,
|
||||
} from "./util.js";
|
||||
import * as English from "./english.js";
|
||||
import FixedOffsetZone from "../zones/fixedOffsetZone.js";
|
||||
import IANAZone from "../zones/IANAZone.js";
|
||||
|
||||
/*
|
||||
* This file handles parsing for well-specified formats. Here's how it works:
|
||||
* Two things go into parsing: a regex to match with and an extractor to take apart the groups in the match.
|
||||
* An extractor is just a function that takes a regex match array and returns a { year: ..., month: ... } object
|
||||
* parse() does the work of executing the regex and applying the extractor. It takes multiple regex/extractor pairs to try in sequence.
|
||||
* Extractors can take a "cursor" representing the offset in the match to look at. This makes it easy to combine extractors.
|
||||
* combineExtractors() does the work of combining them, keeping track of the cursor through multiple extractions.
|
||||
* Some extractions are super dumb and simpleParse and fromStrings help DRY them.
|
||||
*/
|
||||
|
||||
const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
|
||||
|
||||
function combineRegexes(...regexes) {
|
||||
const full = regexes.reduce((f, r) => f + r.source, "");
|
||||
return RegExp(`^${full}$`);
|
||||
}
|
||||
|
||||
function combineExtractors(...extractors) {
|
||||
return (m) =>
|
||||
extractors
|
||||
.reduce(
|
||||
([mergedVals, mergedZone, cursor], ex) => {
|
||||
const [val, zone, next] = ex(m, cursor);
|
||||
return [{ ...mergedVals, ...val }, zone || mergedZone, next];
|
||||
},
|
||||
[{}, null, 1]
|
||||
)
|
||||
.slice(0, 2);
|
||||
}
|
||||
|
||||
function parse(s, ...patterns) {
|
||||
if (s == null) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
for (const [regex, extractor] of patterns) {
|
||||
const m = regex.exec(s);
|
||||
if (m) {
|
||||
return extractor(m);
|
||||
}
|
||||
}
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
function simpleParse(...keys) {
|
||||
return (match, cursor) => {
|
||||
const ret = {};
|
||||
let i;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
ret[keys[i]] = parseInteger(match[cursor + i]);
|
||||
}
|
||||
return [ret, null, cursor + i];
|
||||
};
|
||||
}
|
||||
|
||||
// ISO and SQL parsing
|
||||
const offsetRegex = /(?:([Zz])|([+-]\d\d)(?::?(\d\d))?)/;
|
||||
const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;
|
||||
const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;
|
||||
const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);
|
||||
const isoTimeExtensionRegex = RegExp(`(?:[Tt]${isoTimeRegex.source})?`);
|
||||
const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
|
||||
const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
|
||||
const isoOrdinalRegex = /(\d{4})-?(\d{3})/;
|
||||
const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay");
|
||||
const extractISOOrdinalData = simpleParse("year", "ordinal");
|
||||
const sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/; // dumbed-down version of the ISO one
|
||||
const sqlTimeRegex = RegExp(
|
||||
`${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?`
|
||||
);
|
||||
const sqlTimeExtensionRegex = RegExp(`(?: ${sqlTimeRegex.source})?`);
|
||||
|
||||
function int(match, pos, fallback) {
|
||||
const m = match[pos];
|
||||
return isUndefined(m) ? fallback : parseInteger(m);
|
||||
}
|
||||
|
||||
function extractISOYmd(match, cursor) {
|
||||
const item = {
|
||||
year: int(match, cursor),
|
||||
month: int(match, cursor + 1, 1),
|
||||
day: int(match, cursor + 2, 1),
|
||||
};
|
||||
|
||||
return [item, null, cursor + 3];
|
||||
}
|
||||
|
||||
function extractISOTime(match, cursor) {
|
||||
const item = {
|
||||
hours: int(match, cursor, 0),
|
||||
minutes: int(match, cursor + 1, 0),
|
||||
seconds: int(match, cursor + 2, 0),
|
||||
milliseconds: parseMillis(match[cursor + 3]),
|
||||
};
|
||||
|
||||
return [item, null, cursor + 4];
|
||||
}
|
||||
|
||||
function extractISOOffset(match, cursor) {
|
||||
const local = !match[cursor] && !match[cursor + 1],
|
||||
fullOffset = signedOffset(match[cursor + 1], match[cursor + 2]),
|
||||
zone = local ? null : FixedOffsetZone.instance(fullOffset);
|
||||
return [{}, zone, cursor + 3];
|
||||
}
|
||||
|
||||
function extractIANAZone(match, cursor) {
|
||||
const zone = match[cursor] ? IANAZone.create(match[cursor]) : null;
|
||||
return [{}, zone, cursor + 1];
|
||||
}
|
||||
|
||||
// ISO time parsing
|
||||
|
||||
const isoTimeOnly = RegExp(`^T?${isoTimeBaseRegex.source}$`);
|
||||
|
||||
// ISO duration parsing
|
||||
|
||||
const isoDuration =
|
||||
/^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;
|
||||
|
||||
function extractISODuration(match) {
|
||||
const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] =
|
||||
match;
|
||||
|
||||
const hasNegativePrefix = s[0] === "-";
|
||||
const negativeSeconds = secondStr && secondStr[0] === "-";
|
||||
|
||||
const maybeNegate = (num, force = false) =>
|
||||
num !== undefined && (force || (num && hasNegativePrefix)) ? -num : num;
|
||||
|
||||
return [
|
||||
{
|
||||
years: maybeNegate(parseFloating(yearStr)),
|
||||
months: maybeNegate(parseFloating(monthStr)),
|
||||
weeks: maybeNegate(parseFloating(weekStr)),
|
||||
days: maybeNegate(parseFloating(dayStr)),
|
||||
hours: maybeNegate(parseFloating(hourStr)),
|
||||
minutes: maybeNegate(parseFloating(minuteStr)),
|
||||
seconds: maybeNegate(parseFloating(secondStr), secondStr === "-0"),
|
||||
milliseconds: maybeNegate(parseMillis(millisecondsStr), negativeSeconds),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// These are a little braindead. EDT *should* tell us that we're in, say, America/New_York
|
||||
// and not just that we're in -240 *right now*. But since I don't think these are used that often
|
||||
// I'm just going to ignore that
|
||||
const obsOffsets = {
|
||||
GMT: 0,
|
||||
EDT: -4 * 60,
|
||||
EST: -5 * 60,
|
||||
CDT: -5 * 60,
|
||||
CST: -6 * 60,
|
||||
MDT: -6 * 60,
|
||||
MST: -7 * 60,
|
||||
PDT: -7 * 60,
|
||||
PST: -8 * 60,
|
||||
};
|
||||
|
||||
function fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
|
||||
const result = {
|
||||
year: yearStr.length === 2 ? untruncateYear(parseInteger(yearStr)) : parseInteger(yearStr),
|
||||
month: English.monthsShort.indexOf(monthStr) + 1,
|
||||
day: parseInteger(dayStr),
|
||||
hour: parseInteger(hourStr),
|
||||
minute: parseInteger(minuteStr),
|
||||
};
|
||||
|
||||
if (secondStr) result.second = parseInteger(secondStr);
|
||||
if (weekdayStr) {
|
||||
result.weekday =
|
||||
weekdayStr.length > 3
|
||||
? English.weekdaysLong.indexOf(weekdayStr) + 1
|
||||
: English.weekdaysShort.indexOf(weekdayStr) + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// RFC 2822/5322
|
||||
const rfc2822 =
|
||||
/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;
|
||||
|
||||
function extractRFC2822(match) {
|
||||
const [
|
||||
,
|
||||
weekdayStr,
|
||||
dayStr,
|
||||
monthStr,
|
||||
yearStr,
|
||||
hourStr,
|
||||
minuteStr,
|
||||
secondStr,
|
||||
obsOffset,
|
||||
milOffset,
|
||||
offHourStr,
|
||||
offMinuteStr,
|
||||
] = match,
|
||||
result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
|
||||
|
||||
let offset;
|
||||
if (obsOffset) {
|
||||
offset = obsOffsets[obsOffset];
|
||||
} else if (milOffset) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = signedOffset(offHourStr, offMinuteStr);
|
||||
}
|
||||
|
||||
return [result, new FixedOffsetZone(offset)];
|
||||
}
|
||||
|
||||
function preprocessRFC2822(s) {
|
||||
// Remove comments and folding whitespace and replace multiple-spaces with a single space
|
||||
return s
|
||||
.replace(/\([^()]*\)|[\n\t]/g, " ")
|
||||
.replace(/(\s\s+)/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
// http date
|
||||
|
||||
const rfc1123 =
|
||||
/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,
|
||||
rfc850 =
|
||||
/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,
|
||||
ascii =
|
||||
/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;
|
||||
|
||||
function extractRFC1123Or850(match) {
|
||||
const [, weekdayStr, dayStr, monthStr, yearStr, hourStr, minuteStr, secondStr] = match,
|
||||
result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
|
||||
return [result, FixedOffsetZone.utcInstance];
|
||||
}
|
||||
|
||||
function extractASCII(match) {
|
||||
const [, weekdayStr, monthStr, dayStr, hourStr, minuteStr, secondStr, yearStr] = match,
|
||||
result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
|
||||
return [result, FixedOffsetZone.utcInstance];
|
||||
}
|
||||
|
||||
const isoYmdWithTimeExtensionRegex = combineRegexes(isoYmdRegex, isoTimeExtensionRegex);
|
||||
const isoWeekWithTimeExtensionRegex = combineRegexes(isoWeekRegex, isoTimeExtensionRegex);
|
||||
const isoOrdinalWithTimeExtensionRegex = combineRegexes(isoOrdinalRegex, isoTimeExtensionRegex);
|
||||
const isoTimeCombinedRegex = combineRegexes(isoTimeRegex);
|
||||
|
||||
const extractISOYmdTimeAndOffset = combineExtractors(
|
||||
extractISOYmd,
|
||||
extractISOTime,
|
||||
extractISOOffset,
|
||||
extractIANAZone
|
||||
);
|
||||
const extractISOWeekTimeAndOffset = combineExtractors(
|
||||
extractISOWeekData,
|
||||
extractISOTime,
|
||||
extractISOOffset,
|
||||
extractIANAZone
|
||||
);
|
||||
const extractISOOrdinalDateAndTime = combineExtractors(
|
||||
extractISOOrdinalData,
|
||||
extractISOTime,
|
||||
extractISOOffset,
|
||||
extractIANAZone
|
||||
);
|
||||
const extractISOTimeAndOffset = combineExtractors(
|
||||
extractISOTime,
|
||||
extractISOOffset,
|
||||
extractIANAZone
|
||||
);
|
||||
|
||||
/*
|
||||
* @private
|
||||
*/
|
||||
|
||||
export function parseISODate(s) {
|
||||
return parse(
|
||||
s,
|
||||
[isoYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
|
||||
[isoWeekWithTimeExtensionRegex, extractISOWeekTimeAndOffset],
|
||||
[isoOrdinalWithTimeExtensionRegex, extractISOOrdinalDateAndTime],
|
||||
[isoTimeCombinedRegex, extractISOTimeAndOffset]
|
||||
);
|
||||
}
|
||||
|
||||
export function parseRFC2822Date(s) {
|
||||
return parse(preprocessRFC2822(s), [rfc2822, extractRFC2822]);
|
||||
}
|
||||
|
||||
export function parseHTTPDate(s) {
|
||||
return parse(
|
||||
s,
|
||||
[rfc1123, extractRFC1123Or850],
|
||||
[rfc850, extractRFC1123Or850],
|
||||
[ascii, extractASCII]
|
||||
);
|
||||
}
|
||||
|
||||
export function parseISODuration(s) {
|
||||
return parse(s, [isoDuration, extractISODuration]);
|
||||
}
|
||||
|
||||
const extractISOTimeOnly = combineExtractors(extractISOTime);
|
||||
|
||||
export function parseISOTimeOnly(s) {
|
||||
return parse(s, [isoTimeOnly, extractISOTimeOnly]);
|
||||
}
|
||||
|
||||
const sqlYmdWithTimeExtensionRegex = combineRegexes(sqlYmdRegex, sqlTimeExtensionRegex);
|
||||
const sqlTimeCombinedRegex = combineRegexes(sqlTimeRegex);
|
||||
|
||||
const extractISOTimeOffsetAndIANAZone = combineExtractors(
|
||||
extractISOTime,
|
||||
extractISOOffset,
|
||||
extractIANAZone
|
||||
);
|
||||
|
||||
export function parseSQL(s) {
|
||||
return parse(
|
||||
s,
|
||||
[sqlYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
|
||||
[sqlTimeCombinedRegex, extractISOTimeOffsetAndIANAZone]
|
||||
);
|
||||
}
|
||||
505
node_modules/luxon/src/impl/tokenParser.js
generated
vendored
Normal file
505
node_modules/luxon/src/impl/tokenParser.js
generated
vendored
Normal file
@@ -0,0 +1,505 @@
|
||||
import { parseMillis, isUndefined, untruncateYear, signedOffset, hasOwnProperty } from "./util.js";
|
||||
import Formatter from "./formatter.js";
|
||||
import FixedOffsetZone from "../zones/fixedOffsetZone.js";
|
||||
import IANAZone from "../zones/IANAZone.js";
|
||||
import DateTime from "../datetime.js";
|
||||
import { digitRegex, parseDigits } from "./digits.js";
|
||||
import { ConflictingSpecificationError } from "../errors.js";
|
||||
|
||||
const MISSING_FTP = "missing Intl.DateTimeFormat.formatToParts support";
|
||||
|
||||
function intUnit(regex, post = (i) => i) {
|
||||
return { regex, deser: ([s]) => post(parseDigits(s)) };
|
||||
}
|
||||
|
||||
const NBSP = String.fromCharCode(160);
|
||||
const spaceOrNBSP = `[ ${NBSP}]`;
|
||||
const spaceOrNBSPRegExp = new RegExp(spaceOrNBSP, "g");
|
||||
|
||||
function fixListRegex(s) {
|
||||
// make dots optional and also make them literal
|
||||
// make space and non breakable space characters interchangeable
|
||||
return s.replace(/\./g, "\\.?").replace(spaceOrNBSPRegExp, spaceOrNBSP);
|
||||
}
|
||||
|
||||
function stripInsensitivities(s) {
|
||||
return s
|
||||
.replace(/\./g, "") // ignore dots that were made optional
|
||||
.replace(spaceOrNBSPRegExp, " ") // interchange space and nbsp
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
function oneOf(strings, startIndex) {
|
||||
if (strings === null) {
|
||||
return null;
|
||||
} else {
|
||||
return {
|
||||
regex: RegExp(strings.map(fixListRegex).join("|")),
|
||||
deser: ([s]) =>
|
||||
strings.findIndex((i) => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function offset(regex, groups) {
|
||||
return { regex, deser: ([, h, m]) => signedOffset(h, m), groups };
|
||||
}
|
||||
|
||||
function simple(regex) {
|
||||
return { regex, deser: ([s]) => s };
|
||||
}
|
||||
|
||||
function escapeToken(value) {
|
||||
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @param {Locale} loc
|
||||
*/
|
||||
function unitForToken(token, loc) {
|
||||
const one = digitRegex(loc),
|
||||
two = digitRegex(loc, "{2}"),
|
||||
three = digitRegex(loc, "{3}"),
|
||||
four = digitRegex(loc, "{4}"),
|
||||
six = digitRegex(loc, "{6}"),
|
||||
oneOrTwo = digitRegex(loc, "{1,2}"),
|
||||
oneToThree = digitRegex(loc, "{1,3}"),
|
||||
oneToSix = digitRegex(loc, "{1,6}"),
|
||||
oneToNine = digitRegex(loc, "{1,9}"),
|
||||
twoToFour = digitRegex(loc, "{2,4}"),
|
||||
fourToSix = digitRegex(loc, "{4,6}"),
|
||||
literal = (t) => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }),
|
||||
unitate = (t) => {
|
||||
if (token.literal) {
|
||||
return literal(t);
|
||||
}
|
||||
switch (t.val) {
|
||||
// era
|
||||
case "G":
|
||||
return oneOf(loc.eras("short"), 0);
|
||||
case "GG":
|
||||
return oneOf(loc.eras("long"), 0);
|
||||
// years
|
||||
case "y":
|
||||
return intUnit(oneToSix);
|
||||
case "yy":
|
||||
return intUnit(twoToFour, untruncateYear);
|
||||
case "yyyy":
|
||||
return intUnit(four);
|
||||
case "yyyyy":
|
||||
return intUnit(fourToSix);
|
||||
case "yyyyyy":
|
||||
return intUnit(six);
|
||||
// months
|
||||
case "M":
|
||||
return intUnit(oneOrTwo);
|
||||
case "MM":
|
||||
return intUnit(two);
|
||||
case "MMM":
|
||||
return oneOf(loc.months("short", true), 1);
|
||||
case "MMMM":
|
||||
return oneOf(loc.months("long", true), 1);
|
||||
case "L":
|
||||
return intUnit(oneOrTwo);
|
||||
case "LL":
|
||||
return intUnit(two);
|
||||
case "LLL":
|
||||
return oneOf(loc.months("short", false), 1);
|
||||
case "LLLL":
|
||||
return oneOf(loc.months("long", false), 1);
|
||||
// dates
|
||||
case "d":
|
||||
return intUnit(oneOrTwo);
|
||||
case "dd":
|
||||
return intUnit(two);
|
||||
// ordinals
|
||||
case "o":
|
||||
return intUnit(oneToThree);
|
||||
case "ooo":
|
||||
return intUnit(three);
|
||||
// time
|
||||
case "HH":
|
||||
return intUnit(two);
|
||||
case "H":
|
||||
return intUnit(oneOrTwo);
|
||||
case "hh":
|
||||
return intUnit(two);
|
||||
case "h":
|
||||
return intUnit(oneOrTwo);
|
||||
case "mm":
|
||||
return intUnit(two);
|
||||
case "m":
|
||||
return intUnit(oneOrTwo);
|
||||
case "q":
|
||||
return intUnit(oneOrTwo);
|
||||
case "qq":
|
||||
return intUnit(two);
|
||||
case "s":
|
||||
return intUnit(oneOrTwo);
|
||||
case "ss":
|
||||
return intUnit(two);
|
||||
case "S":
|
||||
return intUnit(oneToThree);
|
||||
case "SSS":
|
||||
return intUnit(three);
|
||||
case "u":
|
||||
return simple(oneToNine);
|
||||
case "uu":
|
||||
return simple(oneOrTwo);
|
||||
case "uuu":
|
||||
return intUnit(one);
|
||||
// meridiem
|
||||
case "a":
|
||||
return oneOf(loc.meridiems(), 0);
|
||||
// weekYear (k)
|
||||
case "kkkk":
|
||||
return intUnit(four);
|
||||
case "kk":
|
||||
return intUnit(twoToFour, untruncateYear);
|
||||
// weekNumber (W)
|
||||
case "W":
|
||||
return intUnit(oneOrTwo);
|
||||
case "WW":
|
||||
return intUnit(two);
|
||||
// weekdays
|
||||
case "E":
|
||||
case "c":
|
||||
return intUnit(one);
|
||||
case "EEE":
|
||||
return oneOf(loc.weekdays("short", false), 1);
|
||||
case "EEEE":
|
||||
return oneOf(loc.weekdays("long", false), 1);
|
||||
case "ccc":
|
||||
return oneOf(loc.weekdays("short", true), 1);
|
||||
case "cccc":
|
||||
return oneOf(loc.weekdays("long", true), 1);
|
||||
// offset/zone
|
||||
case "Z":
|
||||
case "ZZ":
|
||||
return offset(new RegExp(`([+-]${oneOrTwo.source})(?::(${two.source}))?`), 2);
|
||||
case "ZZZ":
|
||||
return offset(new RegExp(`([+-]${oneOrTwo.source})(${two.source})?`), 2);
|
||||
// we don't support ZZZZ (PST) or ZZZZZ (Pacific Standard Time) in parsing
|
||||
// because we don't have any way to figure out what they are
|
||||
case "z":
|
||||
return simple(/[a-z_+-/]{1,256}?/i);
|
||||
// this special-case "token" represents a place where a macro-token expanded into a white-space literal
|
||||
// in this case we accept any non-newline white-space
|
||||
case " ":
|
||||
return simple(/[^\S\n\r]/);
|
||||
default:
|
||||
return literal(t);
|
||||
}
|
||||
};
|
||||
|
||||
const unit = unitate(token) || {
|
||||
invalidReason: MISSING_FTP,
|
||||
};
|
||||
|
||||
unit.token = token;
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
const partTypeStyleToTokenVal = {
|
||||
year: {
|
||||
"2-digit": "yy",
|
||||
numeric: "yyyyy",
|
||||
},
|
||||
month: {
|
||||
numeric: "M",
|
||||
"2-digit": "MM",
|
||||
short: "MMM",
|
||||
long: "MMMM",
|
||||
},
|
||||
day: {
|
||||
numeric: "d",
|
||||
"2-digit": "dd",
|
||||
},
|
||||
weekday: {
|
||||
short: "EEE",
|
||||
long: "EEEE",
|
||||
},
|
||||
dayperiod: "a",
|
||||
dayPeriod: "a",
|
||||
hour12: {
|
||||
numeric: "h",
|
||||
"2-digit": "hh",
|
||||
},
|
||||
hour24: {
|
||||
numeric: "H",
|
||||
"2-digit": "HH",
|
||||
},
|
||||
minute: {
|
||||
numeric: "m",
|
||||
"2-digit": "mm",
|
||||
},
|
||||
second: {
|
||||
numeric: "s",
|
||||
"2-digit": "ss",
|
||||
},
|
||||
timeZoneName: {
|
||||
long: "ZZZZZ",
|
||||
short: "ZZZ",
|
||||
},
|
||||
};
|
||||
|
||||
function tokenForPart(part, formatOpts, resolvedOpts) {
|
||||
const { type, value } = part;
|
||||
|
||||
if (type === "literal") {
|
||||
const isSpace = /^\s+$/.test(value);
|
||||
return {
|
||||
literal: !isSpace,
|
||||
val: isSpace ? " " : value,
|
||||
};
|
||||
}
|
||||
|
||||
const style = formatOpts[type];
|
||||
|
||||
// The user might have explicitly specified hour12 or hourCycle
|
||||
// if so, respect their decision
|
||||
// if not, refer back to the resolvedOpts, which are based on the locale
|
||||
let actualType = type;
|
||||
if (type === "hour") {
|
||||
if (formatOpts.hour12 != null) {
|
||||
actualType = formatOpts.hour12 ? "hour12" : "hour24";
|
||||
} else if (formatOpts.hourCycle != null) {
|
||||
if (formatOpts.hourCycle === "h11" || formatOpts.hourCycle === "h12") {
|
||||
actualType = "hour12";
|
||||
} else {
|
||||
actualType = "hour24";
|
||||
}
|
||||
} else {
|
||||
// tokens only differentiate between 24 hours or not,
|
||||
// so we do not need to check hourCycle here, which is less supported anyways
|
||||
actualType = resolvedOpts.hour12 ? "hour12" : "hour24";
|
||||
}
|
||||
}
|
||||
let val = partTypeStyleToTokenVal[actualType];
|
||||
if (typeof val === "object") {
|
||||
val = val[style];
|
||||
}
|
||||
|
||||
if (val) {
|
||||
return {
|
||||
literal: false,
|
||||
val,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function buildRegex(units) {
|
||||
const re = units.map((u) => u.regex).reduce((f, r) => `${f}(${r.source})`, "");
|
||||
return [`^${re}$`, units];
|
||||
}
|
||||
|
||||
function match(input, regex, handlers) {
|
||||
const matches = input.match(regex);
|
||||
|
||||
if (matches) {
|
||||
const all = {};
|
||||
let matchIndex = 1;
|
||||
for (const i in handlers) {
|
||||
if (hasOwnProperty(handlers, i)) {
|
||||
const h = handlers[i],
|
||||
groups = h.groups ? h.groups + 1 : 1;
|
||||
if (!h.literal && h.token) {
|
||||
all[h.token.val[0]] = h.deser(matches.slice(matchIndex, matchIndex + groups));
|
||||
}
|
||||
matchIndex += groups;
|
||||
}
|
||||
}
|
||||
return [matches, all];
|
||||
} else {
|
||||
return [matches, {}];
|
||||
}
|
||||
}
|
||||
|
||||
function dateTimeFromMatches(matches) {
|
||||
const toField = (token) => {
|
||||
switch (token) {
|
||||
case "S":
|
||||
return "millisecond";
|
||||
case "s":
|
||||
return "second";
|
||||
case "m":
|
||||
return "minute";
|
||||
case "h":
|
||||
case "H":
|
||||
return "hour";
|
||||
case "d":
|
||||
return "day";
|
||||
case "o":
|
||||
return "ordinal";
|
||||
case "L":
|
||||
case "M":
|
||||
return "month";
|
||||
case "y":
|
||||
return "year";
|
||||
case "E":
|
||||
case "c":
|
||||
return "weekday";
|
||||
case "W":
|
||||
return "weekNumber";
|
||||
case "k":
|
||||
return "weekYear";
|
||||
case "q":
|
||||
return "quarter";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
let zone = null;
|
||||
let specificOffset;
|
||||
if (!isUndefined(matches.z)) {
|
||||
zone = IANAZone.create(matches.z);
|
||||
}
|
||||
|
||||
if (!isUndefined(matches.Z)) {
|
||||
if (!zone) {
|
||||
zone = new FixedOffsetZone(matches.Z);
|
||||
}
|
||||
specificOffset = matches.Z;
|
||||
}
|
||||
|
||||
if (!isUndefined(matches.q)) {
|
||||
matches.M = (matches.q - 1) * 3 + 1;
|
||||
}
|
||||
|
||||
if (!isUndefined(matches.h)) {
|
||||
if (matches.h < 12 && matches.a === 1) {
|
||||
matches.h += 12;
|
||||
} else if (matches.h === 12 && matches.a === 0) {
|
||||
matches.h = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches.G === 0 && matches.y) {
|
||||
matches.y = -matches.y;
|
||||
}
|
||||
|
||||
if (!isUndefined(matches.u)) {
|
||||
matches.S = parseMillis(matches.u);
|
||||
}
|
||||
|
||||
const vals = Object.keys(matches).reduce((r, k) => {
|
||||
const f = toField(k);
|
||||
if (f) {
|
||||
r[f] = matches[k];
|
||||
}
|
||||
|
||||
return r;
|
||||
}, {});
|
||||
|
||||
return [vals, zone, specificOffset];
|
||||
}
|
||||
|
||||
let dummyDateTimeCache = null;
|
||||
|
||||
function getDummyDateTime() {
|
||||
if (!dummyDateTimeCache) {
|
||||
dummyDateTimeCache = DateTime.fromMillis(1555555555555);
|
||||
}
|
||||
|
||||
return dummyDateTimeCache;
|
||||
}
|
||||
|
||||
function maybeExpandMacroToken(token, locale) {
|
||||
if (token.literal) {
|
||||
return token;
|
||||
}
|
||||
|
||||
const formatOpts = Formatter.macroTokenToFormatOpts(token.val);
|
||||
const tokens = formatOptsToTokens(formatOpts, locale);
|
||||
|
||||
if (tokens == null || tokens.includes(undefined)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
export function expandMacroTokens(tokens, locale) {
|
||||
return Array.prototype.concat(...tokens.map((t) => maybeExpandMacroToken(t, locale)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
export class TokenParser {
|
||||
constructor(locale, format) {
|
||||
this.locale = locale;
|
||||
this.format = format;
|
||||
this.tokens = expandMacroTokens(Formatter.parseFormat(format), locale);
|
||||
this.units = this.tokens.map((t) => unitForToken(t, locale));
|
||||
this.disqualifyingUnit = this.units.find((t) => t.invalidReason);
|
||||
|
||||
if (!this.disqualifyingUnit) {
|
||||
const [regexString, handlers] = buildRegex(this.units);
|
||||
this.regex = RegExp(regexString, "i");
|
||||
this.handlers = handlers;
|
||||
}
|
||||
}
|
||||
|
||||
explainFromTokens(input) {
|
||||
if (!this.isValid) {
|
||||
return { input, tokens: this.tokens, invalidReason: this.invalidReason };
|
||||
} else {
|
||||
const [rawMatches, matches] = match(input, this.regex, this.handlers),
|
||||
[result, zone, specificOffset] = matches
|
||||
? dateTimeFromMatches(matches)
|
||||
: [null, null, undefined];
|
||||
if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) {
|
||||
throw new ConflictingSpecificationError(
|
||||
"Can't include meridiem when specifying 24-hour format"
|
||||
);
|
||||
}
|
||||
return {
|
||||
input,
|
||||
tokens: this.tokens,
|
||||
regex: this.regex,
|
||||
rawMatches,
|
||||
matches,
|
||||
result,
|
||||
zone,
|
||||
specificOffset,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get isValid() {
|
||||
return !this.disqualifyingUnit;
|
||||
}
|
||||
|
||||
get invalidReason() {
|
||||
return this.disqualifyingUnit ? this.disqualifyingUnit.invalidReason : null;
|
||||
}
|
||||
}
|
||||
|
||||
export function explainFromTokens(locale, input, format) {
|
||||
const parser = new TokenParser(locale, format);
|
||||
return parser.explainFromTokens(input);
|
||||
}
|
||||
|
||||
export function parseFromTokens(locale, input, format) {
|
||||
const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format);
|
||||
return [result, zone, specificOffset, invalidReason];
|
||||
}
|
||||
|
||||
export function formatOptsToTokens(formatOpts, locale) {
|
||||
if (!formatOpts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const formatter = Formatter.create(locale, formatOpts);
|
||||
const df = formatter.dtFormatter(getDummyDateTime());
|
||||
const parts = df.formatToParts();
|
||||
const resolvedOpts = df.resolvedOptions();
|
||||
return parts.map((p) => tokenForPart(p, formatOpts, resolvedOpts));
|
||||
}
|
||||
330
node_modules/luxon/src/impl/util.js
generated
vendored
Normal file
330
node_modules/luxon/src/impl/util.js
generated
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
This is just a junk drawer, containing anything used across multiple classes.
|
||||
Because Luxon is small(ish), this should stay small and we won't worry about splitting
|
||||
it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
|
||||
*/
|
||||
|
||||
import { InvalidArgumentError } from "../errors.js";
|
||||
import Settings from "../settings.js";
|
||||
import { dayOfWeek, isoWeekdayToLocal } from "./conversions.js";
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
// TYPES
|
||||
|
||||
export function isUndefined(o) {
|
||||
return typeof o === "undefined";
|
||||
}
|
||||
|
||||
export function isNumber(o) {
|
||||
return typeof o === "number";
|
||||
}
|
||||
|
||||
export function isInteger(o) {
|
||||
return typeof o === "number" && o % 1 === 0;
|
||||
}
|
||||
|
||||
export function isString(o) {
|
||||
return typeof o === "string";
|
||||
}
|
||||
|
||||
export function isDate(o) {
|
||||
return Object.prototype.toString.call(o) === "[object Date]";
|
||||
}
|
||||
|
||||
// CAPABILITIES
|
||||
|
||||
export function hasRelative() {
|
||||
try {
|
||||
return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasLocaleWeekInfo() {
|
||||
try {
|
||||
return (
|
||||
typeof Intl !== "undefined" &&
|
||||
!!Intl.Locale &&
|
||||
("weekInfo" in Intl.Locale.prototype || "getWeekInfo" in Intl.Locale.prototype)
|
||||
);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// OBJECTS AND ARRAYS
|
||||
|
||||
export function maybeArray(thing) {
|
||||
return Array.isArray(thing) ? thing : [thing];
|
||||
}
|
||||
|
||||
export function bestBy(arr, by, compare) {
|
||||
if (arr.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return arr.reduce((best, next) => {
|
||||
const pair = [by(next), next];
|
||||
if (!best) {
|
||||
return pair;
|
||||
} else if (compare(best[0], pair[0]) === best[0]) {
|
||||
return best;
|
||||
} else {
|
||||
return pair;
|
||||
}
|
||||
}, null)[1];
|
||||
}
|
||||
|
||||
export function pick(obj, keys) {
|
||||
return keys.reduce((a, k) => {
|
||||
a[k] = obj[k];
|
||||
return a;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function hasOwnProperty(obj, prop) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||
}
|
||||
|
||||
export function validateWeekSettings(settings) {
|
||||
if (settings == null) {
|
||||
return null;
|
||||
} else if (typeof settings !== "object") {
|
||||
throw new InvalidArgumentError("Week settings must be an object");
|
||||
} else {
|
||||
if (
|
||||
!integerBetween(settings.firstDay, 1, 7) ||
|
||||
!integerBetween(settings.minimalDays, 1, 7) ||
|
||||
!Array.isArray(settings.weekend) ||
|
||||
settings.weekend.some((v) => !integerBetween(v, 1, 7))
|
||||
) {
|
||||
throw new InvalidArgumentError("Invalid week settings");
|
||||
}
|
||||
return {
|
||||
firstDay: settings.firstDay,
|
||||
minimalDays: settings.minimalDays,
|
||||
weekend: Array.from(settings.weekend),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// NUMBERS AND STRINGS
|
||||
|
||||
export function integerBetween(thing, bottom, top) {
|
||||
return isInteger(thing) && thing >= bottom && thing <= top;
|
||||
}
|
||||
|
||||
// x % n but takes the sign of n instead of x
|
||||
export function floorMod(x, n) {
|
||||
return x - n * Math.floor(x / n);
|
||||
}
|
||||
|
||||
export function padStart(input, n = 2) {
|
||||
const isNeg = input < 0;
|
||||
let padded;
|
||||
if (isNeg) {
|
||||
padded = "-" + ("" + -input).padStart(n, "0");
|
||||
} else {
|
||||
padded = ("" + input).padStart(n, "0");
|
||||
}
|
||||
return padded;
|
||||
}
|
||||
|
||||
export function parseInteger(string) {
|
||||
if (isUndefined(string) || string === null || string === "") {
|
||||
return undefined;
|
||||
} else {
|
||||
return parseInt(string, 10);
|
||||
}
|
||||
}
|
||||
|
||||
export function parseFloating(string) {
|
||||
if (isUndefined(string) || string === null || string === "") {
|
||||
return undefined;
|
||||
} else {
|
||||
return parseFloat(string);
|
||||
}
|
||||
}
|
||||
|
||||
export function parseMillis(fraction) {
|
||||
// Return undefined (instead of 0) in these cases, where fraction is not set
|
||||
if (isUndefined(fraction) || fraction === null || fraction === "") {
|
||||
return undefined;
|
||||
} else {
|
||||
const f = parseFloat("0." + fraction) * 1000;
|
||||
return Math.floor(f);
|
||||
}
|
||||
}
|
||||
|
||||
export function roundTo(number, digits, rounding = "round") {
|
||||
const factor = 10 ** digits;
|
||||
switch (rounding) {
|
||||
case "expand":
|
||||
return number > 0
|
||||
? Math.ceil(number * factor) / factor
|
||||
: Math.floor(number * factor) / factor;
|
||||
case "trunc":
|
||||
return Math.trunc(number * factor) / factor;
|
||||
case "round":
|
||||
return Math.round(number * factor) / factor;
|
||||
case "floor":
|
||||
return Math.floor(number * factor) / factor;
|
||||
case "ceil":
|
||||
return Math.ceil(number * factor) / factor;
|
||||
default:
|
||||
throw new RangeError(`Value rounding ${rounding} is out of range`);
|
||||
}
|
||||
}
|
||||
|
||||
// DATE BASICS
|
||||
|
||||
export function isLeapYear(year) {
|
||||
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
||||
}
|
||||
|
||||
export function daysInYear(year) {
|
||||
return isLeapYear(year) ? 366 : 365;
|
||||
}
|
||||
|
||||
export function daysInMonth(year, month) {
|
||||
const modMonth = floorMod(month - 1, 12) + 1,
|
||||
modYear = year + (month - modMonth) / 12;
|
||||
|
||||
if (modMonth === 2) {
|
||||
return isLeapYear(modYear) ? 29 : 28;
|
||||
} else {
|
||||
return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// convert a calendar object to a local timestamp (epoch, but with the offset baked in)
|
||||
export function objToLocalTS(obj) {
|
||||
let d = Date.UTC(
|
||||
obj.year,
|
||||
obj.month - 1,
|
||||
obj.day,
|
||||
obj.hour,
|
||||
obj.minute,
|
||||
obj.second,
|
||||
obj.millisecond
|
||||
);
|
||||
|
||||
// for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
|
||||
if (obj.year < 100 && obj.year >= 0) {
|
||||
d = new Date(d);
|
||||
// set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not
|
||||
// so if obj.year is in 99, but obj.day makes it roll over into year 100,
|
||||
// the calculations done by Date.UTC are using year 2000 - which is incorrect
|
||||
d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
|
||||
}
|
||||
return +d;
|
||||
}
|
||||
|
||||
// adapted from moment.js: https://github.com/moment/moment/blob/000ac1800e620f770f4eb31b5ae908f6167b0ab2/src/lib/units/week-calendar-utils.js
|
||||
function firstWeekOffset(year, minDaysInFirstWeek, startOfWeek) {
|
||||
const fwdlw = isoWeekdayToLocal(dayOfWeek(year, 1, minDaysInFirstWeek), startOfWeek);
|
||||
return -fwdlw + minDaysInFirstWeek - 1;
|
||||
}
|
||||
|
||||
export function weeksInWeekYear(weekYear, minDaysInFirstWeek = 4, startOfWeek = 1) {
|
||||
const weekOffset = firstWeekOffset(weekYear, minDaysInFirstWeek, startOfWeek);
|
||||
const weekOffsetNext = firstWeekOffset(weekYear + 1, minDaysInFirstWeek, startOfWeek);
|
||||
return (daysInYear(weekYear) - weekOffset + weekOffsetNext) / 7;
|
||||
}
|
||||
|
||||
export function untruncateYear(year) {
|
||||
if (year > 99) {
|
||||
return year;
|
||||
} else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
|
||||
}
|
||||
|
||||
// PARSING
|
||||
|
||||
export function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
|
||||
const date = new Date(ts),
|
||||
intlOpts = {
|
||||
hourCycle: "h23",
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
};
|
||||
|
||||
if (timeZone) {
|
||||
intlOpts.timeZone = timeZone;
|
||||
}
|
||||
|
||||
const modified = { timeZoneName: offsetFormat, ...intlOpts };
|
||||
|
||||
const parsed = new Intl.DateTimeFormat(locale, modified)
|
||||
.formatToParts(date)
|
||||
.find((m) => m.type.toLowerCase() === "timezonename");
|
||||
return parsed ? parsed.value : null;
|
||||
}
|
||||
|
||||
// signedOffset('-5', '30') -> -330
|
||||
export function signedOffset(offHourStr, offMinuteStr) {
|
||||
let offHour = parseInt(offHourStr, 10);
|
||||
|
||||
// don't || this because we want to preserve -0
|
||||
if (Number.isNaN(offHour)) {
|
||||
offHour = 0;
|
||||
}
|
||||
|
||||
const offMin = parseInt(offMinuteStr, 10) || 0,
|
||||
offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
|
||||
return offHour * 60 + offMinSigned;
|
||||
}
|
||||
|
||||
// COERCION
|
||||
|
||||
export function asNumber(value) {
|
||||
const numericValue = Number(value);
|
||||
if (typeof value === "boolean" || value === "" || !Number.isFinite(numericValue))
|
||||
throw new InvalidArgumentError(`Invalid unit value ${value}`);
|
||||
return numericValue;
|
||||
}
|
||||
|
||||
export function normalizeObject(obj, normalizer) {
|
||||
const normalized = {};
|
||||
for (const u in obj) {
|
||||
if (hasOwnProperty(obj, u)) {
|
||||
const v = obj[u];
|
||||
if (v === undefined || v === null) continue;
|
||||
normalized[normalizer(u)] = asNumber(v);
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset's value as a string
|
||||
* @param {number} ts - Epoch milliseconds for which to get the offset
|
||||
* @param {string} format - What style of offset to return.
|
||||
* Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
|
||||
* @return {string}
|
||||
*/
|
||||
export function formatOffset(offset, format) {
|
||||
const hours = Math.trunc(Math.abs(offset / 60)),
|
||||
minutes = Math.trunc(Math.abs(offset % 60)),
|
||||
sign = offset >= 0 ? "+" : "-";
|
||||
|
||||
switch (format) {
|
||||
case "short":
|
||||
return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
|
||||
case "narrow":
|
||||
return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
|
||||
case "techie":
|
||||
return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
|
||||
default:
|
||||
throw new RangeError(`Value format ${format} is out of range for property format`);
|
||||
}
|
||||
}
|
||||
|
||||
export function timeObject(obj) {
|
||||
return pick(obj, ["hour", "minute", "second", "millisecond"]);
|
||||
}
|
||||
34
node_modules/luxon/src/impl/zoneUtil.js
generated
vendored
Normal file
34
node_modules/luxon/src/impl/zoneUtil.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
import Zone from "../zone.js";
|
||||
import IANAZone from "../zones/IANAZone.js";
|
||||
import FixedOffsetZone from "../zones/fixedOffsetZone.js";
|
||||
import InvalidZone from "../zones/invalidZone.js";
|
||||
|
||||
import { isUndefined, isString, isNumber } from "./util.js";
|
||||
import SystemZone from "../zones/systemZone.js";
|
||||
|
||||
export function normalizeZone(input, defaultZone) {
|
||||
let offset;
|
||||
if (isUndefined(input) || input === null) {
|
||||
return defaultZone;
|
||||
} else if (input instanceof Zone) {
|
||||
return input;
|
||||
} else if (isString(input)) {
|
||||
const lowered = input.toLowerCase();
|
||||
if (lowered === "default") return defaultZone;
|
||||
else if (lowered === "local" || lowered === "system") return SystemZone.instance;
|
||||
else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance;
|
||||
else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input);
|
||||
} else if (isNumber(input)) {
|
||||
return FixedOffsetZone.instance(input);
|
||||
} else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") {
|
||||
// This is dumb, but the instanceof check above doesn't seem to really work
|
||||
// so we're duck checking it
|
||||
return input;
|
||||
} else {
|
||||
return new InvalidZone(input);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user