@bbn/bbn 2.0.22 → 2.0.24

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.
@@ -0,0 +1,526 @@
1
+ import locales from '../vars/locales.js';
2
+ export default function parse(input, format, locale) {
3
+ var _a, _b, _c, _d;
4
+ const TemporalAny = globalThis.Temporal;
5
+ if (!TemporalAny) {
6
+ throw new Error('Temporal API is required (load @js-temporal/polyfill)');
7
+ }
8
+ const T = TemporalAny;
9
+ const loc = {
10
+ monthsLong: (_a = locale === null || locale === void 0 ? void 0 : locale.monthsLong) !== null && _a !== void 0 ? _a : locales.monthsLong,
11
+ monthsShort: (_b = locale === null || locale === void 0 ? void 0 : locale.monthsShort) !== null && _b !== void 0 ? _b : locales.monthsShort,
12
+ weekdaysLong: (_c = locale === null || locale === void 0 ? void 0 : locale.weekdaysLong) !== null && _c !== void 0 ? _c : locales.weekdaysLong,
13
+ weekdaysShort: (_d = locale === null || locale === void 0 ? void 0 : locale.weekdaysShort) !== null && _d !== void 0 ? _d : locales.weekdaysShort
14
+ };
15
+ const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
16
+ const makeTokenSpecs = () => [
17
+ // Years
18
+ {
19
+ token: 'YYYY',
20
+ regex: '\\d{4}',
21
+ apply: (v, ctx) => {
22
+ ctx.year = parseInt(v, 10);
23
+ ctx.hasYear = true;
24
+ }
25
+ },
26
+ {
27
+ token: 'YY',
28
+ regex: '\\d{2}',
29
+ apply: (v, ctx) => {
30
+ const n = parseInt(v, 10);
31
+ ctx.year = n >= 70 ? 1900 + n : 2000 + n;
32
+ ctx.hasYear = true;
33
+ }
34
+ },
35
+ {
36
+ token: 'Y',
37
+ regex: '[+-]?\\d{1,6}',
38
+ apply: (v, ctx) => {
39
+ ctx.year = parseInt(v, 10);
40
+ ctx.hasYear = true;
41
+ }
42
+ },
43
+ // Months
44
+ {
45
+ token: 'MMMM',
46
+ regex: '[^\\d\\s]+',
47
+ apply: (v, ctx) => {
48
+ const idx = loc.monthsLong
49
+ .findIndex((m) => m.toLowerCase() === v.toLowerCase());
50
+ if (idx === -1) {
51
+ throw new Error('Invalid month name: ' + v);
52
+ }
53
+ ctx.month = idx + 1;
54
+ ctx.hasMonth = true;
55
+ }
56
+ },
57
+ {
58
+ token: 'MMM',
59
+ regex: '[^\\d\\s]+',
60
+ apply: (v, ctx) => {
61
+ const idx = loc.monthsShort
62
+ .findIndex((m) => m.toLowerCase() === v.toLowerCase());
63
+ if (idx === -1) {
64
+ throw new Error('Invalid short month name: ' + v);
65
+ }
66
+ ctx.month = idx + 1;
67
+ ctx.hasMonth = true;
68
+ }
69
+ },
70
+ {
71
+ token: 'MM',
72
+ regex: '\\d{2}',
73
+ apply: (v, ctx) => {
74
+ const n = parseInt(v, 10);
75
+ if (n < 1 || n > 12) {
76
+ throw new Error('Invalid month: ' + n);
77
+ }
78
+ ctx.month = n;
79
+ ctx.hasMonth = true;
80
+ }
81
+ },
82
+ {
83
+ token: 'mm',
84
+ regex: '\\d{2}',
85
+ apply: (v, ctx) => {
86
+ const n = parseInt(v, 10);
87
+ if (n < 0 || n > 59) {
88
+ throw new Error('Invalid minute: ' + n);
89
+ }
90
+ // NOTE: in your original code this wrote to month, but name suggests minutes.
91
+ // I'm keeping original behavior, but you might want to correct this.
92
+ ctx.month = n;
93
+ ctx.hasMonth = true;
94
+ }
95
+ },
96
+ {
97
+ token: 'M',
98
+ regex: '\\d{1,2}',
99
+ apply: (v, ctx) => {
100
+ const n = parseInt(v, 10);
101
+ if (n < 1 || n > 12) {
102
+ throw new Error('Invalid month: ' + n);
103
+ }
104
+ ctx.month = n;
105
+ ctx.hasMonth = true;
106
+ }
107
+ },
108
+ {
109
+ token: 'm', // PHP-like month
110
+ regex: '\\d{2}',
111
+ apply: (v, ctx) => {
112
+ const n = parseInt(v, 10);
113
+ if (n < 1 || n > 12) {
114
+ throw new Error('Invalid month: ' + n);
115
+ }
116
+ ctx.month = n;
117
+ ctx.hasMonth = true;
118
+ }
119
+ },
120
+ // Day of month
121
+ {
122
+ token: 'DD',
123
+ regex: '\\d{2}',
124
+ apply: (v, ctx) => {
125
+ const n = parseInt(v, 10);
126
+ if (n < 1 || n > 31) {
127
+ throw new Error('Invalid day of month: ' + n);
128
+ }
129
+ ctx.day = n;
130
+ ctx.hasDay = true;
131
+ }
132
+ },
133
+ {
134
+ token: 'D',
135
+ regex: '\\d{1,2}',
136
+ apply: (v, ctx) => {
137
+ const n = parseInt(v, 10);
138
+ if (n < 1 || n > 31) {
139
+ throw new Error('Invalid day of month: ' + n);
140
+ }
141
+ ctx.day = n;
142
+ ctx.hasDay = true;
143
+ }
144
+ },
145
+ {
146
+ token: 'd', // PHP-like day-of-month
147
+ regex: '\\d{2}',
148
+ apply: (v, ctx) => {
149
+ const n = parseInt(v, 10);
150
+ if (n < 1 || n > 31) {
151
+ throw new Error('Invalid day of month: ' + n);
152
+ }
153
+ ctx.day = n;
154
+ ctx.hasDay = true;
155
+ }
156
+ },
157
+ // Weekday (validated only, not used for construction)
158
+ {
159
+ token: 'dddd',
160
+ regex: '[^\\d\\s]+',
161
+ apply: (v, ctx) => {
162
+ const idx = loc.weekdaysLong
163
+ .findIndex((w) => w.toLowerCase() === v.toLowerCase());
164
+ if (idx === -1) {
165
+ throw new Error('Invalid weekday name: ' + v);
166
+ }
167
+ ctx.weekday = idx; // 0-6
168
+ }
169
+ },
170
+ {
171
+ token: 'ddd',
172
+ regex: '[^\\d\\s]+',
173
+ apply: (v, ctx) => {
174
+ const idx = loc.weekdaysShort
175
+ .findIndex((w) => w.toLowerCase() === v.toLowerCase());
176
+ if (idx === -1) {
177
+ throw new Error('Invalid short weekday name: ' + v);
178
+ }
179
+ ctx.weekday = idx;
180
+ }
181
+ },
182
+ {
183
+ token: 'EE',
184
+ regex: '\\d{1}',
185
+ apply: (v, ctx) => {
186
+ const n = parseInt(v, 10);
187
+ if (n < 0 || n > 7) {
188
+ throw new Error('Invalid weekday number: ' + n);
189
+ }
190
+ ctx.weekday = n;
191
+ }
192
+ },
193
+ // Hours
194
+ {
195
+ token: 'HH',
196
+ regex: '\\d{2}',
197
+ apply: (v, ctx) => {
198
+ const n = parseInt(v, 10);
199
+ if (n < 0 || n > 23) {
200
+ throw new Error('Invalid hour: ' + n);
201
+ }
202
+ ctx.hour = n;
203
+ ctx.hasHour = true;
204
+ }
205
+ },
206
+ {
207
+ token: 'H',
208
+ regex: '\\d{1,2}',
209
+ apply: (v, ctx) => {
210
+ const n = parseInt(v, 10);
211
+ if (n < 0 || n > 23) {
212
+ throw new Error('Invalid hour: ' + n);
213
+ }
214
+ ctx.hour = n;
215
+ ctx.hasHour = true;
216
+ }
217
+ },
218
+ {
219
+ token: 'h', // PHP-like 24h alias here
220
+ regex: '\\d{2}',
221
+ apply: (v, ctx) => {
222
+ const n = parseInt(v, 10);
223
+ if (n < 0 || n > 23) {
224
+ throw new Error('Invalid hour: ' + n);
225
+ }
226
+ ctx.hour = n;
227
+ ctx.hasHour = true;
228
+ }
229
+ },
230
+ // Minutes
231
+ {
232
+ token: 'II',
233
+ regex: '\\d{2}',
234
+ apply: (v, ctx) => {
235
+ const n = parseInt(v, 10);
236
+ if (n < 0 || n > 59) {
237
+ throw new Error('Invalid minute: ' + n);
238
+ }
239
+ ctx.minute = n;
240
+ ctx.hasMinute = true;
241
+ }
242
+ },
243
+ {
244
+ token: 'I',
245
+ regex: '\\d{1,2}',
246
+ apply: (v, ctx) => {
247
+ const n = parseInt(v, 10);
248
+ if (n < 0 || n > 59) {
249
+ throw new Error('Invalid minute: ' + n);
250
+ }
251
+ ctx.minute = n;
252
+ ctx.hasMinute = true;
253
+ }
254
+ },
255
+ {
256
+ token: 'i', // PHP-like minutes
257
+ regex: '\\d{2}',
258
+ apply: (v, ctx) => {
259
+ const n = parseInt(v, 10);
260
+ if (n < 0 || n > 59) {
261
+ throw new Error('Invalid minute: ' + n);
262
+ }
263
+ ctx.minute = n;
264
+ ctx.hasMinute = true;
265
+ }
266
+ },
267
+ // Seconds
268
+ {
269
+ token: 'SS',
270
+ regex: '\\d{2}',
271
+ apply: (v, ctx) => {
272
+ const n = parseInt(v, 10);
273
+ if (n < 0 || n > 59) {
274
+ throw new Error('Invalid second: ' + n);
275
+ }
276
+ ctx.second = n;
277
+ ctx.hasSecond = true;
278
+ }
279
+ },
280
+ {
281
+ token: 'S',
282
+ regex: '\\d{1,2}',
283
+ apply: (v, ctx) => {
284
+ const n = parseInt(v, 10);
285
+ if (n < 0 || n > 59) {
286
+ throw new Error('Invalid second: ' + n);
287
+ }
288
+ ctx.second = n;
289
+ ctx.hasSecond = true;
290
+ }
291
+ },
292
+ {
293
+ token: 's', // PHP-like seconds
294
+ regex: '\\d{2}',
295
+ apply: (v, ctx) => {
296
+ const n = parseInt(v, 10);
297
+ if (n < 0 || n > 59) {
298
+ throw new Error('Invalid second: ' + n);
299
+ }
300
+ ctx.second = n;
301
+ ctx.hasSecond = true;
302
+ }
303
+ },
304
+ // Milliseconds
305
+ {
306
+ token: 'ms',
307
+ regex: '\\d{1,3}',
308
+ apply: (v, ctx) => {
309
+ const n = parseInt(v, 10);
310
+ if (n < 0 || n > 999) {
311
+ throw new Error('Invalid millisecond: ' + n);
312
+ }
313
+ ctx.ms = n;
314
+ ctx.hasMs = true;
315
+ }
316
+ },
317
+ // Week (parsed, not used yet)
318
+ {
319
+ token: 'WWWW',
320
+ regex: '\\d{1,2}',
321
+ apply: (v, ctx) => {
322
+ const n = parseInt(v, 10);
323
+ if (n < 1 || n > 53) {
324
+ throw new Error('Invalid week number: ' + n);
325
+ }
326
+ ctx.week = n;
327
+ }
328
+ },
329
+ {
330
+ token: 'WWW',
331
+ regex: '\\d{1,2}',
332
+ apply: (v, ctx) => {
333
+ const n = parseInt(v, 10);
334
+ if (n < 1 || n > 53) {
335
+ throw new Error('Invalid week number: ' + n);
336
+ }
337
+ ctx.week = n;
338
+ }
339
+ },
340
+ {
341
+ token: 'WW',
342
+ regex: '\\d{1,2}',
343
+ apply: (v, ctx) => {
344
+ const n = parseInt(v, 10);
345
+ if (n < 1 || n > 53) {
346
+ throw new Error('Invalid week number: ' + n);
347
+ }
348
+ ctx.week = n;
349
+ }
350
+ },
351
+ {
352
+ token: 'W',
353
+ regex: '\\d{1,2}',
354
+ apply: (v, ctx) => {
355
+ const n = parseInt(v, 10);
356
+ if (n < 1 || n > 53) {
357
+ throw new Error('Invalid week number: ' + n);
358
+ }
359
+ ctx.week = n;
360
+ }
361
+ },
362
+ // Timezone offset (Z)
363
+ {
364
+ token: 'Z',
365
+ regex: '(?:Z|[+-]\\d{2}:?\\d{2})',
366
+ apply: (v, ctx) => {
367
+ if (v === 'Z' || v === 'z') {
368
+ ctx.offsetMinutes = 0;
369
+ return;
370
+ }
371
+ const sign = v[0] === '-' ? -1 : 1;
372
+ const rest = v.slice(1); // "02:00" or "0500"
373
+ let hh;
374
+ let mm;
375
+ if (rest.includes(':')) {
376
+ const [h, m] = rest.split(':');
377
+ hh = parseInt(h, 10);
378
+ mm = parseInt(m, 10);
379
+ }
380
+ else {
381
+ hh = parseInt(rest.slice(0, 2), 10);
382
+ mm = parseInt(rest.slice(2, 4), 10);
383
+ }
384
+ if (hh < 0 || hh > 23 || mm < 0 || mm > 59) {
385
+ throw new Error('Invalid timezone offset: ' + v);
386
+ }
387
+ ctx.offsetMinutes = sign * (hh * 60 + mm);
388
+ }
389
+ },
390
+ // Timezone name (z) – IANA like "Europe/Rome"
391
+ {
392
+ token: 'z',
393
+ regex: '[A-Za-z_\\/]+',
394
+ apply: (v, ctx) => {
395
+ ctx.timeZone = v;
396
+ }
397
+ }
398
+ ];
399
+ function parseWithFormat(fmt) {
400
+ var _a;
401
+ const ctx = {
402
+ year: 1970,
403
+ month: 1,
404
+ day: 1,
405
+ hour: 0,
406
+ minute: 0,
407
+ second: 0,
408
+ ms: 0,
409
+ hasYear: false,
410
+ hasMonth: false,
411
+ hasDay: false,
412
+ hasHour: false,
413
+ hasMinute: false,
414
+ hasSecond: false,
415
+ hasMs: false
416
+ };
417
+ const tokenSpecs = makeTokenSpecs();
418
+ const tokensByLength = [...tokenSpecs].sort((a, b) => b.token.length - a.token.length);
419
+ let pattern = '';
420
+ const applyFns = [];
421
+ let i = 0;
422
+ while (i < fmt.length) {
423
+ let matchedToken = null;
424
+ for (const spec of tokensByLength) {
425
+ if (fmt.startsWith(spec.token, i)) {
426
+ matchedToken = spec;
427
+ break;
428
+ }
429
+ }
430
+ if (matchedToken) {
431
+ pattern += `(${matchedToken.regex})`;
432
+ if (matchedToken.apply) {
433
+ applyFns.push(value => matchedToken.apply(value, ctx));
434
+ }
435
+ else {
436
+ applyFns.push(() => { });
437
+ }
438
+ i += matchedToken.token.length;
439
+ }
440
+ else {
441
+ pattern += escapeRegex(fmt[i]);
442
+ i += 1;
443
+ }
444
+ }
445
+ const fullRegex = new RegExp('^' + pattern + '$');
446
+ const match = fullRegex.exec(input);
447
+ if (!match) {
448
+ throw new Error(`Date string "${input}" does not match format "${fmt}"`);
449
+ }
450
+ for (let idx = 1; idx < match.length; idx++) {
451
+ const value = match[idx];
452
+ const apply = applyFns[idx - 1];
453
+ if (value != null && apply) {
454
+ apply(value);
455
+ }
456
+ }
457
+ const hasDate = ctx.hasYear || ctx.hasMonth || ctx.hasDay;
458
+ const hasFullDate = ctx.hasYear && ctx.hasMonth && ctx.hasDay;
459
+ const hasYearMonthOnly = ctx.hasYear && ctx.hasMonth && !ctx.hasDay;
460
+ const hasMonthDayOnly = !ctx.hasYear && ctx.hasMonth && ctx.hasDay;
461
+ const hasTime = ctx.hasHour || ctx.hasMinute || ctx.hasSecond || ctx.hasMs;
462
+ const hasZone = ctx.timeZone != null || ctx.offsetMinutes != null;
463
+ // ---------- 1) If timezone (Z or z) → Instant ----------
464
+ if (hasZone) {
465
+ // Fill date/time with whatever we have + defaults (1970-01-01 etc.)
466
+ let pdt;
467
+ try {
468
+ pdt = new T.PlainDateTime(ctx.year, ctx.month, ctx.day, ctx.hour, ctx.minute, ctx.second, ctx.ms * 1000000);
469
+ }
470
+ catch (_b) {
471
+ throw new Error('Invalid date/time components');
472
+ }
473
+ if (ctx.timeZone) {
474
+ const tz = T.TimeZone.from(ctx.timeZone);
475
+ const zdt = pdt.toZonedDateTime(tz);
476
+ return zdt.toInstant();
477
+ }
478
+ // offsetMinutes only
479
+ const utcMs = Date.UTC(ctx.year, ctx.month - 1, ctx.day, ctx.hour, ctx.minute, ctx.second, ctx.ms);
480
+ const epochMs = utcMs - ((_a = ctx.offsetMinutes) !== null && _a !== void 0 ? _a : 0) * 60000;
481
+ return T.Instant.fromEpochMilliseconds(epochMs);
482
+ }
483
+ // ---------- 2) No timezone: decide which Plain* type ----------
484
+ if (hasDate && hasTime) {
485
+ // Full DateTime (even if some date fields defaulted; we require full date)
486
+ if (!hasFullDate) {
487
+ throw new Error('PlainDateTime requires year, month and day');
488
+ }
489
+ return new T.PlainDateTime(ctx.year, ctx.month, ctx.day, ctx.hour, ctx.minute, ctx.second, ctx.ms * 1000000);
490
+ }
491
+ if (hasDate && !hasTime) {
492
+ if (hasFullDate) {
493
+ return new T.PlainDate(ctx.year, ctx.month, ctx.day);
494
+ }
495
+ if (hasYearMonthOnly) {
496
+ return new T.PlainYearMonth(ctx.year, ctx.month);
497
+ }
498
+ if (hasMonthDayOnly) {
499
+ // Reference year: 1972 is often used (leap year)
500
+ return new T.PlainMonthDay(ctx.month, ctx.day, 1972);
501
+ }
502
+ // e.g. only year → ambiguous, you can decide another behavior if you want
503
+ throw new Error('Not enough date components for a known Temporal type');
504
+ }
505
+ if (!hasDate && hasTime) {
506
+ // PlainTime
507
+ return new T.PlainTime(ctx.hour, ctx.minute, ctx.second, ctx.ms * 1000000);
508
+ }
509
+ throw new Error('No date or time information found in input');
510
+ }
511
+ // ---------- Handle single format or array of formats ----------
512
+ if (Array.isArray(format)) {
513
+ let lastError = null;
514
+ for (const fmt of format) {
515
+ try {
516
+ return parseWithFormat(fmt);
517
+ }
518
+ catch (e) {
519
+ lastError = e;
520
+ }
521
+ }
522
+ throw lastError !== null && lastError !== void 0 ? lastError : new Error('No format matched');
523
+ }
524
+ return parseWithFormat(format);
525
+ }
526
+ ;
@@ -0,0 +1,2 @@
1
+ declare const locales: any;
2
+ export default locales;
@@ -0,0 +1,5 @@
1
+ import buildLocaleFromIntl from "../functions/buildLocaleFromIntl.js";
2
+ import extend from "../../fn/object/extend.js";
3
+ const locales = {};
4
+ extend(locales, buildLocaleFromIntl());
5
+ export default locales;
package/dist/dt.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import parse from './dt/functions/parse.js';
2
+ declare const dt: {
3
+ (value: any, inputFormat?: null | String): void;
4
+ parse: typeof parse;
5
+ time(): void;
6
+ date(): void;
7
+ dateTime(): void;
8
+ duration(): void;
9
+ zoned(): void;
10
+ monthDay(): void;
11
+ yearMonth(): void;
12
+ };
13
+ export default dt;