@peter-present/format-number 0.0.1 → 0.0.11
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 +57 -67
- package/dist/compact.d.ts +19 -1
- package/dist/format.d.ts +36 -7
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +178 -103
- package/dist/io.d.ts +26 -0
- package/dist/notation.d.ts +24 -0
- package/dist/round.d.ts +13 -0
- package/dist/types.d.ts +27 -4
- package/package.json +2 -2
- package/dist/utils.d.ts +0 -2
package/README.md
CHANGED
|
@@ -1,115 +1,105 @@
|
|
|
1
1
|
# format-number
|
|
2
2
|
|
|
3
|
-
A lightweight,
|
|
3
|
+
A lightweight, zero-dependency JavaScript/TypeScript library for precise number formatting. Designed for financial applications, crypto dashboards, and scientific data where precision is paramount.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Unlike standard libraries that rely on floating-point math, **format-number** uses internal string-based arithmetic to handle numbers of any size (including `string`, `number`, and `bigint`) without losing a single decimal point.
|
|
6
6
|
|
|
7
|
-
For detailed documentation
|
|
7
|
+
For detailed documentation, visit: [here](https://blog.peter-present.xyz/format-number)
|
|
8
8
|
|
|
9
9
|
## Key Features
|
|
10
10
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **Flexible
|
|
16
|
-
- **Fluent API**:
|
|
17
|
-
- **Zero Dependencies**: Keeps your bundle size minimal.
|
|
11
|
+
- **Zero Precision Loss**: Uses string manipulation for rounding and formatting to avoid binary floating-point errors.
|
|
12
|
+
- **Robust Input Parsing**: Handles messy strings with currency symbols ($€£¥), commas, underscores, and scientific notation automatically.
|
|
13
|
+
- **Advanced Rounding**: 5 strategies (`half`, `up`, `down`, `banker`, `truncate`) with customizable decimal precision.
|
|
14
|
+
- **Intelligent Notation**: Format small numbers with subscript zeros (e.g., `0.0₃5`) or standard scientific notation.
|
|
15
|
+
- **Flexible Compacting**: Shorten massive numbers into readable strings like `1.5T` or `20.4B`.
|
|
16
|
+
- **Fluent Chainable API**: Build complex formatting logic with a clean, readable syntax.
|
|
18
17
|
|
|
19
18
|
## Installation
|
|
20
19
|
|
|
21
20
|
```shell
|
|
22
21
|
# npm
|
|
23
|
-
npm install format-number
|
|
22
|
+
npm install @peter-present/format-number
|
|
24
23
|
|
|
25
24
|
# yarn
|
|
26
|
-
yarn add format-number
|
|
25
|
+
yarn add @peter-present/format-number
|
|
27
26
|
|
|
28
27
|
# bun
|
|
29
|
-
bun install format-number
|
|
28
|
+
bun install @peter-present/format-number
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
## Core
|
|
31
|
+
## Core API
|
|
33
32
|
|
|
34
|
-
###
|
|
33
|
+
### `formatNumber(value, options)`
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
The primary entry point for one-off formatting. It combines parsing, rounding, and visualization.
|
|
37
36
|
|
|
38
37
|
```typescript
|
|
39
|
-
import {
|
|
38
|
+
import { formatNumber } from '@peter-present/format-number';
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Compact Formatting: `compact()`
|
|
46
|
-
|
|
47
|
-
Format large numbers with readable suffixes.
|
|
40
|
+
// Currency & Rounding
|
|
41
|
+
formatNumber('$1,234.567', { prefix: '€', precision: 2 }); // '€1234.57'
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
// Compact Notation
|
|
44
|
+
formatNumber(1500000000, { isCompact: true }); // '1.5B'
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
// Special Notations
|
|
47
|
+
formatNumber(0.00005, { notation: 'subscript' }); // '0.0₄5'
|
|
48
|
+
formatNumber(12345, { notation: 'scientific' }); // '1.2345e+4'
|
|
55
49
|
```
|
|
56
50
|
|
|
57
|
-
###
|
|
51
|
+
### `FN(value)` - Fluent API
|
|
58
52
|
|
|
59
|
-
|
|
53
|
+
Best for complex, multi-step formatting requirements where readability is key.
|
|
60
54
|
|
|
61
55
|
```typescript
|
|
62
|
-
import {
|
|
56
|
+
import { FN } from '@peter-present/format-number';
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
const formatted = FN('1234567.89')
|
|
59
|
+
.round({ precision: 0, rounding: 'banker' })
|
|
60
|
+
.prefix('Balance: ')
|
|
61
|
+
.suffix(' USD')
|
|
62
|
+
.toNumber();
|
|
66
63
|
|
|
67
|
-
//
|
|
68
|
-
formatNumber(1500000, { isCompact: true, suffix: ' units' }); // '1.5M units'
|
|
64
|
+
console.log(formatted); // 'Balance: 1234568 USD'
|
|
69
65
|
|
|
70
|
-
//
|
|
71
|
-
|
|
66
|
+
// Seamlessly combine with compact and notation
|
|
67
|
+
FN(1500).compact({ precision: 1 }).prefix('$').toNumber(); // '$1.5K'
|
|
72
68
|
```
|
|
73
69
|
|
|
74
|
-
###
|
|
70
|
+
### `round(value, options)`
|
|
75
71
|
|
|
76
|
-
|
|
72
|
+
Independent rounding utility with high-precision string logic.
|
|
77
73
|
|
|
78
74
|
```typescript
|
|
79
|
-
import {
|
|
80
|
-
|
|
81
|
-
const result = FN('1234567.89')
|
|
82
|
-
.round({ precision: 0 })
|
|
83
|
-
.format({ prefix: 'Total: ', suffix: ' tokens' });
|
|
84
|
-
|
|
85
|
-
console.log(result); // 'Total: 1234568 tokens'
|
|
75
|
+
import { round } from '@peter-present/format-number';
|
|
86
76
|
|
|
87
|
-
//
|
|
88
|
-
|
|
77
|
+
round(1.235, { precision: 2, rounding: 'half' }); // '1.24'
|
|
78
|
+
round(1.235, { precision: 2, rounding: 'down' }); // '1.23'
|
|
89
79
|
```
|
|
90
80
|
|
|
91
|
-
##
|
|
81
|
+
## Configuration Reference
|
|
92
82
|
|
|
93
|
-
###
|
|
83
|
+
### `RoundingMode`
|
|
94
84
|
|
|
95
|
-
| Mode | Description
|
|
96
|
-
| :--------- |
|
|
97
|
-
| `half` |
|
|
98
|
-
| `up` |
|
|
99
|
-
| `down` |
|
|
100
|
-
| `truncate` |
|
|
101
|
-
| `banker` |
|
|
85
|
+
| Mode | Description |
|
|
86
|
+
| :--------- | :--------------------------------------------------------------------- |
|
|
87
|
+
| `half` | Rounds to the nearest neighbor (rounds away from zero if equidistant). |
|
|
88
|
+
| `up` | Rounds towards Positive Infinity. |
|
|
89
|
+
| `down` | Rounds towards Negative Infinity. |
|
|
90
|
+
| `truncate` | Rounds towards Zero (trims decimals). |
|
|
91
|
+
| `banker` | Rounds to the nearest even neighbor (minimizes statistical bias). |
|
|
102
92
|
|
|
103
|
-
###
|
|
93
|
+
### `FormattingConfigType`
|
|
104
94
|
|
|
105
|
-
|
|
|
106
|
-
| :---------- |
|
|
107
|
-
| `precision` | `number`
|
|
108
|
-
| `
|
|
109
|
-
| `prefix` | `string`
|
|
110
|
-
| `suffix` | `string`
|
|
111
|
-
| `isCompact` | `boolean`
|
|
112
|
-
| `
|
|
95
|
+
| Property | Type | Default | Description |
|
|
96
|
+
| :---------- | :---------------------------- | :---------- | :------------------------------------------------- |
|
|
97
|
+
| `precision` | `number` | `0` | Number of decimal places to maintain. |
|
|
98
|
+
| `rounding` | `RoundingMode` | `'half'` | Strategy used for rounding. |
|
|
99
|
+
| `prefix` | `string` | `""` | Text prepended to the result. |
|
|
100
|
+
| `suffix` | `string` | `""` | Text appended to the result. |
|
|
101
|
+
| `isCompact` | `boolean` | `false` | Whether to use K/M/B/T suffixes for large numbers. |
|
|
102
|
+
| `notation` | `'subscript' \| 'scientific'` | `undefined` | Special formatting for extreme values. |
|
|
113
103
|
|
|
114
104
|
## License
|
|
115
105
|
|
package/dist/compact.d.ts
CHANGED
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NumberType, RoundingConfigType } from './types';
|
|
2
|
+
export declare function _compact(value: NumberType, options?: RoundingConfigType): {
|
|
3
|
+
value: string;
|
|
4
|
+
symbol: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Formats a number into a short, human-readable string with a suffix (e.g., K, M, B).
|
|
8
|
+
*
|
|
9
|
+
* @param value - The value to be compacted. Can be a number, string, or bigint.
|
|
10
|
+
* @param options - Configuration for rounding the compacted value.
|
|
11
|
+
* @param options.rounding - The rounding strategy to use. Default is 'half'.
|
|
12
|
+
* @param options.precision - The number of decimal places to include after compacting. Default is 0.
|
|
13
|
+
* @returns The compacted number with a suffix as a string.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* compact(1500); // '1.5K'
|
|
17
|
+
* compact(1200000, { precision: 1 }); // '1.2M'
|
|
18
|
+
* compact('1000000000000'); // '1T'
|
|
19
|
+
*/
|
|
2
20
|
export declare function compact(value: NumberType, options?: RoundingConfigType): string;
|
package/dist/format.d.ts
CHANGED
|
@@ -1,8 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { FormattingConfigType, NotationMode, NumberType, ObjectNumberType, RoundingConfigType } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Fluent API for performing multiple formatting operations in a readable chain.
|
|
4
|
+
* Wraps the input value into a formatter object that supports rounding,
|
|
5
|
+
* compacting, and metadata addition.
|
|
6
|
+
*
|
|
7
|
+
* @param value - The initial value to format.
|
|
8
|
+
* @returns A chainable formatter object.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* FN('1234567.89')
|
|
12
|
+
* .round({ precision: 0 })
|
|
13
|
+
* .prefix('$')
|
|
14
|
+
* .toNumber(); // '$1234568'
|
|
15
|
+
*/
|
|
16
|
+
export declare function FN(value: NumberType | ObjectNumberType): {
|
|
17
|
+
round: (options?: RoundingConfigType) => any;
|
|
18
|
+
compact: (options?: RoundingConfigType) => any;
|
|
19
|
+
notation(mode?: NotationMode): any;
|
|
20
|
+
prefix(symbol: string): any;
|
|
21
|
+
suffix(symbol: string): any;
|
|
22
|
+
toNumber(): string;
|
|
23
|
+
toObject(): ObjectNumberType;
|
|
8
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Comprehensive formatting function that combines rounding, compacting, and metadata.
|
|
27
|
+
* This is the quickest way to format a number with multiple options.
|
|
28
|
+
*
|
|
29
|
+
* @param value - The value to format.
|
|
30
|
+
* @param options - Formatting configuration (precision, rounding, isCompact, prefix, suffix, notation).
|
|
31
|
+
* @returns The formatted number string.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* formatNumber(1234.56, { prefix: '$', precision: 1 }); // '$1234.6'
|
|
35
|
+
* formatNumber(1500000, { isCompact: true }); // '1.5M'
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatNumber(value: NumberType, options?: FormattingConfigType): string;
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function $(n){return n.replace(/^(-?)0+(?=\d)/,"$1").replace(/(\.\d*?)0+$/,"$1").replace(/\.$/,"")}function d(n){let t=String(n);t=t.trim();let e="";return t.startsWith("-")&&(t=t.slice(1),e="-"),{sign:e,value:$(t)}}const Z={K:3,M:6,B:9,T:12,Q:15};function E(n){if(typeof n=="number"||typeof n=="bigint")return n.toString();const t=String(n??"").trim();if(t==="")return"0";const e=t.match(/^[\s+-]*/),i=((e?e[0]:"").match(/-/g)||[]).length%2===1,s=t.replace(/[$€£¥,_\s]/g,""),c=/^([+-]?\d+)\.0([\u2080-\u2089]+)([0-9]*)$/i,u=s.match(c);if(u){const m=u[1].replace(/^[+-]/,""),j=u[2],D=u[3],R=j.split("").reduce((K,O)=>{const Q=O.charCodeAt(0)-8320;return K+Q},0),w="0".repeat(R)+D;let h=m;return(w!==""||R>0)&&(h+="."+w),h=$(h),(i?"-":"")+(h||"0")}const l=s.match(/[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[KMBTQ]*/i);if(!l)return"0";let o=l[0].toUpperCase(),P=0;const S=o.match(/[KMBTQ]$/);S&&(P+=Z[S[0]]??0,o=o.slice(0,-1));const y=o.match(/[eE][+-]?\d+$/);if(y&&(P+=parseInt(y[0].slice(1),10),o=o.replace(/[eE][+-]?\d+$/i,"")),o=o.replace(/^[+-]/,""),!/^(?:\d+\.?\d*|\.\d+)$/.test(o))return"0";const[C="0",M=""]=o.split(".");let g=(C.replace(/^0+/,"")||"0")+M;const b=M.length-P;let p;if(b<=0)g+="0".repeat(-b),p=g.replace(/^0+(?=\d)/,"")||"0";else{const m=g.length-b;m<=0?p="0."+"0".repeat(-m)+g:p=g.slice(0,m)+"."+g.slice(m),p=$(p)}return(i?"-":"")+(p||"0")}function F(n){const t=typeof n;if(t=="string"||t=="bigint"||t=="number"){const{sign:e,value:r}=d(n);return{sign:e,value:r}}return n}function a(n){let t="",e=n.length-1,r="1";for(;e>=0;){const i=n[e];let s=Number(i)+(r?1:0);s>=10?(r="1",s-=10):r="",t=s.toString()+t,e--}return{result:r+t,remaining:r}}function I(n,t=0){const[e,r=""]=n.split(".");if(t===0)return r&&Number(r[0])>=5?a(e).result:e;if(t>=r.length)return e+(r?`.${r}`:"");const i=r.slice(0,t),s=r.slice(t);if(Number(s[0])>=5){const c=a(i);return c.remaining?a(e).result:e+"."+c.result}else return e+"."+i}function v(n,t=0){const[e,r=""]=n.split(".");if(t===0)return r?a(e).result:e;if(t>=r.length)return e+"."+r;const i=a(r.slice(0,t));return i.remaining?a(e).result:e+"."+i.result}function x(n,t=0){const[e,r=""]=n.split(".");if(t===0)return e;let i=r.slice(0,t),s=i.length-1;for(;s>=0&&i[s]=="0";)s--;return i=i.slice(0,s+1),e+(i?`.${i}`:"")}function k(n,t=0){const[e,r=""]=n.split(".");if(t===0)return r&&Number(r[0])>=5?Number(e[0])/2==0?e:a(e).result:e;if(t>=r.length)return e+(r?`.${r}`:"");const i=r.slice(0,t),s=r.slice(t);if(s[0]=="5"){if(Number(i[i.length-1])%2==0)return e+"."+i;{const c=a(i);return c.remaining?a(e).result:e+"."+c.result}}else if(Number(s[0])>5){const c=a(i);return c.remaining?a(e).result:e+"."+c.result}else return e+"."+i}function N(n,t={}){const e=t.rounding||"half",r=t.precision||0,{sign:i,value:s}=d(n);switch(e){case"half":return i+I(s,r);case"up":return i==""?v(s,r):"-"+x(s,r);case"down":return i==""?x(s,r):"-"+v(s,r);case"truncate":return i+x(s,r);case"banker":return i+k(s,r)}}const U=["K","M","B","T","Q"];function _(n,t={}){const{sign:e,value:r}=d(n);let[i,s=""]=r.split("."),c=i.length,u=-1;for(;c>3&&u<4;){const o=i.slice(0,c-3);s=i.slice(c-3)+s,i=o,c-=3,u++}const l=`${e}${i}${s.length>0?"."+s:s}`;return{value:t.precision!=null?N(l,t):l,symbol:u>=0?U[u]:""}}function V(n,t={}){const{value:e,symbol:r}=_(n,t);return e+r}function T(n){const{sign:t,value:e}=d(n),[r,i=""]=e.split("."),s=i.match(/^0+/)?.[0]?.length||0,c=s.toString().split("").map(l=>String.fromCharCode(8320+parseInt(l))).join(""),u=i.slice(s);return`${t}${r}.0${c}${u}`}function z(n){const{sign:t,value:e}=d(n);if(e=="0")return{value:"0",exponent:0};const[r,i=""]=e.split(".");if(r!=="0"){const l=r.length-1,o=r[0]+"."+(r.slice(1)+i).replace(/0+$/,"");return{value:`${t}${o}${o.length>1,""}`,exponent:l,sign:"+"}}const s=i.search(/[1-9]/);if(s===-1)return{value:"0",exponent:0};const c=-(s+1),u=i[s]+"."+i.slice(s+1).replace(/0+$/,"");return{value:`${t}${u}`,exponent:c-1,sign:""}}function B(n){const{value:t,exponent:e,sign:r}=z(n);return e!=0?`${t}e${r}${e}`:t}function f(n){return{round:t=>{const e=N(n.value,t);return f({...n,value:e})},compact:t=>{if(n.compactedSymbol)return f(n);const{value:e,symbol:r}=_(n.value,t);return f({...n,compactedSymbol:r,value:e})},notation(t="scientific"){return f({...n,notation:t})},prefix(t){return f({...n,prefix:t})},suffix(t){return f({...n,suffix:t})},toNumber(){let{value:t}=n;const{sign:e,prefix:r,suffix:i,compactedSymbol:s}=n;return n.notation=="scientific"?t=B(t):n.notation=="subscript"&&(t=T(t)),`${r||""}${e}${t}${s||""}${i||""}`},toObject(){return n}}}function A(n){return f(F(n))}exports.FN=A;exports.clearTrailingZero=$;exports.compact=V;exports.parseNum=E;exports.round=N;exports.scientific=B;exports.subscript=T;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './types';
|
|
2
|
-
export * from './utils';
|
|
3
2
|
export { compact } from './compact';
|
|
4
|
-
export { FN
|
|
3
|
+
export { FN } from './format';
|
|
4
|
+
export { clearTrailingZero, parseNum } from './io';
|
|
5
|
+
export { scientific, subscript } from './notation';
|
|
5
6
|
export { round } from './round';
|
package/dist/index.js
CHANGED
|
@@ -1,125 +1,200 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
function x(r) {
|
|
2
|
+
return r.replace(/^(-?)0+(?=\d)/, "$1").replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "");
|
|
3
|
+
}
|
|
4
|
+
function d(r) {
|
|
5
|
+
let t = String(r);
|
|
6
|
+
t = t.trim();
|
|
7
|
+
let e = "";
|
|
8
|
+
return t.startsWith("-") && (t = t.slice(1), e = "-"), { sign: e, value: x(t) };
|
|
9
|
+
}
|
|
10
|
+
const j = { K: 3, M: 6, B: 9, T: 12, Q: 15 };
|
|
11
|
+
function z(r) {
|
|
12
|
+
if (typeof r == "number" || typeof r == "bigint")
|
|
13
|
+
return r.toString();
|
|
14
|
+
const t = String(r ?? "").trim();
|
|
15
|
+
if (t === "") return "0";
|
|
16
|
+
const e = t.match(/^[\s+-]*/), i = ((e ? e[0] : "").match(/-/g) || []).length % 2 === 1, s = t.replace(/[$€£¥,_\s]/g, ""), c = /^([+-]?\d+)\.0([\u2080-\u2089]+)([0-9]*)$/i, u = s.match(c);
|
|
17
|
+
if (u) {
|
|
18
|
+
const m = u[1].replace(/^[+-]/, ""), B = u[2], C = u[3], w = B.split("").reduce((D, K) => {
|
|
19
|
+
const Q = K.charCodeAt(0) - 8320;
|
|
20
|
+
return D + Q;
|
|
21
|
+
}, 0), y = "0".repeat(w) + C;
|
|
22
|
+
let h = m;
|
|
23
|
+
return (y !== "" || w > 0) && (h += "." + y), h = x(h), (i ? "-" : "") + (h || "0");
|
|
24
|
+
}
|
|
25
|
+
const l = s.match(/[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[KMBTQ]*/i);
|
|
26
|
+
if (!l) return "0";
|
|
27
|
+
let o = l[0].toUpperCase(), $ = 0;
|
|
28
|
+
const N = o.match(/[KMBTQ]$/);
|
|
29
|
+
N && ($ += j[N[0]] ?? 0, o = o.slice(0, -1));
|
|
30
|
+
const S = o.match(/[eE][+-]?\d+$/);
|
|
31
|
+
if (S && ($ += parseInt(S[0].slice(1), 10), o = o.replace(/[eE][+-]?\d+$/i, "")), o = o.replace(/^[+-]/, ""), !/^(?:\d+\.?\d*|\.\d+)$/.test(o)) return "0";
|
|
32
|
+
const [T = "0", R = ""] = o.split(".");
|
|
33
|
+
let g = (T.replace(/^0+/, "") || "0") + R;
|
|
34
|
+
const P = R.length - $;
|
|
35
|
+
let p;
|
|
36
|
+
if (P <= 0)
|
|
37
|
+
g += "0".repeat(-P), p = g.replace(/^0+(?=\d)/, "") || "0";
|
|
38
|
+
else {
|
|
39
|
+
const m = g.length - P;
|
|
40
|
+
m <= 0 ? p = "0." + "0".repeat(-m) + g : p = g.slice(0, m) + "." + g.slice(m), p = x(p);
|
|
21
41
|
}
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
return (i ? "-" : "") + (p || "0");
|
|
43
|
+
}
|
|
44
|
+
function E(r) {
|
|
45
|
+
const t = typeof r;
|
|
46
|
+
if (t == "string" || t == "bigint" || t == "number") {
|
|
47
|
+
const { sign: e, value: n } = d(r);
|
|
48
|
+
return { sign: e, value: n };
|
|
49
|
+
}
|
|
50
|
+
return r;
|
|
51
|
+
}
|
|
52
|
+
function a(r) {
|
|
53
|
+
let t = "", e = r.length - 1, n = "1";
|
|
54
|
+
for (; e >= 0; ) {
|
|
55
|
+
const i = r[e];
|
|
56
|
+
let s = Number(i) + (n ? 1 : 0);
|
|
57
|
+
s >= 10 ? (n = "1", s -= 10) : n = "", t = s.toString() + t, e--;
|
|
58
|
+
}
|
|
59
|
+
return { result: n + t, remaining: n };
|
|
60
|
+
}
|
|
61
|
+
function I(r, t = 0) {
|
|
62
|
+
const [e, n = ""] = r.split(".");
|
|
63
|
+
if (t === 0)
|
|
64
|
+
return n && Number(n[0]) >= 5 ? a(e).result : e;
|
|
65
|
+
if (t >= n.length) return e + (n ? `.${n}` : "");
|
|
66
|
+
const i = n.slice(0, t), s = n.slice(t);
|
|
67
|
+
if (Number(s[0]) >= 5) {
|
|
68
|
+
const c = a(i);
|
|
69
|
+
return c.remaining ? a(e).result : e + "." + c.result;
|
|
70
|
+
} else return e + "." + i;
|
|
71
|
+
}
|
|
72
|
+
function M(r, t = 0) {
|
|
73
|
+
const [e, n = ""] = r.split(".");
|
|
74
|
+
if (t === 0)
|
|
75
|
+
return n ? a(e).result : e;
|
|
76
|
+
if (t >= n.length) return e + "." + n;
|
|
77
|
+
const i = a(n.slice(0, t));
|
|
78
|
+
return i.remaining ? a(e).result : e + "." + i.result;
|
|
79
|
+
}
|
|
80
|
+
function b(r, t = 0) {
|
|
81
|
+
const [e, n = ""] = r.split(".");
|
|
82
|
+
if (t === 0) return e;
|
|
83
|
+
let i = n.slice(0, t), s = i.length - 1;
|
|
84
|
+
for (; s >= 0 && i[s] == "0"; ) s--;
|
|
85
|
+
return i = i.slice(0, s + 1), e + (i ? `.${i}` : "");
|
|
86
|
+
}
|
|
87
|
+
function O(r, t = 0) {
|
|
88
|
+
const [e, n = ""] = r.split(".");
|
|
89
|
+
if (t === 0)
|
|
90
|
+
return n && Number(n[0]) >= 5 ? Number(e[0]) / 2 == 0 ? e : a(e).result : e;
|
|
91
|
+
if (t >= n.length) return e + (n ? `.${n}` : "");
|
|
92
|
+
const i = n.slice(0, t), s = n.slice(t);
|
|
93
|
+
if (s[0] == "5") {
|
|
94
|
+
if (Number(i[i.length - 1]) % 2 == 0)
|
|
95
|
+
return e + "." + i;
|
|
59
96
|
{
|
|
60
|
-
const
|
|
61
|
-
return
|
|
97
|
+
const c = a(i);
|
|
98
|
+
return c.remaining ? a(e).result : e + "." + c.result;
|
|
62
99
|
}
|
|
63
|
-
} else if (Number(
|
|
64
|
-
const
|
|
65
|
-
return
|
|
66
|
-
} else return
|
|
67
|
-
}
|
|
68
|
-
function
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
switch (n.startsWith("-") && (n = n.slice(1), i = "-"), t) {
|
|
100
|
+
} else if (Number(s[0]) > 5) {
|
|
101
|
+
const c = a(i);
|
|
102
|
+
return c.remaining ? a(e).result : e + "." + c.result;
|
|
103
|
+
} else return e + "." + i;
|
|
104
|
+
}
|
|
105
|
+
function _(r, t = {}) {
|
|
106
|
+
const e = t.rounding || "half", n = t.precision || 0, { sign: i, value: s } = d(r);
|
|
107
|
+
switch (e) {
|
|
72
108
|
case "half":
|
|
73
|
-
return i +
|
|
109
|
+
return i + I(s, n);
|
|
74
110
|
case "up":
|
|
75
|
-
return i == "" ?
|
|
111
|
+
return i == "" ? M(s, n) : "-" + b(s, n);
|
|
76
112
|
case "down":
|
|
77
|
-
return i == "" ?
|
|
113
|
+
return i == "" ? b(s, n) : "-" + M(s, n);
|
|
78
114
|
case "truncate":
|
|
79
|
-
return i +
|
|
115
|
+
return i + b(s, n);
|
|
80
116
|
case "banker":
|
|
81
|
-
return i +
|
|
117
|
+
return i + O(s, n);
|
|
82
118
|
}
|
|
83
119
|
}
|
|
84
|
-
const
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
i = n.slice(l - 3) + i, n = f, l -= 3, c++;
|
|
120
|
+
const Z = ["K", "M", "B", "T", "Q"];
|
|
121
|
+
function v(r, t = {}) {
|
|
122
|
+
const { sign: e, value: n } = d(r);
|
|
123
|
+
let [i, s = ""] = n.split("."), c = i.length, u = -1;
|
|
124
|
+
for (; c > 3 && u < 4; ) {
|
|
125
|
+
const o = i.slice(0, c - 3);
|
|
126
|
+
s = i.slice(c - 3) + s, i = o, c -= 3, u++;
|
|
92
127
|
}
|
|
93
|
-
|
|
128
|
+
const l = `${e}${i}${s.length > 0 ? "." + s : s}`;
|
|
129
|
+
return {
|
|
130
|
+
value: t.precision != null ? _(l, t) : l,
|
|
131
|
+
symbol: u >= 0 ? Z[u] : ""
|
|
132
|
+
};
|
|
94
133
|
}
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
134
|
+
function A(r, t = {}) {
|
|
135
|
+
const { value: e, symbol: n } = v(r, t);
|
|
136
|
+
return e + n;
|
|
137
|
+
}
|
|
138
|
+
function k(r) {
|
|
139
|
+
const { sign: t, value: e } = d(r), [n, i = ""] = e.split("."), s = i.match(/^0+/)?.[0]?.length || 0, c = s.toString().split("").map((l) => String.fromCharCode(8320 + parseInt(l))).join(""), u = i.slice(s);
|
|
140
|
+
return `${t}${n}.0${c}${u}`;
|
|
141
|
+
}
|
|
142
|
+
function F(r) {
|
|
143
|
+
const { sign: t, value: e } = d(r);
|
|
144
|
+
if (e == "0") return { value: "0", exponent: 0 };
|
|
145
|
+
const [n, i = ""] = e.split(".");
|
|
146
|
+
if (n !== "0") {
|
|
147
|
+
const l = n.length - 1, o = n[0] + "." + (n.slice(1) + i).replace(/0+$/, "");
|
|
148
|
+
return { value: `${t}${o}${o.length > 1, ""}`, exponent: l, sign: "+" };
|
|
149
|
+
}
|
|
150
|
+
const s = i.search(/[1-9]/);
|
|
151
|
+
if (s === -1) return { value: "0", exponent: 0 };
|
|
152
|
+
const c = -(s + 1), u = i[s] + "." + i.slice(s + 1).replace(/0+$/, "");
|
|
153
|
+
return { value: `${t}${u}`, exponent: c - 1, sign: "" };
|
|
100
154
|
}
|
|
101
|
-
function
|
|
155
|
+
function U(r) {
|
|
156
|
+
const { value: t, exponent: e, sign: n } = F(r);
|
|
157
|
+
return e != 0 ? `${t}e${n}${e}` : t;
|
|
158
|
+
}
|
|
159
|
+
function f(r) {
|
|
102
160
|
return {
|
|
103
|
-
round(
|
|
104
|
-
|
|
161
|
+
round: (t) => {
|
|
162
|
+
const e = _(r.value, t);
|
|
163
|
+
return f({ ...r, value: e });
|
|
164
|
+
},
|
|
165
|
+
compact: (t) => {
|
|
166
|
+
if (r.compactedSymbol) return f(r);
|
|
167
|
+
const { value: e, symbol: n } = v(r.value, t);
|
|
168
|
+
return f({ ...r, compactedSymbol: n, value: e });
|
|
169
|
+
},
|
|
170
|
+
notation(t = "scientific") {
|
|
171
|
+
return f({ ...r, notation: t });
|
|
105
172
|
},
|
|
106
|
-
|
|
107
|
-
return
|
|
173
|
+
prefix(t) {
|
|
174
|
+
return f({ ...r, prefix: t });
|
|
108
175
|
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return `${t}${n ? P(String(s)) : s}${e}`;
|
|
176
|
+
suffix(t) {
|
|
177
|
+
return f({ ...r, suffix: t });
|
|
112
178
|
},
|
|
113
|
-
|
|
114
|
-
|
|
179
|
+
toNumber() {
|
|
180
|
+
let { value: t } = r;
|
|
181
|
+
const { sign: e, prefix: n, suffix: i, compactedSymbol: s } = r;
|
|
182
|
+
return r.notation == "scientific" ? t = U(t) : r.notation == "subscript" && (t = k(t)), `${n || ""}${e}${t}${s || ""}${i || ""}`;
|
|
183
|
+
},
|
|
184
|
+
toObject() {
|
|
185
|
+
return r;
|
|
115
186
|
}
|
|
116
187
|
};
|
|
117
188
|
}
|
|
189
|
+
function H(r) {
|
|
190
|
+
return f(E(r));
|
|
191
|
+
}
|
|
118
192
|
export {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
193
|
+
H as FN,
|
|
194
|
+
x as clearTrailingZero,
|
|
195
|
+
A as compact,
|
|
196
|
+
z as parseNum,
|
|
197
|
+
_ as round,
|
|
198
|
+
U as scientific,
|
|
199
|
+
k as subscript
|
|
125
200
|
};
|
package/dist/io.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NumberType, ObjectNumberType, SignType } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Removes redundant leading and trailing zeros from a number string.
|
|
4
|
+
*
|
|
5
|
+
* @param value - The number string to clean.
|
|
6
|
+
* @returns The cleaned number string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function clearTrailingZero(value: string): string;
|
|
9
|
+
export declare function getInput(value: NumberType): {
|
|
10
|
+
sign: SignType;
|
|
11
|
+
value: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Parses various input formats into a standard decimal string.
|
|
15
|
+
* Supports numbers, bigints, currencies ($€£¥), commas, underscores,
|
|
16
|
+
* scientific notation (e+), and custom subscript notation (e.g., "5.0₄6").
|
|
17
|
+
*
|
|
18
|
+
* @param value - The input value to parse.
|
|
19
|
+
* @returns A standardized decimal string.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* parseNum('$1,234.56'); // '1234.56'
|
|
23
|
+
* parseNum('5.0₄6'); // '5.00006'
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseNum(value: NumberType): string;
|
|
26
|
+
export declare function convertToObjectNumber(value: NumberType | ObjectNumberType): ObjectNumberType;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats the decimal part of small numbers using subscript characters
|
|
3
|
+
* to represent the number of consecutive leading zeros.
|
|
4
|
+
*
|
|
5
|
+
* @param value - The number string to format.
|
|
6
|
+
* @returns A string with subscript notation (e.g., '0.0₃5').
|
|
7
|
+
*/
|
|
8
|
+
export declare function subscript(value: string): string;
|
|
9
|
+
export declare function _scientific(value: string): {
|
|
10
|
+
value: string;
|
|
11
|
+
exponent: number;
|
|
12
|
+
sign?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
value: string;
|
|
15
|
+
exponent: number;
|
|
16
|
+
sign: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Formats a number string using standard scientific notation.
|
|
20
|
+
*
|
|
21
|
+
* @param value - The number string to format.
|
|
22
|
+
* @returns A string in scientific notation (e.g., '1.23e+5').
|
|
23
|
+
*/
|
|
24
|
+
export declare function scientific(value: string): string;
|
package/dist/round.d.ts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import { NumberType, RoundingConfigType } from './types';
|
|
2
2
|
export declare function roundPositiveHalf(value: string, precision?: number): string;
|
|
3
|
+
/**
|
|
4
|
+
* Rounds a number based on the specified precision and rounding mode.
|
|
5
|
+
*
|
|
6
|
+
* @param value - The value to be rounded. Can be a number, string, or bigint.
|
|
7
|
+
* @param options - Configuration for rounding.
|
|
8
|
+
* @param options.rounding - The rounding strategy to use ('half', 'up', 'down', 'banker', 'truncate'). Default is 'half'.
|
|
9
|
+
* @param options.precision - The number of decimal places to round to. Default is 0.
|
|
10
|
+
* @returns The rounded number as a string.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* round(123.456, { precision: 2 }); // '123.46'
|
|
14
|
+
* round(123.45, { rounding: 'down', precision: 1 }); // '123.4'
|
|
15
|
+
*/
|
|
3
16
|
export declare function round(value: NumberType, options?: RoundingConfigType): string;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
|
+
/** Supported input types for number formatting */
|
|
1
2
|
export type NumberType = number | string | bigint;
|
|
3
|
+
/** Strategies for rounding numbers */
|
|
2
4
|
export type RoundingMode = 'half' | 'up' | 'down' | 'banker' | 'truncate';
|
|
5
|
+
/** Modes for special numerical notation */
|
|
6
|
+
export type NotationMode = 'subscript' | 'scientific';
|
|
7
|
+
/** Possible sign values for internal number representation */
|
|
8
|
+
export type SignType = '-' | '';
|
|
9
|
+
/** Configuration for rounding operations */
|
|
3
10
|
export type RoundingConfigType = Partial<{
|
|
4
|
-
|
|
11
|
+
/** The rounding strategy to use */
|
|
12
|
+
rounding: RoundingMode;
|
|
13
|
+
/** Number of decimal places to keep */
|
|
5
14
|
precision: number;
|
|
6
15
|
}>;
|
|
7
|
-
|
|
16
|
+
/** Configuration for basic number display properties */
|
|
17
|
+
export type NumberConfigType = Partial<{
|
|
18
|
+
/** Text to prepend to the number (e.g., '$') */
|
|
8
19
|
prefix: string;
|
|
20
|
+
/** Text to append to the number (e.g., ' units') */
|
|
9
21
|
suffix: string;
|
|
10
|
-
|
|
22
|
+
/** The notation style to apply */
|
|
23
|
+
notation: NotationMode;
|
|
11
24
|
}>;
|
|
12
|
-
|
|
25
|
+
/** Internal object structure containing full formatting state */
|
|
26
|
+
export type ObjectNumberType = {
|
|
27
|
+
sign: SignType;
|
|
28
|
+
value: string;
|
|
29
|
+
} & NumberConfigType & Partial<{
|
|
30
|
+
/** The symbol used for compact notation (e.g., 'K', 'M') */
|
|
31
|
+
compactedSymbol: string;
|
|
32
|
+
}>;
|
|
33
|
+
/** Full configuration options for the formatNumber function */
|
|
34
|
+
export type FormattingConfigType = RoundingConfigType & NumberConfigType & Partial<{
|
|
35
|
+
/** Whether to use compact notation (K, M, B, etc.) */
|
|
13
36
|
isCompact: boolean;
|
|
14
37
|
}>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter-present/format-number",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.11",
|
|
4
|
+
"description": "A lightweight, zero-dependency JavaScript/TypeScript library for precise number formatting. Designed for financial applications, crypto dashboards, and scientific data where precision is paramount.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
package/dist/utils.d.ts
DELETED