@bpmn-io/form-js-playground 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1521,772 +1521,6 @@
1521
1521
  timeZoneName: l$1
1522
1522
  };
1523
1523
 
1524
- /*
1525
- This is just a junk drawer, containing anything used across multiple classes.
1526
- Because Luxon is small(ish), this should stay small and we won't worry about splitting
1527
- it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
1528
- */
1529
-
1530
- /**
1531
- * @private
1532
- */
1533
-
1534
- // TYPES
1535
-
1536
- function isUndefined$1(o) {
1537
- return typeof o === "undefined";
1538
- }
1539
- function isNumber$2(o) {
1540
- return typeof o === "number";
1541
- }
1542
- function isInteger(o) {
1543
- return typeof o === "number" && o % 1 === 0;
1544
- }
1545
- function isString$2(o) {
1546
- return typeof o === "string";
1547
- }
1548
- function isDate(o) {
1549
- return Object.prototype.toString.call(o) === "[object Date]";
1550
- }
1551
-
1552
- // CAPABILITIES
1553
-
1554
- function hasRelative() {
1555
- try {
1556
- return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
1557
- } catch (e) {
1558
- return false;
1559
- }
1560
- }
1561
-
1562
- // OBJECTS AND ARRAYS
1563
-
1564
- function maybeArray(thing) {
1565
- return Array.isArray(thing) ? thing : [thing];
1566
- }
1567
- function bestBy(arr, by, compare) {
1568
- if (arr.length === 0) {
1569
- return undefined;
1570
- }
1571
- return arr.reduce((best, next) => {
1572
- const pair = [by(next), next];
1573
- if (!best) {
1574
- return pair;
1575
- } else if (compare(best[0], pair[0]) === best[0]) {
1576
- return best;
1577
- } else {
1578
- return pair;
1579
- }
1580
- }, null)[1];
1581
- }
1582
- function pick(obj, keys) {
1583
- return keys.reduce((a, k) => {
1584
- a[k] = obj[k];
1585
- return a;
1586
- }, {});
1587
- }
1588
- function hasOwnProperty(obj, prop) {
1589
- return Object.prototype.hasOwnProperty.call(obj, prop);
1590
- }
1591
-
1592
- // NUMBERS AND STRINGS
1593
-
1594
- function integerBetween(thing, bottom, top) {
1595
- return isInteger(thing) && thing >= bottom && thing <= top;
1596
- }
1597
-
1598
- // x % n but takes the sign of n instead of x
1599
- function floorMod(x, n) {
1600
- return x - n * Math.floor(x / n);
1601
- }
1602
- function padStart(input, n = 2) {
1603
- const isNeg = input < 0;
1604
- let padded;
1605
- if (isNeg) {
1606
- padded = "-" + ("" + -input).padStart(n, "0");
1607
- } else {
1608
- padded = ("" + input).padStart(n, "0");
1609
- }
1610
- return padded;
1611
- }
1612
- function parseInteger(string) {
1613
- if (isUndefined$1(string) || string === null || string === "") {
1614
- return undefined;
1615
- } else {
1616
- return parseInt(string, 10);
1617
- }
1618
- }
1619
- function parseFloating(string) {
1620
- if (isUndefined$1(string) || string === null || string === "") {
1621
- return undefined;
1622
- } else {
1623
- return parseFloat(string);
1624
- }
1625
- }
1626
- function parseMillis(fraction) {
1627
- // Return undefined (instead of 0) in these cases, where fraction is not set
1628
- if (isUndefined$1(fraction) || fraction === null || fraction === "") {
1629
- return undefined;
1630
- } else {
1631
- const f = parseFloat("0." + fraction) * 1000;
1632
- return Math.floor(f);
1633
- }
1634
- }
1635
- function roundTo(number, digits, towardZero = false) {
1636
- const factor = 10 ** digits,
1637
- rounder = towardZero ? Math.trunc : Math.round;
1638
- return rounder(number * factor) / factor;
1639
- }
1640
-
1641
- // DATE BASICS
1642
-
1643
- function isLeapYear(year) {
1644
- return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
1645
- }
1646
- function daysInYear(year) {
1647
- return isLeapYear(year) ? 366 : 365;
1648
- }
1649
- function daysInMonth(year, month) {
1650
- const modMonth = floorMod(month - 1, 12) + 1,
1651
- modYear = year + (month - modMonth) / 12;
1652
- if (modMonth === 2) {
1653
- return isLeapYear(modYear) ? 29 : 28;
1654
- } else {
1655
- return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
1656
- }
1657
- }
1658
-
1659
- // covert a calendar object to a local timestamp (epoch, but with the offset baked in)
1660
- function objToLocalTS(obj) {
1661
- let d = Date.UTC(obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, obj.millisecond);
1662
-
1663
- // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
1664
- if (obj.year < 100 && obj.year >= 0) {
1665
- d = new Date(d);
1666
- d.setUTCFullYear(d.getUTCFullYear() - 1900);
1667
- }
1668
- return +d;
1669
- }
1670
- function weeksInWeekYear(weekYear) {
1671
- const p1 = (weekYear + Math.floor(weekYear / 4) - Math.floor(weekYear / 100) + Math.floor(weekYear / 400)) % 7,
1672
- last = weekYear - 1,
1673
- p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7;
1674
- return p1 === 4 || p2 === 3 ? 53 : 52;
1675
- }
1676
- function untruncateYear(year) {
1677
- if (year > 99) {
1678
- return year;
1679
- } else return year > 60 ? 1900 + year : 2000 + year;
1680
- }
1681
-
1682
- // PARSING
1683
-
1684
- function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
1685
- const date = new Date(ts),
1686
- intlOpts = {
1687
- hourCycle: "h23",
1688
- year: "numeric",
1689
- month: "2-digit",
1690
- day: "2-digit",
1691
- hour: "2-digit",
1692
- minute: "2-digit"
1693
- };
1694
- if (timeZone) {
1695
- intlOpts.timeZone = timeZone;
1696
- }
1697
- const modified = {
1698
- timeZoneName: offsetFormat,
1699
- ...intlOpts
1700
- };
1701
- const parsed = new Intl.DateTimeFormat(locale, modified).formatToParts(date).find(m => m.type.toLowerCase() === "timezonename");
1702
- return parsed ? parsed.value : null;
1703
- }
1704
-
1705
- // signedOffset('-5', '30') -> -330
1706
- function signedOffset(offHourStr, offMinuteStr) {
1707
- let offHour = parseInt(offHourStr, 10);
1708
-
1709
- // don't || this because we want to preserve -0
1710
- if (Number.isNaN(offHour)) {
1711
- offHour = 0;
1712
- }
1713
- const offMin = parseInt(offMinuteStr, 10) || 0,
1714
- offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
1715
- return offHour * 60 + offMinSigned;
1716
- }
1717
-
1718
- // COERCION
1719
-
1720
- function asNumber(value) {
1721
- const numericValue = Number(value);
1722
- if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue)) throw new InvalidArgumentError(`Invalid unit value ${value}`);
1723
- return numericValue;
1724
- }
1725
- function normalizeObject(obj, normalizer) {
1726
- const normalized = {};
1727
- for (const u in obj) {
1728
- if (hasOwnProperty(obj, u)) {
1729
- const v = obj[u];
1730
- if (v === undefined || v === null) continue;
1731
- normalized[normalizer(u)] = asNumber(v);
1732
- }
1733
- }
1734
- return normalized;
1735
- }
1736
- function formatOffset(offset, format) {
1737
- const hours = Math.trunc(Math.abs(offset / 60)),
1738
- minutes = Math.trunc(Math.abs(offset % 60)),
1739
- sign = offset >= 0 ? "+" : "-";
1740
- switch (format) {
1741
- case "short":
1742
- return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
1743
- case "narrow":
1744
- return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
1745
- case "techie":
1746
- return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
1747
- default:
1748
- throw new RangeError(`Value format ${format} is out of range for property format`);
1749
- }
1750
- }
1751
- function timeObject(obj) {
1752
- return pick(obj, ["hour", "minute", "second", "millisecond"]);
1753
- }
1754
- const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
1755
-
1756
- /**
1757
- * @private
1758
- */
1759
-
1760
- const monthsLong = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
1761
- const monthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1762
- const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
1763
- function months(length) {
1764
- switch (length) {
1765
- case "narrow":
1766
- return [...monthsNarrow];
1767
- case "short":
1768
- return [...monthsShort];
1769
- case "long":
1770
- return [...monthsLong];
1771
- case "numeric":
1772
- return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
1773
- case "2-digit":
1774
- return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
1775
- default:
1776
- return null;
1777
- }
1778
- }
1779
- const weekdaysLong = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
1780
- const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
1781
- const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
1782
- function weekdays(length) {
1783
- switch (length) {
1784
- case "narrow":
1785
- return [...weekdaysNarrow];
1786
- case "short":
1787
- return [...weekdaysShort];
1788
- case "long":
1789
- return [...weekdaysLong];
1790
- case "numeric":
1791
- return ["1", "2", "3", "4", "5", "6", "7"];
1792
- default:
1793
- return null;
1794
- }
1795
- }
1796
- const meridiems = ["AM", "PM"];
1797
- const erasLong = ["Before Christ", "Anno Domini"];
1798
- const erasShort = ["BC", "AD"];
1799
- const erasNarrow = ["B", "A"];
1800
- function eras(length) {
1801
- switch (length) {
1802
- case "narrow":
1803
- return [...erasNarrow];
1804
- case "short":
1805
- return [...erasShort];
1806
- case "long":
1807
- return [...erasLong];
1808
- default:
1809
- return null;
1810
- }
1811
- }
1812
- function meridiemForDateTime(dt) {
1813
- return meridiems[dt.hour < 12 ? 0 : 1];
1814
- }
1815
- function weekdayForDateTime(dt, length) {
1816
- return weekdays(length)[dt.weekday - 1];
1817
- }
1818
- function monthForDateTime(dt, length) {
1819
- return months(length)[dt.month - 1];
1820
- }
1821
- function eraForDateTime(dt, length) {
1822
- return eras(length)[dt.year < 0 ? 0 : 1];
1823
- }
1824
- function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
1825
- const units = {
1826
- years: ["year", "yr."],
1827
- quarters: ["quarter", "qtr."],
1828
- months: ["month", "mo."],
1829
- weeks: ["week", "wk."],
1830
- days: ["day", "day", "days"],
1831
- hours: ["hour", "hr."],
1832
- minutes: ["minute", "min."],
1833
- seconds: ["second", "sec."]
1834
- };
1835
- const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
1836
- if (numeric === "auto" && lastable) {
1837
- const isDay = unit === "days";
1838
- switch (count) {
1839
- case 1:
1840
- return isDay ? "tomorrow" : `next ${units[unit][0]}`;
1841
- case -1:
1842
- return isDay ? "yesterday" : `last ${units[unit][0]}`;
1843
- case 0:
1844
- return isDay ? "today" : `this ${units[unit][0]}`;
1845
- }
1846
- }
1847
-
1848
- const isInPast = Object.is(count, -0) || count < 0,
1849
- fmtValue = Math.abs(count),
1850
- singular = fmtValue === 1,
1851
- lilUnits = units[unit],
1852
- fmtUnit = narrow ? singular ? lilUnits[1] : lilUnits[2] || lilUnits[1] : singular ? units[unit][0] : unit;
1853
- return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
1854
- }
1855
-
1856
- function stringifyTokens(splits, tokenToString) {
1857
- let s = "";
1858
- for (const token of splits) {
1859
- if (token.literal) {
1860
- s += token.val;
1861
- } else {
1862
- s += tokenToString(token.val);
1863
- }
1864
- }
1865
- return s;
1866
- }
1867
- const macroTokenToFormatOpts = {
1868
- D: DATE_SHORT,
1869
- DD: DATE_MED,
1870
- DDD: DATE_FULL,
1871
- DDDD: DATE_HUGE,
1872
- t: TIME_SIMPLE,
1873
- tt: TIME_WITH_SECONDS,
1874
- ttt: TIME_WITH_SHORT_OFFSET,
1875
- tttt: TIME_WITH_LONG_OFFSET,
1876
- T: TIME_24_SIMPLE,
1877
- TT: TIME_24_WITH_SECONDS,
1878
- TTT: TIME_24_WITH_SHORT_OFFSET,
1879
- TTTT: TIME_24_WITH_LONG_OFFSET,
1880
- f: DATETIME_SHORT,
1881
- ff: DATETIME_MED,
1882
- fff: DATETIME_FULL,
1883
- ffff: DATETIME_HUGE,
1884
- F: DATETIME_SHORT_WITH_SECONDS,
1885
- FF: DATETIME_MED_WITH_SECONDS,
1886
- FFF: DATETIME_FULL_WITH_SECONDS,
1887
- FFFF: DATETIME_HUGE_WITH_SECONDS
1888
- };
1889
-
1890
- /**
1891
- * @private
1892
- */
1893
-
1894
- class Formatter {
1895
- static create(locale, opts = {}) {
1896
- return new Formatter(locale, opts);
1897
- }
1898
- static parseFormat(fmt) {
1899
- let current = null,
1900
- currentFull = "",
1901
- bracketed = false;
1902
- const splits = [];
1903
- for (let i = 0; i < fmt.length; i++) {
1904
- const c = fmt.charAt(i);
1905
- if (c === "'") {
1906
- if (currentFull.length > 0) {
1907
- splits.push({
1908
- literal: bracketed,
1909
- val: currentFull
1910
- });
1911
- }
1912
- current = null;
1913
- currentFull = "";
1914
- bracketed = !bracketed;
1915
- } else if (bracketed) {
1916
- currentFull += c;
1917
- } else if (c === current) {
1918
- currentFull += c;
1919
- } else {
1920
- if (currentFull.length > 0) {
1921
- splits.push({
1922
- literal: false,
1923
- val: currentFull
1924
- });
1925
- }
1926
- currentFull = c;
1927
- current = c;
1928
- }
1929
- }
1930
- if (currentFull.length > 0) {
1931
- splits.push({
1932
- literal: bracketed,
1933
- val: currentFull
1934
- });
1935
- }
1936
- return splits;
1937
- }
1938
- static macroTokenToFormatOpts(token) {
1939
- return macroTokenToFormatOpts[token];
1940
- }
1941
- constructor(locale, formatOpts) {
1942
- this.opts = formatOpts;
1943
- this.loc = locale;
1944
- this.systemLoc = null;
1945
- }
1946
- formatWithSystemDefault(dt, opts) {
1947
- if (this.systemLoc === null) {
1948
- this.systemLoc = this.loc.redefaultToSystem();
1949
- }
1950
- const df = this.systemLoc.dtFormatter(dt, {
1951
- ...this.opts,
1952
- ...opts
1953
- });
1954
- return df.format();
1955
- }
1956
- formatDateTime(dt, opts = {}) {
1957
- const df = this.loc.dtFormatter(dt, {
1958
- ...this.opts,
1959
- ...opts
1960
- });
1961
- return df.format();
1962
- }
1963
- formatDateTimeParts(dt, opts = {}) {
1964
- const df = this.loc.dtFormatter(dt, {
1965
- ...this.opts,
1966
- ...opts
1967
- });
1968
- return df.formatToParts();
1969
- }
1970
- resolvedOptions(dt, opts = {}) {
1971
- const df = this.loc.dtFormatter(dt, {
1972
- ...this.opts,
1973
- ...opts
1974
- });
1975
- return df.resolvedOptions();
1976
- }
1977
- num(n, p = 0) {
1978
- // we get some perf out of doing this here, annoyingly
1979
- if (this.opts.forceSimple) {
1980
- return padStart(n, p);
1981
- }
1982
- const opts = {
1983
- ...this.opts
1984
- };
1985
- if (p > 0) {
1986
- opts.padTo = p;
1987
- }
1988
- return this.loc.numberFormatter(opts).format(n);
1989
- }
1990
- formatDateTimeFromString(dt, fmt) {
1991
- const knownEnglish = this.loc.listingMode() === "en",
1992
- useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
1993
- string = (opts, extract) => this.loc.extract(dt, opts, extract),
1994
- formatOffset = opts => {
1995
- if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
1996
- return "Z";
1997
- }
1998
- return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
1999
- },
2000
- meridiem = () => knownEnglish ? meridiemForDateTime(dt) : string({
2001
- hour: "numeric",
2002
- hourCycle: "h12"
2003
- }, "dayperiod"),
2004
- month = (length, standalone) => knownEnglish ? monthForDateTime(dt, length) : string(standalone ? {
2005
- month: length
2006
- } : {
2007
- month: length,
2008
- day: "numeric"
2009
- }, "month"),
2010
- weekday = (length, standalone) => knownEnglish ? weekdayForDateTime(dt, length) : string(standalone ? {
2011
- weekday: length
2012
- } : {
2013
- weekday: length,
2014
- month: "long",
2015
- day: "numeric"
2016
- }, "weekday"),
2017
- maybeMacro = token => {
2018
- const formatOpts = Formatter.macroTokenToFormatOpts(token);
2019
- if (formatOpts) {
2020
- return this.formatWithSystemDefault(dt, formatOpts);
2021
- } else {
2022
- return token;
2023
- }
2024
- },
2025
- era = length => knownEnglish ? eraForDateTime(dt, length) : string({
2026
- era: length
2027
- }, "era"),
2028
- tokenToString = token => {
2029
- // Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles
2030
- switch (token) {
2031
- // ms
2032
- case "S":
2033
- return this.num(dt.millisecond);
2034
- case "u":
2035
- // falls through
2036
- case "SSS":
2037
- return this.num(dt.millisecond, 3);
2038
- // seconds
2039
- case "s":
2040
- return this.num(dt.second);
2041
- case "ss":
2042
- return this.num(dt.second, 2);
2043
- // fractional seconds
2044
- case "uu":
2045
- return this.num(Math.floor(dt.millisecond / 10), 2);
2046
- case "uuu":
2047
- return this.num(Math.floor(dt.millisecond / 100));
2048
- // minutes
2049
- case "m":
2050
- return this.num(dt.minute);
2051
- case "mm":
2052
- return this.num(dt.minute, 2);
2053
- // hours
2054
- case "h":
2055
- return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
2056
- case "hh":
2057
- return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
2058
- case "H":
2059
- return this.num(dt.hour);
2060
- case "HH":
2061
- return this.num(dt.hour, 2);
2062
- // offset
2063
- case "Z":
2064
- // like +6
2065
- return formatOffset({
2066
- format: "narrow",
2067
- allowZ: this.opts.allowZ
2068
- });
2069
- case "ZZ":
2070
- // like +06:00
2071
- return formatOffset({
2072
- format: "short",
2073
- allowZ: this.opts.allowZ
2074
- });
2075
- case "ZZZ":
2076
- // like +0600
2077
- return formatOffset({
2078
- format: "techie",
2079
- allowZ: this.opts.allowZ
2080
- });
2081
- case "ZZZZ":
2082
- // like EST
2083
- return dt.zone.offsetName(dt.ts, {
2084
- format: "short",
2085
- locale: this.loc.locale
2086
- });
2087
- case "ZZZZZ":
2088
- // like Eastern Standard Time
2089
- return dt.zone.offsetName(dt.ts, {
2090
- format: "long",
2091
- locale: this.loc.locale
2092
- });
2093
- // zone
2094
- case "z":
2095
- // like America/New_York
2096
- return dt.zoneName;
2097
- // meridiems
2098
- case "a":
2099
- return meridiem();
2100
- // dates
2101
- case "d":
2102
- return useDateTimeFormatter ? string({
2103
- day: "numeric"
2104
- }, "day") : this.num(dt.day);
2105
- case "dd":
2106
- return useDateTimeFormatter ? string({
2107
- day: "2-digit"
2108
- }, "day") : this.num(dt.day, 2);
2109
- // weekdays - standalone
2110
- case "c":
2111
- // like 1
2112
- return this.num(dt.weekday);
2113
- case "ccc":
2114
- // like 'Tues'
2115
- return weekday("short", true);
2116
- case "cccc":
2117
- // like 'Tuesday'
2118
- return weekday("long", true);
2119
- case "ccccc":
2120
- // like 'T'
2121
- return weekday("narrow", true);
2122
- // weekdays - format
2123
- case "E":
2124
- // like 1
2125
- return this.num(dt.weekday);
2126
- case "EEE":
2127
- // like 'Tues'
2128
- return weekday("short", false);
2129
- case "EEEE":
2130
- // like 'Tuesday'
2131
- return weekday("long", false);
2132
- case "EEEEE":
2133
- // like 'T'
2134
- return weekday("narrow", false);
2135
- // months - standalone
2136
- case "L":
2137
- // like 1
2138
- return useDateTimeFormatter ? string({
2139
- month: "numeric",
2140
- day: "numeric"
2141
- }, "month") : this.num(dt.month);
2142
- case "LL":
2143
- // like 01, doesn't seem to work
2144
- return useDateTimeFormatter ? string({
2145
- month: "2-digit",
2146
- day: "numeric"
2147
- }, "month") : this.num(dt.month, 2);
2148
- case "LLL":
2149
- // like Jan
2150
- return month("short", true);
2151
- case "LLLL":
2152
- // like January
2153
- return month("long", true);
2154
- case "LLLLL":
2155
- // like J
2156
- return month("narrow", true);
2157
- // months - format
2158
- case "M":
2159
- // like 1
2160
- return useDateTimeFormatter ? string({
2161
- month: "numeric"
2162
- }, "month") : this.num(dt.month);
2163
- case "MM":
2164
- // like 01
2165
- return useDateTimeFormatter ? string({
2166
- month: "2-digit"
2167
- }, "month") : this.num(dt.month, 2);
2168
- case "MMM":
2169
- // like Jan
2170
- return month("short", false);
2171
- case "MMMM":
2172
- // like January
2173
- return month("long", false);
2174
- case "MMMMM":
2175
- // like J
2176
- return month("narrow", false);
2177
- // years
2178
- case "y":
2179
- // like 2014
2180
- return useDateTimeFormatter ? string({
2181
- year: "numeric"
2182
- }, "year") : this.num(dt.year);
2183
- case "yy":
2184
- // like 14
2185
- return useDateTimeFormatter ? string({
2186
- year: "2-digit"
2187
- }, "year") : this.num(dt.year.toString().slice(-2), 2);
2188
- case "yyyy":
2189
- // like 0012
2190
- return useDateTimeFormatter ? string({
2191
- year: "numeric"
2192
- }, "year") : this.num(dt.year, 4);
2193
- case "yyyyyy":
2194
- // like 000012
2195
- return useDateTimeFormatter ? string({
2196
- year: "numeric"
2197
- }, "year") : this.num(dt.year, 6);
2198
- // eras
2199
- case "G":
2200
- // like AD
2201
- return era("short");
2202
- case "GG":
2203
- // like Anno Domini
2204
- return era("long");
2205
- case "GGGGG":
2206
- return era("narrow");
2207
- case "kk":
2208
- return this.num(dt.weekYear.toString().slice(-2), 2);
2209
- case "kkkk":
2210
- return this.num(dt.weekYear, 4);
2211
- case "W":
2212
- return this.num(dt.weekNumber);
2213
- case "WW":
2214
- return this.num(dt.weekNumber, 2);
2215
- case "o":
2216
- return this.num(dt.ordinal);
2217
- case "ooo":
2218
- return this.num(dt.ordinal, 3);
2219
- case "q":
2220
- // like 1
2221
- return this.num(dt.quarter);
2222
- case "qq":
2223
- // like 01
2224
- return this.num(dt.quarter, 2);
2225
- case "X":
2226
- return this.num(Math.floor(dt.ts / 1000));
2227
- case "x":
2228
- return this.num(dt.ts);
2229
- default:
2230
- return maybeMacro(token);
2231
- }
2232
- };
2233
- return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
2234
- }
2235
- formatDurationFromString(dur, fmt) {
2236
- const tokenToField = token => {
2237
- switch (token[0]) {
2238
- case "S":
2239
- return "millisecond";
2240
- case "s":
2241
- return "second";
2242
- case "m":
2243
- return "minute";
2244
- case "h":
2245
- return "hour";
2246
- case "d":
2247
- return "day";
2248
- case "w":
2249
- return "week";
2250
- case "M":
2251
- return "month";
2252
- case "y":
2253
- return "year";
2254
- default:
2255
- return null;
2256
- }
2257
- },
2258
- tokenToString = lildur => token => {
2259
- const mapped = tokenToField(token);
2260
- if (mapped) {
2261
- return this.num(lildur.get(mapped), token.length);
2262
- } else {
2263
- return token;
2264
- }
2265
- },
2266
- tokens = Formatter.parseFormat(fmt),
2267
- realTokens = tokens.reduce((found, {
2268
- literal,
2269
- val
2270
- }) => literal ? found : found.concat(val), []),
2271
- collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter(t => t));
2272
- return stringifyTokens(tokens, tokenToString(collapsed));
2273
- }
2274
- }
2275
-
2276
- class Invalid {
2277
- constructor(reason, explanation) {
2278
- this.reason = reason;
2279
- this.explanation = explanation;
2280
- }
2281
- toMessage() {
2282
- if (this.explanation) {
2283
- return `${this.reason}: ${this.explanation}`;
2284
- } else {
2285
- return this.reason;
2286
- }
2287
- }
2288
- }
2289
-
2290
1524
  /**
2291
1525
  * @interface
2292
1526
  */
