@aemforms/af-formatters 0.22.30 → 0.22.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ShorthandStyles = void 0;
7
+ exports.getSkeleton = getSkeleton;
8
+ exports.parseDateTimeSkeleton = parseDateTimeSkeleton;
9
+
10
+ /*************************************************************************
11
+ * ADOBE CONFIDENTIAL
12
+ * ___________________
13
+ *
14
+ * Copyright 2022 Adobe
15
+ * All Rights Reserved.
16
+ *
17
+ * NOTICE: All information contained herein is, and remains
18
+ * the property of Adobe and its suppliers, if any. The intellectual
19
+ * and technical concepts contained herein are proprietary to Adobe
20
+ * and its suppliers and are protected by all applicable intellectual
21
+ * property laws, including trade secret and copyright laws.
22
+ * Dissemination of this information or reproduction of this material
23
+ * is strictly forbidden unless prior written permission is obtained
24
+ * from Adobe.
25
+
26
+ * Adobe permits you to use and modify this file solely in accordance with
27
+ * the terms of the Adobe license agreement accompanying it.
28
+ *************************************************************************/
29
+
30
+ /**
31
+ * https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
32
+ * Credit: https://git.corp.adobe.com/dc/dfl/blob/master/src/patterns/parseDateTimeSkeleton.js
33
+ * Created a separate library to be used elsewhere as well.
34
+ */
35
+ const DATE_TIME_REGEX = // eslint-disable-next-line max-len
36
+ /(?:[Eec]{1,6}|G{1,5}|[Qq]{1,5}|(?:[yYur]+|U{1,5})|[ML]{1,5}|d{1,2}|D{1,3}|F{1}|[abB]{1,5}|[hkHK]{1,2}|w{1,2}|W{1}|m{1,2}|s{1,2}|[zZOvV]{1,5}|[zZOvVxX]{1,3}|S{1,3}|'(?:[^']|'')*')|[^a-zA-Z']+/g;
37
+ const ShorthandStyles = ["full", "long", "medium", "short"];
38
+ exports.ShorthandStyles = ShorthandStyles;
39
+ const testDate = new Date(2000, 2, 1, 2, 3, 4);
40
+ /**
41
+ * Since the formatted month names are different than standalone month names, we need to identify the correct option
42
+ * to pass for formatting
43
+ * @param value {string} formatted value of the month
44
+ * @param language {string} language in which the month is formatted
45
+ * @param isMediumFormatStyle {boolean} if shorthand style used for formatting was medium
46
+ */
47
+
48
+ function deduceMonthOption(value, language, isMediumFormatStyle) {
49
+ const formattedMarch = value;
50
+ const longMarch = new Intl.DateTimeFormat(language, {
51
+ month: 'long'
52
+ }).formatToParts(testDate)[0].value;
53
+ const shortMarch = new Intl.DateTimeFormat(language, {
54
+ month: 'short'
55
+ }).formatToParts(testDate)[0].value;
56
+ const monthOptions = {
57
+ [longMarch]: 'long',
58
+ [shortMarch]: 'short',
59
+ '03': '2-digit',
60
+ '3': 'numeric'
61
+ };
62
+
63
+ if (formattedMarch !== undefined) {
64
+ monthOptions[formattedMarch] = isMediumFormatStyle ? 'short' : 'long';
65
+ }
66
+
67
+ return monthOptions[value];
68
+ }
69
+
70
+ function getSkeleton(skeleton, language) {
71
+ if (ShorthandStyles.find(type => skeleton.includes(type))) {
72
+ const parsed = parseDateStyle(skeleton, language);
73
+ const result = [];
74
+ const symbols = {
75
+ month: 'M',
76
+ year: 'Y',
77
+ day: 'd'
78
+ };
79
+ parsed.forEach(_ref => {
80
+ let [type, option, length] = _ref;
81
+
82
+ if (type in symbols) {
83
+ result.push(Array(length).fill(symbols[type]).join(''));
84
+ } else if (type === 'literal') {
85
+ result.push(option);
86
+ }
87
+ });
88
+ return result.join('');
89
+ }
90
+
91
+ return skeleton;
92
+ }
93
+ /**
94
+ *
95
+ * @param skeleton shorthand style for the date concatenated with shorthand style of time. The
96
+ * Shorthand style for both date and time is one of ['full', 'long', 'medium', 'short'].
97
+ * @param language {string} language to parse the date shorthand style
98
+ * @returns {[*,string][]}
99
+ */
100
+
101
+
102
+ function parseDateStyle(skeleton, language) {
103
+ const options = {}; // the skeleton could have two keywords -- one for date, one for time
104
+
105
+ const styles = skeleton.split(/\s/).filter(s => s.length);
106
+ options.dateStyle = styles[0];
107
+ if (styles.length > 1) options.timeStyle = styles[1];
108
+ const testDate = new Date(2000, 2, 1, 2, 3, 4);
109
+ const parts = new Intl.DateTimeFormat(language, options).formatToParts(testDate); // oddly, the formatted month name can be different from the standalone month name
110
+
111
+ const formattedMarch = parts.find(p => p.type === 'month').value;
112
+ const longMarch = new Intl.DateTimeFormat(language, {
113
+ month: 'long'
114
+ }).formatToParts(testDate)[0].value;
115
+ const shortMarch = new Intl.DateTimeFormat(language, {
116
+ month: 'short'
117
+ }).formatToParts(testDate)[0].value;
118
+ const result = [];
119
+ parts.forEach(_ref2 => {
120
+ let {
121
+ type,
122
+ value
123
+ } = _ref2;
124
+ let option;
125
+
126
+ if (type === 'month') {
127
+ option = {
128
+ [formattedMarch]: skeleton === 'medium' ? 'short' : 'long',
129
+ [longMarch]: 'long',
130
+ [shortMarch]: 'short',
131
+ '03': '2-digit',
132
+ '3': 'numeric'
133
+ }[value];
134
+ }
135
+
136
+ if (type === 'year') option = {
137
+ '2000': 'numeric',
138
+ '00': '2-digit'
139
+ }[value];
140
+ if (['day', 'hour', 'minute', 'second'].includes(type)) option = value.length === 2 ? '2-digit' : 'numeric';
141
+ if (type === 'literal') option = value;
142
+ if (type === 'dayPeriod') option = 'short';
143
+ result.push([type, option, value.length]);
144
+ });
145
+ return result;
146
+ }
147
+ /**
148
+ * Parse Date time skeleton into Intl.DateTimeFormatOptions parts
149
+ * Ref: https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
150
+ */
151
+
152
+
153
+ function parseDateTimeSkeleton(skeleton, language) {
154
+ if (ShorthandStyles.find(type => skeleton.includes(type))) {
155
+ return parseDateStyle(skeleton, language);
156
+ }
157
+
158
+ const result = [];
159
+ skeleton.replace(DATE_TIME_REGEX, match => {
160
+ const len = match.length;
161
+
162
+ switch (match[0]) {
163
+ // Era
164
+ case 'G':
165
+ result.push(['era', len === 4 ? 'long' : len === 5 ? 'narrow' : 'short', len]);
166
+ break;
167
+ // Year
168
+
169
+ case 'y':
170
+ result.push(['year', len === 2 ? '2-digit' : 'numeric', len]);
171
+ break;
172
+
173
+ case 'Y':
174
+ case 'u':
175
+ case 'U':
176
+ case 'r':
177
+ throw new RangeError('`Y/u/U/r` (year) patterns are not supported, use `y` instead');
178
+ // Quarter
179
+
180
+ case 'q':
181
+ case 'Q':
182
+ throw new RangeError('`q/Q` (quarter) patterns are not supported');
183
+ // Month
184
+
185
+ case 'M':
186
+ case 'L':
187
+ result.push(['month', ['numeric', '2-digit', 'short', 'long', 'narrow'][len - 1], len]);
188
+ break;
189
+ // Week
190
+
191
+ case 'w':
192
+ case 'W':
193
+ throw new RangeError('`w/W` (week) patterns are not supported');
194
+
195
+ case 'd':
196
+ result.push(['day', ['numeric', '2-digit'][len - 1], len]);
197
+ break;
198
+
199
+ case 'D':
200
+ case 'F':
201
+ case 'g':
202
+ throw new RangeError('`D/F/g` (day) patterns are not supported, use `d` instead');
203
+ // Weekday
204
+
205
+ case 'E':
206
+ result.push(['weekday', ['short', 'short', 'short', 'long', 'narrow', 'narrow'][len - 1], len]);
207
+ break;
208
+
209
+ case 'e':
210
+ if (len < 4) {
211
+ throw new RangeError('`e..eee` (weekday) patterns are not supported');
212
+ }
213
+
214
+ result.push(['weekday', ['short', 'long', 'narrow', 'short'][len - 4], len]);
215
+ break;
216
+
217
+ case 'c':
218
+ if (len < 3 || len > 5) {
219
+ throw new RangeError('`c, cc, cccccc` (weekday) patterns are not supported');
220
+ }
221
+
222
+ result.push(['weekday', ['short', 'long', 'narrow', 'short'][len - 3], len]);
223
+ break;
224
+ // Period
225
+
226
+ case 'a':
227
+ // AM, PM
228
+ result.push(['hour12', true, 1]);
229
+ break;
230
+
231
+ case 'b': // am, pm, noon, midnight
232
+
233
+ case 'B':
234
+ // flexible day periods
235
+ throw new RangeError('`b/B` (period) patterns are not supported, use `a` instead');
236
+ // Hour
237
+
238
+ case 'h':
239
+ result.push(['hourCycle', 'h12']);
240
+ result.push(['hour', ['numeric', '2-digit'][len - 1], len]);
241
+ break;
242
+
243
+ case 'H':
244
+ result.push(['hourCycle', 'h23', 1]);
245
+ result.push(['hour', ['numeric', '2-digit'][len - 1], len]);
246
+ break;
247
+
248
+ case 'K':
249
+ result.push(['hourCycle', 'h11', 1]);
250
+ result.push(['hour', ['numeric', '2-digit'][len - 1], len]);
251
+ break;
252
+
253
+ case 'k':
254
+ result.push(['hourCycle', 'h24', 1]);
255
+ result.push(['hour', ['numeric', '2-digit'][len - 1], len]);
256
+ break;
257
+
258
+ case 'j':
259
+ case 'J':
260
+ case 'C':
261
+ throw new RangeError('`j/J/C` (hour) patterns are not supported, use `h/H/K/k` instead');
262
+ // Minute
263
+
264
+ case 'm':
265
+ result.push(['minute', ['numeric', '2-digit'][len - 1], len]);
266
+ break;
267
+ // Second
268
+
269
+ case 's':
270
+ result.push(['second', ['numeric', '2-digit'][len - 1], len]);
271
+ break;
272
+
273
+ case 'S':
274
+ result.push(['fractionalSecondDigits', len, len]);
275
+ break;
276
+
277
+ case 'A':
278
+ throw new RangeError('`S/A` (millisecond) patterns are not supported, use `s` instead');
279
+ // Zone
280
+
281
+ case 'O':
282
+ // timeZone GMT-8 or GMT-08:00
283
+ result.push(['timeZoneName', len < 4 ? 'shortOffset' : 'longOffset', len]);
284
+ result.push(['x-timeZoneName', len < 4 ? 'O' : 'OOOO', len]);
285
+ break;
286
+
287
+ case 'X': // 1, 2, 3, 4: The ISO8601 varios formats
288
+
289
+ case 'x': // 1, 2, 3, 4: The ISO8601 varios formats
290
+
291
+ case 'Z':
292
+ // 1..3, 4, 5: The ISO8601 varios formats
293
+ // Z, ZZ, ZZZ should produce -0800
294
+ // ZZZZ should produce GMT-08:00
295
+ // ZZZZZ should produce -8:00 or -07:52:58
296
+ result.push(['timeZoneName', 'longOffset', 1]);
297
+ result.push(['x-timeZoneName', match, 1]);
298
+ break;
299
+
300
+ case 'z': // 1..3, 4: specific non-location format
301
+
302
+ case 'v': // 1, 4: generic non-location format
303
+
304
+ case 'V':
305
+ // 1, 2, 3, 4: time zone ID or city
306
+ throw new RangeError('z/v/V` (timeZone) patterns are not supported, use `X/x/Z/O` instead');
307
+
308
+ case '\'':
309
+ result.push(['literal', match.slice(1, -1).replace(/''/g, '\''), -1]);
310
+ break;
311
+
312
+ default:
313
+ result.push(['literal', match, -1]);
314
+ }
315
+
316
+ return '';
317
+ });
318
+ return result;
319
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "formatDate", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _DateParser.formatDate;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "getSkeleton", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _SkeletonParser.getSkeleton;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "parseDate", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _DateParser.parseDate;
22
+ }
23
+ });
24
+
25
+ var _DateParser = require("./DateParser.js");
26
+
27
+ var _SkeletonParser = require("./SkeletonParser.js");
package/lib/index.js ADDED
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.format = void 0;
7
+ Object.defineProperty(exports, "formatDate", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _index.formatDate;
11
+ }
12
+ });
13
+ Object.defineProperty(exports, "formatNumber", {
14
+ enumerable: true,
15
+ get: function () {
16
+ return _NumberParser.formatNumber;
17
+ }
18
+ });
19
+ exports.parse = void 0;
20
+ Object.defineProperty(exports, "parseDate", {
21
+ enumerable: true,
22
+ get: function () {
23
+ return _index.parseDate;
24
+ }
25
+ });
26
+ Object.defineProperty(exports, "parseDateSkeleton", {
27
+ enumerable: true,
28
+ get: function () {
29
+ return _index.getSkeleton;
30
+ }
31
+ });
32
+ Object.defineProperty(exports, "parseNumber", {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _NumberParser.parseNumber;
36
+ }
37
+ });
38
+
39
+ var _index = require("./date/index.js");
40
+
41
+ var _NumberParser = require("./number/NumberParser.js");
42
+
43
+ /*************************************************************************
44
+ * ADOBE CONFIDENTIAL
45
+ * ___________________
46
+ *
47
+ * Copyright 2022 Adobe
48
+ * All Rights Reserved.
49
+ *
50
+ * NOTICE: All information contained herein is, and remains
51
+ * the property of Adobe and its suppliers, if any. The intellectual
52
+ * and technical concepts contained herein are proprietary to Adobe
53
+ * and its suppliers and are protected by all applicable intellectual
54
+ * property laws, including trade secret and copyright laws.
55
+ * Dissemination of this information or reproduction of this material
56
+ * is strictly forbidden unless prior written permission is obtained
57
+ * from Adobe.
58
+
59
+ * Adobe permits you to use and modify this file solely in accordance with
60
+ * the terms of the Adobe license agreement accompanying it.
61
+ *************************************************************************/
62
+ const getCategory = function (skeleton) {
63
+ const chkCategory = skeleton === null || skeleton === void 0 ? void 0 : skeleton.match(/^(?:(num|date)\|)?(.+)/);
64
+ return [chkCategory === null || chkCategory === void 0 ? void 0 : chkCategory[1], chkCategory === null || chkCategory === void 0 ? void 0 : chkCategory[2]];
65
+ };
66
+
67
+ const format = function (value, locale, skeleton, timezone) {
68
+ const [category, skelton] = getCategory(skeleton);
69
+
70
+ switch (category) {
71
+ case 'date':
72
+ if (!(value instanceof Date)) {
73
+ value = new Date(value);
74
+ }
75
+
76
+ return (0, _index.formatDate)(value, locale, skelton, timezone);
77
+
78
+ case 'num':
79
+ return (0, _NumberParser.formatNumber)(value, locale, skelton);
80
+
81
+ default:
82
+ throw `unable to deduce the format. The skeleton should be date|<format> for date formats and num|<format> for numbers`;
83
+ }
84
+ };
85
+
86
+ exports.format = format;
87
+
88
+ const parse = function (value, locale, skeleton, timezone) {
89
+ const [category, skelton] = getCategory(skeleton);
90
+
91
+ switch (category) {
92
+ case 'date':
93
+ return (0, _index.parseDate)(value, locale, skelton, timezone);
94
+
95
+ case 'number':
96
+ return (0, _NumberParser.parseNumber)(value, locale, skelton);
97
+
98
+ default:
99
+ throw `unable to deduce the format. The skeleton should be date|<format> for date formats and num|<format> for numbers`;
100
+ }
101
+ };
102
+
103
+ exports.parse = parse;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.formatNumber = formatNumber;
7
+ exports.parseDefaultNumber = parseDefaultNumber;
8
+ exports.parseNumber = parseNumber;
9
+
10
+ var _SkeletonParser = require("./SkeletonParser.js");
11
+
12
+ /*************************************************************************
13
+ * ADOBE CONFIDENTIAL
14
+ * ___________________
15
+ *
16
+ * Copyright 2022 Adobe
17
+ * All Rights Reserved.
18
+ *
19
+ * NOTICE: All information contained herein is, and remains
20
+ * the property of Adobe and its suppliers, if any. The intellectual
21
+ * and technical concepts contained herein are proprietary to Adobe
22
+ * and its suppliers and are protected by all applicable intellectual
23
+ * property laws, including trade secret and copyright laws.
24
+ * Dissemination of this information or reproduction of this material
25
+ * is strictly forbidden unless prior written permission is obtained
26
+ * from Adobe.
27
+
28
+ * Adobe permits you to use and modify this file solely in accordance with
29
+ * the terms of the Adobe license agreement accompanying it.
30
+ *************************************************************************/
31
+ function formatNumber(numberValue, language, skeletn) {
32
+ if (skeletn.startsWith('num|')) {
33
+ skeletn = skel.split('|')[1];
34
+ }
35
+
36
+ if (!skeletn) return numberValue;
37
+ language = language || "en";
38
+ const {
39
+ options,
40
+ order
41
+ } = (0, _SkeletonParser.parseNumberSkeleton)(skeletn, language);
42
+ return new Intl.NumberFormat(language, options).format(numberValue);
43
+ }
44
+
45
+ function getMetaInfo(language, skel) {
46
+ const parts = {}; // gather digits and radix symbol
47
+
48
+ let options = new Intl.NumberFormat(language, {
49
+ style: 'decimal',
50
+ useGrouping: false
51
+ }).formatToParts(9876543210.1);
52
+ parts.digits = options.find(p => p.type === 'integer').value.split('').reverse();
53
+ parts.decimal = options.find(p => p.type === 'decimal').value; // extract type values from the parts
54
+
55
+ const gather = type => {
56
+ const find = options.find(p => p.type === type);
57
+ if (find) parts[type] = find.value;
58
+ }; // now gather the localized parts that correspond to the provided skeleton.
59
+
60
+
61
+ const parsed = (0, _SkeletonParser.parseNumberSkeleton)(skel);
62
+ const nf = new Intl.NumberFormat(language, parsed);
63
+ options = nf.formatToParts(-987654321);
64
+ gather('group');
65
+ gather('minusSign');
66
+ gather('percentSign'); // it's possible to have multiple currency representations in a single value
67
+
68
+ parts.currency = options.filter(p => p.type === 'currency').map(p => p.value); // collect all literals. Most likely a literal is an accounting bracket
69
+
70
+ parts.literal = options.filter(p => p.type === 'literal').map(p => p.value);
71
+ options = nf.formatToParts(987654321);
72
+ gather('plusSign');
73
+ gather('exponentSeparator');
74
+ gather('unit');
75
+ return parts;
76
+ }
77
+
78
+ function parseNumber(numberString, language, skel) {
79
+ try {
80
+ // factor will be updated to reflect: negative, percent, exponent etc.
81
+ if (skel.startsWith('num|')) {
82
+ skel = skel.split('|')[1];
83
+ }
84
+
85
+ let factor = 1;
86
+ let number = numberString;
87
+ const meta = getMetaInfo(language, skel);
88
+ if (meta.group) number = number.replaceAll(meta.group, '');
89
+ number = number.replace(meta.decimal, '.');
90
+ if (meta.unit) number = number.replaceAll(meta.unit, '');
91
+
92
+ if (meta.minusSign && number.includes(meta.minusSign)) {
93
+ number = number.replace(meta.minusSign, '');
94
+ factor *= -1;
95
+ }
96
+
97
+ if (meta.percentSign && number.includes(meta.percentSign)) {
98
+ factor = factor / 100;
99
+ number = number.replace(meta.percentSign, '');
100
+ }
101
+
102
+ meta.currency.forEach(currency => number = number.replace(currency, ''));
103
+ meta.literal.forEach(literal => {
104
+ if (number.includes(literal)) {
105
+ if (literal === '(') factor = factor * -1;
106
+ number = number.replace(literal, '');
107
+ }
108
+ });
109
+ if (meta.plusSign) number = number.replace(meta.plusSign, '');
110
+
111
+ if (meta.exponentSeparator) {
112
+ let e;
113
+ [number, e] = number.split(meta.exponentSeparator);
114
+ factor = factor * Math.pow(10, e);
115
+ }
116
+
117
+ const result = factor * number;
118
+ return isNaN(result) ? numberString : result;
119
+ } catch (e) {
120
+ console.dir(e);
121
+ return numberString;
122
+ }
123
+ }
124
+
125
+ function parseDefaultNumber(numberString, language) {
126
+ const currency = currencies[language] || 'USD';
127
+ return parseNumber(numberString, language, `currency/${currency}`);
128
+ }