diff options
Diffstat (limited to 'npm_assets/node_modules/luxon/src/impl')
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/conversions.js | 157 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/diff.js | 79 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/digits.js | 76 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/english.js | 233 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/formats.js | 191 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/formatter.js | 386 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/invalid.js | 14 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/locale.js | 469 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/regexParser.js | 319 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/tokenParser.js | 424 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/util.js | 286 | ||||
| -rw-r--r-- | npm_assets/node_modules/luxon/src/impl/zoneUtil.js | 36 |
12 files changed, 2670 insertions, 0 deletions
diff --git a/npm_assets/node_modules/luxon/src/impl/conversions.js b/npm_assets/node_modules/luxon/src/impl/conversions.js new file mode 100644 index 0000000..cbe7172 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/conversions.js @@ -0,0 +1,157 @@ +import { + integerBetween, + isLeapYear, + timeObject, + daysInYear, + daysInMonth, + weeksInWeekYear, + isInteger +} from "./util.js"; +import Invalid from "./invalid.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` + ); +} + +function dayOfWeek(year, month, day) { + const js = new Date(Date.UTC(year, month - 1, day)).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 }; +} + +/** + * @private + */ + +export function gregorianToWeek(gregObj) { + const { year, month, day } = gregObj, + ordinal = computeOrdinal(year, month, day), + weekday = dayOfWeek(year, month, day); + + let weekNumber = Math.floor((ordinal - weekday + 10) / 7), + weekYear; + + if (weekNumber < 1) { + weekYear = year - 1; + weekNumber = weeksInWeekYear(weekYear); + } else if (weekNumber > weeksInWeekYear(year)) { + weekYear = year + 1; + weekNumber = 1; + } else { + weekYear = year; + } + + return Object.assign({ weekYear, weekNumber, weekday }, timeObject(gregObj)); +} + +export function weekToGregorian(weekData) { + const { weekYear, weekNumber, weekday } = weekData, + weekdayOfJan4 = dayOfWeek(weekYear, 1, 4), + yearInDays = daysInYear(weekYear); + + let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 3, + 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 Object.assign({ year, month, day }, timeObject(weekData)); +} + +export function gregorianToOrdinal(gregData) { + const { year, month, day } = gregData, + ordinal = computeOrdinal(year, month, day); + + return Object.assign({ year, ordinal }, timeObject(gregData)); +} + +export function ordinalToGregorian(ordinalData) { + const { year, ordinal } = ordinalData, + { month, day } = uncomputeOrdinal(year, ordinal); + + return Object.assign({ year, month, day }, timeObject(ordinalData)); +} + +export function hasInvalidWeekData(obj) { + const validYear = isInteger(obj.weekYear), + validWeek = integerBetween(obj.weekNumber, 1, weeksInWeekYear(obj.weekYear)), + validWeekday = integerBetween(obj.weekday, 1, 7); + + if (!validYear) { + return unitOutOfRange("weekYear", obj.weekYear); + } else if (!validWeek) { + return unitOutOfRange("week", obj.week); + } 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; +} diff --git a/npm_assets/node_modules/luxon/src/impl/diff.js b/npm_assets/node_modules/luxon/src/impl/diff.js new file mode 100644 index 0000000..57246dc --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/diff.js @@ -0,0 +1,79 @@ +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], + ["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 = {}; + let lowestOrder, highWater; + + for (const [unit, differ] of differs) { + if (units.indexOf(unit) >= 0) { + lowestOrder = unit; + + let delta = differ(cursor, later); + highWater = cursor.plus({ [unit]: delta }); + + if (highWater > later) { + cursor = cursor.plus({ [unit]: delta - 1 }); + delta -= 1; + } else { + cursor = highWater; + } + + results[unit] = delta; + } + } + + 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(Object.assign(results, opts)); + + if (lowerOrderUnits.length > 0) { + return Duration.fromMillis(remainingMillis, opts) + .shiftTo(...lowerOrderUnits) + .plus(duration); + } else { + return duration; + } +} diff --git a/npm_assets/node_modules/luxon/src/impl/digits.js b/npm_assets/node_modules/luxon/src/impl/digits.js new file mode 100644 index 0000000..0d081c2 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/digits.js @@ -0,0 +1,76 @@ +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] +}; + +// eslint-disable-next-line +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; + } +} + +export function digitRegex({ numberingSystem }, append = "") { + return new RegExp(`${numberingSystems[numberingSystem || "latn"]}${append}`); +} diff --git a/npm_assets/node_modules/luxon/src/impl/english.js b/npm_assets/node_modules/luxon/src/impl/english.js new file mode 100644 index 0000000..633f594 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/english.js @@ -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", + "hour12" + ]), + 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; + } +} diff --git a/npm_assets/node_modules/luxon/src/impl/formats.js b/npm_assets/node_modules/luxon/src/impl/formats.js new file mode 100644 index 0000000..25210f6 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/formats.js @@ -0,0 +1,191 @@ +/** + * @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, + hour12: false +}; + +/** + * {@link toLocaleString}; format like '09:30:23', always 24-hour. + */ +export const TIME_24_WITH_SECONDS = { + hour: n, + minute: n, + second: n, + hour12: false +}; + +/** + * {@link toLocaleString}; format like '09:30:23 EDT', always 24-hour. + */ +export const TIME_24_WITH_SHORT_OFFSET = { + hour: n, + minute: n, + second: n, + hour12: false, + timeZoneName: s +}; + +/** + * {@link toLocaleString}; format like '09:30:23 Eastern Daylight Time', always 24-hour. + */ +export const TIME_24_WITH_LONG_OFFSET = { + hour: n, + minute: n, + second: n, + hour12: false, + timeZoneName: l +}; + +/** + * {@link toLocaleString}; format like '10/14/1983, 9:30 AM'. Only 12-hour if the locale is. + */ +export const DATETIME_SHORT = { + year: n, + month: n, + day: n, + hour: n, + minute: n +}; + +/** + * {@link toLocaleString}; format like '10/14/1983, 9:30:33 AM'. Only 12-hour if the locale is. + */ +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 +}; diff --git a/npm_assets/node_modules/luxon/src/impl/formatter.js b/npm_assets/node_modules/luxon/src/impl/formatter.js new file mode 100644 index 0000000..98872f9 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/formatter.js @@ -0,0 +1,386 @@ +import * as English from "./english.js"; +import * as Formats from "./formats.js"; +import { hasFormatToParts, 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) { + let current = null, + currentFull = "", + bracketed = false; + const splits = []; + for (let i = 0; i < fmt.length; i++) { + const c = fmt.charAt(i); + if (c === "'") { + if (currentFull.length > 0) { + splits.push({ literal: bracketed, val: 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: false, val: currentFull }); + } + currentFull = c; + current = c; + } + } + + if (currentFull.length > 0) { + splits.push({ literal: bracketed, 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, Object.assign({}, this.opts, opts)); + return df.format(); + } + + formatDateTime(dt, opts = {}) { + const df = this.loc.dtFormatter(dt, Object.assign({}, this.opts, opts)); + return df.format(); + } + + formatDateTimeParts(dt, opts = {}) { + const df = this.loc.dtFormatter(dt, Object.assign({}, this.opts, opts)); + return df.formatToParts(); + } + + resolvedOptions(dt, opts = {}) { + const df = this.loc.dtFormatter(dt, Object.assign({}, this.opts, opts)); + return df.resolvedOptions(); + } + + num(n, p = 0) { + // we get some perf out of doing this here, annoyingly + if (this.opts.forceSimple) { + return padStart(n, p); + } + + const opts = Object.assign({}, this.opts); + + if (p > 0) { + opts.padTo = p; + } + + return this.loc.numberFormatter(opts).format(n); + } + + formatDateTimeFromString(dt, fmt) { + const knownEnglish = this.loc.listingMode() === "en", + useDateTimeFormatter = + this.loc.outputCalendar && this.loc.outputCalendar !== "gregory" && hasFormatToParts(), + 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", hour12: true }, "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: http://cldr.unicode.org/translation/date-time#TOC-Stand-Alone-vs.-Format-Styles + 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); + // 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 "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 tokenToField = token => { + switch (token[0]) { + case "S": + return "millisecond"; + case "s": + return "second"; + case "m": + return "minute"; + case "h": + return "hour"; + case "d": + return "day"; + case "M": + return "month"; + case "y": + return "year"; + default: + return null; + } + }, + tokenToString = lildur => token => { + const mapped = tokenToField(token); + if (mapped) { + return this.num(lildur.get(mapped), token.length); + } 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)); + return stringifyTokens(tokens, tokenToString(collapsed)); + } +} diff --git a/npm_assets/node_modules/luxon/src/impl/invalid.js b/npm_assets/node_modules/luxon/src/impl/invalid.js new file mode 100644 index 0000000..2a2c95b --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/invalid.js @@ -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; + } + } +} diff --git a/npm_assets/node_modules/luxon/src/impl/locale.js b/npm_assets/node_modules/luxon/src/impl/locale.js new file mode 100644 index 0000000..0f797b1 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/locale.js @@ -0,0 +1,469 @@ +import { hasFormatToParts, hasIntl, padStart, roundTo, hasRelative } from "./util.js"; +import * as English from "./english.js"; +import Settings from "../settings.js"; +import DateTime from "../datetime.js"; +import Formatter from "./formatter.js"; + +let intlDTCache = {}; +function getCachedDTF(locString, opts = {}) { + const key = JSON.stringify([locString, opts]); + let dtf = intlDTCache[key]; + if (!dtf) { + dtf = new Intl.DateTimeFormat(locString, opts); + intlDTCache[key] = dtf; + } + return dtf; +} + +let intlNumCache = {}; +function getCachedINF(locString, opts = {}) { + const key = JSON.stringify([locString, opts]); + let inf = intlNumCache[key]; + if (!inf) { + inf = new Intl.NumberFormat(locString, opts); + intlNumCache[key] = inf; + } + return inf; +} + +let intlRelCache = {}; +function getCachedRTF(locString, opts = {}) { + const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options + const key = JSON.stringify([locString, cacheKeyOpts]); + let inf = intlRelCache[key]; + if (!inf) { + inf = new Intl.RelativeTimeFormat(locString, opts); + intlRelCache[key] = inf; + } + return inf; +} + +let sysLocaleCache = null; +function systemLocale() { + if (sysLocaleCache) { + return sysLocaleCache; + } else if (hasIntl()) { + const computedSys = new Intl.DateTimeFormat().resolvedOptions().locale; + // node sometimes defaults to "und". Override that because that is dumb + sysLocaleCache = !computedSys || computedSys === "und" ? "en-US" : computedSys; + return sysLocaleCache; + } else { + sysLocaleCache = "en-US"; + return sysLocaleCache; + } +} + +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 + + const uIndex = localeStr.indexOf("-u-"); + if (uIndex === -1) { + return [localeStr]; + } else { + let options; + const smaller = localeStr.substring(0, uIndex); + try { + options = getCachedDTF(localeStr).resolvedOptions(); + } catch (e) { + options = getCachedDTF(smaller).resolvedOptions(); + } + + const { numberingSystem, calendar } = options; + // return the smaller one so that we can append the calendar and numbering overrides to it + return [smaller, numberingSystem, calendar]; + } +} + +function intlConfigString(localeStr, numberingSystem, outputCalendar) { + if (hasIntl()) { + if (outputCalendar || numberingSystem) { + localeStr += "-u"; + + if (outputCalendar) { + localeStr += `-ca-${outputCalendar}`; + } + + if (numberingSystem) { + localeStr += `-nu-${numberingSystem}`; + } + return localeStr; + } else { + return localeStr; + } + } else { + return []; + } +} + +function mapMonths(f) { + const ms = []; + for (let i = 1; i <= 12; i++) { + const dt = DateTime.utc(2016, 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, defaultOK, englishFn, intlFn) { + const mode = loc.listingMode(defaultOK); + + 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") || + (hasIntl() && new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn") + ); + } +} + +/** + * @private + */ + +class PolyNumberFormatter { + constructor(intl, forceSimple, opts) { + this.padTo = opts.padTo || 0; + this.floor = opts.floor || false; + + if (!forceSimple && hasIntl()) { + const intlOpts = { useGrouping: false }; + 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.hasIntl = hasIntl(); + + let z; + if (dt.zone.universal && this.hasIntl) { + // Chromium doesn't support fixed-offset zones like Etc/GMT+8 in its formatter, + // See https://bugs.chromium.org/p/chromium/issues/detail?id=364374. + // So we have to make do. Two cases: + // 1. The format options tell us to show the zone. We can't do that, so the best + // we can do is format the date in UTC. + // 2. The format options don't tell us to show the zone. Then we can adjust them + // the time and tell the formatter to show it to us in UTC, so that the time is right + // and the bad zone doesn't show up. + // We can clean all this up when Chrome fixes this. + z = "UTC"; + if (opts.timeZoneName) { + this.dt = dt; + } else { + this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000); + } + } else if (dt.zone.type === "local") { + this.dt = dt; + } else { + this.dt = dt; + z = dt.zone.name; + } + + if (this.hasIntl) { + const intlOpts = Object.assign({}, this.opts); + if (z) { + intlOpts.timeZone = z; + } + this.dtf = getCachedDTF(intl, intlOpts); + } + } + + format() { + if (this.hasIntl) { + return this.dtf.format(this.dt.toJSDate()); + } else { + const tokenFormat = English.formatString(this.opts), + loc = Locale.create("en-US"); + return Formatter.create(loc).formatDateTimeFromString(this.dt, tokenFormat); + } + } + + formatToParts() { + if (this.hasIntl && hasFormatToParts()) { + return this.dtf.formatToParts(this.dt.toJSDate()); + } else { + // This is kind of a cop out. We actually could do this for English. However, we couldn't do it for intl strings + // and IMO it's too weird to have an uncanny valley like that + return []; + } + } + + resolvedOptions() { + if (this.hasIntl) { + return this.dtf.resolvedOptions(); + } else { + return { + locale: "en-US", + numberingSystem: "latn", + outputCalendar: "gregory" + }; + } + } +} + +/** + * @private + */ +class PolyRelFormatter { + constructor(intl, isEnglish, opts) { + this.opts = Object.assign({ 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 []; + } + } +} + +/** + * @private + */ + +export default class Locale { + static fromOpts(opts) { + return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.defaultToEN); + } + + static create(locale, numberingSystem, outputCalendar, defaultToEN = false) { + const specifiedLocale = locale || Settings.defaultLocale, + // the system locale is useful for human readable strings but annoying for parsing/formatting known formats + localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale()), + numberingSystemR = numberingSystem || Settings.defaultNumberingSystem, + outputCalendarR = outputCalendar || Settings.defaultOutputCalendar; + return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale); + } + + static resetCache() { + sysLocaleCache = null; + intlDTCache = {}; + intlNumCache = {}; + intlRelCache = {}; + } + + static fromObject({ locale, numberingSystem, outputCalendar } = {}) { + return Locale.create(locale, numberingSystem, outputCalendar); + } + + constructor(locale, numbering, outputCalendar, specifiedLocale) { + const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale); + + this.locale = parsedLocale; + this.numberingSystem = numbering || parsedNumberingSystem || null; + this.outputCalendar = outputCalendar || parsedOutputCalendar || null; + 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(defaultOK = true) { + const intl = hasIntl(), + hasFTP = intl && hasFormatToParts(), + isActuallyEn = this.isEnglish(), + hasNoWeirdness = + (this.numberingSystem === null || this.numberingSystem === "latn") && + (this.outputCalendar === null || this.outputCalendar === "gregory"); + + if (!hasFTP && !(isActuallyEn && hasNoWeirdness) && !defaultOK) { + return "error"; + } else if (!hasFTP || (isActuallyEn && hasNoWeirdness)) { + return "en"; + } else { + return "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, + alts.defaultToEN || false + ); + } + } + + redefaultToEN(alts = {}) { + return this.clone(Object.assign({}, alts, { defaultToEN: true })); + } + + redefaultToSystem(alts = {}) { + return this.clone(Object.assign({}, alts, { defaultToEN: false })); + } + + months(length, format = false, defaultOK = true) { + return listStuff(this, length, defaultOK, English.months, () => { + const intl = format ? { month: length, day: "numeric" } : { month: length }, + formatStr = format ? "format" : "standalone"; + if (!this.monthsCache[formatStr][length]) { + this.monthsCache[formatStr][length] = mapMonths(dt => this.extract(dt, intl, "month")); + } + return this.monthsCache[formatStr][length]; + }); + } + + weekdays(length, format = false, defaultOK = true) { + return listStuff(this, length, defaultOK, 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(defaultOK = true) { + return listStuff( + this, + undefined, + defaultOK, + () => 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", hour12: true }; + 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, defaultOK = true) { + return listStuff(this, length, defaultOK, English.eras, () => { + const intl = { era: length }; + + // This is utter bullshit. 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); + } + + isEnglish() { + return ( + this.locale === "en" || + this.locale.toLowerCase() === "en-us" || + (hasIntl() && new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us")) + ); + } + + equals(other) { + return ( + this.locale === other.locale && + this.numberingSystem === other.numberingSystem && + this.outputCalendar === other.outputCalendar + ); + } +} diff --git a/npm_assets/node_modules/luxon/src/impl/regexParser.js b/npm_assets/node_modules/luxon/src/impl/regexParser.js new file mode 100644 index 0000000..74ba737 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/regexParser.js @@ -0,0 +1,319 @@ +import { + untruncateYear, + signedOffset, + parseInteger, + parseMillis, + ianaRegex, + isUndefined +} 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. + */ + +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 [Object.assign(mergedVals, val), mergedZone || zone, 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 = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/, + isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/, + isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${offsetRegex.source}?`), + isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`), + isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/, + isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/, + isoOrdinalRegex = /(\d{4})-?(\d{3})/, + extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay"), + extractISOOrdinalData = simpleParse("year", "ordinal"), + sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/, // dumbed-down version of the ISO one + sqlTimeRegex = RegExp( + `${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?` + ), + 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 = { + hour: int(match, cursor, 0), + minute: int(match, cursor + 1, 0), + second: int(match, cursor + 2, 0), + millisecond: 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 duration parsing + +const isoDuration = /^-?P(?:(?:(-?\d{1,9})Y)?(?:(-?\d{1,9})M)?(?:(-?\d{1,9})W)?(?:(-?\d{1,9})D)?(?:T(?:(-?\d{1,9})H)?(?:(-?\d{1,9})M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,9}))?S)?)?)$/; + +function extractISODuration(match) { + const [ + s, + yearStr, + monthStr, + weekStr, + dayStr, + hourStr, + minuteStr, + secondStr, + millisecondsStr + ] = match; + + const hasNegativePrefix = s[0] === "-"; + + const maybeNegate = num => (num && hasNegativePrefix ? -num : num); + + return [ + { + years: maybeNegate(parseInteger(yearStr)), + months: maybeNegate(parseInteger(monthStr)), + weeks: maybeNegate(parseInteger(weekStr)), + days: maybeNegate(parseInteger(dayStr)), + hours: maybeNegate(parseInteger(hourStr)), + minutes: maybeNegate(parseInteger(minuteStr)), + seconds: maybeNegate(parseInteger(secondStr)), + milliseconds: maybeNegate(parseMillis(millisecondsStr)) + } + ]; +} + +// 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|Wedsday|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 +); +const extractISOWeekTimeAndOffset = combineExtractors( + extractISOWeekData, + extractISOTime, + extractISOOffset +); +const extractISOOrdinalDataAndTime = combineExtractors(extractISOOrdinalData, extractISOTime); +const extractISOTimeAndOffset = combineExtractors(extractISOTime, extractISOOffset); + +/** + * @private + */ + +export function parseISODate(s) { + return parse( + s, + [isoYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset], + [isoWeekWithTimeExtensionRegex, extractISOWeekTimeAndOffset], + [isoOrdinalWithTimeExtensionRegex, extractISOOrdinalDataAndTime], + [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 sqlYmdWithTimeExtensionRegex = combineRegexes(sqlYmdRegex, sqlTimeExtensionRegex); +const sqlTimeCombinedRegex = combineRegexes(sqlTimeRegex); + +const extractISOYmdTimeOffsetAndIANAZone = combineExtractors( + extractISOYmd, + extractISOTime, + extractISOOffset, + extractIANAZone +); +const extractISOTimeOffsetAndIANAZone = combineExtractors( + extractISOTime, + extractISOOffset, + extractIANAZone +); + +export function parseSQL(s) { + return parse( + s, + [sqlYmdWithTimeExtensionRegex, extractISOYmdTimeOffsetAndIANAZone], + [sqlTimeCombinedRegex, extractISOTimeOffsetAndIANAZone] + ); +} diff --git a/npm_assets/node_modules/luxon/src/impl/tokenParser.js b/npm_assets/node_modules/luxon/src/impl/tokenParser.js new file mode 100644 index 0000000..4ca0401 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/tokenParser.js @@ -0,0 +1,424 @@ +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) { + // eslint-disable-next-line no-useless-escape + return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); +} + +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", false), 0); + case "GG": + return oneOf(loc.eras("long", false), 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, false), 1); + case "MMMM": + return oneOf(loc.months("long", true, false), 1); + case "L": + return intUnit(oneOrTwo); + case "LL": + return intUnit(two); + case "LLL": + return oneOf(loc.months("short", false, false), 1); + case "LLLL": + return oneOf(loc.months("long", false, 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); + // 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, false), 1); + case "EEEE": + return oneOf(loc.weekdays("long", false, false), 1); + case "ccc": + return oneOf(loc.weekdays("short", true, false), 1); + case "cccc": + return oneOf(loc.weekdays("long", true, false), 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); + 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", + hour: { + numeric: "h", + "2-digit": "hh" + }, + minute: { + numeric: "m", + "2-digit": "mm" + }, + second: { + numeric: "s", + "2-digit": "ss" + } +}; + +function tokenForPart(part, locale, formatOpts) { + const { type, value } = part; + + if (type === "literal") { + return { + literal: true, + val: value + }; + } + + const style = formatOpts[type]; + + let val = partTypeStyleToTokenVal[type]; + 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; + if (!isUndefined(matches.Z)) { + zone = new FixedOffsetZone(matches.Z); + } else if (!isUndefined(matches.z)) { + zone = IANAZone.create(matches.z); + } else { + zone = null; + } + + 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]; +} + +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); + + if (!formatOpts) { + return token; + } + + const formatter = Formatter.create(locale, formatOpts); + const parts = formatter.formatDateTimeParts(getDummyDateTime()); + + const tokens = parts.map(p => tokenForPart(p, locale, formatOpts)); + + if (tokens.includes(undefined)) { + return token; + } + + return tokens; +} + +function expandMacroTokens(tokens, locale) { + return Array.prototype.concat(...tokens.map(t => maybeExpandMacroToken(t, locale))); +} + +/** + * @private + */ + +export function explainFromTokens(locale, input, format) { + const tokens = expandMacroTokens(Formatter.parseFormat(format), locale), + units = tokens.map(t => unitForToken(t, locale)), + disqualifyingUnit = units.find(t => t.invalidReason); + + if (disqualifyingUnit) { + return { input, tokens, invalidReason: disqualifyingUnit.invalidReason }; + } else { + const [regexString, handlers] = buildRegex(units), + regex = RegExp(regexString, "i"), + [rawMatches, matches] = match(input, regex, handlers), + [result, zone] = matches ? dateTimeFromMatches(matches) : [null, null]; + if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) { + throw new ConflictingSpecificationError( + "Can't include meridiem when specifying 24-hour format" + ); + } + return { input, tokens, regex, rawMatches, matches, result, zone }; + } +} + +export function parseFromTokens(locale, input, format) { + const { result, zone, invalidReason } = explainFromTokens(locale, input, format); + return [result, zone, invalidReason]; +} diff --git a/npm_assets/node_modules/luxon/src/impl/util.js b/npm_assets/node_modules/luxon/src/impl/util.js new file mode 100644 index 0000000..b345c69 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/util.js @@ -0,0 +1,286 @@ +/* + 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"; + +/** + * @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 hasIntl() { + try { + return typeof Intl !== "undefined" && Intl.DateTimeFormat; + } catch (e) { + return false; + } +} + +export function hasFormatToParts() { + return !isUndefined(Intl.DateTimeFormat.prototype.formatToParts); +} + +export function hasRelative() { + try { + return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat; + } 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); +} + +// 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) { + if (input.toString().length < n) { + return ("0".repeat(n) + input).slice(-n); + } else { + return input.toString(); + } +} + +export function parseInteger(string) { + if (isUndefined(string) || string === null || string === "") { + return undefined; + } else { + return parseInt(string, 10); + } +} + +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, towardZero = false) { + const factor = 10 ** digits, + rounder = towardZero ? Math.trunc : Math.round; + return rounder(number * factor) / factor; +} + +// 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]; + } +} + +// covert 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); + d.setUTCFullYear(d.getUTCFullYear() - 1900); + } + return +d; +} + +export function weeksInWeekYear(weekYear) { + const p1 = + (weekYear + + Math.floor(weekYear / 4) - + Math.floor(weekYear / 100) + + Math.floor(weekYear / 400)) % + 7, + last = weekYear - 1, + p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7; + return p1 === 4 || p2 === 3 ? 53 : 52; +} + +export function untruncateYear(year) { + if (year > 99) { + return year; + } else return year > 60 ? 1900 + year : 2000 + year; +} + +// PARSING + +export function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) { + const date = new Date(ts), + intlOpts = { + hour12: false, + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit" + }; + + if (timeZone) { + intlOpts.timeZone = timeZone; + } + + const modified = Object.assign({ timeZoneName: offsetFormat }, intlOpts), + intl = hasIntl(); + + if (intl && hasFormatToParts()) { + const parsed = new Intl.DateTimeFormat(locale, modified) + .formatToParts(date) + .find(m => m.type.toLowerCase() === "timezonename"); + return parsed ? parsed.value : null; + } else if (intl) { + // this probably doesn't work for all locales + const without = new Intl.DateTimeFormat(locale, intlOpts).format(date), + included = new Intl.DateTimeFormat(locale, modified).format(date), + diffed = included.substring(without.length), + trimmed = diffed.replace(/^[, \u200e]+/, ""); + return trimmed; + } else { + return 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.isNaN(numericValue)) + throw new InvalidArgumentError(`Invalid unit value ${value}`); + return numericValue; +} + +export function normalizeObject(obj, normalizer, nonUnitKeys) { + const normalized = {}; + for (const u in obj) { + if (hasOwnProperty(obj, u)) { + if (nonUnitKeys.indexOf(u) >= 0) continue; + const v = obj[u]; + if (v === undefined || v === null) continue; + normalized[normalizer(u)] = asNumber(v); + } + } + return normalized; +} + +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"]); +} + +export const ianaRegex = /[A-Za-z_+-]{1,256}(:?\/[A-Za-z_+-]{1,256}(\/[A-Za-z_+-]{1,256})?)?/; diff --git a/npm_assets/node_modules/luxon/src/impl/zoneUtil.js b/npm_assets/node_modules/luxon/src/impl/zoneUtil.js new file mode 100644 index 0000000..c45e828 --- /dev/null +++ b/npm_assets/node_modules/luxon/src/impl/zoneUtil.js @@ -0,0 +1,36 @@ +/** + * @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"; + +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 === "local") return defaultZone; + else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance; + else if ((offset = IANAZone.parseGMTOffset(input)) != null) { + // handle Etc/GMT-4, which V8 chokes on + return FixedOffsetZone.instance(offset); + } else if (IANAZone.isValidSpecifier(lowered)) return IANAZone.create(input); + else return FixedOffsetZone.parseSpecifier(lowered) || new InvalidZone(input); + } else if (isNumber(input)) { + return FixedOffsetZone.instance(input); + } else if (typeof input === "object" && input.offset && typeof input.offset === "number") { + // 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); + } +} |
