@samline/date 2.0.0 → 2.1.0

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/README.md CHANGED
@@ -45,6 +45,21 @@ const date = await getDate({
45
45
  })
46
46
  ```
47
47
 
48
+ You can also inspect the effective locale before formatting:
49
+
50
+ ```ts
51
+ import { resolveLocale } from '@samline/date'
52
+
53
+ resolveLocale('es-mx')
54
+ // es-mx
55
+
56
+ resolveLocale('en-us')
57
+ // en
58
+
59
+ resolveLocale('zz-zz')
60
+ // null
61
+ ```
62
+
48
63
  For repeated work with the same locale or invalid text, create one formatter instance and reuse it:
49
64
 
50
65
  ```ts
@@ -67,7 +82,7 @@ const date = formatter.getDate({
67
82
 
68
83
  ```ts
69
84
  createDateFormatter(config?: {
70
- locale?: SupportedLocale
85
+ locale?: LocaleInput
71
86
  strict?: boolean
72
87
  invalid?: string
73
88
  }): {
@@ -76,7 +91,7 @@ createDateFormatter(config?: {
76
91
  isValidDate(props: DateParsingOptions): boolean
77
92
  getSupportedLocales(): readonly SupportedLocale[]
78
93
  getCurrentLocale(): SupportedLocale
79
- setLocale(locale: SupportedLocale): Promise<void>
94
+ setLocale(locale: LocaleInput): Promise<void>
80
95
  ready: Promise<void>
81
96
  }
82
97
  ```
@@ -85,7 +100,9 @@ Creates a formatter instance with its own locale state. This avoids coupling fra
85
100
 
86
101
  `strict` is `true` by default, so parsing fails when the input does not match the provided format exactly. Use `strict: false` only when you explicitly want lenient parsing.
87
102
 
88
- If you override `locale` per call, make sure that locale was already loaded by a formatter instance.
103
+ If you override `locale` per call, make sure the effective locale was already loaded by a formatter instance.
104
+
105
+ Regional locale input falls back to the base locale when the exact variant is not supported by the package. For example, `en-us` resolves to `en`, while `es-mx` stays as `es-mx` because that locale is supported explicitly.
89
106
 
90
107
  The formatter instance exposes:
91
108
 
@@ -97,6 +114,19 @@ The formatter instance exposes:
97
114
  - `getSupportedLocales()`
98
115
  - `ready`
99
116
 
117
+ ### Locale helpers
118
+
119
+ ```ts
120
+ resolveLocale(locale: LocaleInput): SupportedLocale | null
121
+ isSupportedLocale(locale: string): boolean
122
+ ```
123
+
124
+ Use `resolveLocale` when you want to know the effective locale before creating a formatter or calling a helper.
125
+
126
+ Use `isSupportedLocale` when you only need a boolean check after the package applies its exact-match and base-locale fallback rules.
127
+
128
+ These helpers are also available in the browser build through `DateKit.resolveLocale(...)` and `DateKit.isSupportedLocale(...)`.
129
+
100
130
  ### One-shot helpers
101
131
 
102
132
  ```ts
@@ -176,7 +206,23 @@ The package ships helper support for these locale keys:
176
206
  - `it`
177
207
  - `ja`
178
208
 
179
- Use `createDateFormatter({ locale: 'es-mx' })` when you need a locale other than English.
209
+ You can also pass regional locale input such as `en-us`, `fr-ca`, or `pt-pt`.
210
+
211
+ The resolution rule is:
212
+
213
+ - if the exact locale exists, use it
214
+ - otherwise, try the base locale before the hyphen
215
+ - if neither exists, throw an unsupported locale error
216
+
217
+ Examples:
218
+
219
+ - `es-mx` -> `es-mx`
220
+ - `es-ar` -> `es`
221
+ - `en-us` -> `en`
222
+ - `pt-pt` -> `pt`
223
+ - `zz-zz` -> error
224
+
225
+ Use a simple locale like `fr` or `en` when the base language is enough. Use a regional locale like `es-mx` or `pt-br` when you need a supported country-specific variant.
180
226
 
181
227
  ## Documentation
182
228
 
@@ -1,11 +1,13 @@
1
- import { DateFormatterConfig, DateFormatter, GetDateOptions, SupportedLocale, DateParsingOptions, ParseDateResult } from '../index.js';
1
+ import { DateFormatterConfig, DateFormatter, GetDateOptions, SupportedLocale, DateParsingOptions, ParseDateResult, LocaleInput } from '../index.js';
2
2
 
3
3
  declare const DateKit: {
4
4
  createDateFormatter: (config?: DateFormatterConfig) => DateFormatter;
5
5
  getDate: (props?: GetDateOptions, config?: DateFormatterConfig) => Promise<string>;
6
6
  getSupportedLocales: () => readonly SupportedLocale[];
7
+ isSupportedLocale: (locale: string) => boolean;
7
8
  parseDate: (props: DateParsingOptions, config?: DateFormatterConfig) => Promise<ParseDateResult>;
8
9
  isValidDate: (props: DateParsingOptions, config?: DateFormatterConfig) => Promise<boolean>;
10
+ resolveLocale: (locale: LocaleInput) => SupportedLocale | null;
9
11
  };
10
12
  declare global {
11
13
  interface Window {
@@ -25,8 +25,29 @@ var localeLoaders = {
25
25
  it: () => import("dayjs/locale/it.js"),
26
26
  ja: () => import("dayjs/locale/ja.js")
27
27
  };
28
+ var normalizeLocale = (locale) => {
29
+ return locale.trim().toLowerCase().replace(/_/g, "-");
30
+ };
31
+ var asSupportedLocale = (locale) => {
32
+ if (!SUPPORTED_LOCALES.includes(locale)) {
33
+ return null;
34
+ }
35
+ return locale;
36
+ };
28
37
  var isSupportedLocale = (locale) => {
29
- return SUPPORTED_LOCALES.includes(locale);
38
+ return resolveLocale(locale) !== null;
39
+ };
40
+ var resolveLocale = (locale) => {
41
+ const normalizedLocale = normalizeLocale(locale);
42
+ const exactLocale = asSupportedLocale(normalizedLocale);
43
+ if (exactLocale) {
44
+ return exactLocale;
45
+ }
46
+ const [baseLocale] = normalizedLocale.split("-");
47
+ if (!baseLocale) {
48
+ return null;
49
+ }
50
+ return asSupportedLocale(baseLocale);
30
51
  };
31
52
  var ensureLocaleLoaded = async (locale) => {
32
53
  const load = localeLoaders[locale];
@@ -52,10 +73,19 @@ var getInvalidDateText = (config, props) => {
52
73
  return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE;
53
74
  };
54
75
  var getTargetLocale = (currentLocale, props) => {
55
- return props?.locale ?? currentLocale;
76
+ if (!props?.locale) {
77
+ return currentLocale;
78
+ }
79
+ return resolveLocaleOrThrow(props.locale);
56
80
  };
57
81
  var getHelperLocale = (config, props) => {
58
- return props?.locale ?? config?.locale ?? DEFAULT_LOCALE;
82
+ if (props?.locale) {
83
+ return resolveLocaleOrThrow(props.locale);
84
+ }
85
+ if (config?.locale) {
86
+ return resolveLocaleOrThrow(config.locale);
87
+ }
88
+ return DEFAULT_LOCALE;
59
89
  };
60
90
  var parseDateValue = (value, input, locale, strict) => {
61
91
  if (!input) {
@@ -118,10 +148,14 @@ var createFormatterGetDate = (getConfig) => {
118
148
  return parsed.format(output);
119
149
  };
120
150
  };
121
- function assertSupportedLocale(locale) {
122
- if (!isSupportedLocale(locale)) {
123
- throw new Error(`Unsupported locale: ${locale}`);
151
+ function resolveLocaleOrThrow(locale) {
152
+ const resolvedLocale = resolveLocale(locale);
153
+ if (!resolvedLocale) {
154
+ throw new Error(
155
+ `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`
156
+ );
124
157
  }
158
+ return resolvedLocale;
125
159
  }
126
160
  var getSupportedLocales = () => SUPPORTED_LOCALES;
127
161
  var getDate = async (props, config) => {
@@ -143,7 +177,7 @@ var isValidDate = async (props, config) => {
143
177
  return formatter.isValidDate(props);
144
178
  };
145
179
  var createDateFormatter = (config) => {
146
- let currentLocale = config?.locale ?? DEFAULT_LOCALE;
180
+ let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE;
147
181
  const getConfig = () => createResolvedConfig(currentLocale, config);
148
182
  const ready = ensureLocaleLoaded(currentLocale);
149
183
  const parseDate2 = createFormatterParseDate(getConfig);
@@ -154,9 +188,9 @@ var createDateFormatter = (config) => {
154
188
  getSupportedLocales,
155
189
  getCurrentLocale: () => currentLocale,
156
190
  setLocale: async (locale) => {
157
- assertSupportedLocale(locale);
158
- await ensureLocaleLoaded(locale);
159
- currentLocale = locale;
191
+ const resolvedLocale = resolveLocaleOrThrow(locale);
192
+ await ensureLocaleLoaded(resolvedLocale);
193
+ currentLocale = resolvedLocale;
160
194
  },
161
195
  ready
162
196
  };
@@ -167,8 +201,10 @@ var DateKit = {
167
201
  createDateFormatter,
168
202
  getDate,
169
203
  getSupportedLocales,
204
+ isSupportedLocale,
170
205
  parseDate,
171
- isValidDate
206
+ isValidDate,
207
+ resolveLocale
172
208
  };
173
209
  if (typeof window !== "undefined") {
174
210
  window.DateKit = DateKit;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/date.ts","../../src/core/locales.ts","../../src/browser/global.ts"],"sourcesContent":["import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, isSupportedLocale, SUPPORTED_LOCALES, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: SupportedLocale\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: SupportedLocale\n strict?: boolean\n invalid?: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: SupportedLocale) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): Required<DateFormatterConfig> => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n return props?.locale ?? currentLocale\n}\n\nconst getHelperLocale = <T extends { locale?: SupportedLocale }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n return props?.locale ?? config?.locale ?? DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => Required<DateFormatterConfig>) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => Required<DateFormatterConfig>) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction assertSupportedLocale(locale: string): asserts locale is SupportedLocale {\n if (!isSupportedLocale(locale)) {\n throw new Error(`Unsupported locale: ${locale}`)\n }\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ?? DEFAULT_LOCALE\n\n const getConfig = (): Required<DateFormatterConfig> => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: SupportedLocale) => {\n assertSupportedLocale(locale)\n await ensureLocaleLoaded(locale)\n currentLocale = locale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nexport const isSupportedLocale = (locale: string): locale is SupportedLocale => {\n return SUPPORTED_LOCALES.includes(locale as SupportedLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n","import { createDateFormatter, getDate, getSupportedLocales, isValidDate, parseDate } from '../index.js'\n\nexport const DateKit = {\n createDateFormatter,\n getDate,\n getSupportedLocales\n ,\n parseDate,\n isValidDate\n}\n\ndeclare global {\n interface Window {\n DateKit: typeof DateKit\n }\n}\n\nif (typeof window !== 'undefined') {\n window.DateKit = DateKit\n}\n"],"mappings":"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","names":["parseDate"]}
1
+ {"version":3,"sources":["../../src/core/date.ts","../../src/core/locales.ts","../../src/browser/global.ts"],"sourcesContent":["import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, resolveLocale, SUPPORTED_LOCALES, type LocaleInput, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: LocaleInput\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: LocaleInput\n strict?: boolean\n invalid?: string\n}\n\ntype ResolvedDateFormatterConfig = {\n locale: SupportedLocale\n strict: boolean\n invalid: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: LocaleInput) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): ResolvedDateFormatterConfig => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n if (!props?.locale) {\n return currentLocale\n }\n\n return resolveLocaleOrThrow(props.locale)\n}\n\nconst getHelperLocale = <T extends { locale?: LocaleInput }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n if (props?.locale) {\n return resolveLocaleOrThrow(props.locale)\n }\n\n if (config?.locale) {\n return resolveLocaleOrThrow(config.locale)\n }\n\n return DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction resolveLocaleOrThrow(locale: LocaleInput): SupportedLocale {\n const resolvedLocale = resolveLocale(locale)\n\n if (!resolvedLocale) {\n throw new Error(\n `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`\n )\n }\n\n return resolvedLocale\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE\n\n const getConfig = (): ResolvedDateFormatterConfig => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: LocaleInput) => {\n const resolvedLocale = resolveLocaleOrThrow(locale)\n\n await ensureLocaleLoaded(resolvedLocale)\n currentLocale = resolvedLocale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\nexport type LocaleInput = string\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nconst normalizeLocale = (locale: string): string => {\n return locale.trim().toLowerCase().replace(/_/g, '-')\n}\n\nconst asSupportedLocale = (locale: string): SupportedLocale | null => {\n if (!SUPPORTED_LOCALES.includes(locale as SupportedLocale)) {\n return null\n }\n\n return locale as SupportedLocale\n}\n\nexport const isSupportedLocale = (locale: string): boolean => {\n return resolveLocale(locale) !== null\n}\n\nexport const resolveLocale = (locale: LocaleInput): SupportedLocale | null => {\n const normalizedLocale = normalizeLocale(locale)\n const exactLocale = asSupportedLocale(normalizedLocale)\n\n if (exactLocale) {\n return exactLocale\n }\n\n const [baseLocale] = normalizedLocale.split('-')\n\n if (!baseLocale) {\n return null\n }\n\n return asSupportedLocale(baseLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n","import {\n createDateFormatter,\n getDate,\n getSupportedLocales,\n isSupportedLocale,\n isValidDate,\n parseDate,\n resolveLocale\n} from '../index.js'\n\nexport const DateKit = {\n createDateFormatter,\n getDate,\n getSupportedLocales,\n isSupportedLocale,\n parseDate,\n isValidDate,\n resolveLocale\n}\n\ndeclare global {\n interface Window {\n DateKit: typeof DateKit\n }\n}\n\nif (typeof window !== 'undefined') {\n window.DateKit = DateKit\n}\n"],"mappings":"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","names":["parseDate"]}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,13 @@
1
1
  declare const SUPPORTED_LOCALES: readonly ["en", "es", "es-mx", "fr", "pt", "pt-br", "de", "it", "ja"];
2
2
  type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
3
+ type LocaleInput = string;
4
+ declare const isSupportedLocale: (locale: string) => boolean;
5
+ declare const resolveLocale: (locale: LocaleInput) => SupportedLocale | null;
3
6
 
4
7
  type DateValue = string | number | Date;
5
8
  type DateInputOptions = {
6
9
  input?: string | readonly string[];
7
- locale?: SupportedLocale;
10
+ locale?: LocaleInput;
8
11
  strict?: boolean;
9
12
  };
10
13
  type DateParsingOptions = DateInputOptions & {
@@ -16,7 +19,7 @@ type GetDateOptions = DateInputOptions & {
16
19
  invalid?: string;
17
20
  };
18
21
  type DateFormatterConfig = {
19
- locale?: SupportedLocale;
22
+ locale?: LocaleInput;
20
23
  strict?: boolean;
21
24
  invalid?: string;
22
25
  };
@@ -26,7 +29,7 @@ type DateFormatter = {
26
29
  isValidDate: (props: DateParsingOptions) => boolean;
27
30
  getSupportedLocales: () => readonly SupportedLocale[];
28
31
  getCurrentLocale: () => SupportedLocale;
29
- setLocale: (locale: SupportedLocale) => Promise<void>;
32
+ setLocale: (locale: LocaleInput) => Promise<void>;
30
33
  ready: Promise<void>;
31
34
  };
32
35
  type ParseDateSuccess = {
@@ -52,4 +55,4 @@ declare const parseDate: (props: DateParsingOptions, config?: DateFormatterConfi
52
55
  declare const isValidDate: (props: DateParsingOptions, config?: DateFormatterConfig) => Promise<boolean>;
53
56
  declare const createDateFormatter: (config?: DateFormatterConfig) => DateFormatter;
54
57
 
55
- export { type DateFormatter, type DateFormatterConfig, type DateParsingOptions, type DateValue, type GetDateOptions, type ParseDateFailure, type ParseDateResult, type ParseDateSuccess, SUPPORTED_LOCALES, type SupportedLocale, createDateFormatter, getDate, getSupportedLocales, isValidDate, parseDate };
58
+ export { type DateFormatter, type DateFormatterConfig, type DateParsingOptions, type DateValue, type GetDateOptions, type LocaleInput, type ParseDateFailure, type ParseDateResult, type ParseDateSuccess, SUPPORTED_LOCALES, type SupportedLocale, createDateFormatter, getDate, getSupportedLocales, isSupportedLocale, isValidDate, parseDate, resolveLocale };
package/dist/index.js CHANGED
@@ -25,8 +25,29 @@ var localeLoaders = {
25
25
  it: () => import("dayjs/locale/it.js"),
26
26
  ja: () => import("dayjs/locale/ja.js")
27
27
  };
28
+ var normalizeLocale = (locale) => {
29
+ return locale.trim().toLowerCase().replace(/_/g, "-");
30
+ };
31
+ var asSupportedLocale = (locale) => {
32
+ if (!SUPPORTED_LOCALES.includes(locale)) {
33
+ return null;
34
+ }
35
+ return locale;
36
+ };
28
37
  var isSupportedLocale = (locale) => {
29
- return SUPPORTED_LOCALES.includes(locale);
38
+ return resolveLocale(locale) !== null;
39
+ };
40
+ var resolveLocale = (locale) => {
41
+ const normalizedLocale = normalizeLocale(locale);
42
+ const exactLocale = asSupportedLocale(normalizedLocale);
43
+ if (exactLocale) {
44
+ return exactLocale;
45
+ }
46
+ const [baseLocale] = normalizedLocale.split("-");
47
+ if (!baseLocale) {
48
+ return null;
49
+ }
50
+ return asSupportedLocale(baseLocale);
30
51
  };
31
52
  var ensureLocaleLoaded = async (locale) => {
32
53
  const load = localeLoaders[locale];
@@ -52,10 +73,19 @@ var getInvalidDateText = (config, props) => {
52
73
  return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE;
53
74
  };
54
75
  var getTargetLocale = (currentLocale, props) => {
55
- return props?.locale ?? currentLocale;
76
+ if (!props?.locale) {
77
+ return currentLocale;
78
+ }
79
+ return resolveLocaleOrThrow(props.locale);
56
80
  };
57
81
  var getHelperLocale = (config, props) => {
58
- return props?.locale ?? config?.locale ?? DEFAULT_LOCALE;
82
+ if (props?.locale) {
83
+ return resolveLocaleOrThrow(props.locale);
84
+ }
85
+ if (config?.locale) {
86
+ return resolveLocaleOrThrow(config.locale);
87
+ }
88
+ return DEFAULT_LOCALE;
59
89
  };
60
90
  var parseDateValue = (value, input, locale, strict) => {
61
91
  if (!input) {
@@ -118,10 +148,14 @@ var createFormatterGetDate = (getConfig) => {
118
148
  return parsed.format(output);
119
149
  };
120
150
  };
121
- function assertSupportedLocale(locale) {
122
- if (!isSupportedLocale(locale)) {
123
- throw new Error(`Unsupported locale: ${locale}`);
151
+ function resolveLocaleOrThrow(locale) {
152
+ const resolvedLocale = resolveLocale(locale);
153
+ if (!resolvedLocale) {
154
+ throw new Error(
155
+ `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`
156
+ );
124
157
  }
158
+ return resolvedLocale;
125
159
  }
126
160
  var getSupportedLocales = () => SUPPORTED_LOCALES;
127
161
  var getDate = async (props, config) => {
@@ -143,7 +177,7 @@ var isValidDate = async (props, config) => {
143
177
  return formatter.isValidDate(props);
144
178
  };
145
179
  var createDateFormatter = (config) => {
146
- let currentLocale = config?.locale ?? DEFAULT_LOCALE;
180
+ let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE;
147
181
  const getConfig = () => createResolvedConfig(currentLocale, config);
148
182
  const ready = ensureLocaleLoaded(currentLocale);
149
183
  const parseDate2 = createFormatterParseDate(getConfig);
@@ -154,9 +188,9 @@ var createDateFormatter = (config) => {
154
188
  getSupportedLocales,
155
189
  getCurrentLocale: () => currentLocale,
156
190
  setLocale: async (locale) => {
157
- assertSupportedLocale(locale);
158
- await ensureLocaleLoaded(locale);
159
- currentLocale = locale;
191
+ const resolvedLocale = resolveLocaleOrThrow(locale);
192
+ await ensureLocaleLoaded(resolvedLocale);
193
+ currentLocale = resolvedLocale;
160
194
  },
161
195
  ready
162
196
  };
@@ -166,7 +200,9 @@ export {
166
200
  createDateFormatter,
167
201
  getDate,
168
202
  getSupportedLocales,
203
+ isSupportedLocale,
169
204
  isValidDate,
170
- parseDate
205
+ parseDate,
206
+ resolveLocale
171
207
  };
172
208
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/date.ts","../src/core/locales.ts"],"sourcesContent":["import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, isSupportedLocale, SUPPORTED_LOCALES, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: SupportedLocale\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: SupportedLocale\n strict?: boolean\n invalid?: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: SupportedLocale) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): Required<DateFormatterConfig> => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n return props?.locale ?? currentLocale\n}\n\nconst getHelperLocale = <T extends { locale?: SupportedLocale }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n return props?.locale ?? config?.locale ?? DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => Required<DateFormatterConfig>) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => Required<DateFormatterConfig>) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction assertSupportedLocale(locale: string): asserts locale is SupportedLocale {\n if (!isSupportedLocale(locale)) {\n throw new Error(`Unsupported locale: ${locale}`)\n }\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ?? DEFAULT_LOCALE\n\n const getConfig = (): Required<DateFormatterConfig> => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: SupportedLocale) => {\n assertSupportedLocale(locale)\n await ensureLocaleLoaded(locale)\n currentLocale = locale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nexport const isSupportedLocale = (locale: string): locale is SupportedLocale => {\n return SUPPORTED_LOCALES.includes(locale as SupportedLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate"]}
1
+ {"version":3,"sources":["../src/core/date.ts","../src/core/locales.ts"],"sourcesContent":["import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, resolveLocale, SUPPORTED_LOCALES, type LocaleInput, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: LocaleInput\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: LocaleInput\n strict?: boolean\n invalid?: string\n}\n\ntype ResolvedDateFormatterConfig = {\n locale: SupportedLocale\n strict: boolean\n invalid: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: LocaleInput) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): ResolvedDateFormatterConfig => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n if (!props?.locale) {\n return currentLocale\n }\n\n return resolveLocaleOrThrow(props.locale)\n}\n\nconst getHelperLocale = <T extends { locale?: LocaleInput }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n if (props?.locale) {\n return resolveLocaleOrThrow(props.locale)\n }\n\n if (config?.locale) {\n return resolveLocaleOrThrow(config.locale)\n }\n\n return DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction resolveLocaleOrThrow(locale: LocaleInput): SupportedLocale {\n const resolvedLocale = resolveLocale(locale)\n\n if (!resolvedLocale) {\n throw new Error(\n `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`\n )\n }\n\n return resolvedLocale\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE\n\n const getConfig = (): ResolvedDateFormatterConfig => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: LocaleInput) => {\n const resolvedLocale = resolveLocaleOrThrow(locale)\n\n await ensureLocaleLoaded(resolvedLocale)\n currentLocale = resolvedLocale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\nexport type LocaleInput = string\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nconst normalizeLocale = (locale: string): string => {\n return locale.trim().toLowerCase().replace(/_/g, '-')\n}\n\nconst asSupportedLocale = (locale: string): SupportedLocale | null => {\n if (!SUPPORTED_LOCALES.includes(locale as SupportedLocale)) {\n return null\n }\n\n return locale as SupportedLocale\n}\n\nexport const isSupportedLocale = (locale: string): boolean => {\n return resolveLocale(locale) !== null\n}\n\nexport const resolveLocale = (locale: LocaleInput): SupportedLocale | null => {\n const normalizedLocale = normalizeLocale(locale)\n const exactLocale = asSupportedLocale(normalizedLocale)\n\n if (exactLocale) {\n return exactLocale\n }\n\n const [baseLocale] = normalizedLocale.split('-')\n\n if (!baseLocale) {\n return null\n }\n\n return asSupportedLocale(baseLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate"]}
@@ -1,4 +1,4 @@
1
- import { DateFormatterConfig, GetDateOptions, DateParsingOptions, ParseDateResult, SupportedLocale } from '../index.js';
1
+ import { DateFormatterConfig, GetDateOptions, DateParsingOptions, ParseDateResult, SupportedLocale, LocaleInput } from '../index.js';
2
2
 
3
3
  type UseDateFormatterOptions = DateFormatterConfig;
4
4
  declare const useDateFormatter: (options?: UseDateFormatterOptions) => {
@@ -9,7 +9,7 @@ declare const useDateFormatter: (options?: UseDateFormatterOptions) => {
9
9
  isValidDate: (props: DateParsingOptions) => boolean;
10
10
  getSupportedLocales: () => readonly SupportedLocale[];
11
11
  ready: Promise<void>;
12
- setLocale: (nextLocale: SupportedLocale) => Promise<void>;
12
+ setLocale: (nextLocale: LocaleInput) => Promise<void>;
13
13
  };
14
14
 
15
15
  export { type UseDateFormatterOptions, useDateFormatter };
@@ -28,8 +28,26 @@ var localeLoaders = {
28
28
  it: () => import("dayjs/locale/it.js"),
29
29
  ja: () => import("dayjs/locale/ja.js")
30
30
  };
31
- var isSupportedLocale = (locale) => {
32
- return SUPPORTED_LOCALES.includes(locale);
31
+ var normalizeLocale = (locale) => {
32
+ return locale.trim().toLowerCase().replace(/_/g, "-");
33
+ };
34
+ var asSupportedLocale = (locale) => {
35
+ if (!SUPPORTED_LOCALES.includes(locale)) {
36
+ return null;
37
+ }
38
+ return locale;
39
+ };
40
+ var resolveLocale = (locale) => {
41
+ const normalizedLocale = normalizeLocale(locale);
42
+ const exactLocale = asSupportedLocale(normalizedLocale);
43
+ if (exactLocale) {
44
+ return exactLocale;
45
+ }
46
+ const [baseLocale] = normalizedLocale.split("-");
47
+ if (!baseLocale) {
48
+ return null;
49
+ }
50
+ return asSupportedLocale(baseLocale);
33
51
  };
34
52
  var ensureLocaleLoaded = async (locale) => {
35
53
  const load = localeLoaders[locale];
@@ -55,7 +73,10 @@ var getInvalidDateText = (config, props) => {
55
73
  return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE;
56
74
  };
57
75
  var getTargetLocale = (currentLocale, props) => {
58
- return props?.locale ?? currentLocale;
76
+ if (!props?.locale) {
77
+ return currentLocale;
78
+ }
79
+ return resolveLocaleOrThrow(props.locale);
59
80
  };
60
81
  var parseDateValue = (value, input, locale, strict) => {
61
82
  if (!input) {
@@ -118,14 +139,18 @@ var createFormatterGetDate = (getConfig) => {
118
139
  return parsed.format(output);
119
140
  };
120
141
  };
121
- function assertSupportedLocale(locale) {
122
- if (!isSupportedLocale(locale)) {
123
- throw new Error(`Unsupported locale: ${locale}`);
142
+ function resolveLocaleOrThrow(locale) {
143
+ const resolvedLocale = resolveLocale(locale);
144
+ if (!resolvedLocale) {
145
+ throw new Error(
146
+ `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`
147
+ );
124
148
  }
149
+ return resolvedLocale;
125
150
  }
126
151
  var getSupportedLocales = () => SUPPORTED_LOCALES;
127
152
  var createDateFormatter = (config) => {
128
- let currentLocale = config?.locale ?? DEFAULT_LOCALE;
153
+ let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE;
129
154
  const getConfig = () => createResolvedConfig(currentLocale, config);
130
155
  const ready = ensureLocaleLoaded(currentLocale);
131
156
  const parseDate2 = createFormatterParseDate(getConfig);
@@ -136,9 +161,9 @@ var createDateFormatter = (config) => {
136
161
  getSupportedLocales,
137
162
  getCurrentLocale: () => currentLocale,
138
163
  setLocale: async (locale) => {
139
- assertSupportedLocale(locale);
140
- await ensureLocaleLoaded(locale);
141
- currentLocale = locale;
164
+ const resolvedLocale = resolveLocaleOrThrow(locale);
165
+ await ensureLocaleLoaded(resolvedLocale);
166
+ currentLocale = resolvedLocale;
142
167
  },
143
168
  ready
144
169
  };
@@ -158,7 +183,7 @@ var useDateFormatter = (options) => {
158
183
  ready: formatterRef.current.ready,
159
184
  setLocale: async (nextLocale) => {
160
185
  await formatterRef.current.setLocale(nextLocale);
161
- setLocaleState(nextLocale);
186
+ setLocaleState(formatterRef.current.getCurrentLocale());
162
187
  }
163
188
  };
164
189
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/index.ts","../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import { useRef, useState } from 'react'\n\nimport {\n createDateFormatter,\n getSupportedLocales,\n type DateFormatterConfig,\n type DateParsingOptions,\n type GetDateOptions,\n type SupportedLocale\n} from '../index.js'\n\nexport type UseDateFormatterOptions = DateFormatterConfig\n\nexport const useDateFormatter = (options?: UseDateFormatterOptions) => {\n const formatterRef = useRef(createDateFormatter(options))\n const [locale, setLocaleState] = useState<SupportedLocale>(formatterRef.current.getCurrentLocale())\n\n return {\n locale,\n currentLocale: locale,\n getDate: (props?: GetDateOptions) => formatterRef.current.getDate(props),\n parseDate: (props: DateParsingOptions) => formatterRef.current.parseDate(props),\n isValidDate: (props: DateParsingOptions) => formatterRef.current.isValidDate(props),\n getSupportedLocales,\n ready: formatterRef.current.ready,\n setLocale: async (nextLocale: SupportedLocale) => {\n await formatterRef.current.setLocale(nextLocale)\n setLocaleState(nextLocale)\n }\n }\n}\n","import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, isSupportedLocale, SUPPORTED_LOCALES, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: SupportedLocale\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: SupportedLocale\n strict?: boolean\n invalid?: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: SupportedLocale) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): Required<DateFormatterConfig> => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n return props?.locale ?? currentLocale\n}\n\nconst getHelperLocale = <T extends { locale?: SupportedLocale }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n return props?.locale ?? config?.locale ?? DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => Required<DateFormatterConfig>) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => Required<DateFormatterConfig>) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction assertSupportedLocale(locale: string): asserts locale is SupportedLocale {\n if (!isSupportedLocale(locale)) {\n throw new Error(`Unsupported locale: ${locale}`)\n }\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ?? DEFAULT_LOCALE\n\n const getConfig = (): Required<DateFormatterConfig> => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: SupportedLocale) => {\n assertSupportedLocale(locale)\n await ensureLocaleLoaded(locale)\n currentLocale = locale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nexport const isSupportedLocale = (locale: string): locale is SupportedLocale => {\n return SUPPORTED_LOCALES.includes(locale as SupportedLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate","parseDate"]}
1
+ {"version":3,"sources":["../../src/react/index.ts","../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import { useRef, useState } from 'react'\n\nimport {\n createDateFormatter,\n getSupportedLocales,\n type DateFormatterConfig,\n type DateParsingOptions,\n type GetDateOptions,\n type LocaleInput,\n type SupportedLocale\n} from '../index.js'\n\nexport type UseDateFormatterOptions = DateFormatterConfig\n\nexport const useDateFormatter = (options?: UseDateFormatterOptions) => {\n const formatterRef = useRef(createDateFormatter(options))\n const [locale, setLocaleState] = useState<SupportedLocale>(formatterRef.current.getCurrentLocale())\n\n return {\n locale,\n currentLocale: locale,\n getDate: (props?: GetDateOptions) => formatterRef.current.getDate(props),\n parseDate: (props: DateParsingOptions) => formatterRef.current.parseDate(props),\n isValidDate: (props: DateParsingOptions) => formatterRef.current.isValidDate(props),\n getSupportedLocales,\n ready: formatterRef.current.ready,\n setLocale: async (nextLocale: LocaleInput) => {\n await formatterRef.current.setLocale(nextLocale)\n setLocaleState(formatterRef.current.getCurrentLocale())\n }\n }\n}\n","import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, resolveLocale, SUPPORTED_LOCALES, type LocaleInput, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: LocaleInput\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: LocaleInput\n strict?: boolean\n invalid?: string\n}\n\ntype ResolvedDateFormatterConfig = {\n locale: SupportedLocale\n strict: boolean\n invalid: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: LocaleInput) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): ResolvedDateFormatterConfig => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n if (!props?.locale) {\n return currentLocale\n }\n\n return resolveLocaleOrThrow(props.locale)\n}\n\nconst getHelperLocale = <T extends { locale?: LocaleInput }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n if (props?.locale) {\n return resolveLocaleOrThrow(props.locale)\n }\n\n if (config?.locale) {\n return resolveLocaleOrThrow(config.locale)\n }\n\n return DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction resolveLocaleOrThrow(locale: LocaleInput): SupportedLocale {\n const resolvedLocale = resolveLocale(locale)\n\n if (!resolvedLocale) {\n throw new Error(\n `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`\n )\n }\n\n return resolvedLocale\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE\n\n const getConfig = (): ResolvedDateFormatterConfig => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: LocaleInput) => {\n const resolvedLocale = resolveLocaleOrThrow(locale)\n\n await ensureLocaleLoaded(resolvedLocale)\n currentLocale = resolvedLocale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\nexport type LocaleInput = string\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nconst normalizeLocale = (locale: string): string => {\n return locale.trim().toLowerCase().replace(/_/g, '-')\n}\n\nconst asSupportedLocale = (locale: string): SupportedLocale | null => {\n if (!SUPPORTED_LOCALES.includes(locale as SupportedLocale)) {\n return null\n }\n\n return locale as SupportedLocale\n}\n\nexport const isSupportedLocale = (locale: string): boolean => {\n return resolveLocale(locale) !== null\n}\n\nexport const resolveLocale = (locale: LocaleInput): SupportedLocale | null => {\n const normalizedLocale = normalizeLocale(locale)\n const exactLocale = asSupportedLocale(normalizedLocale)\n\n if (exactLocale) {\n return exactLocale\n }\n\n const [baseLocale] = normalizedLocale.split('-')\n\n if (!baseLocale) {\n return null\n }\n\n return asSupportedLocale(baseLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate","parseDate"]}
@@ -1,4 +1,4 @@
1
- import { DateFormatterConfig, GetDateOptions, DateParsingOptions, ParseDateResult, SupportedLocale } from '../index.js';
1
+ import { DateFormatterConfig, GetDateOptions, DateParsingOptions, ParseDateResult, SupportedLocale, LocaleInput } from '../index.js';
2
2
  import * as svelte_store from 'svelte/store';
3
3
 
4
4
  type CreateDateFormatterStoreOptions = DateFormatterConfig;
@@ -12,7 +12,7 @@ declare const createDateFormatterStore: (options?: CreateDateFormatterStoreOptio
12
12
  isValidDate: (props: DateParsingOptions) => boolean;
13
13
  getSupportedLocales: () => readonly SupportedLocale[];
14
14
  ready: Promise<void>;
15
- setLocale: (nextLocale: SupportedLocale) => Promise<void>;
15
+ setLocale: (nextLocale: LocaleInput) => Promise<void>;
16
16
  getLocale: () => "en" | "es" | "es-mx" | "fr" | "pt" | "pt-br" | "de" | "it" | "ja";
17
17
  };
18
18
 
@@ -28,8 +28,26 @@ var localeLoaders = {
28
28
  it: () => import("dayjs/locale/it.js"),
29
29
  ja: () => import("dayjs/locale/ja.js")
30
30
  };
31
- var isSupportedLocale = (locale) => {
32
- return SUPPORTED_LOCALES.includes(locale);
31
+ var normalizeLocale = (locale) => {
32
+ return locale.trim().toLowerCase().replace(/_/g, "-");
33
+ };
34
+ var asSupportedLocale = (locale) => {
35
+ if (!SUPPORTED_LOCALES.includes(locale)) {
36
+ return null;
37
+ }
38
+ return locale;
39
+ };
40
+ var resolveLocale = (locale) => {
41
+ const normalizedLocale = normalizeLocale(locale);
42
+ const exactLocale = asSupportedLocale(normalizedLocale);
43
+ if (exactLocale) {
44
+ return exactLocale;
45
+ }
46
+ const [baseLocale] = normalizedLocale.split("-");
47
+ if (!baseLocale) {
48
+ return null;
49
+ }
50
+ return asSupportedLocale(baseLocale);
33
51
  };
34
52
  var ensureLocaleLoaded = async (locale) => {
35
53
  const load = localeLoaders[locale];
@@ -55,7 +73,10 @@ var getInvalidDateText = (config, props) => {
55
73
  return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE;
56
74
  };
57
75
  var getTargetLocale = (currentLocale, props) => {
58
- return props?.locale ?? currentLocale;
76
+ if (!props?.locale) {
77
+ return currentLocale;
78
+ }
79
+ return resolveLocaleOrThrow(props.locale);
59
80
  };
60
81
  var parseDateValue = (value, input, locale, strict) => {
61
82
  if (!input) {
@@ -118,14 +139,18 @@ var createFormatterGetDate = (getConfig) => {
118
139
  return parsed.format(output);
119
140
  };
120
141
  };
121
- function assertSupportedLocale(locale) {
122
- if (!isSupportedLocale(locale)) {
123
- throw new Error(`Unsupported locale: ${locale}`);
142
+ function resolveLocaleOrThrow(locale) {
143
+ const resolvedLocale = resolveLocale(locale);
144
+ if (!resolvedLocale) {
145
+ throw new Error(
146
+ `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`
147
+ );
124
148
  }
149
+ return resolvedLocale;
125
150
  }
126
151
  var getSupportedLocales = () => SUPPORTED_LOCALES;
127
152
  var createDateFormatter = (config) => {
128
- let currentLocale = config?.locale ?? DEFAULT_LOCALE;
153
+ let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE;
129
154
  const getConfig = () => createResolvedConfig(currentLocale, config);
130
155
  const ready = ensureLocaleLoaded(currentLocale);
131
156
  const parseDate2 = createFormatterParseDate(getConfig);
@@ -136,9 +161,9 @@ var createDateFormatter = (config) => {
136
161
  getSupportedLocales,
137
162
  getCurrentLocale: () => currentLocale,
138
163
  setLocale: async (locale) => {
139
- assertSupportedLocale(locale);
140
- await ensureLocaleLoaded(locale);
141
- currentLocale = locale;
164
+ const resolvedLocale = resolveLocaleOrThrow(locale);
165
+ await ensureLocaleLoaded(resolvedLocale);
166
+ currentLocale = resolvedLocale;
142
167
  },
143
168
  ready
144
169
  };
@@ -160,7 +185,7 @@ var createDateFormatterStore = (options) => {
160
185
  ready: formatter.ready,
161
186
  setLocale: async (nextLocale) => {
162
187
  await formatter.setLocale(nextLocale);
163
- locale.set(nextLocale);
188
+ locale.set(formatter.getCurrentLocale());
164
189
  },
165
190
  getLocale: () => get(locale)
166
191
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/svelte/index.ts","../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import { get, writable } from 'svelte/store'\n\nimport {\n createDateFormatter,\n getSupportedLocales,\n type DateFormatterConfig,\n type DateParsingOptions,\n type GetDateOptions,\n type SupportedLocale\n} from '../index.js'\n\nexport type CreateDateFormatterStoreOptions = DateFormatterConfig\n\nexport const createDateFormatterStore = (options?: CreateDateFormatterStoreOptions) => {\n const formatter = createDateFormatter(options)\n const locale = writable<SupportedLocale>(formatter.getCurrentLocale())\n\n return {\n locale: {\n subscribe: locale.subscribe\n },\n currentLocale: () => get(locale),\n getDate: (props?: GetDateOptions) => formatter.getDate(props),\n parseDate: (props: DateParsingOptions) => formatter.parseDate(props),\n isValidDate: (props: DateParsingOptions) => formatter.isValidDate(props),\n getSupportedLocales,\n ready: formatter.ready,\n setLocale: async (nextLocale: SupportedLocale) => {\n await formatter.setLocale(nextLocale)\n locale.set(nextLocale)\n },\n getLocale: () => get(locale)\n }\n}\n","import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, isSupportedLocale, SUPPORTED_LOCALES, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: SupportedLocale\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: SupportedLocale\n strict?: boolean\n invalid?: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: SupportedLocale) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): Required<DateFormatterConfig> => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n return props?.locale ?? currentLocale\n}\n\nconst getHelperLocale = <T extends { locale?: SupportedLocale }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n return props?.locale ?? config?.locale ?? DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => Required<DateFormatterConfig>) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => Required<DateFormatterConfig>) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction assertSupportedLocale(locale: string): asserts locale is SupportedLocale {\n if (!isSupportedLocale(locale)) {\n throw new Error(`Unsupported locale: ${locale}`)\n }\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ?? DEFAULT_LOCALE\n\n const getConfig = (): Required<DateFormatterConfig> => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: SupportedLocale) => {\n assertSupportedLocale(locale)\n await ensureLocaleLoaded(locale)\n currentLocale = locale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nexport const isSupportedLocale = (locale: string): locale is SupportedLocale => {\n return SUPPORTED_LOCALES.includes(locale as SupportedLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate","parseDate"]}
1
+ {"version":3,"sources":["../../src/svelte/index.ts","../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import { get, writable } from 'svelte/store'\n\nimport {\n createDateFormatter,\n getSupportedLocales,\n type DateFormatterConfig,\n type DateParsingOptions,\n type GetDateOptions,\n type LocaleInput,\n type SupportedLocale\n} from '../index.js'\n\nexport type CreateDateFormatterStoreOptions = DateFormatterConfig\n\nexport const createDateFormatterStore = (options?: CreateDateFormatterStoreOptions) => {\n const formatter = createDateFormatter(options)\n const locale = writable<SupportedLocale>(formatter.getCurrentLocale())\n\n return {\n locale: {\n subscribe: locale.subscribe\n },\n currentLocale: () => get(locale),\n getDate: (props?: GetDateOptions) => formatter.getDate(props),\n parseDate: (props: DateParsingOptions) => formatter.parseDate(props),\n isValidDate: (props: DateParsingOptions) => formatter.isValidDate(props),\n getSupportedLocales,\n ready: formatter.ready,\n setLocale: async (nextLocale: LocaleInput) => {\n await formatter.setLocale(nextLocale)\n locale.set(formatter.getCurrentLocale())\n },\n getLocale: () => get(locale)\n }\n}\n","import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, resolveLocale, SUPPORTED_LOCALES, type LocaleInput, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: LocaleInput\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: LocaleInput\n strict?: boolean\n invalid?: string\n}\n\ntype ResolvedDateFormatterConfig = {\n locale: SupportedLocale\n strict: boolean\n invalid: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: LocaleInput) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): ResolvedDateFormatterConfig => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n if (!props?.locale) {\n return currentLocale\n }\n\n return resolveLocaleOrThrow(props.locale)\n}\n\nconst getHelperLocale = <T extends { locale?: LocaleInput }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n if (props?.locale) {\n return resolveLocaleOrThrow(props.locale)\n }\n\n if (config?.locale) {\n return resolveLocaleOrThrow(config.locale)\n }\n\n return DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction resolveLocaleOrThrow(locale: LocaleInput): SupportedLocale {\n const resolvedLocale = resolveLocale(locale)\n\n if (!resolvedLocale) {\n throw new Error(\n `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`\n )\n }\n\n return resolvedLocale\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE\n\n const getConfig = (): ResolvedDateFormatterConfig => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: LocaleInput) => {\n const resolvedLocale = resolveLocaleOrThrow(locale)\n\n await ensureLocaleLoaded(resolvedLocale)\n currentLocale = resolvedLocale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\nexport type LocaleInput = string\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nconst normalizeLocale = (locale: string): string => {\n return locale.trim().toLowerCase().replace(/_/g, '-')\n}\n\nconst asSupportedLocale = (locale: string): SupportedLocale | null => {\n if (!SUPPORTED_LOCALES.includes(locale as SupportedLocale)) {\n return null\n }\n\n return locale as SupportedLocale\n}\n\nexport const isSupportedLocale = (locale: string): boolean => {\n return resolveLocale(locale) !== null\n}\n\nexport const resolveLocale = (locale: LocaleInput): SupportedLocale | null => {\n const normalizedLocale = normalizeLocale(locale)\n const exactLocale = asSupportedLocale(normalizedLocale)\n\n if (exactLocale) {\n return exactLocale\n }\n\n const [baseLocale] = normalizedLocale.split('-')\n\n if (!baseLocale) {\n return null\n }\n\n return asSupportedLocale(baseLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate","parseDate"]}
@@ -1 +1 @@
1
- export { DateFormatter, DateFormatterConfig, DateParsingOptions, DateValue, GetDateOptions, ParseDateFailure, ParseDateResult, ParseDateSuccess, SUPPORTED_LOCALES, SupportedLocale, createDateFormatter, getDate, getSupportedLocales, isValidDate, parseDate } from '../index.js';
1
+ export { DateFormatter, DateFormatterConfig, DateParsingOptions, DateValue, GetDateOptions, LocaleInput, ParseDateFailure, ParseDateResult, ParseDateSuccess, SUPPORTED_LOCALES, SupportedLocale, createDateFormatter, getDate, getSupportedLocales, isSupportedLocale, isValidDate, parseDate, resolveLocale } from '../index.js';
@@ -25,8 +25,29 @@ var localeLoaders = {
25
25
  it: () => import("dayjs/locale/it.js"),
26
26
  ja: () => import("dayjs/locale/ja.js")
27
27
  };
28
+ var normalizeLocale = (locale) => {
29
+ return locale.trim().toLowerCase().replace(/_/g, "-");
30
+ };
31
+ var asSupportedLocale = (locale) => {
32
+ if (!SUPPORTED_LOCALES.includes(locale)) {
33
+ return null;
34
+ }
35
+ return locale;
36
+ };
28
37
  var isSupportedLocale = (locale) => {
29
- return SUPPORTED_LOCALES.includes(locale);
38
+ return resolveLocale(locale) !== null;
39
+ };
40
+ var resolveLocale = (locale) => {
41
+ const normalizedLocale = normalizeLocale(locale);
42
+ const exactLocale = asSupportedLocale(normalizedLocale);
43
+ if (exactLocale) {
44
+ return exactLocale;
45
+ }
46
+ const [baseLocale] = normalizedLocale.split("-");
47
+ if (!baseLocale) {
48
+ return null;
49
+ }
50
+ return asSupportedLocale(baseLocale);
30
51
  };
31
52
  var ensureLocaleLoaded = async (locale) => {
32
53
  const load = localeLoaders[locale];
@@ -52,10 +73,19 @@ var getInvalidDateText = (config, props) => {
52
73
  return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE;
53
74
  };
54
75
  var getTargetLocale = (currentLocale, props) => {
55
- return props?.locale ?? currentLocale;
76
+ if (!props?.locale) {
77
+ return currentLocale;
78
+ }
79
+ return resolveLocaleOrThrow(props.locale);
56
80
  };
57
81
  var getHelperLocale = (config, props) => {
58
- return props?.locale ?? config?.locale ?? DEFAULT_LOCALE;
82
+ if (props?.locale) {
83
+ return resolveLocaleOrThrow(props.locale);
84
+ }
85
+ if (config?.locale) {
86
+ return resolveLocaleOrThrow(config.locale);
87
+ }
88
+ return DEFAULT_LOCALE;
59
89
  };
60
90
  var parseDateValue = (value, input, locale, strict) => {
61
91
  if (!input) {
@@ -118,10 +148,14 @@ var createFormatterGetDate = (getConfig) => {
118
148
  return parsed.format(output);
119
149
  };
120
150
  };
121
- function assertSupportedLocale(locale) {
122
- if (!isSupportedLocale(locale)) {
123
- throw new Error(`Unsupported locale: ${locale}`);
151
+ function resolveLocaleOrThrow(locale) {
152
+ const resolvedLocale = resolveLocale(locale);
153
+ if (!resolvedLocale) {
154
+ throw new Error(
155
+ `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`
156
+ );
124
157
  }
158
+ return resolvedLocale;
125
159
  }
126
160
  var getSupportedLocales = () => SUPPORTED_LOCALES;
127
161
  var getDate = async (props, config) => {
@@ -143,7 +177,7 @@ var isValidDate = async (props, config) => {
143
177
  return formatter.isValidDate(props);
144
178
  };
145
179
  var createDateFormatter = (config) => {
146
- let currentLocale = config?.locale ?? DEFAULT_LOCALE;
180
+ let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE;
147
181
  const getConfig = () => createResolvedConfig(currentLocale, config);
148
182
  const ready = ensureLocaleLoaded(currentLocale);
149
183
  const parseDate2 = createFormatterParseDate(getConfig);
@@ -154,9 +188,9 @@ var createDateFormatter = (config) => {
154
188
  getSupportedLocales,
155
189
  getCurrentLocale: () => currentLocale,
156
190
  setLocale: async (locale) => {
157
- assertSupportedLocale(locale);
158
- await ensureLocaleLoaded(locale);
159
- currentLocale = locale;
191
+ const resolvedLocale = resolveLocaleOrThrow(locale);
192
+ await ensureLocaleLoaded(resolvedLocale);
193
+ currentLocale = resolvedLocale;
160
194
  },
161
195
  ready
162
196
  };
@@ -166,7 +200,9 @@ export {
166
200
  createDateFormatter,
167
201
  getDate,
168
202
  getSupportedLocales,
203
+ isSupportedLocale,
169
204
  isValidDate,
170
- parseDate
205
+ parseDate,
206
+ resolveLocale
171
207
  };
172
208
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, isSupportedLocale, SUPPORTED_LOCALES, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: SupportedLocale\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: SupportedLocale\n strict?: boolean\n invalid?: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: SupportedLocale) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): Required<DateFormatterConfig> => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n return props?.locale ?? currentLocale\n}\n\nconst getHelperLocale = <T extends { locale?: SupportedLocale }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n return props?.locale ?? config?.locale ?? DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => Required<DateFormatterConfig>) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => Required<DateFormatterConfig>) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction assertSupportedLocale(locale: string): asserts locale is SupportedLocale {\n if (!isSupportedLocale(locale)) {\n throw new Error(`Unsupported locale: ${locale}`)\n }\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ?? DEFAULT_LOCALE\n\n const getConfig = (): Required<DateFormatterConfig> => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: SupportedLocale) => {\n assertSupportedLocale(locale)\n await ensureLocaleLoaded(locale)\n currentLocale = locale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nexport const isSupportedLocale = (locale: string): locale is SupportedLocale => {\n return SUPPORTED_LOCALES.includes(locale as SupportedLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate"]}
1
+ {"version":3,"sources":["../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, resolveLocale, SUPPORTED_LOCALES, type LocaleInput, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: LocaleInput\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: LocaleInput\n strict?: boolean\n invalid?: string\n}\n\ntype ResolvedDateFormatterConfig = {\n locale: SupportedLocale\n strict: boolean\n invalid: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: LocaleInput) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): ResolvedDateFormatterConfig => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n if (!props?.locale) {\n return currentLocale\n }\n\n return resolveLocaleOrThrow(props.locale)\n}\n\nconst getHelperLocale = <T extends { locale?: LocaleInput }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n if (props?.locale) {\n return resolveLocaleOrThrow(props.locale)\n }\n\n if (config?.locale) {\n return resolveLocaleOrThrow(config.locale)\n }\n\n return DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction resolveLocaleOrThrow(locale: LocaleInput): SupportedLocale {\n const resolvedLocale = resolveLocale(locale)\n\n if (!resolvedLocale) {\n throw new Error(\n `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`\n )\n }\n\n return resolvedLocale\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE\n\n const getConfig = (): ResolvedDateFormatterConfig => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: LocaleInput) => {\n const resolvedLocale = resolveLocaleOrThrow(locale)\n\n await ensureLocaleLoaded(resolvedLocale)\n currentLocale = resolvedLocale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\nexport type LocaleInput = string\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nconst normalizeLocale = (locale: string): string => {\n return locale.trim().toLowerCase().replace(/_/g, '-')\n}\n\nconst asSupportedLocale = (locale: string): SupportedLocale | null => {\n if (!SUPPORTED_LOCALES.includes(locale as SupportedLocale)) {\n return null\n }\n\n return locale as SupportedLocale\n}\n\nexport const isSupportedLocale = (locale: string): boolean => {\n return resolveLocale(locale) !== null\n}\n\nexport const resolveLocale = (locale: LocaleInput): SupportedLocale | null => {\n const normalizedLocale = normalizeLocale(locale)\n const exactLocale = asSupportedLocale(normalizedLocale)\n\n if (exactLocale) {\n return exactLocale\n }\n\n const [baseLocale] = normalizedLocale.split('-')\n\n if (!baseLocale) {\n return null\n }\n\n return asSupportedLocale(baseLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate"]}
@@ -1,4 +1,4 @@
1
- import { DateFormatterConfig, GetDateOptions, DateParsingOptions, ParseDateResult, SupportedLocale } from '../index.js';
1
+ import { DateFormatterConfig, GetDateOptions, DateParsingOptions, ParseDateResult, SupportedLocale, LocaleInput } from '../index.js';
2
2
  import * as vue from 'vue';
3
3
 
4
4
  type UseDateFormatterOptions = DateFormatterConfig;
@@ -10,7 +10,7 @@ declare const useDateFormatter: (options?: UseDateFormatterOptions) => {
10
10
  isValidDate: (props: DateParsingOptions) => boolean;
11
11
  getSupportedLocales: () => readonly SupportedLocale[];
12
12
  ready: Promise<void>;
13
- setLocale: (nextLocale: SupportedLocale) => Promise<void>;
13
+ setLocale: (nextLocale: LocaleInput) => Promise<void>;
14
14
  };
15
15
 
16
16
  export { type UseDateFormatterOptions, useDateFormatter };
package/dist/vue/index.js CHANGED
@@ -28,8 +28,26 @@ var localeLoaders = {
28
28
  it: () => import("dayjs/locale/it.js"),
29
29
  ja: () => import("dayjs/locale/ja.js")
30
30
  };
31
- var isSupportedLocale = (locale) => {
32
- return SUPPORTED_LOCALES.includes(locale);
31
+ var normalizeLocale = (locale) => {
32
+ return locale.trim().toLowerCase().replace(/_/g, "-");
33
+ };
34
+ var asSupportedLocale = (locale) => {
35
+ if (!SUPPORTED_LOCALES.includes(locale)) {
36
+ return null;
37
+ }
38
+ return locale;
39
+ };
40
+ var resolveLocale = (locale) => {
41
+ const normalizedLocale = normalizeLocale(locale);
42
+ const exactLocale = asSupportedLocale(normalizedLocale);
43
+ if (exactLocale) {
44
+ return exactLocale;
45
+ }
46
+ const [baseLocale] = normalizedLocale.split("-");
47
+ if (!baseLocale) {
48
+ return null;
49
+ }
50
+ return asSupportedLocale(baseLocale);
33
51
  };
34
52
  var ensureLocaleLoaded = async (locale) => {
35
53
  const load = localeLoaders[locale];
@@ -55,7 +73,10 @@ var getInvalidDateText = (config, props) => {
55
73
  return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE;
56
74
  };
57
75
  var getTargetLocale = (currentLocale, props) => {
58
- return props?.locale ?? currentLocale;
76
+ if (!props?.locale) {
77
+ return currentLocale;
78
+ }
79
+ return resolveLocaleOrThrow(props.locale);
59
80
  };
60
81
  var parseDateValue = (value, input, locale, strict) => {
61
82
  if (!input) {
@@ -118,14 +139,18 @@ var createFormatterGetDate = (getConfig) => {
118
139
  return parsed.format(output);
119
140
  };
120
141
  };
121
- function assertSupportedLocale(locale) {
122
- if (!isSupportedLocale(locale)) {
123
- throw new Error(`Unsupported locale: ${locale}`);
142
+ function resolveLocaleOrThrow(locale) {
143
+ const resolvedLocale = resolveLocale(locale);
144
+ if (!resolvedLocale) {
145
+ throw new Error(
146
+ `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`
147
+ );
124
148
  }
149
+ return resolvedLocale;
125
150
  }
126
151
  var getSupportedLocales = () => SUPPORTED_LOCALES;
127
152
  var createDateFormatter = (config) => {
128
- let currentLocale = config?.locale ?? DEFAULT_LOCALE;
153
+ let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE;
129
154
  const getConfig = () => createResolvedConfig(currentLocale, config);
130
155
  const ready = ensureLocaleLoaded(currentLocale);
131
156
  const parseDate2 = createFormatterParseDate(getConfig);
@@ -136,9 +161,9 @@ var createDateFormatter = (config) => {
136
161
  getSupportedLocales,
137
162
  getCurrentLocale: () => currentLocale,
138
163
  setLocale: async (locale) => {
139
- assertSupportedLocale(locale);
140
- await ensureLocaleLoaded(locale);
141
- currentLocale = locale;
164
+ const resolvedLocale = resolveLocaleOrThrow(locale);
165
+ await ensureLocaleLoaded(resolvedLocale);
166
+ currentLocale = resolvedLocale;
142
167
  },
143
168
  ready
144
169
  };
@@ -150,7 +175,7 @@ var useDateFormatter = (options) => {
150
175
  const locale = ref(formatter.getCurrentLocale());
151
176
  const setLocale = async (nextLocale) => {
152
177
  await formatter.setLocale(nextLocale);
153
- locale.value = nextLocale;
178
+ locale.value = formatter.getCurrentLocale();
154
179
  };
155
180
  return {
156
181
  locale,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vue/index.ts","../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import { computed, ref } from 'vue'\n\nimport {\n createDateFormatter,\n getSupportedLocales,\n type DateFormatterConfig,\n type DateParsingOptions,\n type GetDateOptions,\n type SupportedLocale\n} from '../index.js'\n\nexport type UseDateFormatterOptions = DateFormatterConfig\n\nexport const useDateFormatter = (options?: UseDateFormatterOptions) => {\n const formatter = createDateFormatter(options)\n const locale = ref<SupportedLocale>(formatter.getCurrentLocale())\n\n const setLocale = async (nextLocale: SupportedLocale) => {\n await formatter.setLocale(nextLocale)\n locale.value = nextLocale\n }\n\n return {\n locale,\n currentLocale: computed(() => locale.value),\n getDate: (props?: GetDateOptions) => formatter.getDate(props),\n parseDate: (props: DateParsingOptions) => formatter.parseDate(props),\n isValidDate: (props: DateParsingOptions) => formatter.isValidDate(props),\n getSupportedLocales,\n ready: formatter.ready,\n setLocale\n }\n}\n","import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, isSupportedLocale, SUPPORTED_LOCALES, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: SupportedLocale\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: SupportedLocale\n strict?: boolean\n invalid?: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: SupportedLocale) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): Required<DateFormatterConfig> => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n return props?.locale ?? currentLocale\n}\n\nconst getHelperLocale = <T extends { locale?: SupportedLocale }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n return props?.locale ?? config?.locale ?? DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => Required<DateFormatterConfig>) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => Required<DateFormatterConfig>) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction assertSupportedLocale(locale: string): asserts locale is SupportedLocale {\n if (!isSupportedLocale(locale)) {\n throw new Error(`Unsupported locale: ${locale}`)\n }\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ?? DEFAULT_LOCALE\n\n const getConfig = (): Required<DateFormatterConfig> => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: SupportedLocale) => {\n assertSupportedLocale(locale)\n await ensureLocaleLoaded(locale)\n currentLocale = locale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nexport const isSupportedLocale = (locale: string): locale is SupportedLocale => {\n return SUPPORTED_LOCALES.includes(locale as SupportedLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate","parseDate"]}
1
+ {"version":3,"sources":["../../src/vue/index.ts","../../src/core/date.ts","../../src/core/locales.ts"],"sourcesContent":["import { computed, ref } from 'vue'\n\nimport {\n createDateFormatter,\n getSupportedLocales,\n type DateFormatterConfig,\n type DateParsingOptions,\n type GetDateOptions,\n type LocaleInput,\n type SupportedLocale\n} from '../index.js'\n\nexport type UseDateFormatterOptions = DateFormatterConfig\n\nexport const useDateFormatter = (options?: UseDateFormatterOptions) => {\n const formatter = createDateFormatter(options)\n const locale = ref<SupportedLocale>(formatter.getCurrentLocale())\n\n const setLocale = async (nextLocale: LocaleInput) => {\n await formatter.setLocale(nextLocale)\n locale.value = formatter.getCurrentLocale()\n }\n\n return {\n locale,\n currentLocale: computed(() => locale.value),\n getDate: (props?: GetDateOptions) => formatter.getDate(props),\n parseDate: (props: DateParsingOptions) => formatter.parseDate(props),\n isValidDate: (props: DateParsingOptions) => formatter.isValidDate(props),\n getSupportedLocales,\n ready: formatter.ready,\n setLocale\n }\n}\n","import customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport dayjs from 'dayjs'\nimport type { Dayjs } from 'dayjs'\n\nimport { ensureLocaleLoaded, resolveLocale, SUPPORTED_LOCALES, type LocaleInput, type SupportedLocale } from './locales.js'\n\ndayjs.extend(customParseFormat)\ndayjs.locale('en')\n\nexport type DateValue = string | number | Date\n\ntype DateInputOptions = {\n input?: string | readonly string[]\n locale?: LocaleInput\n strict?: boolean\n}\n\nexport type DateParsingOptions = DateInputOptions & {\n date: DateValue\n}\n\nexport type GetDateOptions = DateInputOptions & {\n date?: DateValue\n output?: string\n invalid?: string\n}\n\nexport type DateFormatterConfig = {\n locale?: LocaleInput\n strict?: boolean\n invalid?: string\n}\n\ntype ResolvedDateFormatterConfig = {\n locale: SupportedLocale\n strict: boolean\n invalid: string\n}\n\nexport type DateFormatter = {\n getDate: (props?: GetDateOptions) => string\n parseDate: (props: DateParsingOptions) => ParseDateResult\n isValidDate: (props: DateParsingOptions) => boolean\n getSupportedLocales: () => readonly SupportedLocale[]\n getCurrentLocale: () => SupportedLocale\n setLocale: (locale: LocaleInput) => Promise<void>\n ready: Promise<void>\n}\n\nexport type ParseDateSuccess = {\n isValid: true\n locale: SupportedLocale\n date: Date\n iso: string\n timestamp: number\n format: (output?: string) => string\n}\n\nexport type ParseDateFailure = {\n isValid: false\n locale: SupportedLocale\n date: null\n iso: null\n timestamp: null\n error: string\n}\n\nexport type ParseDateResult = ParseDateSuccess | ParseDateFailure\n\nconst DEFAULT_FORMAT = 'YYYY-MM-DD'\nconst DEFAULT_LOCALE: SupportedLocale = 'en'\nconst DEFAULT_INVALID_DATE = 'Invalid Date'\nconst DEFAULT_STRICT = true\n\nconst createResolvedConfig = (\n locale: SupportedLocale,\n config?: DateFormatterConfig\n): ResolvedDateFormatterConfig => ({\n locale,\n strict: config?.strict ?? DEFAULT_STRICT,\n invalid: config?.invalid ?? DEFAULT_INVALID_DATE\n})\n\nconst getInvalidDateText = (config?: DateFormatterConfig, props?: GetDateOptions): string => {\n return props?.invalid ?? config?.invalid ?? DEFAULT_INVALID_DATE\n}\n\nconst getTargetLocale = (currentLocale: SupportedLocale, props?: GetDateOptions): SupportedLocale => {\n if (!props?.locale) {\n return currentLocale\n }\n\n return resolveLocaleOrThrow(props.locale)\n}\n\nconst getHelperLocale = <T extends { locale?: LocaleInput }>(\n config?: DateFormatterConfig,\n props?: T\n): SupportedLocale => {\n if (props?.locale) {\n return resolveLocaleOrThrow(props.locale)\n }\n\n if (config?.locale) {\n return resolveLocaleOrThrow(config.locale)\n }\n\n return DEFAULT_LOCALE\n}\n\nconst parseDateValue = (\n value: DateValue,\n input: DateParsingOptions['input'],\n locale: SupportedLocale,\n strict: boolean\n): Dayjs => {\n if (!input) {\n return dayjs(value).locale(locale)\n }\n\n if (typeof input === 'string') {\n return dayjs(value, input, locale, strict).locale(locale)\n }\n\n return dayjs(value, [...input], locale, strict).locale(locale)\n}\n\nconst createFormatterParseDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n return (props: DateParsingOptions): ParseDateResult => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const parsed = parseDateValue(props.date, props.input, locale, props.strict ?? config.strict)\n\n if (!parsed.isValid()) {\n return {\n isValid: false,\n locale,\n date: null,\n iso: null,\n timestamp: null,\n error: getInvalidDateText(config, props)\n }\n }\n\n return {\n isValid: true,\n locale,\n date: parsed.toDate(),\n iso: parsed.toISOString(),\n timestamp: parsed.valueOf(),\n format: (output = DEFAULT_FORMAT) => parsed.format(output)\n }\n }\n}\n\nconst createFormatterIsValidDate = (parseDate: (props: DateParsingOptions) => ParseDateResult) => {\n return (props: DateParsingOptions): boolean => parseDate(props).isValid\n}\n\nconst createFormatterGetDate = (getConfig: () => ResolvedDateFormatterConfig) => {\n const parseDate = createFormatterParseDate(getConfig)\n\n return (props?: GetDateOptions): string => {\n const config = getConfig()\n const locale = getTargetLocale(config.locale, props)\n const output = props?.output ?? DEFAULT_FORMAT\n\n if (!props) {\n return dayjs().locale(locale).format(DEFAULT_FORMAT)\n }\n\n if (props.date === undefined) {\n return dayjs().locale(locale).format(output)\n }\n\n const parsed = parseDate({\n date: props.date,\n input: props.input,\n locale: props.locale,\n strict: props.strict\n })\n\n if (!parsed.isValid) {\n return props.invalid ?? parsed.error\n }\n\n return parsed.format(output)\n }\n}\n\nfunction resolveLocaleOrThrow(locale: LocaleInput): SupportedLocale {\n const resolvedLocale = resolveLocale(locale)\n\n if (!resolvedLocale) {\n throw new Error(\n `Unsupported locale: ${locale}. The package tries an exact locale match first and then falls back to the base locale.`\n )\n }\n\n return resolvedLocale\n}\n\nexport const getSupportedLocales = (): readonly SupportedLocale[] => SUPPORTED_LOCALES\n\nexport const getDate = async (props?: GetDateOptions, config?: DateFormatterConfig): Promise<string> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.getDate(props)\n}\n\nexport const parseDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<ParseDateResult> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.parseDate(props)\n}\n\nexport const isValidDate = async (\n props: DateParsingOptions,\n config?: DateFormatterConfig\n): Promise<boolean> => {\n const locale = getHelperLocale(config, props)\n const formatter = createDateFormatter({ ...config, locale })\n\n await formatter.ready\n\n return formatter.isValidDate(props)\n}\n\nexport const createDateFormatter = (config?: DateFormatterConfig): DateFormatter => {\n let currentLocale = config?.locale ? resolveLocaleOrThrow(config.locale) : DEFAULT_LOCALE\n\n const getConfig = (): ResolvedDateFormatterConfig => createResolvedConfig(currentLocale, config)\n\n const ready = ensureLocaleLoaded(currentLocale)\n const parseDate = createFormatterParseDate(getConfig)\n\n return {\n getDate: createFormatterGetDate(getConfig),\n parseDate,\n isValidDate: createFormatterIsValidDate(parseDate),\n getSupportedLocales,\n getCurrentLocale: () => currentLocale,\n setLocale: async (locale: LocaleInput) => {\n const resolvedLocale = resolveLocaleOrThrow(locale)\n\n await ensureLocaleLoaded(resolvedLocale)\n currentLocale = resolvedLocale\n },\n ready\n }\n}\n","export const SUPPORTED_LOCALES = [\n 'en',\n 'es',\n 'es-mx',\n 'fr',\n 'pt',\n 'pt-br',\n 'de',\n 'it',\n 'ja'\n] as const\n\nexport type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]\nexport type LocaleInput = string\n\nconst localeLoaders: Record<SupportedLocale, (() => Promise<unknown>) | null> = {\n en: null,\n es: () => import('dayjs/locale/es.js'),\n 'es-mx': () => import('dayjs/locale/es-mx.js'),\n fr: () => import('dayjs/locale/fr.js'),\n pt: () => import('dayjs/locale/pt.js'),\n 'pt-br': () => import('dayjs/locale/pt-br.js'),\n de: () => import('dayjs/locale/de.js'),\n it: () => import('dayjs/locale/it.js'),\n ja: () => import('dayjs/locale/ja.js')\n}\n\nconst normalizeLocale = (locale: string): string => {\n return locale.trim().toLowerCase().replace(/_/g, '-')\n}\n\nconst asSupportedLocale = (locale: string): SupportedLocale | null => {\n if (!SUPPORTED_LOCALES.includes(locale as SupportedLocale)) {\n return null\n }\n\n return locale as SupportedLocale\n}\n\nexport const isSupportedLocale = (locale: string): boolean => {\n return resolveLocale(locale) !== null\n}\n\nexport const resolveLocale = (locale: LocaleInput): SupportedLocale | null => {\n const normalizedLocale = normalizeLocale(locale)\n const exactLocale = asSupportedLocale(normalizedLocale)\n\n if (exactLocale) {\n return exactLocale\n }\n\n const [baseLocale] = normalizedLocale.split('-')\n\n if (!baseLocale) {\n return null\n }\n\n return asSupportedLocale(baseLocale)\n}\n\nexport const ensureLocaleLoaded = async (locale: SupportedLocale): Promise<void> => {\n const load = localeLoaders[locale]\n\n if (!load) {\n return\n }\n\n await load()\n}\n"],"mappings":"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","names":["parseDate","parseDate"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samline/date",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Format and localize dates with Day.js through a small multi-entrypoint API.",
5
5
  "type": "module",
6
6
  "license": "MIT",