@@ -2620,6 +1854,435 @@
2620
1854
  }
2621
1855
  }
2622
1856
 
1857
+ // todo - remap caching
1858
+
1859
+ let intlLFCache = {};
1860
+ function getCachedLF(locString, opts = {}) {
1861
+ const key = JSON.stringify([locString, opts]);
1862
+ let dtf = intlLFCache[key];
1863
+ if (!dtf) {
1864
+ dtf = new Intl.ListFormat(locString, opts);
1865
+ intlLFCache[key] = dtf;
1866
+ }
1867
+ return dtf;
1868
+ }
1869
+ let intlDTCache = {};
1870
+ function getCachedDTF(locString, opts = {}) {
1871
+ const key = JSON.stringify([locString, opts]);
1872
+ let dtf = intlDTCache[key];
1873
+ if (!dtf) {
1874
+ dtf = new Intl.DateTimeFormat(locString, opts);
1875
+ intlDTCache[key] = dtf;
1876
+ }
1877
+ return dtf;
1878
+ }
1879
+ let intlNumCache = {};
1880
+ function getCachedINF(locString, opts = {}) {
1881
+ const key = JSON.stringify([locString, opts]);
1882
+ let inf = intlNumCache[key];
1883
+ if (!inf) {
1884
+ inf = new Intl.NumberFormat(locString, opts);
1885
+ intlNumCache[key] = inf;
1886
+ }
1887
+ return inf;
1888
+ }
1889
+ let intlRelCache = {};
1890
+ function getCachedRTF(locString, opts = {}) {
1891
+ const {
1892
+ base,
1893
+ ...cacheKeyOpts
1894
+ } = opts; // exclude `base` from the options
1895
+ const key = JSON.stringify([locString, cacheKeyOpts]);
1896
+ let inf = intlRelCache[key];
1897
+ if (!inf) {
1898
+ inf = new Intl.RelativeTimeFormat(locString, opts);
1899
+ intlRelCache[key] = inf;
1900
+ }
1901
+ return inf;
1902
+ }
1903
+ let sysLocaleCache = null;
1904
+ function systemLocale() {
1905
+ if (sysLocaleCache) {
1906
+ return sysLocaleCache;
1907
+ } else {
1908
+ sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
1909
+ return sysLocaleCache;
1910
+ }
1911
+ }
1912
+ function parseLocaleString(localeStr) {
1913
+ // I really want to avoid writing a BCP 47 parser
1914
+ // see, e.g. https://github.com/wooorm/bcp-47
1915
+ // Instead, we'll do this:
1916
+
1917
+ // a) if the string has no -u extensions, just leave it alone
1918
+ // b) if it does, use Intl to resolve everything
1919
+ // c) if Intl fails, try again without the -u
1920
+
1921
+ // private subtags and unicode subtags have ordering requirements,
1922
+ // and we're not properly parsing this, so just strip out the
1923
+ // private ones if they exist.
1924
+ const xIndex = localeStr.indexOf("-x-");
1925
+ if (xIndex !== -1) {
1926
+ localeStr = localeStr.substring(0, xIndex);
1927
+ }
1928
+ const uIndex = localeStr.indexOf("-u-");
1929
+ if (uIndex === -1) {
1930
+ return [localeStr];
1931
+ } else {
1932
+ let options;
1933
+ let selectedStr;
1934
+ try {
1935
+ options = getCachedDTF(localeStr).resolvedOptions();
1936
+ selectedStr = localeStr;
1937
+ } catch (e) {
1938
+ const smaller = localeStr.substring(0, uIndex);
1939
+ options = getCachedDTF(smaller).resolvedOptions();
1940
+ selectedStr = smaller;
1941
+ }
1942
+ const {
1943
+ numberingSystem,
1944
+ calendar
1945
+ } = options;
1946
+ return [selectedStr, numberingSystem, calendar];
1947
+ }
1948
+ }
1949
+ function intlConfigString(localeStr, numberingSystem, outputCalendar) {
1950
+ if (outputCalendar || numberingSystem) {
1951
+ if (!localeStr.includes("-u-")) {
1952
+ localeStr += "-u";
1953
+ }
1954
+ if (outputCalendar) {
1955
+ localeStr += `-ca-${outputCalendar}`;
1956
+ }
1957
+ if (numberingSystem) {
1958
+ localeStr += `-nu-${numberingSystem}`;
1959
+ }
1960
+ return localeStr;
1961
+ } else {
1962
+ return localeStr;
1963
+ }
1964
+ }
1965
+ function mapMonths(f) {
1966
+ const ms = [];
1967
+ for (let i = 1; i <= 12; i++) {
1968
+ const dt = DateTime.utc(2016, i, 1);
1969
+ ms.push(f(dt));
1970
+ }
1971
+ return ms;
1972
+ }
1973
+ function mapWeekdays(f) {
1974
+ const ms = [];
1975
+ for (let i = 1; i <= 7; i++) {
1976
+ const dt = DateTime.utc(2016, 11, 13 + i);
1977
+ ms.push(f(dt));
1978
+ }
1979
+ return ms;
1980
+ }
1981
+ function listStuff(loc, length, defaultOK, englishFn, intlFn) {
1982
+ const mode = loc.listingMode(defaultOK);
1983
+ if (mode === "error") {
1984
+ return null;
1985
+ } else if (mode === "en") {
1986
+ return englishFn(length);
1987
+ } else {
1988
+ return intlFn(length);
1989
+ }
1990
+ }
1991
+ function supportsFastNumbers(loc) {
1992
+ if (loc.numberingSystem && loc.numberingSystem !== "latn") {
1993
+ return false;
1994
+ } else {
1995
+ return loc.numberingSystem === "latn" || !loc.locale || loc.locale.startsWith("en") || new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn";
1996
+ }
1997
+ }
1998
+
1999
+ /**
2000
+ * @private
2001
+ */
2002
+
2003
+ class PolyNumberFormatter {
2004
+ constructor(intl, forceSimple, opts) {
2005
+ this.padTo = opts.padTo || 0;
2006
+ this.floor = opts.floor || false;
2007
+ const {
2008
+ padTo,
2009
+ floor,
2010
+ ...otherOpts
2011
+ } = opts;
2012
+ if (!forceSimple || Object.keys(otherOpts).length > 0) {
2013
+ const intlOpts = {
2014
+ useGrouping: false,
2015
+ ...opts
2016
+ };
2017
+ if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
2018
+ this.inf = getCachedINF(intl, intlOpts);
2019
+ }
2020
+ }
2021
+ format(i) {
2022
+ if (this.inf) {
2023
+ const fixed = this.floor ? Math.floor(i) : i;
2024
+ return this.inf.format(fixed);
2025
+ } else {
2026
+ // to match the browser's numberformatter defaults
2027
+ const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
2028
+ return padStart(fixed, this.padTo);
2029
+ }
2030
+ }
2031
+ }
2032
+
2033
+ /**
2034
+ * @private
2035
+ */
2036
+
2037
+ class PolyDateFormatter {
2038
+ constructor(dt, intl, opts) {
2039
+ this.opts = opts;
2040
+ let z = undefined;
2041
+ if (dt.zone.isUniversal) {
2042
+ // UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
2043
+ // That is why fixed-offset TZ is set to that unless it is:
2044
+ // 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
2045
+ // 2. Unsupported by the browser:
2046
+ // - some do not support Etc/
2047
+ // - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
2048
+ const gmtOffset = -1 * (dt.offset / 60);
2049
+ const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
2050
+ if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
2051
+ z = offsetZ;
2052
+ this.dt = dt;
2053
+ } else {
2054
+ // Not all fixed-offset zones like Etc/+4:30 are present in tzdata.
2055
+ // So we have to make do. Two cases:
2056
+ // 1. The format options tell us to show the zone. We can't do that, so the best
2057
+ // we can do is format the date in UTC.
2058
+ // 2. The format options don't tell us to show the zone. Then we can adjust them
2059
+ // the time and tell the formatter to show it to us in UTC, so that the time is right
2060
+ // and the bad zone doesn't show up.
2061
+ z = "UTC";
2062
+ if (opts.timeZoneName) {
2063
+ this.dt = dt;
2064
+ } else {
2065
+ this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000);
2066
+ }
2067
+ }
2068
+ } else if (dt.zone.type === "system") {
2069
+ this.dt = dt;
2070
+ } else {
2071
+ this.dt = dt;
2072
+ z = dt.zone.name;
2073
+ }
2074
+ const intlOpts = {
2075
+ ...this.opts
2076
+ };
2077
+ intlOpts.timeZone = intlOpts.timeZone || z;
2078
+ this.dtf = getCachedDTF(intl, intlOpts);
2079
+ }
2080
+ format() {
2081
+ return this.dtf.format(this.dt.toJSDate());
2082
+ }
2083
+ formatToParts() {
2084
+ return this.dtf.formatToParts(this.dt.toJSDate());
2085
+ }
2086
+ resolvedOptions() {
2087
+ return this.dtf.resolvedOptions();
2088
+ }
2089
+ }
2090
+
2091
+ /**
2092
+ * @private
2093
+ */
2094
+ class PolyRelFormatter {
2095
+ constructor(intl, isEnglish, opts) {
2096
+ this.opts = {
2097
+ style: "long",
2098
+ ...opts
2099
+ };
2100
+ if (!isEnglish && hasRelative()) {
2101
+ this.rtf = getCachedRTF(intl, opts);
2102
+ }
2103
+ }
2104
+ format(count, unit) {
2105
+ if (this.rtf) {
2106
+ return this.rtf.format(count, unit);
2107
+ } else {
2108
+ return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
2109
+ }
2110
+ }
2111
+ formatToParts(count, unit) {
2112
+ if (this.rtf) {
2113
+ return this.rtf.formatToParts(count, unit);
2114
+ } else {
2115
+ return [];
2116
+ }
2117
+ }
2118
+ }
2119
+
2120
+ /**
2121
+ * @private
2122
+ */
2123
+
2124
+ class Locale {
2125
+ static fromOpts(opts) {
2126
+ return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.defaultToEN);
2127
+ }
2128
+ static create(locale, numberingSystem, outputCalendar, defaultToEN = false) {
2129
+ const specifiedLocale = locale || Settings.defaultLocale;
2130
+ // the system locale is useful for human readable strings but annoying for parsing/formatting known formats
2131
+ const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
2132
+ const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
2133
+ const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
2134
+ return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale);
2135
+ }
2136
+ static resetCache() {
2137
+ sysLocaleCache = null;
2138
+ intlDTCache = {};
2139
+ intlNumCache = {};
2140
+ intlRelCache = {};
2141
+ }
2142
+ static fromObject({
2143
+ locale,
2144
+ numberingSystem,
2145
+ outputCalendar
2146
+ } = {}) {
2147
+ return Locale.create(locale, numberingSystem, outputCalendar);
2148
+ }
2149
+ constructor(locale, numbering, outputCalendar, specifiedLocale) {
2150
+ const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
2151
+ this.locale = parsedLocale;
2152
+ this.numberingSystem = numbering || parsedNumberingSystem || null;
2153
+ this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
2154
+ this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
2155
+ this.weekdaysCache = {
2156
+ format: {},
2157
+ standalone: {}
2158
+ };
2159
+ this.monthsCache = {
2160
+ format: {},
2161
+ standalone: {}
2162
+ };
2163
+ this.meridiemCache = null;
2164
+ this.eraCache = {};
2165
+ this.specifiedLocale = specifiedLocale;
2166
+ this.fastNumbersCached = null;
2167
+ }
2168
+ get fastNumbers() {
2169
+ if (this.fastNumbersCached == null) {
2170
+ this.fastNumbersCached = supportsFastNumbers(this);
2171
+ }
2172
+ return this.fastNumbersCached;
2173
+ }
2174
+ listingMode() {
2175
+ const isActuallyEn = this.isEnglish();
2176
+ const hasNoWeirdness = (this.numberingSystem === null || this.numberingSystem === "latn") && (this.outputCalendar === null || this.outputCalendar === "gregory");
2177
+ return isActuallyEn && hasNoWeirdness ? "en" : "intl";
2178
+ }
2179
+ clone(alts) {
2180
+ if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
2181
+ return this;
2182
+ } else {
2183
+ return Locale.create(alts.locale || this.specifiedLocale, alts.numberingSystem || this.numberingSystem, alts.outputCalendar || this.outputCalendar, alts.defaultToEN || false);
2184
+ }
2185
+ }
2186
+ redefaultToEN(alts = {}) {
2187
+ return this.clone({
2188
+ ...alts,
2189
+ defaultToEN: true
2190
+ });
2191
+ }
2192
+ redefaultToSystem(alts = {}) {
2193
+ return this.clone({
2194
+ ...alts,
2195
+ defaultToEN: false
2196
+ });
2197
+ }
2198
+ months(length, format = false, defaultOK = true) {
2199
+ return listStuff(this, length, defaultOK, months, () => {
2200
+ const intl = format ? {
2201
+ month: length,
2202
+ day: "numeric"
2203
+ } : {
2204
+ month: length
2205
+ },
2206
+ formatStr = format ? "format" : "standalone";
2207
+ if (!this.monthsCache[formatStr][length]) {
2208
+ this.monthsCache[formatStr][length] = mapMonths(dt => this.extract(dt, intl, "month"));
2209
+ }
2210
+ return this.monthsCache[formatStr][length];
2211
+ });
2212
+ }
2213
+ weekdays(length, format = false, defaultOK = true) {
2214
+ return listStuff(this, length, defaultOK, weekdays, () => {
2215
+ const intl = format ? {
2216
+ weekday: length,
2217
+ year: "numeric",
2218
+ month: "long",
2219
+ day: "numeric"
2220
+ } : {
2221
+ weekday: length
2222
+ },
2223
+ formatStr = format ? "format" : "standalone";
2224
+ if (!this.weekdaysCache[formatStr][length]) {
2225
+ this.weekdaysCache[formatStr][length] = mapWeekdays(dt => this.extract(dt, intl, "weekday"));
2226
+ }
2227
+ return this.weekdaysCache[formatStr][length];
2228
+ });
2229
+ }
2230
+ meridiems(defaultOK = true) {
2231
+ return listStuff(this, undefined, defaultOK, () => meridiems, () => {
2232
+ // In theory there could be aribitrary day periods. We're gonna assume there are exactly two
2233
+ // for AM and PM. This is probably wrong, but it's makes parsing way easier.
2234
+ if (!this.meridiemCache) {
2235
+ const intl = {
2236
+ hour: "numeric",
2237
+ hourCycle: "h12"
2238
+ };
2239
+ this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(dt => this.extract(dt, intl, "dayperiod"));
2240
+ }
2241
+ return this.meridiemCache;
2242
+ });
2243
+ }
2244
+ eras(length, defaultOK = true) {
2245
+ return listStuff(this, length, defaultOK, eras, () => {
2246
+ const intl = {
2247
+ era: length
2248
+ };
2249
+
2250
+ // This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
2251
+ // to definitely enumerate them.
2252
+ if (!this.eraCache[length]) {
2253
+ this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map(dt => this.extract(dt, intl, "era"));
2254
+ }
2255
+ return this.eraCache[length];
2256
+ });
2257
+ }
2258
+ extract(dt, intlOpts, field) {
2259
+ const df = this.dtFormatter(dt, intlOpts),
2260
+ results = df.formatToParts(),
2261
+ matching = results.find(m => m.type.toLowerCase() === field);
2262
+ return matching ? matching.value : null;
2263
+ }
2264
+ numberFormatter(opts = {}) {
2265
+ // this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
2266
+ // (in contrast, the rest of the condition is used heavily)
2267
+ return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
2268
+ }
2269
+ dtFormatter(dt, intlOpts = {}) {
2270
+ return new PolyDateFormatter(dt, this.intl, intlOpts);
2271
+ }
2272
+ relFormatter(opts = {}) {
2273
+ return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
2274
+ }
2275
+ listFormatter(opts = {}) {
2276
+ return getCachedLF(this.intl, opts);
2277
+ }
2278
+ isEnglish() {
2279
+ return this.locale === "en" || this.locale.toLowerCase() === "en-us" || new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us");
2280
+ }
2281
+ equals(other) {
2282
+ return this.locale === other.locale && this.numberingSystem === other.numberingSystem && this.outputCalendar === other.outputCalendar;
2283
+ }
2284
+ }
2285
+
2623
2286
  let singleton = null;
