@aemforms/af-formatters 0.22.19 → 0.22.22
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/LICENSE +19 -0
- package/lib/cjs/index.cjs +781 -0
- package/lib/esm/date/DateParser.js +320 -0
- package/lib/esm/date/SkeletonParser.js +199 -0
- package/lib/esm/date/index.js +22 -0
- package/lib/esm/index.js +57 -0
- package/lib/esm/number/NumberParser.js +100 -0
- package/lib/esm/number/SkeletonParser.js +173 -0
- package/lib/esm/number/currencies.js +56 -0
- package/package.json +9 -5
- package/lib/date/DateParser.js +0 -522
- package/lib/date/SkeletonParser.js +0 -315
- package/lib/date/index.js +0 -27
- package/lib/index.js +0 -25
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*************************************************************************
|
|
2
|
+
* ADOBE CONFIDENTIAL
|
|
3
|
+
* ___________________
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2022 Adobe
|
|
6
|
+
* All Rights Reserved.
|
|
7
|
+
*
|
|
8
|
+
* NOTICE: All information contained herein is, and remains
|
|
9
|
+
* the property of Adobe and its suppliers, if any. The intellectual
|
|
10
|
+
* and technical concepts contained herein are proprietary to Adobe
|
|
11
|
+
* and its suppliers and are protected by all applicable intellectual
|
|
12
|
+
* property laws, including trade secret and copyright laws.
|
|
13
|
+
* Dissemination of this information or reproduction of this material
|
|
14
|
+
* is strictly forbidden unless prior written permission is obtained
|
|
15
|
+
* from Adobe.
|
|
16
|
+
|
|
17
|
+
* Adobe permits you to use and modify this file solely in accordance with
|
|
18
|
+
* the terms of the Adobe license agreement accompanying it.
|
|
19
|
+
*************************************************************************/
|
|
20
|
+
|
|
21
|
+
import { parseNumberSkeleton } from './SkeletonParser.js';
|
|
22
|
+
import './currencies.js';
|
|
23
|
+
|
|
24
|
+
function formatNumber(numberValue, language, skeletn) {
|
|
25
|
+
if (skeletn.startsWith('num|')) {
|
|
26
|
+
skeletn = skel.split('|')[1];
|
|
27
|
+
}
|
|
28
|
+
if (!skeletn) return numberValue
|
|
29
|
+
language = language || "en";
|
|
30
|
+
const {options, order} = parseNumberSkeleton(skeletn, language);
|
|
31
|
+
return new Intl.NumberFormat(language, options).format(numberValue);
|
|
32
|
+
}
|
|
33
|
+
function getMetaInfo(language, skel) {
|
|
34
|
+
const parts = {};
|
|
35
|
+
let options = new Intl.NumberFormat(language, {style:'decimal', useGrouping:false}).formatToParts(9876543210.1);
|
|
36
|
+
parts.digits = options.find(p => p.type === 'integer').value.split('').reverse();
|
|
37
|
+
parts.decimal = options.find(p => p.type === 'decimal').value;
|
|
38
|
+
const gather = type => {
|
|
39
|
+
const find = options.find(p => p.type === type);
|
|
40
|
+
if (find) parts[type] = find.value;
|
|
41
|
+
};
|
|
42
|
+
const parsed = parseNumberSkeleton(skel);
|
|
43
|
+
const nf = new Intl.NumberFormat(language, parsed);
|
|
44
|
+
options = nf.formatToParts(-987654321);
|
|
45
|
+
gather('group');
|
|
46
|
+
gather('minusSign');
|
|
47
|
+
gather('percentSign');
|
|
48
|
+
parts.currency = options.filter(p => p.type === 'currency').map(p => p.value);
|
|
49
|
+
parts.literal = options.filter(p => p.type === 'literal').map(p => p.value);
|
|
50
|
+
options = nf.formatToParts(987654321);
|
|
51
|
+
gather('plusSign');
|
|
52
|
+
gather('exponentSeparator');
|
|
53
|
+
gather('unit');
|
|
54
|
+
return parts;
|
|
55
|
+
}
|
|
56
|
+
function parseNumber(numberString, language, skel) {
|
|
57
|
+
try {
|
|
58
|
+
if (skel.startsWith('num|')) {
|
|
59
|
+
skel = skel.split('|')[1];
|
|
60
|
+
}
|
|
61
|
+
let factor = 1;
|
|
62
|
+
let number = numberString;
|
|
63
|
+
const meta = getMetaInfo(language, skel);
|
|
64
|
+
if (meta.group) number = number.replaceAll(meta.group, '');
|
|
65
|
+
number = number.replace(meta.decimal, '.');
|
|
66
|
+
if (meta.unit) number = number.replaceAll(meta.unit, '');
|
|
67
|
+
if (meta.minusSign && number.includes(meta.minusSign)) {
|
|
68
|
+
number = number.replace(meta.minusSign, '');
|
|
69
|
+
factor *= -1;
|
|
70
|
+
}
|
|
71
|
+
if (meta.percentSign && number.includes(meta.percentSign)) {
|
|
72
|
+
factor = factor/100;
|
|
73
|
+
number = number.replace(meta.percentSign, '');
|
|
74
|
+
}
|
|
75
|
+
meta.currency.forEach(currency => number = number.replace(currency, ''));
|
|
76
|
+
meta.literal.forEach(literal => {
|
|
77
|
+
if (number.includes(literal)) {
|
|
78
|
+
if (literal === '(') factor = factor * -1;
|
|
79
|
+
number = number.replace(literal, '');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
if (meta.plusSign) number = number.replace(meta.plusSign, '');
|
|
83
|
+
if (meta.exponentSeparator) {
|
|
84
|
+
let e;
|
|
85
|
+
[number, e] = number.split(meta.exponentSeparator);
|
|
86
|
+
factor = factor * Math.pow(10, e);
|
|
87
|
+
}
|
|
88
|
+
const result = factor * number;
|
|
89
|
+
return isNaN(result) ? numberString : result;
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.dir(e);
|
|
92
|
+
return numberString;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function parseDefaultNumber(numberString, language) {
|
|
96
|
+
const currency = currencies[language] || 'USD';
|
|
97
|
+
return parseNumber(numberString, language, `currency/${currency}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { formatNumber, parseDefaultNumber, parseNumber };
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/*************************************************************************
|
|
2
|
+
* ADOBE CONFIDENTIAL
|
|
3
|
+
* ___________________
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2022 Adobe
|
|
6
|
+
* All Rights Reserved.
|
|
7
|
+
*
|
|
8
|
+
* NOTICE: All information contained herein is, and remains
|
|
9
|
+
* the property of Adobe and its suppliers, if any. The intellectual
|
|
10
|
+
* and technical concepts contained herein are proprietary to Adobe
|
|
11
|
+
* and its suppliers and are protected by all applicable intellectual
|
|
12
|
+
* property laws, including trade secret and copyright laws.
|
|
13
|
+
* Dissemination of this information or reproduction of this material
|
|
14
|
+
* is strictly forbidden unless prior written permission is obtained
|
|
15
|
+
* from Adobe.
|
|
16
|
+
|
|
17
|
+
* Adobe permits you to use and modify this file solely in accordance with
|
|
18
|
+
* the terms of the Adobe license agreement accompanying it.
|
|
19
|
+
*************************************************************************/
|
|
20
|
+
|
|
21
|
+
import { getCurrency } from './currencies.js';
|
|
22
|
+
|
|
23
|
+
const NUMBER_REGEX =
|
|
24
|
+
/(?:[#]+|[@]+(#+)?|[0]+|[,]|[.]|[-]|[+]|[%]|[¤]{1,4}(?:\/([a-zA-Z]{3}))?|[;]|[K]{1,2}|E{1,2}[+]?|'(?:[^']|'')*')|[^a-zA-Z']+/g;
|
|
25
|
+
const supportedUnits = ['acre', 'bit', 'byte', 'celsius', 'centimeter', 'day',
|
|
26
|
+
'degree', 'fahrenheit', 'fluid-ounce', 'foot', 'gallon', 'gigabit',
|
|
27
|
+
'gigabyte', 'gram', 'hectare', 'hour', 'inch', 'kilobit', 'kilobyte',
|
|
28
|
+
'kilogram', 'kilometer', 'liter', 'megabit', 'megabyte', 'meter', 'mile',
|
|
29
|
+
'mile-scandinavian', 'milliliter', 'millimeter', 'millisecond', 'minute', 'month',
|
|
30
|
+
'ounce', 'percent', 'petabyte', 'pound', 'second', 'stone', 'terabit', 'terabyte', 'week', 'yard', 'year'].join('|');
|
|
31
|
+
const ShorthandStyles = [/^currency(?:\/([a-zA-Z]{3}))?$/, /^decimal$/, /^integer$/, /^percent$/, new RegExp(`^unit\/(${supportedUnits})$`)];
|
|
32
|
+
function parseNumberSkeleton(skeleton, language) {
|
|
33
|
+
const options = {};
|
|
34
|
+
const order = [];
|
|
35
|
+
let match, index;
|
|
36
|
+
for (index = 0; index < ShorthandStyles.length && match == null; index++) {
|
|
37
|
+
match = ShorthandStyles[index].exec(skeleton);
|
|
38
|
+
}
|
|
39
|
+
if (match) {
|
|
40
|
+
switch(index) {
|
|
41
|
+
case 1:
|
|
42
|
+
options.style = 'currency';
|
|
43
|
+
options.currencyDisplay = 'narrowSymbol';
|
|
44
|
+
if (match[1]) {
|
|
45
|
+
options.currency = match[1];
|
|
46
|
+
} else {
|
|
47
|
+
options.currency = getCurrency(language);
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 2:
|
|
51
|
+
new Intl.NumberFormat(language, {}).resolvedOptions();
|
|
52
|
+
options.minimumFractionDigits = options.minimumFractionDigits || 2;
|
|
53
|
+
break;
|
|
54
|
+
case 3:
|
|
55
|
+
options.minimumFractionDigits = 0;
|
|
56
|
+
options.maximumFractionDigits = 0;
|
|
57
|
+
break;
|
|
58
|
+
case 4:
|
|
59
|
+
options.style = 'percent';
|
|
60
|
+
options.maximumFractionDigits = 2;
|
|
61
|
+
break;
|
|
62
|
+
case 5:
|
|
63
|
+
options.style = "unit";
|
|
64
|
+
options.unitDisplay = "long";
|
|
65
|
+
options.unit = match[1];
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
options,
|
|
70
|
+
order
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
options.useGrouping = false;
|
|
74
|
+
options.minimumIntegerDigits = 1;
|
|
75
|
+
options.maximumFractionDigits = 0;
|
|
76
|
+
options.minimumFractionDigits = 0;
|
|
77
|
+
skeleton.replace(NUMBER_REGEX, (match, maxSignificantDigits, currencySymbol, offset) => {
|
|
78
|
+
const len = match.length;
|
|
79
|
+
switch(match[0]) {
|
|
80
|
+
case '#':
|
|
81
|
+
order.push(['digit', len]);
|
|
82
|
+
if (options?.decimal === true) {
|
|
83
|
+
options.maximumFractionDigits = options.minimumFractionDigits + len;
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
case '@':
|
|
87
|
+
if (options?.minimumSignificantDigits) {
|
|
88
|
+
throw "@ symbol should occur together"
|
|
89
|
+
}
|
|
90
|
+
const hashes = maxSignificantDigits || "";
|
|
91
|
+
order.push(['@', len - hashes.length]);
|
|
92
|
+
options.minimumSignificantDigits = len - hashes.length;
|
|
93
|
+
options.maximumSignificantDigits = len;
|
|
94
|
+
order.push(['digit', hashes.length]);
|
|
95
|
+
break;
|
|
96
|
+
case ',':
|
|
97
|
+
if (options?.decimal === true) {
|
|
98
|
+
throw "grouping character not supporting for fractions"
|
|
99
|
+
}
|
|
100
|
+
order.push(['group', 1]);
|
|
101
|
+
options.useGrouping = 'auto';
|
|
102
|
+
break;
|
|
103
|
+
case '.':
|
|
104
|
+
if (options?.decimal) {
|
|
105
|
+
console.error("only one decimal symbol is allowed");
|
|
106
|
+
} else {
|
|
107
|
+
order.push(['decimal', 1]);
|
|
108
|
+
options.decimal = true;
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
case '0':
|
|
112
|
+
order.push('0', len);
|
|
113
|
+
if(options.minimumSignificantDigits || options.maximumSignificantDigits) {
|
|
114
|
+
throw "0 is not supported with @"
|
|
115
|
+
}
|
|
116
|
+
if (options?.decimal === true) {
|
|
117
|
+
options.minimumFractionDigits = len;
|
|
118
|
+
if (!options.maximumFractionDigits) {
|
|
119
|
+
options.maximumFractionDigits = len;
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
options.minimumIntegerDigits = len;
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
case '-':
|
|
126
|
+
if (offset !== 0) {
|
|
127
|
+
console.error("sign display is always in the beginning");
|
|
128
|
+
}
|
|
129
|
+
options.signDisplay = 'negative';
|
|
130
|
+
order.push(['signDisplay', 1, '-']);
|
|
131
|
+
break;
|
|
132
|
+
case '+':
|
|
133
|
+
if (offset !== 0 && order[order.length - 1][0] === 'E') {
|
|
134
|
+
console.error("sign display is always in the beginning");
|
|
135
|
+
}
|
|
136
|
+
if (offset === 0) {
|
|
137
|
+
options.signDisplay = 'always';
|
|
138
|
+
}
|
|
139
|
+
order.push(['signDisplay', 1, '+']);
|
|
140
|
+
break;
|
|
141
|
+
case '¤':
|
|
142
|
+
if (offset !== 0 && offset !== skeleton.length - 1) {
|
|
143
|
+
console.error("currency display should be either in the beginning or at the end");
|
|
144
|
+
} else {
|
|
145
|
+
options.style = 'currency';
|
|
146
|
+
options.currencyDisplay = ['symbol', 'code', 'name', 'narrowSymbol'][len - 1];
|
|
147
|
+
options.currency = currencySymbol || getCurrency(language);
|
|
148
|
+
order.push(['currency', len]);
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
case '%':
|
|
152
|
+
if (offset !== 0 && offset !== skeleton.length - 1) {
|
|
153
|
+
console.error("percent display should be either in the beginning or at the end");
|
|
154
|
+
} else {
|
|
155
|
+
order.push(['%', 1]);
|
|
156
|
+
options.style = 'percent';
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
case 'E':
|
|
160
|
+
order.push(['E', len]);
|
|
161
|
+
options.style = ['scientific','engineering'](len - 1);
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
console.error("unknown chars" + match);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
options,
|
|
169
|
+
order
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { ShorthandStyles, parseNumberSkeleton };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*************************************************************************
|
|
2
|
+
* ADOBE CONFIDENTIAL
|
|
3
|
+
* ___________________
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2022 Adobe
|
|
6
|
+
* All Rights Reserved.
|
|
7
|
+
*
|
|
8
|
+
* NOTICE: All information contained herein is, and remains
|
|
9
|
+
* the property of Adobe and its suppliers, if any. The intellectual
|
|
10
|
+
* and technical concepts contained herein are proprietary to Adobe
|
|
11
|
+
* and its suppliers and are protected by all applicable intellectual
|
|
12
|
+
* property laws, including trade secret and copyright laws.
|
|
13
|
+
* Dissemination of this information or reproduction of this material
|
|
14
|
+
* is strictly forbidden unless prior written permission is obtained
|
|
15
|
+
* from Adobe.
|
|
16
|
+
|
|
17
|
+
* Adobe permits you to use and modify this file solely in accordance with
|
|
18
|
+
* the terms of the Adobe license agreement accompanying it.
|
|
19
|
+
*************************************************************************/
|
|
20
|
+
|
|
21
|
+
const currencies = {
|
|
22
|
+
'da-DK': 'DKK',
|
|
23
|
+
'de-DE': 'EUR',
|
|
24
|
+
'en-US': 'USD',
|
|
25
|
+
'en-GB': 'GBP',
|
|
26
|
+
'es-ES': 'EUR',
|
|
27
|
+
'fi-FI': 'EUR',
|
|
28
|
+
'fr-FR': 'EUR',
|
|
29
|
+
'it-IT': 'EUR',
|
|
30
|
+
'ja-JP': 'JPY',
|
|
31
|
+
'nb-NO': 'NOK',
|
|
32
|
+
'nl-NL': 'EUR',
|
|
33
|
+
'pt-BR': 'BRL',
|
|
34
|
+
'sv-SE': 'SEK',
|
|
35
|
+
'zh-CN': 'CNY',
|
|
36
|
+
'zh-TW': 'TWD',
|
|
37
|
+
'ko-KR': 'KRW',
|
|
38
|
+
'cs-CZ': 'CZK',
|
|
39
|
+
'pl-PL': 'PLN',
|
|
40
|
+
'ru-RU': 'RUB',
|
|
41
|
+
'tr-TR': 'TRY'
|
|
42
|
+
};
|
|
43
|
+
const locales = Object.keys(currencies);
|
|
44
|
+
const getCurrency = function (locale) {
|
|
45
|
+
if (locales.indexOf(locale) > -1) {
|
|
46
|
+
return currencies[locale]
|
|
47
|
+
} else {
|
|
48
|
+
const matchingLocale = locales.find(x => x.startsWith(locale));
|
|
49
|
+
if (matchingLocale) {
|
|
50
|
+
return currencies[matchingLocale]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return ''
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export { getCurrency };
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aemforms/af-formatters",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.22",
|
|
4
4
|
"description": "Core Module for Forms Runtime",
|
|
5
5
|
"author": "Adobe Systems",
|
|
6
6
|
"license": "Adobe Proprietary",
|
|
7
|
-
"main": "lib/index.
|
|
7
|
+
"main": "lib/cjs/index.cjs",
|
|
8
8
|
"directories": {
|
|
9
9
|
"lib": "lib",
|
|
10
10
|
"source": "src",
|
|
11
11
|
"test": "src/__tests__"
|
|
12
12
|
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./lib/esm/index.js"
|
|
16
|
+
},
|
|
13
17
|
"publishConfig": {
|
|
14
18
|
"access": "public"
|
|
15
19
|
},
|
|
@@ -24,11 +28,11 @@
|
|
|
24
28
|
"LICENSE"
|
|
25
29
|
],
|
|
26
30
|
"scripts": {
|
|
27
|
-
"test": "jest --silent",
|
|
31
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest --silent",
|
|
28
32
|
"eslint": "npx eslint src/**",
|
|
29
33
|
"eslint:fix": "npx eslint --fix src/**",
|
|
30
|
-
"test:ci": "jest --silent --coverage",
|
|
31
|
-
"build": "
|
|
34
|
+
"test:ci": "NODE_OPTIONS=--experimental-vm-modules jest --silent --coverage",
|
|
35
|
+
"build": "npm run clean && mkdir -p lib/esm && cp -R src/* lib/esm/ && rollup -c rollup.config.js",
|
|
32
36
|
"clean": "rm -rf lib target",
|
|
33
37
|
"prepublishOnly": "npm run build && npm run test",
|
|
34
38
|
"docs": "npx typedoc --options .typedoc.cjs"
|