reduce-precision 1.0.7 → 1.2.0
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/package.json +21 -21
- package/ts/lib/bundle.min.js +1 -1
- package/ts/lib/{format → src/format}/index.d.ts +4 -2
- package/ts/lib/{format → src/format}/index.js +275 -24
- package/ts/lib/test/format/index.spec.d.ts +1 -0
- package/ts/lib/test/format/index.spec.js +149 -0
- /package/ts/lib/{index.d.ts → src/index.d.ts} +0 -0
- /package/ts/lib/{index.js → src/index.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reduce-precision",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./ts/lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -31,26 +31,26 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/ArzDigitalLabs/reduce-precision#readme",
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@babel/core": "^7.
|
|
35
|
-
"@babel/preset-env": "^7.
|
|
36
|
-
"@types/jest": "^
|
|
37
|
-
"@types/node": "^
|
|
38
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
39
|
-
"@typescript-eslint/parser": "^
|
|
40
|
-
"babel-loader": "^
|
|
41
|
-
"eslint": "^
|
|
42
|
-
"eslint-config-prettier": "^
|
|
34
|
+
"@babel/core": "^7.28.0",
|
|
35
|
+
"@babel/preset-env": "^7.28.0",
|
|
36
|
+
"@types/jest": "^30.0.0",
|
|
37
|
+
"@types/node": "^24.2.1",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^8.39.1",
|
|
39
|
+
"@typescript-eslint/parser": "^8.39.1",
|
|
40
|
+
"babel-loader": "^10.0.0",
|
|
41
|
+
"eslint": "^9.33.0",
|
|
42
|
+
"eslint-config-prettier": "^10.1.8",
|
|
43
43
|
"eslint-plugin-node": "^11.1.0",
|
|
44
|
-
"eslint-plugin-prettier": "^
|
|
45
|
-
"jest": "^
|
|
46
|
-
"lint-staged": "^
|
|
47
|
-
"prettier": "^
|
|
48
|
-
"ts-jest": "^
|
|
49
|
-
"ts-loader": "^9.5.
|
|
50
|
-
"ts-node": "^10.2
|
|
51
|
-
"typescript": "^
|
|
52
|
-
"webpack": "^5.
|
|
53
|
-
"webpack-cli": "^
|
|
44
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
45
|
+
"jest": "^30.0.5",
|
|
46
|
+
"lint-staged": "^16.1.5",
|
|
47
|
+
"prettier": "^3.6.2",
|
|
48
|
+
"ts-jest": "^29.4.1",
|
|
49
|
+
"ts-loader": "^9.5.2",
|
|
50
|
+
"ts-node": "^10.9.2",
|
|
51
|
+
"typescript": "^5.9.2",
|
|
52
|
+
"webpack": "^5.101.0",
|
|
53
|
+
"webpack-cli": "^6.0.1"
|
|
54
54
|
},
|
|
55
55
|
"lint-staged": {
|
|
56
56
|
"*.ts": "eslint --cache --cache-location .eslintcache --fix"
|
|
@@ -60,4 +60,4 @@
|
|
|
60
60
|
"main"
|
|
61
61
|
]
|
|
62
62
|
}
|
|
63
|
-
}
|
|
63
|
+
}
|
package/ts/lib/bundle.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ReducePrecision=t():e.ReducePrecision=t()}(self,(()=>(()=>{"use strict";var e={900:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.default=class{constructor(e={}){this.languageBaseConfig={prefixMarker:"i",postfixMarker:"i",prefix:"",postfix:""},this.defaultLanguageConfig={en:Object.assign(Object.assign({},this.languageBaseConfig),{thousandSeparator:",",decimalSeparator:"."}),fa:Object.assign(Object.assign({},this.languageBaseConfig),{thousandSeparator:"٫",decimalSeparator:"٬"})},this.options=Object.assign({language:"en",template:"number",precision:"high",outputFormat:"plain"},this.defaultLanguageConfig.en),this.options=Object.assign(Object.assign({},this.options),e)}setLanguage(e,t={}){return this.options.language=e,this.options.prefixMarker=t.prefixMarker||this.defaultLanguageConfig[e].prefixMarker,this.options.postfixMarker=t.postfixMarker||this.defaultLanguageConfig[e].postfixMarker,this.options.prefix=t.prefix||this.defaultLanguageConfig[e].prefix,this.options.postfix=t.postfix||this.defaultLanguageConfig[e].postfix,this.options.thousandSeparator=t.thousandSeparator||this.defaultLanguageConfig[e].thousandSeparator,this.options.decimalSeparator=t.decimalSeparator||this.defaultLanguageConfig[e].decimalSeparator,this}setTemplate(e,t){return this.options.template=e,this.options.precision=t,this}toJson(e){const t=this.format(e);return delete t.value,t}toString(e){return this.format(e).value||""}toPlainString(e){return this.options.outputFormat="plain",this.format(e).value||""}toHtmlString(e){return this.options.outputFormat="html",this.format(e).value||""}toMdString(e){return this.options.outputFormat="markdown",this.format(e).value||""}isENotation(e){return/^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)$/.test(e)}format(e){let{precision:t,template:r}=this.options;const{language:i,outputFormat:n,prefixMarker:o,postfixMarker:a,prefix:s,postfix:l,thousandSeparator:u,decimalSeparator:g}=this.options;if(null==e||""===e)return{};(null==r?void 0:r.match(/^(number|usd|irt|irr|percent)$/g))||(r="number");const f=e.toString();this.isENotation(f)&&(e=this.convertENotationToRegularNumber(Number(e)));let p=e.toString().replace(/[\u0660-\u0669\u06F0-\u06F9]/g,(function(e){return String(15&e.charCodeAt(0))})).replace(/[^\d.-]/g,"");p=p.replace(/^0+(?=\d)/g,"");const c=Math.abs(Number(p));let h,d,m,b,x=0;if("auto"===t&&(r.match(/^(usd|irt|irr|number)$/g)?t=c>=1e-4&&c<1e11?"high":"medium":"percent"===r&&(t="low")),"medium"===t)if(c>=0&&c<1e-4)h=33,d=4,m=!1,b=!0;else if(c>=1e-4&&c<.001)h=7,d=4,m=!1,b=!1;else if(c>=.001&&c<.01)h=5,d=3,m=!1,b=!1;else if(c>=.001&&c<.1)h=3,d=2,m=!1,b=!1;else if(c>=.1&&c<1)h=1,d=1,m=!1,b=!1;else if(c>=1&&c<10)h=3,d=3,m=!1,b=!1;else if(c>=10&&c<100)h=2,d=2,m=!1,b=!1;else if(c>=100&&c<1e3)h=1,d=1,m=!1,b=!1;else if(c>=1e3){const e=Math.floor(Math.log10(c))%3;h=2-e,d=2-e,m=!0,b=!0}else h=0,d=0,m=!0,b=!0;else if("low"===t)if(c>=0&&c<.01)h=2,d=0,m=!0,b=!1,x=2;else if(c>=.01&&c<.1)h=2,d=1,m=!0,b=!1;else if(c>=.1&&c<1)h=2,d=2,m=!0,b=!1;else if(c>=1&&c<10)h=2,d=2,m=!0,b=!1,x=2;else if(c>=10&&c<100)h=1,d=1,m=!0,b=!1,x=1;else if(c>=100&&c<1e3)h=0,d=0,m=!0,b=!1;else if(c>=1e3){const e=Math.floor(Math.log10(c))%3;h=1-e,d=1-e,m=!0,b=!0}else h=0,d=0,m=!0,b=!0,x=2;else c>=0&&c<1?(h=33,d=4,m=!1,b=!1):c>=1&&c<10?(h=3,d=3,m=!0,b=!1):c>=10&&c<100||c>=100&&c<1e3?(h=2,d=2,m=!0,b=!1):c>=1e3&&c<1e4?(h=1,d=1,m=!0,b=!1):(h=0,d=0,m=!0,b=!1);return this.isENotation(f)&&(h=Math.max(h,20),m=!1),this.reducePrecision(p,h,d,m,b,x,r,i,n,o,a,s,l,u,g,f)}convertENotationToRegularNumber(e){if(Number.isInteger(e)&&e>=1e3)return e.toString();const t=e.toString().toLowerCase().split("e");if(2!==t.length)return e.toString();parseFloat(t[0]);const r=parseInt(t[1],10);if(r<0){const i=Math.abs(r)+(t[0].includes(".")?t[0].split(".")[1].length:0);return e.toFixed(i)}return e.toString()}reducePrecision(e,t=30,r=4,i=!1,n=!1,o=0,a="number",s="en",l="plain",u="span",g="span",f="",p="",c=",",h=".",d=""){var m,b;if(null==e||""===e.trim())return{};"-0"!==e&&"-0.0"!==e||(e=e.substring(1)),e=e.toString();const x=a.match(/^(number|percent)$/g)?{"":"",K:" هزار",M:" میلیون",B:" میلیارد",T:" تریلیون",Qd:" کادریلیون",Qt:" کنتیلیون"}:{"":"",K:" هزار ت",M:" میلیون ت",B:" میلیارد ت",T:" همت",Qd:" هزار همت",Qt:" میلیون همت"},S=a.match(/^(number|percent)$/g)?{"":"",K:" هزار",M:" میلیون",B:" میلیارد",T:" تریلیون",Qd:" کادریلیون",Qt:" کنتیلیون"}:{"":"",K:" هزار تومان",M:" میلیون تومان",B:" میلیارد تومان",T:" هزار میلیارد تومان",Qd:" کادریلیون تومان",Qt:" کنتیلیون تومان"};let $=/^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(e);if(!$)return{};const M=$[1]||"";let v=$[2],C=$[3],N=$[4],Q="",j="";if(C.length>=30?(C="0".padEnd(29,"0"),N="1"):C.length+r>t?(r=t-C.length)<1&&(r=1):v.length>21&&(v="0",C="",N=""),n&&v.length>=4){const e=Object.keys(x);let t=v,r=0;for(;+t>999&&r<e.length-1;)t=(+t/1e3).toFixed(2),r++;if(j=e[r],$=/^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(t.toString()),!$)return{};v=$[2],C=$[3],N=$[4]}N.length>r&&(i?parseInt(N[r])<5?N=N.substring(0,r):(N=(parseInt(N.substring(0,r))+1).toString(),N.length>r&&(C.length>0?C=C.substring(0,C.length-1):(v=(Number(v)+1).toString(),N=N.substring(1)))):N=N.substring(0,r)),n&&""!==C&&""===j&&(C="0"+C.length.toString().replace(/\d/g,(function(e){return["₀","₁","₂","₃","₄","₅","₆","₇","₈","₉"][parseInt(e,10)]})));let k=`${C}${N}`;if(k.length>t&&!d.includes("e")&&(k=k.substring(0,t)),d.includes("e")||d.includes("E"));else if(d.includes(".")){const e=d.split(".");if(2===e.length){const t=e[1];if(t.length>k.length&&t.endsWith("0")){let e=0;for(let r=t.length-1;r>=0&&"0"===t[r];r--)e++;e>0&&(k=k.padEnd(k.length+e,"0"))}}}"usd"===a?(Q="en"===s?"$":"",j||(j="fa"===s?" دلار":"")):"irr"===a?j||(j="fa"===s?" ر":" R"):"irt"===a?j||(j="fa"===s?" ت":" T"):"percent"===a&&(j+="en"===s?"%":j?" درصد":"٪"),Q=f+Q,j+=p,"html"===l?(Q&&(Q=`<${u}>${Q}</${u}>`),j&&(j=`<${g}>${j}</${g}>`)):"markdown"===l&&(Q&&(Q=`${u}${Q}${u}`),j&&(j=`${g}${j}${g}`));const B=/\B(?=(\d{3})+(?!\d))/g,F=o?".".padEnd(o+1,"0"):"";let T,E="";T=t<=0||r<=0||""===N&&""===C?`${v.replace(B,",")}${F}`:`${v.replace(B,",")}.${k}`,E=`${M}${Q}${T}${j}`;const L={value:E,prefix:Q,postfix:j,sign:M,wholeNumber:T};return L.value=(null!==(m=null==L?void 0:L.value)&&void 0!==m?m:"").replace(/,/g,c).replace(/\./g,h),"fa"===s&&(L.value=(null!==(b=null==L?void 0:L.value)&&void 0!==b?b:"").replace(/[0-9]/g,(e=>String.fromCharCode(e.charCodeAt(0)+1728))).replace(/(K|M|B|T|Qt|Qd)/g,(function(e){return String(x[e])})),L.fullPostfix=j.replace(/[0-9]/g,(e=>String.fromCharCode(e.charCodeAt(0)+1728))).replace(/(K|M|B|T|Qt|Qd)/g,(function(e){return String(S[e])})),L.postfix=L.postfix.replace(/[0-9]/g,(e=>String.fromCharCode(e.charCodeAt(0)+1728))).replace(/(K|M|B|T|Qt|Qd)/g,(function(e){return String(x[e])})),L.wholeNumber=L.wholeNumber.replace(/[0-9]/g,(e=>String.fromCharCode(e.charCodeAt(0)+1728))).replace(/(K|M|B|T|Qt|Qd)/g,(function(e){return String(x[e])}))),L}}},986:function(e,t,r){var i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.NumberFormatter=void 0;const n=i(r(900));t.NumberFormatter=n.default}},t={};return function r(i){var n=t[i];if(void 0!==n)return n.exports;var o=t[i]={exports:{}};return e[i].call(o.exports,o,o.exports,r),o.exports}(986)})()));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ReducePrecision=t():e.ReducePrecision=t()}(self,()=>(()=>{"use strict";var e={900:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.default=class{constructor(e={}){this.languageBaseConfig={prefixMarker:"i",postfixMarker:"i",prefix:"",postfix:""},this.defaultLanguageConfig={en:Object.assign(Object.assign({},this.languageBaseConfig),{thousandSeparator:",",decimalSeparator:"."}),fa:Object.assign(Object.assign({},this.languageBaseConfig),{thousandSeparator:"٬",decimalSeparator:"٫"})},this.options=Object.assign({language:"en",template:"number",precision:"high",outputFormat:"plain"},this.defaultLanguageConfig.en),this.options=Object.assign(Object.assign({},this.options),e)}setLanguage(e,t={}){return this.options.language=e,this.options.prefixMarker=t.prefixMarker||this.defaultLanguageConfig[e].prefixMarker,this.options.postfixMarker=t.postfixMarker||this.defaultLanguageConfig[e].postfixMarker,this.options.prefix=t.prefix||this.defaultLanguageConfig[e].prefix,this.options.postfix=t.postfix||this.defaultLanguageConfig[e].postfix,this.options.thousandSeparator=t.thousandSeparator||this.defaultLanguageConfig[e].thousandSeparator,this.options.decimalSeparator=t.decimalSeparator||this.defaultLanguageConfig[e].decimalSeparator,this}setTemplate(e,t){return this.options.template=e,this.options.precision=t,this}toJson(e){const t=this.format(e);return delete t.value,t}toString(e){return this.format(e).value||""}toPlainString(e){return this.options.outputFormat="plain",this.format(e).value||""}toHtmlString(e){return this.options.outputFormat="html",this.format(e).value||""}toMdString(e){return this.options.outputFormat="markdown",this.format(e).value||""}isENotation(e){return/^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)$/.test(e)}convertENotationToRegularNumber(e,t){let r=String(e);if(0===e&&t){const e=t.toLowerCase().split("e");if(2===e.length&&e[0].match(/^0\.0*$/))return e[0]}if(-1===r.toLowerCase().indexOf("e"))return r;if(Math.abs(e)<1&&0!==e){const t=r.toLowerCase().split("e");if(2===t.length){const r=parseInt(t[1],10);if(r<0){let i=Math.abs(r);return t[0].includes(".")&&(i+=t[0].split(".")[1].length),e.toFixed(Math.min(i,100))}}}const i=r.toLowerCase().split("e");if(2===i.length){const t=i[0],r=parseInt(i[1],10);let[n,o]=t.split(".");if(o=o||"",r>0){const e=n.startsWith("-")?"-":"";return e&&(n=n.substring(1)),o.length<=r?e+n+o.padEnd(r,"0"):e+n+o.substring(0,r)+"."+o.substring(r)}if(r<0){let i=Math.abs(r);return t.includes(".")&&(i+=t.split(".")[1].length),e.toFixed(Math.min(i,100))}return t}return r}format(e){var t;let{precision:r,template:i}=this.options;const{language:n,outputFormat:o,prefixMarker:s,postfixMarker:a,prefix:l,postfix:u,thousandSeparator:g,decimalSeparator:f}=this.options;if(null==e||""===e)return{};const p=e.toString();if("liveformat"===i){let e=this._sanitizeLiveInput(p);const r=g||",",i=f||".";let n=p.replace(/[٠-٩۰-۹]/g,function(e){return String(15&e.charCodeAt(0))});if("fa"===(null!==(t=this.options.language)&&void 0!==t?t:"en")){const e=this.defaultLanguageConfig.fa.decimalSeparator||"٫";n=n.replace(new RegExp(e,"g"),".")}if(this.isENotation(n)&&0===Number(n)){const t=p.toLowerCase().indexOf("e");if(t>-1){const r=p.substring(0,t).replace(/[٠-٩۰-۹]/g,function(e){return String(15&e.charCodeAt(0))});let n=r;r.includes(".")&&"."!==i?n=r.replace(".",i):r.includes("٫")&&"٫"!==i&&(n=r.replace("٫",i));const o=new RegExp(`^0\\${i}0*$`);n.match(o)&&(e=n)}}let o="";if(e.startsWith("-")&&(o="-",e=e.substring(1)),""===e)return{value:"",prefix:"",postfix:"",sign:"",wholeNumber:""};if("0"===e){let e="0";return"fa"===this.options.language&&(e=String.fromCharCode("0".charCodeAt(0)+1728)),{value:e,prefix:"",postfix:"",sign:"",wholeNumber:e}}e===i&&(e="0"+i);let s="",a="",l=!1;if(e.includes(i)){l=!0;const t=e.split(i);s=t[0],a=t.length>1?t[1]:""}else if("."!==i&&e.includes(".")){l=!0;const t=e.split(".");s=t[0],a=t.length>1?t[1]:""}else s=e;if(""===s)s="0";else if("0"!==s){const e=s.replace(/^0+/,"");s=""===e?"0":e}let u=s.replace(/\B(?=(\d{3})+(?!\d))/g,r);l&&(u+=i+a);const c=u;let h="",d=c;"-"===o&&(0!==parseFloat(c)||c.includes(".")?(h="-",d=o+c):h="");const m=this._convertToFarsiDigits(u);let b="";return"-"===o&&(b="0"===u?"":"-"),{value:b+m,prefix:"",postfix:"",sign:b,wholeNumber:m}}(null==i?void 0:i.match(/^(number|usd|irt|irr|percent|liveformat)$/g))||(i="number"),this.isENotation(p)&&(e=this.convertENotationToRegularNumber(Number(e)));let c=e.toString().replace(/[\u0660-\u0669\u06F0-\u06F9]/g,function(e){return String(15&e.charCodeAt(0))}).replace(/[^\d.-]/g,"");c=c.replace(/^0+(?=\d)/g,"");const h=Math.abs(Number(c));let d,m,b,x,v=0;if("auto"===r&&(i.match(/^(usd|irt|irr|number)$/g)?r=h>=1e-4&&h<1e11?"high":"medium":"percent"===i&&(r="low")),"medium"===r)if(h>=0&&h<1e-4)d=33,m=4,b=!1,x=!0;else if(h>=1e-4&&h<.001)d=7,m=4,b=!1,x=!1;else if(h>=.001&&h<.01)d=5,m=3,b=!1,x=!1;else if(h>=.001&&h<.1)d=3,m=2,b=!1,x=!1;else if(h>=.1&&h<1)d=1,m=1,b=!1,x=!1;else if(h>=1&&h<10)d=3,m=3,b=!1,x=!1;else if(h>=10&&h<100)d=2,m=2,b=!1,x=!1;else if(h>=100&&h<1e3)d=1,m=1,b=!1,x=!1;else if(h>=1e3){const e=Math.floor(Math.log10(h))%3;d=2-e,m=2-e,b=!0,x=!0}else d=0,m=0,b=!0,x=!0;else if("low"===r)if(h>=0&&h<.01)d=2,m=0,b=!0,x=!1,v=2;else if(h>=.01&&h<.1)d=2,m=1,b=!0,x=!1;else if(h>=.1&&h<1)d=2,m=2,b=!0,x=!1;else if(h>=1&&h<10)d=2,m=2,b=!0,x=!1,v=2;else if(h>=10&&h<100)d=1,m=1,b=!0,x=!1,v=1;else if(h>=100&&h<1e3)d=0,m=0,b=!0,x=!1;else if(h>=1e3){const e=Math.floor(Math.log10(h))%3;d=1-e,m=1-e,b=!0,x=!0}else d=0,m=0,b=!0,x=!0,v=2;else h>=0&&h<1?(d=33,m=4,b=!1,x=!1):h>=1&&h<10?(d=3,m=3,b=!0,x=!1):h>=10&&h<100||h>=100&&h<1e3?(d=2,m=2,b=!0,x=!1):h>=1e3&&h<1e4?(d=1,m=1,b=!0,x=!1):(d=0,m=0,b=!0,x=!1);return this.isENotation(p)&&(d=Math.max(d,20),b=!1),this.reducePrecision(c,d,m,b,x,v,i,n,o,s,a,l,u,g,f,p)}reducePrecision(e,t=30,r=4,i=!1,n=!1,o=0,s="number",a="en",l="plain",u="span",g="span",f="",p="",c=",",h=".",d=""){var m,b;if(null==e||""===e.trim())return{};"-0"!==e&&"-0.0"!==e||(e=e.substring(1)),e=e.toString();const x=s.match(/^(number|percent)$/g)?{"":"",K:" هزار",M:" میلیون",B:" میلیارد",T:" تریلیون",Qd:" کادریلیون",Qt:" کنتیلیون"}:{"":"",K:" هزار ت",M:" میلیون ت",B:" میلیارد ت",T:" همت",Qd:" هزار همت",Qt:" میلیون همت"},v=s.match(/^(number|percent)$/g)?{"":"",K:" هزار",M:" میلیون",B:" میلیارد",T:" تریلیون",Qd:" کادریلیون",Qt:" کنتیلیون"}:{"":"",K:" هزار تومان",M:" میلیون تومان",B:" میلیارد تومان",T:" هزار میلیارد تومان",Qd:" کادریلیون تومان",Qt:" کنتیلیون تومان"};let C=/^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(e);if(!C)return{};const S=C[1]||"";let M=C[2],$=C[3],N=C[4],w="",L="";if($.length>=30?($="0".padEnd(29,"0"),N="1"):$.length+r>t?(r=t-$.length)<1&&(r=1):M.length>21&&(M="0",$="",N=""),n&&M.length>=4){const e=Object.keys(x);let t=M,r=0;for(;+t>999&&r<e.length-1;)t=(+t/1e3).toFixed(2),r++;if(L=e[r],C=/^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(t.toString()),!C)return{};M=C[2],$=C[3],N=C[4]}N.length>r&&(i?parseInt(N[r])<5?N=N.substring(0,r):(N=(parseInt(N.substring(0,r))+1).toString(),N.length>r&&($.length>0?$=$.substring(0,$.length-1):(M=(Number(M)+1).toString(),N=N.substring(1)))):N=N.substring(0,r)),n&&""!==$&&""===L&&($="0"+$.length.toString().replace(/\d/g,function(e){return["₀","₁","₂","₃","₄","₅","₆","₇","₈","₉"][parseInt(e,10)]}));let E=`${$}${N}`;if(E.length>t&&!d.includes("e")&&(E=E.substring(0,t)),d.includes("e")||d.includes("E"));else if(d.includes(".")){const e=d.split(".");if(2===e.length){const t=e[1];if(t.length>E.length&&t.endsWith("0")){let e=0;for(let r=t.length-1;r>=0&&"0"===t[r];r--)e++;e>0&&(E=E.padEnd(E.length+e,"0"))}}}"usd"===s?(w="en"===a?"$":"",L||(L="fa"===a?" دلار":"")):"irr"===s?L||(L="fa"===a?" ر":" R"):"irt"===s?L||(L="fa"===a?" ت":" T"):"percent"===s&&(L+="en"===a?"%":L?" درصد":"٪"),w=f+w,L+=p,"html"===l?(w&&(w=`<${u}>${w}</${u}>`),L&&(L=`<${g}>${L}</${g}>`)):"markdown"===l&&(w&&(w=`${u}${w}${u}`),L&&(L=`${g}${L}${g}`));const Q=/\B(?=(\d{3})+(?!\d))/g,F=o?".".padEnd(o+1,"0"):"";let T,j="";T=t<=0||r<=0||""===N&&""===$?`${M.replace(Q,",")}${F}`:`${M.replace(Q,",")}.${E}`,j=`${S}${w}${T}${L}`;const k={value:j,prefix:w,postfix:L,sign:S,wholeNumber:T};return k.value=(null!==(m=null==k?void 0:k.value)&&void 0!==m?m:"").replace(/,/g,c).replace(/\./g,h),"fa"===a&&(k.value=(null!==(b=null==k?void 0:k.value)&&void 0!==b?b:"").replace(/[0-9]/g,e=>String.fromCharCode(e.charCodeAt(0)+1728)).replace(/(K|M|B|T|Qt|Qd)/g,function(e){return String(x[e])}),k.fullPostfix=L.replace(/[0-9]/g,e=>String.fromCharCode(e.charCodeAt(0)+1728)).replace(/(K|M|B|T|Qt|Qd)/g,function(e){return String(v[e])}),k.postfix=k.postfix.replace(/[0-9]/g,e=>String.fromCharCode(e.charCodeAt(0)+1728)).replace(/(K|M|B|T|Qt|Qd)/g,function(e){return String(x[e])}),k.wholeNumber=k.wholeNumber.replace(/[0-9]/g,e=>String.fromCharCode(e.charCodeAt(0)+1728)).replace(/(K|M|B|T|Qt|Qd)/g,function(e){return String(x[e])})),k}_sanitizeLiveInput(e){var t;let r=e;r=r.replace(/[٠-٩۰-۹]/g,function(e){return String(15&e.charCodeAt(0))});let i=r,n=null;if("fa"===(null!==(t=this.options.language)&&void 0!==t?t:"en")){const e=this.defaultLanguageConfig.fa.decimalSeparator||"٫";r.includes(e)&&(n=e,i=r.replace(new RegExp(e,"g"),"."))}if(this.isENotation(i)){const e=this.convertENotationToRegularNumber(Number(i),i);r=n&&e.includes(".")?e.replace(/\./g,n):e}return r}_convertToFarsiDigits(e){if("fa"!==this.options.language||null==e)return e;let t="";for(let r=0;r<e.length;r++){const i=e[r];t+=i>="0"&&i<="9"?String.fromCharCode(i.charCodeAt(0)+1728):i}return t}}},986:function(e,t,r){var i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.NumberFormatter=void 0;const n=i(r(900));t.NumberFormatter=n.default}},t={};return function r(i){var n=t[i];if(void 0!==n)return n.exports;var o=t[i]={exports:{}};return e[i].call(o.exports,o,o.exports,r),o.exports}(986)})());
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type Template = 'number' | 'usd' | 'irt' | 'irr' | 'percent';
|
|
1
|
+
type Template = 'number' | 'usd' | 'irt' | 'irr' | 'percent' | 'liveformat';
|
|
2
2
|
type Precision = 'auto' | 'high' | 'medium' | 'low';
|
|
3
3
|
type Language = 'en' | 'fa';
|
|
4
4
|
type OutputFormat = 'plain' | 'html' | 'markdown';
|
|
@@ -37,8 +37,10 @@ declare class NumberFormatter {
|
|
|
37
37
|
toHtmlString(input: string | number): string;
|
|
38
38
|
toMdString(input: string | number): string;
|
|
39
39
|
private isENotation;
|
|
40
|
-
private format;
|
|
41
40
|
private convertENotationToRegularNumber;
|
|
41
|
+
private format;
|
|
42
42
|
private reducePrecision;
|
|
43
|
+
private _sanitizeLiveInput;
|
|
44
|
+
private _convertToFarsiDigits;
|
|
43
45
|
}
|
|
44
46
|
export default NumberFormatter;
|
|
@@ -10,7 +10,7 @@ class NumberFormatter {
|
|
|
10
10
|
};
|
|
11
11
|
this.defaultLanguageConfig = {
|
|
12
12
|
en: Object.assign(Object.assign({}, this.languageBaseConfig), { thousandSeparator: ',', decimalSeparator: '.' }),
|
|
13
|
-
fa: Object.assign(Object.assign({}, this.languageBaseConfig), { thousandSeparator: '
|
|
13
|
+
fa: Object.assign(Object.assign({}, this.languageBaseConfig), { thousandSeparator: '٬', decimalSeparator: '٫' }),
|
|
14
14
|
};
|
|
15
15
|
this.options = Object.assign({ language: 'en', template: 'number', precision: 'high', outputFormat: 'plain' }, this.defaultLanguageConfig['en']);
|
|
16
16
|
this.options = Object.assign(Object.assign({}, this.options), options);
|
|
@@ -66,16 +66,240 @@ class NumberFormatter {
|
|
|
66
66
|
isENotation(input) {
|
|
67
67
|
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)$/.test(input);
|
|
68
68
|
}
|
|
69
|
+
// Modify to accept originalEString to handle cases like "0.0e0" -> "0.0"
|
|
70
|
+
convertENotationToRegularNumber(num, originalEString) {
|
|
71
|
+
let numStr = String(num);
|
|
72
|
+
// If an originalEString is provided and represents 0 but has a specific format like "0.0", prefer that.
|
|
73
|
+
if (num === 0 && originalEString) {
|
|
74
|
+
const ePartsOriginal = originalEString.toLowerCase().split('e');
|
|
75
|
+
if (ePartsOriginal.length === 2) {
|
|
76
|
+
// Check if coefficient was like "0.0", "0.00" etc.
|
|
77
|
+
if (ePartsOriginal[0].match(/^0\.0*$/)) {
|
|
78
|
+
return ePartsOriginal[0]; // Return "0.0" or "0.00" etc.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// If not E-notation according to JS default toString for the number, or if it's simple "0", return it.
|
|
83
|
+
if (numStr.toLowerCase().indexOf('e') === -1) {
|
|
84
|
+
return numStr;
|
|
85
|
+
}
|
|
86
|
+
// If it IS E-notation, attempt to convert to plain decimal string.
|
|
87
|
+
// Handle very small numbers (negative exponent) using toFixed.
|
|
88
|
+
// Check num !== 0 because String(0) is "0", which doesn't contain 'e'.
|
|
89
|
+
if (Math.abs(num) < 1.0 && num !== 0) {
|
|
90
|
+
const eParts = numStr.toLowerCase().split('e'); // Use numStr here, not originalEString unless passed carefully
|
|
91
|
+
// Ensure it's a valid E-notation string with a negative exponent
|
|
92
|
+
if (eParts.length === 2) {
|
|
93
|
+
const exponent = parseInt(eParts[1], 10);
|
|
94
|
+
if (exponent < 0) {
|
|
95
|
+
let precision = Math.abs(exponent);
|
|
96
|
+
// Use coefficient from numStr for precision calculation
|
|
97
|
+
if (eParts[0].includes('.')) {
|
|
98
|
+
precision += eParts[0].split('.')[1].length;
|
|
99
|
+
}
|
|
100
|
+
// Cap precision to prevent overly long strings or errors with toFixed.
|
|
101
|
+
return num.toFixed(Math.min(precision, 100));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Handle large numbers or numbers with positive E-notation if not caught above.
|
|
106
|
+
// This part manually reconstructs the string from numStr.
|
|
107
|
+
const parts = numStr.toLowerCase().split('e');
|
|
108
|
+
if (parts.length === 2) {
|
|
109
|
+
const coefficientStr = parts[0];
|
|
110
|
+
const exponent = parseInt(parts[1], 10);
|
|
111
|
+
let [integer, fraction] = coefficientStr.split('.');
|
|
112
|
+
fraction = fraction || '';
|
|
113
|
+
if (exponent > 0) { // Positive exponent
|
|
114
|
+
const sign = integer.startsWith('-') ? "-" : "";
|
|
115
|
+
if (sign)
|
|
116
|
+
integer = integer.substring(1);
|
|
117
|
+
if (fraction.length <= exponent) {
|
|
118
|
+
return sign + integer + fraction.padEnd(exponent, '0');
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return sign + integer + fraction.substring(0, exponent) + '.' + fraction.substring(exponent);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else if (exponent < 0) { // Should have been caught by toFixed if num was < 1.0
|
|
125
|
+
let precision = Math.abs(exponent);
|
|
126
|
+
if (coefficientStr.includes('.')) {
|
|
127
|
+
precision += coefficientStr.split('.')[1].length;
|
|
128
|
+
}
|
|
129
|
+
return num.toFixed(Math.min(precision, 100));
|
|
130
|
+
}
|
|
131
|
+
else { // exponent === 0
|
|
132
|
+
return coefficientStr;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return numStr;
|
|
136
|
+
}
|
|
69
137
|
format(input) {
|
|
138
|
+
var _a;
|
|
70
139
|
let { precision, template } = this.options;
|
|
71
140
|
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, thousandSeparator, decimalSeparator, } = this.options;
|
|
72
141
|
if (input === undefined || input === null || input === '') {
|
|
73
142
|
return {};
|
|
74
143
|
}
|
|
75
|
-
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g)))
|
|
76
|
-
template = 'number';
|
|
77
144
|
// Store original input string to preserve format for trailing zeros
|
|
78
145
|
const originalInput = input.toString();
|
|
146
|
+
if (template === 'liveformat') {
|
|
147
|
+
let currentInput = this._sanitizeLiveInput(originalInput);
|
|
148
|
+
// Define locale-specific separators early
|
|
149
|
+
const currentThousandSeparator = thousandSeparator || ',';
|
|
150
|
+
const currentDecimalSeparator = decimalSeparator || '.';
|
|
151
|
+
// Special override for inputs like "0.0e0" or "۰٫۰e0" which _sanitizeLiveInput might turn into "0".
|
|
152
|
+
// This override aims to restore the "0.0" or "0٫0" representation if originalInput implies it.
|
|
153
|
+
// First, create a version of originalInput with Western digits and '.' as decimal for reliable parsing.
|
|
154
|
+
let westernizedOriginalInput = originalInput.replace(/[٠-٩۰-۹]/g, function (match) {
|
|
155
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
156
|
+
});
|
|
157
|
+
if (((_a = this.options.language) !== null && _a !== void 0 ? _a : 'en') === 'fa') {
|
|
158
|
+
const farsiDecimal = this.defaultLanguageConfig.fa.decimalSeparator || '٫';
|
|
159
|
+
westernizedOriginalInput = westernizedOriginalInput.replace(new RegExp(farsiDecimal, 'g'), '.');
|
|
160
|
+
}
|
|
161
|
+
if (this.isENotation(westernizedOriginalInput)) {
|
|
162
|
+
const numValOriginal = Number(westernizedOriginalInput);
|
|
163
|
+
if (numValOriginal === 0) {
|
|
164
|
+
const eIndex = originalInput.toLowerCase().indexOf('e');
|
|
165
|
+
if (eIndex > -1) {
|
|
166
|
+
const partBeforeEOriginal = originalInput.substring(0, eIndex);
|
|
167
|
+
const partBeforeEWesternDigits = partBeforeEOriginal.replace(/[٠-٩۰-۹]/g, function (match) {
|
|
168
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
169
|
+
});
|
|
170
|
+
// Check if this part (e.g., "0.0" or "0٫0") matches the "zero with explicit decimals" pattern
|
|
171
|
+
// Normalize its decimal separator to currentDecimalSeparator for consistency before assigning to currentInput
|
|
172
|
+
let partToTest = partBeforeEWesternDigits;
|
|
173
|
+
if (partBeforeEWesternDigits.includes('.') && currentDecimalSeparator !== '.') {
|
|
174
|
+
partToTest = partBeforeEWesternDigits.replace('.', currentDecimalSeparator);
|
|
175
|
+
}
|
|
176
|
+
else if (partBeforeEWesternDigits.includes('٫') && currentDecimalSeparator !== '٫') {
|
|
177
|
+
// This case should ideally not happen if Farsi decimal is '٫' and currentDecimalSeparator is also '٫'
|
|
178
|
+
partToTest = partBeforeEWesternDigits.replace('٫', currentDecimalSeparator);
|
|
179
|
+
}
|
|
180
|
+
const zeroWithDecimalsPattern = new RegExp(`^0\\${currentDecimalSeparator}0*$`);
|
|
181
|
+
if (partToTest.match(zeroWithDecimalsPattern)) {
|
|
182
|
+
currentInput = partToTest; // currentInput is now "0[currentSeparator]0..." e.g. "0.0" or "0٫0"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
let sign = '';
|
|
188
|
+
if (currentInput.startsWith('-')) {
|
|
189
|
+
sign = '-';
|
|
190
|
+
currentInput = currentInput.substring(1); // currentInput is now the absolute numeric string
|
|
191
|
+
}
|
|
192
|
+
// const currentThousandSeparator = thousandSeparator || ','; // Moved up
|
|
193
|
+
// const currentDecimalSeparator = decimalSeparator || '.'; // Moved up
|
|
194
|
+
if (currentInput === '') {
|
|
195
|
+
return {
|
|
196
|
+
value: '',
|
|
197
|
+
prefix: '',
|
|
198
|
+
postfix: '',
|
|
199
|
+
sign: '', // Sign is empty for empty input
|
|
200
|
+
wholeNumber: ''
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Handles "0" (from input "0" or "-0")
|
|
204
|
+
if (currentInput === '0') {
|
|
205
|
+
let outputZero = '0';
|
|
206
|
+
if (this.options.language === 'fa') {
|
|
207
|
+
outputZero = String.fromCharCode('0'.charCodeAt(0) + 1728); // Converts '0' to '۰'
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
value: outputZero,
|
|
211
|
+
prefix: '',
|
|
212
|
+
postfix: '',
|
|
213
|
+
sign: '', // Sign is empty for "0"
|
|
214
|
+
wholeNumber: outputZero,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Handle cases like "." or "0." or ".0"
|
|
218
|
+
// If input is just the decimal separator, treat as "0" + separator
|
|
219
|
+
if (currentInput === currentDecimalSeparator) {
|
|
220
|
+
currentInput = '0' + currentDecimalSeparator;
|
|
221
|
+
}
|
|
222
|
+
let integerPart = '';
|
|
223
|
+
let decimalPart = '';
|
|
224
|
+
let hasDecimalPoint = false;
|
|
225
|
+
// Try splitting with current locale's decimal separator first
|
|
226
|
+
if (currentInput.includes(currentDecimalSeparator)) {
|
|
227
|
+
hasDecimalPoint = true;
|
|
228
|
+
const parts = currentInput.split(currentDecimalSeparator);
|
|
229
|
+
integerPart = parts[0];
|
|
230
|
+
decimalPart = parts.length > 1 ? parts[1] : '';
|
|
231
|
+
}
|
|
232
|
+
// If not found, and current locale is not using '.', check for '.' as a fallback
|
|
233
|
+
else if (currentDecimalSeparator !== '.' && currentInput.includes('.')) {
|
|
234
|
+
hasDecimalPoint = true;
|
|
235
|
+
const parts = currentInput.split('.');
|
|
236
|
+
integerPart = parts[0];
|
|
237
|
+
decimalPart = parts.length > 1 ? parts[1] : '';
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// No decimal point found (neither locale specific nor '.')
|
|
241
|
+
integerPart = currentInput;
|
|
242
|
+
}
|
|
243
|
+
// Now integerPart is the true integer part (still needs leading zero trim).
|
|
244
|
+
if (integerPart === '') {
|
|
245
|
+
integerPart = '0';
|
|
246
|
+
}
|
|
247
|
+
else if (integerPart !== '0') {
|
|
248
|
+
const tempInt = integerPart.replace(/^0+/, '');
|
|
249
|
+
integerPart = (tempInt === '') ? '0' : tempInt;
|
|
250
|
+
}
|
|
251
|
+
// No change if integerPart is already "0"
|
|
252
|
+
const formattedIntegerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, currentThousandSeparator);
|
|
253
|
+
let finalValue = formattedIntegerPart;
|
|
254
|
+
if (hasDecimalPoint) {
|
|
255
|
+
finalValue += currentDecimalSeparator + decimalPart;
|
|
256
|
+
}
|
|
257
|
+
const finalNumericValue = finalValue; // finalValue at this point is the formatted absolute number
|
|
258
|
+
let resultSign = '';
|
|
259
|
+
let resultValue = finalNumericValue;
|
|
260
|
+
if (sign === '-') {
|
|
261
|
+
// Only add sign if the number isn't representing plain zero.
|
|
262
|
+
// parseFloat "0.00" is 0. "0" is 0.
|
|
263
|
+
// We want "-0.123", but "0" for "-0".
|
|
264
|
+
// We want "-0.00" for input "-0.00" (if that's a required display for zero value with decimals)
|
|
265
|
+
// The tests for "-0.000000123" expect "-0.000000123".
|
|
266
|
+
// The tests for 0.000000123 expect "0.000000123".
|
|
267
|
+
// Test for -0 will clarify if it should be "0" or "-0". Assume "0".
|
|
268
|
+
if (parseFloat(finalNumericValue) === 0 && !finalNumericValue.includes('.')) { // handles "0"
|
|
269
|
+
resultSign = ''; // Make "-0" become "0"
|
|
270
|
+
// resultValue is already "0"
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
resultSign = '-';
|
|
274
|
+
resultValue = sign + finalNumericValue;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// At this point, finalValue is the formatted absolute number string (Western digits, Farsi/default separators).
|
|
278
|
+
// sign is the extracted input sign ('-' or '').
|
|
279
|
+
// Convert finalValue to Farsi digits if necessary for the absolute part.
|
|
280
|
+
const outputFormattedAbsoluteValue = this._convertToFarsiDigits(finalValue);
|
|
281
|
+
let outputSign = '';
|
|
282
|
+
// Determine the final sign string.
|
|
283
|
+
// `finalValue` is absolute, western digits, locale separator e.g. "0", "0٫0", "0٫12", "123٫45"
|
|
284
|
+
// `sign` is the original sign from input, like "-"
|
|
285
|
+
if (sign === '-') {
|
|
286
|
+
if (finalValue === '0') { // Check if the absolute formatted value is literally "0"
|
|
287
|
+
outputSign = ''; // Only for "-0" input that results in "0" absolute
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
outputSign = '-'; // For all other cases like "-0.0", "-0.12", "-123"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
value: outputSign + outputFormattedAbsoluteValue, // Prepend sign to Farsi/Western formatted absolute value
|
|
295
|
+
prefix: '',
|
|
296
|
+
postfix: '',
|
|
297
|
+
sign: outputSign, // Store the determined sign
|
|
298
|
+
wholeNumber: outputFormattedAbsoluteValue, // Store Farsi/Western formatted absolute value (unsigned)
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent|liveformat)$/g)))
|
|
302
|
+
template = 'number';
|
|
79
303
|
if (this.isENotation(originalInput)) {
|
|
80
304
|
input = this.convertENotationToRegularNumber(Number(input));
|
|
81
305
|
}
|
|
@@ -270,27 +494,6 @@ class NumberFormatter {
|
|
|
270
494
|
}
|
|
271
495
|
return this.reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, thousandSeparator, decimalSeparator, originalInput);
|
|
272
496
|
}
|
|
273
|
-
convertENotationToRegularNumber(eNotation) {
|
|
274
|
-
// For simple cases like 1e3, directly use Number constructor
|
|
275
|
-
if (Number.isInteger(eNotation) && eNotation >= 1000) {
|
|
276
|
-
return eNotation.toString();
|
|
277
|
-
}
|
|
278
|
-
const parts = eNotation.toString().toLowerCase().split('e');
|
|
279
|
-
if (parts.length !== 2)
|
|
280
|
-
return eNotation.toString();
|
|
281
|
-
const coefficient = parseFloat(parts[0]);
|
|
282
|
-
const exponent = parseInt(parts[1], 10);
|
|
283
|
-
// Handle negative exponents (very small numbers)
|
|
284
|
-
if (exponent < 0) {
|
|
285
|
-
const absExponent = Math.abs(exponent);
|
|
286
|
-
// Determine precision needed to show all digits
|
|
287
|
-
const precision = absExponent +
|
|
288
|
-
(parts[0].includes('.') ? parts[0].split('.')[1].length : 0);
|
|
289
|
-
return eNotation.toFixed(precision);
|
|
290
|
-
}
|
|
291
|
-
// For positive exponents, let JavaScript do the conversion
|
|
292
|
-
return eNotation.toString();
|
|
293
|
-
}
|
|
294
497
|
reducePrecision(numberString, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '', thousandSeparator = ',', decimalSeparator = '.', originalInput = '') {
|
|
295
498
|
var _a, _b;
|
|
296
499
|
if (numberString === undefined || numberString === null || numberString.trim() === '') {
|
|
@@ -552,5 +755,53 @@ class NumberFormatter {
|
|
|
552
755
|
}
|
|
553
756
|
return formattedObject;
|
|
554
757
|
}
|
|
758
|
+
_sanitizeLiveInput(input) {
|
|
759
|
+
var _a;
|
|
760
|
+
let sanitizedInput = input;
|
|
761
|
+
// Convert Farsi/Arabic numerals to Western numerals
|
|
762
|
+
sanitizedInput = sanitizedInput.replace(/[٠-٩۰-۹]/g, function (match) {
|
|
763
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
764
|
+
});
|
|
765
|
+
// Handle potential E-notation
|
|
766
|
+
let stringForENotationProcessing = sanitizedInput;
|
|
767
|
+
let originalFarsiSeparator = null;
|
|
768
|
+
if (((_a = this.options.language) !== null && _a !== void 0 ? _a : 'en') === 'fa') {
|
|
769
|
+
const farsiDecimal = this.defaultLanguageConfig.fa.decimalSeparator || '٫'; // Default to '٫'
|
|
770
|
+
if (sanitizedInput.includes(farsiDecimal)) {
|
|
771
|
+
originalFarsiSeparator = farsiDecimal;
|
|
772
|
+
stringForENotationProcessing = sanitizedInput.replace(new RegExp(farsiDecimal, 'g'), '.');
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (this.isENotation(stringForENotationProcessing)) {
|
|
776
|
+
// Pass stringForENotationProcessing as the originalEString argument
|
|
777
|
+
const convertedValue = this.convertENotationToRegularNumber(Number(stringForENotationProcessing), stringForENotationProcessing);
|
|
778
|
+
// If we replaced a Farsi separator and the result has a '.', convert it back.
|
|
779
|
+
// Otherwise, use the converted value directly.
|
|
780
|
+
if (originalFarsiSeparator && convertedValue.includes('.')) {
|
|
781
|
+
sanitizedInput = convertedValue.replace(/\./g, originalFarsiSeparator);
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
sanitizedInput = convertedValue;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
// If not E-notation, sanitizedInput (with original separators after Farsi digit conversion) is returned.
|
|
788
|
+
return sanitizedInput;
|
|
789
|
+
}
|
|
790
|
+
_convertToFarsiDigits(value) {
|
|
791
|
+
if (this.options.language !== 'fa' || value === null || value === undefined) {
|
|
792
|
+
return value;
|
|
793
|
+
}
|
|
794
|
+
let farsiConvertedValue = "";
|
|
795
|
+
for (let i = 0; i < value.length; i++) {
|
|
796
|
+
const char = value[i];
|
|
797
|
+
if (char >= '0' && char <= '9') {
|
|
798
|
+
farsiConvertedValue += String.fromCharCode(char.charCodeAt(0) + 1728);
|
|
799
|
+
}
|
|
800
|
+
else {
|
|
801
|
+
farsiConvertedValue += char;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return farsiConvertedValue;
|
|
805
|
+
}
|
|
555
806
|
}
|
|
556
807
|
exports.default = NumberFormatter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
const format_1 = __importDefault(require("../../src/format")); // Adjust path if necessary based on actual structure
|
|
7
|
+
describe('NumberFormatter - Liveformat Template', () => {
|
|
8
|
+
const options = { template: 'liveformat' }; // Cast to any to allow new template type if TS is strict before build
|
|
9
|
+
const testCases = [
|
|
10
|
+
{ input: '0', expected: '0' },
|
|
11
|
+
{ input: '02', expected: '2' },
|
|
12
|
+
{ input: '29', expected: '29' },
|
|
13
|
+
{ input: '292', expected: '292' },
|
|
14
|
+
{ input: '2923', expected: '2,923' },
|
|
15
|
+
{ input: '29231', expected: '29,231' },
|
|
16
|
+
{ input: '292312', expected: '292,312' },
|
|
17
|
+
{ input: '2923123', expected: '2,923,123' },
|
|
18
|
+
{ input: '2923123.', expected: '2,923,123.' },
|
|
19
|
+
{ input: '2923123.0', expected: '2,923,123.0' },
|
|
20
|
+
{ input: '2923123.00', expected: '2,923,123.00' },
|
|
21
|
+
{ input: '2923123.003', expected: '2,923,123.003' },
|
|
22
|
+
{ input: '2923123.0030', expected: '2,923,123.0030' },
|
|
23
|
+
{ input: '2923123.00301', expected: '2,923,123.00301' },
|
|
24
|
+
{ input: '2923123.003012', expected: '2,923,123.003012' },
|
|
25
|
+
// Edge cases
|
|
26
|
+
{ input: '', expected: '' }, // Empty input
|
|
27
|
+
{ input: '.', expected: '0.' }, // Just decimal separator
|
|
28
|
+
{ input: '0.0', expected: '0.0' },
|
|
29
|
+
{ input: '0.12', expected: '0.12' },
|
|
30
|
+
{ input: '.5', expected: '0.5' }, // Leading decimal separator
|
|
31
|
+
{ input: '007', expected: '7' }, // Multiple leading zeros, integer
|
|
32
|
+
{ input: '00.25', expected: '0.25' }, // Multiple leading zeros, decimal
|
|
33
|
+
{ input: '12345.6700', expected: '12,345.6700' }, // Trailing zeros in decimal
|
|
34
|
+
{ input: '000', expected: '0' }, // Multiple zeros
|
|
35
|
+
{ input: '000.000', expected: '0.000' }, // Multiple zeros with decimal
|
|
36
|
+
// Test cases for E-notation handling by incremental template
|
|
37
|
+
{ input: '1.23e-7', expected: '0.000000123' },
|
|
38
|
+
{ input: '1.23E-7', expected: '0.000000123' }, // Uppercase E
|
|
39
|
+
{ input: 0.000000123, expected: '0.000000123' }, // Number input that becomes E-notation
|
|
40
|
+
{ input: '12345e-2', expected: '123.45' }, // Positive coefficient, negative exponent
|
|
41
|
+
{ input: '0.00012345e+2', expected: '0.012345' }, // Decimal coefficient, positive exponent
|
|
42
|
+
{ input: '1.23e+8', expected: '123,000,000' },
|
|
43
|
+
{ input: '1.23E+8', expected: '123,000,000' },
|
|
44
|
+
{ input: 123000000, expected: '123,000,000' }, // Number input (large)
|
|
45
|
+
{ input: '1234567.89e+3', expected: '1,234,567,890' }, // Large number with decimal, positive exponent
|
|
46
|
+
{ input: '123456789012345', expected: '123,456,789,012,345' }, // Large integer string (no E)
|
|
47
|
+
{ input: 123456789012345, expected: '123,456,789,012,345' }, // Large integer number
|
|
48
|
+
{ input: '1e-3', expected: '0.001' },
|
|
49
|
+
{ input: 0.001, expected: '0.001' },
|
|
50
|
+
{ input: '1e+3', expected: '1,000' },
|
|
51
|
+
{ input: 1000, expected: '1,000' },
|
|
52
|
+
{ input: '0e0', expected: '0' }, // Zero in E-notation
|
|
53
|
+
{ input: 0e0, expected: '0' },
|
|
54
|
+
{ input: '0.0e0', expected: '0.0' },
|
|
55
|
+
// Cases that might stress the convertENotationToRegularNumber
|
|
56
|
+
{ input: '123456789123456789123', expected: '123,456,789,123,456,789,123' }, // Very large integer string
|
|
57
|
+
{ input: 123456789123456789123, expected: '123,456,789,123,456,800,000' }, // Very large integer number (JS might show as E if too large for its default toString)
|
|
58
|
+
{ input: '1.0e-20', expected: '0.00000000000000000001' }, // Small number, many zeros
|
|
59
|
+
{ input: 1.0e-20, expected: '0.00000000000000000001' },
|
|
60
|
+
{ input: '1.0e+20', expected: '100,000,000,000,000,000,000' }, // Large number, many zeros
|
|
61
|
+
{ input: 1.0e+20, expected: '100,000,000,000,000,000,000' },
|
|
62
|
+
// Check inputs that convertENotationToRegularNumber might have previously struggled with
|
|
63
|
+
{ input: '1e21', expected: '1,000,000,000,000,000,000,000' }, // Number that is 10^21
|
|
64
|
+
{ input: 1e21, expected: '1,000,000,000,000,000,000,000' },
|
|
65
|
+
// Test with negative numbers in E-notation
|
|
66
|
+
{ input: '-1.23e-7', expected: '-0.000000123' },
|
|
67
|
+
{ input: -0.000000123, expected: '-0.000000123' },
|
|
68
|
+
{ input: '-1.23e+8', expected: '-123,000,000' },
|
|
69
|
+
{ input: -123000000, expected: '-123,000,000' },
|
|
70
|
+
];
|
|
71
|
+
testCases.forEach(({ input, expected }) => {
|
|
72
|
+
it(`should format '${input}' to '${expected}'`, () => {
|
|
73
|
+
const formatter = new format_1.default(options);
|
|
74
|
+
expect(formatter.toPlainString(input)).toBe(expected);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// Test with different separators if possible, though the problem implies fixed separators for this template
|
|
78
|
+
// For now, assuming default separators (',' and '.') as per examples
|
|
79
|
+
describe('NumberFormatter - Liveformat Template with Fa Language (different separators)', () => {
|
|
80
|
+
const faOptions = {
|
|
81
|
+
template: 'liveformat',
|
|
82
|
+
language: 'fa' // 'fa' uses '٫' and '٬'
|
|
83
|
+
};
|
|
84
|
+
const formatter = new format_1.default(); // Create once
|
|
85
|
+
formatter.setLanguage('fa'); // Set language
|
|
86
|
+
formatter.setTemplate('liveformat', 'auto'); // Set template
|
|
87
|
+
// Confirmed Farsi Separators: Thousands: ٬ (U+066C), Decimal: ٫ (U+066B)
|
|
88
|
+
// Output Digits: Persian Numerals ۰۱۲... (U+06F0 range) as per TS implementation
|
|
89
|
+
it('should format Farsi input "۱۲۳۴" to "۱٬۲۳۴"', () => {
|
|
90
|
+
expect(formatter.toPlainString('۱۲۳۴')).toBe('۱٬۲۳۴');
|
|
91
|
+
});
|
|
92
|
+
it('should format Farsi input "۱۲۳۴۵٫۶۷" (Farsi decimal) to "۱۲٬۳۴۵٫۶۷"', () => {
|
|
93
|
+
expect(formatter.toPlainString('۱۲۳۴۵٫۶۷')).toBe('۱۲٬۳۴۵٫۶۷');
|
|
94
|
+
});
|
|
95
|
+
it('should format Farsi input "-۷۸۹٫۰۱" (Farsi decimal) to "-۷۸۹٫۰۱"', () => {
|
|
96
|
+
expect(formatter.toPlainString('-۷۸۹٫۰۱')).toBe('-۷۸۹٫۰۱');
|
|
97
|
+
});
|
|
98
|
+
it('should format Farsi input "۰" to "۰"', () => {
|
|
99
|
+
expect(formatter.toPlainString('۰')).toBe('۰');
|
|
100
|
+
});
|
|
101
|
+
it('should format Farsi input "-۰" to "۰"', () => {
|
|
102
|
+
expect(formatter.toPlainString('-۰')).toBe('۰');
|
|
103
|
+
});
|
|
104
|
+
it('should format Farsi input "۰٫۱۲" (Farsi decimal) to "۰٫۱۲"', () => {
|
|
105
|
+
expect(formatter.toPlainString('۰٫۱۲')).toBe('۰٫۱۲');
|
|
106
|
+
});
|
|
107
|
+
it('should format Farsi input "-۰٫۱۲" (Farsi decimal) to "-۰٫۱۲"', () => {
|
|
108
|
+
expect(formatter.toPlainString('-۰٫۱۲')).toBe('-۰٫۱۲');
|
|
109
|
+
});
|
|
110
|
+
it('should format Farsi input "۱۲۳۴۵۶۷۸۹٫۱۲۳" (Farsi decimal) to "۱۲۳٬۴۵۶٬۷۸۹٫۱۲۳"', () => {
|
|
111
|
+
expect(formatter.toPlainString('۱۲۳۴۵۶۷۸۹٫۱۲۳')).toBe('۱۲۳٬۴۵۶٬۷۸۹٫۱۲۳');
|
|
112
|
+
});
|
|
113
|
+
it('should format mixed Farsi/Western digit input "1۲۳۴٫۵۶" (Farsi decimal) to "۱٬۲۳۴٫۵۶"', () => {
|
|
114
|
+
expect(formatter.toPlainString('1۲۳۴٫۵۶')).toBe('۱٬۲۳۴٫۵۶');
|
|
115
|
+
});
|
|
116
|
+
it('should format Farsi input with only Farsi decimal separator "٫" to "۰٫"', () => {
|
|
117
|
+
expect(formatter.toPlainString('٫')).toBe('۰٫');
|
|
118
|
+
});
|
|
119
|
+
// User's critical case 1 (Farsi input, Farsi decimal '٫')
|
|
120
|
+
it('should format Farsi input "۹۳۱۲۸۳٫۰۰۰۹۱۲۳" to "۹۳۱٬۲۸۳٫۰۰۰۹۱۲۳"', () => {
|
|
121
|
+
expect(formatter.toPlainString('۹۳۱۲۸۳٫۰۰۰۹۱۲۳')).toBe('۹۳۱٬۲۸۳٫۰۰۰۹۱۲۳');
|
|
122
|
+
});
|
|
123
|
+
// User's critical case 2 (Western input "39312312.123123", lang 'fa')
|
|
124
|
+
// TS liveformat needs input to use '٫' if lang=fa for correct parsing.
|
|
125
|
+
it('should format Western digit input "39312312٫123123" (Farsi decimal) to "۳۹٬۳۱۲٬۳۱۲٫۱۲۳۱۲۳" when lang=fa', () => {
|
|
126
|
+
expect(formatter.toPlainString('39312312٫123123')).toBe('۳۹٬۳۱۲٬۳۱۲٫۱۲۳۱۲۳');
|
|
127
|
+
});
|
|
128
|
+
it('should format Farsi input "۱۲۳۴۵۶۷" to "۱٬۲۳۴٬۵۶۷"', () => {
|
|
129
|
+
expect(formatter.toPlainString('۱۲۳۴۵۶۷')).toBe('۱٬۲۳۴٬۵۶۷');
|
|
130
|
+
});
|
|
131
|
+
it('should format Farsi input "۱۲۳٫۴۵" (Farsi decimal) to "۱۲۳٫۴۵"', () => {
|
|
132
|
+
expect(formatter.toPlainString('۱۲۳٫۴۵')).toBe('۱۲۳٫۴۵');
|
|
133
|
+
});
|
|
134
|
+
// Test "0.0" like inputs
|
|
135
|
+
it('should format Farsi "۰٫۰" to "۰٫۰"', () => {
|
|
136
|
+
expect(formatter.toPlainString('۰٫۰')).toBe('۰٫۰');
|
|
137
|
+
});
|
|
138
|
+
it('should format Farsi "-۰٫۰" to "-۰٫۰"', () => {
|
|
139
|
+
expect(formatter.toPlainString('-۰٫۰')).toBe('-۰٫۰');
|
|
140
|
+
});
|
|
141
|
+
// Expectations for 0.0e0 related inputs, assuming they should result in "۰٫۰" after fixes
|
|
142
|
+
it('should format "0.0e0" to "۰٫۰" when lang=fa', () => {
|
|
143
|
+
expect(formatter.toPlainString('0.0e0')).toBe('۰٫۰');
|
|
144
|
+
});
|
|
145
|
+
it('should format "۰٫۰e0" (Farsi input) to "۰٫۰" when lang=fa', () => {
|
|
146
|
+
expect(formatter.toPlainString('۰٫۰e0')).toBe('۰٫۰');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
File without changes
|
|
File without changes
|