2624
2287
 
2625
2288
  /**
@@ -2797,6 +2460,7 @@
2797
2460
  defaultLocale = null,
2798
2461
  defaultNumberingSystem = null,
2799
2462
  defaultOutputCalendar = null,
2463
+ twoDigitCutoffYear = 60,
2800
2464
  throwOnInvalid;
2801
2465
 
2802
2466
  /**
@@ -2888,6 +2552,26 @@
2888
2552
  defaultOutputCalendar = outputCalendar;
2889
2553
  }
2890
2554
 
2555
+ /**
2556
+ * Get the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century.
2557
+ * @type {number}
2558
+ */
2559
+ static get twoDigitCutoffYear() {
2560
+ return twoDigitCutoffYear;
2561
+ }
2562
+
2563
+ /**
2564
+ * Set the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century.
2565
+ * @type {number}
2566
+ * @example Settings.twoDigitCutoffYear = 0 // cut-off year is 0, so all 'yy' are interpretted as current century
2567
+ * @example Settings.twoDigitCutoffYear = 50 // '49' -> 1949; '50' -> 2050
2568
+ * @example Settings.twoDigitCutoffYear = 1950 // interpretted as 50
2569
+ * @example Settings.twoDigitCutoffYear = 2050 // ALSO interpretted as 50
2570
+ */
2571
+ static set twoDigitCutoffYear(cutoffYear) {
2572
+ twoDigitCutoffYear = cutoffYear % 100;
2573
+ }
2574
+
2891
2575
  /**
2892
2576
  * Get whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals
2893
2577
  * @type {boolean}
@@ -2914,423 +2598,775 @@
2914
2598
  }
2915
2599
  }
2916
2600
 
2917
- // todo - remap caching
2601
+ /*
2602
+ This is just a junk drawer, containing anything used across multiple classes.
2603
+ Because Luxon is small(ish), this should stay small and we won't worry about splitting
2604
+ it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
2605
+ */
2606
+
2607
+ /**
2608
+ * @private
2609
+ */
2610
+
2611
+ // TYPES
2612
+
2613
+ function isUndefined$1(o) {
2614
+ return typeof o === "undefined";
2615
+ }
2616
+ function isNumber$2(o) {
2617
+ return typeof o === "number";
2618
+ }
2619
+ function isInteger(o) {
2620
+ return typeof o === "number" && o % 1 === 0;
2621
+ }
2622
+ function isString$2(o) {
2623
+ return typeof o === "string";
2624
+ }
2625
+ function isDate(o) {
2626
+ return Object.prototype.toString.call(o) === "[object Date]";
2627
+ }
2628
+
2629
+ // CAPABILITIES
2630
+
2631
+ function hasRelative() {
2632
+ try {
2633
+ return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
2634
+ } catch (e) {
2635
+ return false;
2636
+ }
2637
+ }
2638
+
2639
+ // OBJECTS AND ARRAYS
2640
+
2641
+ function maybeArray(thing) {
2642
+ return Array.isArray(thing) ? thing : [thing];
2643
+ }
2644
+ function bestBy(arr, by, compare) {
2645
+ if (arr.length === 0) {
2646
+ return undefined;
2647
+ }
2648
+ return arr.reduce((best, next) => {
2649
+ const pair = [by(next), next];
2650
+ if (!best) {
2651
+ return pair;
2652
+ } else if (compare(best[0], pair[0]) === best[0]) {
2653
+ return best;
2654
+ } else {
2655
+ return pair;
2656
+ }
2657
+ }, null)[1];
2658
+ }
2659
+ function pick(obj, keys) {
2660
+ return keys.reduce((a, k) => {
2661
+ a[k] = obj[k];
2662
+ return a;
2663
+ }, {});
2664
+ }
2665
+ function hasOwnProperty(obj, prop) {
2666
+ return Object.prototype.hasOwnProperty.call(obj, prop);
2667
+ }
2668
+
2669
+ // NUMBERS AND STRINGS
2918
2670
 
