reduce-precision 0.0.2
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 +21 -0
- package/README.md +96 -0
- package/lib/format/index.d.ts +16 -0
- package/lib/format/index.js +402 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +8 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 ArzDigital
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# reduce-precision
|
|
2
|
+
|
|
3
|
+
`reduce-precision` is a versatile JavaScript/TypeScript package for formatting and reducing the precision of numbers, currencies, and percentages. It supports various templates, precision levels, languages, and output formats, making it easy to generate formatted strings for different use cases.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Format numbers with customizable precision levels: high, medium, low, or auto
|
|
8
|
+
- Support for multiple templates: number, USD, IRT (Iranian Toman), IRR (Iranian Rial), and percent
|
|
9
|
+
- Multilingual support: English and Persian (Farsi)
|
|
10
|
+
- Output formats: plain text, HTML, and Markdown
|
|
11
|
+
- Customizable prefix and postfix markers for HTML and Markdown output
|
|
12
|
+
- Intelligent handling of very small and very large numbers
|
|
13
|
+
- Automatic thousand separators and decimal points based on the selected language
|
|
14
|
+
- TypeScript type definitions included
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
You can install `reduce-precision` using npm:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install reduce-precision
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### JavaScript (CommonJS)
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
const { format } = require('reduce-precision');
|
|
30
|
+
|
|
31
|
+
const formatted = format(123456, options);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### TypeScript or ES Modules
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { format } from 'reduce-precision';
|
|
38
|
+
|
|
39
|
+
const formatted = format(123456, options);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Options
|
|
43
|
+
|
|
44
|
+
The `format` function accepts an optional `options` object with the following properties:
|
|
45
|
+
|
|
46
|
+
| Option | Type | Default | Description |
|
|
47
|
+
| ------------- | ------------------------------------------- | --------- | ------------------------------------------------------------------ |
|
|
48
|
+
| `precision` | `'auto'` \| `'high'` \| `'medium'` \| `'low'` | `'high'` | Precision level for formatting |
|
|
49
|
+
| `template` | `'number'` \| `'usd'` \| `'irt'` \| `'irr'` \| `'percent'` | `'number'` | Template for formatting |
|
|
50
|
+
| `language` | `'en'` \| `'fa'` | `'en'` | Language for formatting (English or Persian) |
|
|
51
|
+
| `outputFormat` | `'plain'` \| `'html'` \| `'markdown'` | `'plain'` | Output format |
|
|
52
|
+
| `prefixMarker` | `string` | `'i'` | Prefix marker for HTML and Markdown output |
|
|
53
|
+
| `postfixMarker` | `string` | `'i'` | Postfix marker for HTML and Markdown output |
|
|
54
|
+
| `prefix` | `string` | `''` | Prefix string to be added before the formatted number |
|
|
55
|
+
| `postfix` | `string` | `''` | Postfix string to be added after the formatted number |
|
|
56
|
+
|
|
57
|
+
## Examples
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { format } from 'reduce-precision';
|
|
61
|
+
|
|
62
|
+
// Basic number formatting
|
|
63
|
+
format(1234.5678); // Output: 1,234.5678
|
|
64
|
+
|
|
65
|
+
// Formatting with medium precision
|
|
66
|
+
format(1234.5678, { precision: 'medium' }); // Output: 1,234.57
|
|
67
|
+
|
|
68
|
+
// Formatting as USD
|
|
69
|
+
format(1234.5678, { template: 'usd' }); // Output: $1,234.5678
|
|
70
|
+
|
|
71
|
+
// Formatting as Iranian Rial with Persian numerals
|
|
72
|
+
format(1234.5678, { template: 'irr', language: 'fa' }); // Output: ۱٬۲۳۴٫۵۷ ر
|
|
73
|
+
|
|
74
|
+
// Formatting as a percentage with low precision
|
|
75
|
+
format(0.1234, { template: 'percent', precision: 'low' }); // Output: 12%
|
|
76
|
+
|
|
77
|
+
// Formatting with HTML output and custom markers
|
|
78
|
+
format(1234.5678, { outputFormat: 'html', prefixMarker: 'strong', prefix: 'USD ' });
|
|
79
|
+
// Output: <strong>USD </strong>1,234.5678
|
|
80
|
+
|
|
81
|
+
// Formatting with string input for small or big numbers
|
|
82
|
+
format("0.00000000000000000000005678521", { template: 'usd', precision: 'medium' });
|
|
83
|
+
// Output: $0.0₂₂5678
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## TypeScript
|
|
87
|
+
|
|
88
|
+
`reduce-precision` is written in TypeScript and includes type definitions for all exported functions and interfaces.
|
|
89
|
+
|
|
90
|
+
## Contributing
|
|
91
|
+
|
|
92
|
+
Contributions are welcome! If you find a bug or have a feature request, please open an issue on the [GitHub repository](https://github.com/ArzDigitalLabs/reduce-precision). If you'd like to contribute code, please fork the repository and submit a pull request.
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare type Template = 'number' | 'usd' | 'irt' | 'irr' | 'percent';
|
|
2
|
+
declare type Precision = 'auto' | 'high' | 'medium' | 'low';
|
|
3
|
+
declare type Language = 'en' | 'fa';
|
|
4
|
+
declare type OutputFormat = 'plain' | 'html' | 'markdown';
|
|
5
|
+
interface Options {
|
|
6
|
+
precision?: Precision;
|
|
7
|
+
template?: Template;
|
|
8
|
+
language?: Language;
|
|
9
|
+
outputFormat?: OutputFormat;
|
|
10
|
+
prefixMarker?: string;
|
|
11
|
+
postfixMarker?: string;
|
|
12
|
+
prefix?: string;
|
|
13
|
+
postfix?: string;
|
|
14
|
+
}
|
|
15
|
+
declare function format(input: string | number, options?: Options): string | number;
|
|
16
|
+
export default format;
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function isENotation(input) {
|
|
4
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/.test(input);
|
|
5
|
+
}
|
|
6
|
+
function convertENotationToRegularNumber(eNotation) {
|
|
7
|
+
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
8
|
+
const coefficientLength = coefficientStr
|
|
9
|
+
.replace('.', '')
|
|
10
|
+
.replace('-', '').length;
|
|
11
|
+
const exponent = parseFloat(exponentStr);
|
|
12
|
+
const precision = Math.max(coefficientLength - exponent, 1);
|
|
13
|
+
return eNotation.toFixed(precision);
|
|
14
|
+
}
|
|
15
|
+
function format(input, options = {
|
|
16
|
+
precision: 'high',
|
|
17
|
+
template: 'number',
|
|
18
|
+
language: 'en',
|
|
19
|
+
outputFormat: 'plain',
|
|
20
|
+
prefixMarker: 'i',
|
|
21
|
+
postfixMarker: 'i',
|
|
22
|
+
prefix: '',
|
|
23
|
+
postfix: '',
|
|
24
|
+
}) {
|
|
25
|
+
let { precision, template } = options;
|
|
26
|
+
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = options;
|
|
27
|
+
if (!input)
|
|
28
|
+
return 0;
|
|
29
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g)))
|
|
30
|
+
template = 'number';
|
|
31
|
+
if (isENotation(input.toString())) {
|
|
32
|
+
input = convertENotationToRegularNumber(Number(input));
|
|
33
|
+
}
|
|
34
|
+
// Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
|
|
35
|
+
let numberString = input
|
|
36
|
+
.toString()
|
|
37
|
+
.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
|
|
38
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
39
|
+
})
|
|
40
|
+
.replace(/[^\d.-]/g, '');
|
|
41
|
+
// Stripping leading zeros and trailing zeros after a decimal point
|
|
42
|
+
numberString = numberString
|
|
43
|
+
.replace(/^0+(?=\d)/g, '')
|
|
44
|
+
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
45
|
+
const number = Math.abs(Number(numberString));
|
|
46
|
+
let p, d, r, c;
|
|
47
|
+
let f = 0;
|
|
48
|
+
// Auto precision selection
|
|
49
|
+
if (precision === 'auto') {
|
|
50
|
+
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
51
|
+
if (number >= 0.0001 && number < 100000000000) {
|
|
52
|
+
precision = 'high';
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
precision = 'medium';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (template === 'number') {
|
|
59
|
+
precision = 'medium';
|
|
60
|
+
}
|
|
61
|
+
else if (template === 'percent') {
|
|
62
|
+
precision = 'low';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (precision === 'medium') {
|
|
66
|
+
if (number >= 0 && number < 0.0001) {
|
|
67
|
+
p = 33;
|
|
68
|
+
d = 4;
|
|
69
|
+
r = false;
|
|
70
|
+
c = true;
|
|
71
|
+
}
|
|
72
|
+
else if (number >= 0.0001 && number < 0.001) {
|
|
73
|
+
p = 7;
|
|
74
|
+
d = 4;
|
|
75
|
+
r = false;
|
|
76
|
+
c = false;
|
|
77
|
+
}
|
|
78
|
+
else if (number >= 0.001 && number < 0.01) {
|
|
79
|
+
p = 5;
|
|
80
|
+
d = 3;
|
|
81
|
+
r = false;
|
|
82
|
+
c = false;
|
|
83
|
+
}
|
|
84
|
+
else if (number >= 0.001 && number < 0.1) {
|
|
85
|
+
p = 3;
|
|
86
|
+
d = 2;
|
|
87
|
+
r = false;
|
|
88
|
+
c = false;
|
|
89
|
+
}
|
|
90
|
+
else if (number >= 0.1 && number < 1) {
|
|
91
|
+
p = 1;
|
|
92
|
+
d = 1;
|
|
93
|
+
r = false;
|
|
94
|
+
c = false;
|
|
95
|
+
}
|
|
96
|
+
else if (number >= 1 && number < 10) {
|
|
97
|
+
p = 3;
|
|
98
|
+
d = 3;
|
|
99
|
+
r = false;
|
|
100
|
+
c = false;
|
|
101
|
+
}
|
|
102
|
+
else if (number >= 10 && number < 100) {
|
|
103
|
+
p = 2;
|
|
104
|
+
d = 2;
|
|
105
|
+
r = false;
|
|
106
|
+
c = false;
|
|
107
|
+
}
|
|
108
|
+
else if (number >= 100 && number < 1000) {
|
|
109
|
+
p = 1;
|
|
110
|
+
d = 1;
|
|
111
|
+
r = false;
|
|
112
|
+
c = false;
|
|
113
|
+
}
|
|
114
|
+
else if (number >= 1000) {
|
|
115
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
116
|
+
p = 2 - x;
|
|
117
|
+
d = 2 - x;
|
|
118
|
+
r = true;
|
|
119
|
+
c = true;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
p = 0;
|
|
123
|
+
d = 0;
|
|
124
|
+
r = true;
|
|
125
|
+
c = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (precision === 'low') {
|
|
129
|
+
if (number >= 0 && number < 0.01) {
|
|
130
|
+
p = 2;
|
|
131
|
+
d = 0;
|
|
132
|
+
r = true;
|
|
133
|
+
c = false;
|
|
134
|
+
f = 2;
|
|
135
|
+
}
|
|
136
|
+
else if (number >= 0.01 && number < 0.1) {
|
|
137
|
+
p = 2;
|
|
138
|
+
d = 1;
|
|
139
|
+
r = true;
|
|
140
|
+
c = false;
|
|
141
|
+
}
|
|
142
|
+
else if (number >= 0.1 && number < 1) {
|
|
143
|
+
p = 2;
|
|
144
|
+
d = 2;
|
|
145
|
+
r = true;
|
|
146
|
+
c = false;
|
|
147
|
+
}
|
|
148
|
+
else if (number >= 1 && number < 10) {
|
|
149
|
+
p = 2;
|
|
150
|
+
d = 2;
|
|
151
|
+
r = true;
|
|
152
|
+
c = false;
|
|
153
|
+
f = 2;
|
|
154
|
+
}
|
|
155
|
+
else if (number >= 10 && number < 100) {
|
|
156
|
+
p = 1;
|
|
157
|
+
d = 1;
|
|
158
|
+
r = true;
|
|
159
|
+
c = false;
|
|
160
|
+
f = 1;
|
|
161
|
+
}
|
|
162
|
+
else if (number >= 100 && number < 1000) {
|
|
163
|
+
p = 0;
|
|
164
|
+
d = 0;
|
|
165
|
+
r = true;
|
|
166
|
+
c = false;
|
|
167
|
+
}
|
|
168
|
+
else if (number >= 1000) {
|
|
169
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
170
|
+
p = 1 - x;
|
|
171
|
+
d = 1 - x;
|
|
172
|
+
r = true;
|
|
173
|
+
c = true;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
p = 0;
|
|
177
|
+
d = 0;
|
|
178
|
+
r = true;
|
|
179
|
+
c = true;
|
|
180
|
+
f = 2;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// precision === "high"
|
|
185
|
+
if (number >= 0 && number < 1) {
|
|
186
|
+
p = 33;
|
|
187
|
+
d = 4;
|
|
188
|
+
r = false;
|
|
189
|
+
c = false;
|
|
190
|
+
}
|
|
191
|
+
else if (number >= 1 && number < 10) {
|
|
192
|
+
p = 3;
|
|
193
|
+
d = 3;
|
|
194
|
+
r = true;
|
|
195
|
+
c = false;
|
|
196
|
+
}
|
|
197
|
+
else if (number >= 10 && number < 100) {
|
|
198
|
+
p = 2;
|
|
199
|
+
d = 2;
|
|
200
|
+
r = true;
|
|
201
|
+
c = false;
|
|
202
|
+
}
|
|
203
|
+
else if (number >= 100 && number < 1000) {
|
|
204
|
+
p = 2;
|
|
205
|
+
d = 2;
|
|
206
|
+
r = true;
|
|
207
|
+
c = false;
|
|
208
|
+
}
|
|
209
|
+
else if (number >= 1000 && number < 10000) {
|
|
210
|
+
p = 1;
|
|
211
|
+
d = 1;
|
|
212
|
+
r = true;
|
|
213
|
+
c = false;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
p = 0;
|
|
217
|
+
d = 0;
|
|
218
|
+
r = true;
|
|
219
|
+
c = false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix);
|
|
223
|
+
}
|
|
224
|
+
function reducePrecision(numberString, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '') {
|
|
225
|
+
if (!numberString)
|
|
226
|
+
return 0;
|
|
227
|
+
numberString = numberString.toString();
|
|
228
|
+
const maxPrecision = 30;
|
|
229
|
+
const maxIntegerDigits = 21;
|
|
230
|
+
const scaleUnits = template.match(/^(number|percent)$/g)
|
|
231
|
+
? {
|
|
232
|
+
'': '',
|
|
233
|
+
K: ' هزار',
|
|
234
|
+
M: ' میلیون',
|
|
235
|
+
B: ' میلیارد',
|
|
236
|
+
T: ' تریلیون',
|
|
237
|
+
Qd: ' کادریلیون',
|
|
238
|
+
Qt: ' کنتیلیون',
|
|
239
|
+
}
|
|
240
|
+
: {
|
|
241
|
+
'': '',
|
|
242
|
+
K: ' هزار ت',
|
|
243
|
+
M: ' میلیون ت',
|
|
244
|
+
B: ' میلیارد ت',
|
|
245
|
+
T: ' همت',
|
|
246
|
+
Qd: ' هزار همت',
|
|
247
|
+
Qt: ' میلیون همت',
|
|
248
|
+
};
|
|
249
|
+
let parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(numberString);
|
|
250
|
+
if (!parts) {
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
const sign = parts[1] || '';
|
|
254
|
+
let wholeNumberStr = parts[2];
|
|
255
|
+
let fractionalZeroStr = parts[3];
|
|
256
|
+
let fractionalNonZeroStr = parts[4];
|
|
257
|
+
let unitPrefix = '';
|
|
258
|
+
let unitPostfix = '';
|
|
259
|
+
if (fractionalZeroStr.length >= maxPrecision) {
|
|
260
|
+
// Number is smaller than maximum precision
|
|
261
|
+
fractionalZeroStr = '0'.padEnd(maxPrecision - 1, '0');
|
|
262
|
+
fractionalNonZeroStr = '1';
|
|
263
|
+
}
|
|
264
|
+
else if (fractionalZeroStr.length + nonZeroDigits > precision) {
|
|
265
|
+
// decrease non-zero digits
|
|
266
|
+
nonZeroDigits = precision - fractionalZeroStr.length;
|
|
267
|
+
if (nonZeroDigits < 1)
|
|
268
|
+
nonZeroDigits = 1;
|
|
269
|
+
}
|
|
270
|
+
else if (wholeNumberStr.length > maxIntegerDigits) {
|
|
271
|
+
wholeNumberStr = '0';
|
|
272
|
+
fractionalZeroStr = '';
|
|
273
|
+
fractionalNonZeroStr = '';
|
|
274
|
+
}
|
|
275
|
+
// compress large numbers
|
|
276
|
+
if (compress && wholeNumberStr.length >= 4) {
|
|
277
|
+
const scaleUnitKeys = Object.keys(scaleUnits);
|
|
278
|
+
let scaledWholeNumber = wholeNumberStr;
|
|
279
|
+
let unitIndex = 0;
|
|
280
|
+
while (+scaledWholeNumber > 999 && unitIndex < scaleUnitKeys.length - 1) {
|
|
281
|
+
scaledWholeNumber = (+scaledWholeNumber / 1000).toFixed(2);
|
|
282
|
+
unitIndex++;
|
|
283
|
+
}
|
|
284
|
+
unitPostfix = scaleUnitKeys[unitIndex];
|
|
285
|
+
parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(scaledWholeNumber.toString());
|
|
286
|
+
if (!parts) {
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
// sign = parts[1] || "";
|
|
290
|
+
wholeNumberStr = parts[2];
|
|
291
|
+
fractionalZeroStr = parts[3];
|
|
292
|
+
fractionalNonZeroStr = parts[4];
|
|
293
|
+
}
|
|
294
|
+
// Truncate the fractional part or round it
|
|
295
|
+
// if (precision > 0 && nonZeroDigits > 0 && fractionalNonZeroStr.length > nonZeroDigits) {
|
|
296
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
297
|
+
if (!round) {
|
|
298
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
if (parseInt(fractionalNonZeroStr[nonZeroDigits]) < 5) {
|
|
302
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
fractionalNonZeroStr = (parseInt(fractionalNonZeroStr.substring(0, nonZeroDigits)) + 1).toString();
|
|
306
|
+
// If overflow occurs (e.g., 999 + 1 = 1000), adjust the substring length
|
|
307
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
308
|
+
if (fractionalZeroStr.length > 0) {
|
|
309
|
+
fractionalZeroStr = fractionalZeroStr.substring(0, fractionalZeroStr.length - 1);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
wholeNumberStr = (Number(wholeNumberStr) + 1).toString();
|
|
313
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(1);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Using dex style
|
|
320
|
+
if (compress && fractionalZeroStr !== '' && unitPostfix === '') {
|
|
321
|
+
fractionalZeroStr =
|
|
322
|
+
'0' +
|
|
323
|
+
fractionalZeroStr.length.toString().replace(/\d/g, function (match) {
|
|
324
|
+
return [
|
|
325
|
+
'₀',
|
|
326
|
+
'₁',
|
|
327
|
+
'₂',
|
|
328
|
+
'₃',
|
|
329
|
+
'₄',
|
|
330
|
+
'₅',
|
|
331
|
+
'₆',
|
|
332
|
+
'₇',
|
|
333
|
+
'₈',
|
|
334
|
+
'₉',
|
|
335
|
+
][parseInt(match, 10)];
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
let fractionalPartStr = `${fractionalZeroStr}${fractionalNonZeroStr}`;
|
|
339
|
+
fractionalPartStr = fractionalPartStr.substring(0, precision);
|
|
340
|
+
fractionalPartStr = fractionalPartStr.replace(/^(\d*[1-9])0+$/g, '$1');
|
|
341
|
+
// Output Formating, Prefix, Postfix
|
|
342
|
+
if (template === 'usd') {
|
|
343
|
+
unitPrefix = language === 'en' ? '$' : '';
|
|
344
|
+
}
|
|
345
|
+
else if (template === 'irr') {
|
|
346
|
+
if (!unitPostfix)
|
|
347
|
+
unitPostfix = language === 'fa' ? ' ر' : ' R';
|
|
348
|
+
}
|
|
349
|
+
else if (template === 'irt') {
|
|
350
|
+
if (!unitPostfix)
|
|
351
|
+
unitPostfix = language === 'fa' ? ' ت' : ' T';
|
|
352
|
+
}
|
|
353
|
+
else if (template === 'percent') {
|
|
354
|
+
if (language === 'en') {
|
|
355
|
+
unitPostfix += '%';
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
unitPostfix += !unitPostfix ? '٪' : ' درصد';
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
unitPrefix = prefix + unitPrefix;
|
|
362
|
+
unitPostfix += postfix;
|
|
363
|
+
if (outputFormat === 'html') {
|
|
364
|
+
if (unitPrefix)
|
|
365
|
+
unitPrefix = `<${prefixMarker}>${unitPrefix}</${prefixMarker}>`;
|
|
366
|
+
if (unitPostfix)
|
|
367
|
+
unitPostfix = `<${postfixMarker}>${unitPostfix}</${postfixMarker}>`;
|
|
368
|
+
}
|
|
369
|
+
else if (outputFormat === 'markdown') {
|
|
370
|
+
if (unitPrefix)
|
|
371
|
+
unitPrefix = `${prefixMarker}${unitPrefix}${prefixMarker}`;
|
|
372
|
+
if (unitPostfix)
|
|
373
|
+
unitPostfix = `${postfixMarker}${unitPostfix}${postfixMarker}`;
|
|
374
|
+
}
|
|
375
|
+
const thousandSeparatorRegex = /\B(?=(\d{3})+(?!\d))/g;
|
|
376
|
+
const fixedDecimalZeroStr = fixedDecimalZeros
|
|
377
|
+
? '.'.padEnd(fixedDecimalZeros + 1, '0')
|
|
378
|
+
: '';
|
|
379
|
+
let out = '';
|
|
380
|
+
if (precision <= 0 || nonZeroDigits <= 0 || !fractionalNonZeroStr) {
|
|
381
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}${fixedDecimalZeroStr}${unitPostfix}`;
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}.${fractionalPartStr}${unitPostfix}`;
|
|
385
|
+
}
|
|
386
|
+
// Convert output to Persian numerals if language is "fa"
|
|
387
|
+
if (language === 'fa') {
|
|
388
|
+
out = out
|
|
389
|
+
.replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
|
|
390
|
+
.replace(/,/g, '٬')
|
|
391
|
+
.replace(/\./g, '٫')
|
|
392
|
+
.replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
|
|
393
|
+
return String(scaleUnits[c]);
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
398
|
+
console.log(format(3.1227533815325955e-10, { precision: 'low' }));
|
|
399
|
+
console.log(format(3.1227533815325955e-30, { precision: 'low' }));
|
|
400
|
+
console.log(format(3123123123, { precision: 'low' }));
|
|
401
|
+
console.log(format(2, { precision: 'low' }));
|
|
402
|
+
exports.default = format;
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.format = void 0;
|
|
7
|
+
const format_1 = __importDefault(require("./format"));
|
|
8
|
+
exports.format = format_1.default;
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reduce-precision",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./lib/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"lib/**/*"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc --project tsconfig.build.json",
|
|
11
|
+
"clean": "rm -rf ./lib/",
|
|
12
|
+
"lint": "eslint ./src/ --fix",
|
|
13
|
+
"test:watch": "jest --watch",
|
|
14
|
+
"test": "jest --coverage",
|
|
15
|
+
"typecheck": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/ArzDigitalLabs/reduce-precision.git"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": {
|
|
23
|
+
"name": "Mohammad Anaraki",
|
|
24
|
+
"email": "m.anaraki1376@gmail.com",
|
|
25
|
+
"url": "https://github.com/mohammadanaraki"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/ArzDigitalLabs/reduce-precision/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/ArzDigitalLabs/reduce-precision#readme",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/jest": "^27.5.2",
|
|
33
|
+
"@types/node": "^12.20.11",
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
|
35
|
+
"@typescript-eslint/parser": "^4.22.0",
|
|
36
|
+
"eslint": "^7.25.0",
|
|
37
|
+
"eslint-config-prettier": "^8.3.0",
|
|
38
|
+
"eslint-plugin-node": "^11.1.0",
|
|
39
|
+
"eslint-plugin-prettier": "^3.4.0",
|
|
40
|
+
"jest": "^27.2.0",
|
|
41
|
+
"lint-staged": "^13.2.1",
|
|
42
|
+
"prettier": "^2.2.1",
|
|
43
|
+
"ts-jest": "^27.0.5",
|
|
44
|
+
"ts-node": "^10.2.1",
|
|
45
|
+
"typescript": "^4.2.4"
|
|
46
|
+
},
|
|
47
|
+
"lint-staged": {
|
|
48
|
+
"*.ts": "eslint --cache --cache-location .eslintcache --fix"
|
|
49
|
+
},
|
|
50
|
+
"release": {
|
|
51
|
+
"branches": [
|
|
52
|
+
"main"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|