@nocobase/plugin-auth 0.17.0-alpha.7 → 0.18.0-alpha.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.
- package/dist/client/authenticator.d.ts +13 -0
- package/dist/client/basic/SignInForm.d.ts +9 -0
- package/dist/client/basic/SignUpForm.d.ts +13 -0
- package/dist/client/basic/index.d.ts +3 -0
- package/dist/client/index.d.ts +21 -0
- package/dist/client/index.js +12 -2
- package/dist/client/pages/AuthLayout.d.ts +2 -0
- package/dist/client/pages/SignInPage.d.ts +16 -0
- package/dist/client/pages/SignUpPage.d.ts +21 -0
- package/dist/client/pages/index.d.ts +3 -0
- package/dist/client/settings/Options.d.ts +3 -2
- package/dist/externalVersion.js +14 -12
- package/dist/locale/en-US.json +4 -1
- package/dist/locale/zh-CN.json +4 -1
- package/dist/node_modules/cron/LICENSE +0 -0
- package/dist/node_modules/cron/lib/cron.js +1 -1
- package/dist/node_modules/cron/lib/job.js +0 -0
- package/dist/node_modules/cron/lib/time.js +33 -20
- package/dist/node_modules/cron/node_modules/luxon/build/amd/luxon.js +7826 -0
- package/dist/node_modules/cron/node_modules/luxon/build/cjs-browser/luxon.js +7824 -0
- package/dist/node_modules/cron/node_modules/luxon/build/es6/luxon.js +7217 -0
- package/dist/node_modules/cron/node_modules/luxon/build/global/luxon.js +7829 -0
- package/dist/node_modules/cron/node_modules/luxon/build/global/luxon.min.js +1 -0
- package/dist/node_modules/cron/node_modules/luxon/build/node/luxon.js +6932 -0
- package/dist/node_modules/cron/node_modules/luxon/package.json +85 -0
- package/dist/node_modules/cron/node_modules/luxon/src/datetime.js +2248 -0
- package/dist/node_modules/cron/node_modules/luxon/src/duration.js +948 -0
- package/dist/node_modules/cron/node_modules/luxon/src/errors.js +61 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/conversions.js +161 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/diff.js +75 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/digits.js +75 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/english.js +233 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/formats.js +176 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/formatter.js +400 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/invalid.js +14 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/locale.js +494 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/regexParser.js +335 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/tokenParser.js +444 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/util.js +274 -0
- package/dist/node_modules/cron/node_modules/luxon/src/impl/zoneUtil.js +34 -0
- package/dist/node_modules/cron/node_modules/luxon/src/info.js +169 -0
- package/dist/node_modules/cron/node_modules/luxon/src/interval.js +637 -0
- package/dist/node_modules/cron/node_modules/luxon/src/luxon.js +26 -0
- package/dist/node_modules/cron/node_modules/luxon/src/package.json +4 -0
- package/dist/node_modules/cron/node_modules/luxon/src/settings.js +148 -0
- package/dist/node_modules/cron/node_modules/luxon/src/zone.js +91 -0
- package/dist/node_modules/cron/node_modules/luxon/src/zones/IANAZone.js +189 -0
- package/dist/node_modules/cron/node_modules/luxon/src/zones/fixedOffsetZone.js +102 -0
- package/dist/node_modules/cron/node_modules/luxon/src/zones/invalidZone.js +53 -0
- package/dist/node_modules/cron/node_modules/luxon/src/zones/systemZone.js +61 -0
- package/dist/node_modules/cron/package.json +1 -1
- package/dist/node_modules/cron/types/index.d.ts +181 -0
- package/dist/node_modules/cron/types/index.test-d.ts +85 -0
- package/dist/server/actions/authenticators.js +3 -0
- package/dist/server/basic-auth.js +5 -2
- package/dist/server/migrations/20231218132032-fix-allow-signup.d.ts +5 -0
- package/dist/server/migrations/20231218132032-fix-allow-signup.js +54 -0
- package/dist/server/model/authenticator.d.ts +5 -2
- package/dist/server/model/authenticator.js +2 -2
- package/package.json +2 -2
- package/dist/client/AuthPluginProvider.d.ts +0 -2
- package/dist/client/basic/SigninPage.d.ts +0 -6
- package/dist/client/basic/SignupPage.d.ts +0 -5
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { parseMillis, isUndefined, untruncateYear, signedOffset, hasOwnProperty } from "./util.js";
|
|
2
|
+
import Formatter from "./formatter.js";
|
|
3
|
+
import FixedOffsetZone from "../zones/fixedOffsetZone.js";
|
|
4
|
+
import IANAZone from "../zones/IANAZone.js";
|
|
5
|
+
import DateTime from "../datetime.js";
|
|
6
|
+
import { digitRegex, parseDigits } from "./digits.js";
|
|
7
|
+
import { ConflictingSpecificationError } from "../errors.js";
|
|
8
|
+
|
|
9
|
+
const MISSING_FTP = "missing Intl.DateTimeFormat.formatToParts support";
|
|
10
|
+
|
|
11
|
+
function intUnit(regex, post = (i) => i) {
|
|
12
|
+
return { regex, deser: ([s]) => post(parseDigits(s)) };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const NBSP = String.fromCharCode(160);
|
|
16
|
+
const spaceOrNBSP = `[ ${NBSP}]`;
|
|
17
|
+
const spaceOrNBSPRegExp = new RegExp(spaceOrNBSP, "g");
|
|
18
|
+
|
|
19
|
+
function fixListRegex(s) {
|
|
20
|
+
// make dots optional and also make them literal
|
|
21
|
+
// make space and non breakable space characters interchangeable
|
|
22
|
+
return s.replace(/\./g, "\\.?").replace(spaceOrNBSPRegExp, spaceOrNBSP);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function stripInsensitivities(s) {
|
|
26
|
+
return s
|
|
27
|
+
.replace(/\./g, "") // ignore dots that were made optional
|
|
28
|
+
.replace(spaceOrNBSPRegExp, " ") // interchange space and nbsp
|
|
29
|
+
.toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function oneOf(strings, startIndex) {
|
|
33
|
+
if (strings === null) {
|
|
34
|
+
return null;
|
|
35
|
+
} else {
|
|
36
|
+
return {
|
|
37
|
+
regex: RegExp(strings.map(fixListRegex).join("|")),
|
|
38
|
+
deser: ([s]) =>
|
|
39
|
+
strings.findIndex((i) => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function offset(regex, groups) {
|
|
45
|
+
return { regex, deser: ([, h, m]) => signedOffset(h, m), groups };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function simple(regex) {
|
|
49
|
+
return { regex, deser: ([s]) => s };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function escapeToken(value) {
|
|
53
|
+
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function unitForToken(token, loc) {
|
|
57
|
+
const one = digitRegex(loc),
|
|
58
|
+
two = digitRegex(loc, "{2}"),
|
|
59
|
+
three = digitRegex(loc, "{3}"),
|
|
60
|
+
four = digitRegex(loc, "{4}"),
|
|
61
|
+
six = digitRegex(loc, "{6}"),
|
|
62
|
+
oneOrTwo = digitRegex(loc, "{1,2}"),
|
|
63
|
+
oneToThree = digitRegex(loc, "{1,3}"),
|
|
64
|
+
oneToSix = digitRegex(loc, "{1,6}"),
|
|
65
|
+
oneToNine = digitRegex(loc, "{1,9}"),
|
|
66
|
+
twoToFour = digitRegex(loc, "{2,4}"),
|
|
67
|
+
fourToSix = digitRegex(loc, "{4,6}"),
|
|
68
|
+
literal = (t) => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }),
|
|
69
|
+
unitate = (t) => {
|
|
70
|
+
if (token.literal) {
|
|
71
|
+
return literal(t);
|
|
72
|
+
}
|
|
73
|
+
switch (t.val) {
|
|
74
|
+
// era
|
|
75
|
+
case "G":
|
|
76
|
+
return oneOf(loc.eras("short", false), 0);
|
|
77
|
+
case "GG":
|
|
78
|
+
return oneOf(loc.eras("long", false), 0);
|
|
79
|
+
// years
|
|
80
|
+
case "y":
|
|
81
|
+
return intUnit(oneToSix);
|
|
82
|
+
case "yy":
|
|
83
|
+
return intUnit(twoToFour, untruncateYear);
|
|
84
|
+
case "yyyy":
|
|
85
|
+
return intUnit(four);
|
|
86
|
+
case "yyyyy":
|
|
87
|
+
return intUnit(fourToSix);
|
|
88
|
+
case "yyyyyy":
|
|
89
|
+
return intUnit(six);
|
|
90
|
+
// months
|
|
91
|
+
case "M":
|
|
92
|
+
return intUnit(oneOrTwo);
|
|
93
|
+
case "MM":
|
|
94
|
+
return intUnit(two);
|
|
95
|
+
case "MMM":
|
|
96
|
+
return oneOf(loc.months("short", true, false), 1);
|
|
97
|
+
case "MMMM":
|
|
98
|
+
return oneOf(loc.months("long", true, false), 1);
|
|
99
|
+
case "L":
|
|
100
|
+
return intUnit(oneOrTwo);
|
|
101
|
+
case "LL":
|
|
102
|
+
return intUnit(two);
|
|
103
|
+
case "LLL":
|
|
104
|
+
return oneOf(loc.months("short", false, false), 1);
|
|
105
|
+
case "LLLL":
|
|
106
|
+
return oneOf(loc.months("long", false, false), 1);
|
|
107
|
+
// dates
|
|
108
|
+
case "d":
|
|
109
|
+
return intUnit(oneOrTwo);
|
|
110
|
+
case "dd":
|
|
111
|
+
return intUnit(two);
|
|
112
|
+
// ordinals
|
|
113
|
+
case "o":
|
|
114
|
+
return intUnit(oneToThree);
|
|
115
|
+
case "ooo":
|
|
116
|
+
return intUnit(three);
|
|
117
|
+
// time
|
|
118
|
+
case "HH":
|
|
119
|
+
return intUnit(two);
|
|
120
|
+
case "H":
|
|
121
|
+
return intUnit(oneOrTwo);
|
|
122
|
+
case "hh":
|
|
123
|
+
return intUnit(two);
|
|
124
|
+
case "h":
|
|
125
|
+
return intUnit(oneOrTwo);
|
|
126
|
+
case "mm":
|
|
127
|
+
return intUnit(two);
|
|
128
|
+
case "m":
|
|
129
|
+
return intUnit(oneOrTwo);
|
|
130
|
+
case "q":
|
|
131
|
+
return intUnit(oneOrTwo);
|
|
132
|
+
case "qq":
|
|
133
|
+
return intUnit(two);
|
|
134
|
+
case "s":
|
|
135
|
+
return intUnit(oneOrTwo);
|
|
136
|
+
case "ss":
|
|
137
|
+
return intUnit(two);
|
|
138
|
+
case "S":
|
|
139
|
+
return intUnit(oneToThree);
|
|
140
|
+
case "SSS":
|
|
141
|
+
return intUnit(three);
|
|
142
|
+
case "u":
|
|
143
|
+
return simple(oneToNine);
|
|
144
|
+
case "uu":
|
|
145
|
+
return simple(oneOrTwo);
|
|
146
|
+
case "uuu":
|
|
147
|
+
return intUnit(one);
|
|
148
|
+
// meridiem
|
|
149
|
+
case "a":
|
|
150
|
+
return oneOf(loc.meridiems(), 0);
|
|
151
|
+
// weekYear (k)
|
|
152
|
+
case "kkkk":
|
|
153
|
+
return intUnit(four);
|
|
154
|
+
case "kk":
|
|
155
|
+
return intUnit(twoToFour, untruncateYear);
|
|
156
|
+
// weekNumber (W)
|
|
157
|
+
case "W":
|
|
158
|
+
return intUnit(oneOrTwo);
|
|
159
|
+
case "WW":
|
|
160
|
+
return intUnit(two);
|
|
161
|
+
// weekdays
|
|
162
|
+
case "E":
|
|
163
|
+
case "c":
|
|
164
|
+
return intUnit(one);
|
|
165
|
+
case "EEE":
|
|
166
|
+
return oneOf(loc.weekdays("short", false, false), 1);
|
|
167
|
+
case "EEEE":
|
|
168
|
+
return oneOf(loc.weekdays("long", false, false), 1);
|
|
169
|
+
case "ccc":
|
|
170
|
+
return oneOf(loc.weekdays("short", true, false), 1);
|
|
171
|
+
case "cccc":
|
|
172
|
+
return oneOf(loc.weekdays("long", true, false), 1);
|
|
173
|
+
// offset/zone
|
|
174
|
+
case "Z":
|
|
175
|
+
case "ZZ":
|
|
176
|
+
return offset(new RegExp(`([+-]${oneOrTwo.source})(?::(${two.source}))?`), 2);
|
|
177
|
+
case "ZZZ":
|
|
178
|
+
return offset(new RegExp(`([+-]${oneOrTwo.source})(${two.source})?`), 2);
|
|
179
|
+
// we don't support ZZZZ (PST) or ZZZZZ (Pacific Standard Time) in parsing
|
|
180
|
+
// because we don't have any way to figure out what they are
|
|
181
|
+
case "z":
|
|
182
|
+
return simple(/[a-z_+-/]{1,256}?/i);
|
|
183
|
+
// this special-case "token" represents a place where a macro-token expanded into a white-space literal
|
|
184
|
+
// in this case we accept any non-newline white-space
|
|
185
|
+
case " ":
|
|
186
|
+
return simple(/[^\S\n\r]/);
|
|
187
|
+
default:
|
|
188
|
+
return literal(t);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const unit = unitate(token) || {
|
|
193
|
+
invalidReason: MISSING_FTP,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
unit.token = token;
|
|
197
|
+
|
|
198
|
+
return unit;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const partTypeStyleToTokenVal = {
|
|
202
|
+
year: {
|
|
203
|
+
"2-digit": "yy",
|
|
204
|
+
numeric: "yyyyy",
|
|
205
|
+
},
|
|
206
|
+
month: {
|
|
207
|
+
numeric: "M",
|
|
208
|
+
"2-digit": "MM",
|
|
209
|
+
short: "MMM",
|
|
210
|
+
long: "MMMM",
|
|
211
|
+
},
|
|
212
|
+
day: {
|
|
213
|
+
numeric: "d",
|
|
214
|
+
"2-digit": "dd",
|
|
215
|
+
},
|
|
216
|
+
weekday: {
|
|
217
|
+
short: "EEE",
|
|
218
|
+
long: "EEEE",
|
|
219
|
+
},
|
|
220
|
+
dayperiod: "a",
|
|
221
|
+
dayPeriod: "a",
|
|
222
|
+
hour: {
|
|
223
|
+
numeric: "h",
|
|
224
|
+
"2-digit": "hh",
|
|
225
|
+
},
|
|
226
|
+
minute: {
|
|
227
|
+
numeric: "m",
|
|
228
|
+
"2-digit": "mm",
|
|
229
|
+
},
|
|
230
|
+
second: {
|
|
231
|
+
numeric: "s",
|
|
232
|
+
"2-digit": "ss",
|
|
233
|
+
},
|
|
234
|
+
timeZoneName: {
|
|
235
|
+
long: "ZZZZZ",
|
|
236
|
+
short: "ZZZ",
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
function tokenForPart(part, formatOpts) {
|
|
241
|
+
const { type, value } = part;
|
|
242
|
+
|
|
243
|
+
if (type === "literal") {
|
|
244
|
+
const isSpace = /^\s+$/.test(value);
|
|
245
|
+
return {
|
|
246
|
+
literal: !isSpace,
|
|
247
|
+
val: isSpace ? " " : value,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const style = formatOpts[type];
|
|
252
|
+
|
|
253
|
+
let val = partTypeStyleToTokenVal[type];
|
|
254
|
+
if (typeof val === "object") {
|
|
255
|
+
val = val[style];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (val) {
|
|
259
|
+
return {
|
|
260
|
+
literal: false,
|
|
261
|
+
val,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function buildRegex(units) {
|
|
269
|
+
const re = units.map((u) => u.regex).reduce((f, r) => `${f}(${r.source})`, "");
|
|
270
|
+
return [`^${re}$`, units];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function match(input, regex, handlers) {
|
|
274
|
+
const matches = input.match(regex);
|
|
275
|
+
|
|
276
|
+
if (matches) {
|
|
277
|
+
const all = {};
|
|
278
|
+
let matchIndex = 1;
|
|
279
|
+
for (const i in handlers) {
|
|
280
|
+
if (hasOwnProperty(handlers, i)) {
|
|
281
|
+
const h = handlers[i],
|
|
282
|
+
groups = h.groups ? h.groups + 1 : 1;
|
|
283
|
+
if (!h.literal && h.token) {
|
|
284
|
+
all[h.token.val[0]] = h.deser(matches.slice(matchIndex, matchIndex + groups));
|
|
285
|
+
}
|
|
286
|
+
matchIndex += groups;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return [matches, all];
|
|
290
|
+
} else {
|
|
291
|
+
return [matches, {}];
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function dateTimeFromMatches(matches) {
|
|
296
|
+
const toField = (token) => {
|
|
297
|
+
switch (token) {
|
|
298
|
+
case "S":
|
|
299
|
+
return "millisecond";
|
|
300
|
+
case "s":
|
|
301
|
+
return "second";
|
|
302
|
+
case "m":
|
|
303
|
+
return "minute";
|
|
304
|
+
case "h":
|
|
305
|
+
case "H":
|
|
306
|
+
return "hour";
|
|
307
|
+
case "d":
|
|
308
|
+
return "day";
|
|
309
|
+
case "o":
|
|
310
|
+
return "ordinal";
|
|
311
|
+
case "L":
|
|
312
|
+
case "M":
|
|
313
|
+
return "month";
|
|
314
|
+
case "y":
|
|
315
|
+
return "year";
|
|
316
|
+
case "E":
|
|
317
|
+
case "c":
|
|
318
|
+
return "weekday";
|
|
319
|
+
case "W":
|
|
320
|
+
return "weekNumber";
|
|
321
|
+
case "k":
|
|
322
|
+
return "weekYear";
|
|
323
|
+
case "q":
|
|
324
|
+
return "quarter";
|
|
325
|
+
default:
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
let zone = null;
|
|
331
|
+
let specificOffset;
|
|
332
|
+
if (!isUndefined(matches.z)) {
|
|
333
|
+
zone = IANAZone.create(matches.z);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (!isUndefined(matches.Z)) {
|
|
337
|
+
if (!zone) {
|
|
338
|
+
zone = new FixedOffsetZone(matches.Z);
|
|
339
|
+
}
|
|
340
|
+
specificOffset = matches.Z;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!isUndefined(matches.q)) {
|
|
344
|
+
matches.M = (matches.q - 1) * 3 + 1;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (!isUndefined(matches.h)) {
|
|
348
|
+
if (matches.h < 12 && matches.a === 1) {
|
|
349
|
+
matches.h += 12;
|
|
350
|
+
} else if (matches.h === 12 && matches.a === 0) {
|
|
351
|
+
matches.h = 0;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (matches.G === 0 && matches.y) {
|
|
356
|
+
matches.y = -matches.y;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (!isUndefined(matches.u)) {
|
|
360
|
+
matches.S = parseMillis(matches.u);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const vals = Object.keys(matches).reduce((r, k) => {
|
|
364
|
+
const f = toField(k);
|
|
365
|
+
if (f) {
|
|
366
|
+
r[f] = matches[k];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return r;
|
|
370
|
+
}, {});
|
|
371
|
+
|
|
372
|
+
return [vals, zone, specificOffset];
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let dummyDateTimeCache = null;
|
|
376
|
+
|
|
377
|
+
function getDummyDateTime() {
|
|
378
|
+
if (!dummyDateTimeCache) {
|
|
379
|
+
dummyDateTimeCache = DateTime.fromMillis(1555555555555);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return dummyDateTimeCache;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function maybeExpandMacroToken(token, locale) {
|
|
386
|
+
if (token.literal) {
|
|
387
|
+
return token;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const formatOpts = Formatter.macroTokenToFormatOpts(token.val);
|
|
391
|
+
const tokens = formatOptsToTokens(formatOpts, locale);
|
|
392
|
+
|
|
393
|
+
if (tokens == null || tokens.includes(undefined)) {
|
|
394
|
+
return token;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return tokens;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function expandMacroTokens(tokens, locale) {
|
|
401
|
+
return Array.prototype.concat(...tokens.map((t) => maybeExpandMacroToken(t, locale)));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* @private
|
|
406
|
+
*/
|
|
407
|
+
|
|
408
|
+
export function explainFromTokens(locale, input, format) {
|
|
409
|
+
const tokens = expandMacroTokens(Formatter.parseFormat(format), locale),
|
|
410
|
+
units = tokens.map((t) => unitForToken(t, locale)),
|
|
411
|
+
disqualifyingUnit = units.find((t) => t.invalidReason);
|
|
412
|
+
|
|
413
|
+
if (disqualifyingUnit) {
|
|
414
|
+
return { input, tokens, invalidReason: disqualifyingUnit.invalidReason };
|
|
415
|
+
} else {
|
|
416
|
+
const [regexString, handlers] = buildRegex(units),
|
|
417
|
+
regex = RegExp(regexString, "i"),
|
|
418
|
+
[rawMatches, matches] = match(input, regex, handlers),
|
|
419
|
+
[result, zone, specificOffset] = matches
|
|
420
|
+
? dateTimeFromMatches(matches)
|
|
421
|
+
: [null, null, undefined];
|
|
422
|
+
if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) {
|
|
423
|
+
throw new ConflictingSpecificationError(
|
|
424
|
+
"Can't include meridiem when specifying 24-hour format"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
return { input, tokens, regex, rawMatches, matches, result, zone, specificOffset };
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function parseFromTokens(locale, input, format) {
|
|
432
|
+
const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format);
|
|
433
|
+
return [result, zone, specificOffset, invalidReason];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export function formatOptsToTokens(formatOpts, locale) {
|
|
437
|
+
if (!formatOpts) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const formatter = Formatter.create(locale, formatOpts);
|
|
442
|
+
const parts = formatter.formatDateTimeParts(getDummyDateTime());
|
|
443
|
+
return parts.map((p) => tokenForPart(p, formatOpts));
|
|
444
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This is just a junk drawer, containing anything used across multiple classes.
|
|
3
|
+
Because Luxon is small(ish), this should stay small and we won't worry about splitting
|
|
4
|
+
it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { InvalidArgumentError } from "../errors.js";
|
|
8
|
+
import Settings from "../settings.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// TYPES
|
|
15
|
+
|
|
16
|
+
export function isUndefined(o) {
|
|
17
|
+
return typeof o === "undefined";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isNumber(o) {
|
|
21
|
+
return typeof o === "number";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isInteger(o) {
|
|
25
|
+
return typeof o === "number" && o % 1 === 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isString(o) {
|
|
29
|
+
return typeof o === "string";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isDate(o) {
|
|
33
|
+
return Object.prototype.toString.call(o) === "[object Date]";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// CAPABILITIES
|
|
37
|
+
|
|
38
|
+
export function hasRelative() {
|
|
39
|
+
try {
|
|
40
|
+
return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// OBJECTS AND ARRAYS
|
|
47
|
+
|
|
48
|
+
export function maybeArray(thing) {
|
|
49
|
+
return Array.isArray(thing) ? thing : [thing];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function bestBy(arr, by, compare) {
|
|
53
|
+
if (arr.length === 0) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return arr.reduce((best, next) => {
|
|
57
|
+
const pair = [by(next), next];
|
|
58
|
+
if (!best) {
|
|
59
|
+
return pair;
|
|
60
|
+
} else if (compare(best[0], pair[0]) === best[0]) {
|
|
61
|
+
return best;
|
|
62
|
+
} else {
|
|
63
|
+
return pair;
|
|
64
|
+
}
|
|
65
|
+
}, null)[1];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function pick(obj, keys) {
|
|
69
|
+
return keys.reduce((a, k) => {
|
|
70
|
+
a[k] = obj[k];
|
|
71
|
+
return a;
|
|
72
|
+
}, {});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function hasOwnProperty(obj, prop) {
|
|
76
|
+
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// NUMBERS AND STRINGS
|
|
80
|
+
|
|
81
|
+
export function integerBetween(thing, bottom, top) {
|
|
82
|
+
return isInteger(thing) && thing >= bottom && thing <= top;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// x % n but takes the sign of n instead of x
|
|
86
|
+
export function floorMod(x, n) {
|
|
87
|
+
return x - n * Math.floor(x / n);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function padStart(input, n = 2) {
|
|
91
|
+
const isNeg = input < 0;
|
|
92
|
+
let padded;
|
|
93
|
+
if (isNeg) {
|
|
94
|
+
padded = "-" + ("" + -input).padStart(n, "0");
|
|
95
|
+
} else {
|
|
96
|
+
padded = ("" + input).padStart(n, "0");
|
|
97
|
+
}
|
|
98
|
+
return padded;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function parseInteger(string) {
|
|
102
|
+
if (isUndefined(string) || string === null || string === "") {
|
|
103
|
+
return undefined;
|
|
104
|
+
} else {
|
|
105
|
+
return parseInt(string, 10);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function parseFloating(string) {
|
|
110
|
+
if (isUndefined(string) || string === null || string === "") {
|
|
111
|
+
return undefined;
|
|
112
|
+
} else {
|
|
113
|
+
return parseFloat(string);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function parseMillis(fraction) {
|
|
118
|
+
// Return undefined (instead of 0) in these cases, where fraction is not set
|
|
119
|
+
if (isUndefined(fraction) || fraction === null || fraction === "") {
|
|
120
|
+
return undefined;
|
|
121
|
+
} else {
|
|
122
|
+
const f = parseFloat("0." + fraction) * 1000;
|
|
123
|
+
return Math.floor(f);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function roundTo(number, digits, towardZero = false) {
|
|
128
|
+
const factor = 10 ** digits,
|
|
129
|
+
rounder = towardZero ? Math.trunc : Math.round;
|
|
130
|
+
return rounder(number * factor) / factor;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// DATE BASICS
|
|
134
|
+
|
|
135
|
+
export function isLeapYear(year) {
|
|
136
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function daysInYear(year) {
|
|
140
|
+
return isLeapYear(year) ? 366 : 365;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function daysInMonth(year, month) {
|
|
144
|
+
const modMonth = floorMod(month - 1, 12) + 1,
|
|
145
|
+
modYear = year + (month - modMonth) / 12;
|
|
146
|
+
|
|
147
|
+
if (modMonth === 2) {
|
|
148
|
+
return isLeapYear(modYear) ? 29 : 28;
|
|
149
|
+
} else {
|
|
150
|
+
return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// covert a calendar object to a local timestamp (epoch, but with the offset baked in)
|
|
155
|
+
export function objToLocalTS(obj) {
|
|
156
|
+
let d = Date.UTC(
|
|
157
|
+
obj.year,
|
|
158
|
+
obj.month - 1,
|
|
159
|
+
obj.day,
|
|
160
|
+
obj.hour,
|
|
161
|
+
obj.minute,
|
|
162
|
+
obj.second,
|
|
163
|
+
obj.millisecond
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
|
|
167
|
+
if (obj.year < 100 && obj.year >= 0) {
|
|
168
|
+
d = new Date(d);
|
|
169
|
+
// set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not
|
|
170
|
+
// so if obj.year is in 99, but obj.day makes it roll over into year 100,
|
|
171
|
+
// the calculations done by Date.UTC are using year 2000 - which is incorrect
|
|
172
|
+
d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
|
|
173
|
+
}
|
|
174
|
+
return +d;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function weeksInWeekYear(weekYear) {
|
|
178
|
+
const p1 =
|
|
179
|
+
(weekYear +
|
|
180
|
+
Math.floor(weekYear / 4) -
|
|
181
|
+
Math.floor(weekYear / 100) +
|
|
182
|
+
Math.floor(weekYear / 400)) %
|
|
183
|
+
7,
|
|
184
|
+
last = weekYear - 1,
|
|
185
|
+
p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7;
|
|
186
|
+
return p1 === 4 || p2 === 3 ? 53 : 52;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function untruncateYear(year) {
|
|
190
|
+
if (year > 99) {
|
|
191
|
+
return year;
|
|
192
|
+
} else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// PARSING
|
|
196
|
+
|
|
197
|
+
export function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
|
|
198
|
+
const date = new Date(ts),
|
|
199
|
+
intlOpts = {
|
|
200
|
+
hourCycle: "h23",
|
|
201
|
+
year: "numeric",
|
|
202
|
+
month: "2-digit",
|
|
203
|
+
day: "2-digit",
|
|
204
|
+
hour: "2-digit",
|
|
205
|
+
minute: "2-digit",
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
if (timeZone) {
|
|
209
|
+
intlOpts.timeZone = timeZone;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const modified = { timeZoneName: offsetFormat, ...intlOpts };
|
|
213
|
+
|
|
214
|
+
const parsed = new Intl.DateTimeFormat(locale, modified)
|
|
215
|
+
.formatToParts(date)
|
|
216
|
+
.find((m) => m.type.toLowerCase() === "timezonename");
|
|
217
|
+
return parsed ? parsed.value : null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// signedOffset('-5', '30') -> -330
|
|
221
|
+
export function signedOffset(offHourStr, offMinuteStr) {
|
|
222
|
+
let offHour = parseInt(offHourStr, 10);
|
|
223
|
+
|
|
224
|
+
// don't || this because we want to preserve -0
|
|
225
|
+
if (Number.isNaN(offHour)) {
|
|
226
|
+
offHour = 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const offMin = parseInt(offMinuteStr, 10) || 0,
|
|
230
|
+
offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
|
|
231
|
+
return offHour * 60 + offMinSigned;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// COERCION
|
|
235
|
+
|
|
236
|
+
export function asNumber(value) {
|
|
237
|
+
const numericValue = Number(value);
|
|
238
|
+
if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue))
|
|
239
|
+
throw new InvalidArgumentError(`Invalid unit value ${value}`);
|
|
240
|
+
return numericValue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function normalizeObject(obj, normalizer) {
|
|
244
|
+
const normalized = {};
|
|
245
|
+
for (const u in obj) {
|
|
246
|
+
if (hasOwnProperty(obj, u)) {
|
|
247
|
+
const v = obj[u];
|
|
248
|
+
if (v === undefined || v === null) continue;
|
|
249
|
+
normalized[normalizer(u)] = asNumber(v);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return normalized;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function formatOffset(offset, format) {
|
|
256
|
+
const hours = Math.trunc(Math.abs(offset / 60)),
|
|
257
|
+
minutes = Math.trunc(Math.abs(offset % 60)),
|
|
258
|
+
sign = offset >= 0 ? "+" : "-";
|
|
259
|
+
|
|
260
|
+
switch (format) {
|
|
261
|
+
case "short":
|
|
262
|
+
return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
|
|
263
|
+
case "narrow":
|
|
264
|
+
return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
|
|
265
|
+
case "techie":
|
|
266
|
+
return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
|
|
267
|
+
default:
|
|
268
|
+
throw new RangeError(`Value format ${format} is out of range for property format`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function timeObject(obj) {
|
|
273
|
+
return pick(obj, ["hour", "minute", "second", "millisecond"]);
|
|
274
|
+
}
|