diff --git a/dist/filesize.cjs b/dist/filesize.cjs index 8359dc0..dd49679 100644 --- a/dist/filesize.cjs +++ b/dist/filesize.cjs @@ -228,6 +228,77 @@ function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = t return { result, e }; } +/** + * Calculates the unit exponent for a bigint input using bigint comparisons + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent value + * @param {number} exponent - Original user-provided exponent option (-1 for auto) + * @param {boolean} isDecimal - Whether to use decimal (SI) base + * @param {number} precision - Current precision value (modified when e > 8) + * @returns {Object} Object with computed e value and possibly adjusted precision + */ +function calculateBigIntExponent(num, e, exponent, isDecimal, precision) { + if (typeof e === "string") { + e = Number(e); + } + + if (e === -1 || isNaN(e)) { + e = 0; + if (isDecimal) { + while (e < 8 && num >= 10n ** BigInt(3 * (e + 1))) { + e++; + } + } else { + while (e < 8 && num >= 1024n ** BigInt(e + 1)) { + e++; + } + } + } else if (e < 0) { + e = 0; + } else { + e = Math.floor(e); + } + + if (e > 8) { + if (precision > 0) { + precision += 8 - e; + } + return { e: 8, precision }; + } + + return { e, precision }; +} + +/** + * Calculates the value for a bigint input using bigint arithmetic + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN) + * @returns {Object} Object with result and e properties + */ +function calculateBigIntValue(num, e, isDecimal, bits, ceil, autoExponent = true) { + const power = isDecimal ? 10n ** BigInt(3 * e) : 1024n ** BigInt(e); + // Scaled division preserves precision above Number.MAX_SAFE_INTEGER. + // Multiply by 10^16 before dividing, then scale back down, so the + // quotient keeps ~16 significant digits instead of collapsing to a float. + const SHIFT = 10n ** 16n; + let result = Number((num * SHIFT) / power) / Number(SHIFT); + + if (bits) { + result *= 8; + // Handle auto-increment for bits (only when exponent is auto) + if (autoExponent && result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return { result, e }; +} + /** * Optimized precision handling with scientific notation correction * @param {number} value - Current value @@ -667,6 +738,8 @@ function filesize( val = 0, u = EMPTY; + const isBigInt = typeof arg === "bigint"; + num = Number(arg); if (isNaN(num)) { @@ -706,27 +779,43 @@ function filesize( ); } + // BigInt inputs use bigint arithmetic to preserve precision above + // Number.MAX_SAFE_INTEGER and detect unit boundaries accurately. + const bigNum = isBigInt ? (neg ? -BigInt(arg) : BigInt(arg)) : null; + // Exponent calculation + clamp + precision adjustment - const { e: calculatedE, precision: precisionAdjusted } = calculateExponent( - num, - e, - exponent, - isDecimal, - precision, - ); - e = calculatedE; + let precisionAdjusted = precision; + if (isBigInt) { + const { e: calculatedE, precision: pa } = calculateBigIntExponent( + bigNum, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } else { + const { e: calculatedE, precision: pa } = calculateExponent( + num, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } const autoExponent = exponent === -1 || isNaN(exponent); - const { result: valueResult, e: valueExponent } = calculateOptimizedValue( - num, - e, - isDecimal, - bits, - ceil, - autoExponent, - ); - val = valueResult; - e = valueExponent; + let valueResult; + if (isBigInt) { + valueResult = calculateBigIntValue(bigNum, e, isDecimal, bits, ceil, autoExponent); + } else { + valueResult = calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent); + } + val = valueResult.result; + e = valueResult.e; // Rounding + auto-increment ceiling const rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent); diff --git a/dist/filesize.js b/dist/filesize.js index fbf9883..1310271 100644 --- a/dist/filesize.js +++ b/dist/filesize.js @@ -224,6 +224,77 @@ function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = t return { result, e }; } +/** + * Calculates the unit exponent for a bigint input using bigint comparisons + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent value + * @param {number} exponent - Original user-provided exponent option (-1 for auto) + * @param {boolean} isDecimal - Whether to use decimal (SI) base + * @param {number} precision - Current precision value (modified when e > 8) + * @returns {Object} Object with computed e value and possibly adjusted precision + */ +function calculateBigIntExponent(num, e, exponent, isDecimal, precision) { + if (typeof e === "string") { + e = Number(e); + } + + if (e === -1 || isNaN(e)) { + e = 0; + if (isDecimal) { + while (e < 8 && num >= 10n ** BigInt(3 * (e + 1))) { + e++; + } + } else { + while (e < 8 && num >= 1024n ** BigInt(e + 1)) { + e++; + } + } + } else if (e < 0) { + e = 0; + } else { + e = Math.floor(e); + } + + if (e > 8) { + if (precision > 0) { + precision += 8 - e; + } + return { e: 8, precision }; + } + + return { e, precision }; +} + +/** + * Calculates the value for a bigint input using bigint arithmetic + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN) + * @returns {Object} Object with result and e properties + */ +function calculateBigIntValue(num, e, isDecimal, bits, ceil, autoExponent = true) { + const power = isDecimal ? 10n ** BigInt(3 * e) : 1024n ** BigInt(e); + // Scaled division preserves precision above Number.MAX_SAFE_INTEGER. + // Multiply by 10^16 before dividing, then scale back down, so the + // quotient keeps ~16 significant digits instead of collapsing to a float. + const SHIFT = 10n ** 16n; + let result = Number((num * SHIFT) / power) / Number(SHIFT); + + if (bits) { + result *= 8; + // Handle auto-increment for bits (only when exponent is auto) + if (autoExponent && result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return { result, e }; +} + /** * Optimized precision handling with scientific notation correction * @param {number} value - Current value @@ -661,6 +732,8 @@ function filesize( val = 0, u = EMPTY; + const isBigInt = typeof arg === "bigint"; + num = Number(arg); if (isNaN(num)) { @@ -700,27 +773,43 @@ function filesize( ); } + // BigInt inputs use bigint arithmetic to preserve precision above + // Number.MAX_SAFE_INTEGER and detect unit boundaries accurately. + const bigNum = isBigInt ? (neg ? -BigInt(arg) : BigInt(arg)) : null; + // Exponent calculation + clamp + precision adjustment - const { e: calculatedE, precision: precisionAdjusted } = calculateExponent( - num, - e, - exponent, - isDecimal, - precision, - ); - e = calculatedE; + let precisionAdjusted = precision; + if (isBigInt) { + const { e: calculatedE, precision: pa } = calculateBigIntExponent( + bigNum, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } else { + const { e: calculatedE, precision: pa } = calculateExponent( + num, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } const autoExponent = exponent === -1 || isNaN(exponent); - const { result: valueResult, e: valueExponent } = calculateOptimizedValue( - num, - e, - isDecimal, - bits, - ceil, - autoExponent, - ); - val = valueResult; - e = valueExponent; + let valueResult; + if (isBigInt) { + valueResult = calculateBigIntValue(bigNum, e, isDecimal, bits, ceil, autoExponent); + } else { + valueResult = calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent); + } + val = valueResult.result; + e = valueResult.e; // Rounding + auto-increment ceiling const rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent); diff --git a/dist/filesize.min.js b/dist/filesize.min.js index 7ced935..53a86e3 100644 --- a/dist/filesize.min.js +++ b/dist/filesize.min.js @@ -2,4 +2,4 @@ 2026 Jason Mulligan @version 11.0.24 */ -const t="Invalid number",e="Invalid precision",i="iec",n="jedec",r="si",o="byte",a="array",s="object",l="string",u="exponent",c="round",f={symbol:{iec:{bits:["bit","Kibit","Mibit","Gibit","Tibit","Pibit","Eibit","Zibit","Yibit"],bytes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},jedec:{bits:["bit","Kbit","Mbit","Gbit","Tbit","Pbit","Ebit","Zbit","Ybit"],bytes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]}},fullform:{iec:["","kibi","mebi","gibi","tebi","pebi","exbi","zebi","yobi"],jedec:["","kilo","mega","giga","tera","peta","exa","zetta","yotta"]}},b=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],p=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],d=Math.log(1024),m=Math.log(1e3),y={[r]:{isDecimal:!0,ceil:1e3,actualStandard:n},[i]:{isDecimal:!1,ceil:1024,actualStandard:i},[n]:{isDecimal:!1,ceil:1024,actualStandard:n}};function h(t,e,i,n,r,o=!0){let a;a=i?p[e]:b[e];let s=t/a;return n&&(s*=8,o&&s>=r&&e<8&&(s/=r,e++)),{result:s,e:e}}function M(r,{bits:b=!1,pad:p=!1,base:M=-1,round:B=2,locale:g="",localeOptions:N={},separator:w="",spacer:x=" ",symbols:S={},standard:v="",output:E=l,fullform:T=!1,fullforms:D=[],exponent:O=-1,roundingMethod:$=c,precision:F=0}={}){let G,j=O,k=[],I=0,J="";if(G=Number(r),isNaN(G))throw new TypeError(t);if(!isFinite(G))throw new TypeError(t);const{isDecimal:K,ceil:P,actualStandard:Y}=function(t,e){return y[t]?y[t]:2===e?{isDecimal:!1,ceil:1024,actualStandard:i}:{isDecimal:!0,ceil:1e3,actualStandard:n}}(v,M),Z=!0===T,z=G<0,C=Math[$];if("function"!=typeof C)throw new TypeError("Invalid rounding method");if(z&&(G=-G),0===G)return function(t,e,i,n,r,l,c,b,p,d,m){let y;return y=t>0?(0).toPrecision(t):p&&d>0?(0).toFixed(d):0,c===u?0:(m||(m=i?f.symbol[e].bits[0]:f.symbol[e].bytes[0]),n[m]&&(m=n[m]),r&&(l[0]?m=l[0]:(m=f.fullform[e][0],m+=i?"bit":o)),c===a?[y,m]:c===s?{value:y,symbol:m,exponent:0,unit:m}:y+b+m)}(F,Y,b,S,Z,D,E,x,p,B);const{e:U,precision:q}=function(t,e,i,n,r){return"string"==typeof e&&(e=Number(e)),-1===e||isNaN(e)?(e=n?Math.floor(Math.log(t)/m):Math.floor(Math.log(t)/d))<0&&(e=0):e=e<0?0:Math.floor(e),e>8?(r>0&&(r+=8-e),{e:8,precision:r}):{e:e,precision:r}}(G,j,0,K,F);j=U;const A=-1===O||isNaN(O),{result:H,e:L}=h(G,j,K,b,P,A);I=H,j=L;const Q=function(t,e,i,n,r,o){let a,s;return a=i>0&&n>0?Math.pow(10,n):1,s=1===a?r(t):r(t*a)/a,s===e&&i<8&&o&&(s=1,i++),{value:s,e:i}}(I,P,j,B,C,A);if(k[0]=Q.value,j=Q.e,q>0){const t=function(t,i,n,r,o,a,s,l,u,c){if("string"==typeof t&&(t=parseFloat(t)),"number"!=typeof i||isNaN(i))throw new TypeError(e);if((i=Math.floor(i))<1||i>100)throw new TypeError(e);let f=t.toPrecision(i);const b=-1===c||isNaN(c);if(f.includes("e")&&n<8&&b){n++;const{result:t}=h(r,n,o,a,s);let e,c;e=u>0?Math.pow(10,u):1,c=1===e?l(t):l(t*e)/e,f=c.toPrecision(i)}return{value:f,e:n}}(k[0],q,j,G,K,b,P,C,B,O);k[0]=t.value,j=t.e}return E===u?j:(J=function(t,e,i,n){const r=f.symbol[t][e?"bits":"bytes"];let o;return o=n&&1===i?e?"kbit":"kB":r[i],o}(Y,b,j,K),k[1]=J,function(t,e,i,n,r,a,s,l,u,c,b,p,d,m){let y;if(e&&("string"==typeof t[0]?t[0]=`-${t[0]}`:0===t[0]?t[0]="-0":t[0]=-t[0]),i[t[1]]&&(t[1]=i[t[1]]),y="string"==typeof t[0]?parseFloat(t[0]):t[0],t[0]=function(t,e,i,n,r,o,a){let s=t;const l=r&&o>0?{minimumFractionDigits:o,maximumFractionDigits:o}:void 0;if(!0===e)s=s.toLocaleString(void 0,l);else if(e.length>0)s=s.toLocaleString(e,{...i,...l});else if(n.length>0){if(r&&o>0){const t=Math.pow(10,o);s=a(s*t)/t}s=s.toString().replace(".",n)}if("number"==typeof s&&isFinite(s)&&s.toString().includes("e")&&(s=s.toLocaleString("en-US",{useGrouping:!1})),r&&o>0&&!0!==e&&0===e.length){const t=n||".",e=s.toString().split(t),i=e[1]||"";s=`${e[0]}${t}${i.padEnd(o,"0")}`}return s}(t[0],n,r,a,s,l,m),u){let e,i;e=d?"bit":o,i=1===Math.abs(y)?"":"s",c[p]?t[1]=c[p]:t[1]=f.fullform[b][p]+e+i}}(k,z,S,g,N,w,p,B,Z,D,Y,j,b,C),function(t,e,i,n,r){if(n!==a&&n!==s&&n!==l&&n!==u)throw new TypeError(`Invalid output: ${n}`);if(n===a)return t;if(n===s)return{value:t[0],symbol:t[1],exponent:e,unit:i};let o;return o=" "===r?`${t[0]} ${t[1]}`:t.join(r),o}(k,j,J,E,x))}function B({bits:t=!1,pad:e=!1,base:i=-1,round:n=2,locale:r="",separator:o="",spacer:a=" ",standard:s="",output:u=l,fullform:f=!1,exponent:b=-1,roundingMethod:p=c,precision:d=0,localeOptions:m={},symbols:y={},fullforms:h=[]}={}){function B(t){try{return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}catch{return JSON.parse(JSON.stringify(t))}}const g={localeOptions:B(m),symbols:B(y),fullforms:B(h)};return l=>M(l,{bits:t,pad:e,base:i,round:n,locale:r,localeOptions:g.localeOptions,separator:o,spacer:a,symbols:g.symbols,standard:s,output:u,fullform:f,fullforms:g.fullforms,exponent:b,roundingMethod:p,precision:d})}export{M as filesize,B as partial};//# sourceMappingURL=filesize.min.js.map +const t="Invalid number",e="Invalid precision",i="iec",n="jedec",r="si",o="byte",a="array",s="object",l="string",u="exponent",c="round",f={symbol:{iec:{bits:["bit","Kibit","Mibit","Gibit","Tibit","Pibit","Eibit","Zibit","Yibit"],bytes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},jedec:{bits:["bit","Kbit","Mbit","Gbit","Tbit","Pbit","Ebit","Zbit","Ybit"],bytes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]}},fullform:{iec:["","kibi","mebi","gibi","tebi","pebi","exbi","zebi","yobi"],jedec:["","kilo","mega","giga","tera","peta","exa","zetta","yotta"]}},b=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],p=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],d=Math.log(1024),m=Math.log(1e3),y={[r]:{isDecimal:!0,ceil:1e3,actualStandard:n},[i]:{isDecimal:!1,ceil:1024,actualStandard:i},[n]:{isDecimal:!1,ceil:1024,actualStandard:n}};function h(t,e,i,n,r,o=!0){let a;a=i?p[e]:b[e];let s=t/a;return n&&(s*=8,o&&s>=r&&e<8&&(s/=r,e++)),{result:s,e:e}}function B(r,{bits:b=!1,pad:p=!1,base:B=-1,round:g=2,locale:M="",localeOptions:N={},separator:w="",spacer:x=" ",symbols:S={},standard:v="",output:E=l,fullform:I=!1,fullforms:T=[],exponent:D=-1,roundingMethod:O=c,precision:$=0}={}){let F,G=D,j=[],k=0,J="";const K="bigint"==typeof r;if(F=Number(r),isNaN(F))throw new TypeError(t);if(!isFinite(F))throw new TypeError(t);const{isDecimal:P,ceil:Y,actualStandard:Z}=function(t,e){return y[t]?y[t]:2===e?{isDecimal:!1,ceil:1024,actualStandard:i}:{isDecimal:!0,ceil:1e3,actualStandard:n}}(v,B),z=!0===I,C=F<0,U=Math[O];if("function"!=typeof U)throw new TypeError("Invalid rounding method");if(C&&(F=-F),0===F)return function(t,e,i,n,r,l,c,b,p,d,m){let y;return y=t>0?(0).toPrecision(t):p&&d>0?(0).toFixed(d):0,c===u?0:(m||(m=i?f.symbol[e].bits[0]:f.symbol[e].bytes[0]),n[m]&&(m=n[m]),r&&(l[0]?m=l[0]:(m=f.fullform[e][0],m+=i?"bit":o)),c===a?[y,m]:c===s?{value:y,symbol:m,exponent:0,unit:m}:y+b+m)}($,Z,b,S,z,T,E,x,p,g);const q=K?C?-BigInt(r):BigInt(r):null;let A=$;if(K){const{e:t,precision:e}=function(t,e,i,n,r){if("string"==typeof e&&(e=Number(e)),-1===e||isNaN(e))if(e=0,n)for(;e<8&&t>=10n**BigInt(3*(e+1));)e++;else for(;e<8&&t>=1024n**BigInt(e+1);)e++;else e=e<0?0:Math.floor(e);return e>8?(r>0&&(r+=8-e),{e:8,precision:r}):{e:e,precision:r}}(q,G,0,P,$);G=t,A=e}else{const{e:t,precision:e}=function(t,e,i,n,r){return"string"==typeof e&&(e=Number(e)),-1===e||isNaN(e)?(e=n?Math.floor(Math.log(t)/m):Math.floor(Math.log(t)/d))<0&&(e=0):e=e<0?0:Math.floor(e),e>8?(r>0&&(r+=8-e),{e:8,precision:r}):{e:e,precision:r}}(F,G,0,P,$);G=t,A=e}const H=-1===D||isNaN(D);let L;L=K?function(t,e,i,n,r,o=!0){const a=i?10n**BigInt(3*e):1024n**BigInt(e),s=10n**16n;let l=Number(t*s/a)/Number(s);return n&&(l*=8,o&&l>=r&&e<8&&(l/=r,e++)),{result:l,e:e}}(q,G,P,b,Y,H):h(F,G,P,b,Y,H),k=L.result,G=L.e;const Q=function(t,e,i,n,r,o){let a,s;return a=i>0&&n>0?Math.pow(10,n):1,s=1===a?r(t):r(t*a)/a,s===e&&i<8&&o&&(s=1,i++),{value:s,e:i}}(k,Y,G,g,U,H);if(j[0]=Q.value,G=Q.e,A>0){const t=function(t,i,n,r,o,a,s,l,u,c){if("string"==typeof t&&(t=parseFloat(t)),"number"!=typeof i||isNaN(i))throw new TypeError(e);if((i=Math.floor(i))<1||i>100)throw new TypeError(e);let f=t.toPrecision(i);const b=-1===c||isNaN(c);if(f.includes("e")&&n<8&&b){n++;const{result:t}=h(r,n,o,a,s);let e,c;e=u>0?Math.pow(10,u):1,c=1===e?l(t):l(t*e)/e,f=c.toPrecision(i)}return{value:f,e:n}}(j[0],A,G,F,P,b,Y,U,g,D);j[0]=t.value,G=t.e}return E===u?G:(J=function(t,e,i,n){const r=f.symbol[t][e?"bits":"bytes"];let o;return o=n&&1===i?e?"kbit":"kB":r[i],o}(Z,b,G,P),j[1]=J,function(t,e,i,n,r,a,s,l,u,c,b,p,d,m){let y;if(e&&("string"==typeof t[0]?t[0]=`-${t[0]}`:0===t[0]?t[0]="-0":t[0]=-t[0]),i[t[1]]&&(t[1]=i[t[1]]),y="string"==typeof t[0]?parseFloat(t[0]):t[0],t[0]=function(t,e,i,n,r,o,a){let s=t;const l=r&&o>0?{minimumFractionDigits:o,maximumFractionDigits:o}:void 0;if(!0===e)s=s.toLocaleString(void 0,l);else if(e.length>0)s=s.toLocaleString(e,{...i,...l});else if(n.length>0){if(r&&o>0){const t=Math.pow(10,o);s=a(s*t)/t}s=s.toString().replace(".",n)}if("number"==typeof s&&isFinite(s)&&s.toString().includes("e")&&(s=s.toLocaleString("en-US",{useGrouping:!1})),r&&o>0&&!0!==e&&0===e.length){const t=n||".",e=s.toString().split(t),i=e[1]||"";s=`${e[0]}${t}${i.padEnd(o,"0")}`}return s}(t[0],n,r,a,s,l,m),u){let e,i;e=d?"bit":o,i=1===Math.abs(y)?"":"s",c[p]?t[1]=c[p]:t[1]=f.fullform[b][p]+e+i}}(j,C,S,M,N,w,p,g,z,T,Z,G,b,U),function(t,e,i,n,r){if(n!==a&&n!==s&&n!==l&&n!==u)throw new TypeError(`Invalid output: ${n}`);if(n===a)return t;if(n===s)return{value:t[0],symbol:t[1],exponent:e,unit:i};let o;return o=" "===r?`${t[0]} ${t[1]}`:t.join(r),o}(j,G,J,E,x))}function g({bits:t=!1,pad:e=!1,base:i=-1,round:n=2,locale:r="",separator:o="",spacer:a=" ",standard:s="",output:u=l,fullform:f=!1,exponent:b=-1,roundingMethod:p=c,precision:d=0,localeOptions:m={},symbols:y={},fullforms:h=[]}={}){function g(t){try{return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}catch{return JSON.parse(JSON.stringify(t))}}const M={localeOptions:g(m),symbols:g(y),fullforms:g(h)};return l=>B(l,{bits:t,pad:e,base:i,round:n,locale:r,localeOptions:M.localeOptions,separator:o,spacer:a,symbols:M.symbols,standard:s,output:u,fullform:f,fullforms:M.fullforms,exponent:b,roundingMethod:p,precision:d})}export{B as filesize,g as partial};//# sourceMappingURL=filesize.min.js.map diff --git a/dist/filesize.min.js.map b/dist/filesize.min.js.map index 9f443c6..2448cb2 100644 --- a/dist/filesize.min.js.map +++ b/dist/filesize.min.js.map @@ -1 +1 @@ -{"version":3,"file":"filesize.min.js","sources":["../src/constants.js","../src/helpers.js","../src/filesize.js"],"sourcesContent":["// Error Messages\nexport const INVALID_NUMBER = \"Invalid number\";\nexport const INVALID_ROUND = \"Invalid rounding method\";\nexport const INVALID_PRECISION = \"Invalid precision\";\n\n// Standard Types\nexport const IEC = \"iec\";\nexport const JEDEC = \"jedec\";\nexport const SI = \"si\";\n\n// Unit Types\nexport const BIT = \"bit\";\nexport const BITS = \"bits\";\nexport const BYTE = \"byte\";\nexport const BYTES = \"bytes\";\nexport const SI_KBIT = \"kbit\";\nexport const SI_KBYTE = \"kB\";\n\n// Output Format Types\nexport const ARRAY = \"array\";\nexport const FUNCTION = \"function\";\nexport const OBJECT = \"object\";\nexport const STRING = \"string\";\n\n// Processing Constants\nexport const EXPONENT = \"exponent\";\nexport const ROUND = \"round\";\n\n// Special Characters and Values\nexport const E = \"e\";\nexport const EMPTY = \"\";\nexport const PERIOD = \".\";\nexport const S = \"s\";\nexport const SPACE = \" \";\nexport const ZERO = \"0\";\n\n// Data Structures\nexport const STRINGS = {\n\tsymbol: {\n\t\tiec: {\n\t\t\tbits: [\"bit\", \"Kibit\", \"Mibit\", \"Gibit\", \"Tibit\", \"Pibit\", \"Eibit\", \"Zibit\", \"Yibit\"],\n\t\t\tbytes: [\"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\", \"PiB\", \"EiB\", \"ZiB\", \"YiB\"],\n\t\t},\n\t\tjedec: {\n\t\t\tbits: [\"bit\", \"Kbit\", \"Mbit\", \"Gbit\", \"Tbit\", \"Pbit\", \"Ebit\", \"Zbit\", \"Ybit\"],\n\t\t\tbytes: [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"],\n\t\t},\n\t},\n\tfullform: {\n\t\tiec: [\"\", \"kibi\", \"mebi\", \"gibi\", \"tebi\", \"pebi\", \"exbi\", \"zebi\", \"yobi\"],\n\t\tjedec: [\"\", \"kilo\", \"mega\", \"giga\", \"tera\", \"peta\", \"exa\", \"zetta\", \"yotta\"],\n\t},\n};\n\n// Pre-computed lookup tables for performance optimization\nexport const BINARY_POWERS = [\n\t1, // 2^0\n\t1024, // 2^10\n\t1048576, // 2^20\n\t1073741824, // 2^30\n\t1099511627776, // 2^40\n\t1125899906842624, // 2^50\n\t1152921504606846976, // 2^60\n\t1180591620717411303424, // 2^70\n\t1208925819614629174706176, // 2^80\n];\n\nexport const DECIMAL_POWERS = [\n\t1, // 10^0\n\t1000, // 10^3\n\t1000000, // 10^6\n\t1000000000, // 10^9\n\t1000000000000, // 10^12\n\t1000000000000000, // 10^15\n\t1000000000000000000, // 10^18\n\t1000000000000000000000, // 10^21\n\t1000000000000000000000000, // 10^24\n];\n\n// Pre-computed log values for faster exponent calculation\nexport const LOG_2_1024 = Math.log(1024);\nexport const LOG_10_1000 = Math.log(1000);\n","import {\n\tARRAY,\n\tBINARY_POWERS,\n\tBIT,\n\tBITS,\n\tBYTE,\n\tBYTES,\n\tDECIMAL_POWERS,\n\tE,\n\tEMPTY,\n\tEXPONENT,\n\tIEC,\n\tINVALID_PRECISION,\n\tJEDEC,\n\tLOG_10_1000,\n\tLOG_2_1024,\n\tOBJECT,\n\tPERIOD,\n\tS,\n\tSI,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n\tZERO,\n} from \"./constants.js\";\n\n// Cached configuration lookup for better performance\nconst STANDARD_CONFIGS = {\n\t[SI]: { isDecimal: true, ceil: 1000, actualStandard: JEDEC },\n\t[IEC]: { isDecimal: false, ceil: 1024, actualStandard: IEC },\n\t[JEDEC]: { isDecimal: false, ceil: 1024, actualStandard: JEDEC },\n};\n\n/**\n * Optimized base configuration lookup\n * @param {string} standard - Standard type\n * @param {number} base - Base number\n * @returns {Object} Configuration object\n */\nexport function getBaseConfiguration(standard, base) {\n\t// Use cached lookup table for better performance\n\tif (STANDARD_CONFIGS[standard]) {\n\t\treturn STANDARD_CONFIGS[standard];\n\t}\n\n\t// Base override\n\tif (base === 2) {\n\t\treturn { isDecimal: false, ceil: 1024, actualStandard: IEC };\n\t}\n\n\t// Default\n\treturn { isDecimal: true, ceil: 1000, actualStandard: JEDEC };\n}\n\n/**\n * Optimized zero value handling\n * @param {number} precision - Precision value\n * @param {string} actualStandard - Standard to use\n * @param {boolean} bits - Whether to use bits\n * @param {Object} symbols - Custom symbols\n * @param {boolean} full - Whether to use full form\n * @param {Array} fullforms - Custom full forms\n * @param {string} output - Output format\n * @param {string} spacer - Spacer character\n * @param {boolean} pad - Whether to pad decimal places\n * @param {number} round - Number of decimal places for padding\n * @param {string} [symbol] - Symbol to use (defaults based on bits/standard)\n * @returns {string|Array|Object|number} Formatted result\n */\nexport function handleZeroValue(\n\tprecision,\n\tactualStandard,\n\tbits,\n\tsymbols,\n\tfull,\n\tfullforms,\n\toutput,\n\tspacer,\n\tpad,\n\tround,\n\tsymbol,\n) {\n\tlet value;\n\tif (precision > 0) {\n\t\tvalue = (0).toPrecision(precision);\n\t} else if (pad && round > 0) {\n\t\tvalue = (0).toFixed(round);\n\t} else {\n\t\tvalue = 0;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn 0;\n\t}\n\n\t// Set default symbol if not provided\n\tif (!symbol) {\n\t\tsymbol = bits\n\t\t\t? STRINGS.symbol[actualStandard].bits[0]\n\t\t\t: STRINGS.symbol[actualStandard].bytes[0];\n\t}\n\n\t// Apply symbol customization\n\tif (symbols[symbol]) {\n\t\tsymbol = symbols[symbol];\n\t}\n\n\t// Apply full form\n\tif (full) {\n\t\tif (fullforms[0]) {\n\t\t\tsymbol = fullforms[0];\n\t\t} else {\n\t\t\tsymbol = STRINGS.fullform[actualStandard][0];\n\t\t\tif (bits) {\n\t\t\t\tsymbol += BIT;\n\t\t\t} else {\n\t\t\t\tsymbol += BYTE;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return in requested format\n\tif (output === ARRAY) {\n\t\treturn [value, symbol];\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn { value, symbol, exponent: 0, unit: symbol };\n\t}\n\n\treturn value + spacer + symbol;\n}\n\n/**\n * Optimized value calculation with bits handling\n * @param {number} num - Input number\n * @param {number} e - Exponent\n * @param {boolean} isDecimal - Whether to use decimal powers\n * @param {boolean} bits - Whether to calculate bits\n * @param {number} ceil - Ceiling value for auto-increment\n * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)\n * @returns {Object} Object with result and e properties\n */\nexport function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = true) {\n\tlet d;\n\tif (isDecimal) {\n\t\td = DECIMAL_POWERS[e];\n\t} else {\n\t\td = BINARY_POWERS[e];\n\t}\n\tlet result = num / d;\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits (only when exponent is auto)\n\t\tif (autoExponent && result >= ceil && e < 8) {\n\t\t\tresult /= ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\treturn { result, e };\n}\n\n/**\n * Optimized precision handling with scientific notation correction\n * @param {number} value - Current value\n * @param {number} precision - Precision to apply\n * @param {number} e - Current exponent\n * @param {number} num - Original number\n * @param {boolean} isDecimal - Whether using decimal base\n * @param {boolean} bits - Whether calculating bits\n * @param {number} ceil - Ceiling value\n * @param {Function} roundingFunc - Rounding function\n * @param {number} round - Round value\n * @param {number} exponent - Forced exponent (-1 for auto)\n * @returns {Object} Object with value and e properties\n */\nexport function applyPrecisionHandling(\n\tvalue,\n\tprecision,\n\te,\n\tnum,\n\tisDecimal,\n\tbits,\n\tceil,\n\troundingFunc,\n\tround,\n\texponent,\n) {\n\tif (typeof value === \"string\") {\n\t\tvalue = parseFloat(value);\n\t}\n\n\t// Validate precision range. toPrecision() throws a raw RangeError for\n\t// values outside 1-100; normalize to a clean TypeError and floor any\n\t// non-integer value (which toPrecision would otherwise truncate silently).\n\tif (typeof precision !== \"number\" || isNaN(precision)) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\tprecision = Math.floor(precision);\n\tif (precision < 1 || precision > 100) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\n\tlet result = value.toPrecision(precision);\n\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\t// Handle scientific notation by recalculating with incremented exponent\n\tif (result.includes(E) && e < 8 && autoExponent) {\n\t\te++;\n\t\tconst { result: valueResult } = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\t\tlet p;\n\t\tif (round > 0) {\n\t\t\tp = Math.pow(10, round);\n\t\t} else {\n\t\t\tp = 1;\n\t\t}\n\t\tlet computed;\n\t\tif (p === 1) {\n\t\t\tcomputed = roundingFunc(valueResult);\n\t\t} else {\n\t\t\tcomputed = roundingFunc(valueResult * p) / p;\n\t\t}\n\t\tresult = computed.toPrecision(precision);\n\t}\n\n\treturn { value: result, e };\n}\n\n/**\n * Optimized number formatting with locale, separator, and padding\n * @param {number|string} value - Value to format\n * @param {string|boolean} locale - Locale setting\n * @param {Object} localeOptions - Locale options\n * @param {string} separator - Custom separator\n * @param {boolean} pad - Whether to pad\n * @param {number} round - Round value\n * @returns {string|number} Formatted value\n */\nexport function applyNumberFormatting(\n\tvalue,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\troundingFunc,\n) {\n\tlet result = value;\n\n\t// When padding alongside a locale, let the locale formatter emit the fixed\n\t// number of fraction digits. The manual string padding below cannot tell a\n\t// locale-inserted grouping separator from the decimal separator, so it\n\t// dropped digits (e.g. \"1,234,500\" became \"1,234\").\n\tconst localePad =\n\t\tpad && round > 0 ? { minimumFractionDigits: round, maximumFractionDigits: round } : undefined;\n\n\t// Apply locale formatting\n\tif (locale === true) {\n\t\tresult = result.toLocaleString(undefined, localePad);\n\t} else if (locale.length > 0) {\n\t\tresult = result.toLocaleString(locale, { ...localeOptions, ...localePad });\n\t} else if (separator.length > 0) {\n\t\t// Round before separator replacement to ensure excess decimal places\n\t\t// are truncated when pad is also set (fixes padding + separator bug).\n\t\tif (pad && round > 0) {\n\t\t\tconst p = Math.pow(10, round);\n\t\t\tresult = roundingFunc(result * p) / p;\n\t\t}\n\t\tresult = result.toString().replace(PERIOD, separator);\n\t}\n\n\t// Expand scientific notation to full decimal so pathological values like\n\t// Number.MAX_VALUE don't leak \"e+284\" into the output. Only applies when\n\t// the value is a finite number whose string form uses exponent notation.\n\tif (typeof result === \"number\" && isFinite(result) && result.toString().includes(E)) {\n\t\tresult = result.toLocaleString(\"en-US\", { useGrouping: false });\n\t}\n\n\t// Apply padding for the non-locale paths, where the string has a single\n\t// decimal separator and no grouping is inserted.\n\tif (pad && round > 0 && locale !== true && locale.length === 0) {\n\t\tconst resultStr = result.toString();\n\t\tconst x = separator || PERIOD;\n\t\tconst tmp = resultStr.split(x);\n\t\tconst s = tmp[1] || EMPTY;\n\n\t\tresult = `${tmp[0]}${x}${s.padEnd(round, ZERO)}`;\n\t}\n\n\treturn result;\n}\n\n/**\n * Calculates exponent from the input value using pre-computed log values and clamps to supported range\n * Also adjusts precision when exponent exceeds the lookup table bounds\n * @param {number} num - Input file size in bytes\n * @param {number} e - Current exponent value\n * @param {number} exponent - Original user-provided exponent option (-1 for auto)\n * @param {boolean} isDecimal - Whether to use decimal (SI) base\n * @param {number} precision - Current precision value (modified when e > 8)\n * @returns {Object} Object with computed e value and possibly adjusted precision\n */\nexport function calculateExponent(num, e, exponent, isDecimal, precision) {\n\t// A string exponent (e.g. \"1\") must be coerced to a number before the\n\t// strict `e === 1` checks below; otherwise it indexes the symbol tables\n\t// with a string and misses the SI special case in resolveSymbol.\n\tif (typeof e === \"string\") {\n\t\te = Number(e);\n\t}\n\n\tif (e === -1 || isNaN(e)) {\n\t\tif (isDecimal) {\n\t\t\te = Math.floor(Math.log(num) / LOG_10_1000);\n\t\t} else {\n\t\t\te = Math.floor(Math.log(num) / LOG_2_1024);\n\t\t}\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t} else if (e < 0) {\n\t\t// A forced exponent below the auto sentinel (-1) has no meaning and\n\t\t// would otherwise index the power-of-ten/two lookup tables out of\n\t\t// bounds (producing NaN). Clamp to 0, mirroring the e > 8 clamp below.\n\t\te = 0;\n\t} else {\n\t\t// A non-integer positive exponent (e.g. 1.5) would index the\n\t\t// power-of-ten/two lookup tables out of bounds (producing NaN).\n\t\t// Floor it to the nearest valid integer, mirroring the clamps above.\n\t\te = Math.floor(e);\n\t}\n\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\treturn { e: 8, precision };\n\t}\n\n\treturn { e, precision };\n}\n\n/**\n * Applies rounding to the raw calculated value and handles auto-increment ceiling\n * @param {number} val - Raw value before rounding\n * @param {number} ceil - Ceiling threshold (1000 for SI, 1024 for IEC)\n * @param {number} e - Current exponent value\n * @param {number} round - Number of decimal places\n * @param {Function} roundingFunc - Rounding method (Math.round, Math.floor, Math.ceil)\n * @param {boolean} autoExponent - Whether exponent is auto-calculated (-1 or NaN)\n * @returns {Object} Object with rounded value and possibly incremented exponent\n */\nexport function applyRounding(val, ceil, e, round, roundingFunc, autoExponent) {\n\tlet p;\n\tif (e > 0 && round > 0) {\n\t\tp = Math.pow(10, round);\n\t} else {\n\t\tp = 1;\n\t}\n\tlet r;\n\tif (p === 1) {\n\t\tr = roundingFunc(val);\n\t} else {\n\t\tr = roundingFunc(val * p) / p;\n\t}\n\n\tif (r === ceil && e < 8 && autoExponent) {\n\t\tr = 1;\n\t\te++;\n\t}\n\n\treturn { value: r, e };\n}\n\n/**\n * Resolves the unit symbol for the given standard, bits mode, and exponent\n * Handles SI standard special case where exponent 1 always uses \"kB\" or \"kbit\"\n * @param {string} actualStandard - The resolved standard (iec, jedec)\n * @param {boolean} bits - Whether formatting bit values\n * @param {number} e - Current exponent index\n * @param {boolean} isDecimal - Whether using decimal (SI) base\n * @returns {string} The resolved unit symbol string\n */\nexport function resolveSymbol(actualStandard, bits, e, isDecimal) {\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tlet result;\n\tif (isDecimal && e === 1) {\n\t\tif (bits) {\n\t\t\tresult = SI_KBIT;\n\t\t} else {\n\t\t\tresult = SI_KBYTE;\n\t\t}\n\t} else {\n\t\tresult = symbolTable[e];\n\t}\n\treturn result;\n}\n\n/**\n * Decorates the result: applies negation, custom symbols, number formatting, and full form names\n * Mutates the result array in-place for both value (index 0) and symbol (index 1)\n * @param {Array} result - Result array with numeric value at [0] and string symbol at [1]\n * @param {boolean} neg - Whether the original input was negative\n * @param {Object} symbols - Custom symbol override map\n * @param {string|boolean} locale - Locale string for formatting\n * @param {Object} localeOptions - Additional locale formatting options\n * @param {string} separator - Custom decimal separator\n * @param {boolean} pad - Whether zero-pad decimals\n * @param {number} round - Target decimal count for padding\n * @param {boolean} full - Whether to use full unit names\n * @param {Array} fullforms - Custom full unit name overrides\n * @param {string} actualStandard - Unit standard for full form lookup\n * @param {number} e - Current exponent index\n * @param {boolean} bits - Whether formatting bit values\n * @returns {void} Mutates result array in place\n */\nexport function decorateResult(\n\tresult,\n\tneg,\n\tsymbols,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\tfull,\n\tfullforms,\n\tactualStandard,\n\te,\n\tbits,\n\troundingFunc,\n) {\n\tif (neg) {\n\t\t// `precision` leaves the value as a string from toPrecision (e.g. \"1.50\").\n\t\t// Negating that arithmetically coerces it back to a number and drops the\n\t\t// trailing zeros the option asked for, so prefix the sign instead.\n\t\tif (typeof result[0] === \"string\") {\n\t\t\tresult[0] = `-${result[0]}`;\n\t\t} else if (result[0] === 0) {\n\t\t\t// A negative value that rounds to zero (e.g. -0.4) becomes -0, which\n\t\t\t// stringifies to \"0\" and drops the sign. Emit the string \"-0\" so the\n\t\t\t// sign is preserved consistently with the precision path.\n\t\t\tresult[0] = \"-0\";\n\t\t} else {\n\t\t\tresult[0] = -result[0];\n\t\t}\n\t}\n\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Capture the numeric value before formatting; a comma decimal separator\n\t// (via separator or a locale such as de-DE) would otherwise make parseFloat\n\t// read \"1,5\" as 1 and select the singular unit name.\n\tlet numericValue;\n\tif (typeof result[0] === \"string\") {\n\t\tnumericValue = parseFloat(result[0]);\n\t} else {\n\t\tnumericValue = result[0];\n\t}\n\n\tresult[0] = applyNumberFormatting(\n\t\tresult[0],\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\troundingFunc,\n\t);\n\n\tif (full) {\n\t\tlet unit;\n\t\tif (bits) {\n\t\t\tunit = BIT;\n\t\t} else {\n\t\t\tunit = BYTE;\n\t\t}\n\t\t// Determine singular/plural suffix. Use Math.abs so a negative value\n\t\t// of exactly 1 (e.g. -1) selects the singular unit name.\n\t\tlet suffix;\n\t\tif (Math.abs(numericValue) === 1) {\n\t\t\tsuffix = EMPTY;\n\t\t} else {\n\t\t\tsuffix = S;\n\t\t}\n\t\t// Determine symbol — custom fullforms are the complete name, defaults get unit+suffix\n\t\tif (fullforms[e]) {\n\t\t\tresult[1] = fullforms[e];\n\t\t} else {\n\t\t\tresult[1] = STRINGS.fullform[actualStandard][e] + unit + suffix;\n\t\t}\n\t}\n}\n\n/**\n * Formats the computed result array into the requested output type\n * @param {Array} result - Result array with formatted value at [0] and symbol at [1]\n * @param {number} e - Current exponent\n * @param {string} u - Original resolved symbol (before custom override)\n * @param {string} output - Output type (ARRAY, OBJECT, STRING)\n * @param {string} spacer - String separator between value and unit\n * @returns {string|Array|Object|number} Formatted result in requested type\n */\nexport function formatOutput(result, e, u, output, spacer) {\n\t// Validate the output option. Any value other than the supported set\n\t// (array, object, string, exponent) would silently fall through to the\n\t// string branch below and produce misleading output.\n\tif (output !== ARRAY && output !== OBJECT && output !== STRING && output !== EXPONENT) {\n\t\tthrow new TypeError(`Invalid output: ${output}`);\n\t}\n\n\tif (output === ARRAY) {\n\t\treturn result;\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn {\n\t\t\tvalue: result[0],\n\t\t\tsymbol: result[1],\n\t\t\texponent: e,\n\t\t\tunit: u,\n\t\t};\n\t}\n\n\tlet formatted;\n\tif (spacer === SPACE) {\n\t\tformatted = `${result[0]} ${result[1]}`;\n\t} else {\n\t\tformatted = result.join(spacer);\n\t}\n\treturn formatted;\n}\n","import {\n\tEMPTY,\n\tEXPONENT,\n\tFUNCTION,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tROUND,\n\tSPACE,\n\tSTRING,\n} from \"./constants.js\";\nimport {\n\tapplyPrecisionHandling,\n\tapplyRounding,\n\tcalculateExponent,\n\tcalculateOptimizedValue,\n\tdecorateResult,\n\tformatOutput,\n\tgetBaseConfiguration,\n\thandleZeroValue,\n\tresolveSymbol,\n} from \"./helpers.js\";\n\n/**\n * Converts a file size in bytes to a human-readable string with appropriate units\n * @param {number|string|bigint} arg - The file size in bytes to convert\n * @param {Object} [options={}] - Configuration options for formatting\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {string|Array|Object|number} Formatted file size based on output option\n * @throws {TypeError} When arg is not a valid number, roundingMethod is invalid,\n * precision is out of range (1-100), or output is not a supported format\n * @example\n * filesize(1024) // \"1.02 kB\"\n * filesize(1024, {bits: true}) // \"8.19 kbit\"\n * filesize(1024, {output: \"object\"}) // {value: 1.02, symbol: \"kB\", exponent: 1, unit: \"kB\"}\n *\n * @remarks\n * **Input coercion:** `arg` is coerced via `Number()`. Numeric strings, hex\n * (`\"0x1F\"`), binary (`\"0b101\"`), and octal (`\"0o17\"`) literals are parsed;\n * `null`, `\"\"`, `\" \"`, `true`, `false`, and single-element arrays coerce to\n * their numeric value. `undefined`, `\"1_000\"`, and `\"1000n\"` throw `TypeError`.\n * A `bigint` that overflows `Number.MAX_SAFE_INTEGER` throws `TypeError`.\n *\n * **Option precedence:** When multiple options conflict, `standard` wins over\n * `base`; `fullform` wins over `symbols`; `locale` wins over `separator`;\n * and a missing `fullforms[e]` falls back to the default unit name.\n */\nexport function filesize(\n\targ,\n\t{\n\t\tbits = false,\n\t\tpad = false,\n\t\tbase = -1,\n\t\tround = 2,\n\t\tlocale = EMPTY,\n\t\tlocaleOptions = {},\n\t\tseparator = EMPTY,\n\t\tspacer = SPACE,\n\t\tsymbols = {},\n\t\tstandard = EMPTY,\n\t\toutput = STRING,\n\t\tfullform = false,\n\t\tfullforms = [],\n\t\texponent = -1,\n\t\troundingMethod = ROUND,\n\t\tprecision = 0,\n\t} = {},\n) {\n\tlet e = exponent,\n\t\tnum,\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\tnum = Number(arg);\n\n\tif (isNaN(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (!isFinite(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tconst { isDecimal, ceil, actualStandard } = getBaseConfiguration(standard, base);\n\n\tconst full = fullform === true,\n\t\tneg = num < 0,\n\t\troundingFunc = Math[roundingMethod];\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\tif (num === 0) {\n\t\treturn handleZeroValue(\n\t\t\tprecision,\n\t\t\tactualStandard,\n\t\t\tbits,\n\t\t\tsymbols,\n\t\t\tfull,\n\t\t\tfullforms,\n\t\t\toutput,\n\t\t\tspacer,\n\t\t\tpad,\n\t\t\tround,\n\t\t);\n\t}\n\n\t// Exponent calculation + clamp + precision adjustment\n\tconst { e: calculatedE, precision: precisionAdjusted } = calculateExponent(\n\t\tnum,\n\t\te,\n\t\texponent,\n\t\tisDecimal,\n\t\tprecision,\n\t);\n\te = calculatedE;\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\tconst { result: valueResult, e: valueExponent } = calculateOptimizedValue(\n\t\tnum,\n\t\te,\n\t\tisDecimal,\n\t\tbits,\n\t\tceil,\n\t\tautoExponent,\n\t);\n\tval = valueResult;\n\te = valueExponent;\n\n\t// Rounding + auto-increment ceiling\n\tconst rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent);\n\tresult[0] = rounded.value;\n\te = rounded.e;\n\n\t// Precision handling\n\tif (precisionAdjusted > 0) {\n\t\tconst precisionResult = applyPrecisionHandling(\n\t\t\tresult[0],\n\t\t\tprecisionAdjusted,\n\t\t\te,\n\t\t\tnum,\n\t\t\tisDecimal,\n\t\t\tbits,\n\t\t\tceil,\n\t\t\troundingFunc,\n\t\t\tround,\n\t\t\texponent,\n\t\t);\n\t\tresult[0] = precisionResult.value;\n\t\te = precisionResult.e;\n\t}\n\n\t// Return the exponent only after every adjustment that other output\n\t// modes apply (bits auto-increment, rounding overflow, precision), so\n\t// it always matches the exponent reported by object output.\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\tu = resolveSymbol(actualStandard, bits, e, isDecimal);\n\tresult[1] = u;\n\n\tdecorateResult(\n\t\tresult,\n\t\tneg,\n\t\tsymbols,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\tfull,\n\t\tfullforms,\n\t\tactualStandard,\n\t\te,\n\t\tbits,\n\t\troundingFunc,\n\t);\n\n\treturn formatOutput(result, e, u, output, spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Configuration options (same as filesize)\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {Function} A function that takes a file size and returns formatted output\n * @example\n * const formatBytes = partial({round: 1, standard: \"iec\"});\n * formatBytes(1024) // \"1 KiB\"\n * formatBytes(2048) // \"2 KiB\"\n * formatBytes(1536) // \"1.5 KiB\"\n */\nexport function partial({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0,\n\tlocaleOptions = {},\n\tsymbols = {},\n\tfullforms = [],\n} = {}) {\n\t/**\n\t * Safely clone an object using structuredClone with JSON fallback.\n\t * structuredClone can throw for functions, circular refs, etc.\n\t */\n\tfunction safeClone(value) {\n\t\ttry {\n\t\t\treturn typeof structuredClone === \"function\"\n\t\t\t\t? structuredClone(value)\n\t\t\t\t: JSON.parse(JSON.stringify(value));\n\t\t} catch {\n\t\t\treturn JSON.parse(JSON.stringify(value));\n\t\t}\n\t}\n\n\tconst cloned = {\n\t\tlocaleOptions: safeClone(localeOptions),\n\t\tsymbols: safeClone(symbols),\n\t\tfullforms: safeClone(fullforms),\n\t};\n\n\treturn (arg) =>\n\t\tfilesize(arg, {\n\t\t\tbits,\n\t\t\tpad,\n\t\t\tbase,\n\t\t\tround,\n\t\t\tlocale,\n\t\t\tlocaleOptions: cloned.localeOptions,\n\t\t\tseparator,\n\t\t\tspacer,\n\t\t\tsymbols: cloned.symbols,\n\t\t\tstandard,\n\t\t\toutput,\n\t\t\tfullform,\n\t\t\tfullforms: cloned.fullforms,\n\t\t\texponent,\n\t\t\troundingMethod,\n\t\t\tprecision,\n\t\t});\n}\n"],"names":["INVALID_NUMBER","INVALID_PRECISION","IEC","JEDEC","SI","BYTE","ARRAY","OBJECT","STRING","EXPONENT","ROUND","STRINGS","symbol","iec","bits","bytes","jedec","fullform","BINARY_POWERS","DECIMAL_POWERS","LOG_2_1024","Math","log","LOG_10_1000","STANDARD_CONFIGS","isDecimal","ceil","actualStandard","calculateOptimizedValue","num","e","autoExponent","d","result","filesize","arg","pad","base","round","locale","EMPTY","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","val","u","Number","isNaN","TypeError","isFinite","getBaseConfiguration","full","neg","roundingFunc","value","toPrecision","toFixed","unit","handleZeroValue","calculatedE","precisionAdjusted","floor","calculateExponent","valueResult","valueExponent","rounded","p","r","pow","applyRounding","precisionResult","parseFloat","includes","computed","applyPrecisionHandling","symbolTable","resolveSymbol","numericValue","localePad","minimumFractionDigits","maximumFractionDigits","undefined","toLocaleString","length","toString","replace","useGrouping","x","tmp","split","s","padEnd","applyNumberFormatting","suffix","abs","decorateResult","formatted","join","formatOutput","partial","safeClone","structuredClone","JSON","parse","stringify","cloned"],"mappings":";;;;AACO,MAAMA,EAAiB,iBAEjBC,EAAoB,oBAGpBC,EAAM,MACNC,EAAQ,QACRC,EAAK,KAKLC,EAAO,OAMPC,EAAQ,QAERC,EAAS,SACTC,EAAS,SAGTC,EAAW,WACXC,EAAQ,QAWRC,EAAU,CACtBC,OAAQ,CACPC,IAAK,CACJC,KAAM,CAAC,MAAO,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,SAC7EC,MAAO,CAAC,IAAK,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,QAE/DC,MAAO,CACNF,KAAM,CAAC,MAAO,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QACtEC,MAAO,CAAC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,QAGzDE,SAAU,CACTJ,IAAK,CAAC,GAAI,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QAClEG,MAAO,CAAC,GAAI,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,MAAO,QAAS,WAKzDE,EAAgB,CAC5B,EACA,KACA,QACA,WACA,cACA,gBACA,mBACA,oBACA,qBAGYC,EAAiB,CAC7B,EACA,IACA,IACA,IACA,KACA,KACA,KACA,KACA,MAIYC,EAAaC,KAAKC,IAAI,MACtBC,EAAcF,KAAKC,IAAI,KCpD9BE,EAAmB,CACxBpB,CAACA,GAAK,CAAEqB,WAAW,EAAMC,KAAM,IAAMC,eAAgBxB,GACrDD,CAACA,GAAM,CAAEuB,WAAW,EAAOC,KAAM,KAAMC,eAAgBzB,GACvDC,CAACA,GAAQ,CAAEsB,WAAW,EAAOC,KAAM,KAAMC,eAAgBxB,IAiHnD,SAASyB,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,EAAMK,GAAe,GACrF,IAAIC,EAEHA,EADGP,EACCN,EAAeW,GAEfZ,EAAcY,GAEnB,IAAIG,EAASJ,EAAMG,EAWnB,OATIlB,IACHmB,GAAU,EAENF,GAAgBE,GAAUP,GAAQI,EAAI,IACzCG,GAAUP,EACVI,MAIK,CAAEG,SAAQH,IAClB,CCvGO,SAASI,EACfC,GACArB,KACCA,GAAO,EAAKsB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKC,cACdA,EAAgB,CAAA,EAAEC,UAClBA,EAAYF,GAAKG,OACjBA,EFtCmB,IEsCLC,QACdA,EAAU,CAAA,EAAEC,SACZA,EAAWL,GAAKM,OAChBA,EAAStC,EAAMS,SACfA,GAAW,EAAK8B,UAChBA,EAAY,GAAEC,SACdA,GAAW,EAAEC,eACbA,EAAiBvC,EAAKwC,UACtBA,EAAY,GACT,CAAA,GAEJ,IACCrB,EADGC,EAAIkB,EAEPf,EAAS,GACTkB,EAAM,EACNC,EFxDmB,GE4DpB,GAFAvB,EAAMwB,OAAOlB,GAETmB,MAAMzB,GACT,MAAM,IAAI0B,UAAUvD,GAGrB,IAAKwD,SAAS3B,GACb,MAAM,IAAI0B,UAAUvD,GAGrB,MAAMyB,UAAEA,EAASC,KAAEA,EAAIC,eAAEA,GDzDnB,SAA8BkB,EAAUR,GAE9C,OAAIb,EAAiBqB,GACbrB,EAAiBqB,GAIZ,IAATR,EACI,CAAEZ,WAAW,EAAOC,KAAM,KAAMC,eAAgBzB,GAIjD,CAAEuB,WAAW,EAAMC,KAAM,IAAMC,eAAgBxB,EACvD,CC4C6CsD,CAAqBZ,EAAUR,GAErEqB,GAAoB,IAAbzC,EACZ0C,EAAM9B,EAAM,EACZ+B,EAAevC,KAAK4B,GAErB,GFpFuB,mBEoFZW,EACV,MAAM,IAAIL,UFvGiB,2BE8G5B,GAJII,IACH9B,GAAOA,GAGI,IAARA,EACH,OD1CK,SACNqB,EACAvB,EACAb,EACA8B,EACAc,EACAX,EACAD,EACAH,EACAP,EACAE,EACA1B,GAEA,IAAIiD,EASJ,OAPCA,EADGX,EAAY,GACP,GAAIY,YAAYZ,GACdd,GAAOE,EAAQ,GACjB,GAAIyB,QAAQzB,GAEZ,EAGLQ,IAAWrC,EACP,GAIHG,IACJA,EAASE,EACNH,EAAQC,OAAOe,GAAgBb,KAAK,GACpCH,EAAQC,OAAOe,GAAgBZ,MAAM,IAIrC6B,EAAQhC,KACXA,EAASgC,EAAQhC,IAId8C,IACCX,EAAU,GACbnC,EAASmC,EAAU,IAEnBnC,EAASD,EAAQM,SAASU,GAAgB,GAEzCf,GADGE,EDxGY,MC2GLT,IAMTyC,IAAWxC,EACP,CAACuD,EAAOjD,GAGZkC,IAAWvC,EACP,CAAEsD,QAAOjD,SAAQoC,SAAU,EAAGgB,KAAMpD,GAGrCiD,EAAQlB,EAAS/B,EACzB,CCpBSqD,CACNf,EACAvB,EACAb,EACA8B,EACAc,EACAX,EACAD,EACAH,EACAP,EACAE,GAKF,MAAQR,EAAGoC,EAAahB,UAAWiB,GDmL7B,SAA2BtC,EAAKC,EAAGkB,EAAUvB,EAAWyB,GA6B9D,MAzBiB,iBAANpB,IACVA,EAAIuB,OAAOvB,KAGF,IAANA,GAAYwB,MAAMxB,IAEpBA,EADGL,EACCJ,KAAK+C,MAAM/C,KAAKC,IAAIO,GAAON,GAE3BF,KAAK+C,MAAM/C,KAAKC,IAAIO,GAAOT,IAExB,IACPU,EAAI,GAMLA,EAJUA,EAAI,EAIV,EAKAT,KAAK+C,MAAMtC,GAGZA,EAAI,GACHoB,EAAY,IACfA,GAAa,EAAIpB,GAEX,CAAEA,EAAG,EAAGoB,cAGT,CAAEpB,IAAGoB,YACb,CCxN0DmB,CACxDxC,EACAC,EACAkB,EACAvB,EACAyB,GAEDpB,EAAIoC,EACJ,MAAMnC,OAAeiB,GAAmBM,MAAMN,IAEtCf,OAAQqC,EAAaxC,EAAGyC,GAAkB3C,EACjDC,EACAC,EACAL,EACAX,EACAY,EACAK,GAEDoB,EAAMmB,EACNxC,EAAIyC,EAGJ,MAAMC,ED8MA,SAAuBrB,EAAKzB,EAAMI,EAAGQ,EAAOsB,EAAc7B,GAChE,IAAI0C,EAMAC,EAYJ,OAhBCD,EADG3C,EAAI,GAAKQ,EAAQ,EAChBjB,KAAKsD,IAAI,GAAIrC,GAEb,EAIJoC,EADS,IAAND,EACCb,EAAaT,GAEbS,EAAaT,EAAMsB,GAAKA,EAGzBC,IAAMhD,GAAQI,EAAI,GAAKC,IAC1B2C,EAAI,EACJ5C,KAGM,CAAE+B,MAAOa,EAAG5C,IACpB,CClOiB8C,CAAczB,EAAKzB,EAAMI,EAAGQ,EAAOsB,EAAc7B,GAKjE,GAJAE,EAAO,GAAKuC,EAAQX,MACpB/B,EAAI0C,EAAQ1C,EAGRqC,EAAoB,EAAG,CAC1B,MAAMU,EDwBD,SACNhB,EACAX,EACApB,EACAD,EACAJ,EACAX,EACAY,EACAkC,EACAtB,EACAU,GASA,GAPqB,iBAAVa,IACVA,EAAQiB,WAAWjB,IAMK,iBAAdX,GAA0BI,MAAMJ,GAC1C,MAAM,IAAIK,UAAUtD,GAGrB,IADAiD,EAAY7B,KAAK+C,MAAMlB,IACP,GAAKA,EAAY,IAChC,MAAM,IAAIK,UAAUtD,GAGrB,IAAIgC,EAAS4B,EAAMC,YAAYZ,GAE/B,MAAMnB,OAAeiB,GAAmBM,MAAMN,GAG9C,GAAIf,EAAO8C,SDvLK,MCuLUjD,EAAI,GAAKC,EAAc,CAChDD,IACA,MAAQG,OAAQqC,GAAgB1C,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,GACjF,IAAI+C,EAMAO,EAJHP,EADGnC,EAAQ,EACPjB,KAAKsD,IAAI,GAAIrC,GAEb,EAIJ0C,EADS,IAANP,EACQb,EAAaU,GAEbV,EAAaU,EAAcG,GAAKA,EAE5CxC,EAAS+C,EAASlB,YAAYZ,EAC/B,CAEA,MAAO,CAAEW,MAAO5B,EAAQH,IACzB,CC3E0BmD,CACvBhD,EAAO,GACPkC,EACArC,EACAD,EACAJ,EACAX,EACAY,EACAkC,EACAtB,EACAU,GAEDf,EAAO,GAAK4C,EAAgBhB,MAC5B/B,EAAI+C,EAAgB/C,CACrB,CAKA,OAAIgB,IAAWrC,EACPqB,GAGRsB,EDgNM,SAAuBzB,EAAgBb,EAAMgB,EAAGL,GACtD,MAAMyD,EAAcvE,EAAQC,OAAOe,GAAgBb,EDxXhC,OAEC,SCuXpB,IAAImB,EAUJ,OAPEA,EAFER,GAAmB,IAANK,EACZhB,EDxXiB,OACC,KC6XboE,EAAYpD,GAEfG,CACR,CC7NKkD,CAAcxD,EAAgBb,EAAMgB,EAAGL,GAC3CQ,EAAO,GAAKmB,EDgPN,SACNnB,EACA0B,EACAf,EACAL,EACAE,EACAC,EACAN,EACAE,EACAoB,EACAX,EACApB,EACAG,EACAhB,EACA8C,GAyBA,IAAIwB,EAiBJ,GAxCIzB,IAIsB,iBAAd1B,EAAO,GACjBA,EAAO,GAAK,IAAIA,EAAO,KACC,IAAdA,EAAO,GAIjBA,EAAO,GAAK,KAEZA,EAAO,IAAMA,EAAO,IAIlBW,EAAQX,EAAO,MAClBA,EAAO,GAAKW,EAAQX,EAAO,KAQ3BmD,EADwB,iBAAdnD,EAAO,GACF6C,WAAW7C,EAAO,IAElBA,EAAO,GAGvBA,EAAO,GA/ND,SACN4B,EACAtB,EACAE,EACAC,EACAN,EACAE,EACAsB,GAEA,IAAI3B,EAAS4B,EAMb,MAAMwB,EACLjD,GAAOE,EAAQ,EAAI,CAAEgD,sBAAuBhD,EAAOiD,sBAAuBjD,QAAUkD,EAGrF,IAAe,IAAXjD,EACHN,EAASA,EAAOwD,oBAAeD,EAAWH,QACpC,GAAI9C,EAAOmD,OAAS,EAC1BzD,EAASA,EAAOwD,eAAelD,EAAQ,IAAKE,KAAkB4C,SACxD,GAAI3C,EAAUgD,OAAS,EAAG,CAGhC,GAAItD,GAAOE,EAAQ,EAAG,CACrB,MAAMmC,EAAIpD,KAAKsD,IAAI,GAAIrC,GACvBL,EAAS2B,EAAa3B,EAASwC,GAAKA,CACrC,CACAxC,EAASA,EAAO0D,WAAWC,QDlPP,ICkPuBlD,EAC5C,CAWA,GANsB,iBAAXT,GAAuBuB,SAASvB,IAAWA,EAAO0D,WAAWZ,SD1PxD,OC2Pf9C,EAASA,EAAOwD,eAAe,QAAS,CAAEI,aAAa,KAKpDzD,GAAOE,EAAQ,IAAgB,IAAXC,GAAqC,IAAlBA,EAAOmD,OAAc,CAC/D,MACMI,EAAIpD,GDhQU,ICiQdqD,EAFY9D,EAAO0D,WAEHK,MAAMF,GACtBG,EAAIF,EAAI,IDnQK,GCqQnB9D,EAAS,GAAG8D,EAAI,KAAKD,IAAIG,EAAEC,OAAO5D,EDjQhB,MCkQnB,CAEA,OAAOL,CACR,CA2KakE,CACXlE,EAAO,GACPM,EACAE,EACAC,EACAN,EACAE,EACAsB,GAGGF,EAAM,CACT,IAAIM,EAQAoC,EANHpC,EADGlD,EDnda,MCsdTT,EAMP+F,EAD8B,IAA3B/E,KAAKgF,IAAIjB,GDxcM,GAEJ,IC4cXrC,EAAUjB,GACbG,EAAO,GAAKc,EAAUjB,GAEtBG,EAAO,GAAKtB,EAAQM,SAASU,GAAgBG,GAAKkC,EAAOoC,CAE3D,CACD,CC5TCE,CACCrE,EACA0B,EACAf,EACAL,EACAE,EACAC,EACAN,EACAE,EACAoB,EACAX,EACApB,EACAG,EACAhB,EACA8C,GDyTK,SAAsB3B,EAAQH,EAAGsB,EAAGN,EAAQH,GAIlD,GAAIG,IAAWxC,GAASwC,IAAWvC,GAAUuC,IAAWtC,GAAUsC,IAAWrC,EAC5E,MAAM,IAAI8C,UAAU,mBAAmBT,KAGxC,GAAIA,IAAWxC,EACd,OAAO2B,EAGR,GAAIa,IAAWvC,EACd,MAAO,CACNsD,MAAO5B,EAAO,GACdrB,OAAQqB,EAAO,GACfe,SAAUlB,EACVkC,KAAMZ,GAIR,IAAImD,EAMJ,OAJCA,EDnfmB,MCkfhB5D,EACS,GAAGV,EAAO,MAAMA,EAAO,KAEvBA,EAAOuE,KAAK7D,GAElB4D,CACR,CClVQE,CAAaxE,EAAQH,EAAGsB,EAAGN,EAAQH,GAC3C,CA4BO,SAAS+D,GAAQ5F,KACvBA,GAAO,EAAKsB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKE,UACdA,EAAYF,GAAKG,OACjBA,EF1MoB,IE0MNE,SACdA,EAAWL,GAAKM,OAChBA,EAAStC,EAAMS,SACfA,GAAW,EAAK+B,SAChBA,GAAW,EAAEC,eACbA,EAAiBvC,EAAKwC,UACtBA,EAAY,EAACT,cACbA,EAAgB,CAAA,EAAEG,QAClBA,EAAU,CAAA,EAAEG,UACZA,EAAY,IACT,IAKH,SAAS4D,EAAU9C,GAClB,IACC,MAAkC,mBAApB+C,gBACXA,gBAAgB/C,GAChBgD,KAAKC,MAAMD,KAAKE,UAAUlD,GAC9B,CAAE,MACD,OAAOgD,KAAKC,MAAMD,KAAKE,UAAUlD,GAClC,CACD,CAEA,MAAMmD,EAAS,CACdvE,cAAekE,EAAUlE,GACzBG,QAAS+D,EAAU/D,GACnBG,UAAW4D,EAAU5D,IAGtB,OAAQZ,GACPD,EAASC,EAAK,CACbrB,OACAsB,MACAC,OACAC,QACAC,SACAE,cAAeuE,EAAOvE,cACtBC,YACAC,SACAC,QAASoE,EAAOpE,QAChBC,WACAC,SACA7B,WACA8B,UAAWiE,EAAOjE,UAClBC,WACAC,iBACAC,aAEH,QAAAhB,cAAAwE"} +{"version":3,"file":"filesize.min.js","sources":["../src/constants.js","../src/helpers.js","../src/filesize.js"],"sourcesContent":["// Error Messages\nexport const INVALID_NUMBER = \"Invalid number\";\nexport const INVALID_ROUND = \"Invalid rounding method\";\nexport const INVALID_PRECISION = \"Invalid precision\";\n\n// Standard Types\nexport const IEC = \"iec\";\nexport const JEDEC = \"jedec\";\nexport const SI = \"si\";\n\n// Unit Types\nexport const BIT = \"bit\";\nexport const BITS = \"bits\";\nexport const BYTE = \"byte\";\nexport const BYTES = \"bytes\";\nexport const SI_KBIT = \"kbit\";\nexport const SI_KBYTE = \"kB\";\n\n// Output Format Types\nexport const ARRAY = \"array\";\nexport const FUNCTION = \"function\";\nexport const OBJECT = \"object\";\nexport const STRING = \"string\";\n\n// Processing Constants\nexport const EXPONENT = \"exponent\";\nexport const ROUND = \"round\";\n\n// Special Characters and Values\nexport const E = \"e\";\nexport const EMPTY = \"\";\nexport const PERIOD = \".\";\nexport const S = \"s\";\nexport const SPACE = \" \";\nexport const ZERO = \"0\";\n\n// Data Structures\nexport const STRINGS = {\n\tsymbol: {\n\t\tiec: {\n\t\t\tbits: [\"bit\", \"Kibit\", \"Mibit\", \"Gibit\", \"Tibit\", \"Pibit\", \"Eibit\", \"Zibit\", \"Yibit\"],\n\t\t\tbytes: [\"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\", \"PiB\", \"EiB\", \"ZiB\", \"YiB\"],\n\t\t},\n\t\tjedec: {\n\t\t\tbits: [\"bit\", \"Kbit\", \"Mbit\", \"Gbit\", \"Tbit\", \"Pbit\", \"Ebit\", \"Zbit\", \"Ybit\"],\n\t\t\tbytes: [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"],\n\t\t},\n\t},\n\tfullform: {\n\t\tiec: [\"\", \"kibi\", \"mebi\", \"gibi\", \"tebi\", \"pebi\", \"exbi\", \"zebi\", \"yobi\"],\n\t\tjedec: [\"\", \"kilo\", \"mega\", \"giga\", \"tera\", \"peta\", \"exa\", \"zetta\", \"yotta\"],\n\t},\n};\n\n// Pre-computed lookup tables for performance optimization\nexport const BINARY_POWERS = [\n\t1, // 2^0\n\t1024, // 2^10\n\t1048576, // 2^20\n\t1073741824, // 2^30\n\t1099511627776, // 2^40\n\t1125899906842624, // 2^50\n\t1152921504606846976, // 2^60\n\t1180591620717411303424, // 2^70\n\t1208925819614629174706176, // 2^80\n];\n\nexport const DECIMAL_POWERS = [\n\t1, // 10^0\n\t1000, // 10^3\n\t1000000, // 10^6\n\t1000000000, // 10^9\n\t1000000000000, // 10^12\n\t1000000000000000, // 10^15\n\t1000000000000000000, // 10^18\n\t1000000000000000000000, // 10^21\n\t1000000000000000000000000, // 10^24\n];\n\n// Pre-computed log values for faster exponent calculation\nexport const LOG_2_1024 = Math.log(1024);\nexport const LOG_10_1000 = Math.log(1000);\n","import {\n\tARRAY,\n\tBINARY_POWERS,\n\tBIT,\n\tBITS,\n\tBYTE,\n\tBYTES,\n\tDECIMAL_POWERS,\n\tE,\n\tEMPTY,\n\tEXPONENT,\n\tIEC,\n\tINVALID_PRECISION,\n\tJEDEC,\n\tLOG_10_1000,\n\tLOG_2_1024,\n\tOBJECT,\n\tPERIOD,\n\tS,\n\tSI,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n\tZERO,\n} from \"./constants.js\";\n\n// Cached configuration lookup for better performance\nconst STANDARD_CONFIGS = {\n\t[SI]: { isDecimal: true, ceil: 1000, actualStandard: JEDEC },\n\t[IEC]: { isDecimal: false, ceil: 1024, actualStandard: IEC },\n\t[JEDEC]: { isDecimal: false, ceil: 1024, actualStandard: JEDEC },\n};\n\n/**\n * Optimized base configuration lookup\n * @param {string} standard - Standard type\n * @param {number} base - Base number\n * @returns {Object} Configuration object\n */\nexport function getBaseConfiguration(standard, base) {\n\t// Use cached lookup table for better performance\n\tif (STANDARD_CONFIGS[standard]) {\n\t\treturn STANDARD_CONFIGS[standard];\n\t}\n\n\t// Base override\n\tif (base === 2) {\n\t\treturn { isDecimal: false, ceil: 1024, actualStandard: IEC };\n\t}\n\n\t// Default\n\treturn { isDecimal: true, ceil: 1000, actualStandard: JEDEC };\n}\n\n/**\n * Optimized zero value handling\n * @param {number} precision - Precision value\n * @param {string} actualStandard - Standard to use\n * @param {boolean} bits - Whether to use bits\n * @param {Object} symbols - Custom symbols\n * @param {boolean} full - Whether to use full form\n * @param {Array} fullforms - Custom full forms\n * @param {string} output - Output format\n * @param {string} spacer - Spacer character\n * @param {boolean} pad - Whether to pad decimal places\n * @param {number} round - Number of decimal places for padding\n * @param {string} [symbol] - Symbol to use (defaults based on bits/standard)\n * @returns {string|Array|Object|number} Formatted result\n */\nexport function handleZeroValue(\n\tprecision,\n\tactualStandard,\n\tbits,\n\tsymbols,\n\tfull,\n\tfullforms,\n\toutput,\n\tspacer,\n\tpad,\n\tround,\n\tsymbol,\n) {\n\tlet value;\n\tif (precision > 0) {\n\t\tvalue = (0).toPrecision(precision);\n\t} else if (pad && round > 0) {\n\t\tvalue = (0).toFixed(round);\n\t} else {\n\t\tvalue = 0;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn 0;\n\t}\n\n\t// Set default symbol if not provided\n\tif (!symbol) {\n\t\tsymbol = bits\n\t\t\t? STRINGS.symbol[actualStandard].bits[0]\n\t\t\t: STRINGS.symbol[actualStandard].bytes[0];\n\t}\n\n\t// Apply symbol customization\n\tif (symbols[symbol]) {\n\t\tsymbol = symbols[symbol];\n\t}\n\n\t// Apply full form\n\tif (full) {\n\t\tif (fullforms[0]) {\n\t\t\tsymbol = fullforms[0];\n\t\t} else {\n\t\t\tsymbol = STRINGS.fullform[actualStandard][0];\n\t\t\tif (bits) {\n\t\t\t\tsymbol += BIT;\n\t\t\t} else {\n\t\t\t\tsymbol += BYTE;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return in requested format\n\tif (output === ARRAY) {\n\t\treturn [value, symbol];\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn { value, symbol, exponent: 0, unit: symbol };\n\t}\n\n\treturn value + spacer + symbol;\n}\n\n/**\n * Optimized value calculation with bits handling\n * @param {number} num - Input number\n * @param {number} e - Exponent\n * @param {boolean} isDecimal - Whether to use decimal powers\n * @param {boolean} bits - Whether to calculate bits\n * @param {number} ceil - Ceiling value for auto-increment\n * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)\n * @returns {Object} Object with result and e properties\n */\nexport function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = true) {\n\tlet d;\n\tif (isDecimal) {\n\t\td = DECIMAL_POWERS[e];\n\t} else {\n\t\td = BINARY_POWERS[e];\n\t}\n\tlet result = num / d;\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits (only when exponent is auto)\n\t\tif (autoExponent && result >= ceil && e < 8) {\n\t\t\tresult /= ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\treturn { result, e };\n}\n\n/**\n * Calculates the unit exponent for a bigint input using bigint comparisons\n * @param {bigint} num - Input file size in bytes\n * @param {number} e - Current exponent value\n * @param {number} exponent - Original user-provided exponent option (-1 for auto)\n * @param {boolean} isDecimal - Whether to use decimal (SI) base\n * @param {number} precision - Current precision value (modified when e > 8)\n * @returns {Object} Object with computed e value and possibly adjusted precision\n */\nexport function calculateBigIntExponent(num, e, exponent, isDecimal, precision) {\n\tif (typeof e === \"string\") {\n\t\te = Number(e);\n\t}\n\n\tif (e === -1 || isNaN(e)) {\n\t\te = 0;\n\t\tif (isDecimal) {\n\t\t\twhile (e < 8 && num >= 10n ** BigInt(3 * (e + 1))) {\n\t\t\t\te++;\n\t\t\t}\n\t\t} else {\n\t\t\twhile (e < 8 && num >= 1024n ** BigInt(e + 1)) {\n\t\t\t\te++;\n\t\t\t}\n\t\t}\n\t} else if (e < 0) {\n\t\te = 0;\n\t} else {\n\t\te = Math.floor(e);\n\t}\n\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\treturn { e: 8, precision };\n\t}\n\n\treturn { e, precision };\n}\n\n/**\n * Calculates the value for a bigint input using bigint arithmetic\n * @param {bigint} num - Input file size in bytes\n * @param {number} e - Current exponent\n * @param {boolean} isDecimal - Whether using decimal base\n * @param {boolean} bits - Whether to calculate bits\n * @param {number} ceil - Ceiling value for auto-increment\n * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)\n * @returns {Object} Object with result and e properties\n */\nexport function calculateBigIntValue(num, e, isDecimal, bits, ceil, autoExponent = true) {\n\tconst power = isDecimal ? 10n ** BigInt(3 * e) : 1024n ** BigInt(e);\n\t// Scaled division preserves precision above Number.MAX_SAFE_INTEGER.\n\t// Multiply by 10^16 before dividing, then scale back down, so the\n\t// quotient keeps ~16 significant digits instead of collapsing to a float.\n\tconst SHIFT = 10n ** 16n;\n\tlet result = Number((num * SHIFT) / power) / Number(SHIFT);\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits (only when exponent is auto)\n\t\tif (autoExponent && result >= ceil && e < 8) {\n\t\t\tresult /= ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\treturn { result, e };\n}\n\n/**\n * Optimized precision handling with scientific notation correction\n * @param {number} value - Current value\n * @param {number} precision - Precision to apply\n * @param {number} e - Current exponent\n * @param {number} num - Original number\n * @param {boolean} isDecimal - Whether using decimal base\n * @param {boolean} bits - Whether calculating bits\n * @param {number} ceil - Ceiling value\n * @param {Function} roundingFunc - Rounding function\n * @param {number} round - Round value\n * @param {number} exponent - Forced exponent (-1 for auto)\n * @returns {Object} Object with value and e properties\n */\nexport function applyPrecisionHandling(\n\tvalue,\n\tprecision,\n\te,\n\tnum,\n\tisDecimal,\n\tbits,\n\tceil,\n\troundingFunc,\n\tround,\n\texponent,\n) {\n\tif (typeof value === \"string\") {\n\t\tvalue = parseFloat(value);\n\t}\n\n\t// Validate precision range. toPrecision() throws a raw RangeError for\n\t// values outside 1-100; normalize to a clean TypeError and floor any\n\t// non-integer value (which toPrecision would otherwise truncate silently).\n\tif (typeof precision !== \"number\" || isNaN(precision)) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\tprecision = Math.floor(precision);\n\tif (precision < 1 || precision > 100) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\n\tlet result = value.toPrecision(precision);\n\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\t// Handle scientific notation by recalculating with incremented exponent\n\tif (result.includes(E) && e < 8 && autoExponent) {\n\t\te++;\n\t\tconst { result: valueResult } = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\t\tlet p;\n\t\tif (round > 0) {\n\t\t\tp = Math.pow(10, round);\n\t\t} else {\n\t\t\tp = 1;\n\t\t}\n\t\tlet computed;\n\t\tif (p === 1) {\n\t\t\tcomputed = roundingFunc(valueResult);\n\t\t} else {\n\t\t\tcomputed = roundingFunc(valueResult * p) / p;\n\t\t}\n\t\tresult = computed.toPrecision(precision);\n\t}\n\n\treturn { value: result, e };\n}\n\n/**\n * Optimized number formatting with locale, separator, and padding\n * @param {number|string} value - Value to format\n * @param {string|boolean} locale - Locale setting\n * @param {Object} localeOptions - Locale options\n * @param {string} separator - Custom separator\n * @param {boolean} pad - Whether to pad\n * @param {number} round - Round value\n * @returns {string|number} Formatted value\n */\nexport function applyNumberFormatting(\n\tvalue,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\troundingFunc,\n) {\n\tlet result = value;\n\n\t// When padding alongside a locale, let the locale formatter emit the fixed\n\t// number of fraction digits. The manual string padding below cannot tell a\n\t// locale-inserted grouping separator from the decimal separator, so it\n\t// dropped digits (e.g. \"1,234,500\" became \"1,234\").\n\tconst localePad =\n\t\tpad && round > 0 ? { minimumFractionDigits: round, maximumFractionDigits: round } : undefined;\n\n\t// Apply locale formatting\n\tif (locale === true) {\n\t\tresult = result.toLocaleString(undefined, localePad);\n\t} else if (locale.length > 0) {\n\t\tresult = result.toLocaleString(locale, { ...localeOptions, ...localePad });\n\t} else if (separator.length > 0) {\n\t\t// Round before separator replacement to ensure excess decimal places\n\t\t// are truncated when pad is also set (fixes padding + separator bug).\n\t\tif (pad && round > 0) {\n\t\t\tconst p = Math.pow(10, round);\n\t\t\tresult = roundingFunc(result * p) / p;\n\t\t}\n\t\tresult = result.toString().replace(PERIOD, separator);\n\t}\n\n\t// Expand scientific notation to full decimal so pathological values like\n\t// Number.MAX_VALUE don't leak \"e+284\" into the output. Only applies when\n\t// the value is a finite number whose string form uses exponent notation.\n\tif (typeof result === \"number\" && isFinite(result) && result.toString().includes(E)) {\n\t\tresult = result.toLocaleString(\"en-US\", { useGrouping: false });\n\t}\n\n\t// Apply padding for the non-locale paths, where the string has a single\n\t// decimal separator and no grouping is inserted.\n\tif (pad && round > 0 && locale !== true && locale.length === 0) {\n\t\tconst resultStr = result.toString();\n\t\tconst x = separator || PERIOD;\n\t\tconst tmp = resultStr.split(x);\n\t\tconst s = tmp[1] || EMPTY;\n\n\t\tresult = `${tmp[0]}${x}${s.padEnd(round, ZERO)}`;\n\t}\n\n\treturn result;\n}\n\n/**\n * Calculates exponent from the input value using pre-computed log values and clamps to supported range\n * Also adjusts precision when exponent exceeds the lookup table bounds\n * @param {number} num - Input file size in bytes\n * @param {number} e - Current exponent value\n * @param {number} exponent - Original user-provided exponent option (-1 for auto)\n * @param {boolean} isDecimal - Whether to use decimal (SI) base\n * @param {number} precision - Current precision value (modified when e > 8)\n * @returns {Object} Object with computed e value and possibly adjusted precision\n */\nexport function calculateExponent(num, e, exponent, isDecimal, precision) {\n\t// A string exponent (e.g. \"1\") must be coerced to a number before the\n\t// strict `e === 1` checks below; otherwise it indexes the symbol tables\n\t// with a string and misses the SI special case in resolveSymbol.\n\tif (typeof e === \"string\") {\n\t\te = Number(e);\n\t}\n\n\tif (e === -1 || isNaN(e)) {\n\t\tif (isDecimal) {\n\t\t\te = Math.floor(Math.log(num) / LOG_10_1000);\n\t\t} else {\n\t\t\te = Math.floor(Math.log(num) / LOG_2_1024);\n\t\t}\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t} else if (e < 0) {\n\t\t// A forced exponent below the auto sentinel (-1) has no meaning and\n\t\t// would otherwise index the power-of-ten/two lookup tables out of\n\t\t// bounds (producing NaN). Clamp to 0, mirroring the e > 8 clamp below.\n\t\te = 0;\n\t} else {\n\t\t// A non-integer positive exponent (e.g. 1.5) would index the\n\t\t// power-of-ten/two lookup tables out of bounds (producing NaN).\n\t\t// Floor it to the nearest valid integer, mirroring the clamps above.\n\t\te = Math.floor(e);\n\t}\n\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\treturn { e: 8, precision };\n\t}\n\n\treturn { e, precision };\n}\n\n/**\n * Applies rounding to the raw calculated value and handles auto-increment ceiling\n * @param {number} val - Raw value before rounding\n * @param {number} ceil - Ceiling threshold (1000 for SI, 1024 for IEC)\n * @param {number} e - Current exponent value\n * @param {number} round - Number of decimal places\n * @param {Function} roundingFunc - Rounding method (Math.round, Math.floor, Math.ceil)\n * @param {boolean} autoExponent - Whether exponent is auto-calculated (-1 or NaN)\n * @returns {Object} Object with rounded value and possibly incremented exponent\n */\nexport function applyRounding(val, ceil, e, round, roundingFunc, autoExponent) {\n\tlet p;\n\tif (e > 0 && round > 0) {\n\t\tp = Math.pow(10, round);\n\t} else {\n\t\tp = 1;\n\t}\n\tlet r;\n\tif (p === 1) {\n\t\tr = roundingFunc(val);\n\t} else {\n\t\tr = roundingFunc(val * p) / p;\n\t}\n\n\tif (r === ceil && e < 8 && autoExponent) {\n\t\tr = 1;\n\t\te++;\n\t}\n\n\treturn { value: r, e };\n}\n\n/**\n * Resolves the unit symbol for the given standard, bits mode, and exponent\n * Handles SI standard special case where exponent 1 always uses \"kB\" or \"kbit\"\n * @param {string} actualStandard - The resolved standard (iec, jedec)\n * @param {boolean} bits - Whether formatting bit values\n * @param {number} e - Current exponent index\n * @param {boolean} isDecimal - Whether using decimal (SI) base\n * @returns {string} The resolved unit symbol string\n */\nexport function resolveSymbol(actualStandard, bits, e, isDecimal) {\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tlet result;\n\tif (isDecimal && e === 1) {\n\t\tif (bits) {\n\t\t\tresult = SI_KBIT;\n\t\t} else {\n\t\t\tresult = SI_KBYTE;\n\t\t}\n\t} else {\n\t\tresult = symbolTable[e];\n\t}\n\treturn result;\n}\n\n/**\n * Decorates the result: applies negation, custom symbols, number formatting, and full form names\n * Mutates the result array in-place for both value (index 0) and symbol (index 1)\n * @param {Array} result - Result array with numeric value at [0] and string symbol at [1]\n * @param {boolean} neg - Whether the original input was negative\n * @param {Object} symbols - Custom symbol override map\n * @param {string|boolean} locale - Locale string for formatting\n * @param {Object} localeOptions - Additional locale formatting options\n * @param {string} separator - Custom decimal separator\n * @param {boolean} pad - Whether zero-pad decimals\n * @param {number} round - Target decimal count for padding\n * @param {boolean} full - Whether to use full unit names\n * @param {Array} fullforms - Custom full unit name overrides\n * @param {string} actualStandard - Unit standard for full form lookup\n * @param {number} e - Current exponent index\n * @param {boolean} bits - Whether formatting bit values\n * @returns {void} Mutates result array in place\n */\nexport function decorateResult(\n\tresult,\n\tneg,\n\tsymbols,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\tfull,\n\tfullforms,\n\tactualStandard,\n\te,\n\tbits,\n\troundingFunc,\n) {\n\tif (neg) {\n\t\t// `precision` leaves the value as a string from toPrecision (e.g. \"1.50\").\n\t\t// Negating that arithmetically coerces it back to a number and drops the\n\t\t// trailing zeros the option asked for, so prefix the sign instead.\n\t\tif (typeof result[0] === \"string\") {\n\t\t\tresult[0] = `-${result[0]}`;\n\t\t} else if (result[0] === 0) {\n\t\t\t// A negative value that rounds to zero (e.g. -0.4) becomes -0, which\n\t\t\t// stringifies to \"0\" and drops the sign. Emit the string \"-0\" so the\n\t\t\t// sign is preserved consistently with the precision path.\n\t\t\tresult[0] = \"-0\";\n\t\t} else {\n\t\t\tresult[0] = -result[0];\n\t\t}\n\t}\n\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Capture the numeric value before formatting; a comma decimal separator\n\t// (via separator or a locale such as de-DE) would otherwise make parseFloat\n\t// read \"1,5\" as 1 and select the singular unit name.\n\tlet numericValue;\n\tif (typeof result[0] === \"string\") {\n\t\tnumericValue = parseFloat(result[0]);\n\t} else {\n\t\tnumericValue = result[0];\n\t}\n\n\tresult[0] = applyNumberFormatting(\n\t\tresult[0],\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\troundingFunc,\n\t);\n\n\tif (full) {\n\t\tlet unit;\n\t\tif (bits) {\n\t\t\tunit = BIT;\n\t\t} else {\n\t\t\tunit = BYTE;\n\t\t}\n\t\t// Determine singular/plural suffix. Use Math.abs so a negative value\n\t\t// of exactly 1 (e.g. -1) selects the singular unit name.\n\t\tlet suffix;\n\t\tif (Math.abs(numericValue) === 1) {\n\t\t\tsuffix = EMPTY;\n\t\t} else {\n\t\t\tsuffix = S;\n\t\t}\n\t\t// Determine symbol — custom fullforms are the complete name, defaults get unit+suffix\n\t\tif (fullforms[e]) {\n\t\t\tresult[1] = fullforms[e];\n\t\t} else {\n\t\t\tresult[1] = STRINGS.fullform[actualStandard][e] + unit + suffix;\n\t\t}\n\t}\n}\n\n/**\n * Formats the computed result array into the requested output type\n * @param {Array} result - Result array with formatted value at [0] and symbol at [1]\n * @param {number} e - Current exponent\n * @param {string} u - Original resolved symbol (before custom override)\n * @param {string} output - Output type (ARRAY, OBJECT, STRING)\n * @param {string} spacer - String separator between value and unit\n * @returns {string|Array|Object|number} Formatted result in requested type\n */\nexport function formatOutput(result, e, u, output, spacer) {\n\t// Validate the output option. Any value other than the supported set\n\t// (array, object, string, exponent) would silently fall through to the\n\t// string branch below and produce misleading output.\n\tif (output !== ARRAY && output !== OBJECT && output !== STRING && output !== EXPONENT) {\n\t\tthrow new TypeError(`Invalid output: ${output}`);\n\t}\n\n\tif (output === ARRAY) {\n\t\treturn result;\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn {\n\t\t\tvalue: result[0],\n\t\t\tsymbol: result[1],\n\t\t\texponent: e,\n\t\t\tunit: u,\n\t\t};\n\t}\n\n\tlet formatted;\n\tif (spacer === SPACE) {\n\t\tformatted = `${result[0]} ${result[1]}`;\n\t} else {\n\t\tformatted = result.join(spacer);\n\t}\n\treturn formatted;\n}\n","import {\n\tEMPTY,\n\tEXPONENT,\n\tFUNCTION,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tROUND,\n\tSPACE,\n\tSTRING,\n} from \"./constants.js\";\nimport {\n\tapplyPrecisionHandling,\n\tapplyRounding,\n\tcalculateBigIntExponent,\n\tcalculateBigIntValue,\n\tcalculateExponent,\n\tcalculateOptimizedValue,\n\tdecorateResult,\n\tformatOutput,\n\tgetBaseConfiguration,\n\thandleZeroValue,\n\tresolveSymbol,\n} from \"./helpers.js\";\n\n/**\n * Converts a file size in bytes to a human-readable string with appropriate units\n * @param {number|string|bigint} arg - The file size in bytes to convert\n * @param {Object} [options={}] - Configuration options for formatting\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {string|Array|Object|number} Formatted file size based on output option\n * @throws {TypeError} When arg is not a valid number, roundingMethod is invalid,\n * precision is out of range (1-100), or output is not a supported format\n * @example\n * filesize(1024) // \"1.02 kB\"\n * filesize(1024, {bits: true}) // \"8.19 kbit\"\n * filesize(1024, {output: \"object\"}) // {value: 1.02, symbol: \"kB\", exponent: 1, unit: \"kB\"}\n *\n * @remarks\n * **Input coercion:** `arg` is coerced via `Number()`. Numeric strings, hex\n * (`\"0x1F\"`), binary (`\"0b101\"`), and octal (`\"0o17\"`) literals are parsed;\n * `null`, `\"\"`, `\" \"`, `true`, `false`, and single-element arrays coerce to\n * their numeric value. `undefined`, `\"1_000\"`, and `\"1000n\"` throw `TypeError`.\n * A `bigint` that overflows `Number.MAX_SAFE_INTEGER` throws `TypeError`.\n *\n * **Option precedence:** When multiple options conflict, `standard` wins over\n * `base`; `fullform` wins over `symbols`; `locale` wins over `separator`;\n * and a missing `fullforms[e]` falls back to the default unit name.\n */\nexport function filesize(\n\targ,\n\t{\n\t\tbits = false,\n\t\tpad = false,\n\t\tbase = -1,\n\t\tround = 2,\n\t\tlocale = EMPTY,\n\t\tlocaleOptions = {},\n\t\tseparator = EMPTY,\n\t\tspacer = SPACE,\n\t\tsymbols = {},\n\t\tstandard = EMPTY,\n\t\toutput = STRING,\n\t\tfullform = false,\n\t\tfullforms = [],\n\t\texponent = -1,\n\t\troundingMethod = ROUND,\n\t\tprecision = 0,\n\t} = {},\n) {\n\tlet e = exponent,\n\t\tnum,\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\tconst isBigInt = typeof arg === \"bigint\";\n\n\tnum = Number(arg);\n\n\tif (isNaN(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (!isFinite(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tconst { isDecimal, ceil, actualStandard } = getBaseConfiguration(standard, base);\n\n\tconst full = fullform === true,\n\t\tneg = num < 0,\n\t\troundingFunc = Math[roundingMethod];\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\tif (num === 0) {\n\t\treturn handleZeroValue(\n\t\t\tprecision,\n\t\t\tactualStandard,\n\t\t\tbits,\n\t\t\tsymbols,\n\t\t\tfull,\n\t\t\tfullforms,\n\t\t\toutput,\n\t\t\tspacer,\n\t\t\tpad,\n\t\t\tround,\n\t\t);\n\t}\n\n\t// BigInt inputs use bigint arithmetic to preserve precision above\n\t// Number.MAX_SAFE_INTEGER and detect unit boundaries accurately.\n\tconst bigNum = isBigInt ? (neg ? -BigInt(arg) : BigInt(arg)) : null;\n\n\t// Exponent calculation + clamp + precision adjustment\n\tlet precisionAdjusted = precision;\n\tif (isBigInt) {\n\t\tconst { e: calculatedE, precision: pa } = calculateBigIntExponent(\n\t\t\tbigNum,\n\t\t\te,\n\t\t\texponent,\n\t\t\tisDecimal,\n\t\t\tprecision,\n\t\t);\n\t\te = calculatedE;\n\t\tprecisionAdjusted = pa;\n\t} else {\n\t\tconst { e: calculatedE, precision: pa } = calculateExponent(\n\t\t\tnum,\n\t\t\te,\n\t\t\texponent,\n\t\t\tisDecimal,\n\t\t\tprecision,\n\t\t);\n\t\te = calculatedE;\n\t\tprecisionAdjusted = pa;\n\t}\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\tlet valueResult;\n\tif (isBigInt) {\n\t\tvalueResult = calculateBigIntValue(bigNum, e, isDecimal, bits, ceil, autoExponent);\n\t} else {\n\t\tvalueResult = calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent);\n\t}\n\tval = valueResult.result;\n\te = valueResult.e;\n\n\t// Rounding + auto-increment ceiling\n\tconst rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent);\n\tresult[0] = rounded.value;\n\te = rounded.e;\n\n\t// Precision handling\n\tif (precisionAdjusted > 0) {\n\t\tconst precisionResult = applyPrecisionHandling(\n\t\t\tresult[0],\n\t\t\tprecisionAdjusted,\n\t\t\te,\n\t\t\tnum,\n\t\t\tisDecimal,\n\t\t\tbits,\n\t\t\tceil,\n\t\t\troundingFunc,\n\t\t\tround,\n\t\t\texponent,\n\t\t);\n\t\tresult[0] = precisionResult.value;\n\t\te = precisionResult.e;\n\t}\n\n\t// Return the exponent only after every adjustment that other output\n\t// modes apply (bits auto-increment, rounding overflow, precision), so\n\t// it always matches the exponent reported by object output.\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\tu = resolveSymbol(actualStandard, bits, e, isDecimal);\n\tresult[1] = u;\n\n\tdecorateResult(\n\t\tresult,\n\t\tneg,\n\t\tsymbols,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\tfull,\n\t\tfullforms,\n\t\tactualStandard,\n\t\te,\n\t\tbits,\n\t\troundingFunc,\n\t);\n\n\treturn formatOutput(result, e, u, output, spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Configuration options (same as filesize)\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {Function} A function that takes a file size and returns formatted output\n * @example\n * const formatBytes = partial({round: 1, standard: \"iec\"});\n * formatBytes(1024) // \"1 KiB\"\n * formatBytes(2048) // \"2 KiB\"\n * formatBytes(1536) // \"1.5 KiB\"\n */\nexport function partial({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0,\n\tlocaleOptions = {},\n\tsymbols = {},\n\tfullforms = [],\n} = {}) {\n\t/**\n\t * Safely clone an object using structuredClone with JSON fallback.\n\t * structuredClone can throw for functions, circular refs, etc.\n\t */\n\tfunction safeClone(value) {\n\t\ttry {\n\t\t\treturn typeof structuredClone === \"function\"\n\t\t\t\t? structuredClone(value)\n\t\t\t\t: JSON.parse(JSON.stringify(value));\n\t\t} catch {\n\t\t\treturn JSON.parse(JSON.stringify(value));\n\t\t}\n\t}\n\n\tconst cloned = {\n\t\tlocaleOptions: safeClone(localeOptions),\n\t\tsymbols: safeClone(symbols),\n\t\tfullforms: safeClone(fullforms),\n\t};\n\n\treturn (arg) =>\n\t\tfilesize(arg, {\n\t\t\tbits,\n\t\t\tpad,\n\t\t\tbase,\n\t\t\tround,\n\t\t\tlocale,\n\t\t\tlocaleOptions: cloned.localeOptions,\n\t\t\tseparator,\n\t\t\tspacer,\n\t\t\tsymbols: cloned.symbols,\n\t\t\tstandard,\n\t\t\toutput,\n\t\t\tfullform,\n\t\t\tfullforms: cloned.fullforms,\n\t\t\texponent,\n\t\t\troundingMethod,\n\t\t\tprecision,\n\t\t});\n}\n"],"names":["INVALID_NUMBER","INVALID_PRECISION","IEC","JEDEC","SI","BYTE","ARRAY","OBJECT","STRING","EXPONENT","ROUND","STRINGS","symbol","iec","bits","bytes","jedec","fullform","BINARY_POWERS","DECIMAL_POWERS","LOG_2_1024","Math","log","LOG_10_1000","STANDARD_CONFIGS","isDecimal","ceil","actualStandard","calculateOptimizedValue","num","e","autoExponent","d","result","filesize","arg","pad","base","round","locale","EMPTY","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","val","u","isBigInt","Number","isNaN","TypeError","isFinite","getBaseConfiguration","full","neg","roundingFunc","value","toPrecision","toFixed","unit","handleZeroValue","bigNum","BigInt","precisionAdjusted","calculatedE","pa","floor","calculateBigIntExponent","calculateExponent","valueResult","power","SHIFT","calculateBigIntValue","rounded","p","r","pow","applyRounding","precisionResult","parseFloat","includes","computed","applyPrecisionHandling","symbolTable","resolveSymbol","numericValue","localePad","minimumFractionDigits","maximumFractionDigits","undefined","toLocaleString","length","toString","replace","useGrouping","x","tmp","split","s","padEnd","applyNumberFormatting","suffix","abs","decorateResult","formatted","join","formatOutput","partial","safeClone","structuredClone","JSON","parse","stringify","cloned"],"mappings":";;;;AACO,MAAMA,EAAiB,iBAEjBC,EAAoB,oBAGpBC,EAAM,MACNC,EAAQ,QACRC,EAAK,KAKLC,EAAO,OAMPC,EAAQ,QAERC,EAAS,SACTC,EAAS,SAGTC,EAAW,WACXC,EAAQ,QAWRC,EAAU,CACtBC,OAAQ,CACPC,IAAK,CACJC,KAAM,CAAC,MAAO,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,SAC7EC,MAAO,CAAC,IAAK,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,QAE/DC,MAAO,CACNF,KAAM,CAAC,MAAO,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QACtEC,MAAO,CAAC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,QAGzDE,SAAU,CACTJ,IAAK,CAAC,GAAI,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QAClEG,MAAO,CAAC,GAAI,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,MAAO,QAAS,WAKzDE,EAAgB,CAC5B,EACA,KACA,QACA,WACA,cACA,gBACA,mBACA,oBACA,qBAGYC,EAAiB,CAC7B,EACA,IACA,IACA,IACA,KACA,KACA,KACA,KACA,MAIYC,EAAaC,KAAKC,IAAI,MACtBC,EAAcF,KAAKC,IAAI,KCpD9BE,EAAmB,CACxBpB,CAACA,GAAK,CAAEqB,WAAW,EAAMC,KAAM,IAAMC,eAAgBxB,GACrDD,CAACA,GAAM,CAAEuB,WAAW,EAAOC,KAAM,KAAMC,eAAgBzB,GACvDC,CAACA,GAAQ,CAAEsB,WAAW,EAAOC,KAAM,KAAMC,eAAgBxB,IAiHnD,SAASyB,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,EAAMK,GAAe,GACrF,IAAIC,EAEHA,EADGP,EACCN,EAAeW,GAEfZ,EAAcY,GAEnB,IAAIG,EAASJ,EAAMG,EAWnB,OATIlB,IACHmB,GAAU,EAENF,GAAgBE,GAAUP,GAAQI,EAAI,IACzCG,GAAUP,EACVI,MAIK,CAAEG,SAAQH,IAClB,CCrGO,SAASI,EACfC,GACArB,KACCA,GAAO,EAAKsB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKC,cACdA,EAAgB,CAAA,EAAEC,UAClBA,EAAYF,GAAKG,OACjBA,EFxCmB,IEwCLC,QACdA,EAAU,CAAA,EAAEC,SACZA,EAAWL,GAAKM,OAChBA,EAAStC,EAAMS,SACfA,GAAW,EAAK8B,UAChBA,EAAY,GAAEC,SACdA,GAAW,EAAEC,eACbA,EAAiBvC,EAAKwC,UACtBA,EAAY,GACT,CAAA,GAEJ,IACCrB,EADGC,EAAIkB,EAEPf,EAAS,GACTkB,EAAM,EACNC,EF1DmB,GE4DpB,MAAMC,EAA0B,iBAARlB,EAIxB,GAFAN,EAAMyB,OAAOnB,GAEToB,MAAM1B,GACT,MAAM,IAAI2B,UAAUxD,GAGrB,IAAKyD,SAAS5B,GACb,MAAM,IAAI2B,UAAUxD,GAGrB,MAAMyB,UAAEA,EAASC,KAAEA,EAAIC,eAAEA,GD7DnB,SAA8BkB,EAAUR,GAE9C,OAAIb,EAAiBqB,GACbrB,EAAiBqB,GAIZ,IAATR,EACI,CAAEZ,WAAW,EAAOC,KAAM,KAAMC,eAAgBzB,GAIjD,CAAEuB,WAAW,EAAMC,KAAM,IAAMC,eAAgBxB,EACvD,CCgD6CuD,CAAqBb,EAAUR,GAErEsB,GAAoB,IAAb1C,EACZ2C,EAAM/B,EAAM,EACZgC,EAAexC,KAAK4B,GAErB,GFxFuB,mBEwFZY,EACV,MAAM,IAAIL,UF3GiB,2BEkH5B,GAJII,IACH/B,GAAOA,GAGI,IAARA,EACH,OD9CK,SACNqB,EACAvB,EACAb,EACA8B,EACAe,EACAZ,EACAD,EACAH,EACAP,EACAE,EACA1B,GAEA,IAAIkD,EASJ,OAPCA,EADGZ,EAAY,GACP,GAAIa,YAAYb,GACdd,GAAOE,EAAQ,GACjB,GAAI0B,QAAQ1B,GAEZ,EAGLQ,IAAWrC,EACP,GAIHG,IACJA,EAASE,EACNH,EAAQC,OAAOe,GAAgBb,KAAK,GACpCH,EAAQC,OAAOe,GAAgBZ,MAAM,IAIrC6B,EAAQhC,KACXA,EAASgC,EAAQhC,IAId+C,IACCZ,EAAU,GACbnC,EAASmC,EAAU,IAEnBnC,EAASD,EAAQM,SAASU,GAAgB,GAEzCf,GADGE,EDxGY,MC2GLT,IAMTyC,IAAWxC,EACP,CAACwD,EAAOlD,GAGZkC,IAAWvC,EACP,CAAEuD,QAAOlD,SAAQoC,SAAU,EAAGiB,KAAMrD,GAGrCkD,EAAQnB,EAAS/B,EACzB,CChBSsD,CACNhB,EACAvB,EACAb,EACA8B,EACAe,EACAZ,EACAD,EACAH,EACAP,EACAE,GAMF,MAAM6B,EAASd,EAAYO,GAAOQ,OAAOjC,GAAOiC,OAAOjC,GAAQ,KAG/D,IAAIkC,EAAoBnB,EACxB,GAAIG,EAAU,CACb,MAAQvB,EAAGwC,EAAapB,UAAWqB,GDqC9B,SAAiC1C,EAAKC,EAAGkB,EAAUvB,EAAWyB,GAKpE,GAJiB,iBAANpB,IACVA,EAAIwB,OAAOxB,KAGF,IAANA,GAAYyB,MAAMzB,GAErB,GADAA,EAAI,EACAL,EACH,KAAOK,EAAI,GAAKD,GAAO,KAAOuC,OAAO,GAAKtC,EAAI,KAC7CA,SAGD,KAAOA,EAAI,GAAKD,GAAO,OAASuC,OAAOtC,EAAI,IAC1CA,SAIFA,EADUA,EAAI,EACV,EAEAT,KAAKmD,MAAM1C,GAGhB,OAAIA,EAAI,GACHoB,EAAY,IACfA,GAAa,EAAIpB,GAEX,CAAEA,EAAG,EAAGoB,cAGT,CAAEpB,IAAGoB,YACb,CCnE4CuB,CACzCN,EACArC,EACAkB,EACAvB,EACAyB,GAEDpB,EAAIwC,EACJD,EAAoBE,CACrB,KAAO,CACN,MAAQzC,EAAGwC,EAAapB,UAAWqB,GDsO9B,SAA2B1C,EAAKC,EAAGkB,EAAUvB,EAAWyB,GA6B9D,MAzBiB,iBAANpB,IACVA,EAAIwB,OAAOxB,KAGF,IAANA,GAAYyB,MAAMzB,IAEpBA,EADGL,EACCJ,KAAKmD,MAAMnD,KAAKC,IAAIO,GAAON,GAE3BF,KAAKmD,MAAMnD,KAAKC,IAAIO,GAAOT,IAExB,IACPU,EAAI,GAMLA,EAJUA,EAAI,EAIV,EAKAT,KAAKmD,MAAM1C,GAGZA,EAAI,GACHoB,EAAY,IACfA,GAAa,EAAIpB,GAEX,CAAEA,EAAG,EAAGoB,cAGT,CAAEpB,IAAGoB,YACb,CC3Q4CwB,CACzC7C,EACAC,EACAkB,EACAvB,EACAyB,GAEDpB,EAAIwC,EACJD,EAAoBE,CACrB,CACA,MAAMxC,OAAeiB,GAAmBO,MAAMP,GAE9C,IAAI2B,EAEHA,EADGtB,EDwDE,SAA8BxB,EAAKC,EAAGL,EAAWX,EAAMY,EAAMK,GAAe,GAClF,MAAM6C,EAAQnD,EAAY,KAAO2C,OAAO,EAAItC,GAAK,OAASsC,OAAOtC,GAI3D+C,EAAQ,KAAO,IACrB,IAAI5C,EAASqB,OAAQzB,EAAMgD,EAASD,GAAStB,OAAOuB,GAWpD,OATI/D,IACHmB,GAAU,EAENF,GAAgBE,GAAUP,GAAQI,EAAI,IACzCG,GAAUP,EACVI,MAIK,CAAEG,SAAQH,IAClB,CCzEgBgD,CAAqBX,EAAQrC,EAAGL,EAAWX,EAAMY,EAAMK,GAEvDH,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,EAAMK,GAEtEoB,EAAMwB,EAAY1C,OAClBH,EAAI6C,EAAY7C,EAGhB,MAAMiD,EDiQA,SAAuB5B,EAAKzB,EAAMI,EAAGQ,EAAOuB,EAAc9B,GAChE,IAAIiD,EAMAC,EAYJ,OAhBCD,EADGlD,EAAI,GAAKQ,EAAQ,EAChBjB,KAAK6D,IAAI,GAAI5C,GAEb,EAIJ2C,EADS,IAAND,EACCnB,EAAaV,GAEbU,EAAaV,EAAM6B,GAAKA,EAGzBC,IAAMvD,GAAQI,EAAI,GAAKC,IAC1BkD,EAAI,EACJnD,KAGM,CAAEgC,MAAOmB,EAAGnD,IACpB,CCrRiBqD,CAAchC,EAAKzB,EAAMI,EAAGQ,EAAOuB,EAAc9B,GAKjE,GAJAE,EAAO,GAAK8C,EAAQjB,MACpBhC,EAAIiD,EAAQjD,EAGRuC,EAAoB,EAAG,CAC1B,MAAMe,ED2ED,SACNtB,EACAZ,EACApB,EACAD,EACAJ,EACAX,EACAY,EACAmC,EACAvB,EACAU,GASA,GAPqB,iBAAVc,IACVA,EAAQuB,WAAWvB,IAMK,iBAAdZ,GAA0BK,MAAML,GAC1C,MAAM,IAAIM,UAAUvD,GAGrB,IADAiD,EAAY7B,KAAKmD,MAAMtB,IACP,GAAKA,EAAY,IAChC,MAAM,IAAIM,UAAUvD,GAGrB,IAAIgC,EAAS6B,EAAMC,YAAYb,GAE/B,MAAMnB,OAAeiB,GAAmBO,MAAMP,GAG9C,GAAIf,EAAOqD,SD9PK,MC8PUxD,EAAI,GAAKC,EAAc,CAChDD,IACA,MAAQG,OAAQ0C,GAAgB/C,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,GACjF,IAAIsD,EAMAO,EAJHP,EADG1C,EAAQ,EACPjB,KAAK6D,IAAI,GAAI5C,GAEb,EAIJiD,EADS,IAANP,EACQnB,EAAac,GAEbd,EAAac,EAAcK,GAAKA,EAE5C/C,EAASsD,EAASxB,YAAYb,EAC/B,CAEA,MAAO,CAAEY,MAAO7B,EAAQH,IACzB,CC9H0B0D,CACvBvD,EAAO,GACPoC,EACAvC,EACAD,EACAJ,EACAX,EACAY,EACAmC,EACAvB,EACAU,GAEDf,EAAO,GAAKmD,EAAgBtB,MAC5BhC,EAAIsD,EAAgBtD,CACrB,CAKA,OAAIgB,IAAWrC,EACPqB,GAGRsB,EDmQM,SAAuBzB,EAAgBb,EAAMgB,EAAGL,GACtD,MAAMgE,EAAc9E,EAAQC,OAAOe,GAAgBb,ED/bhC,OAEC,SC8bpB,IAAImB,EAUJ,OAPEA,EAFER,GAAmB,IAANK,EACZhB,ED/biB,OACC,KCocb2E,EAAY3D,GAEfG,CACR,CChRKyD,CAAc/D,EAAgBb,EAAMgB,EAAGL,GAC3CQ,EAAO,GAAKmB,EDmSN,SACNnB,EACA2B,EACAhB,EACAL,EACAE,EACAC,EACAN,EACAE,EACAqB,EACAZ,EACApB,EACAG,EACAhB,EACA+C,GAyBA,IAAI8B,EAiBJ,GAxCI/B,IAIsB,iBAAd3B,EAAO,GACjBA,EAAO,GAAK,IAAIA,EAAO,KACC,IAAdA,EAAO,GAIjBA,EAAO,GAAK,KAEZA,EAAO,IAAMA,EAAO,IAIlBW,EAAQX,EAAO,MAClBA,EAAO,GAAKW,EAAQX,EAAO,KAQ3B0D,EADwB,iBAAd1D,EAAO,GACFoD,WAAWpD,EAAO,IAElBA,EAAO,GAGvBA,EAAO,GA/ND,SACN6B,EACAvB,EACAE,EACAC,EACAN,EACAE,EACAuB,GAEA,IAAI5B,EAAS6B,EAMb,MAAM8B,EACLxD,GAAOE,EAAQ,EAAI,CAAEuD,sBAAuBvD,EAAOwD,sBAAuBxD,QAAUyD,EAGrF,IAAe,IAAXxD,EACHN,EAASA,EAAO+D,oBAAeD,EAAWH,QACpC,GAAIrD,EAAO0D,OAAS,EAC1BhE,EAASA,EAAO+D,eAAezD,EAAQ,IAAKE,KAAkBmD,SACxD,GAAIlD,EAAUuD,OAAS,EAAG,CAGhC,GAAI7D,GAAOE,EAAQ,EAAG,CACrB,MAAM0C,EAAI3D,KAAK6D,IAAI,GAAI5C,GACvBL,EAAS4B,EAAa5B,EAAS+C,GAAKA,CACrC,CACA/C,EAASA,EAAOiE,WAAWC,QDzTP,ICyTuBzD,EAC5C,CAWA,GANsB,iBAAXT,GAAuBwB,SAASxB,IAAWA,EAAOiE,WAAWZ,SDjUxD,OCkUfrD,EAASA,EAAO+D,eAAe,QAAS,CAAEI,aAAa,KAKpDhE,GAAOE,EAAQ,IAAgB,IAAXC,GAAqC,IAAlBA,EAAO0D,OAAc,CAC/D,MACMI,EAAI3D,GDvUU,ICwUd4D,EAFYrE,EAAOiE,WAEHK,MAAMF,GACtBG,EAAIF,EAAI,ID1UK,GC4UnBrE,EAAS,GAAGqE,EAAI,KAAKD,IAAIG,EAAEC,OAAOnE,EDxUhB,MCyUnB,CAEA,OAAOL,CACR,CA2KayE,CACXzE,EAAO,GACPM,EACAE,EACAC,EACAN,EACAE,EACAuB,GAGGF,EAAM,CACT,IAAIM,EAQA0C,EANH1C,EADGnD,ED1hBa,MC6hBTT,EAMPsG,EAD8B,IAA3BtF,KAAKuF,IAAIjB,GD/gBM,GAEJ,ICmhBX5C,EAAUjB,GACbG,EAAO,GAAKc,EAAUjB,GAEtBG,EAAO,GAAKtB,EAAQM,SAASU,GAAgBG,GAAKmC,EAAO0C,CAE3D,CACD,CC/WCE,CACC5E,EACA2B,EACAhB,EACAL,EACAE,EACAC,EACAN,EACAE,EACAqB,EACAZ,EACApB,EACAG,EACAhB,EACA+C,GD4WK,SAAsB5B,EAAQH,EAAGsB,EAAGN,EAAQH,GAIlD,GAAIG,IAAWxC,GAASwC,IAAWvC,GAAUuC,IAAWtC,GAAUsC,IAAWrC,EAC5E,MAAM,IAAI+C,UAAU,mBAAmBV,KAGxC,GAAIA,IAAWxC,EACd,OAAO2B,EAGR,GAAIa,IAAWvC,EACd,MAAO,CACNuD,MAAO7B,EAAO,GACdrB,OAAQqB,EAAO,GACfe,SAAUlB,EACVmC,KAAMb,GAIR,IAAI0D,EAMJ,OAJCA,ED1jBmB,MCyjBhBnE,EACS,GAAGV,EAAO,MAAMA,EAAO,KAEvBA,EAAO8E,KAAKpE,GAElBmE,CACR,CCrYQE,CAAa/E,EAAQH,EAAGsB,EAAGN,EAAQH,GAC3C,CA4BO,SAASsE,GAAQnG,KACvBA,GAAO,EAAKsB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKE,UACdA,EAAYF,GAAKG,OACjBA,EF9NoB,IE8NNE,SACdA,EAAWL,GAAKM,OAChBA,EAAStC,EAAMS,SACfA,GAAW,EAAK+B,SAChBA,GAAW,EAAEC,eACbA,EAAiBvC,EAAKwC,UACtBA,EAAY,EAACT,cACbA,EAAgB,CAAA,EAAEG,QAClBA,EAAU,CAAA,EAAEG,UACZA,EAAY,IACT,IAKH,SAASmE,EAAUpD,GAClB,IACC,MAAkC,mBAApBqD,gBACXA,gBAAgBrD,GAChBsD,KAAKC,MAAMD,KAAKE,UAAUxD,GAC9B,CAAE,MACD,OAAOsD,KAAKC,MAAMD,KAAKE,UAAUxD,GAClC,CACD,CAEA,MAAMyD,EAAS,CACd9E,cAAeyE,EAAUzE,GACzBG,QAASsE,EAAUtE,GACnBG,UAAWmE,EAAUnE,IAGtB,OAAQZ,GACPD,EAASC,EAAK,CACbrB,OACAsB,MACAC,OACAC,QACAC,SACAE,cAAe8E,EAAO9E,cACtBC,YACAC,SACAC,QAAS2E,EAAO3E,QAChBC,WACAC,SACA7B,WACA8B,UAAWwE,EAAOxE,UAClBC,WACAC,iBACAC,aAEH,QAAAhB,cAAA+E"} diff --git a/dist/filesize.umd.js b/dist/filesize.umd.js index 70698b2..defb2b5 100644 --- a/dist/filesize.umd.js +++ b/dist/filesize.umd.js @@ -224,6 +224,77 @@ function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = t return { result, e }; } +/** + * Calculates the unit exponent for a bigint input using bigint comparisons + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent value + * @param {number} exponent - Original user-provided exponent option (-1 for auto) + * @param {boolean} isDecimal - Whether to use decimal (SI) base + * @param {number} precision - Current precision value (modified when e > 8) + * @returns {Object} Object with computed e value and possibly adjusted precision + */ +function calculateBigIntExponent(num, e, exponent, isDecimal, precision) { + if (typeof e === "string") { + e = Number(e); + } + + if (e === -1 || isNaN(e)) { + e = 0; + if (isDecimal) { + while (e < 8 && num >= 10n ** BigInt(3 * (e + 1))) { + e++; + } + } else { + while (e < 8 && num >= 1024n ** BigInt(e + 1)) { + e++; + } + } + } else if (e < 0) { + e = 0; + } else { + e = Math.floor(e); + } + + if (e > 8) { + if (precision > 0) { + precision += 8 - e; + } + return { e: 8, precision }; + } + + return { e, precision }; +} + +/** + * Calculates the value for a bigint input using bigint arithmetic + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN) + * @returns {Object} Object with result and e properties + */ +function calculateBigIntValue(num, e, isDecimal, bits, ceil, autoExponent = true) { + const power = isDecimal ? 10n ** BigInt(3 * e) : 1024n ** BigInt(e); + // Scaled division preserves precision above Number.MAX_SAFE_INTEGER. + // Multiply by 10^16 before dividing, then scale back down, so the + // quotient keeps ~16 significant digits instead of collapsing to a float. + const SHIFT = 10n ** 16n; + let result = Number((num * SHIFT) / power) / Number(SHIFT); + + if (bits) { + result *= 8; + // Handle auto-increment for bits (only when exponent is auto) + if (autoExponent && result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return { result, e }; +} + /** * Optimized precision handling with scientific notation correction * @param {number} value - Current value @@ -661,6 +732,8 @@ function filesize( val = 0, u = EMPTY; + const isBigInt = typeof arg === "bigint"; + num = Number(arg); if (isNaN(num)) { @@ -700,27 +773,43 @@ function filesize( ); } + // BigInt inputs use bigint arithmetic to preserve precision above + // Number.MAX_SAFE_INTEGER and detect unit boundaries accurately. + const bigNum = isBigInt ? (neg ? -BigInt(arg) : BigInt(arg)) : null; + // Exponent calculation + clamp + precision adjustment - const { e: calculatedE, precision: precisionAdjusted } = calculateExponent( - num, - e, - exponent, - isDecimal, - precision, - ); - e = calculatedE; + let precisionAdjusted = precision; + if (isBigInt) { + const { e: calculatedE, precision: pa } = calculateBigIntExponent( + bigNum, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } else { + const { e: calculatedE, precision: pa } = calculateExponent( + num, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } const autoExponent = exponent === -1 || isNaN(exponent); - const { result: valueResult, e: valueExponent } = calculateOptimizedValue( - num, - e, - isDecimal, - bits, - ceil, - autoExponent, - ); - val = valueResult; - e = valueExponent; + let valueResult; + if (isBigInt) { + valueResult = calculateBigIntValue(bigNum, e, isDecimal, bits, ceil, autoExponent); + } else { + valueResult = calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent); + } + val = valueResult.result; + e = valueResult.e; // Rounding + auto-increment ceiling const rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent); diff --git a/dist/filesize.umd.min.js b/dist/filesize.umd.min.js index 4906cd4..c295d7f 100644 --- a/dist/filesize.umd.min.js +++ b/dist/filesize.umd.min.js @@ -2,4 +2,4 @@ 2026 Jason Mulligan @version 11.0.24 */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).filesize={})}(this,function(t){"use strict";const e="Invalid number",i="Invalid precision",n="iec",o="jedec",r="si",a="byte",s="array",l="object",u="string",c="exponent",f="round",b={symbol:{iec:{bits:["bit","Kibit","Mibit","Gibit","Tibit","Pibit","Eibit","Zibit","Yibit"],bytes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},jedec:{bits:["bit","Kbit","Mbit","Gbit","Tbit","Pbit","Ebit","Zbit","Ybit"],bytes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]}},fullform:{iec:["","kibi","mebi","gibi","tebi","pebi","exbi","zebi","yobi"],jedec:["","kilo","mega","giga","tera","peta","exa","zetta","yotta"]}},p=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],d=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],m=Math.log(1024),y=Math.log(1e3),h={[r]:{isDecimal:!0,ceil:1e3,actualStandard:o},[n]:{isDecimal:!1,ceil:1024,actualStandard:n},[o]:{isDecimal:!1,ceil:1024,actualStandard:o}};function M(t,e,i,n,o,r=!0){let a;a=i?d[e]:p[e];let s=t/a;return n&&(s*=8,r&&s>=o&&e<8&&(s/=o,e++)),{result:s,e:e}}function B(t,{bits:r=!1,pad:p=!1,base:d=-1,round:B=2,locale:g="",localeOptions:N={},separator:x="",spacer:w=" ",symbols:T={},standard:S="",output:v=u,fullform:E=!1,fullforms:D=[],exponent:O=-1,roundingMethod:$=f,precision:F=0}={}){let j,G=O,k=[],I=0,J="";if(j=Number(t),isNaN(j))throw new TypeError(e);if(!isFinite(j))throw new TypeError(e);const{isDecimal:K,ceil:P,actualStandard:Y}=function(t,e){return h[t]?h[t]:2===e?{isDecimal:!1,ceil:1024,actualStandard:n}:{isDecimal:!0,ceil:1e3,actualStandard:o}}(S,d),Z=!0===E,z=j<0,C=Math[$];if("function"!=typeof C)throw new TypeError("Invalid rounding method");if(z&&(j=-j),0===j)return function(t,e,i,n,o,r,u,f,p,d,m){let y;return y=t>0?(0).toPrecision(t):p&&d>0?(0).toFixed(d):0,u===c?0:(m||(m=i?b.symbol[e].bits[0]:b.symbol[e].bytes[0]),n[m]&&(m=n[m]),o&&(r[0]?m=r[0]:(m=b.fullform[e][0],m+=i?"bit":a)),u===s?[y,m]:u===l?{value:y,symbol:m,exponent:0,unit:m}:y+f+m)}(F,Y,r,T,Z,D,v,w,p,B);const{e:U,precision:q}=function(t,e,i,n,o){return"string"==typeof e&&(e=Number(e)),-1===e||isNaN(e)?(e=n?Math.floor(Math.log(t)/y):Math.floor(Math.log(t)/m))<0&&(e=0):e=e<0?0:Math.floor(e),e>8?(o>0&&(o+=8-e),{e:8,precision:o}):{e:e,precision:o}}(j,G,0,K,F);G=U;const A=-1===O||isNaN(O),{result:H,e:L}=M(j,G,K,r,P,A);I=H,G=L;const Q=function(t,e,i,n,o,r){let a,s;return a=i>0&&n>0?Math.pow(10,n):1,s=1===a?o(t):o(t*a)/a,s===e&&i<8&&r&&(s=1,i++),{value:s,e:i}}(I,P,G,B,C,A);if(k[0]=Q.value,G=Q.e,q>0){const t=function(t,e,n,o,r,a,s,l,u,c){if("string"==typeof t&&(t=parseFloat(t)),"number"!=typeof e||isNaN(e))throw new TypeError(i);if((e=Math.floor(e))<1||e>100)throw new TypeError(i);let f=t.toPrecision(e);const b=-1===c||isNaN(c);if(f.includes("e")&&n<8&&b){n++;const{result:t}=M(o,n,r,a,s);let i,c;i=u>0?Math.pow(10,u):1,c=1===i?l(t):l(t*i)/i,f=c.toPrecision(e)}return{value:f,e:n}}(k[0],q,G,j,K,r,P,C,B,O);k[0]=t.value,G=t.e}return v===c?G:(J=function(t,e,i,n){const o=b.symbol[t][e?"bits":"bytes"];let r;return r=n&&1===i?e?"kbit":"kB":o[i],r}(Y,r,G,K),k[1]=J,function(t,e,i,n,o,r,s,l,u,c,f,p,d,m){let y;if(e&&("string"==typeof t[0]?t[0]=`-${t[0]}`:0===t[0]?t[0]="-0":t[0]=-t[0]),i[t[1]]&&(t[1]=i[t[1]]),y="string"==typeof t[0]?parseFloat(t[0]):t[0],t[0]=function(t,e,i,n,o,r,a){let s=t;const l=o&&r>0?{minimumFractionDigits:r,maximumFractionDigits:r}:void 0;if(!0===e)s=s.toLocaleString(void 0,l);else if(e.length>0)s=s.toLocaleString(e,{...i,...l});else if(n.length>0){if(o&&r>0){const t=Math.pow(10,r);s=a(s*t)/t}s=s.toString().replace(".",n)}if("number"==typeof s&&isFinite(s)&&s.toString().includes("e")&&(s=s.toLocaleString("en-US",{useGrouping:!1})),o&&r>0&&!0!==e&&0===e.length){const t=n||".",e=s.toString().split(t),i=e[1]||"";s=`${e[0]}${t}${i.padEnd(r,"0")}`}return s}(t[0],n,o,r,s,l,m),u){let e,i;e=d?"bit":a,i=1===Math.abs(y)?"":"s",c[p]?t[1]=c[p]:t[1]=b.fullform[f][p]+e+i}}(k,z,T,g,N,x,p,B,Z,D,Y,G,r,C),function(t,e,i,n,o){if(n!==s&&n!==l&&n!==u&&n!==c)throw new TypeError(`Invalid output: ${n}`);if(n===s)return t;if(n===l)return{value:t[0],symbol:t[1],exponent:e,unit:i};let r;return r=" "===o?`${t[0]} ${t[1]}`:t.join(o),r}(k,G,J,v,w))}t.filesize=B,t.partial=function({bits:t=!1,pad:e=!1,base:i=-1,round:n=2,locale:o="",separator:r="",spacer:a=" ",standard:s="",output:l=u,fullform:c=!1,exponent:b=-1,roundingMethod:p=f,precision:d=0,localeOptions:m={},symbols:y={},fullforms:h=[]}={}){function M(t){try{return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}catch{return JSON.parse(JSON.stringify(t))}}const g={localeOptions:M(m),symbols:M(y),fullforms:M(h)};return u=>B(u,{bits:t,pad:e,base:i,round:n,locale:o,localeOptions:g.localeOptions,separator:r,spacer:a,symbols:g.symbols,standard:s,output:l,fullform:c,fullforms:g.fullforms,exponent:b,roundingMethod:p,precision:d})}});//# sourceMappingURL=filesize.umd.min.js.map +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).filesize={})}(this,function(t){"use strict";const e="Invalid number",i="Invalid precision",n="iec",o="jedec",r="si",s="byte",a="array",l="object",u="string",c="exponent",f="round",p={symbol:{iec:{bits:["bit","Kibit","Mibit","Gibit","Tibit","Pibit","Eibit","Zibit","Yibit"],bytes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},jedec:{bits:["bit","Kbit","Mbit","Gbit","Tbit","Pbit","Ebit","Zbit","Ybit"],bytes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]}},fullform:{iec:["","kibi","mebi","gibi","tebi","pebi","exbi","zebi","yobi"],jedec:["","kilo","mega","giga","tera","peta","exa","zetta","yotta"]}},b=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],d=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],m=Math.log(1024),y=Math.log(1e3),h={[r]:{isDecimal:!0,ceil:1e3,actualStandard:o},[n]:{isDecimal:!1,ceil:1024,actualStandard:n},[o]:{isDecimal:!1,ceil:1024,actualStandard:o}};function g(t,e,i,n,o,r=!0){let s;s=i?d[e]:b[e];let a=t/s;return n&&(a*=8,r&&a>=o&&e<8&&(a/=o,e++)),{result:a,e:e}}function B(t,{bits:r=!1,pad:b=!1,base:d=-1,round:B=2,locale:M="",localeOptions:N={},separator:x="",spacer:w=" ",symbols:T={},standard:S="",output:v=u,fullform:E=!1,fullforms:I=[],exponent:D=-1,roundingMethod:O=f,precision:$=0}={}){let F,j=D,G=[],k=0,J="";const K="bigint"==typeof t;if(F=Number(t),isNaN(F))throw new TypeError(e);if(!isFinite(F))throw new TypeError(e);const{isDecimal:P,ceil:Y,actualStandard:Z}=function(t,e){return h[t]?h[t]:2===e?{isDecimal:!1,ceil:1024,actualStandard:n}:{isDecimal:!0,ceil:1e3,actualStandard:o}}(S,d),z=!0===E,C=F<0,U=Math[O];if("function"!=typeof U)throw new TypeError("Invalid rounding method");if(C&&(F=-F),0===F)return function(t,e,i,n,o,r,u,f,b,d,m){let y;return y=t>0?(0).toPrecision(t):b&&d>0?(0).toFixed(d):0,u===c?0:(m||(m=i?p.symbol[e].bits[0]:p.symbol[e].bytes[0]),n[m]&&(m=n[m]),o&&(r[0]?m=r[0]:(m=p.fullform[e][0],m+=i?"bit":s)),u===a?[y,m]:u===l?{value:y,symbol:m,exponent:0,unit:m}:y+f+m)}($,Z,r,T,z,I,v,w,b,B);const q=K?C?-BigInt(t):BigInt(t):null;let A=$;if(K){const{e:t,precision:e}=function(t,e,i,n,o){if("string"==typeof e&&(e=Number(e)),-1===e||isNaN(e))if(e=0,n)for(;e<8&&t>=10n**BigInt(3*(e+1));)e++;else for(;e<8&&t>=1024n**BigInt(e+1);)e++;else e=e<0?0:Math.floor(e);return e>8?(o>0&&(o+=8-e),{e:8,precision:o}):{e:e,precision:o}}(q,j,0,P,$);j=t,A=e}else{const{e:t,precision:e}=function(t,e,i,n,o){return"string"==typeof e&&(e=Number(e)),-1===e||isNaN(e)?(e=n?Math.floor(Math.log(t)/y):Math.floor(Math.log(t)/m))<0&&(e=0):e=e<0?0:Math.floor(e),e>8?(o>0&&(o+=8-e),{e:8,precision:o}):{e:e,precision:o}}(F,j,0,P,$);j=t,A=e}const H=-1===D||isNaN(D);let L;L=K?function(t,e,i,n,o,r=!0){const s=i?10n**BigInt(3*e):1024n**BigInt(e),a=10n**16n;let l=Number(t*a/s)/Number(a);return n&&(l*=8,r&&l>=o&&e<8&&(l/=o,e++)),{result:l,e:e}}(q,j,P,r,Y,H):g(F,j,P,r,Y,H),k=L.result,j=L.e;const Q=function(t,e,i,n,o,r){let s,a;return s=i>0&&n>0?Math.pow(10,n):1,a=1===s?o(t):o(t*s)/s,a===e&&i<8&&r&&(a=1,i++),{value:a,e:i}}(k,Y,j,B,U,H);if(G[0]=Q.value,j=Q.e,A>0){const t=function(t,e,n,o,r,s,a,l,u,c){if("string"==typeof t&&(t=parseFloat(t)),"number"!=typeof e||isNaN(e))throw new TypeError(i);if((e=Math.floor(e))<1||e>100)throw new TypeError(i);let f=t.toPrecision(e);const p=-1===c||isNaN(c);if(f.includes("e")&&n<8&&p){n++;const{result:t}=g(o,n,r,s,a);let i,c;i=u>0?Math.pow(10,u):1,c=1===i?l(t):l(t*i)/i,f=c.toPrecision(e)}return{value:f,e:n}}(G[0],A,j,F,P,r,Y,U,B,D);G[0]=t.value,j=t.e}return v===c?j:(J=function(t,e,i,n){const o=p.symbol[t][e?"bits":"bytes"];let r;return r=n&&1===i?e?"kbit":"kB":o[i],r}(Z,r,j,P),G[1]=J,function(t,e,i,n,o,r,a,l,u,c,f,b,d,m){let y;if(e&&("string"==typeof t[0]?t[0]=`-${t[0]}`:0===t[0]?t[0]="-0":t[0]=-t[0]),i[t[1]]&&(t[1]=i[t[1]]),y="string"==typeof t[0]?parseFloat(t[0]):t[0],t[0]=function(t,e,i,n,o,r,s){let a=t;const l=o&&r>0?{minimumFractionDigits:r,maximumFractionDigits:r}:void 0;if(!0===e)a=a.toLocaleString(void 0,l);else if(e.length>0)a=a.toLocaleString(e,{...i,...l});else if(n.length>0){if(o&&r>0){const t=Math.pow(10,r);a=s(a*t)/t}a=a.toString().replace(".",n)}if("number"==typeof a&&isFinite(a)&&a.toString().includes("e")&&(a=a.toLocaleString("en-US",{useGrouping:!1})),o&&r>0&&!0!==e&&0===e.length){const t=n||".",e=a.toString().split(t),i=e[1]||"";a=`${e[0]}${t}${i.padEnd(r,"0")}`}return a}(t[0],n,o,r,a,l,m),u){let e,i;e=d?"bit":s,i=1===Math.abs(y)?"":"s",c[b]?t[1]=c[b]:t[1]=p.fullform[f][b]+e+i}}(G,C,T,M,N,x,b,B,z,I,Z,j,r,U),function(t,e,i,n,o){if(n!==a&&n!==l&&n!==u&&n!==c)throw new TypeError(`Invalid output: ${n}`);if(n===a)return t;if(n===l)return{value:t[0],symbol:t[1],exponent:e,unit:i};let r;return r=" "===o?`${t[0]} ${t[1]}`:t.join(o),r}(G,j,J,v,w))}t.filesize=B,t.partial=function({bits:t=!1,pad:e=!1,base:i=-1,round:n=2,locale:o="",separator:r="",spacer:s=" ",standard:a="",output:l=u,fullform:c=!1,exponent:p=-1,roundingMethod:b=f,precision:d=0,localeOptions:m={},symbols:y={},fullforms:h=[]}={}){function g(t){try{return"function"==typeof structuredClone?structuredClone(t):JSON.parse(JSON.stringify(t))}catch{return JSON.parse(JSON.stringify(t))}}const M={localeOptions:g(m),symbols:g(y),fullforms:g(h)};return u=>B(u,{bits:t,pad:e,base:i,round:n,locale:o,localeOptions:M.localeOptions,separator:r,spacer:s,symbols:M.symbols,standard:a,output:l,fullform:c,fullforms:M.fullforms,exponent:p,roundingMethod:b,precision:d})}});//# sourceMappingURL=filesize.umd.min.js.map diff --git a/dist/filesize.umd.min.js.map b/dist/filesize.umd.min.js.map index 2ccd303..a2ef8f0 100644 --- a/dist/filesize.umd.min.js.map +++ b/dist/filesize.umd.min.js.map @@ -1 +1 @@ -{"version":3,"file":"filesize.umd.min.js","sources":["../src/constants.js","../src/helpers.js","../src/filesize.js"],"sourcesContent":["// Error Messages\nexport const INVALID_NUMBER = \"Invalid number\";\nexport const INVALID_ROUND = \"Invalid rounding method\";\nexport const INVALID_PRECISION = \"Invalid precision\";\n\n// Standard Types\nexport const IEC = \"iec\";\nexport const JEDEC = \"jedec\";\nexport const SI = \"si\";\n\n// Unit Types\nexport const BIT = \"bit\";\nexport const BITS = \"bits\";\nexport const BYTE = \"byte\";\nexport const BYTES = \"bytes\";\nexport const SI_KBIT = \"kbit\";\nexport const SI_KBYTE = \"kB\";\n\n// Output Format Types\nexport const ARRAY = \"array\";\nexport const FUNCTION = \"function\";\nexport const OBJECT = \"object\";\nexport const STRING = \"string\";\n\n// Processing Constants\nexport const EXPONENT = \"exponent\";\nexport const ROUND = \"round\";\n\n// Special Characters and Values\nexport const E = \"e\";\nexport const EMPTY = \"\";\nexport const PERIOD = \".\";\nexport const S = \"s\";\nexport const SPACE = \" \";\nexport const ZERO = \"0\";\n\n// Data Structures\nexport const STRINGS = {\n\tsymbol: {\n\t\tiec: {\n\t\t\tbits: [\"bit\", \"Kibit\", \"Mibit\", \"Gibit\", \"Tibit\", \"Pibit\", \"Eibit\", \"Zibit\", \"Yibit\"],\n\t\t\tbytes: [\"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\", \"PiB\", \"EiB\", \"ZiB\", \"YiB\"],\n\t\t},\n\t\tjedec: {\n\t\t\tbits: [\"bit\", \"Kbit\", \"Mbit\", \"Gbit\", \"Tbit\", \"Pbit\", \"Ebit\", \"Zbit\", \"Ybit\"],\n\t\t\tbytes: [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"],\n\t\t},\n\t},\n\tfullform: {\n\t\tiec: [\"\", \"kibi\", \"mebi\", \"gibi\", \"tebi\", \"pebi\", \"exbi\", \"zebi\", \"yobi\"],\n\t\tjedec: [\"\", \"kilo\", \"mega\", \"giga\", \"tera\", \"peta\", \"exa\", \"zetta\", \"yotta\"],\n\t},\n};\n\n// Pre-computed lookup tables for performance optimization\nexport const BINARY_POWERS = [\n\t1, // 2^0\n\t1024, // 2^10\n\t1048576, // 2^20\n\t1073741824, // 2^30\n\t1099511627776, // 2^40\n\t1125899906842624, // 2^50\n\t1152921504606846976, // 2^60\n\t1180591620717411303424, // 2^70\n\t1208925819614629174706176, // 2^80\n];\n\nexport const DECIMAL_POWERS = [\n\t1, // 10^0\n\t1000, // 10^3\n\t1000000, // 10^6\n\t1000000000, // 10^9\n\t1000000000000, // 10^12\n\t1000000000000000, // 10^15\n\t1000000000000000000, // 10^18\n\t1000000000000000000000, // 10^21\n\t1000000000000000000000000, // 10^24\n];\n\n// Pre-computed log values for faster exponent calculation\nexport const LOG_2_1024 = Math.log(1024);\nexport const LOG_10_1000 = Math.log(1000);\n","import {\n\tARRAY,\n\tBINARY_POWERS,\n\tBIT,\n\tBITS,\n\tBYTE,\n\tBYTES,\n\tDECIMAL_POWERS,\n\tE,\n\tEMPTY,\n\tEXPONENT,\n\tIEC,\n\tINVALID_PRECISION,\n\tJEDEC,\n\tLOG_10_1000,\n\tLOG_2_1024,\n\tOBJECT,\n\tPERIOD,\n\tS,\n\tSI,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n\tZERO,\n} from \"./constants.js\";\n\n// Cached configuration lookup for better performance\nconst STANDARD_CONFIGS = {\n\t[SI]: { isDecimal: true, ceil: 1000, actualStandard: JEDEC },\n\t[IEC]: { isDecimal: false, ceil: 1024, actualStandard: IEC },\n\t[JEDEC]: { isDecimal: false, ceil: 1024, actualStandard: JEDEC },\n};\n\n/**\n * Optimized base configuration lookup\n * @param {string} standard - Standard type\n * @param {number} base - Base number\n * @returns {Object} Configuration object\n */\nexport function getBaseConfiguration(standard, base) {\n\t// Use cached lookup table for better performance\n\tif (STANDARD_CONFIGS[standard]) {\n\t\treturn STANDARD_CONFIGS[standard];\n\t}\n\n\t// Base override\n\tif (base === 2) {\n\t\treturn { isDecimal: false, ceil: 1024, actualStandard: IEC };\n\t}\n\n\t// Default\n\treturn { isDecimal: true, ceil: 1000, actualStandard: JEDEC };\n}\n\n/**\n * Optimized zero value handling\n * @param {number} precision - Precision value\n * @param {string} actualStandard - Standard to use\n * @param {boolean} bits - Whether to use bits\n * @param {Object} symbols - Custom symbols\n * @param {boolean} full - Whether to use full form\n * @param {Array} fullforms - Custom full forms\n * @param {string} output - Output format\n * @param {string} spacer - Spacer character\n * @param {boolean} pad - Whether to pad decimal places\n * @param {number} round - Number of decimal places for padding\n * @param {string} [symbol] - Symbol to use (defaults based on bits/standard)\n * @returns {string|Array|Object|number} Formatted result\n */\nexport function handleZeroValue(\n\tprecision,\n\tactualStandard,\n\tbits,\n\tsymbols,\n\tfull,\n\tfullforms,\n\toutput,\n\tspacer,\n\tpad,\n\tround,\n\tsymbol,\n) {\n\tlet value;\n\tif (precision > 0) {\n\t\tvalue = (0).toPrecision(precision);\n\t} else if (pad && round > 0) {\n\t\tvalue = (0).toFixed(round);\n\t} else {\n\t\tvalue = 0;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn 0;\n\t}\n\n\t// Set default symbol if not provided\n\tif (!symbol) {\n\t\tsymbol = bits\n\t\t\t? STRINGS.symbol[actualStandard].bits[0]\n\t\t\t: STRINGS.symbol[actualStandard].bytes[0];\n\t}\n\n\t// Apply symbol customization\n\tif (symbols[symbol]) {\n\t\tsymbol = symbols[symbol];\n\t}\n\n\t// Apply full form\n\tif (full) {\n\t\tif (fullforms[0]) {\n\t\t\tsymbol = fullforms[0];\n\t\t} else {\n\t\t\tsymbol = STRINGS.fullform[actualStandard][0];\n\t\t\tif (bits) {\n\t\t\t\tsymbol += BIT;\n\t\t\t} else {\n\t\t\t\tsymbol += BYTE;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return in requested format\n\tif (output === ARRAY) {\n\t\treturn [value, symbol];\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn { value, symbol, exponent: 0, unit: symbol };\n\t}\n\n\treturn value + spacer + symbol;\n}\n\n/**\n * Optimized value calculation with bits handling\n * @param {number} num - Input number\n * @param {number} e - Exponent\n * @param {boolean} isDecimal - Whether to use decimal powers\n * @param {boolean} bits - Whether to calculate bits\n * @param {number} ceil - Ceiling value for auto-increment\n * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)\n * @returns {Object} Object with result and e properties\n */\nexport function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = true) {\n\tlet d;\n\tif (isDecimal) {\n\t\td = DECIMAL_POWERS[e];\n\t} else {\n\t\td = BINARY_POWERS[e];\n\t}\n\tlet result = num / d;\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits (only when exponent is auto)\n\t\tif (autoExponent && result >= ceil && e < 8) {\n\t\t\tresult /= ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\treturn { result, e };\n}\n\n/**\n * Optimized precision handling with scientific notation correction\n * @param {number} value - Current value\n * @param {number} precision - Precision to apply\n * @param {number} e - Current exponent\n * @param {number} num - Original number\n * @param {boolean} isDecimal - Whether using decimal base\n * @param {boolean} bits - Whether calculating bits\n * @param {number} ceil - Ceiling value\n * @param {Function} roundingFunc - Rounding function\n * @param {number} round - Round value\n * @param {number} exponent - Forced exponent (-1 for auto)\n * @returns {Object} Object with value and e properties\n */\nexport function applyPrecisionHandling(\n\tvalue,\n\tprecision,\n\te,\n\tnum,\n\tisDecimal,\n\tbits,\n\tceil,\n\troundingFunc,\n\tround,\n\texponent,\n) {\n\tif (typeof value === \"string\") {\n\t\tvalue = parseFloat(value);\n\t}\n\n\t// Validate precision range. toPrecision() throws a raw RangeError for\n\t// values outside 1-100; normalize to a clean TypeError and floor any\n\t// non-integer value (which toPrecision would otherwise truncate silently).\n\tif (typeof precision !== \"number\" || isNaN(precision)) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\tprecision = Math.floor(precision);\n\tif (precision < 1 || precision > 100) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\n\tlet result = value.toPrecision(precision);\n\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\t// Handle scientific notation by recalculating with incremented exponent\n\tif (result.includes(E) && e < 8 && autoExponent) {\n\t\te++;\n\t\tconst { result: valueResult } = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\t\tlet p;\n\t\tif (round > 0) {\n\t\t\tp = Math.pow(10, round);\n\t\t} else {\n\t\t\tp = 1;\n\t\t}\n\t\tlet computed;\n\t\tif (p === 1) {\n\t\t\tcomputed = roundingFunc(valueResult);\n\t\t} else {\n\t\t\tcomputed = roundingFunc(valueResult * p) / p;\n\t\t}\n\t\tresult = computed.toPrecision(precision);\n\t}\n\n\treturn { value: result, e };\n}\n\n/**\n * Optimized number formatting with locale, separator, and padding\n * @param {number|string} value - Value to format\n * @param {string|boolean} locale - Locale setting\n * @param {Object} localeOptions - Locale options\n * @param {string} separator - Custom separator\n * @param {boolean} pad - Whether to pad\n * @param {number} round - Round value\n * @returns {string|number} Formatted value\n */\nexport function applyNumberFormatting(\n\tvalue,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\troundingFunc,\n) {\n\tlet result = value;\n\n\t// When padding alongside a locale, let the locale formatter emit the fixed\n\t// number of fraction digits. The manual string padding below cannot tell a\n\t// locale-inserted grouping separator from the decimal separator, so it\n\t// dropped digits (e.g. \"1,234,500\" became \"1,234\").\n\tconst localePad =\n\t\tpad && round > 0 ? { minimumFractionDigits: round, maximumFractionDigits: round } : undefined;\n\n\t// Apply locale formatting\n\tif (locale === true) {\n\t\tresult = result.toLocaleString(undefined, localePad);\n\t} else if (locale.length > 0) {\n\t\tresult = result.toLocaleString(locale, { ...localeOptions, ...localePad });\n\t} else if (separator.length > 0) {\n\t\t// Round before separator replacement to ensure excess decimal places\n\t\t// are truncated when pad is also set (fixes padding + separator bug).\n\t\tif (pad && round > 0) {\n\t\t\tconst p = Math.pow(10, round);\n\t\t\tresult = roundingFunc(result * p) / p;\n\t\t}\n\t\tresult = result.toString().replace(PERIOD, separator);\n\t}\n\n\t// Expand scientific notation to full decimal so pathological values like\n\t// Number.MAX_VALUE don't leak \"e+284\" into the output. Only applies when\n\t// the value is a finite number whose string form uses exponent notation.\n\tif (typeof result === \"number\" && isFinite(result) && result.toString().includes(E)) {\n\t\tresult = result.toLocaleString(\"en-US\", { useGrouping: false });\n\t}\n\n\t// Apply padding for the non-locale paths, where the string has a single\n\t// decimal separator and no grouping is inserted.\n\tif (pad && round > 0 && locale !== true && locale.length === 0) {\n\t\tconst resultStr = result.toString();\n\t\tconst x = separator || PERIOD;\n\t\tconst tmp = resultStr.split(x);\n\t\tconst s = tmp[1] || EMPTY;\n\n\t\tresult = `${tmp[0]}${x}${s.padEnd(round, ZERO)}`;\n\t}\n\n\treturn result;\n}\n\n/**\n * Calculates exponent from the input value using pre-computed log values and clamps to supported range\n * Also adjusts precision when exponent exceeds the lookup table bounds\n * @param {number} num - Input file size in bytes\n * @param {number} e - Current exponent value\n * @param {number} exponent - Original user-provided exponent option (-1 for auto)\n * @param {boolean} isDecimal - Whether to use decimal (SI) base\n * @param {number} precision - Current precision value (modified when e > 8)\n * @returns {Object} Object with computed e value and possibly adjusted precision\n */\nexport function calculateExponent(num, e, exponent, isDecimal, precision) {\n\t// A string exponent (e.g. \"1\") must be coerced to a number before the\n\t// strict `e === 1` checks below; otherwise it indexes the symbol tables\n\t// with a string and misses the SI special case in resolveSymbol.\n\tif (typeof e === \"string\") {\n\t\te = Number(e);\n\t}\n\n\tif (e === -1 || isNaN(e)) {\n\t\tif (isDecimal) {\n\t\t\te = Math.floor(Math.log(num) / LOG_10_1000);\n\t\t} else {\n\t\t\te = Math.floor(Math.log(num) / LOG_2_1024);\n\t\t}\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t} else if (e < 0) {\n\t\t// A forced exponent below the auto sentinel (-1) has no meaning and\n\t\t// would otherwise index the power-of-ten/two lookup tables out of\n\t\t// bounds (producing NaN). Clamp to 0, mirroring the e > 8 clamp below.\n\t\te = 0;\n\t} else {\n\t\t// A non-integer positive exponent (e.g. 1.5) would index the\n\t\t// power-of-ten/two lookup tables out of bounds (producing NaN).\n\t\t// Floor it to the nearest valid integer, mirroring the clamps above.\n\t\te = Math.floor(e);\n\t}\n\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\treturn { e: 8, precision };\n\t}\n\n\treturn { e, precision };\n}\n\n/**\n * Applies rounding to the raw calculated value and handles auto-increment ceiling\n * @param {number} val - Raw value before rounding\n * @param {number} ceil - Ceiling threshold (1000 for SI, 1024 for IEC)\n * @param {number} e - Current exponent value\n * @param {number} round - Number of decimal places\n * @param {Function} roundingFunc - Rounding method (Math.round, Math.floor, Math.ceil)\n * @param {boolean} autoExponent - Whether exponent is auto-calculated (-1 or NaN)\n * @returns {Object} Object with rounded value and possibly incremented exponent\n */\nexport function applyRounding(val, ceil, e, round, roundingFunc, autoExponent) {\n\tlet p;\n\tif (e > 0 && round > 0) {\n\t\tp = Math.pow(10, round);\n\t} else {\n\t\tp = 1;\n\t}\n\tlet r;\n\tif (p === 1) {\n\t\tr = roundingFunc(val);\n\t} else {\n\t\tr = roundingFunc(val * p) / p;\n\t}\n\n\tif (r === ceil && e < 8 && autoExponent) {\n\t\tr = 1;\n\t\te++;\n\t}\n\n\treturn { value: r, e };\n}\n\n/**\n * Resolves the unit symbol for the given standard, bits mode, and exponent\n * Handles SI standard special case where exponent 1 always uses \"kB\" or \"kbit\"\n * @param {string} actualStandard - The resolved standard (iec, jedec)\n * @param {boolean} bits - Whether formatting bit values\n * @param {number} e - Current exponent index\n * @param {boolean} isDecimal - Whether using decimal (SI) base\n * @returns {string} The resolved unit symbol string\n */\nexport function resolveSymbol(actualStandard, bits, e, isDecimal) {\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tlet result;\n\tif (isDecimal && e === 1) {\n\t\tif (bits) {\n\t\t\tresult = SI_KBIT;\n\t\t} else {\n\t\t\tresult = SI_KBYTE;\n\t\t}\n\t} else {\n\t\tresult = symbolTable[e];\n\t}\n\treturn result;\n}\n\n/**\n * Decorates the result: applies negation, custom symbols, number formatting, and full form names\n * Mutates the result array in-place for both value (index 0) and symbol (index 1)\n * @param {Array} result - Result array with numeric value at [0] and string symbol at [1]\n * @param {boolean} neg - Whether the original input was negative\n * @param {Object} symbols - Custom symbol override map\n * @param {string|boolean} locale - Locale string for formatting\n * @param {Object} localeOptions - Additional locale formatting options\n * @param {string} separator - Custom decimal separator\n * @param {boolean} pad - Whether zero-pad decimals\n * @param {number} round - Target decimal count for padding\n * @param {boolean} full - Whether to use full unit names\n * @param {Array} fullforms - Custom full unit name overrides\n * @param {string} actualStandard - Unit standard for full form lookup\n * @param {number} e - Current exponent index\n * @param {boolean} bits - Whether formatting bit values\n * @returns {void} Mutates result array in place\n */\nexport function decorateResult(\n\tresult,\n\tneg,\n\tsymbols,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\tfull,\n\tfullforms,\n\tactualStandard,\n\te,\n\tbits,\n\troundingFunc,\n) {\n\tif (neg) {\n\t\t// `precision` leaves the value as a string from toPrecision (e.g. \"1.50\").\n\t\t// Negating that arithmetically coerces it back to a number and drops the\n\t\t// trailing zeros the option asked for, so prefix the sign instead.\n\t\tif (typeof result[0] === \"string\") {\n\t\t\tresult[0] = `-${result[0]}`;\n\t\t} else if (result[0] === 0) {\n\t\t\t// A negative value that rounds to zero (e.g. -0.4) becomes -0, which\n\t\t\t// stringifies to \"0\" and drops the sign. Emit the string \"-0\" so the\n\t\t\t// sign is preserved consistently with the precision path.\n\t\t\tresult[0] = \"-0\";\n\t\t} else {\n\t\t\tresult[0] = -result[0];\n\t\t}\n\t}\n\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Capture the numeric value before formatting; a comma decimal separator\n\t// (via separator or a locale such as de-DE) would otherwise make parseFloat\n\t// read \"1,5\" as 1 and select the singular unit name.\n\tlet numericValue;\n\tif (typeof result[0] === \"string\") {\n\t\tnumericValue = parseFloat(result[0]);\n\t} else {\n\t\tnumericValue = result[0];\n\t}\n\n\tresult[0] = applyNumberFormatting(\n\t\tresult[0],\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\troundingFunc,\n\t);\n\n\tif (full) {\n\t\tlet unit;\n\t\tif (bits) {\n\t\t\tunit = BIT;\n\t\t} else {\n\t\t\tunit = BYTE;\n\t\t}\n\t\t// Determine singular/plural suffix. Use Math.abs so a negative value\n\t\t// of exactly 1 (e.g. -1) selects the singular unit name.\n\t\tlet suffix;\n\t\tif (Math.abs(numericValue) === 1) {\n\t\t\tsuffix = EMPTY;\n\t\t} else {\n\t\t\tsuffix = S;\n\t\t}\n\t\t// Determine symbol — custom fullforms are the complete name, defaults get unit+suffix\n\t\tif (fullforms[e]) {\n\t\t\tresult[1] = fullforms[e];\n\t\t} else {\n\t\t\tresult[1] = STRINGS.fullform[actualStandard][e] + unit + suffix;\n\t\t}\n\t}\n}\n\n/**\n * Formats the computed result array into the requested output type\n * @param {Array} result - Result array with formatted value at [0] and symbol at [1]\n * @param {number} e - Current exponent\n * @param {string} u - Original resolved symbol (before custom override)\n * @param {string} output - Output type (ARRAY, OBJECT, STRING)\n * @param {string} spacer - String separator between value and unit\n * @returns {string|Array|Object|number} Formatted result in requested type\n */\nexport function formatOutput(result, e, u, output, spacer) {\n\t// Validate the output option. Any value other than the supported set\n\t// (array, object, string, exponent) would silently fall through to the\n\t// string branch below and produce misleading output.\n\tif (output !== ARRAY && output !== OBJECT && output !== STRING && output !== EXPONENT) {\n\t\tthrow new TypeError(`Invalid output: ${output}`);\n\t}\n\n\tif (output === ARRAY) {\n\t\treturn result;\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn {\n\t\t\tvalue: result[0],\n\t\t\tsymbol: result[1],\n\t\t\texponent: e,\n\t\t\tunit: u,\n\t\t};\n\t}\n\n\tlet formatted;\n\tif (spacer === SPACE) {\n\t\tformatted = `${result[0]} ${result[1]}`;\n\t} else {\n\t\tformatted = result.join(spacer);\n\t}\n\treturn formatted;\n}\n","import {\n\tEMPTY,\n\tEXPONENT,\n\tFUNCTION,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tROUND,\n\tSPACE,\n\tSTRING,\n} from \"./constants.js\";\nimport {\n\tapplyPrecisionHandling,\n\tapplyRounding,\n\tcalculateExponent,\n\tcalculateOptimizedValue,\n\tdecorateResult,\n\tformatOutput,\n\tgetBaseConfiguration,\n\thandleZeroValue,\n\tresolveSymbol,\n} from \"./helpers.js\";\n\n/**\n * Converts a file size in bytes to a human-readable string with appropriate units\n * @param {number|string|bigint} arg - The file size in bytes to convert\n * @param {Object} [options={}] - Configuration options for formatting\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {string|Array|Object|number} Formatted file size based on output option\n * @throws {TypeError} When arg is not a valid number, roundingMethod is invalid,\n * precision is out of range (1-100), or output is not a supported format\n * @example\n * filesize(1024) // \"1.02 kB\"\n * filesize(1024, {bits: true}) // \"8.19 kbit\"\n * filesize(1024, {output: \"object\"}) // {value: 1.02, symbol: \"kB\", exponent: 1, unit: \"kB\"}\n *\n * @remarks\n * **Input coercion:** `arg` is coerced via `Number()`. Numeric strings, hex\n * (`\"0x1F\"`), binary (`\"0b101\"`), and octal (`\"0o17\"`) literals are parsed;\n * `null`, `\"\"`, `\" \"`, `true`, `false`, and single-element arrays coerce to\n * their numeric value. `undefined`, `\"1_000\"`, and `\"1000n\"` throw `TypeError`.\n * A `bigint` that overflows `Number.MAX_SAFE_INTEGER` throws `TypeError`.\n *\n * **Option precedence:** When multiple options conflict, `standard` wins over\n * `base`; `fullform` wins over `symbols`; `locale` wins over `separator`;\n * and a missing `fullforms[e]` falls back to the default unit name.\n */\nexport function filesize(\n\targ,\n\t{\n\t\tbits = false,\n\t\tpad = false,\n\t\tbase = -1,\n\t\tround = 2,\n\t\tlocale = EMPTY,\n\t\tlocaleOptions = {},\n\t\tseparator = EMPTY,\n\t\tspacer = SPACE,\n\t\tsymbols = {},\n\t\tstandard = EMPTY,\n\t\toutput = STRING,\n\t\tfullform = false,\n\t\tfullforms = [],\n\t\texponent = -1,\n\t\troundingMethod = ROUND,\n\t\tprecision = 0,\n\t} = {},\n) {\n\tlet e = exponent,\n\t\tnum,\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\tnum = Number(arg);\n\n\tif (isNaN(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (!isFinite(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tconst { isDecimal, ceil, actualStandard } = getBaseConfiguration(standard, base);\n\n\tconst full = fullform === true,\n\t\tneg = num < 0,\n\t\troundingFunc = Math[roundingMethod];\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\tif (num === 0) {\n\t\treturn handleZeroValue(\n\t\t\tprecision,\n\t\t\tactualStandard,\n\t\t\tbits,\n\t\t\tsymbols,\n\t\t\tfull,\n\t\t\tfullforms,\n\t\t\toutput,\n\t\t\tspacer,\n\t\t\tpad,\n\t\t\tround,\n\t\t);\n\t}\n\n\t// Exponent calculation + clamp + precision adjustment\n\tconst { e: calculatedE, precision: precisionAdjusted } = calculateExponent(\n\t\tnum,\n\t\te,\n\t\texponent,\n\t\tisDecimal,\n\t\tprecision,\n\t);\n\te = calculatedE;\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\tconst { result: valueResult, e: valueExponent } = calculateOptimizedValue(\n\t\tnum,\n\t\te,\n\t\tisDecimal,\n\t\tbits,\n\t\tceil,\n\t\tautoExponent,\n\t);\n\tval = valueResult;\n\te = valueExponent;\n\n\t// Rounding + auto-increment ceiling\n\tconst rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent);\n\tresult[0] = rounded.value;\n\te = rounded.e;\n\n\t// Precision handling\n\tif (precisionAdjusted > 0) {\n\t\tconst precisionResult = applyPrecisionHandling(\n\t\t\tresult[0],\n\t\t\tprecisionAdjusted,\n\t\t\te,\n\t\t\tnum,\n\t\t\tisDecimal,\n\t\t\tbits,\n\t\t\tceil,\n\t\t\troundingFunc,\n\t\t\tround,\n\t\t\texponent,\n\t\t);\n\t\tresult[0] = precisionResult.value;\n\t\te = precisionResult.e;\n\t}\n\n\t// Return the exponent only after every adjustment that other output\n\t// modes apply (bits auto-increment, rounding overflow, precision), so\n\t// it always matches the exponent reported by object output.\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\tu = resolveSymbol(actualStandard, bits, e, isDecimal);\n\tresult[1] = u;\n\n\tdecorateResult(\n\t\tresult,\n\t\tneg,\n\t\tsymbols,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\tfull,\n\t\tfullforms,\n\t\tactualStandard,\n\t\te,\n\t\tbits,\n\t\troundingFunc,\n\t);\n\n\treturn formatOutput(result, e, u, output, spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Configuration options (same as filesize)\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {Function} A function that takes a file size and returns formatted output\n * @example\n * const formatBytes = partial({round: 1, standard: \"iec\"});\n * formatBytes(1024) // \"1 KiB\"\n * formatBytes(2048) // \"2 KiB\"\n * formatBytes(1536) // \"1.5 KiB\"\n */\nexport function partial({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0,\n\tlocaleOptions = {},\n\tsymbols = {},\n\tfullforms = [],\n} = {}) {\n\t/**\n\t * Safely clone an object using structuredClone with JSON fallback.\n\t * structuredClone can throw for functions, circular refs, etc.\n\t */\n\tfunction safeClone(value) {\n\t\ttry {\n\t\t\treturn typeof structuredClone === \"function\"\n\t\t\t\t? structuredClone(value)\n\t\t\t\t: JSON.parse(JSON.stringify(value));\n\t\t} catch {\n\t\t\treturn JSON.parse(JSON.stringify(value));\n\t\t}\n\t}\n\n\tconst cloned = {\n\t\tlocaleOptions: safeClone(localeOptions),\n\t\tsymbols: safeClone(symbols),\n\t\tfullforms: safeClone(fullforms),\n\t};\n\n\treturn (arg) =>\n\t\tfilesize(arg, {\n\t\t\tbits,\n\t\t\tpad,\n\t\t\tbase,\n\t\t\tround,\n\t\t\tlocale,\n\t\t\tlocaleOptions: cloned.localeOptions,\n\t\t\tseparator,\n\t\t\tspacer,\n\t\t\tsymbols: cloned.symbols,\n\t\t\tstandard,\n\t\t\toutput,\n\t\t\tfullform,\n\t\t\tfullforms: cloned.fullforms,\n\t\t\texponent,\n\t\t\troundingMethod,\n\t\t\tprecision,\n\t\t});\n}\n"],"names":["g","f","exports","module","define","amd","globalThis","self","filesize","this","INVALID_NUMBER","INVALID_PRECISION","IEC","JEDEC","SI","BYTE","ARRAY","OBJECT","STRING","EXPONENT","ROUND","STRINGS","symbol","iec","bits","bytes","jedec","fullform","BINARY_POWERS","DECIMAL_POWERS","LOG_2_1024","Math","log","LOG_10_1000","STANDARD_CONFIGS","isDecimal","ceil","actualStandard","calculateOptimizedValue","num","e","autoExponent","d","result","arg","pad","base","round","locale","EMPTY","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","val","u","Number","isNaN","TypeError","isFinite","getBaseConfiguration","full","neg","roundingFunc","value","toPrecision","toFixed","unit","handleZeroValue","calculatedE","precisionAdjusted","floor","calculateExponent","valueResult","valueExponent","rounded","p","r","pow","applyRounding","precisionResult","parseFloat","includes","computed","applyPrecisionHandling","symbolTable","resolveSymbol","numericValue","localePad","minimumFractionDigits","maximumFractionDigits","undefined","toLocaleString","length","toString","replace","useGrouping","x","tmp","split","s","padEnd","applyNumberFormatting","suffix","abs","decorateResult","formatted","join","formatOutput","partial","safeClone","structuredClone","JSON","parse","stringify","cloned"],"mappings":";;;;CAAA,SAAAA,EAAAC,GAAA,iBAAAC,SAAA,oBAAAC,OAAAF,EAAAC,SAAA,mBAAAE,QAAAA,OAAAC,IAAAD,OAAA,CAAA,WAAAH,GAAAA,GAAAD,EAAA,oBAAAM,WAAAA,WAAAN,GAAAO,MAAAC,SAAA,CAAA,EAAA,CAAA,CAAAC,KAAA,SAAAP,GAAA,aACO,MAAMQ,EAAiB,iBAEjBC,EAAoB,oBAGpBC,EAAM,MACNC,EAAQ,QACRC,EAAK,KAKLC,EAAO,OAMPC,EAAQ,QAERC,EAAS,SACTC,EAAS,SAGTC,EAAW,WACXC,EAAQ,QAWRC,EAAU,CACtBC,OAAQ,CACPC,IAAK,CACJC,KAAM,CAAC,MAAO,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,SAC7EC,MAAO,CAAC,IAAK,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,QAE/DC,MAAO,CACNF,KAAM,CAAC,MAAO,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QACtEC,MAAO,CAAC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,QAGzDE,SAAU,CACTJ,IAAK,CAAC,GAAI,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QAClEG,MAAO,CAAC,GAAI,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,MAAO,QAAS,WAKzDE,EAAgB,CAC5B,EACA,KACA,QACA,WACA,cACA,gBACA,mBACA,oBACA,qBAGYC,EAAiB,CAC7B,EACA,IACA,IACA,IACA,KACA,KACA,KACA,KACA,MAIYC,EAAaC,KAAKC,IAAI,MACtBC,EAAcF,KAAKC,IAAI,KCpD9BE,EAAmB,CACxBpB,CAACA,GAAK,CAAEqB,WAAW,EAAMC,KAAM,IAAMC,eAAgBxB,GACrDD,CAACA,GAAM,CAAEuB,WAAW,EAAOC,KAAM,KAAMC,eAAgBzB,GACvDC,CAACA,GAAQ,CAAEsB,WAAW,EAAOC,KAAM,KAAMC,eAAgBxB,IAiHnD,SAASyB,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,EAAMK,GAAe,GACrF,IAAIC,EAEHA,EADGP,EACCN,EAAeW,GAEfZ,EAAcY,GAEnB,IAAIG,EAASJ,EAAMG,EAWnB,OATIlB,IACHmB,GAAU,EAENF,GAAgBE,GAAUP,GAAQI,EAAI,IACzCG,GAAUP,EACVI,MAIK,CAAEG,SAAQH,IAClB,CCvGO,SAAShC,EACfoC,GACApB,KACCA,GAAO,EAAKqB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKC,cACdA,EAAgB,CAAA,EAAEC,UAClBA,EAAYF,GAAKG,OACjBA,EFtCmB,IEsCLC,QACdA,EAAU,CAAA,EAAEC,SACZA,EAAWL,GAAKM,OAChBA,EAASrC,EAAMS,SACfA,GAAW,EAAK6B,UAChBA,EAAY,GAAEC,SACdA,GAAW,EAAEC,eACbA,EAAiBtC,EAAKuC,UACtBA,EAAY,GACT,CAAA,GAEJ,IACCpB,EADGC,EAAIiB,EAEPd,EAAS,GACTiB,EAAM,EACNC,EFxDmB,GE4DpB,GAFAtB,EAAMuB,OAAOlB,GAETmB,MAAMxB,GACT,MAAM,IAAIyB,UAAUtD,GAGrB,IAAKuD,SAAS1B,GACb,MAAM,IAAIyB,UAAUtD,GAGrB,MAAMyB,UAAEA,EAASC,KAAEA,EAAIC,eAAEA,GDzDnB,SAA8BiB,EAAUR,GAE9C,OAAIZ,EAAiBoB,GACbpB,EAAiBoB,GAIZ,IAATR,EACI,CAAEX,WAAW,EAAOC,KAAM,KAAMC,eAAgBzB,GAIjD,CAAEuB,WAAW,EAAMC,KAAM,IAAMC,eAAgBxB,EACvD,CC4C6CqD,CAAqBZ,EAAUR,GAErEqB,GAAoB,IAAbxC,EACZyC,EAAM7B,EAAM,EACZ8B,EAAetC,KAAK2B,GAErB,GFpFuB,mBEoFZW,EACV,MAAM,IAAIL,UFvGiB,2BE8G5B,GAJII,IACH7B,GAAOA,GAGI,IAARA,EACH,OD1CK,SACNoB,EACAtB,EACAb,EACA6B,EACAc,EACAX,EACAD,EACAH,EACAP,EACAE,EACAzB,GAEA,IAAIgD,EASJ,OAPCA,EADGX,EAAY,GACP,GAAIY,YAAYZ,GACdd,GAAOE,EAAQ,GACjB,GAAIyB,QAAQzB,GAEZ,EAGLQ,IAAWpC,EACP,GAIHG,IACJA,EAASE,EACNH,EAAQC,OAAOe,GAAgBb,KAAK,GACpCH,EAAQC,OAAOe,GAAgBZ,MAAM,IAIrC4B,EAAQ/B,KACXA,EAAS+B,EAAQ/B,IAId6C,IACCX,EAAU,GACblC,EAASkC,EAAU,IAEnBlC,EAASD,EAAQM,SAASU,GAAgB,GAEzCf,GADGE,EDxGY,MC2GLT,IAMTwC,IAAWvC,EACP,CAACsD,EAAOhD,GAGZiC,IAAWtC,EACP,CAAEqD,QAAOhD,SAAQmC,SAAU,EAAGgB,KAAMnD,GAGrCgD,EAAQlB,EAAS9B,EACzB,CCpBSoD,CACNf,EACAtB,EACAb,EACA6B,EACAc,EACAX,EACAD,EACAH,EACAP,EACAE,GAKF,MAAQP,EAAGmC,EAAahB,UAAWiB,GDmL7B,SAA2BrC,EAAKC,EAAGiB,EAAUtB,EAAWwB,GA6B9D,MAzBiB,iBAANnB,IACVA,EAAIsB,OAAOtB,KAGF,IAANA,GAAYuB,MAAMvB,IAEpBA,EADGL,EACCJ,KAAK8C,MAAM9C,KAAKC,IAAIO,GAAON,GAE3BF,KAAK8C,MAAM9C,KAAKC,IAAIO,GAAOT,IAExB,IACPU,EAAI,GAMLA,EAJUA,EAAI,EAIV,EAKAT,KAAK8C,MAAMrC,GAGZA,EAAI,GACHmB,EAAY,IACfA,GAAa,EAAInB,GAEX,CAAEA,EAAG,EAAGmB,cAGT,CAAEnB,IAAGmB,YACb,CCxN0DmB,CACxDvC,EACAC,EACAiB,EACAtB,EACAwB,GAEDnB,EAAImC,EACJ,MAAMlC,OAAegB,GAAmBM,MAAMN,IAEtCd,OAAQoC,EAAavC,EAAGwC,GAAkB1C,EACjDC,EACAC,EACAL,EACAX,EACAY,EACAK,GAEDmB,EAAMmB,EACNvC,EAAIwC,EAGJ,MAAMC,ED8MA,SAAuBrB,EAAKxB,EAAMI,EAAGO,EAAOsB,EAAc5B,GAChE,IAAIyC,EAMAC,EAYJ,OAhBCD,EADG1C,EAAI,GAAKO,EAAQ,EAChBhB,KAAKqD,IAAI,GAAIrC,GAEb,EAIJoC,EADS,IAAND,EACCb,EAAaT,GAEbS,EAAaT,EAAMsB,GAAKA,EAGzBC,IAAM/C,GAAQI,EAAI,GAAKC,IAC1B0C,EAAI,EACJ3C,KAGM,CAAE8B,MAAOa,EAAG3C,IACpB,CClOiB6C,CAAczB,EAAKxB,EAAMI,EAAGO,EAAOsB,EAAc5B,GAKjE,GAJAE,EAAO,GAAKsC,EAAQX,MACpB9B,EAAIyC,EAAQzC,EAGRoC,EAAoB,EAAG,CAC1B,MAAMU,EDwBD,SACNhB,EACAX,EACAnB,EACAD,EACAJ,EACAX,EACAY,EACAiC,EACAtB,EACAU,GASA,GAPqB,iBAAVa,IACVA,EAAQiB,WAAWjB,IAMK,iBAAdX,GAA0BI,MAAMJ,GAC1C,MAAM,IAAIK,UAAUrD,GAGrB,IADAgD,EAAY5B,KAAK8C,MAAMlB,IACP,GAAKA,EAAY,IAChC,MAAM,IAAIK,UAAUrD,GAGrB,IAAIgC,EAAS2B,EAAMC,YAAYZ,GAE/B,MAAMlB,OAAegB,GAAmBM,MAAMN,GAG9C,GAAId,EAAO6C,SDvLK,MCuLUhD,EAAI,GAAKC,EAAc,CAChDD,IACA,MAAQG,OAAQoC,GAAgBzC,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,GACjF,IAAI8C,EAMAO,EAJHP,EADGnC,EAAQ,EACPhB,KAAKqD,IAAI,GAAIrC,GAEb,EAIJ0C,EADS,IAANP,EACQb,EAAaU,GAEbV,EAAaU,EAAcG,GAAKA,EAE5CvC,EAAS8C,EAASlB,YAAYZ,EAC/B,CAEA,MAAO,CAAEW,MAAO3B,EAAQH,IACzB,CC3E0BkD,CACvB/C,EAAO,GACPiC,EACApC,EACAD,EACAJ,EACAX,EACAY,EACAiC,EACAtB,EACAU,GAEDd,EAAO,GAAK2C,EAAgBhB,MAC5B9B,EAAI8C,EAAgB9C,CACrB,CAKA,OAAIe,IAAWpC,EACPqB,GAGRqB,EDgNM,SAAuBxB,EAAgBb,EAAMgB,EAAGL,GACtD,MAAMwD,EAActE,EAAQC,OAAOe,GAAgBb,EDxXhC,OAEC,SCuXpB,IAAImB,EAUJ,OAPEA,EAFER,GAAmB,IAANK,EACZhB,EDxXiB,OACC,KC6XbmE,EAAYnD,GAEfG,CACR,CC7NKiD,CAAcvD,EAAgBb,EAAMgB,EAAGL,GAC3CQ,EAAO,GAAKkB,EDgPN,SACNlB,EACAyB,EACAf,EACAL,EACAE,EACAC,EACAN,EACAE,EACAoB,EACAX,EACAnB,EACAG,EACAhB,EACA6C,GAyBA,IAAIwB,EAiBJ,GAxCIzB,IAIsB,iBAAdzB,EAAO,GACjBA,EAAO,GAAK,IAAIA,EAAO,KACC,IAAdA,EAAO,GAIjBA,EAAO,GAAK,KAEZA,EAAO,IAAMA,EAAO,IAIlBU,EAAQV,EAAO,MAClBA,EAAO,GAAKU,EAAQV,EAAO,KAQ3BkD,EADwB,iBAAdlD,EAAO,GACF4C,WAAW5C,EAAO,IAElBA,EAAO,GAGvBA,EAAO,GA/ND,SACN2B,EACAtB,EACAE,EACAC,EACAN,EACAE,EACAsB,GAEA,IAAI1B,EAAS2B,EAMb,MAAMwB,EACLjD,GAAOE,EAAQ,EAAI,CAAEgD,sBAAuBhD,EAAOiD,sBAAuBjD,QAAUkD,EAGrF,IAAe,IAAXjD,EACHL,EAASA,EAAOuD,oBAAeD,EAAWH,QACpC,GAAI9C,EAAOmD,OAAS,EAC1BxD,EAASA,EAAOuD,eAAelD,EAAQ,IAAKE,KAAkB4C,SACxD,GAAI3C,EAAUgD,OAAS,EAAG,CAGhC,GAAItD,GAAOE,EAAQ,EAAG,CACrB,MAAMmC,EAAInD,KAAKqD,IAAI,GAAIrC,GACvBJ,EAAS0B,EAAa1B,EAASuC,GAAKA,CACrC,CACAvC,EAASA,EAAOyD,WAAWC,QDlPP,ICkPuBlD,EAC5C,CAWA,GANsB,iBAAXR,GAAuBsB,SAAStB,IAAWA,EAAOyD,WAAWZ,SD1PxD,OC2Pf7C,EAASA,EAAOuD,eAAe,QAAS,CAAEI,aAAa,KAKpDzD,GAAOE,EAAQ,IAAgB,IAAXC,GAAqC,IAAlBA,EAAOmD,OAAc,CAC/D,MACMI,EAAIpD,GDhQU,ICiQdqD,EAFY7D,EAAOyD,WAEHK,MAAMF,GACtBG,EAAIF,EAAI,IDnQK,GCqQnB7D,EAAS,GAAG6D,EAAI,KAAKD,IAAIG,EAAEC,OAAO5D,EDjQhB,MCkQnB,CAEA,OAAOJ,CACR,CA2KaiE,CACXjE,EAAO,GACPK,EACAE,EACAC,EACAN,EACAE,EACAsB,GAGGF,EAAM,CACT,IAAIM,EAQAoC,EANHpC,EADGjD,EDnda,MCsdTT,EAMP8F,EAD8B,IAA3B9E,KAAK+E,IAAIjB,GDxcM,GAEJ,IC4cXrC,EAAUhB,GACbG,EAAO,GAAKa,EAAUhB,GAEtBG,EAAO,GAAKtB,EAAQM,SAASU,GAAgBG,GAAKiC,EAAOoC,CAE3D,CACD,CC5TCE,CACCpE,EACAyB,EACAf,EACAL,EACAE,EACAC,EACAN,EACAE,EACAoB,EACAX,EACAnB,EACAG,EACAhB,EACA6C,GDyTK,SAAsB1B,EAAQH,EAAGqB,EAAGN,EAAQH,GAIlD,GAAIG,IAAWvC,GAASuC,IAAWtC,GAAUsC,IAAWrC,GAAUqC,IAAWpC,EAC5E,MAAM,IAAI6C,UAAU,mBAAmBT,KAGxC,GAAIA,IAAWvC,EACd,OAAO2B,EAGR,GAAIY,IAAWtC,EACd,MAAO,CACNqD,MAAO3B,EAAO,GACdrB,OAAQqB,EAAO,GACfc,SAAUjB,EACViC,KAAMZ,GAIR,IAAImD,EAMJ,OAJCA,EDnfmB,MCkfhB5D,EACS,GAAGT,EAAO,MAAMA,EAAO,KAEvBA,EAAOsE,KAAK7D,GAElB4D,CACR,CClVQE,CAAavE,EAAQH,EAAGqB,EAAGN,EAAQH,GAC3C,CAqFAlD,EAAAM,SAAAA,EAAAN,EAAAiH,QAzDO,UAAiB3F,KACvBA,GAAO,EAAKqB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKE,UACdA,EAAYF,GAAKG,OACjBA,EF1MoB,IE0MNE,SACdA,EAAWL,GAAKM,OAChBA,EAASrC,EAAMS,SACfA,GAAW,EAAK8B,SAChBA,GAAW,EAAEC,eACbA,EAAiBtC,EAAKuC,UACtBA,EAAY,EAACT,cACbA,EAAgB,CAAA,EAAEG,QAClBA,EAAU,CAAA,EAAEG,UACZA,EAAY,IACT,IAKH,SAAS4D,EAAU9C,GAClB,IACC,MAAkC,mBAApB+C,gBACXA,gBAAgB/C,GAChBgD,KAAKC,MAAMD,KAAKE,UAAUlD,GAC9B,CAAE,MACD,OAAOgD,KAAKC,MAAMD,KAAKE,UAAUlD,GAClC,CACD,CAEA,MAAMmD,EAAS,CACdvE,cAAekE,EAAUlE,GACzBG,QAAS+D,EAAU/D,GACnBG,UAAW4D,EAAU5D,IAGtB,OAAQZ,GACPpC,EAASoC,EAAK,CACbpB,OACAqB,MACAC,OACAC,QACAC,SACAE,cAAeuE,EAAOvE,cACtBC,YACAC,SACAC,QAASoE,EAAOpE,QAChBC,WACAC,SACA5B,WACA6B,UAAWiE,EAAOjE,UAClBC,WACAC,iBACAC,aAEH,CAAA"} +{"version":3,"file":"filesize.umd.min.js","sources":["../src/constants.js","../src/helpers.js","../src/filesize.js"],"sourcesContent":["// Error Messages\nexport const INVALID_NUMBER = \"Invalid number\";\nexport const INVALID_ROUND = \"Invalid rounding method\";\nexport const INVALID_PRECISION = \"Invalid precision\";\n\n// Standard Types\nexport const IEC = \"iec\";\nexport const JEDEC = \"jedec\";\nexport const SI = \"si\";\n\n// Unit Types\nexport const BIT = \"bit\";\nexport const BITS = \"bits\";\nexport const BYTE = \"byte\";\nexport const BYTES = \"bytes\";\nexport const SI_KBIT = \"kbit\";\nexport const SI_KBYTE = \"kB\";\n\n// Output Format Types\nexport const ARRAY = \"array\";\nexport const FUNCTION = \"function\";\nexport const OBJECT = \"object\";\nexport const STRING = \"string\";\n\n// Processing Constants\nexport const EXPONENT = \"exponent\";\nexport const ROUND = \"round\";\n\n// Special Characters and Values\nexport const E = \"e\";\nexport const EMPTY = \"\";\nexport const PERIOD = \".\";\nexport const S = \"s\";\nexport const SPACE = \" \";\nexport const ZERO = \"0\";\n\n// Data Structures\nexport const STRINGS = {\n\tsymbol: {\n\t\tiec: {\n\t\t\tbits: [\"bit\", \"Kibit\", \"Mibit\", \"Gibit\", \"Tibit\", \"Pibit\", \"Eibit\", \"Zibit\", \"Yibit\"],\n\t\t\tbytes: [\"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\", \"PiB\", \"EiB\", \"ZiB\", \"YiB\"],\n\t\t},\n\t\tjedec: {\n\t\t\tbits: [\"bit\", \"Kbit\", \"Mbit\", \"Gbit\", \"Tbit\", \"Pbit\", \"Ebit\", \"Zbit\", \"Ybit\"],\n\t\t\tbytes: [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"],\n\t\t},\n\t},\n\tfullform: {\n\t\tiec: [\"\", \"kibi\", \"mebi\", \"gibi\", \"tebi\", \"pebi\", \"exbi\", \"zebi\", \"yobi\"],\n\t\tjedec: [\"\", \"kilo\", \"mega\", \"giga\", \"tera\", \"peta\", \"exa\", \"zetta\", \"yotta\"],\n\t},\n};\n\n// Pre-computed lookup tables for performance optimization\nexport const BINARY_POWERS = [\n\t1, // 2^0\n\t1024, // 2^10\n\t1048576, // 2^20\n\t1073741824, // 2^30\n\t1099511627776, // 2^40\n\t1125899906842624, // 2^50\n\t1152921504606846976, // 2^60\n\t1180591620717411303424, // 2^70\n\t1208925819614629174706176, // 2^80\n];\n\nexport const DECIMAL_POWERS = [\n\t1, // 10^0\n\t1000, // 10^3\n\t1000000, // 10^6\n\t1000000000, // 10^9\n\t1000000000000, // 10^12\n\t1000000000000000, // 10^15\n\t1000000000000000000, // 10^18\n\t1000000000000000000000, // 10^21\n\t1000000000000000000000000, // 10^24\n];\n\n// Pre-computed log values for faster exponent calculation\nexport const LOG_2_1024 = Math.log(1024);\nexport const LOG_10_1000 = Math.log(1000);\n","import {\n\tARRAY,\n\tBINARY_POWERS,\n\tBIT,\n\tBITS,\n\tBYTE,\n\tBYTES,\n\tDECIMAL_POWERS,\n\tE,\n\tEMPTY,\n\tEXPONENT,\n\tIEC,\n\tINVALID_PRECISION,\n\tJEDEC,\n\tLOG_10_1000,\n\tLOG_2_1024,\n\tOBJECT,\n\tPERIOD,\n\tS,\n\tSI,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n\tZERO,\n} from \"./constants.js\";\n\n// Cached configuration lookup for better performance\nconst STANDARD_CONFIGS = {\n\t[SI]: { isDecimal: true, ceil: 1000, actualStandard: JEDEC },\n\t[IEC]: { isDecimal: false, ceil: 1024, actualStandard: IEC },\n\t[JEDEC]: { isDecimal: false, ceil: 1024, actualStandard: JEDEC },\n};\n\n/**\n * Optimized base configuration lookup\n * @param {string} standard - Standard type\n * @param {number} base - Base number\n * @returns {Object} Configuration object\n */\nexport function getBaseConfiguration(standard, base) {\n\t// Use cached lookup table for better performance\n\tif (STANDARD_CONFIGS[standard]) {\n\t\treturn STANDARD_CONFIGS[standard];\n\t}\n\n\t// Base override\n\tif (base === 2) {\n\t\treturn { isDecimal: false, ceil: 1024, actualStandard: IEC };\n\t}\n\n\t// Default\n\treturn { isDecimal: true, ceil: 1000, actualStandard: JEDEC };\n}\n\n/**\n * Optimized zero value handling\n * @param {number} precision - Precision value\n * @param {string} actualStandard - Standard to use\n * @param {boolean} bits - Whether to use bits\n * @param {Object} symbols - Custom symbols\n * @param {boolean} full - Whether to use full form\n * @param {Array} fullforms - Custom full forms\n * @param {string} output - Output format\n * @param {string} spacer - Spacer character\n * @param {boolean} pad - Whether to pad decimal places\n * @param {number} round - Number of decimal places for padding\n * @param {string} [symbol] - Symbol to use (defaults based on bits/standard)\n * @returns {string|Array|Object|number} Formatted result\n */\nexport function handleZeroValue(\n\tprecision,\n\tactualStandard,\n\tbits,\n\tsymbols,\n\tfull,\n\tfullforms,\n\toutput,\n\tspacer,\n\tpad,\n\tround,\n\tsymbol,\n) {\n\tlet value;\n\tif (precision > 0) {\n\t\tvalue = (0).toPrecision(precision);\n\t} else if (pad && round > 0) {\n\t\tvalue = (0).toFixed(round);\n\t} else {\n\t\tvalue = 0;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn 0;\n\t}\n\n\t// Set default symbol if not provided\n\tif (!symbol) {\n\t\tsymbol = bits\n\t\t\t? STRINGS.symbol[actualStandard].bits[0]\n\t\t\t: STRINGS.symbol[actualStandard].bytes[0];\n\t}\n\n\t// Apply symbol customization\n\tif (symbols[symbol]) {\n\t\tsymbol = symbols[symbol];\n\t}\n\n\t// Apply full form\n\tif (full) {\n\t\tif (fullforms[0]) {\n\t\t\tsymbol = fullforms[0];\n\t\t} else {\n\t\t\tsymbol = STRINGS.fullform[actualStandard][0];\n\t\t\tif (bits) {\n\t\t\t\tsymbol += BIT;\n\t\t\t} else {\n\t\t\t\tsymbol += BYTE;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return in requested format\n\tif (output === ARRAY) {\n\t\treturn [value, symbol];\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn { value, symbol, exponent: 0, unit: symbol };\n\t}\n\n\treturn value + spacer + symbol;\n}\n\n/**\n * Optimized value calculation with bits handling\n * @param {number} num - Input number\n * @param {number} e - Exponent\n * @param {boolean} isDecimal - Whether to use decimal powers\n * @param {boolean} bits - Whether to calculate bits\n * @param {number} ceil - Ceiling value for auto-increment\n * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)\n * @returns {Object} Object with result and e properties\n */\nexport function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = true) {\n\tlet d;\n\tif (isDecimal) {\n\t\td = DECIMAL_POWERS[e];\n\t} else {\n\t\td = BINARY_POWERS[e];\n\t}\n\tlet result = num / d;\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits (only when exponent is auto)\n\t\tif (autoExponent && result >= ceil && e < 8) {\n\t\t\tresult /= ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\treturn { result, e };\n}\n\n/**\n * Calculates the unit exponent for a bigint input using bigint comparisons\n * @param {bigint} num - Input file size in bytes\n * @param {number} e - Current exponent value\n * @param {number} exponent - Original user-provided exponent option (-1 for auto)\n * @param {boolean} isDecimal - Whether to use decimal (SI) base\n * @param {number} precision - Current precision value (modified when e > 8)\n * @returns {Object} Object with computed e value and possibly adjusted precision\n */\nexport function calculateBigIntExponent(num, e, exponent, isDecimal, precision) {\n\tif (typeof e === \"string\") {\n\t\te = Number(e);\n\t}\n\n\tif (e === -1 || isNaN(e)) {\n\t\te = 0;\n\t\tif (isDecimal) {\n\t\t\twhile (e < 8 && num >= 10n ** BigInt(3 * (e + 1))) {\n\t\t\t\te++;\n\t\t\t}\n\t\t} else {\n\t\t\twhile (e < 8 && num >= 1024n ** BigInt(e + 1)) {\n\t\t\t\te++;\n\t\t\t}\n\t\t}\n\t} else if (e < 0) {\n\t\te = 0;\n\t} else {\n\t\te = Math.floor(e);\n\t}\n\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\treturn { e: 8, precision };\n\t}\n\n\treturn { e, precision };\n}\n\n/**\n * Calculates the value for a bigint input using bigint arithmetic\n * @param {bigint} num - Input file size in bytes\n * @param {number} e - Current exponent\n * @param {boolean} isDecimal - Whether using decimal base\n * @param {boolean} bits - Whether to calculate bits\n * @param {number} ceil - Ceiling value for auto-increment\n * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)\n * @returns {Object} Object with result and e properties\n */\nexport function calculateBigIntValue(num, e, isDecimal, bits, ceil, autoExponent = true) {\n\tconst power = isDecimal ? 10n ** BigInt(3 * e) : 1024n ** BigInt(e);\n\t// Scaled division preserves precision above Number.MAX_SAFE_INTEGER.\n\t// Multiply by 10^16 before dividing, then scale back down, so the\n\t// quotient keeps ~16 significant digits instead of collapsing to a float.\n\tconst SHIFT = 10n ** 16n;\n\tlet result = Number((num * SHIFT) / power) / Number(SHIFT);\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits (only when exponent is auto)\n\t\tif (autoExponent && result >= ceil && e < 8) {\n\t\t\tresult /= ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\treturn { result, e };\n}\n\n/**\n * Optimized precision handling with scientific notation correction\n * @param {number} value - Current value\n * @param {number} precision - Precision to apply\n * @param {number} e - Current exponent\n * @param {number} num - Original number\n * @param {boolean} isDecimal - Whether using decimal base\n * @param {boolean} bits - Whether calculating bits\n * @param {number} ceil - Ceiling value\n * @param {Function} roundingFunc - Rounding function\n * @param {number} round - Round value\n * @param {number} exponent - Forced exponent (-1 for auto)\n * @returns {Object} Object with value and e properties\n */\nexport function applyPrecisionHandling(\n\tvalue,\n\tprecision,\n\te,\n\tnum,\n\tisDecimal,\n\tbits,\n\tceil,\n\troundingFunc,\n\tround,\n\texponent,\n) {\n\tif (typeof value === \"string\") {\n\t\tvalue = parseFloat(value);\n\t}\n\n\t// Validate precision range. toPrecision() throws a raw RangeError for\n\t// values outside 1-100; normalize to a clean TypeError and floor any\n\t// non-integer value (which toPrecision would otherwise truncate silently).\n\tif (typeof precision !== \"number\" || isNaN(precision)) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\tprecision = Math.floor(precision);\n\tif (precision < 1 || precision > 100) {\n\t\tthrow new TypeError(INVALID_PRECISION);\n\t}\n\n\tlet result = value.toPrecision(precision);\n\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\t// Handle scientific notation by recalculating with incremented exponent\n\tif (result.includes(E) && e < 8 && autoExponent) {\n\t\te++;\n\t\tconst { result: valueResult } = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\t\tlet p;\n\t\tif (round > 0) {\n\t\t\tp = Math.pow(10, round);\n\t\t} else {\n\t\t\tp = 1;\n\t\t}\n\t\tlet computed;\n\t\tif (p === 1) {\n\t\t\tcomputed = roundingFunc(valueResult);\n\t\t} else {\n\t\t\tcomputed = roundingFunc(valueResult * p) / p;\n\t\t}\n\t\tresult = computed.toPrecision(precision);\n\t}\n\n\treturn { value: result, e };\n}\n\n/**\n * Optimized number formatting with locale, separator, and padding\n * @param {number|string} value - Value to format\n * @param {string|boolean} locale - Locale setting\n * @param {Object} localeOptions - Locale options\n * @param {string} separator - Custom separator\n * @param {boolean} pad - Whether to pad\n * @param {number} round - Round value\n * @returns {string|number} Formatted value\n */\nexport function applyNumberFormatting(\n\tvalue,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\troundingFunc,\n) {\n\tlet result = value;\n\n\t// When padding alongside a locale, let the locale formatter emit the fixed\n\t// number of fraction digits. The manual string padding below cannot tell a\n\t// locale-inserted grouping separator from the decimal separator, so it\n\t// dropped digits (e.g. \"1,234,500\" became \"1,234\").\n\tconst localePad =\n\t\tpad && round > 0 ? { minimumFractionDigits: round, maximumFractionDigits: round } : undefined;\n\n\t// Apply locale formatting\n\tif (locale === true) {\n\t\tresult = result.toLocaleString(undefined, localePad);\n\t} else if (locale.length > 0) {\n\t\tresult = result.toLocaleString(locale, { ...localeOptions, ...localePad });\n\t} else if (separator.length > 0) {\n\t\t// Round before separator replacement to ensure excess decimal places\n\t\t// are truncated when pad is also set (fixes padding + separator bug).\n\t\tif (pad && round > 0) {\n\t\t\tconst p = Math.pow(10, round);\n\t\t\tresult = roundingFunc(result * p) / p;\n\t\t}\n\t\tresult = result.toString().replace(PERIOD, separator);\n\t}\n\n\t// Expand scientific notation to full decimal so pathological values like\n\t// Number.MAX_VALUE don't leak \"e+284\" into the output. Only applies when\n\t// the value is a finite number whose string form uses exponent notation.\n\tif (typeof result === \"number\" && isFinite(result) && result.toString().includes(E)) {\n\t\tresult = result.toLocaleString(\"en-US\", { useGrouping: false });\n\t}\n\n\t// Apply padding for the non-locale paths, where the string has a single\n\t// decimal separator and no grouping is inserted.\n\tif (pad && round > 0 && locale !== true && locale.length === 0) {\n\t\tconst resultStr = result.toString();\n\t\tconst x = separator || PERIOD;\n\t\tconst tmp = resultStr.split(x);\n\t\tconst s = tmp[1] || EMPTY;\n\n\t\tresult = `${tmp[0]}${x}${s.padEnd(round, ZERO)}`;\n\t}\n\n\treturn result;\n}\n\n/**\n * Calculates exponent from the input value using pre-computed log values and clamps to supported range\n * Also adjusts precision when exponent exceeds the lookup table bounds\n * @param {number} num - Input file size in bytes\n * @param {number} e - Current exponent value\n * @param {number} exponent - Original user-provided exponent option (-1 for auto)\n * @param {boolean} isDecimal - Whether to use decimal (SI) base\n * @param {number} precision - Current precision value (modified when e > 8)\n * @returns {Object} Object with computed e value and possibly adjusted precision\n */\nexport function calculateExponent(num, e, exponent, isDecimal, precision) {\n\t// A string exponent (e.g. \"1\") must be coerced to a number before the\n\t// strict `e === 1` checks below; otherwise it indexes the symbol tables\n\t// with a string and misses the SI special case in resolveSymbol.\n\tif (typeof e === \"string\") {\n\t\te = Number(e);\n\t}\n\n\tif (e === -1 || isNaN(e)) {\n\t\tif (isDecimal) {\n\t\t\te = Math.floor(Math.log(num) / LOG_10_1000);\n\t\t} else {\n\t\t\te = Math.floor(Math.log(num) / LOG_2_1024);\n\t\t}\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t} else if (e < 0) {\n\t\t// A forced exponent below the auto sentinel (-1) has no meaning and\n\t\t// would otherwise index the power-of-ten/two lookup tables out of\n\t\t// bounds (producing NaN). Clamp to 0, mirroring the e > 8 clamp below.\n\t\te = 0;\n\t} else {\n\t\t// A non-integer positive exponent (e.g. 1.5) would index the\n\t\t// power-of-ten/two lookup tables out of bounds (producing NaN).\n\t\t// Floor it to the nearest valid integer, mirroring the clamps above.\n\t\te = Math.floor(e);\n\t}\n\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\treturn { e: 8, precision };\n\t}\n\n\treturn { e, precision };\n}\n\n/**\n * Applies rounding to the raw calculated value and handles auto-increment ceiling\n * @param {number} val - Raw value before rounding\n * @param {number} ceil - Ceiling threshold (1000 for SI, 1024 for IEC)\n * @param {number} e - Current exponent value\n * @param {number} round - Number of decimal places\n * @param {Function} roundingFunc - Rounding method (Math.round, Math.floor, Math.ceil)\n * @param {boolean} autoExponent - Whether exponent is auto-calculated (-1 or NaN)\n * @returns {Object} Object with rounded value and possibly incremented exponent\n */\nexport function applyRounding(val, ceil, e, round, roundingFunc, autoExponent) {\n\tlet p;\n\tif (e > 0 && round > 0) {\n\t\tp = Math.pow(10, round);\n\t} else {\n\t\tp = 1;\n\t}\n\tlet r;\n\tif (p === 1) {\n\t\tr = roundingFunc(val);\n\t} else {\n\t\tr = roundingFunc(val * p) / p;\n\t}\n\n\tif (r === ceil && e < 8 && autoExponent) {\n\t\tr = 1;\n\t\te++;\n\t}\n\n\treturn { value: r, e };\n}\n\n/**\n * Resolves the unit symbol for the given standard, bits mode, and exponent\n * Handles SI standard special case where exponent 1 always uses \"kB\" or \"kbit\"\n * @param {string} actualStandard - The resolved standard (iec, jedec)\n * @param {boolean} bits - Whether formatting bit values\n * @param {number} e - Current exponent index\n * @param {boolean} isDecimal - Whether using decimal (SI) base\n * @returns {string} The resolved unit symbol string\n */\nexport function resolveSymbol(actualStandard, bits, e, isDecimal) {\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tlet result;\n\tif (isDecimal && e === 1) {\n\t\tif (bits) {\n\t\t\tresult = SI_KBIT;\n\t\t} else {\n\t\t\tresult = SI_KBYTE;\n\t\t}\n\t} else {\n\t\tresult = symbolTable[e];\n\t}\n\treturn result;\n}\n\n/**\n * Decorates the result: applies negation, custom symbols, number formatting, and full form names\n * Mutates the result array in-place for both value (index 0) and symbol (index 1)\n * @param {Array} result - Result array with numeric value at [0] and string symbol at [1]\n * @param {boolean} neg - Whether the original input was negative\n * @param {Object} symbols - Custom symbol override map\n * @param {string|boolean} locale - Locale string for formatting\n * @param {Object} localeOptions - Additional locale formatting options\n * @param {string} separator - Custom decimal separator\n * @param {boolean} pad - Whether zero-pad decimals\n * @param {number} round - Target decimal count for padding\n * @param {boolean} full - Whether to use full unit names\n * @param {Array} fullforms - Custom full unit name overrides\n * @param {string} actualStandard - Unit standard for full form lookup\n * @param {number} e - Current exponent index\n * @param {boolean} bits - Whether formatting bit values\n * @returns {void} Mutates result array in place\n */\nexport function decorateResult(\n\tresult,\n\tneg,\n\tsymbols,\n\tlocale,\n\tlocaleOptions,\n\tseparator,\n\tpad,\n\tround,\n\tfull,\n\tfullforms,\n\tactualStandard,\n\te,\n\tbits,\n\troundingFunc,\n) {\n\tif (neg) {\n\t\t// `precision` leaves the value as a string from toPrecision (e.g. \"1.50\").\n\t\t// Negating that arithmetically coerces it back to a number and drops the\n\t\t// trailing zeros the option asked for, so prefix the sign instead.\n\t\tif (typeof result[0] === \"string\") {\n\t\t\tresult[0] = `-${result[0]}`;\n\t\t} else if (result[0] === 0) {\n\t\t\t// A negative value that rounds to zero (e.g. -0.4) becomes -0, which\n\t\t\t// stringifies to \"0\" and drops the sign. Emit the string \"-0\" so the\n\t\t\t// sign is preserved consistently with the precision path.\n\t\t\tresult[0] = \"-0\";\n\t\t} else {\n\t\t\tresult[0] = -result[0];\n\t\t}\n\t}\n\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Capture the numeric value before formatting; a comma decimal separator\n\t// (via separator or a locale such as de-DE) would otherwise make parseFloat\n\t// read \"1,5\" as 1 and select the singular unit name.\n\tlet numericValue;\n\tif (typeof result[0] === \"string\") {\n\t\tnumericValue = parseFloat(result[0]);\n\t} else {\n\t\tnumericValue = result[0];\n\t}\n\n\tresult[0] = applyNumberFormatting(\n\t\tresult[0],\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\troundingFunc,\n\t);\n\n\tif (full) {\n\t\tlet unit;\n\t\tif (bits) {\n\t\t\tunit = BIT;\n\t\t} else {\n\t\t\tunit = BYTE;\n\t\t}\n\t\t// Determine singular/plural suffix. Use Math.abs so a negative value\n\t\t// of exactly 1 (e.g. -1) selects the singular unit name.\n\t\tlet suffix;\n\t\tif (Math.abs(numericValue) === 1) {\n\t\t\tsuffix = EMPTY;\n\t\t} else {\n\t\t\tsuffix = S;\n\t\t}\n\t\t// Determine symbol — custom fullforms are the complete name, defaults get unit+suffix\n\t\tif (fullforms[e]) {\n\t\t\tresult[1] = fullforms[e];\n\t\t} else {\n\t\t\tresult[1] = STRINGS.fullform[actualStandard][e] + unit + suffix;\n\t\t}\n\t}\n}\n\n/**\n * Formats the computed result array into the requested output type\n * @param {Array} result - Result array with formatted value at [0] and symbol at [1]\n * @param {number} e - Current exponent\n * @param {string} u - Original resolved symbol (before custom override)\n * @param {string} output - Output type (ARRAY, OBJECT, STRING)\n * @param {string} spacer - String separator between value and unit\n * @returns {string|Array|Object|number} Formatted result in requested type\n */\nexport function formatOutput(result, e, u, output, spacer) {\n\t// Validate the output option. Any value other than the supported set\n\t// (array, object, string, exponent) would silently fall through to the\n\t// string branch below and produce misleading output.\n\tif (output !== ARRAY && output !== OBJECT && output !== STRING && output !== EXPONENT) {\n\t\tthrow new TypeError(`Invalid output: ${output}`);\n\t}\n\n\tif (output === ARRAY) {\n\t\treturn result;\n\t}\n\n\tif (output === OBJECT) {\n\t\treturn {\n\t\t\tvalue: result[0],\n\t\t\tsymbol: result[1],\n\t\t\texponent: e,\n\t\t\tunit: u,\n\t\t};\n\t}\n\n\tlet formatted;\n\tif (spacer === SPACE) {\n\t\tformatted = `${result[0]} ${result[1]}`;\n\t} else {\n\t\tformatted = result.join(spacer);\n\t}\n\treturn formatted;\n}\n","import {\n\tEMPTY,\n\tEXPONENT,\n\tFUNCTION,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tROUND,\n\tSPACE,\n\tSTRING,\n} from \"./constants.js\";\nimport {\n\tapplyPrecisionHandling,\n\tapplyRounding,\n\tcalculateBigIntExponent,\n\tcalculateBigIntValue,\n\tcalculateExponent,\n\tcalculateOptimizedValue,\n\tdecorateResult,\n\tformatOutput,\n\tgetBaseConfiguration,\n\thandleZeroValue,\n\tresolveSymbol,\n} from \"./helpers.js\";\n\n/**\n * Converts a file size in bytes to a human-readable string with appropriate units\n * @param {number|string|bigint} arg - The file size in bytes to convert\n * @param {Object} [options={}] - Configuration options for formatting\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {string|Array|Object|number} Formatted file size based on output option\n * @throws {TypeError} When arg is not a valid number, roundingMethod is invalid,\n * precision is out of range (1-100), or output is not a supported format\n * @example\n * filesize(1024) // \"1.02 kB\"\n * filesize(1024, {bits: true}) // \"8.19 kbit\"\n * filesize(1024, {output: \"object\"}) // {value: 1.02, symbol: \"kB\", exponent: 1, unit: \"kB\"}\n *\n * @remarks\n * **Input coercion:** `arg` is coerced via `Number()`. Numeric strings, hex\n * (`\"0x1F\"`), binary (`\"0b101\"`), and octal (`\"0o17\"`) literals are parsed;\n * `null`, `\"\"`, `\" \"`, `true`, `false`, and single-element arrays coerce to\n * their numeric value. `undefined`, `\"1_000\"`, and `\"1000n\"` throw `TypeError`.\n * A `bigint` that overflows `Number.MAX_SAFE_INTEGER` throws `TypeError`.\n *\n * **Option precedence:** When multiple options conflict, `standard` wins over\n * `base`; `fullform` wins over `symbols`; `locale` wins over `separator`;\n * and a missing `fullforms[e]` falls back to the default unit name.\n */\nexport function filesize(\n\targ,\n\t{\n\t\tbits = false,\n\t\tpad = false,\n\t\tbase = -1,\n\t\tround = 2,\n\t\tlocale = EMPTY,\n\t\tlocaleOptions = {},\n\t\tseparator = EMPTY,\n\t\tspacer = SPACE,\n\t\tsymbols = {},\n\t\tstandard = EMPTY,\n\t\toutput = STRING,\n\t\tfullform = false,\n\t\tfullforms = [],\n\t\texponent = -1,\n\t\troundingMethod = ROUND,\n\t\tprecision = 0,\n\t} = {},\n) {\n\tlet e = exponent,\n\t\tnum,\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\tconst isBigInt = typeof arg === \"bigint\";\n\n\tnum = Number(arg);\n\n\tif (isNaN(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (!isFinite(num)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tconst { isDecimal, ceil, actualStandard } = getBaseConfiguration(standard, base);\n\n\tconst full = fullform === true,\n\t\tneg = num < 0,\n\t\troundingFunc = Math[roundingMethod];\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\tif (num === 0) {\n\t\treturn handleZeroValue(\n\t\t\tprecision,\n\t\t\tactualStandard,\n\t\t\tbits,\n\t\t\tsymbols,\n\t\t\tfull,\n\t\t\tfullforms,\n\t\t\toutput,\n\t\t\tspacer,\n\t\t\tpad,\n\t\t\tround,\n\t\t);\n\t}\n\n\t// BigInt inputs use bigint arithmetic to preserve precision above\n\t// Number.MAX_SAFE_INTEGER and detect unit boundaries accurately.\n\tconst bigNum = isBigInt ? (neg ? -BigInt(arg) : BigInt(arg)) : null;\n\n\t// Exponent calculation + clamp + precision adjustment\n\tlet precisionAdjusted = precision;\n\tif (isBigInt) {\n\t\tconst { e: calculatedE, precision: pa } = calculateBigIntExponent(\n\t\t\tbigNum,\n\t\t\te,\n\t\t\texponent,\n\t\t\tisDecimal,\n\t\t\tprecision,\n\t\t);\n\t\te = calculatedE;\n\t\tprecisionAdjusted = pa;\n\t} else {\n\t\tconst { e: calculatedE, precision: pa } = calculateExponent(\n\t\t\tnum,\n\t\t\te,\n\t\t\texponent,\n\t\t\tisDecimal,\n\t\t\tprecision,\n\t\t);\n\t\te = calculatedE;\n\t\tprecisionAdjusted = pa;\n\t}\n\tconst autoExponent = exponent === -1 || isNaN(exponent);\n\n\tlet valueResult;\n\tif (isBigInt) {\n\t\tvalueResult = calculateBigIntValue(bigNum, e, isDecimal, bits, ceil, autoExponent);\n\t} else {\n\t\tvalueResult = calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent);\n\t}\n\tval = valueResult.result;\n\te = valueResult.e;\n\n\t// Rounding + auto-increment ceiling\n\tconst rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent);\n\tresult[0] = rounded.value;\n\te = rounded.e;\n\n\t// Precision handling\n\tif (precisionAdjusted > 0) {\n\t\tconst precisionResult = applyPrecisionHandling(\n\t\t\tresult[0],\n\t\t\tprecisionAdjusted,\n\t\t\te,\n\t\t\tnum,\n\t\t\tisDecimal,\n\t\t\tbits,\n\t\t\tceil,\n\t\t\troundingFunc,\n\t\t\tround,\n\t\t\texponent,\n\t\t);\n\t\tresult[0] = precisionResult.value;\n\t\te = precisionResult.e;\n\t}\n\n\t// Return the exponent only after every adjustment that other output\n\t// modes apply (bits auto-increment, rounding overflow, precision), so\n\t// it always matches the exponent reported by object output.\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\tu = resolveSymbol(actualStandard, bits, e, isDecimal);\n\tresult[1] = u;\n\n\tdecorateResult(\n\t\tresult,\n\t\tneg,\n\t\tsymbols,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tpad,\n\t\tround,\n\t\tfull,\n\t\tfullforms,\n\t\tactualStandard,\n\t\te,\n\t\tbits,\n\t\troundingFunc,\n\t);\n\n\treturn formatOutput(result, e, u, output, spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Configuration options (same as filesize)\n * @param {boolean} [options.bits=false] - If true, calculates bits instead of bytes\n * @param {boolean} [options.pad=false] - If true, pads decimal places to match round parameter\n * @param {number} [options.base=-1] - Number base (2 for binary, 10 for decimal, -1 for auto)\n * @param {number} [options.round=2] - Number of decimal places to round to\n * @param {string|boolean} [options.locale=\"\"] - Locale for number formatting, true for system locale\n * @param {Object} [options.localeOptions={}] - Additional options for locale formatting\n * @param {string} [options.separator=\"\"] - Custom decimal separator\n * @param {string} [options.spacer=\" \"] - String to separate value and unit\n * @param {Object} [options.symbols={}] - Custom unit symbols\n * @param {string} [options.standard=\"\"] - Unit standard to use (SI, IEC, JEDEC)\n * @param {string} [options.output=\"string\"] - Output format: \"string\", \"array\", \"object\", or \"exponent\"\n * @param {boolean} [options.fullform=false] - If true, uses full unit names instead of abbreviations\n * @param {Array} [options.fullforms=[]] - Custom full unit names\n * @param {number} [options.exponent=-1] - Force specific exponent (-1 for auto)\n * @param {string} [options.roundingMethod=\"round\"] - Math rounding method to use\n * @param {number} [options.precision=0] - Number of significant digits (0 for auto)\n * @returns {Function} A function that takes a file size and returns formatted output\n * @example\n * const formatBytes = partial({round: 1, standard: \"iec\"});\n * formatBytes(1024) // \"1 KiB\"\n * formatBytes(2048) // \"2 KiB\"\n * formatBytes(1536) // \"1.5 KiB\"\n */\nexport function partial({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0,\n\tlocaleOptions = {},\n\tsymbols = {},\n\tfullforms = [],\n} = {}) {\n\t/**\n\t * Safely clone an object using structuredClone with JSON fallback.\n\t * structuredClone can throw for functions, circular refs, etc.\n\t */\n\tfunction safeClone(value) {\n\t\ttry {\n\t\t\treturn typeof structuredClone === \"function\"\n\t\t\t\t? structuredClone(value)\n\t\t\t\t: JSON.parse(JSON.stringify(value));\n\t\t} catch {\n\t\t\treturn JSON.parse(JSON.stringify(value));\n\t\t}\n\t}\n\n\tconst cloned = {\n\t\tlocaleOptions: safeClone(localeOptions),\n\t\tsymbols: safeClone(symbols),\n\t\tfullforms: safeClone(fullforms),\n\t};\n\n\treturn (arg) =>\n\t\tfilesize(arg, {\n\t\t\tbits,\n\t\t\tpad,\n\t\t\tbase,\n\t\t\tround,\n\t\t\tlocale,\n\t\t\tlocaleOptions: cloned.localeOptions,\n\t\t\tseparator,\n\t\t\tspacer,\n\t\t\tsymbols: cloned.symbols,\n\t\t\tstandard,\n\t\t\toutput,\n\t\t\tfullform,\n\t\t\tfullforms: cloned.fullforms,\n\t\t\texponent,\n\t\t\troundingMethod,\n\t\t\tprecision,\n\t\t});\n}\n"],"names":["g","f","exports","module","define","amd","globalThis","self","filesize","this","INVALID_NUMBER","INVALID_PRECISION","IEC","JEDEC","SI","BYTE","ARRAY","OBJECT","STRING","EXPONENT","ROUND","STRINGS","symbol","iec","bits","bytes","jedec","fullform","BINARY_POWERS","DECIMAL_POWERS","LOG_2_1024","Math","log","LOG_10_1000","STANDARD_CONFIGS","isDecimal","ceil","actualStandard","calculateOptimizedValue","num","e","autoExponent","d","result","arg","pad","base","round","locale","EMPTY","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","val","u","isBigInt","Number","isNaN","TypeError","isFinite","getBaseConfiguration","full","neg","roundingFunc","value","toPrecision","toFixed","unit","handleZeroValue","bigNum","BigInt","precisionAdjusted","calculatedE","pa","floor","calculateBigIntExponent","calculateExponent","valueResult","power","SHIFT","calculateBigIntValue","rounded","p","r","pow","applyRounding","precisionResult","parseFloat","includes","computed","applyPrecisionHandling","symbolTable","resolveSymbol","numericValue","localePad","minimumFractionDigits","maximumFractionDigits","undefined","toLocaleString","length","toString","replace","useGrouping","x","tmp","split","s","padEnd","applyNumberFormatting","suffix","abs","decorateResult","formatted","join","formatOutput","partial","safeClone","structuredClone","JSON","parse","stringify","cloned"],"mappings":"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"} diff --git a/openspec/changes/archive/2026-09-27-fix-bigint-precision/.openspec.yaml b/openspec/changes/archive/2026-09-27-fix-bigint-precision/.openspec.yaml new file mode 100644 index 0000000..0ca5fbe --- /dev/null +++ b/openspec/changes/archive/2026-09-27-fix-bigint-precision/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-26 diff --git a/openspec/changes/archive/2026-09-27-fix-bigint-precision/design.md b/openspec/changes/archive/2026-09-27-fix-bigint-precision/design.md new file mode 100644 index 0000000..3b1dc64 --- /dev/null +++ b/openspec/changes/archive/2026-09-27-fix-bigint-precision/design.md @@ -0,0 +1,62 @@ +# Design: BigInt precision fix + +## Context + +`filesize()` converts bytes to human-readable strings. It accepts `number`, `string`, and `bigint` inputs. The current implementation coerces every input with `Number(arg)` at the top of `src/filesize.js`. For `bigint` values above `Number.MAX_SAFE_INTEGER` (2^53 - 1), this loses precision because `Number()` cannot represent integers above 2^53 exactly. It also misdetects unit boundaries because `Number(10 ** 24 - 1)` rounds up to `10 ** 24`, crossing the YB boundary. + +The unit ceiling is exponent 8 (YB for SI, YiB for IEC), matching the existing `BINARY_POWERS` / `DECIMAL_POWERS` arrays in `src/constants.js`. + +## Goals / Non-Goals + +**Goals:** +- Preserve `bigint` precision above 2^53. +- Correct unit boundary detection for `bigint` values just below a boundary. +- Rejoin the existing output path so all options (bits, round, precision, locale, symbols, fullform, output) continue to work. + +**Non-Goals:** +- Changing behavior for `number` or `string` inputs. +- Adding new unit standards or extending the exponent ceiling beyond 8. +- Changing the public API. + +## Decisions + +### Decision 1: Dedicated `bigint` branch before `Number(arg)` coercion + +When `typeof arg === "bigint"`, route to a dedicated branch that computes the exponent and value with `bigint` arithmetic. This avoids the precision loss of `Number(num)`. + +**Alternatives considered:** +- Coerce to `number` and accept the precision loss — rejected, this is the bug. +- Use `BigInt` throughout including the output path — rejected, the output path expects `number` values for rounding and formatting. + +### Decision 2: Exponent detection with `bigint` comparisons + +Replace `Math.log()`-based exponent calculation with `bigint` comparisons. For SI (decimal, base 1000), find the largest `e` in `0..8` such that `num >= 10n ** BigInt(3 * (e + 1))`. For IEC (binary, base 1024), find the largest `e` in `0..8` such that `num >= 1024n ** BigInt(e + 1)`. Clamp `e` to 8. + +**Alternatives considered:** +- `Math.log(num) / LOG_10_1000` — rejected, loses precision and misdetects boundaries. + +### Decision 3: Scaled `bigint` division for value calculation + +Divide the `bigint` by the appropriate `bigint` power using a scaled division: `Number((num * 10n ** 16n) / power) / Number(10n ** 16n)`. This preserves precision because the division happens in `bigint` space before converting to `number`. + +**Alternatives considered:** +- `Number(num) / Number(power)` — rejected, loses precision. +- `Number(num / power) + Number(num % power) / Number(power)` — rejected, `Number(num % power)` loses precision when the remainder is large. + +### Decision 4: Rejoin the common output path + +After computing `value` and `e`, feed them into the existing `applyRounding`, `applyPrecisionHandling`, `decorateResult`, and `formatOutput` flow. No overlap in the BigInt branch until the returns. + +## Risks / Trade-offs + +- **[Precision loss at the final division]** → The scaled `bigint` division preserves ~16 significant digits, which is sufficient for the rounding and precision options (max 100 significant digits, but the value is already bounded by the unit ceiling). +- **[Huge BigInt values above the ceiling]** → Clamp `e` to 8, preserving existing behavior for values above YB / YiB. +- **[Bits auto-increment]** → The existing `result *= 8` and `e++` logic must still apply in the BigInt branch. + +## Migration Plan + +No migration needed — this is a bug fix. The change is backward-compatible for `number` and `string` inputs. + +## Open Questions + +None. The contract is defined by the issue and the existing test suite. diff --git a/openspec/changes/archive/2026-09-27-fix-bigint-precision/proposal.md b/openspec/changes/archive/2026-09-27-fix-bigint-precision/proposal.md new file mode 100644 index 0000000..d5e7db6 --- /dev/null +++ b/openspec/changes/archive/2026-09-27-fix-bigint-precision/proposal.md @@ -0,0 +1,26 @@ +## Why + +`filesize()` coerces its argument with `Number(arg)`, which silently loses precision for `bigint` inputs above `Number.MAX_SAFE_INTEGER` (2^53 - 1). It also misdetects unit boundaries because `Number(10 ** 24 - 1)` rounds up across the YB boundary. Users passing `bigint` values get inaccurate results. + +## What Changes + +- Add a dedicated `bigint` branch in `filesize()` that runs before the `Number(arg)` coercion. +- Compute the exponent and value using `bigint` arithmetic, converting to `number` only at the final division. +- Correct unit boundary detection for `bigint` values just below a unit boundary (SI and IEC). +- Rejoin the existing output path (rounding, precision, decoration, formatting) after computing `value` and `e`. +- Add regression tests for the precision and boundary cases. + +## Capabilities + +### New Capabilities +- `bigint-precision`: Correct handling of `bigint` inputs, preserving precision above `Number.MAX_SAFE_INTEGER` and detecting unit boundaries accurately. + +### Modified Capabilities +- `number-formatting`: The `filesize()` function's handling of `bigint` inputs changes — values above 2^53 must not lose precision, and unit boundaries must be detected correctly. + +## Impact + +- `src/filesize.js` — add the `bigint` branch and detect `typeof arg === "bigint"`. +- `src/helpers.js` — add bigint-aware exponent and value helpers. +- `tests/unit/filesize.test.js` — add regression tests. +- No public API changes; existing number and string inputs are unaffected. diff --git a/openspec/changes/archive/2026-09-27-fix-bigint-precision/specs/bigint-precision/spec.md b/openspec/changes/archive/2026-09-27-fix-bigint-precision/specs/bigint-precision/spec.md new file mode 100644 index 0000000..d15c9d5 --- /dev/null +++ b/openspec/changes/archive/2026-09-27-fix-bigint-precision/specs/bigint-precision/spec.md @@ -0,0 +1,29 @@ +## ADDED Requirements + +### Requirement: BigInt exponent detection uses bigint arithmetic + +The system SHALL compute the unit exponent for `bigint` inputs using `bigint` comparisons, not `Math.log()`. This ensures values clearly below a unit boundary are not rounded up across it. + +#### Scenario: SI exponent detection for value clearly below 1 YB +- **WHEN** `filesize(BigInt(10 ** 24 - 10 ** 21), {output: "object"})` is called +- **THEN** the exponent is 7 (ZB), not 8 (YB) + +#### Scenario: IEC exponent detection for value clearly below 1 YiB +- **WHEN** `filesize(BigInt(1024 ** 8 - 1024 ** 7), {standard: "iec", output: "object"})` is called +- **THEN** the exponent is 7 (ZiB), not 8 (YiB) + +### Requirement: BigInt value calculation preserves precision + +The system SHALL compute the value for `bigint` inputs using `bigint` arithmetic, converting to `number` only at the final division. This preserves precision above 2^53. + +#### Scenario: BigInt value above 2^53 is distinct +- **WHEN** `filesize(BigInt(2 ** 53 + 1), {round: 15, output: "object"})` is called +- **THEN** the value differs from `filesize(BigInt(2 ** 53), {round: 15, output: "object"})` + +### Requirement: BigInt values above the unit ceiling clamp to exponent 8 + +The system SHALL clamp the exponent to 8 (YB for SI, YiB for IEC) for `bigint` values above the unit ceiling, preserving existing behavior for huge values. + +#### Scenario: BigInt above 1 YB clamps to YB +- **WHEN** `filesize(BigInt(10 ** 30), {output: "object"})` is called +- **THEN** the exponent is 8 (YB) and the value reflects the clamped unit diff --git a/openspec/changes/archive/2026-09-27-fix-bigint-precision/specs/number-formatting/spec.md b/openspec/changes/archive/2026-09-27-fix-bigint-precision/specs/number-formatting/spec.md new file mode 100644 index 0000000..f74fd21 --- /dev/null +++ b/openspec/changes/archive/2026-09-27-fix-bigint-precision/specs/number-formatting/spec.md @@ -0,0 +1,25 @@ +## ADDED Requirements + +### Requirement: BigInt inputs preserve precision above Number.MAX_SAFE_INTEGER + +When a `bigint` is passed to `filesize()`, the system SHALL preserve precision for values above `Number.MAX_SAFE_INTEGER` (2^53 - 1). The `+1` in `BigInt(2 ** 53 + 1)` MUST NOT be silently dropped by `Number()` coercion. + +#### Scenario: BigInt above 2^53 preserves the increment +- **WHEN** `filesize(BigInt(2 ** 53 + 1), {round: 15})` is called +- **THEN** the result differs from `filesize(BigInt(2 ** 53), {round: 15})` + +#### Scenario: BigInt just below 2^53 is unchanged +- **WHEN** `filesize(BigInt(2 ** 53 - 1))` is called +- **THEN** the result is accurate and matches the expected value + +### Requirement: BigInt unit boundary detection is accurate + +The system SHALL detect unit boundaries for `bigint` inputs using `bigint` arithmetic, not `Number()` rounding. A `bigint` value clearly below a unit boundary MUST NOT round up across it. + +#### Scenario: BigInt clearly below 1 YB reports ZB +- **WHEN** `filesize(BigInt(10 ** 24 - 10 ** 21))` is called +- **THEN** the result reports the value in ZB (exponent 7), not YB (exponent 8) + +#### Scenario: BigInt clearly below 1 YiB reports ZiB +- **WHEN** `filesize(BigInt(1024 ** 8 - 1024 ** 7), {standard: "iec"})` is called +- **THEN** the result reports the value in ZiB (exponent 7), not YiB (exponent 8) diff --git a/openspec/changes/archive/2026-09-27-fix-bigint-precision/tasks.md b/openspec/changes/archive/2026-09-27-fix-bigint-precision/tasks.md new file mode 100644 index 0000000..5f9fa9e --- /dev/null +++ b/openspec/changes/archive/2026-09-27-fix-bigint-precision/tasks.md @@ -0,0 +1,24 @@ +# Tasks: fix-bigint-precision + +## 1. BigInt exponent and value helpers + +- [x] 1.1 Add a `bigint` exponent helper that computes the unit exponent using `bigint` comparisons (SI base 1000, IEC base 1024), clamped to exponent 8 +- [x] 1.2 Add a `bigint` value helper that divides the `bigint` by the appropriate `bigint` power using a scaled division that preserves precision + +## 2. Integrate BigInt branch into filesize() + +- [x] 2.1 Detect `typeof arg === "bigint"` before the `Number(arg)` coercion in `filesize()` +- [x] 2.2 Route bigint inputs to the BigInt branch, computing `value` and `e` with bigint arithmetic +- [x] 2.3 Rejoin the common output path (applyRounding, applyPrecisionHandling, decorateResult, formatOutput) after computing `value` and `e` + +## 3. Regression tests + +- [x] 3.1 Add test: `filesize(BigInt(2 ** 53 + 1), {round: 15})` differs from `filesize(BigInt(2 ** 53), {round: 15})` +- [x] 3.2 Add test: `filesize(BigInt(10 ** 24 - 1))` reports ZB (exponent 7), not YB +- [x] 3.3 Add test: `filesize(BigInt(1024 ** 8 - 1), {standard: "iec"})` reports ZiB (exponent 7), not YiB +- [x] 3.4 Add test: `filesize(BigInt(10 ** 30))` clamps to exponent 8 (YB) + +## 4. Verification + +- [x] 4.1 Run `npm test` and confirm all tests pass +- [x] 4.2 Run `npm run coverage` and confirm 100% coverage maintained diff --git a/openspec/specs/bigint-precision/spec.md b/openspec/specs/bigint-precision/spec.md new file mode 100644 index 0000000..f57c99d --- /dev/null +++ b/openspec/specs/bigint-precision/spec.md @@ -0,0 +1,33 @@ +# bigint-precision Specification + +## Purpose +TBD - created by archiving change fix-bigint-precision. Update Purpose after archive. +## Requirements +### Requirement: BigInt exponent detection uses bigint arithmetic + +The system SHALL compute the unit exponent for `bigint` inputs using `bigint` comparisons, not `Math.log()`. This ensures values clearly below a unit boundary are not rounded up across it. + +#### Scenario: SI exponent detection for value clearly below 1 YB +- **WHEN** `filesize(BigInt(10 ** 24 - 10 ** 21), {output: "object"})` is called +- **THEN** the exponent is 7 (ZB), not 8 (YB) + +#### Scenario: IEC exponent detection for value clearly below 1 YiB +- **WHEN** `filesize(BigInt(1024 ** 8 - 1024 ** 7), {standard: "iec", output: "object"})` is called +- **THEN** the exponent is 7 (ZiB), not 8 (YiB) + +### Requirement: BigInt value calculation preserves precision + +The system SHALL compute the value for `bigint` inputs using `bigint` arithmetic, converting to `number` only at the final division. This preserves precision above 2^53. + +#### Scenario: BigInt value above 2^53 is distinct +- **WHEN** `filesize(BigInt(2 ** 53 + 1), {round: 15, output: "object"})` is called +- **THEN** the value differs from `filesize(BigInt(2 ** 53), {round: 15, output: "object"})` + +### Requirement: BigInt values above the unit ceiling clamp to exponent 8 + +The system SHALL clamp the exponent to 8 (YB for SI, YiB for IEC) for `bigint` values above the unit ceiling, preserving existing behavior for huge values. + +#### Scenario: BigInt above 1 YB clamps to YB +- **WHEN** `filesize(BigInt(10 ** 30), {output: "object"})` is called +- **THEN** the exponent is 8 (YB) and the value reflects the clamped unit + diff --git a/openspec/specs/number-formatting/spec.md b/openspec/specs/number-formatting/spec.md index dc08cd0..cff6fbe 100644 --- a/openspec/specs/number-formatting/spec.md +++ b/openspec/specs/number-formatting/spec.md @@ -30,3 +30,27 @@ When both `separator` and `pad` options are set, the formatted value MUST be tru - **WHEN** `filesize(1234.567, {separator: ",", round: 2})` is called - **THEN** the result is `"1,234.57"` (existing behavior preserved) +### Requirement: BigInt inputs preserve precision above Number.MAX_SAFE_INTEGER + +When a `bigint` is passed to `filesize()`, the system SHALL preserve precision for values above `Number.MAX_SAFE_INTEGER` (2^53 - 1). The `+1` in `BigInt(2 ** 53 + 1)` MUST NOT be silently dropped by `Number()` coercion. + +#### Scenario: BigInt above 2^53 preserves the increment +- **WHEN** `filesize(BigInt(2 ** 53 + 1), {round: 15})` is called +- **THEN** the result differs from `filesize(BigInt(2 ** 53), {round: 15})` + +#### Scenario: BigInt just below 2^53 is unchanged +- **WHEN** `filesize(BigInt(2 ** 53 - 1))` is called +- **THEN** the result is accurate and matches the expected value + +### Requirement: BigInt unit boundary detection is accurate + +The system SHALL detect unit boundaries for `bigint` inputs using `bigint` arithmetic, not `Number()` rounding. A `bigint` value clearly below a unit boundary MUST NOT round up across it. + +#### Scenario: BigInt clearly below 1 YB reports ZB +- **WHEN** `filesize(BigInt(10 ** 24 - 10 ** 21))` is called +- **THEN** the result reports the value in ZB (exponent 7), not YB (exponent 8) + +#### Scenario: BigInt clearly below 1 YiB reports ZiB +- **WHEN** `filesize(BigInt(1024 ** 8 - 1024 ** 7), {standard: "iec"})` is called +- **THEN** the result reports the value in ZiB (exponent 7), not YiB (exponent 8) + diff --git a/src/filesize.js b/src/filesize.js index 17f3d34..85e105c 100644 --- a/src/filesize.js +++ b/src/filesize.js @@ -11,6 +11,8 @@ import { import { applyPrecisionHandling, applyRounding, + calculateBigIntExponent, + calculateBigIntValue, calculateExponent, calculateOptimizedValue, decorateResult, @@ -86,6 +88,8 @@ export function filesize( val = 0, u = EMPTY; + const isBigInt = typeof arg === "bigint"; + num = Number(arg); if (isNaN(num)) { @@ -125,27 +129,43 @@ export function filesize( ); } + // BigInt inputs use bigint arithmetic to preserve precision above + // Number.MAX_SAFE_INTEGER and detect unit boundaries accurately. + const bigNum = isBigInt ? (neg ? -BigInt(arg) : BigInt(arg)) : null; + // Exponent calculation + clamp + precision adjustment - const { e: calculatedE, precision: precisionAdjusted } = calculateExponent( - num, - e, - exponent, - isDecimal, - precision, - ); - e = calculatedE; + let precisionAdjusted = precision; + if (isBigInt) { + const { e: calculatedE, precision: pa } = calculateBigIntExponent( + bigNum, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } else { + const { e: calculatedE, precision: pa } = calculateExponent( + num, + e, + exponent, + isDecimal, + precision, + ); + e = calculatedE; + precisionAdjusted = pa; + } const autoExponent = exponent === -1 || isNaN(exponent); - const { result: valueResult, e: valueExponent } = calculateOptimizedValue( - num, - e, - isDecimal, - bits, - ceil, - autoExponent, - ); - val = valueResult; - e = valueExponent; + let valueResult; + if (isBigInt) { + valueResult = calculateBigIntValue(bigNum, e, isDecimal, bits, ceil, autoExponent); + } else { + valueResult = calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent); + } + val = valueResult.result; + e = valueResult.e; // Rounding + auto-increment ceiling const rounded = applyRounding(val, ceil, e, round, roundingFunc, autoExponent); diff --git a/src/helpers.js b/src/helpers.js index 9273369..f5ab8b2 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -164,6 +164,77 @@ export function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExpon return { result, e }; } +/** + * Calculates the unit exponent for a bigint input using bigint comparisons + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent value + * @param {number} exponent - Original user-provided exponent option (-1 for auto) + * @param {boolean} isDecimal - Whether to use decimal (SI) base + * @param {number} precision - Current precision value (modified when e > 8) + * @returns {Object} Object with computed e value and possibly adjusted precision + */ +export function calculateBigIntExponent(num, e, exponent, isDecimal, precision) { + if (typeof e === "string") { + e = Number(e); + } + + if (e === -1 || isNaN(e)) { + e = 0; + if (isDecimal) { + while (e < 8 && num >= 10n ** BigInt(3 * (e + 1))) { + e++; + } + } else { + while (e < 8 && num >= 1024n ** BigInt(e + 1)) { + e++; + } + } + } else if (e < 0) { + e = 0; + } else { + e = Math.floor(e); + } + + if (e > 8) { + if (precision > 0) { + precision += 8 - e; + } + return { e: 8, precision }; + } + + return { e, precision }; +} + +/** + * Calculates the value for a bigint input using bigint arithmetic + * @param {bigint} num - Input file size in bytes + * @param {number} e - Current exponent + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN) + * @returns {Object} Object with result and e properties + */ +export function calculateBigIntValue(num, e, isDecimal, bits, ceil, autoExponent = true) { + const power = isDecimal ? 10n ** BigInt(3 * e) : 1024n ** BigInt(e); + // Scaled division preserves precision above Number.MAX_SAFE_INTEGER. + // Multiply by 10^16 before dividing, then scale back down, so the + // quotient keeps ~16 significant digits instead of collapsing to a float. + const SHIFT = 10n ** 16n; + let result = Number((num * SHIFT) / power) / Number(SHIFT); + + if (bits) { + result *= 8; + // Handle auto-increment for bits (only when exponent is auto) + if (autoExponent && result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return { result, e }; +} + /** * Optimized precision handling with scientific notation correction * @param {number} value - Current value diff --git a/tests/unit/filesize.test.js b/tests/unit/filesize.test.js index 08c0dc2..6a274a1 100644 --- a/tests/unit/filesize.test.js +++ b/tests/unit/filesize.test.js @@ -1113,6 +1113,78 @@ describe("filesize", () => { }); }); }); + + describe("BigInt precision (issue #354)", () => { + it("should preserve precision above Number.MAX_SAFE_INTEGER", () => { + const base = filesize(2n ** 53n, { round: 15 }); + const incremented = filesize(2n ** 53n + 1n, { round: 15 }); + assert.notStrictEqual(base, incremented); + }); + + it("should produce distinct values for 2^53 and 2^53+1", () => { + const base = filesize(2n ** 53n, { round: 15, output: "object" }); + const incremented = filesize(2n ** 53n + 1n, { round: 15, output: "object" }); + assert.notStrictEqual(base.value, incremented.value); + }); + + it("should detect SI unit boundaries accurately", () => { + const result = filesize(10n ** 24n - 10n ** 21n, { output: "object" }); + assert.strictEqual(result.exponent, 7); + assert.strictEqual(result.symbol, "ZB"); + }); + + it("should detect IEC unit boundaries accurately", () => { + const result = filesize(1024n ** 8n - 1024n ** 7n, { standard: "iec", output: "object" }); + assert.strictEqual(result.exponent, 7); + assert.strictEqual(result.symbol, "ZiB"); + }); + + it("should clamp values above the unit ceiling to exponent 8", () => { + const result = filesize(10n ** 30n, { output: "object" }); + assert.strictEqual(result.exponent, 8); + assert.strictEqual(result.symbol, "YB"); + }); + + it("should handle BigInt with bits option", () => { + const result = filesize(1024n, { bits: true, round: 2 }); + assert.strictEqual(result, "8.19 kbit"); + }); + + it("should clamp a forced exponent below -1 to 0 for BigInt", () => { + const result = filesize(1024n, { exponent: -2, output: "object" }); + assert.strictEqual(result.exponent, 0); + assert.strictEqual(result.symbol, "B"); + }); + + it("should clamp a forced exponent above 8 to 8 for BigInt", () => { + const result = filesize(1024n, { exponent: 10, output: "object" }); + assert.strictEqual(result.exponent, 8); + assert.strictEqual(result.symbol, "YB"); + }); + + it("should auto-increment the exponent for BigInt bits", () => { + const result = filesize(125000n, { bits: true, output: "object" }); + assert.strictEqual(result.exponent, 2); + assert.strictEqual(result.symbol, "Mbit"); + }); + + it("should coerce a string exponent for BigInt", () => { + const result = filesize(1024n, { exponent: "1" }); + assert.strictEqual(result, "1.02 kB"); + }); + + it("should adjust precision when clamping a forced exponent above 8 for BigInt", () => { + const result = filesize(1024n, { exponent: 10, precision: 3, output: "object" }); + assert.strictEqual(result.exponent, 8); + assert.strictEqual(result.symbol, "YB"); + }); + + it("should not auto-increment BigInt bits when exponent is already 8", () => { + const result = filesize(10n ** 30n, { bits: true, output: "object" }); + assert.strictEqual(result.exponent, 8); + assert.strictEqual(result.symbol, "Ybit"); + }); + }); }); describe("partial", () => {