@peter-present/format-number 0.0.1

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 ADDED
@@ -0,0 +1,116 @@
1
+ # format-number
2
+
3
+ A lightweight, high-precision JavaScript/TypeScript library for rounding and formatting numbers. It handles everything from large financial figures and crypto balances to extremely small fractions with scientific subscripts.
4
+
5
+ Designed for precision-critical applications where numbers often exceed safe integer limits.
6
+
7
+ For detailed documentation and advanced usage, visit: [here](https://blog.peter-present.xyz/format-number)
8
+
9
+ ## Key Features
10
+
11
+ - **High Precision**: Native support for `string`, `number`, and `bigint` without loss of precision.
12
+ - **Multiple Rounding Modes**: 5 different strategies to handle rounding exactly how you need.
13
+ - **Compact Formatting**: Automatically shorten large numbers with suffixes (K, M, B, T, Q).
14
+ - **Small Number Notation**: Smart formatting for tiny numbers using subscript zeros (e.g., `0.0₃5`).
15
+ - **Flexible Metadata**: Easily add prefixes and suffixes (e.g., Currency symbols, Units).
16
+ - **Fluent API**: Chained operations for cleaner, more readable code.
17
+ - **Zero Dependencies**: Keeps your bundle size minimal.
18
+
19
+ ## Installation
20
+
21
+ ```shell
22
+ # npm
23
+ npm install format-number
24
+
25
+ # yarn
26
+ yarn add format-number
27
+
28
+ # bun
29
+ bun install format-number
30
+ ```
31
+
32
+ ## Core Functions
33
+
34
+ ### Rounding: `round()`
35
+
36
+ Round numbers using specific strategies and precision.
37
+
38
+ ```typescript
39
+ import { round } from 'format-number';
40
+
41
+ round(123.456, { precision: 2 }); // '123.46'
42
+ round(-123.45, { mode: 'up', precision: 1 }); // '-123.4' (Towards +Infinity)
43
+ ```
44
+
45
+ ### Compact Formatting: `compact()`
46
+
47
+ Format large numbers with readable suffixes.
48
+
49
+ ```typescript
50
+ import { compact } from 'format-number';
51
+
52
+ compact(1500); // '1.5K'
53
+ compact(1200000, { precision: 1 }); // '1.2M'
54
+ compact('1000000000000'); // '1T'
55
+ ```
56
+
57
+ ### Advanced Formatting: `formatNumber()`
58
+
59
+ A comprehensive function combining rounding, compacting, and metadata.
60
+
61
+ ```typescript
62
+ import { formatNumber } from 'format-number';
63
+
64
+ // Currency formatting
65
+ formatNumber(1234.56, { prefix: '$', precision: 1 }); // '$1234.6'
66
+
67
+ // Compact with metadata
68
+ formatNumber(1500000, { isCompact: true, suffix: ' units' }); // '1.5M units'
69
+
70
+ // Small number subscript notation
71
+ formatNumber(0.00005, { isSmall: true }); // '0.0₄5'
72
+ ```
73
+
74
+ ### Fluent / Chained API: `FN()`
75
+
76
+ Perform multiple operations in a readable chain.
77
+
78
+ ```typescript
79
+ import { FN } from 'format-number';
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'
86
+
87
+ // Compact chaining
88
+ FN(1000000).compact({ precision: 0 }); // '1M'
89
+ ```
90
+
91
+ ## API Reference
92
+
93
+ ### Rounding Modes (`RoundingMode`)
94
+
95
+ | Mode | Description |
96
+ | :--------- | :------------------------------------------------------------------- |
97
+ | `half` | Round to the nearest neighbor. If equidistant, round away from zero. |
98
+ | `up` | Round towards Positive Infinity. |
99
+ | `down` | Round towards Negative Infinity. |
100
+ | `truncate` | Round towards Zero. |
101
+ | `banker` | Round to the nearest even neighbor (Statistical rounding). |
102
+
103
+ ### Configuration Options
104
+
105
+ | Option | Type | Description |
106
+ | :---------- | :------------- | :----------------------------------------------- |
107
+ | `precision` | `number` | Number of decimal places (default: `0`). |
108
+ | `mode` | `RoundingMode` | Rounding strategy (default: `'half'`). |
109
+ | `prefix` | `string` | Text to prepend to the result. |
110
+ | `suffix` | `string` | Text to append to the result. |
111
+ | `isCompact` | `boolean` | If `true`, uses K/M/B/T suffixes. |
112
+ | `isSmall` | `boolean` | If `true`, formats tiny numbers with subscripts. |
113
+
114
+ ## License
115
+
116
+ ISC
@@ -0,0 +1,2 @@
1
+ import { RoundingConfigType, NumberType } from './types';
2
+ export declare function compact(value: NumberType, options?: RoundingConfigType): string;
@@ -0,0 +1,8 @@
1
+ import { MetadataType, NumberType, OtherMetadataType, RoundingConfigType } from './types';
2
+ export declare function formatNumber(value: NumberType, options?: MetadataType): string;
3
+ export declare function FN(value: NumberType): {
4
+ round(options?: RoundingConfigType): any;
5
+ compact(options?: RoundingConfigType): string;
6
+ format(options?: OtherMetadataType): string;
7
+ toString(): string;
8
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function f(s){const r=s.startsWith("-")?"-":"",t=r?s.slice(1):s;let e=0,n=t.length-1;for(;t[e]=="0"&&e<t.length;)e++;if(s.indexOf(".")>=0)for(;t[n]=="0"&&n>=0;)n--;const u=t.slice(e,n+1);return u==""||u=="."?"0":r+u}function g(s){let r=f(s);r=(r.startsWith("-")?"-":"")?r.slice(1):r;const[e,n=""]=r.split("."),i=n.match(/^0+/)?.[0]?.length||0,u=i.toString().split("").map(o=>String.fromCharCode(8320+parseInt(o))).join(""),c=n.slice(i);return`${e}.0${u}${c}`}function l(s){let r="",t=s.length-1,e="1";for(;t>=0;){const n=s[t];let i=Number(n)+(e?1:0);i>=10?(e="1",i-=10):e="",r=i.toString()+r,t--}return{result:e+r,remaining:e}}function S(s,r=0){const[t,e=""]=s.split(".");if(r===0)return e&&Number(e[0])>=5?l(t).result:t;if(r>=e.length)return t+(e?`.${e}`:"");const n=e.slice(0,r),i=e.slice(r);if(Number(i[0])>=5){const u=l(n);return u.remaining?l(t).result:t+"."+u.result}else return t+"."+n}function d(s,r=0){const[t,e=""]=s.split(".");if(r===0)return e?l(t).result:t;if(r>=e.length)return t+"."+e;const n=l(e.slice(0,r));return n.remaining?l(t).result:t+"."+n.result}function m(s,r=0){const[t,e=""]=s.split(".");if(r===0)return t;let n=e.slice(0,r),i=n.length-1;for(;i>=0&&n[i]=="0";)i--;return n=n.slice(0,i+1),t+(n?`.${n}`:"")}function $(s,r=0){const[t,e=""]=s.split(".");if(r===0)return e&&Number(e[0])>=5?Number(t[0])/2==0?t:l(t).result:t;if(r>=e.length)return t+(e?`.${e}`:"");const n=e.slice(0,r),i=e.slice(r);if(i[0]=="5"){if(Number(n[n.length-1])%2==0)return t+"."+n;{const u=l(n);return u.remaining?l(t).result:t+"."+u.result}}else if(Number(i[0])>5){const u=l(n);return u.remaining?l(t).result:t+"."+u.result}else return t+"."+n}function a(s,r={}){const t=r.mode||"half",e=r.precision||0;let n=f(String(s)),i="";switch(n.startsWith("-")&&(n=n.slice(1),i="-"),t){case"half":return i+S(n,e);case"up":return i==""?d(n,e):"-"+m(n,e);case"down":return i==""?m(n,e):"-"+d(n,e);case"truncate":return i+m(n,e);case"banker":return i+$(n,e)}}const b=["K","M","B","T","Q"];function P(s,r={}){let t=f(String(s)),e="";t.startsWith("-")&&(t=t.slice(1),e="-");let[n,i=""]=t.split("."),u=n.length,c=-1;for(;u>3&&c<4;){const o=n.slice(0,u-3);i=n.slice(u-3)+i,n=o,u-=3,c++}return a(`${e}${n}.${i}`,r)+(c>=0?b[c]:"")}function N(s,r){let t=String(s);r.isCompact==!0?t=P(t,r):r.isSmall||(t=a(t,r));const e=r.prefix||"",n=r.suffix||"",i=r.isSmall||!1;return`${e}${i?g(t):t}${n}`}function h(s){return{round(r={}){return h(a(s,r))},compact(r={}){return P(s,r)},format(r={}){const t=r.prefix||"",e=r.suffix||"",n=r.isSmall||!1;return`${t}${n?g(String(s)):s}${e}`},toString(){return String(s)}}}exports.FN=h;exports.compact=P;exports.formatNumber=N;exports.formatSmallNum=g;exports.removeZero=f;exports.round=a;
@@ -0,0 +1,5 @@
1
+ export * from './types';
2
+ export * from './utils';
3
+ export { compact } from './compact';
4
+ export { FN, formatNumber } from './format';
5
+ export { round } from './round';
package/dist/index.js ADDED
@@ -0,0 +1,125 @@
1
+ function o(s) {
2
+ const r = s.startsWith("-") ? "-" : "", t = r ? s.slice(1) : s;
3
+ let e = 0, n = t.length - 1;
4
+ for (; t[e] == "0" && e < t.length; ) e++;
5
+ if (s.indexOf(".") >= 0) for (; t[n] == "0" && n >= 0; ) n--;
6
+ const l = t.slice(e, n + 1);
7
+ return l == "" || l == "." ? "0" : r + l;
8
+ }
9
+ function P(s) {
10
+ let r = o(s);
11
+ r = (r.startsWith("-") ? "-" : "") ? r.slice(1) : r;
12
+ const [e, n = ""] = r.split("."), i = n.match(/^0+/)?.[0]?.length || 0, l = i.toString().split("").map((f) => String.fromCharCode(8320 + parseInt(f))).join(""), c = n.slice(i);
13
+ return `${e}.0${l}${c}`;
14
+ }
15
+ function u(s) {
16
+ let r = "", t = s.length - 1, e = "1";
17
+ for (; t >= 0; ) {
18
+ const n = s[t];
19
+ let i = Number(n) + (e ? 1 : 0);
20
+ i >= 10 ? (e = "1", i -= 10) : e = "", r = i.toString() + r, t--;
21
+ }
22
+ return { result: e + r, remaining: e };
23
+ }
24
+ function d(s, r = 0) {
25
+ const [t, e = ""] = s.split(".");
26
+ if (r === 0)
27
+ return e && Number(e[0]) >= 5 ? u(t).result : t;
28
+ if (r >= e.length) return t + (e ? `.${e}` : "");
29
+ const n = e.slice(0, r), i = e.slice(r);
30
+ if (Number(i[0]) >= 5) {
31
+ const l = u(n);
32
+ return l.remaining ? u(t).result : t + "." + l.result;
33
+ } else return t + "." + n;
34
+ }
35
+ function g(s, r = 0) {
36
+ const [t, e = ""] = s.split(".");
37
+ if (r === 0)
38
+ return e ? u(t).result : t;
39
+ if (r >= e.length) return t + "." + e;
40
+ const n = u(e.slice(0, r));
41
+ return n.remaining ? u(t).result : t + "." + n.result;
42
+ }
43
+ function a(s, r = 0) {
44
+ const [t, e = ""] = s.split(".");
45
+ if (r === 0) return t;
46
+ let n = e.slice(0, r), i = n.length - 1;
47
+ for (; i >= 0 && n[i] == "0"; ) i--;
48
+ return n = n.slice(0, i + 1), t + (n ? `.${n}` : "");
49
+ }
50
+ function S(s, r = 0) {
51
+ const [t, e = ""] = s.split(".");
52
+ if (r === 0)
53
+ return e && Number(e[0]) >= 5 ? Number(t[0]) / 2 == 0 ? t : u(t).result : t;
54
+ if (r >= e.length) return t + (e ? `.${e}` : "");
55
+ const n = e.slice(0, r), i = e.slice(r);
56
+ if (i[0] == "5") {
57
+ if (Number(n[n.length - 1]) % 2 == 0)
58
+ return t + "." + n;
59
+ {
60
+ const l = u(n);
61
+ return l.remaining ? u(t).result : t + "." + l.result;
62
+ }
63
+ } else if (Number(i[0]) > 5) {
64
+ const l = u(n);
65
+ return l.remaining ? u(t).result : t + "." + l.result;
66
+ } else return t + "." + n;
67
+ }
68
+ function m(s, r = {}) {
69
+ const t = r.mode || "half", e = r.precision || 0;
70
+ let n = o(String(s)), i = "";
71
+ switch (n.startsWith("-") && (n = n.slice(1), i = "-"), t) {
72
+ case "half":
73
+ return i + d(n, e);
74
+ case "up":
75
+ return i == "" ? g(n, e) : "-" + a(n, e);
76
+ case "down":
77
+ return i == "" ? a(n, e) : "-" + g(n, e);
78
+ case "truncate":
79
+ return i + a(n, e);
80
+ case "banker":
81
+ return i + S(n, e);
82
+ }
83
+ }
84
+ const $ = ["K", "M", "B", "T", "Q"];
85
+ function h(s, r = {}) {
86
+ let t = o(String(s)), e = "";
87
+ t.startsWith("-") && (t = t.slice(1), e = "-");
88
+ let [n, i = ""] = t.split("."), l = n.length, c = -1;
89
+ for (; l > 3 && c < 4; ) {
90
+ const f = n.slice(0, l - 3);
91
+ i = n.slice(l - 3) + i, n = f, l -= 3, c++;
92
+ }
93
+ return m(`${e}${n}.${i}`, r) + (c >= 0 ? $[c] : "");
94
+ }
95
+ function b(s, r) {
96
+ let t = String(s);
97
+ r.isCompact == !0 ? t = h(t, r) : r.isSmall || (t = m(t, r));
98
+ const e = r.prefix || "", n = r.suffix || "", i = r.isSmall || !1;
99
+ return `${e}${i ? P(t) : t}${n}`;
100
+ }
101
+ function x(s) {
102
+ return {
103
+ round(r = {}) {
104
+ return x(m(s, r));
105
+ },
106
+ compact(r = {}) {
107
+ return h(s, r);
108
+ },
109
+ format(r = {}) {
110
+ const t = r.prefix || "", e = r.suffix || "", n = r.isSmall || !1;
111
+ return `${t}${n ? P(String(s)) : s}${e}`;
112
+ },
113
+ toString() {
114
+ return String(s);
115
+ }
116
+ };
117
+ }
118
+ export {
119
+ x as FN,
120
+ h as compact,
121
+ b as formatNumber,
122
+ P as formatSmallNum,
123
+ o as removeZero,
124
+ m as round
125
+ };
@@ -0,0 +1,3 @@
1
+ import { NumberType, RoundingConfigType } from './types';
2
+ export declare function roundPositiveHalf(value: string, precision?: number): string;
3
+ export declare function round(value: NumberType, options?: RoundingConfigType): string;
@@ -0,0 +1,14 @@
1
+ export type NumberType = number | string | bigint;
2
+ export type RoundingMode = 'half' | 'up' | 'down' | 'banker' | 'truncate';
3
+ export type RoundingConfigType = Partial<{
4
+ mode: RoundingMode;
5
+ precision: number;
6
+ }>;
7
+ export type OtherMetadataType = Partial<{
8
+ prefix: string;
9
+ suffix: string;
10
+ isSmall: boolean;
11
+ }>;
12
+ export type MetadataType = RoundingConfigType & OtherMetadataType & Partial<{
13
+ isCompact: boolean;
14
+ }>;
@@ -0,0 +1,2 @@
1
+ export declare function removeZero(value: string): string;
2
+ export declare function formatSmallNum(value: string): string;
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@peter-present/format-number",
3
+ "version": "0.0.1",
4
+ "description": "Utility library for number formatting, rounding, and compact display.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "bun run clear && tsc && vite build",
14
+ "preview": "vite preview",
15
+ "clear": "rm -rf dist",
16
+ "test": "vitest run",
17
+ "prepare": "bun run build",
18
+ "eslint": "eslint --config ./eslint.config.js --cache",
19
+ "format": "prettier --write .",
20
+ "prepublishOnly": "bun run clear && bun run build && bun run test"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/phamhongphuc1999/format-number.git"
25
+ },
26
+ "keywords": [
27
+ "number",
28
+ "format",
29
+ "number-format",
30
+ "compact"
31
+ ],
32
+ "author": "phamhongphuc1999",
33
+ "license": "ISC",
34
+ "bugs": {
35
+ "url": "https://github.com/phamhongphuc1999/format-number/issues"
36
+ },
37
+ "homepage": "https://github.com/phamhongphuc1999/format-number#readme",
38
+ "devDependencies": {
39
+ "@eslint/js": "^9.29.0",
40
+ "@types/node": "^20.12.2",
41
+ "eslint": "^9.29.0",
42
+ "eslint-import-resolver-typescript": "^4.4.4",
43
+ "eslint-plugin-import": "^2.32.0",
44
+ "eslint-plugin-prettier": "^5.5.1",
45
+ "eslint-plugin-react-hooks": "^5.2.0",
46
+ "eslint-plugin-react-refresh": "^0.4.20",
47
+ "path": "^0.12.7",
48
+ "tslib": "^2.6.2",
49
+ "typescript": "5.5.3",
50
+ "typescript-eslint": "^8.34.1",
51
+ "vite": "^7.2.7",
52
+ "vite-plugin-dts": "^4.5.4",
53
+ "vitest": "^4.0.15"
54
+ },
55
+ "contributors": [
56
+ {
57
+ "name": "Phạm Hồng Phúc",
58
+ "email": "phamhongphuc12atm1@gmail.com",
59
+ "url": "https://github.com/phamhongphuc1999"
60
+ }
61
+ ],
62
+ "engines": {
63
+ "node": ">=16",
64
+ "npm": ">=7"
65
+ }
66
+ }