reduce-precision 1.0.7 → 1.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reduce-precision",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "./ts/lib/index.js",
6
6
  "files": [
@@ -60,4 +60,4 @@
60
60
  "main"
61
61
  ]
62
62
  }
63
- }
63
+ }
@@ -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)})()));
@@ -0,0 +1,46 @@
1
+ type Template = 'number' | 'usd' | 'irt' | 'irr' | 'percent' | 'liveformat';
2
+ type Precision = 'auto' | 'high' | 'medium' | 'low';
3
+ type Language = 'en' | 'fa';
4
+ type OutputFormat = 'plain' | 'html' | 'markdown';
5
+ interface FormattedObject {
6
+ value?: string;
7
+ prefix: string;
8
+ postfix: string;
9
+ fullPostfix?: string;
10
+ sign: string;
11
+ wholeNumber: string;
12
+ }
13
+ interface LanguageConfig {
14
+ prefixMarker?: string;
15
+ postfixMarker?: string;
16
+ prefix?: string;
17
+ postfix?: string;
18
+ thousandSeparator?: string;
19
+ decimalSeparator?: string;
20
+ }
21
+ interface Options extends LanguageConfig {
22
+ precision?: Precision;
23
+ template?: Template;
24
+ language?: Language;
25
+ outputFormat?: OutputFormat;
26
+ }
27
+ declare class NumberFormatter {
28
+ private readonly languageBaseConfig;
29
+ private defaultLanguageConfig;
30
+ private options;
31
+ constructor(options?: Options);
32
+ setLanguage(lang: Language, config?: LanguageConfig): NumberFormatter;
33
+ setTemplate(template: Template, precision: Precision): NumberFormatter;
34
+ toJson(input: string | number): FormattedObject;
35
+ toString(input: string | number): string;
36
+ toPlainString(input: string | number): string;
37
+ toHtmlString(input: string | number): string;
38
+ toMdString(input: string | number): string;
39
+ private isENotation;
40
+ private convertENotationToRegularNumber;
41
+ private format;
42
+ private reducePrecision;
43
+ private _sanitizeLiveInput;
44
+ private _convertToFarsiDigits;
45
+ }
46
+ export default NumberFormatter;
@@ -0,0 +1,807 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class NumberFormatter {
4
+ constructor(options = {}) {
5
+ this.languageBaseConfig = {
6
+ prefixMarker: 'i',
7
+ postfixMarker: 'i',
8
+ prefix: '',
9
+ postfix: '',
10
+ };
11
+ this.defaultLanguageConfig = {
12
+ en: Object.assign(Object.assign({}, this.languageBaseConfig), { thousandSeparator: ',', decimalSeparator: '.' }),
13
+ fa: Object.assign(Object.assign({}, this.languageBaseConfig), { thousandSeparator: '٬', decimalSeparator: '٫' }),
14
+ };
15
+ this.options = Object.assign({ language: 'en', template: 'number', precision: 'high', outputFormat: 'plain' }, this.defaultLanguageConfig['en']);
16
+ this.options = Object.assign(Object.assign({}, this.options), options);
17
+ }
18
+ setLanguage(lang, config = {}) {
19
+ this.options.language = lang;
20
+ this.options.prefixMarker =
21
+ config.prefixMarker || this.defaultLanguageConfig[lang].prefixMarker;
22
+ this.options.postfixMarker =
23
+ config.postfixMarker || this.defaultLanguageConfig[lang].postfixMarker;
24
+ this.options.prefix =
25
+ config.prefix || this.defaultLanguageConfig[lang].prefix;
26
+ this.options.postfix =
27
+ config.postfix || this.defaultLanguageConfig[lang].postfix;
28
+ this.options.thousandSeparator =
29
+ config.thousandSeparator ||
30
+ this.defaultLanguageConfig[lang].thousandSeparator;
31
+ this.options.decimalSeparator =
32
+ config.decimalSeparator ||
33
+ this.defaultLanguageConfig[lang].decimalSeparator;
34
+ return this;
35
+ }
36
+ setTemplate(template, precision) {
37
+ this.options.template = template;
38
+ this.options.precision = precision;
39
+ return this;
40
+ }
41
+ toJson(input) {
42
+ const formattedObject = this.format(input);
43
+ delete formattedObject.value;
44
+ return formattedObject;
45
+ }
46
+ toString(input) {
47
+ const formattedObject = this.format(input);
48
+ return formattedObject.value || '';
49
+ }
50
+ toPlainString(input) {
51
+ this.options.outputFormat = 'plain';
52
+ const formattedObject = this.format(input);
53
+ return formattedObject.value || '';
54
+ }
55
+ toHtmlString(input) {
56
+ this.options.outputFormat = 'html';
57
+ const formattedObject = this.format(input);
58
+ return formattedObject.value || '';
59
+ }
60
+ toMdString(input) {
61
+ this.options.outputFormat = 'markdown';
62
+ const formattedObject = this.format(input);
63
+ return formattedObject.value || '';
64
+ }
65
+ // Private methods...
66
+ isENotation(input) {
67
+ return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)$/.test(input);
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
+ }
137
+ format(input) {
138
+ var _a;
139
+ let { precision, template } = this.options;
140
+ const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, thousandSeparator, decimalSeparator, } = this.options;
141
+ if (input === undefined || input === null || input === '') {
142
+ return {};
143
+ }
144
+ // Store original input string to preserve format for trailing zeros
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: '',
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: '',
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,
295
+ prefix: '',
296
+ postfix: '',
297
+ sign: outputSign,
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';
303
+ if (this.isENotation(originalInput)) {
304
+ input = this.convertENotationToRegularNumber(Number(input));
305
+ }
306
+ // Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
307
+ let numberString = input
308
+ .toString()
309
+ .replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
310
+ return String(match.charCodeAt(0) & 0xf);
311
+ })
312
+ .replace(/[^\d.-]/g, '');
313
+ // Stripping leading zeros only, preserve trailing zeros
314
+ numberString = numberString
315
+ .replace(/^0+(?=\d)/g, '');
316
+ const number = Math.abs(Number(numberString));
317
+ let p, d, r, c;
318
+ let f = 0;
319
+ // Auto precision selection
320
+ if (precision === 'auto') {
321
+ if (template.match(/^(usd|irt|irr|number)$/g)) {
322
+ if (number >= 0.0001 && number < 100000000000) {
323
+ precision = 'high';
324
+ }
325
+ else {
326
+ precision = 'medium';
327
+ }
328
+ }
329
+ else if (template === 'percent') {
330
+ precision = 'low';
331
+ }
332
+ }
333
+ if (precision === 'medium') {
334
+ if (number >= 0 && number < 0.0001) {
335
+ p = 33;
336
+ d = 4;
337
+ r = false;
338
+ c = true;
339
+ }
340
+ else if (number >= 0.0001 && number < 0.001) {
341
+ p = 7;
342
+ d = 4;
343
+ r = false;
344
+ c = false;
345
+ }
346
+ else if (number >= 0.001 && number < 0.01) {
347
+ p = 5;
348
+ d = 3;
349
+ r = false;
350
+ c = false;
351
+ }
352
+ else if (number >= 0.001 && number < 0.1) {
353
+ p = 3;
354
+ d = 2;
355
+ r = false;
356
+ c = false;
357
+ }
358
+ else if (number >= 0.1 && number < 1) {
359
+ p = 1;
360
+ d = 1;
361
+ r = false;
362
+ c = false;
363
+ }
364
+ else if (number >= 1 && number < 10) {
365
+ p = 3;
366
+ d = 3;
367
+ r = false;
368
+ c = false;
369
+ }
370
+ else if (number >= 10 && number < 100) {
371
+ p = 2;
372
+ d = 2;
373
+ r = false;
374
+ c = false;
375
+ }
376
+ else if (number >= 100 && number < 1000) {
377
+ p = 1;
378
+ d = 1;
379
+ r = false;
380
+ c = false;
381
+ }
382
+ else if (number >= 1000) {
383
+ const x = Math.floor(Math.log10(number)) % 3;
384
+ p = 2 - x;
385
+ d = 2 - x;
386
+ r = true;
387
+ c = true;
388
+ }
389
+ else {
390
+ p = 0;
391
+ d = 0;
392
+ r = true;
393
+ c = true;
394
+ }
395
+ }
396
+ else if (precision === 'low') {
397
+ if (number >= 0 && number < 0.01) {
398
+ p = 2;
399
+ d = 0;
400
+ r = true;
401
+ c = false;
402
+ f = 2;
403
+ }
404
+ else if (number >= 0.01 && number < 0.1) {
405
+ p = 2;
406
+ d = 1;
407
+ r = true;
408
+ c = false;
409
+ }
410
+ else if (number >= 0.1 && number < 1) {
411
+ p = 2;
412
+ d = 2;
413
+ r = true;
414
+ c = false;
415
+ }
416
+ else if (number >= 1 && number < 10) {
417
+ p = 2;
418
+ d = 2;
419
+ r = true;
420
+ c = false;
421
+ f = 2;
422
+ }
423
+ else if (number >= 10 && number < 100) {
424
+ p = 1;
425
+ d = 1;
426
+ r = true;
427
+ c = false;
428
+ f = 1;
429
+ }
430
+ else if (number >= 100 && number < 1000) {
431
+ p = 0;
432
+ d = 0;
433
+ r = true;
434
+ c = false;
435
+ }
436
+ else if (number >= 1000) {
437
+ const x = Math.floor(Math.log10(number)) % 3;
438
+ p = 1 - x;
439
+ d = 1 - x;
440
+ r = true;
441
+ c = true;
442
+ }
443
+ else {
444
+ p = 0;
445
+ d = 0;
446
+ r = true;
447
+ c = true;
448
+ f = 2;
449
+ }
450
+ }
451
+ else {
452
+ // precision === "high"
453
+ if (number >= 0 && number < 1) {
454
+ p = 33;
455
+ d = 4;
456
+ r = false;
457
+ c = false;
458
+ }
459
+ else if (number >= 1 && number < 10) {
460
+ p = 3;
461
+ d = 3;
462
+ r = true;
463
+ c = false;
464
+ }
465
+ else if (number >= 10 && number < 100) {
466
+ p = 2;
467
+ d = 2;
468
+ r = true;
469
+ c = false;
470
+ }
471
+ else if (number >= 100 && number < 1000) {
472
+ p = 2;
473
+ d = 2;
474
+ r = true;
475
+ c = false;
476
+ }
477
+ else if (number >= 1000 && number < 10000) {
478
+ p = 1;
479
+ d = 1;
480
+ r = true;
481
+ c = false;
482
+ }
483
+ else {
484
+ p = 0;
485
+ d = 0;
486
+ r = true;
487
+ c = false;
488
+ }
489
+ }
490
+ // For scientific notation, increase precision to ensure correct representation
491
+ if (this.isENotation(originalInput)) {
492
+ p = Math.max(p, 20);
493
+ r = false;
494
+ }
495
+ return this.reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, thousandSeparator, decimalSeparator, originalInput);
496
+ }
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 = '') {
498
+ var _a, _b;
499
+ if (numberString === undefined || numberString === null || numberString.trim() === '') {
500
+ return {};
501
+ }
502
+ // Handle negative zero
503
+ if (numberString === '-0' || numberString === '-0.0') {
504
+ numberString = numberString.substring(1); // Remove negative sign for zero
505
+ }
506
+ numberString = numberString.toString();
507
+ const maxPrecision = 30;
508
+ const maxIntegerDigits = 21;
509
+ const scaleUnits = template.match(/^(number|percent)$/g)
510
+ ? {
511
+ '': '',
512
+ K: ' هزار',
513
+ M: ' میلیون',
514
+ B: ' میلیارد',
515
+ T: ' تریلیون',
516
+ Qd: ' کادریلیون',
517
+ Qt: ' کنتیلیون',
518
+ }
519
+ : {
520
+ '': '',
521
+ K: ' هزار ت',
522
+ M: ' میلیون ت',
523
+ B: ' میلیارد ت',
524
+ T: ' همت',
525
+ Qd: ' هزار همت',
526
+ Qt: ' میلیون همت',
527
+ };
528
+ const fullScaleUnits = template.match(/^(number|percent)$/g)
529
+ ? {
530
+ '': '',
531
+ K: ' هزار',
532
+ M: ' میلیون',
533
+ B: ' میلیارد',
534
+ T: ' تریلیون',
535
+ Qd: ' کادریلیون',
536
+ Qt: ' کنتیلیون',
537
+ }
538
+ : {
539
+ '': '',
540
+ K: ' هزار تومان',
541
+ M: ' میلیون تومان',
542
+ B: ' میلیارد تومان',
543
+ T: ' هزار میلیارد تومان',
544
+ Qd: ' کادریلیون تومان',
545
+ Qt: ' کنتیلیون تومان',
546
+ };
547
+ let parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(numberString);
548
+ if (!parts) {
549
+ return {};
550
+ }
551
+ const sign = parts[1] || '';
552
+ let nonFractionalStr = parts[2];
553
+ let fractionalZeroStr = parts[3];
554
+ let fractionalNonZeroStr = parts[4];
555
+ let unitPrefix = '';
556
+ let unitPostfix = '';
557
+ if (fractionalZeroStr.length >= maxPrecision) {
558
+ // Number is smaller than maximum precision
559
+ fractionalZeroStr = '0'.padEnd(maxPrecision - 1, '0');
560
+ fractionalNonZeroStr = '1';
561
+ }
562
+ else if (fractionalZeroStr.length + nonZeroDigits > precision) {
563
+ // decrease non-zero digits
564
+ nonZeroDigits = precision - fractionalZeroStr.length;
565
+ if (nonZeroDigits < 1)
566
+ nonZeroDigits = 1;
567
+ }
568
+ else if (nonFractionalStr.length > maxIntegerDigits) {
569
+ nonFractionalStr = '0';
570
+ fractionalZeroStr = '';
571
+ fractionalNonZeroStr = '';
572
+ }
573
+ // compress large numbers
574
+ if (compress && nonFractionalStr.length >= 4) {
575
+ const scaleUnitKeys = Object.keys(scaleUnits);
576
+ let scaledWholeNumber = nonFractionalStr;
577
+ let unitIndex = 0;
578
+ while (+scaledWholeNumber > 999 && unitIndex < scaleUnitKeys.length - 1) {
579
+ scaledWholeNumber = (+scaledWholeNumber / 1000).toFixed(2);
580
+ unitIndex++;
581
+ }
582
+ unitPostfix = scaleUnitKeys[unitIndex];
583
+ parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(scaledWholeNumber.toString());
584
+ if (!parts) {
585
+ return {};
586
+ }
587
+ // sign = parts[1] || "";
588
+ nonFractionalStr = parts[2];
589
+ fractionalZeroStr = parts[3];
590
+ fractionalNonZeroStr = parts[4];
591
+ }
592
+ // Truncate the fractional part or round it
593
+ // if (precision > 0 && nonZeroDigits > 0 && fractionalNonZeroStr.length > nonZeroDigits) {
594
+ if (fractionalNonZeroStr.length > nonZeroDigits) {
595
+ if (!round) {
596
+ fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
597
+ }
598
+ else {
599
+ if (parseInt(fractionalNonZeroStr[nonZeroDigits]) < 5) {
600
+ fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
601
+ }
602
+ else {
603
+ fractionalNonZeroStr = (parseInt(fractionalNonZeroStr.substring(0, nonZeroDigits)) + 1).toString();
604
+ // If overflow occurs (e.g., 999 + 1 = 1000), adjust the substring length
605
+ if (fractionalNonZeroStr.length > nonZeroDigits) {
606
+ if (fractionalZeroStr.length > 0) {
607
+ fractionalZeroStr = fractionalZeroStr.substring(0, fractionalZeroStr.length - 1);
608
+ }
609
+ else {
610
+ nonFractionalStr = (Number(nonFractionalStr) + 1).toString();
611
+ fractionalNonZeroStr = fractionalNonZeroStr.substring(1);
612
+ }
613
+ }
614
+ }
615
+ }
616
+ }
617
+ // Using dex style
618
+ if (compress && fractionalZeroStr !== '' && unitPostfix === '') {
619
+ fractionalZeroStr =
620
+ '0' +
621
+ fractionalZeroStr.length.toString().replace(/\d/g, function (match) {
622
+ return [
623
+ '₀',
624
+ '₁',
625
+ '₂',
626
+ '₃',
627
+ '₄',
628
+ '₅',
629
+ '₆',
630
+ '₇',
631
+ '₈',
632
+ '₉',
633
+ ][parseInt(match, 10)];
634
+ });
635
+ }
636
+ // Check if the original input had trailing zeros
637
+ let fractionalPartStr = `${fractionalZeroStr}${fractionalNonZeroStr}`;
638
+ // Don't truncate trailing zeros when they're in the original string
639
+ if (fractionalPartStr.length > precision && !originalInput.includes('e')) {
640
+ fractionalPartStr = fractionalPartStr.substring(0, precision);
641
+ }
642
+ // For scientific notation and numbers with trailing zeros, preserve the format
643
+ if (originalInput.includes('e') || originalInput.includes('E')) {
644
+ // For scientific notation, use the converted string
645
+ }
646
+ else if (originalInput.includes('.')) {
647
+ // For regular numbers with decimal point, check for trailing zeros
648
+ const originalParts = originalInput.split('.');
649
+ if (originalParts.length === 2) {
650
+ const originalDecimal = originalParts[1];
651
+ // If original has more digits than what we have now, preserve those trailing zeros
652
+ if (originalDecimal.length > fractionalPartStr.length && originalDecimal.endsWith('0')) {
653
+ // Count trailing zeros in original
654
+ let trailingZeros = 0;
655
+ for (let i = originalDecimal.length - 1; i >= 0; i--) {
656
+ if (originalDecimal[i] === '0') {
657
+ trailingZeros++;
658
+ }
659
+ else {
660
+ break;
661
+ }
662
+ }
663
+ // Add back trailing zeros if they were in the original
664
+ if (trailingZeros > 0) {
665
+ fractionalPartStr = fractionalPartStr.padEnd(fractionalPartStr.length + trailingZeros, '0');
666
+ }
667
+ }
668
+ }
669
+ }
670
+ // Output Formating, Prefix, Postfix
671
+ if (template === 'usd') {
672
+ unitPrefix = language === 'en' ? '$' : '';
673
+ if (!unitPostfix)
674
+ unitPostfix = language === 'fa' ? ' دلار' : '';
675
+ }
676
+ else if (template === 'irr') {
677
+ if (!unitPostfix)
678
+ unitPostfix = language === 'fa' ? ' ر' : ' R';
679
+ }
680
+ else if (template === 'irt') {
681
+ if (!unitPostfix)
682
+ unitPostfix = language === 'fa' ? ' ت' : ' T';
683
+ }
684
+ else if (template === 'percent') {
685
+ if (language === 'en') {
686
+ unitPostfix += '%';
687
+ }
688
+ else {
689
+ unitPostfix += !unitPostfix ? '٪' : ' درصد';
690
+ }
691
+ }
692
+ unitPrefix = prefix + unitPrefix;
693
+ unitPostfix += postfix;
694
+ if (outputFormat === 'html') {
695
+ if (unitPrefix)
696
+ unitPrefix = `<${prefixMarker}>${unitPrefix}</${prefixMarker}>`;
697
+ if (unitPostfix)
698
+ unitPostfix = `<${postfixMarker}>${unitPostfix}</${postfixMarker}>`;
699
+ }
700
+ else if (outputFormat === 'markdown') {
701
+ if (unitPrefix)
702
+ unitPrefix = `${prefixMarker}${unitPrefix}${prefixMarker}`;
703
+ if (unitPostfix)
704
+ unitPostfix = `${postfixMarker}${unitPostfix}${postfixMarker}`;
705
+ }
706
+ const thousandSeparatorRegex = /\B(?=(\d{3})+(?!\d))/g;
707
+ const fixedDecimalZeroStr = fixedDecimalZeros
708
+ ? '.'.padEnd(fixedDecimalZeros + 1, '0')
709
+ : '';
710
+ let out = '';
711
+ let wholeNumberStr;
712
+ // FIXED: Changed condition to correctly handle numbers with trailing zeros
713
+ // Old condition: if (precision <= 0 || nonZeroDigits <= 0 || !fractionalNonZeroStr) {
714
+ // New condition checks if both fractional parts are empty
715
+ if (precision <= 0 || nonZeroDigits <= 0 || (fractionalNonZeroStr === '' && fractionalZeroStr === '')) {
716
+ wholeNumberStr = `${nonFractionalStr.replace(thousandSeparatorRegex, ',')}${fixedDecimalZeroStr}`;
717
+ }
718
+ else {
719
+ wholeNumberStr = `${nonFractionalStr.replace(thousandSeparatorRegex, ',')}.${fractionalPartStr}`;
720
+ }
721
+ out = `${sign}${unitPrefix}${wholeNumberStr}${unitPostfix}`;
722
+ const formattedObject = {
723
+ value: out,
724
+ prefix: unitPrefix,
725
+ postfix: unitPostfix,
726
+ sign: sign,
727
+ wholeNumber: wholeNumberStr,
728
+ };
729
+ // replace custom config
730
+ formattedObject.value = ((_a = formattedObject === null || formattedObject === void 0 ? void 0 : formattedObject.value) !== null && _a !== void 0 ? _a : '')
731
+ .replace(/,/g, thousandSeparator)
732
+ .replace(/\./g, decimalSeparator);
733
+ // Convert output to Persian numerals if language is "fa"
734
+ if (language === 'fa') {
735
+ formattedObject.value = ((_b = formattedObject === null || formattedObject === void 0 ? void 0 : formattedObject.value) !== null && _b !== void 0 ? _b : '')
736
+ .replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
737
+ .replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
738
+ return String(scaleUnits[c]);
739
+ });
740
+ formattedObject.fullPostfix = unitPostfix
741
+ .replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
742
+ .replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
743
+ return String(fullScaleUnits[c]);
744
+ });
745
+ formattedObject.postfix = formattedObject.postfix
746
+ .replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
747
+ .replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
748
+ return String(scaleUnits[c]);
749
+ });
750
+ formattedObject.wholeNumber = formattedObject.wholeNumber
751
+ .replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
752
+ .replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
753
+ return String(scaleUnits[c]);
754
+ });
755
+ }
756
+ return formattedObject;
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
+ }
806
+ }
807
+ exports.default = NumberFormatter;
@@ -0,0 +1,2 @@
1
+ import NumberFormatter from './format';
2
+ export { NumberFormatter };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NumberFormatter = void 0;
7
+ const format_1 = __importDefault(require("./format"));
8
+ exports.NumberFormatter = format_1.default;
@@ -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: '' },
27
+ { input: '.', expected: '0.' },
28
+ { input: '0.0', expected: '0.0' },
29
+ { input: '0.12', expected: '0.12' },
30
+ { input: '.5', expected: '0.5' },
31
+ { input: '007', expected: '7' },
32
+ { input: '00.25', expected: '0.25' },
33
+ { input: '12345.6700', expected: '12,345.6700' },
34
+ { input: '000', expected: '0' },
35
+ { input: '000.000', expected: '0.000' },
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' },
39
+ { input: 0.000000123, expected: '0.000000123' },
40
+ { input: '12345e-2', expected: '123.45' },
41
+ { input: '0.00012345e+2', expected: '0.012345' },
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' },
45
+ { input: '1234567.89e+3', expected: '1,234,567,890' },
46
+ { input: '123456789012345', expected: '123,456,789,012,345' },
47
+ { input: 123456789012345, expected: '123,456,789,012,345' },
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' },
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' },
57
+ { input: 123456789123456789123, expected: '123,456,789,123,456,800,000' },
58
+ { input: '1.0e-20', expected: '0.00000000000000000001' },
59
+ { input: 1.0e-20, expected: '0.00000000000000000001' },
60
+ { input: '1.0e+20', expected: '100,000,000,000,000,000,000' },
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' },
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
+ });