2919
- let intlLFCache = {};
2920
- function getCachedLF(locString, opts = {}) {
2921
- const key = JSON.stringify([locString, opts]);
2922
- let dtf = intlLFCache[key];
2923
- if (!dtf) {
2924
- dtf = new Intl.ListFormat(locString, opts);
2925
- intlLFCache[key] = dtf;
2926
- }
2927
- return dtf;
2671
+ function integerBetween(thing, bottom, top) {
2672
+ return isInteger(thing) && thing >= bottom && thing <= top;
2928
2673
  }
2929
- let intlDTCache = {};
2930
- function getCachedDTF(locString, opts = {}) {
2931
- const key = JSON.stringify([locString, opts]);
2932
- let dtf = intlDTCache[key];
2933
- if (!dtf) {
2934
- dtf = new Intl.DateTimeFormat(locString, opts);
2935
- intlDTCache[key] = dtf;
2674
+
2675
+ // x % n but takes the sign of n instead of x
2676
+ function floorMod(x, n) {
2677
+ return x - n * Math.floor(x / n);
2678
+ }
2679
+ function padStart(input, n = 2) {
2680
+ const isNeg = input < 0;
2681
+ let padded;
2682
+ if (isNeg) {
2683
+ padded = "-" + ("" + -input).padStart(n, "0");
2684
+ } else {
2685
+ padded = ("" + input).padStart(n, "0");
2936
2686
  }
2937
- return dtf;
2687
+ return padded;
2938
2688
  }
2939
- let intlNumCache = {};
2940
- function getCachedINF(locString, opts = {}) {
2941
- const key = JSON.stringify([locString, opts]);
2942
- let inf = intlNumCache[key];
2943
- if (!inf) {
2944
- inf = new Intl.NumberFormat(locString, opts);
2945
- intlNumCache[key] = inf;
2689
+ function parseInteger(string) {
2690
+ if (isUndefined$1(string) || string === null || string === "") {
2691
+ return undefined;
2692
+ } else {
2693
+ return parseInt(string, 10);
2946
2694
  }
2947
- return inf;
2948
2695
  }
2949
- let intlRelCache = {};
2950
- function getCachedRTF(locString, opts = {}) {
2951
- const {
2952
- base,
2953
- ...cacheKeyOpts
2954
- } = opts; // exclude `base` from the options
2955
- const key = JSON.stringify([locString, cacheKeyOpts]);
2956
- let inf = intlRelCache[key];
2957
- if (!inf) {
2958
- inf = new Intl.RelativeTimeFormat(locString, opts);
2959
- intlRelCache[key] = inf;
2696
+ function parseFloating(string) {
2697
+ if (isUndefined$1(string) || string === null || string === "") {
2698
+ return undefined;
2699
+ } else {
2700
+ return parseFloat(string);
2960
2701
  }
2961
- return inf;
2962
2702
  }
2963
- let sysLocaleCache = null;
2964
- function systemLocale() {
2965
- if (sysLocaleCache) {
2966
- return sysLocaleCache;
2703
+ function parseMillis(fraction) {
2704
+ // Return undefined (instead of 0) in these cases, where fraction is not set
2705
+ if (isUndefined$1(fraction) || fraction === null || fraction === "") {
2706
+ return undefined;
2967
2707
  } else {
2968
- sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
2969
- return sysLocaleCache;
2708
+ const f = parseFloat("0." + fraction) * 1000;
2709
+ return Math.floor(f);
2970
2710
  }
2971
2711
  }
2972
- function parseLocaleString(localeStr) {
2973
- // I really want to avoid writing a BCP 47 parser
2974
- // see, e.g. https://github.com/wooorm/bcp-47
2975
- // Instead, we'll do this:
2712
+ function roundTo(number, digits, towardZero = false) {
2713
+ const factor = 10 ** digits,
2714
+ rounder = towardZero ? Math.trunc : Math.round;
2715
+ return rounder(number * factor) / factor;
2716
+ }
2976
2717
 
2977
- // a) if the string has no -u extensions, just leave it alone
2978
- // b) if it does, use Intl to resolve everything
2979
- // c) if Intl fails, try again without the -u
2718
+ // DATE BASICS
2980
2719
 
2981
- const uIndex = localeStr.indexOf("-u-");
2982
- if (uIndex === -1) {
2983
- return [localeStr];
2984
- } else {
2985
- let options;
2986
- const smaller = localeStr.substring(0, uIndex);
2987
- try {
2988
- options = getCachedDTF(localeStr).resolvedOptions();
2989
- } catch (e) {
2990
- options = getCachedDTF(smaller).resolvedOptions();
2991
- }
2992
- const {
2993
- numberingSystem,
2994
- calendar
2995
- } = options;
2996
- // return the smaller one so that we can append the calendar and numbering overrides to it
2997
- return [smaller, numberingSystem, calendar];
2998
- }
2720
+ function isLeapYear(year) {
2721
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
2999
2722
  }
3000
- function intlConfigString(localeStr, numberingSystem, outputCalendar) {
3001
- if (outputCalendar || numberingSystem) {
3002
- localeStr += "-u";
3003
- if (outputCalendar) {
3004
- localeStr += `-ca-${outputCalendar}`;
3005
- }
3006
- if (numberingSystem) {
3007
- localeStr += `-nu-${numberingSystem}`;
3008
- }
3009
- return localeStr;
2723
+ function daysInYear(year) {
2724
+ return isLeapYear(year) ? 366 : 365;
2725
+ }
2726
+ function daysInMonth(year, month) {
2727
+ const modMonth = floorMod(month - 1, 12) + 1,
2728
+ modYear = year + (month - modMonth) / 12;
2729
+ if (modMonth === 2) {
2730
+ return isLeapYear(modYear) ? 29 : 28;
3010
2731
  } else {
3011
- return localeStr;
2732
+ return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
3012
2733
  }
3013
2734
  }
3014
- function mapMonths(f) {
3015
- const ms = [];
3016
- for (let i = 1; i <= 12; i++) {
3017
- const dt = DateTime.utc(2016, i, 1);
3018
- ms.push(f(dt));
2735
+
2736
+ // covert a calendar object to a local timestamp (epoch, but with the offset baked in)
2737
+ function objToLocalTS(obj) {
2738
+ let d = Date.UTC(obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, obj.millisecond);
2739
+
2740
+ // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
2741
+ if (obj.year < 100 && obj.year >= 0) {
2742
+ d = new Date(d);
2743
+ d.setUTCFullYear(d.getUTCFullYear() - 1900);
3019
2744
  }
3020
- return ms;
2745
+ return +d;
3021
2746
  }
3022
- function mapWeekdays(f) {
3023
- const ms = [];
3024
- for (let i = 1; i <= 7; i++) {
3025
- const dt = DateTime.utc(2016, 11, 13 + i);
3026
- ms.push(f(dt));
3027
- }
3028
- return ms;
2747
+ function weeksInWeekYear(weekYear) {
2748
+ const p1 = (weekYear + Math.floor(weekYear / 4) - Math.floor(weekYear / 100) + Math.floor(weekYear / 400)) % 7,
2749
+ last = weekYear - 1,
2750
+ p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7;
2751
+ return p1 === 4 || p2 === 3 ? 53 : 52;
3029
2752
  }
3030
- function listStuff(loc, length, defaultOK, englishFn, intlFn) {
3031
- const mode = loc.listingMode(defaultOK);
3032
- if (mode === "error") {
3033
- return null;
3034
- } else if (mode === "en") {
3035
- return englishFn(length);
3036
- } else {
3037
- return intlFn(length);
2753
+ function untruncateYear(year) {
2754
+ if (year > 99) {
2755
+ return year;
2756
+ } else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
2757
+ }
2758
+
2759
+ // PARSING
2760
+
2761
+ function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
2762
+ const date = new Date(ts),
2763
+ intlOpts = {
2764
+ hourCycle: "h23",
2765
+ year: "numeric",
2766
+ month: "2-digit",
2767
+ day: "2-digit",
2768
+ hour: "2-digit",
2769
+ minute: "2-digit"
2770
+ };
2771
+ if (timeZone) {
2772
+ intlOpts.timeZone = timeZone;
3038
2773
  }
2774
+ const modified = {
2775
+ timeZoneName: offsetFormat,
2776
+ ...intlOpts
2777
+ };
2778
+ const parsed = new Intl.DateTimeFormat(locale, modified).formatToParts(date).find(m => m.type.toLowerCase() === "timezonename");
2779
+ return parsed ? parsed.value : null;
3039
2780
  }
3040
- function supportsFastNumbers(loc) {
3041
- if (loc.numberingSystem && loc.numberingSystem !== "latn") {
3042
- return false;
3043
- } else {
3044
- return loc.numberingSystem === "latn" || !loc.locale || loc.locale.startsWith("en") || new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn";
2781
+
2782
+ // signedOffset('-5', '30') -> -330
2783
+ function signedOffset(offHourStr, offMinuteStr) {
2784
+ let offHour = parseInt(offHourStr, 10);
2785
+
2786
+ // don't || this because we want to preserve -0
2787
+ if (Number.isNaN(offHour)) {
2788
+ offHour = 0;
3045
2789
  }
2790
+ const offMin = parseInt(offMinuteStr, 10) || 0,
2791
+ offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
2792
+ return offHour * 60 + offMinSigned;
3046
2793
  }
3047
2794
 
3048
- /**
3049
- * @private
3050
- */
2795
+ // COERCION
3051
2796
 
3052
- class PolyNumberFormatter {
3053
- constructor(intl, forceSimple, opts) {
3054
- this.padTo = opts.padTo || 0;
3055
- this.floor = opts.floor || false;
3056
- const {
3057
- padTo,
3058
- floor,
3059
- ...otherOpts
3060
- } = opts;
3061
- if (!forceSimple || Object.keys(otherOpts).length > 0) {
3062
- const intlOpts = {
3063
- useGrouping: false,
3064
- ...opts
3065
- };
3066
- if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
3067
- this.inf = getCachedINF(intl, intlOpts);
2797
+ function asNumber(value) {
2798
+ const numericValue = Number(value);
2799
+ if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue)) throw new InvalidArgumentError(`Invalid unit value ${value}`);
2800
+ return numericValue;
2801
+ }
2802
+ function normalizeObject(obj, normalizer) {
2803
+ const normalized = {};
2804
+ for (const u in obj) {
2805
+ if (hasOwnProperty(obj, u)) {
2806
+ const v = obj[u];
2807
+ if (v === undefined || v === null) continue;
2808
+ normalized[normalizer(u)] = asNumber(v);
3068
2809
  }
3069
2810
  }
3070
- format(i) {
3071
- if (this.inf) {
3072
- const fixed = this.floor ? Math.floor(i) : i;
3073
- return this.inf.format(fixed);
3074
- } else {
3075
- // to match the browser's numberformatter defaults
3076
- const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
3077
- return padStart(fixed, this.padTo);
3078
- }
2811
+ return normalized;
2812
+ }
2813
+ function formatOffset(offset, format) {
2814
+ const hours = Math.trunc(Math.abs(offset / 60)),
2815
+ minutes = Math.trunc(Math.abs(offset % 60)),
2816
+ sign = offset >= 0 ? "+" : "-";
2817
+ switch (format) {
2818
+ case "short":
2819
+ return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
2820
+ case "narrow":
2821
+ return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
2822
+ case "techie":
2823
+ return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
2824
+ default:
2825
+ throw new RangeError(`Value format ${format} is out of range for property format`);
3079
2826
  }
3080
2827
  }
2828
+ function timeObject(obj) {
2829
+ return pick(obj, ["hour", "minute", "second", "millisecond"]);
2830
+ }
3081
2831
 
3082
2832
  /**
3083
2833
  * @private
3084
2834
  */
3085
2835
 
3086
- class PolyDateFormatter {
3087
- constructor(dt, intl, opts) {
3088
- this.opts = opts;
3089
- let z;
3090
- if (dt.zone.isUniversal) {
3091
- // UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
3092
- // That is why fixed-offset TZ is set to that unless it is:
3093
- // 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
3094
- // 2. Unsupported by the browser:
3095
- // - some do not support Etc/
3096
- // - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
3097
- const gmtOffset = -1 * (dt.offset / 60);
3098
- const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
3099
- if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
3100
- z = offsetZ;
3101
- this.dt = dt;
3102
- } else {
3103
- // Not all fixed-offset zones like Etc/+4:30 are present in tzdata.
3104
- // So we have to make do. Two cases:
3105
- // 1. The format options tell us to show the zone. We can't do that, so the best
3106
- // we can do is format the date in UTC.
3107
- // 2. The format options don't tell us to show the zone. Then we can adjust them
3108
- // the time and tell the formatter to show it to us in UTC, so that the time is right
3109
- // and the bad zone doesn't show up.
3110
- z = "UTC";
3111
- if (opts.timeZoneName) {
3112
- this.dt = dt;
3113
- } else {
3114
- this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000);
3115
- }
3116
- }
3117
- } else if (dt.zone.type === "system") {
3118
- this.dt = dt;
3119
- } else {
3120
- this.dt = dt;
3121
- z = dt.zone.name;
3122
- }
3123
- const intlOpts = {
3124
- ...this.opts
3125
- };
3126
- if (z) {
3127
- intlOpts.timeZone = z;
3128
- }
3129
- this.dtf = getCachedDTF(intl, intlOpts);
3130
- }
3131
- format() {
3132
- return this.dtf.format(this.dt.toJSDate());
3133
- }
3134
- formatToParts() {
3135
- return this.dtf.formatToParts(this.dt.toJSDate());
2836
+ const monthsLong = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
2837
+ const monthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
2838
+ const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
2839
+ function months(length) {
2840
+ switch (length) {
2841
+ case "narrow":
2842
+ return [...monthsNarrow];
2843
+ case "short":
2844
+ return [...monthsShort];
2845
+ case "long":
2846
+ return [...monthsLong];
2847
+ case "numeric":
2848
+ return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
2849
+ case "2-digit":
2850
+ return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
2851
+ default:
2852
+ return null;
3136
2853
  }
3137
- resolvedOptions() {
3138
- return this.dtf.resolvedOptions();
2854
+ }
2855
+ const weekdaysLong = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
2856
+ const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
2857
+ const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
2858
+ function weekdays(length) {
2859
+ switch (length) {
2860
+ case "narrow":
2861
+ return [...weekdaysNarrow];
2862
+ case "short":
2863
+ return [...weekdaysShort];
2864
+ case "long":
2865
+ return [...weekdaysLong];
2866
+ case "numeric":
2867
+ return ["1", "2", "3", "4", "5", "6", "7"];
2868
+ default:
2869
+ return null;
3139
2870
  }
3140
2871
  }
3141
-
3142
- /**
3143
- * @private
3144
- */
3145
- class PolyRelFormatter {
3146
- constructor(intl, isEnglish, opts) {
3147
- this.opts = {
3148
- style: "long",
3149
- ...opts
3150
- };
3151
- if (!isEnglish && hasRelative()) {
3152
- this.rtf = getCachedRTF(intl, opts);
3153
- }
2872
+ const meridiems = ["AM", "PM"];
2873
+ const erasLong = ["Before Christ", "Anno Domini"];
2874
+ const erasShort = ["BC", "AD"];
2875
+ const erasNarrow = ["B", "A"];
2876
+ function eras(length) {
2877
+ switch (length) {
2878
+ case "narrow":
2879
+ return [...erasNarrow];
2880
+ case "short":
2881
+ return [...erasShort];
2882
+ case "long":
2883
+ return [...erasLong];
2884
+ default:
2885
+ return null;
3154
2886
  }
3155
- format(count, unit) {
3156
- if (this.rtf) {
3157
- return this.rtf.format(count, unit);
3158
- } else {
3159
- return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
2887
+ }
2888
+ function meridiemForDateTime(dt) {
2889
+ return meridiems[dt.hour < 12 ? 0 : 1];
2890
+ }
2891
+ function weekdayForDateTime(dt, length) {
2892
+ return weekdays(length)[dt.weekday - 1];
2893
+ }
2894
+ function monthForDateTime(dt, length) {
2895
+ return months(length)[dt.month - 1];
2896
+ }
2897
+ function eraForDateTime(dt, length) {
2898
+ return eras(length)[dt.year < 0 ? 0 : 1];
2899
+ }
2900
+ function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
2901
+ const units = {
2902
+ years: ["year", "yr."],
2903
+ quarters: ["quarter", "qtr."],
2904
+ months: ["month", "mo."],
2905
+ weeks: ["week", "wk."],
2906
+ days: ["day", "day", "days"],
2907
+ hours: ["hour", "hr."],
2908
+ minutes: ["minute", "min."],
2909
+ seconds: ["second", "sec."]
2910
+ };
2911
+ const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
2912
+ if (numeric === "auto" && lastable) {
2913
+ const isDay = unit === "days";
2914
+ switch (count) {
2915
+ case 1:
2916
+ return isDay ? "tomorrow" : `next ${units[unit][0]}`;
2917
+ case -1:
2918
+ return isDay ? "yesterday" : `last ${units[unit][0]}`;
2919
+ case 0:
2920
+ return isDay ? "today" : `this ${units[unit][0]}`;
3160
2921
  }
3161
2922
  }
3162
- formatToParts(count, unit) {
3163
- if (this.rtf) {
3164
- return this.rtf.formatToParts(count, unit);
2923
+
2924
+ const isInPast = Object.is(count, -0) || count < 0,
2925
+ fmtValue = Math.abs(count),
2926
+ singular = fmtValue === 1,
2927
+ lilUnits = units[unit],
2928
+ fmtUnit = narrow ? singular ? lilUnits[1] : lilUnits[2] || lilUnits[1] : singular ? units[unit][0] : unit;
2929
+ return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
2930
+ }
2931
+
2932
+ function stringifyTokens(splits, tokenToString) {
2933
+ let s = "";
2934
+ for (const token of splits) {
2935
+ if (token.literal) {
2936
+ s += token.val;
3165
2937
  } else {
3166
- return [];
2938
+ s += tokenToString(token.val);
3167
2939
  }
3168
2940
  }
2941
+ return s;
3169
2942
  }
3170
-
3171
- /**
3172
- * @private
3173
- */
3174
-
3175
- class Locale {
3176
- static fromOpts(opts) {
3177
- return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.defaultToEN);
3178
- }
3179
- static create(locale, numberingSystem, outputCalendar, defaultToEN = false) {
3180
- const specifiedLocale = locale || Settings.defaultLocale;
3181
- // the system locale is useful for human readable strings but annoying for parsing/formatting known formats
3182
- const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
3183
- const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
3184
- const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
3185
- return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale);
3186
- }
3187
- static resetCache() {
3188
- sysLocaleCache = null;
3189
- intlDTCache = {};
3190
- intlNumCache = {};
3191
- intlRelCache = {};
3192
- }
3193
- static fromObject({
3194
- locale,
3195
- numberingSystem,
3196
- outputCalendar
3197
- } = {}) {
3198
- return Locale.create(locale, numberingSystem, outputCalendar);
3199
- }
3200
- constructor(locale, numbering, outputCalendar, specifiedLocale) {
3201
- const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
3202
- this.locale = parsedLocale;
3203
- this.numberingSystem = numbering || parsedNumberingSystem || null;
3204
- this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
3205
- this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
3206
- this.weekdaysCache = {
3207
- format: {},
3208
- standalone: {}
3209
- };
3210
- this.monthsCache = {
3211
- format: {},
3212
- standalone: {}
3213
- };
3214
- this.meridiemCache = null;
3215
- this.eraCache = {};
3216
- this.specifiedLocale = specifiedLocale;
3217
- this.fastNumbersCached = null;
2943
+ const macroTokenToFormatOpts = {
2944
+ D: DATE_SHORT,
2945
+ DD: DATE_MED,
2946
+ DDD: DATE_FULL,
2947
+ DDDD: DATE_HUGE,
2948
+ t: TIME_SIMPLE,
2949
+ tt: TIME_WITH_SECONDS,
2950
+ ttt: TIME_WITH_SHORT_OFFSET,
2951
+ tttt: TIME_WITH_LONG_OFFSET,
2952
+ T: TIME_24_SIMPLE,
2953
+ TT: TIME_24_WITH_SECONDS,
2954
+ TTT: TIME_24_WITH_SHORT_OFFSET,
2955
+ TTTT: TIME_24_WITH_LONG_OFFSET,
2956
+ f: DATETIME_SHORT,
2957
+ ff: DATETIME_MED,
2958
+ fff: DATETIME_FULL,
2959
+ ffff: DATETIME_HUGE,
2960
+ F: DATETIME_SHORT_WITH_SECONDS,
2961
+ FF: DATETIME_MED_WITH_SECONDS,
2962
+ FFF: DATETIME_FULL_WITH_SECONDS,
2963
+ FFFF: DATETIME_HUGE_WITH_SECONDS
2964
+ };
2965
+
2966
+ /**
2967
+ * @private
2968
+ */
2969
+
2970
+ class Formatter {
2971
+ static create(locale, opts = {}) {
2972
+ return new Formatter(locale, opts);
3218
2973
  }
3219
- get fastNumbers() {
3220
- if (this.fastNumbersCached == null) {
3221
- this.fastNumbersCached = supportsFastNumbers(this);
2974
+ static parseFormat(fmt) {
2975
+ let current = null,
2976
+ currentFull = "",
2977
+ bracketed = false;
2978
+ const splits = [];
2979
+ for (let i = 0; i < fmt.length; i++) {
2980
+ const c = fmt.charAt(i);
2981
+ if (c === "'") {
2982
+ if (currentFull.length > 0) {
2983
+ splits.push({
2984
+ literal: bracketed,
2985
+ val: currentFull
2986
+ });
2987
+ }
2988
+ current = null;
2989
+ currentFull = "";
2990
+ bracketed = !bracketed;
2991
+ } else if (bracketed) {
2992
+ currentFull += c;
2993
+ } else if (c === current) {
2994
+ currentFull += c;
2995
+ } else {
2996
+ if (currentFull.length > 0) {
2997
+ splits.push({
2998
+ literal: false,
2999
+ val: currentFull
3000
+ });
3001
+ }
3002
+ currentFull = c;
3003
+ current = c;
3004
+ }
3222
3005
  }
3223
- return this.fastNumbersCached;
3006
+ if (currentFull.length > 0) {
3007
+ splits.push({
3008
+ literal: bracketed,
3009
+ val: currentFull
3010
+ });
3011
+ }
3012
+ return splits;
3224
3013
  }
3225
- listingMode() {
3226
- const isActuallyEn = this.isEnglish();
3227
- const hasNoWeirdness = (this.numberingSystem === null || this.numberingSystem === "latn") && (this.outputCalendar === null || this.outputCalendar === "gregory");
3228
- return isActuallyEn && hasNoWeirdness ? "en" : "intl";
3014
+ static macroTokenToFormatOpts(token) {
3015
+ return macroTokenToFormatOpts[token];
3229
3016
  }
3230
- clone(alts) {
3231
- if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
3232
- return this;
3233
- } else {
3234
- return Locale.create(alts.locale || this.specifiedLocale, alts.numberingSystem || this.numberingSystem, alts.outputCalendar || this.outputCalendar, alts.defaultToEN || false);
3235
- }
3017
+ constructor(locale, formatOpts) {
3018
+ this.opts = formatOpts;
3019
+ this.loc = locale;
3020
+ this.systemLoc = null;
3236
3021
  }
3237
- redefaultToEN(alts = {}) {
3238
- return this.clone({
3239
- ...alts,
3240
- defaultToEN: true
3022
+ formatWithSystemDefault(dt, opts) {
3023
+ if (this.systemLoc === null) {
3024
+ this.systemLoc = this.loc.redefaultToSystem();
3025
+ }
3026
+ const df = this.systemLoc.dtFormatter(dt, {
3027
+ ...this.opts,
3028
+ ...opts
3241
3029
  });
3030
+ return df.format();
3242
3031
  }
3243
- redefaultToSystem(alts = {}) {
3244
- return this.clone({
3245
- ...alts,
3246
- defaultToEN: false
3032
+ formatDateTime(dt, opts = {}) {
3033
+ const df = this.loc.dtFormatter(dt, {
3034
+ ...this.opts,
3035
+ ...opts
3247
3036
  });
3037
+ return df.format();
3248
3038
  }
3249
- months(length, format = false, defaultOK = true) {
3250
- return listStuff(this, length, defaultOK, months, () => {
3251
- const intl = format ? {
3252
- month: length,
3253
- day: "numeric"
3254
- } : {
3255
- month: length
3256
- },
3257
- formatStr = format ? "format" : "standalone";
3258
- if (!this.monthsCache[formatStr][length]) {
3259
- this.monthsCache[formatStr][length] = mapMonths(dt => this.extract(dt, intl, "month"));
3260
- }
3261
- return this.monthsCache[formatStr][length];
3039
+ formatDateTimeParts(dt, opts = {}) {
3040
+ const df = this.loc.dtFormatter(dt, {
3041
+ ...this.opts,
3042
+ ...opts
3262
3043
  });
3044
+ return df.formatToParts();
3263
3045
  }
3264
- weekdays(length, format = false, defaultOK = true) {
3265
- return listStuff(this, length, defaultOK, weekdays, () => {
3266
- const intl = format ? {
3267
- weekday: length,
3268
- year: "numeric",
3269
- month: "long",
3270
- day: "numeric"
3271
- } : {
3272
- weekday: length
3273
- },
3274
- formatStr = format ? "format" : "standalone";
3275
- if (!this.weekdaysCache[formatStr][length]) {
3276
- this.weekdaysCache[formatStr][length] = mapWeekdays(dt => this.extract(dt, intl, "weekday"));
3277
- }
3278
- return this.weekdaysCache[formatStr][length];
3046
+ formatInterval(interval, opts = {}) {
3047
+ const df = this.loc.dtFormatter(interval.start, {
3048
+ ...this.opts,
3049
+ ...opts
3279
3050
  });
3051
+ return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate());
3280
3052
  }
3281
- meridiems(defaultOK = true) {
3282
- return listStuff(this, undefined, defaultOK, () => meridiems, () => {
3283
- // In theory there could be aribitrary day periods. We're gonna assume there are exactly two
3284
- // for AM and PM. This is probably wrong, but it's makes parsing way easier.
3285
- if (!this.meridiemCache) {
3286
- const intl = {
3287
- hour: "numeric",
3288
- hourCycle: "h12"
3289
- };
3290
- this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(dt => this.extract(dt, intl, "dayperiod"));
3291
- }
3292
- return this.meridiemCache;
3053
+ resolvedOptions(dt, opts = {}) {
3054
+ const df = this.loc.dtFormatter(dt, {
3055
+ ...this.opts,
3056
+ ...opts
3293
3057
  });
3058
+ return df.resolvedOptions();
3294
3059
  }
3295
- eras(length, defaultOK = true) {
3296
- return listStuff(this, length, defaultOK, eras, () => {
3297
- const intl = {
3060
+ num(n, p = 0) {
3061
+ // we get some perf out of doing this here, annoyingly
3062
+ if (this.opts.forceSimple) {
3063
+ return padStart(n, p);
3064
+ }
3065
+ const opts = {
3066
+ ...this.opts
3067
+ };
3068
+ if (p > 0) {
3069
+ opts.padTo = p;
3070
+ }
3071
+ return this.loc.numberFormatter(opts).format(n);
3072
+ }
3073
+ formatDateTimeFromString(dt, fmt) {
3074
+ const knownEnglish = this.loc.listingMode() === "en",
3075
+ useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
3076
+ string = (opts, extract) => this.loc.extract(dt, opts, extract),
3077
+ formatOffset = opts => {
3078
+ if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
3079
+ return "Z";
3080
+ }
3081
+ return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
3082
+ },
3083
+ meridiem = () => knownEnglish ? meridiemForDateTime(dt) : string({
3084
+ hour: "numeric",
3085
+ hourCycle: "h12"
3086
+ }, "dayperiod"),
3087
+ month = (length, standalone) => knownEnglish ? monthForDateTime(dt, length) : string(standalone ? {
3088
+ month: length
3089
+ } : {
3090
+ month: length,
3091
+ day: "numeric"
3092
+ }, "month"),
3093
+ weekday = (length, standalone) => knownEnglish ? weekdayForDateTime(dt, length) : string(standalone ? {
3094
+ weekday: length
3095
+ } : {
3096
+ weekday: length,
3097
+ month: "long",
3098
+ day: "numeric"
3099
+ }, "weekday"),
3100
+ maybeMacro = token => {
3101
+ const formatOpts = Formatter.macroTokenToFormatOpts(token);
3102
+ if (formatOpts) {
3103
+ return this.formatWithSystemDefault(dt, formatOpts);
3104
+ } else {
3105
+ return token;
3106
+ }
3107
+ },
3108
+ era = length => knownEnglish ? eraForDateTime(dt, length) : string({
3298
3109
  era: length
3110
+ }, "era"),
3111
+ tokenToString = token => {
3112
+ // Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles
3113
+ switch (token) {
3114
+ // ms
3115
+ case "S":
3116
+ return this.num(dt.millisecond);
3117
+ case "u":
3118
+ // falls through
3119
+ case "SSS":
3120
+ return this.num(dt.millisecond, 3);
3121
+ // seconds
3122
+ case "s":
3123
+ return this.num(dt.second);
3124
+ case "ss":
3125
+ return this.num(dt.second, 2);
3126
+ // fractional seconds
3127
+ case "uu":
3128
+ return this.num(Math.floor(dt.millisecond / 10), 2);
3129
+ case "uuu":
3130
+ return this.num(Math.floor(dt.millisecond / 100));
3131
+ // minutes
3132
+ case "m":
3133
+ return this.num(dt.minute);
3134
+ case "mm":
3135
+ return this.num(dt.minute, 2);
3136
+ // hours
3137
+ case "h":
3138
+ return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
3139
+ case "hh":
3140
+ return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
3141
+ case "H":
3142
+ return this.num(dt.hour);
3143
+ case "HH":
3144
+ return this.num(dt.hour, 2);
3145
+ // offset
3146
+ case "Z":
3147
+ // like +6
3148
+ return formatOffset({
3149
+ format: "narrow",
3150
+ allowZ: this.opts.allowZ
3151
+ });
3152
+ case "ZZ":
3153
+ // like +06:00
3154
+ return formatOffset({
3155
+ format: "short",
3156
+ allowZ: this.opts.allowZ
3157
+ });
3158
+ case "ZZZ":
3159
+ // like +0600
3160
+ return formatOffset({
3161
+ format: "techie",
3162
+ allowZ: this.opts.allowZ
3163
+ });
3164
+ case "ZZZZ":
3165
+ // like EST
3166
+ return dt.zone.offsetName(dt.ts, {
3167
+ format: "short",
3168
+ locale: this.loc.locale
3169
+ });
3170
+ case "ZZZZZ":
3171
+ // like Eastern Standard Time
3172
+ return dt.zone.offsetName(dt.ts, {
3173
+ format: "long",
3174
+ locale: this.loc.locale
3175
+ });
3176
+ // zone
3177
+ case "z":
3178
+ // like America/New_York
3179
+ return dt.zoneName;
3180
+ // meridiems
3181
+ case "a":
3182
+ return meridiem();
3183
+ // dates
3184
+ case "d":
3185
+ return useDateTimeFormatter ? string({
3186
+ day: "numeric"
3187
+ }, "day") : this.num(dt.day);
3188
+ case "dd":
3189
+ return useDateTimeFormatter ? string({
3190
+ day: "2-digit"
3191
+ }, "day") : this.num(dt.day, 2);
3192
+ // weekdays - standalone
3193
+ case "c":
3194
+ // like 1
3195
+ return this.num(dt.weekday);
3196
+ case "ccc":
3197
+ // like 'Tues'
3198
+ return weekday("short", true);
3199
+ case "cccc":
3200
+ // like 'Tuesday'
3201
+ return weekday("long", true);
3202
+ case "ccccc":
3203
+ // like 'T'
3204
+ return weekday("narrow", true);
3205
+ // weekdays - format
3206
+ case "E":
3207
+ // like 1
3208
+ return this.num(dt.weekday);
3209
+ case "EEE":
3210
+ // like 'Tues'
3211
+ return weekday("short", false);
3212
+ case "EEEE":
3213
+ // like 'Tuesday'
3214
+ return weekday("long", false);
3215
+ case "EEEEE":
3216
+ // like 'T'
3217
+ return weekday("narrow", false);
3218
+ // months - standalone
3219
+ case "L":
3220
+ // like 1
3221
+ return useDateTimeFormatter ? string({
3222
+ month: "numeric",
3223
+ day: "numeric"
3224
+ }, "month") : this.num(dt.month);
3225
+ case "LL":
3226
+ // like 01, doesn't seem to work
3227
+ return useDateTimeFormatter ? string({
3228
+ month: "2-digit",
3229
+ day: "numeric"
3230
+ }, "month") : this.num(dt.month, 2);
3231
+ case "LLL":
3232
+ // like Jan
3233
+ return month("short", true);
3234
+ case "LLLL":
3235
+ // like January
3236
+ return month("long", true);
3237
+ case "LLLLL":
3238
+ // like J
3239
+ return month("narrow", true);
3240
+ // months - format
3241
+ case "M":
3242
+ // like 1
3243
+ return useDateTimeFormatter ? string({
3244
+ month: "numeric"
3245
+ }, "month") : this.num(dt.month);
3246
+ case "MM":
3247
+ // like 01
3248
+ return useDateTimeFormatter ? string({
3249
+ month: "2-digit"
3250
+ }, "month") : this.num(dt.month, 2);
3251
+ case "MMM":
3252
+ // like Jan
3253
+ return month("short", false);
3254
+ case "MMMM":
3255
+ // like January
3256
+ return month("long", false);
3257
+ case "MMMMM":
3258
+ // like J
3259
+ return month("narrow", false);
3260
+ // years
3261
+ case "y":
3262
+ // like 2014
3263
+ return useDateTimeFormatter ? string({
3264
+ year: "numeric"
3265
+ }, "year") : this.num(dt.year);
3266
+ case "yy":
3267
+ // like 14
3268
+ return useDateTimeFormatter ? string({
3269
+ year: "2-digit"
3270
+ }, "year") : this.num(dt.year.toString().slice(-2), 2);
3271
+ case "yyyy":
3272
+ // like 0012
3273
+ return useDateTimeFormatter ? string({
3274
+ year: "numeric"
3275
+ }, "year") : this.num(dt.year, 4);
3276
+ case "yyyyyy":
3277
+ // like 000012
3278
+ return useDateTimeFormatter ? string({
3279
+ year: "numeric"
3280
+ }, "year") : this.num(dt.year, 6);
3281
+ // eras
3282
+ case "G":
3283
+ // like AD
3284
+ return era("short");
3285
+ case "GG":
3286
+ // like Anno Domini
3287
+ return era("long");
3288
+ case "GGGGG":
3289
+ return era("narrow");
3290
+ case "kk":
3291
+ return this.num(dt.weekYear.toString().slice(-2), 2);
3292
+ case "kkkk":
3293
+ return this.num(dt.weekYear, 4);
3294
+ case "W":
3295
+ return this.num(dt.weekNumber);
3296
+ case "WW":
3297
+ return this.num(dt.weekNumber, 2);
3298
+ case "o":
3299
+ return this.num(dt.ordinal);
3300
+ case "ooo":
3301
+ return this.num(dt.ordinal, 3);
3302
+ case "q":
3303
+ // like 1
3304
+ return this.num(dt.quarter);
3305
+ case "qq":
3306
+ // like 01
3307
+ return this.num(dt.quarter, 2);
3308
+ case "X":
3309
+ return this.num(Math.floor(dt.ts / 1000));
3310
+ case "x":
3311
+ return this.num(dt.ts);
3312
+ default:
3313
+ return maybeMacro(token);
3314
+ }
3299
3315
  };
3300
-
3301
- // This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
3302
- // to definitely enumerate them.
3303
- if (!this.eraCache[length]) {
3304
- this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map(dt => this.extract(dt, intl, "era"));
3305
- }
3306
- return this.eraCache[length];
3307
- });
3308
- }
3309
- extract(dt, intlOpts, field) {
3310
- const df = this.dtFormatter(dt, intlOpts),
3311
- results = df.formatToParts(),
3312
- matching = results.find(m => m.type.toLowerCase() === field);
3313
- return matching ? matching.value : null;
3314
- }
3315
- numberFormatter(opts = {}) {
3316
- // this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
3317
- // (in contrast, the rest of the condition is used heavily)
3318
- return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
3319
- }
3320
- dtFormatter(dt, intlOpts = {}) {
3321
- return new PolyDateFormatter(dt, this.intl, intlOpts);
3322
- }
3323
- relFormatter(opts = {}) {
3324
- return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
3316
+ return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
3325
3317
  }
3326
- listFormatter(opts = {}) {
3327
- return getCachedLF(this.intl, opts);
3318
+ formatDurationFromString(dur, fmt) {
3319
+ const tokenToField = token => {
3320
+ switch (token[0]) {
3321
+ case "S":
3322
+ return "millisecond";
3323
+ case "s":
3324
+ return "second";
3325
+ case "m":
3326
+ return "minute";
3327
+ case "h":
3328
+ return "hour";
3329
+ case "d":
3330
+ return "day";
3331
+ case "w":
3332
+ return "week";
3333
+ case "M":
3334
+ return "month";
3335
+ case "y":
3336
+ return "year";
3337
+ default:
3338
+ return null;
3339
+ }
3340
+ },
3341
+ tokenToString = lildur => token => {
3342
+ const mapped = tokenToField(token);
3343
+ if (mapped) {
3344
+ return this.num(lildur.get(mapped), token.length);
3345
+ } else {
3346
+ return token;
3347
+ }
3348
+ },
3349
+ tokens = Formatter.parseFormat(fmt),
3350
+ realTokens = tokens.reduce((found, {
3351
+ literal,
3352
+ val
3353
+ }) => literal ? found : found.concat(val), []),
3354
+ collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter(t => t));
3355
+ return stringifyTokens(tokens, tokenToString(collapsed));
3328
3356
  }
3329
- isEnglish() {
3330
- return this.locale === "en" || this.locale.toLowerCase() === "en-us" || new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us");
3357
+ }
3358
+
3359
+ class Invalid {
3360
+ constructor(reason, explanation) {
3361
+ this.reason = reason;
3362
+ this.explanation = explanation;
3331
3363
  }
3332
- equals(other) {
3333
- return this.locale === other.locale && this.numberingSystem === other.numberingSystem && this.outputCalendar === other.outputCalendar;
3364
+ toMessage() {
3365
+ if (this.explanation) {
3366
+ return `${this.reason}: ${this.explanation}`;
3367
+ } else {
3368
+ return this.reason;
3369
+ }
3334
3370
  }
3335
3371
  }
3336
3372
 
@@ -3344,6 +3380,7 @@
3344
3380
  * Some extractions are super dumb and simpleParse and fromStrings help DRY them.
3345
3381
  */
3346
3382
 
3383
+ const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
3347
3384
  function combineRegexes(...regexes) {
3348
3385
  const full = regexes.reduce((f, r) => f + r.source, "");
3349
3386
  return RegExp(`^${full}$`);
@@ -3496,7 +3533,7 @@
3496
3533
  }
3497
3534
  function preprocessRFC2822(s) {
3498
3535
  // Remove comments and folding whitespace and replace multiple-spaces with a single space
3499
- return s.replace(/\([^)]*\)|[\n\t]/g, " ").replace(/(\s\s+)/g, " ").trim();
3536
+ return s.replace(/\([^()]*\)|[\n\t]/g, " ").replace(/(\s\s+)/g, " ").trim();
3500
3537
  }
3501
3538
 
3502
3539
  // http date
@@ -3690,6 +3727,17 @@
3690
3727
  }, null);
3691
3728
  }
3692
3729
 
3730
+ // Remove all properties with a value of 0 from an object
3731
+ function removeZeroes(vals) {
3732
+ const newVals = {};
3733
+ for (const [key, value] of Object.entries(vals)) {
3734
+ if (value !== 0) {
3735
+ newVals[key] = value;
3736
+ }
3737
+ }
3738
+ return newVals;
3739
+ }
3740
+
3693
3741
  /**
3694
3742
  * A Duration object represents a period of time, like "2 months" or "1 day, 1 hour". Conceptually, it's just a map of units to their quantities, accompanied by some additional configuration and methods for creating, parsing, interrogating, transforming, and formatting them. They can be used on their own or in conjunction with other Luxon types; for example, you can use {@link DateTime#plus} to add a Duration object to a DateTime, producing another DateTime.
3695
3743
  *
@@ -4238,6 +4286,19 @@
4238
4286
  }, true);
4239
4287
  }
4240
4288
 
4289
+ /**
4290
+ * Rescale units to its largest representation
4291
+ * @example Duration.fromObject({ milliseconds: 90000 }).rescale().toObject() //=> { minutes: 1, seconds: 30 }
4292
+ * @return {Duration}
4293
+ */
4294
+ rescale() {
4295
+ if (!this.isValid) return this;
4296
+ const vals = removeZeroes(this.normalize().shiftToAll().toObject());
4297
+ return clone$2(this, {
4298
+ values: vals
4299
+ }, true);
4300
+ }
4301
+
4241
4302
  /**
4242
4303
  * Convert this Duration into its representation in a different set of units.
4243
4304
  * @example Duration.fromObject({ hours: 1, seconds: 30 }).shiftTo('minutes', 'milliseconds').toObject() //=> { minutes: 60, milliseconds: 30000 }
@@ -4296,6 +4357,16 @@
4296
4357
  }, true).normalize();
4297
4358
  }
4298
4359
 
4360
+ /**
4361
+ * Shift this Duration to all available units.
4362
+ * Same as shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds")
4363
+ * @return {Duration}
4364
+ */
4365
+ shiftToAll() {
4366
+ if (!this.isValid) return this;
4367
+ return this.shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds");
4368
+ }
4369
+
4299
4370
  /**
4300
4371
  * Return the negative of this Duration.
4301
4372
  * @example Duration.fromObject({ hours: 1, seconds: 30 }).negate().toObject() //=> { hours: -1, seconds: -30 }
@@ -4461,7 +4532,7 @@
4461
4532
  * * **Interrogation** To analyze the Interval, use {@link Interval#count}, {@link Interval#length}, {@link Interval#hasSame}, {@link Interval#contains}, {@link Interval#isAfter}, or {@link Interval#isBefore}.
4462
4533
  * * **Transformation** To create other Intervals out of this one, use {@link Interval#set}, {@link Interval#splitAt}, {@link Interval#splitBy}, {@link Interval#divideEqually}, {@link Interval.merge}, {@link Interval.xor}, {@link Interval#union}, {@link Interval#intersection}, or {@link Interval#difference}.
4463
4534
  * * **Comparison** To compare this Interval to another one, use {@link Interval#equals}, {@link Interval#overlaps}, {@link Interval#abutsStart}, {@link Interval#abutsEnd}, {@link Interval#engulfs}
4464
- * * **Output** To convert the Interval into other representations, see {@link Interval#toString}, {@link Interval#toISO}, {@link Interval#toISODate}, {@link Interval#toISOTime}, {@link Interval#toFormat}, and {@link Interval#toDuration}.
4535
+ * * **Output** To convert the Interval into other representations, see {@link Interval#toString}, {@link Interval#toLocaleString}, {@link Interval#toISO}, {@link Interval#toISODate}, {@link Interval#toISOTime}, {@link Interval#toFormat}, and {@link Interval#toDuration}.
4465
4536
  */
4466
4537
  class Interval {
4467
4538
  /**
@@ -4941,6 +5012,28 @@
4941
5012
  return `[${this.s.toISO()} – ${this.e.toISO()})`;
4942
5013
  }
4943
5014
 
5015
+ /**
5016
+ * Returns a localized string representing this Interval. Accepts the same options as the
5017
+ * Intl.DateTimeFormat constructor and any presets defined by Luxon, such as
5018
+ * {@link DateTime.DATE_FULL} or {@link DateTime.TIME_SIMPLE}. The exact behavior of this method
5019
+ * is browser-specific, but in general it will return an appropriate representation of the
5020
+ * Interval in the assigned locale. Defaults to the system's locale if no locale has been
5021
+ * specified.
5022
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
5023
+ * @param {Object} [formatOpts=DateTime.DATE_SHORT] - Either a DateTime preset or
5024
+ * Intl.DateTimeFormat constructor options.
5025
+ * @param {Object} opts - Options to override the configuration of the start DateTime.
5026
+ * @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(); //=> 11/7/2022 – 11/8/2022
5027
+ * @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL); //=> November 7 – 8, 2022
5028
+ * @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL, { locale: 'fr-FR' }); //=> 7–8 novembre 2022
5029
+ * @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString(DateTime.TIME_SIMPLE); //=> 6:00 – 8:00 PM
5030
+ * @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString({ weekday: 'short', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); //=> Mon, Nov 07, 6:00 – 8:00 p
5031
+ * @return {string}
5032
+ */
5033
+ toLocaleString(formatOpts = DATE_SHORT, opts = {}) {
5034
+ return this.isValid ? Formatter.create(this.s.loc.clone(opts), formatOpts).formatInterval(this) : INVALID$3;
5035
+ }
5036
+
4944
5037
  /**
4945
5038
  * Returns an ISO 8601-compliant string representation of this Interval.
4946
5039
  * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
@@ -4976,10 +5069,14 @@
4976
5069
  }
4977
5070
 
4978
5071
  /**
4979
- * Returns a string representation of this Interval formatted according to the specified format string.
4980
- * @param {string} dateFormat - the format string. This string formats the start and end time. See {@link DateTime#toFormat} for details.
4981
- * @param {Object} opts - options
4982
- * @param {string} [opts.separator = ' '] - a separator to place between the start and end representations
5072
+ * Returns a string representation of this Interval formatted according to the specified format
5073
+ * string. **You may not want this.** See {@link Interval#toLocaleString} for a more flexible
5074
+ * formatting tool.
5075
+ * @param {string} dateFormat - The format string. This string formats the start and end time.
5076
+ * See {@link DateTime#toFormat} for details.
5077
+ * @param {Object} opts - Options.
5078
+ * @param {string} [opts.separator = ' – '] - A separator to place between the start and end
5079
+ * representations.
4983
5080
  * @return {string}
4984
5081
  */
4985
5082
  toFormat(dateFormat, {
@@ -5213,23 +5310,19 @@
5213
5310
  return (days - days % 7) / 7;
5214
5311
  }], ["days", dayDiff]];
5215
5312
  const results = {};
5313
+ const earlier = cursor;
5216
5314
  let lowestOrder, highWater;
5217
5315
  for (const [unit, differ] of differs) {
5218
5316
  if (units.indexOf(unit) >= 0) {
5219
5317
  lowestOrder = unit;
5220
- let delta = differ(cursor, later);
5221
- highWater = cursor.plus({
5222
- [unit]: delta
5223
- });
5318
+ results[unit] = differ(cursor, later);
5319
+ highWater = earlier.plus(results);
5224
5320
  if (highWater > later) {
5225
- cursor = cursor.plus({
5226
- [unit]: delta - 1
5227
- });
5228
- delta -= 1;
5321
+ results[unit]--;
5322
+ cursor = earlier.plus(results);
5229
5323
  } else {
5230
5324
  cursor = highWater;
5231
5325
  }
5232
- results[unit] = delta;
5233
5326
  }
5234
5327
  }
5235
5328
  return [cursor, results, highWater, lowestOrder];
@@ -5554,7 +5647,7 @@
5554
5647
  short: "ZZZ"
5555
5648
  }
5556
5649
  };
5557
- function tokenForPart(part, locale, formatOpts) {
5650
+ function tokenForPart(part, formatOpts) {
5558
5651
  const {
5559
5652
  type,
5560
5653
  value
@@ -5743,7 +5836,7 @@
5743
5836
  }
5744
5837
  const formatter = Formatter.create(locale, formatOpts);
5745
5838
  const parts = formatter.formatDateTimeParts(getDummyDateTime());
5746
- return parts.map(p => tokenForPart(p, locale, formatOpts));
5839
+ return parts.map(p => tokenForPart(p, formatOpts));
5747
5840
  }
5748
5841
 
5749
5842
  const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
@@ -7765,7 +7858,7 @@
7765
7858
 
7766
7859
  /**
7767
7860
  * Equality check
7768
- * Two DateTimes are equal iff they represent the same millisecond, have the same zone and location, and are both valid.
7861
+ * Two DateTimes are equal if and only if they represent the same millisecond, have the same zone and location, and are both valid.
7769
7862
  * To compare just the millisecond values, use `+dt1 === +dt2`.
7770
7863
  * @param {DateTime} other - the other DateTime
7771
7864
  * @return {boolean}
@@ -20124,11 +20217,17 @@
20124
20217
  children: [pre !== null && e$1("span", {
20125
20218
  class: "fjs-input-adornment border-right border-radius-left",
20126
20219
  onClick: onAdornmentClick,
20127
- children: [" ", pre, " "]
20220
+ children: [" ", isString$3(pre) ? e$1("span", {
20221
+ class: "fjs-input-adornment-text",
20222
+ children: pre
20223
+ }) : pre, " "]
20128
20224
  }), children, post !== null && e$1("span", {
20129
20225
  class: "fjs-input-adornment border-left border-radius-right",
20130
20226
  onClick: onAdornmentClick,
20131
- children: [" ", post, " "]
20227
+ children: [" ", isString$3(post) ? e$1("span", {
20228
+ class: "fjs-input-adornment-text",
20229
+ children: post
20230
+ }) : post, " "]
20132
20231
  })]
20133
20232
  });
20134
20233
  }
@@ -22453,21 +22552,23 @@
22453
22552
  d: "M15 13a2 2 0 00-2 2v24a2 2 0 002 2h24a2 2 0 002-2V15a2 2 0 00-2-2H15zm24 2H15v12.45l4.71-4.709a1.91 1.91 0 012.702 0l6.695 6.695 2.656-1.77a1.91 1.91 0 012.411.239L39 32.73V15zM15 39v-8.754c.06-.038.116-.083.168-.135l5.893-5.893 6.684 6.685a1.911 1.911 0 002.41.238l2.657-1.77 6.02 6.02c.052.051.108.097.168.135V39H15z",
22454
22553
  fill: "#000"
22455
22554
  }));
22456
- const iconsByType = {
22457
- button: ButtonIcon,
22458
- checkbox: CheckboxIcon,
22459
- checklist: ChecklistIcon,
22460
- columns: ColumnsIcon,
22461
- datetime: DatetimeIcon,
22462
- image: ImageIcon,
22463
- number: NumberIcon,
22464
- radio: RadioIcon,
22465
- select: SelectIcon,
22466
- taglist: TaglistIcon,
22467
- text: TextIcon,
22468
- textfield: TextfieldIcon,
22469
- textarea: TextareaIcon,
22470
- default: FormIcon
22555
+ const iconsByType = type => {
22556
+ return {
22557
+ button: ButtonIcon,
22558
+ checkbox: CheckboxIcon,
22559
+ checklist: ChecklistIcon,
22560
+ columns: ColumnsIcon,
22561
+ datetime: DatetimeIcon,
22562
+ image: ImageIcon,
22563
+ number: NumberIcon,
22564
+ radio: RadioIcon,
22565
+ select: SelectIcon,
22566
+ taglist: TaglistIcon,
22567
+ text: TextIcon,
22568
+ textfield: TextfieldIcon,
22569
+ textarea: TextareaIcon,
22570
+ default: FormIcon
22571
+ }[type];
22471
22572
  };
22472
22573
  const formFields = [Button, Checkbox$1, Checklist, Default, Image, Numberfield, Datetime, Radio, Select$1, Taglist, Text$2, Textfield$1, Textarea];
22473
22574
  class FormFields {
@@ -47301,7 +47402,7 @@
47301
47402
  type,
47302
47403
  text = ''
47303
47404
  } = props.field;
47304
- const Icon = iconsByType['text'];
47405
+ const Icon = iconsByType('text');
47305
47406
  if (!text) {
47306
47407
  return e$1("div", {
47307
47408
  class: editorFormFieldClasses(type),
@@ -47474,11 +47575,11 @@
47474
47575
  label,
47475
47576
  type
47476
47577
  }) => {
47477
- const Icon = iconsByType[type];
47578
+ const Icon = iconsByType(type);
47478
47579
  return e$1("div", {
47479
47580
  class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
47480
47581
  "data-field-type": type,
47481
- title: `Create a ${label} element`,
47582
+ title: `Create ${getIndefiniteArticle(type)} ${label} element`,
47482
47583
  children: [Icon ? e$1(Icon, {
47483
47584
  class: "fjs-palette-field-icon",
47484
47585
  width: "36",
@@ -47517,6 +47618,12 @@
47517
47618
  });
47518
47619
  return groups.filter(g => g.entries.length);
47519
47620
  }
47621
+ function getIndefiniteArticle(type) {
47622
+ if (['image'].includes(type)) {
47623
+ return 'an';
47624
+ }
47625
+ return 'a';
47626
+ }
47520
47627
  const CURSOR_CLS_PATTERN = /^fjs-cursor-.*$/;
47521
47628
  function set(mode) {
47522
47629
  const classes$1 = classes(document.body);
@@ -47853,7 +47960,7 @@
47853
47960
  } = F$1(DragAndDropContext$1);
47854
47961
  function handleCloned(clone, original, type) {
47855
47962
  const fieldType = clone.dataset.fieldType;
47856
- const Icon = iconsByType[fieldType];
47963
+ const Icon = iconsByType(fieldType);
47857
47964
  const {
47858
47965
  label
47859
47966
  } = findPaletteEntry(fieldType);
@@ -52040,7 +52147,7 @@
52040
52147
  const {
52041
52148
  type
52042
52149
  } = field;
52043
- const Icon = iconsByType[type];
52150
+ const Icon = iconsByType(type);
52044
52151
  if (Icon) {
52045
52152
  return () => e$1(Icon, {
52046
52153
  width: "36",
@@ -52281,6 +52388,7 @@
52281
52388
  setValue
52282
52389
  });
52283
52390
  }
52391
+ const EMPTY_OPTION = null;
52284
52392
  function DefaultOptionEntry(props) {
52285
52393
  const {
52286
52394
  editField,
@@ -52426,13 +52534,14 @@
52426
52534
  label
52427
52535
  } = props;
52428
52536
  const {
52429
- defaultValue,
52537
+ defaultValue = EMPTY_OPTION,
52430
52538
  values = []
52431
52539
  } = field;
52432
52540
  const path = ['defaultValue'];
52433
52541
  const getOptions = () => {
52434
52542
  return [{
52435
- label: '<none>'
52543
+ label: '<none>',
52544
+ value: EMPTY_OPTION
52436
52545
  }, ...values];
52437
52546
  };
52438
52547
  const setValue = value => {
@@ -53867,7 +53976,7 @@
53867
53976
  }
53868
53977
  const VALIDATION_TYPE_OPTIONS = {
53869
53978
  custom: {
53870
- value: undefined,
53979
+ value: '',
53871
53980
  label: 'Custom'
53872
53981
  },
53873
53982
  email: {
@@ -53884,7 +53993,7 @@
53884
53993
  type
53885
53994
  } = field;
53886
53995
  const validate = get(field, ['validate'], {});
53887
- const isCustomValidation = [undefined, VALIDATION_TYPE_OPTIONS.custom.value].includes(validate && validate.validationType);
53996
+ const isCustomValidation = [undefined, VALIDATION_TYPE_OPTIONS.custom.value].includes(validate.validationType);
53888
53997
  if (!(INPUTS.includes(type) && type !== 'checkbox' && type !== 'checklist' && type !== 'taglist')) {
53889
53998
  return null;
53890
53999
  }