@openmrs/esm-utils 6.3.1-pre.2965 → 6.3.1-pre.2997

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.
Files changed (42) hide show
  1. package/.swcrc +16 -0
  2. package/.turbo/turbo-build.log +3 -17
  3. package/dist/age-helpers.d.ts +12 -0
  4. package/dist/age-helpers.js +86 -0
  5. package/dist/dates/date-util.d.ts +144 -0
  6. package/dist/dates/date-util.js +335 -0
  7. package/dist/dates/index.d.ts +1 -0
  8. package/dist/dates/index.js +1 -0
  9. package/dist/get-locale.d.ts +5 -0
  10. package/dist/get-locale.js +13 -0
  11. package/dist/index.d.ts +10 -0
  12. package/dist/index.js +10 -0
  13. package/dist/is-online.d.ts +1 -0
  14. package/dist/is-online.js +3 -0
  15. package/dist/patient-helpers.d.ts +42 -0
  16. package/dist/patient-helpers.js +78 -0
  17. package/dist/retry.d.ts +38 -0
  18. package/dist/retry.js +45 -0
  19. package/dist/shallowEqual.d.ts +12 -0
  20. package/dist/shallowEqual.js +36 -0
  21. package/dist/storage.d.ts +10 -0
  22. package/dist/storage.js +15 -0
  23. package/dist/test-helpers.d.ts +12 -0
  24. package/dist/test-helpers.js +27 -0
  25. package/dist/version.d.ts +1 -0
  26. package/dist/version.js +21 -0
  27. package/package.json +34 -22
  28. package/src/age-helpers.test.ts +1 -0
  29. package/src/age-helpers.ts +1 -1
  30. package/src/dates/date-util.test.ts +4 -3
  31. package/src/dates/date-util.ts +4 -4
  32. package/src/patient-helpers.test.ts +2 -1
  33. package/src/test-helpers.ts +10 -5
  34. package/src/version.test.ts +4 -0
  35. package/tsconfig.build.json +9 -0
  36. package/tsconfig.json +3 -23
  37. package/vitest.config.ts +8 -0
  38. package/dist/openmrs-esm-utils.js +0 -3
  39. package/dist/openmrs-esm-utils.js.LICENSE.txt +0 -7
  40. package/dist/openmrs-esm-utils.js.map +0 -1
  41. package/jest.config.js +0 -13
  42. package/webpack.config.js +0 -42
