/
index.cjs
119 lines (113 loc) · 4.79 KB
/
index.cjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
flexLoader(typeof window !== `undefined` && window?.document ? window : global, DateFormatFactory);
function flexLoader( global, factory ) {
if ( typeof module === "object" && typeof module.exports === "object" ) {
return module.exports = factory( global, true );
}
return factory( global );
}
function DateFormatFactory() {
const [digits, numeric, long, short] = [`2-digit`, `numeric`, `long`, `short`];
const theOptions = {
fixed: {
MM: {month: long},
M: {month: short},
m: {month: numeric},
mm: {month: digits},
yyyy: {year: numeric},
yy: {year: digits},
WD: {weekday: long},
wd: {weekday: short},
d: {day: numeric},
dd: {day: digits},
h: {hour: numeric},
hh: {hour: digits},
mi: {minute: numeric},
mmi: {minute: digits},
s: {second: numeric},
ss: {second: digits},
ms: {fractionalSecondDigits: 3},
tz: {timeZoneName: `shortOffset`},
dl: {locale: `default`},
h12: {hour12: false},
yn: {yearName: ``},
ry: {relatedYear: true},
msp: {fractionalSecond: true},
},
dynamic: {
tzn: v => ({timeZoneName: v.slice(4)}),
hrc: v => ({hourCycle: `h${v.slice(4)}`}),
ds: v => ({dateStyle: v.slice(3)}),
ts: v => ({timeStyle: v.slice(3)}),
tz: v => ({timeZone: v.slice(3)}),
e: v => ({era: v.slice(2)}),
l: v => ({locale: v.slice(2)}),
},
}
const dtfOptions = {
...theOptions,
retrieveDyn(fromValue) {
const key = fromValue?.slice(0, fromValue.indexOf(`:`));
return theOptions.dynamic[key] && theOptions.dynamic[key](fromValue);
},
get re() { return new RegExp(`\\b(${Object.keys(theOptions.fixed).join(`|`)})\\b`, `g`); },
};
const extractFromTemplate = (rawTemplateString = `dtf`, plainTextIndex = 0) => {
let formatStr = ` ${ rawTemplateString
.replace(/(?<=\{)(.+?)(?=})/g, _ => `[${plainTextIndex++}]`)
.replace(/[{}]/g, ``)
.trim() } `;
const texts = rawTemplateString.match(/(?<=\{)(.+?)(?=})/g) || [];
return {
get texts() { return texts; },
formatString(v) { formatStr = v; },
set formatStr(v) { formatStr = v; },
get formatStr() { return formatStr; },
get units() { return formatStr.match(dtfOptions.re) || []; },
finalize(dtf = ``, h12 = ``, era = ``, yn = ``) {
return formatStr
.replace(/~([\d+]?)/g, `$1`)
.replace(/dtf/, dtf)
.replace(/era/, era)
.replace(/dp\b|~dp\b/, h12)
.replace(/yn\b/, yn)
.replace(/\[(\d+?)]/g, (_, d) => texts[d].trim())
.trim();
}
};
};
const unSpacify = str => str.replace(/\s+/g, ``);
const getOpts = (...opts) => opts?.reduce( (acc, optValue) =>
({...acc, ...(dtfOptions.retrieveDyn(optValue) || dtfOptions.fixed[optValue]),}),
dtfOptions.fixed.dl );
const dtNoParts = (date, xTemplate, moreOptions) => {
const opts = getOpts(...unSpacify(moreOptions).split(`,`));
const formatted = Intl.DateTimeFormat(opts.locale, opts).format(date);
return xTemplate.finalize(formatted);
};
const getMonthName = (forDate, locale, timeZone, shrt) =>
forDate.toLocaleString(locale, {timeZone: timeZone, month: shrt ? short : long});
const dtFormatted = (date, xTemplate, moreOptions) => {
const optsCollected = getOpts( ...xTemplate.units.concat(unSpacify(moreOptions).split(`,`)).flat() );
const opts = {...dtfOptions.fixed};
// note: numeric is locale independent
const checkNumeric = (type, value) => optsCollected[type] === `numeric` && value.startsWith(`0`)
? value.slice(1) : value;
console.log(Intl.DateTimeFormat(optsCollected.locale, optsCollected)
.formatToParts(date));
const dtf = Intl.DateTimeFormat(optsCollected.locale, optsCollected)
.formatToParts(date)
.reduce( (parts, v) =>
((v.type === `literal` && /[ ,/-]/.test(v.value)) ? parts : {...parts, [v.type]: checkNumeric(v.type, v.value) } ), {} );
opts.ms = optsCollected.fractionalSecondDigits ? opts.msp : opts.ms;
opts.yyyy = dtf.relatedYear ? opts.ry : opts.yyyy;
xTemplate.formatStr = xTemplate.formatStr
.replace(dtfOptions.re, dtUnit =>
/^(M|MM)$/.test(dtUnit)
? getMonthName(date, optsCollected.locale, optsCollected.timeZone, /^M$/.test(dtUnit))
: dtf[Object.keys(opts[dtUnit]).shift()] || dtUnit);
return xTemplate.finalize(...[undefined, dtf.dayPeriod, dtf.era, dtf.yearName]);
}
return (date, template, moreOptions = `l:default`) => (/ds:|ts:/.test(moreOptions))
? dtNoParts(...[date, extractFromTemplate(undefined), moreOptions])
: dtFormatted(...[date, extractFromTemplate(template || undefined), moreOptions]);
}