@bbn/bbn 2.0.38 → 2.0.40

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.
@@ -4,78 +4,70 @@ import numProperties from "../../fn/object/numProperties.js";
4
4
  * Build a token pattern (YYYY, MM, DD, dddd, HH, II, SS, A, z) from Intl parts.
5
5
  * Uses Intl options to distinguish MMM vs MMMM, ddd vs dddd, etc.
6
6
  */
7
- function partsToPattern(parts, hourCycle, opts) {
7
+ function partsToPattern(parts, resolved, requestedOpts) {
8
8
  let pattern = '';
9
+ const hourCycle = resolved.hourCycle;
9
10
  const hasDayPeriod = parts.some(p => p.type === 'dayPeriod');
10
11
  const is12h = hasDayPeriod || hourCycle === 'h12' || hourCycle === 'h11';
11
- // ---- detect "all numeric date" ----
12
- const yearIsNumeric = opts.year === 'numeric' || opts.year === '2-digit';
13
- const monthIsNumeric = opts.month === 'numeric' || opts.month === '2-digit';
14
- const dayIsNumeric = opts.day === 'numeric' || opts.day === '2-digit';
15
- const hasYear = !!opts.year;
16
- const hasMonth = !!opts.month;
17
- const hasDay = !!opts.day;
18
- const hasWeekday = !!opts.weekday;
19
- const hasTextMonth = opts.month === 'short' || opts.month === 'long';
20
- const isAllNumericDate = hasYear && hasMonth && hasDay &&
21
- yearIsNumeric && monthIsNumeric && dayIsNumeric &&
22
- !hasWeekday && !hasTextMonth;
12
+ // ALL NUMERIC (not 2-digit): year, month and day resolved as "numeric"
13
+ const allNumericNonPadded = resolved.year === 'numeric' &&
14
+ resolved.month === 'numeric' &&
15
+ resolved.day === 'numeric';
23
16
  for (const p of parts) {
24
17
  switch (p.type) {
25
- case 'year':
26
- if (opts.year === '2-digit') {
18
+ case 'year': {
19
+ // Use YY only if locale actually resolved 2-digit
20
+ if (resolved.year === '2-digit') {
27
21
  pattern += 'YY';
28
22
  }
29
23
  else {
30
24
  pattern += 'YYYY';
31
25
  }
32
26
  break;
33
- case 'month':
34
- if (isAllNumericDate) {
35
- // normalize to single M when date is fully numeric
36
- pattern += 'M';
37
- }
38
- else if (opts.month === 'short') {
39
- pattern += 'MMM';
27
+ }
28
+ case 'month': {
29
+ // textual month
30
+ if (requestedOpts.month === 'short' || requestedOpts.month === 'long') {
31
+ pattern += requestedOpts.month === 'long' ? 'MMMM' : 'MMM';
32
+ break;
40
33
  }
41
- else if (opts.month === 'long') {
42
- pattern += 'MMMM';
34
+ // ALL NUMERIC and non-padded → always use M
35
+ if (allNumericNonPadded) {
36
+ pattern += 'M';
37
+ break;
43
38
  }
44
- else if (opts.month === 'numeric' || opts.month === '2-digit') {
45
- // non "all numeric" case (e.g., month+year or month+day only)
46
- pattern += /^\d{2}$/.test(p.value) ? 'MM' : 'M';
39
+ // numeric / 2-digit generic case
40
+ if (/^\d+$/.test(p.value)) {
41
+ pattern += p.value.length === 2 ? 'MM' : 'M';
47
42
  }
48
43
  else {
49
- // Fallback
50
- if (/^\d+$/.test(p.value)) {
51
- pattern += p.value.length === 2 ? 'MM' : 'M';
52
- }
53
- else {
54
- pattern += p.value.length > 3 ? 'MMMM' : 'MMM';
55
- }
44
+ // fallback (shouldn't really happen without text month)
45
+ pattern += p.value.length > 3 ? 'MMMM' : 'MMM';
56
46
  }
57
47
  break;
58
- case 'day':
59
- if (isAllNumericDate) {
60
- // normalize to single D when date is fully numeric
48
+ }
49
+ case 'day': {
50
+ // ALL NUMERIC and non-padded always use D
51
+ if (allNumericNonPadded) {
61
52
  pattern += 'D';
53
+ break;
62
54
  }
63
- else {
64
- pattern += p.value.length === 2 ? 'DD' : 'D';
65
- }
55
+ pattern += p.value.length === 2 ? 'DD' : 'D';
66
56
  break;
67
- case 'weekday':
68
- if (opts.weekday === 'short' || opts.weekday === 'narrow') {
57
+ }
58
+ case 'weekday': {
59
+ if (requestedOpts.weekday === 'short' || requestedOpts.weekday === 'narrow') {
69
60
  pattern += 'ddd';
70
61
  }
71
- else if (opts.weekday === 'long') {
62
+ else if (requestedOpts.weekday === 'long') {
72
63
  pattern += 'dddd';
73
64
  }
74
65
  else {
75
66
  pattern += p.value.length > 3 ? 'dddd' : 'ddd';
76
67
  }
77
68
  break;
78
- case 'hour':
69
+ }
70
+ case 'hour': {
79
71
  if (is12h) {
80
72
  pattern += p.value.length === 2 ? 'hh' : 'h';
81
73
  }
@@ -83,6 +75,7 @@ function partsToPattern(parts, hourCycle, opts) {
83
75
  pattern += p.value.length === 2 ? 'HH' : 'H';
84
76
  }
85
77
  break;
78
+ }
86
79
  case 'minute':
87
80
  pattern += 'II';
88
81
  break;
@@ -96,7 +89,7 @@ function partsToPattern(parts, hourCycle, opts) {
96
89
  pattern += 'z';
97
90
  break;
98
91
  case 'literal': {
99
- // Wrap literals in [ ... ] so your parser doesn't confuse them
92
+ // Wrap literals in [ ... ] so your parser won't confuse them with tokens
100
93
  if (p.value.length) {
101
94
  const v = p.value.replace(/]/g, '\\]');
102
95
  pattern += `[${v}]`;
@@ -154,7 +147,7 @@ export function getCommonFormatsForLocale(lng) {
154
147
  const fmt = new Intl.DateTimeFormat(lng, opts);
155
148
  const parts = fmt.formatToParts(sample);
156
149
  const resolved = fmt.resolvedOptions();
157
- const pattern = partsToPattern(parts, resolved.hourCycle, opts);
150
+ const pattern = partsToPattern(parts, resolved, opts);
158
151
  if (!seenDatePatterns.has(pattern)) {
159
152
  seenDatePatterns.add(pattern);
160
153
  date.push({
@@ -181,7 +174,7 @@ export function getCommonFormatsForLocale(lng) {
181
174
  const fmt = new Intl.DateTimeFormat(lng, opts);
182
175
  const parts = fmt.formatToParts(sample);
183
176
  const resolved = fmt.resolvedOptions();
184
- const pattern = partsToPattern(parts, resolved.hourCycle, opts);
177
+ const pattern = partsToPattern(parts, resolved, opts);
185
178
  if (!seenTimePatterns.has(pattern)) {
186
179
  seenTimePatterns.add(pattern);
187
180
  time.push({
@@ -198,7 +191,7 @@ export function getCommonFormatsForLocale(lng) {
198
191
  const fmt = new Intl.DateTimeFormat(lng, opts);
199
192
  const parts = fmt.formatToParts(sample);
200
193
  const resolved = fmt.resolvedOptions();
201
- const pattern = partsToPattern(parts, resolved.hourCycle, opts);
194
+ const pattern = partsToPattern(parts, resolved, opts);
202
195
  if (!seenDateTimePatterns.has(pattern)) {
203
196
  seenDateTimePatterns.add(pattern);
204
197
  datetime.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbn/bbn",
3
- "version": "2.0.38",
3
+ "version": "2.0.40",
4
4
  "description": "Javascript toolkit",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",