package/.swcrc ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://swc.rs/schema.json",
3
+ "exclude": [".*\\.test\\..*", "setup-tests\\..*"],
4
+ "module": {
5
+ "type": "es6",
6
+ "resolveFully": true
7
+ },
8
+ "jsc": {
9
+ "parser": {
10
+ "syntax": "typescript",
11
+ "tsx": false
12
+ },
13
+ "target": "es2020",
14
+ "baseUrl": "src"
15
+ }
16
+ }
@@ -1,17 +1,3 @@
1
- asset openmrs-esm-utils.js 226 KiB [emitted] [minimized] (name: main) 2 related assets
2
- orphan modules 1.15 MiB [orphan] 735 modules
3
- runtime modules 937 bytes 4 modules
4
- built modules 798 KiB [built]
5
- modules by path ./ 342 KiB
6
- modules by path ./node_modules/semver/functions/*.js 6.71 KiB 24 modules
7
- modules by path ./node_modules/semver/ranges/*.js 11.8 KiB 11 modules
8
- modules by path ./node_modules/semver/internal/*.js 7.58 KiB 4 modules
9
- modules by path ./node_modules/semver/classes/*.js 23.5 KiB 3 modules
10
- + 2 modules
11
- modules by path ../../../node_modules/ 456 KiB
12
- modules by path ../../../node_modules/@formatjs/intl-durationformat/ 322 KiB 13 modules
13
- modules by path ../../../node_modules/dayjs/plugin/*.js 3.82 KiB 3 modules
14
- ../../../node_modules/tslib/tslib.es6.mjs 17.2 KiB [built] [code generated]
15
- ../../../node_modules/@formatjs/intl-localematcher/lib/index.js + 13 modules 113 KiB [built] [code generated]
16
- external "dayjs" 42 bytes [built] [code generated]
17
- webpack 5.88.0 compiled successfully in 11705 ms
1
+ [0] Successfully compiled: 12 files with swc (128.41ms)
2
+ [0] swc --strip-leading-paths src -d dist exited with code 0
3
+ [1] tsc --project tsconfig.build.json exited with code 0
@@ -0,0 +1,12 @@
1
+ import dayjs from 'dayjs';
2
+ /**
3
+ * Gets a human readable and locale supported representation of a person's age, given their birthDate,
4
+ * The representation logic follows the guideline here:
5
+ * https://webarchive.nationalarchives.gov.uk/ukgwa/20160921162509mp_/http://systems.digital.nhs.uk/data/cui/uig/patben.pdf
6
+ * (See Tables 7 and 8)
7
+ *
8
+ * @param birthDate The birthDate. If birthDate is null, returns null.
9
+ * @param currentDate Optional. If provided, calculates the age of the person at the provided currentDate (instead of now).
10
+ * @returns A human-readable string version of the age.
11
+ */
12
+ export declare function age(birthDate: dayjs.ConfigType, currentDate?: dayjs.ConfigType): string | null;
@@ -0,0 +1,86 @@
1
+ /** @module @category Utility */ import { DurationFormat } from "@formatjs/intl-durationformat";
2
+ import { attempt } from "any-date-parser";
3
+ import dayjs from "dayjs";
4
+ import objectSupport from "dayjs/plugin/objectSupport.js";
5
+ import { omit } from "lodash-es";
6
+ import { getLocale } from "./get-locale.js";
7
+ dayjs.extend(objectSupport);
8
+ /**
9
+ * Gets a human readable and locale supported representation of a person's age, given their birthDate,
10
+ * The representation logic follows the guideline here:
11
+ * https://webarchive.nationalarchives.gov.uk/ukgwa/20160921162509mp_/http://systems.digital.nhs.uk/data/cui/uig/patben.pdf
12
+ * (See Tables 7 and 8)
13
+ *
14
+ * @param birthDate The birthDate. If birthDate is null, returns null.
15
+ * @param currentDate Optional. If provided, calculates the age of the person at the provided currentDate (instead of now).
16
+ * @returns A human-readable string version of the age.
17
+ */ export function age(birthDate, currentDate = dayjs()) {
18
+ if (birthDate == null) {
19
+ return null;
20
+ }
21
+ const locale = getLocale();
22
+ const to = dayjs(currentDate);
23
+ let from;
24
+ if (typeof birthDate === 'string') {
25
+ let parsedDate = attempt(birthDate, locale);
26
+ if (parsedDate.invalid) {
27
+ console.warn(`Could not interpret '${birthDate}' as a date`);
28
+ return null;
29
+ }
30
+ // hack here but any date interprets 2000-01, etc. as yyyy-dd rather than yyyy-mm
31
+ if (parsedDate.day && !parsedDate.month) {
32
+ parsedDate = Object.assign({}, omit(parsedDate, 'day'), {
33
+ month: parsedDate.day
34
+ });
35
+ }
36
+ // dayjs' object support uses 0-based months, whereas any-date-parser uses 1-based months
37
+ if (parsedDate.month) {
38
+ parsedDate.month -= 1;
39
+ }
40
+ // in dayjs day is day of week; in any-date-parser, its day of month, so we need to convert them
41
+ if (parsedDate.day) {
42
+ parsedDate = Object.assign({}, omit(parsedDate, 'day'), {
43
+ date: parsedDate.day
44
+ });
45
+ }
46
+ from = dayjs(to).set(parsedDate);
47
+ } else {
48
+ from = dayjs(birthDate);
49
+ }
50
+ const hourDiff = to.diff(from, 'hours');
51
+ const dayDiff = to.diff(from, 'days');
52
+ const weekDiff = to.diff(from, 'weeks');
53
+ const monthDiff = to.diff(from, 'months');
54
+ const yearDiff = to.diff(from, 'years');
55
+ const duration = {};
56
+ const options = {
57
+ style: 'short',
58
+ localeMatcher: 'lookup'
59
+ };
60
+ if (hourDiff < 2) {
61
+ const minuteDiff = to.diff(from, 'minutes');
62
+ duration['minutes'] = minuteDiff;
63
+ if (minuteDiff === 0) {
64
+ options.minutesDisplay = 'always';
65
+ }
66
+ } else if (dayDiff < 2) {
67
+ duration['hours'] = hourDiff;
68
+ } else if (weekDiff < 4) {
69
+ duration['days'] = dayDiff;
70
+ } else if (yearDiff < 1) {
71
+ const remainderDayDiff = to.subtract(weekDiff, 'weeks').diff(from, 'days');
72
+ duration['weeks'] = weekDiff;
73
+ duration['days'] = remainderDayDiff;
74
+ } else if (yearDiff < 2) {
75
+ const remainderDayDiff = to.subtract(monthDiff, 'months').diff(from, 'days');
76
+ duration['months'] = monthDiff;
77
+ duration['days'] = remainderDayDiff;
78
+ } else if (yearDiff < 18) {
79
+ const remainderMonthDiff = to.subtract(yearDiff, 'year').diff(from, 'months');
80
+ duration['years'] = yearDiff;
81
+ duration['months'] = remainderMonthDiff;
82
+ } else {
83
+ duration['years'] = yearDiff;
84
+ }
85
+ return new DurationFormat(locale, options).format(duration);
86
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @module
3
+ * @category Date and Time
4
+ */
5
+ import { type CalendarDate, type CalendarDateTime, type CalendarIdentifier, type ZonedDateTime } from '@internationalized/date';
6
+ export type DateInput = string | number | Date;
7
+ /**
8
+ * This function checks whether a date string is the OpenMRS ISO format.
9
+ * The format should be YYYY-MM-DDTHH:mm:ss.SSSZZ
10
+ */
11
+ export declare function isOmrsDateStrict(omrsPayloadString: string): boolean;
12
+ /**
13
+ *
14
+ * @param date Checks if the provided date is today.
15
+ */
16
+ export declare function isOmrsDateToday(date: DateInput): boolean;
17
+ /**
18
+ * Converts the object to a date object if it is an OpenMRS ISO date time string.
19
+ * Otherwise returns null.
20
+ */
21
+ export declare function toDateObjectStrict(omrsDateString: string): Date | null;
22
+ /**
23
+ * Formats the input to OpenMRS ISO format: "YYYY-MM-DDTHH:mm:ss.SSSZZ".
24
+ */
25
+ export declare function toOmrsIsoString(date: DateInput, toUTC?: boolean): string;
26
+ /**
27
+ * Utility function to parse an arbitrary string into a date.
28
+ * Uses `dayjs(dateString)`.
29
+ */
30
+ export declare function parseDate(dateString: string): Date;
31
+ /**
32
+ * Provides the name of the calendar to associate, as a default, with the given base locale.
33
+ *
34
+ * @example
35
+ * ```
36
+ * registerDefaultCalendar('en', 'buddhist') // sets the default calendar for the 'en' locale to Buddhist.
37
+ * ```
38
+ *
39
+ * @param locale the locale to register this calendar for
40
+ * @param calendar the calendar to use for this registration
41
+ */
42
+ export declare function registerDefaultCalendar(locale: string, calendar: CalendarIdentifier): void;
43
+ /**
44
+ * Retrieves the default calendar for the specified locale if any.
45
+ *
46
+ * @param locale the locale to look-up
47
+ */
48
+ export declare function getDefaultCalendar(locale: Intl.Locale | string | undefined): CalendarIdentifier | undefined;
49
+ export type FormatDateMode = 'standard' | 'wide';
50
+ export type FormatDateOptions = {
51
+ /**
52
+ * The calendar to use when formatting this date.
53
+ */
54
+ calendar?: string;
55
+ /**
56
+ * The locale to use when formatting this date
57
+ */
58
+ locale?: string;
59
+ /**
60
+ * - `standard`: "03 Feb 2022"
61
+ * - `wide`: "03 — Feb — 2022"
62
+ */
63
+ mode: FormatDateMode;
64
+ /**
65
+ * Whether the time should be included in the output always (`true`),
66
+ * never (`false`), or only when the input date is today (`for today`).
67
+ */
68
+ time: true | false | 'for today';
69
+ /** Whether to include the day number */
70
+ day: boolean;
71
+ /** Whether to include the month number */
72
+ month: boolean;
73
+ /** Whether to include the year */
74
+ year: boolean;
75
+ /** The unicode numbering system to use */
76
+ numberingSystem?: string;
77
+ /**
78
+ * Disables the special handling of dates that are today. If false
79
+ * (the default), then dates that are today will be formatted as "Today"
80
+ * in the locale language. If true, then dates that are today will be
81
+ * formatted the same as all other dates.
82
+ */
83
+ noToday: boolean;
84
+ };
85
+ /**
86
+ * Formats the string representing a date, including partial representations of dates, according to the current
87
+ * locale and the given options.
88
+ *
89
+ * Default options:
90
+ * - mode: "standard",
91
+ * - time: "for today",
92
+ * - day: true,
93
+ * - month: true,
94
+ * - year: true
95
+ * - noToday: false
96
+ *
97
+ * If the date is today then "Today" is produced (in the locale language).
98
+ * This behavior can be disabled with `noToday: true`.
99
+ *
100
+ * When time is included, it is appended with a comma and a space. This
101
+ * agrees with the output of `Date.prototype.toLocaleString` for *most*
102
+ * locales.
103
+ */
104
+ export declare function formatPartialDate(dateString: string, options?: Partial<FormatDateOptions>): string | null;
105
+ /**
106
+ * Formats the input date according to the current locale and the
107
+ * given options.
108
+ *
109
+ * Default options:
110
+ * - mode: "standard",
111
+ * - time: "for today",
112
+ * - day: true,
113
+ * - month: true,
114
+ * - year: true
115
+ * - noToday: false
116
+ *
117
+ * If the date is today then "Today" is produced (in the locale language).
118
+ * This behavior can be disabled with `noToday: true`.
119
+ *
120
+ * When time is included, it is appended with a comma and a space. This
121
+ * agrees with the output of `Date.prototype.toLocaleString` for *most*
122
+ * locales.
123
+ */
124
+ export declare function formatDate(date: Date, options?: Partial<FormatDateOptions>): string;
125
+ /**
126
+ * Formats the input as a time, according to the current locale.
127
+ * 12-hour or 24-hour clock depends on locale.
128
+ */
129
+ export declare function formatTime(date: Date): string;
130
+ /**
131
+ * Formats the input into a string showing the date and time, according
132
+ * to the current locale. The `mode` parameter is as described for
133
+ * `formatDate`.
134
+ *
135
+ * This is created by concatenating the results of `formatDate`
136
+ * and `formatTime` with a comma and space. This agrees with the
137
+ * output of `Date.prototype.toLocaleString` for *most* locales.
138
+ */
139
+ export declare function formatDatetime(date: Date, options?: Partial<Omit<FormatDateOptions, 'time'>>): string;
140
+ /**
141
+ * Converts a calendar date to the equivalent locale calendar date.
142
+ * @returns CalendarDate
143
+ */
144
+ export declare function convertToLocaleCalendar(date: CalendarDate | CalendarDateTime | ZonedDateTime, locale: string | Intl.Locale): CalendarDate | CalendarDateTime | ZonedDateTime;
@@ -0,0 +1,335 @@
1
+ /**
2
+ * @module
3
+ * @category Date and Time
4
+ */ function _check_private_redeclaration(obj, privateCollection) {
5
+ if (privateCollection.has(obj)) {
6
+ throw new TypeError("Cannot initialize the same private elements twice on an object");
7
+ }
8
+ }
9
+ function _class_apply_descriptor_get(receiver, descriptor) {
10
+ if (descriptor.get) {
11
+ return descriptor.get.call(receiver);
12
+ }
13
+ return descriptor.value;
14
+ }
15
+ function _class_extract_field_descriptor(receiver, privateMap, action) {
16
+ if (!privateMap.has(receiver)) {
17
+ throw new TypeError("attempted to " + action + " private field on non-instance");
18
+ }
19
+ return privateMap.get(receiver);
20
+ }
21
+ function _class_private_field_get(receiver, privateMap) {
22
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
23
+ return _class_apply_descriptor_get(receiver, descriptor);
24
+ }
25
+ function _class_private_field_init(obj, privateMap, value) {
26
+ _check_private_redeclaration(obj, privateMap);
27
+ privateMap.set(obj, value);
28
+ }
29
+ import { createCalendar, toCalendar } from "@internationalized/date";
30
+ import { attempt } from "any-date-parser";
31
+ import dayjs from "dayjs";
32
+ import isToday from "dayjs/plugin/isToday.js";
33
+ import objectSupport from "dayjs/plugin/objectSupport.js";
34
+ import utc from "dayjs/plugin/utc.js";
35
+ import { isNil, omit } from "lodash-es";
36
+ import { getLocale } from "../index.js";
37
+ dayjs.extend(isToday);
38
+ dayjs.extend(utc);
39
+ dayjs.extend(objectSupport);
40
+ const isoFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZZ';
41
+ /**
42
+ * This function checks whether a date string is the OpenMRS ISO format.
43
+ * The format should be YYYY-MM-DDTHH:mm:ss.SSSZZ
44
+ */ export function isOmrsDateStrict(omrsPayloadString) {
45
+ // omrs format 2018-03-19T00:00:00.000+0300
46
+ if (omrsPayloadString === null || omrsPayloadString === undefined || omrsPayloadString.trim().length !== 28) {
47
+ return false;
48
+ }
49
+ omrsPayloadString = omrsPayloadString.trim();
50
+ // 11th character will always be T
51
+ if (omrsPayloadString[10] !== 'T') {
52
+ return false;
53
+ }
54
+ // checking time format
55
+ if (omrsPayloadString[13] !== ':' || omrsPayloadString[16] !== ':' || omrsPayloadString[19] !== '.') {
56
+ return false;
57
+ }
58
+ // checking UTC offset format
59
+ if (!(omrsPayloadString[23] === '+' || omrsPayloadString[23] === '-')) {
60
+ return false;
61
+ }
62
+ return dayjs(omrsPayloadString, isoFormat).isValid();
63
+ }
64
+ /**
65
+ *
66
+ * @param date Checks if the provided date is today.
67
+ */ export function isOmrsDateToday(date) {
68
+ return dayjs(date).isToday();
69
+ }
70
+ /**
71
+ * Converts the object to a date object if it is an OpenMRS ISO date time string.
72
+ * Otherwise returns null.
73
+ */ export function toDateObjectStrict(omrsDateString) {
74
+ if (!isOmrsDateStrict(omrsDateString)) {
75
+ return null;
76
+ }
77
+ return dayjs(omrsDateString, isoFormat).toDate();
78
+ }
79
+ /**
80
+ * Formats the input to OpenMRS ISO format: "YYYY-MM-DDTHH:mm:ss.SSSZZ".
81
+ */ export function toOmrsIsoString(date, toUTC = false) {
82
+ let d = dayjs(date);
83
+ if (toUTC) {
84
+ d = d.utc();
85
+ }
86
+ return d.format(isoFormat);
87
+ }
88
+ /**
89
+ * Utility function to parse an arbitrary string into a date.
90
+ * Uses `dayjs(dateString)`.
91
+ */ export function parseDate(dateString) {
92
+ return dayjs(dateString).toDate();
93
+ }
94
+ var _registry = /*#__PURE__*/ new WeakMap();
95
+ /**
96
+ * Internal cache for per-locale calendars
97
+ */ class LocaleCalendars {
98
+ register(locale, calendar) {
99
+ _class_private_field_get(this, _registry).set(locale, calendar);
100
+ }
101
+ getCalendar(locale) {
102
+ if (!Boolean(locale)) {
103
+ return undefined;
104
+ }
105
+ if (locale.calendar) {
106
+ return locale.calendar;
107
+ }
108
+ if (locale.region) {
109
+ const key = `${locale.language}-${locale.region}`;
110
+ if (_class_private_field_get(this, _registry).has(key)) {
111
+ return _class_private_field_get(this, _registry).get(key);
112
+ }
113
+ }
114
+ if (locale.language && _class_private_field_get(this, _registry).has(locale.language)) {
115
+ return _class_private_field_get(this, _registry).get(locale.language);
116
+ }
117
+ const defaultCalendar = new Intl.DateTimeFormat(locale.toString()).resolvedOptions().calendar;
118
+ // cache this result
119
+ _class_private_field_get(this, _registry).set(`${locale.language}${locale.region ? `-${locale.region}` : ''}`, defaultCalendar);
120
+ return defaultCalendar;
121
+ }
122
+ constructor(){
123
+ _class_private_field_init(this, _registry, {
124
+ writable: true,
125
+ value: new Map()
126
+ });
127
+ }
128
+ }
129
+ const registeredLocaleCalendars = new LocaleCalendars();
130
+ /**
131
+ * Provides the name of the calendar to associate, as a default, with the given base locale.
132
+ *
133
+ * @example
134
+ * ```
135
+ * registerDefaultCalendar('en', 'buddhist') // sets the default calendar for the 'en' locale to Buddhist.
136
+ * ```
137
+ *
138
+ * @param locale the locale to register this calendar for
139
+ * @param calendar the calendar to use for this registration
140
+ */ export function registerDefaultCalendar(locale, calendar) {
141
+ registeredLocaleCalendars.register(locale, calendar);
142
+ }
143
+ /**
144
+ * Retrieves the default calendar for the specified locale if any.
145
+ *
146
+ * @param locale the locale to look-up
147
+ */ export function getDefaultCalendar(locale) {
148
+ const locale_ = locale ?? getLocale();
149
+ return registeredLocaleCalendars.getCalendar(locale_ instanceof Intl.Locale ? locale_ : new Intl.Locale(locale_));
150
+ }
151
+ const defaultOptions = {
152
+ mode: 'standard',
153
+ time: 'for today',
154
+ day: true,
155
+ month: true,
156
+ year: true,
157
+ noToday: false
158
+ };
159
+ /**
160
+ * Formats the string representing a date, including partial representations of dates, according to the current
161
+ * locale and the given options.
162
+ *
163
+ * Default options:
164
+ * - mode: "standard",
165
+ * - time: "for today",
166
+ * - day: true,
167
+ * - month: true,
168
+ * - year: true
169
+ * - noToday: false
170
+ *
171
+ * If the date is today then "Today" is produced (in the locale language).
172
+ * This behavior can be disabled with `noToday: true`.
173
+ *
174
+ * When time is included, it is appended with a comma and a space. This
175
+ * agrees with the output of `Date.prototype.toLocaleString` for *most*
176
+ * locales.
177
+ */ // TODO: Shouldn't throw on null input
178
+ export function formatPartialDate(dateString, options = {}) {
179
+ const locale = getLocale();
180
+ let parsed = attempt(dateString, locale);
181
+ if (parsed.invalid) {
182
+ console.warn(`Could not parse invalid date '${dateString}'`);
183
+ return null;
184
+ }
185
+ // hack here but any date interprets 2000-01, etc. as yyyy-dd rather than yyyy-mm
186
+ if (!isNil(parsed.day) && isNil(parsed.month)) {
187
+ parsed = Object.assign({}, omit(parsed, 'day'), {
188
+ month: parsed.day
189
+ });
190
+ }
191
+ // dayjs' object support uses 0-based months, whereas any-date-parser uses 1-based months
192
+ if (parsed.month) {
193
+ parsed.month -= 1;
194
+ }
195
+ // in dayjs day is day of week; in any-date-parser, its day of month, so we need to convert them
196
+ if (parsed.day) {
197
+ parsed = Object.assign({}, omit(parsed, 'day'), {
198
+ date: parsed.day
199
+ });
200
+ }
201
+ const date = dayjs().set(parsed).toDate();
202
+ if (isNil(parsed.year)) {
203
+ options.year = false;
204
+ }
205
+ if (isNil(parsed.month)) {
206
+ options.month = false;
207
+ }
208
+ if (isNil(parsed.date)) {
209
+ options.day = false;
210
+ }
211
+ return formatDate(date, options);
212
+ }
213
+ /**
214
+ * Formats the input date according to the current locale and the
215
+ * given options.
216
+ *
217
+ * Default options:
218
+ * - mode: "standard",
219
+ * - time: "for today",
220
+ * - day: true,
221
+ * - month: true,
222
+ * - year: true
223
+ * - noToday: false
224
+ *
225
+ * If the date is today then "Today" is produced (in the locale language).
226
+ * This behavior can be disabled with `noToday: true`.
227
+ *
228
+ * When time is included, it is appended with a comma and a space. This
229
+ * agrees with the output of `Date.prototype.toLocaleString` for *most*
230
+ * locales.
231
+ */ // TODO: Shouldn't throw on null input
232
+ export function formatDate(date, options) {
233
+ let locale = options?.locale ?? getLocale();
234
+ const _locale = new Intl.Locale(locale);
235
+ const { calendar, mode, time, day, month, year, noToday, numberingSystem } = {
236
+ ...defaultOptions,
237
+ ...{
238
+ noToday: _locale.language === 'am' ? true : false
239
+ },
240
+ ...options
241
+ };
242
+ const formatCalendar = calendar ?? getDefaultCalendar(_locale);
243
+ const formatterOptions = {
244
+ calendar: formatCalendar,
245
+ year: year ? 'numeric' : undefined,
246
+ month: month ? 'short' : undefined,
247
+ day: day ? '2-digit' : undefined,
248
+ numberingSystem
249
+ };
250
+ let localeString;
251
+ const isToday = dayjs(date).isToday();
252
+ if (isToday && !noToday) {
253
+ // This produces the word "Today" in the language of `locale`
254
+ const rtf = new Intl.RelativeTimeFormat(locale, {
255
+ numeric: 'auto'
256
+ });
257
+ localeString = rtf.format(0, 'day');
258
+ localeString = localeString[0].toLocaleUpperCase(locale) + localeString.slice(1);
259
+ } else {
260
+ if (_locale.language === 'en') {
261
+ // This locale override is here rather than in `getLocale`
262
+ // because Americans should see AM/PM for times.
263
+ locale = 'en-GB';
264
+ }
265
+ const formatter = new Intl.DateTimeFormat(locale, formatterOptions);
266
+ let parts = formatter.formatToParts(date);
267
+ if ((_locale.language === 'en' || _locale.language === 'am') && mode == 'standard' && year && day) {
268
+ // Custom formatting for English and Amharic. Use hyphens instead of spaces.
269
+ parts = parts.map(formatParts('-'));
270
+ }
271
+ if (mode == 'wide') {
272
+ parts = parts.map(formatParts(' — ')); // space-emdash-space
273
+ }
274
+ // omit the era when using the Ethiopic calendar
275
+ if (formatterOptions.calendar === 'ethiopic') {
276
+ parts = parts.filter((part, idx, values)=>{
277
+ if (part.type === 'era' || part.type === 'literal' && idx < values.length - 1 && values[idx + 1].type === 'era') {
278
+ return false;
279
+ }
280
+ return true;
281
+ });
282
+ }
283
+ localeString = parts.map((p)=>p.value).join('');
284
+ }
285
+ if (time === true || isToday && time === 'for today') {
286
+ localeString += `, ${formatTime(date)}`;
287
+ }
288
+ return localeString;
289
+ }
290
+ // Internal curried call-back for map()
291
+ const formatParts = (separator)=>{
292
+ return (part, idx, values)=>{
293
+ if (part.type !== 'literal' || part.value !== ' ') {
294
+ return part;
295
+ }
296
+ if (idx < values.length - 1 && values[idx + 1].type === 'era') {
297
+ return part;
298
+ }
299
+ return {
300
+ type: 'literal',
301
+ value: separator
302
+ };
303
+ };
304
+ };
305
+ /**
306
+ * Formats the input as a time, according to the current locale.
307
+ * 12-hour or 24-hour clock depends on locale.
308
+ */ export function formatTime(date) {
309
+ return date.toLocaleTimeString(getLocale(), {
310
+ hour: '2-digit',
311
+ minute: '2-digit'
312
+ });
313
+ }
314
+ /**
315
+ * Formats the input into a string showing the date and time, according
316
+ * to the current locale. The `mode` parameter is as described for
317
+ * `formatDate`.
318
+ *
319
+ * This is created by concatenating the results of `formatDate`
320
+ * and `formatTime` with a comma and space. This agrees with the
321
+ * output of `Date.prototype.toLocaleString` for *most* locales.
322
+ */ export function formatDatetime(date, options) {
323
+ return formatDate(date, {
324
+ ...options,
325
+ time: true
326
+ });
327
+ }
328
+ /**
329
+ * Converts a calendar date to the equivalent locale calendar date.
330
+ * @returns CalendarDate
331
+ */ export function convertToLocaleCalendar(date, locale) {
332
+ let locale_ = typeof locale === 'string' ? new Intl.Locale(locale) : locale;
333
+ const localCalendarName = getDefaultCalendar(locale_);
334
+ return localCalendarName ? toCalendar(date, createCalendar(localCalendarName)) : date;
335
+ }
@@ -0,0 +1 @@
1
+ export * from './date-util';
@@ -0,0 +1 @@
1
+ export * from "./date-util.js";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Returns the current locale of the application.
3
+ * @returns string
4
+ */
5
+ export declare function getLocale(): string;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Returns the current locale of the application.
3
+ * @returns string
4
+ */ export function getLocale() {
5
+ let language = window.i18next.language;
6
+ language = language.replace('_', '-'); // just in case
7
+ // Hack for `ht` until all browsers update their unicode support with ht to fr mapping.
8
+ // See https://unicode-org.atlassian.net/browse/CLDR-14956
9
+ if (language === 'ht') {
10
+ language = 'fr-HT';
11
+ }
12
+ return language;
13
+ }
@@ -0,0 +1,10 @@
1
+ export * from './age-helpers';
2
+ export * from './dates';
3
+ export * from './get-locale';
4
+ export * from './is-online';
5
+ export * from './patient-helpers';
6
+ export * from './shallowEqual';
7
+ export * from './storage';
8
+ export * from './test-helpers';
9
+ export * from './version';
10
+ export * from './retry';
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from "./age-helpers.js";
2
+ export * from "./dates/index.js";
3
+ export * from "./get-locale.js";
4
+ export * from "./is-online.js";
5
+ export * from "./patient-helpers.js";
6
+ export * from "./shallowEqual.js";
7
+ export * from "./storage.js";
8
+ export * from "./test-helpers.js";
9
+ export * from "./version.js";
10
+ export * from "./retry.js";
@@ -0,0 +1 @@
1
+ export declare function isOnline(online?: boolean): boolean;
@@ -0,0 +1,3 @@
1
+ export function isOnline(online) {
2
+ return window.offlineEnabled ? online ?? navigator.onLine : true;
3
+ }