From 3179ad4dd14b34359d39261813c790546ed39c0c Mon Sep 17 00:00:00 2001 From: Jason Mulligan Date: Sun, 21 Sep 2025 09:17:10 -0400 Subject: [PATCH 1/2] Updates (#207) * Reshaping the code for better testing * Splitting helpers out of filesize * Building * Updating build tools & README.md * Reverting an erroneous change * Fixing the engine.value for stable BigInt * Updating documentation * Updating documentation * Updating README.md benchmarks * Updating documentation * Updating types files * oops --- README.md | 126 +++++++++---- dist/filesize.cjs | 279 +++++++++++++++++----------- dist/filesize.js | 279 +++++++++++++++++----------- dist/filesize.min.js | 4 +- dist/filesize.min.js.map | 2 +- dist/filesize.umd.js | 279 +++++++++++++++++----------- dist/filesize.umd.min.js | 4 +- dist/filesize.umd.min.js.map | 2 +- docs/TECHNICAL_DOCUMENTATION.md | 229 ++++++++++++++--------- package-lock.json | 213 +++++++++++---------- package.json | 17 +- rollup.config.js | 74 +++++++- src/filesize.js | 137 +++----------- src/helpers.js | 176 ++++++++++++++++++ tests/unit/filesize-helpers.test.js | 200 ++++++++++++++++++++ types/constants.d.ts | 32 +++- types/helpers.d.ts | 123 ++++++++++++ 17 files changed, 1505 insertions(+), 671 deletions(-) create mode 100644 src/helpers.js create mode 100644 tests/unit/filesize-helpers.test.js create mode 100644 types/helpers.d.ts diff --git a/README.md b/README.md index 1b0dadb..8006fe5 100644 --- a/README.md +++ b/README.md @@ -125,62 +125,70 @@ filesize.js is optimized for high performance with comprehensive benchmarks cove | Scenario | Operations/sec | Notes | |----------|----------------|-------| -| **Basic conversion** | ~10-12M ops/sec | Fastest operations (small numbers) | -| **Large numbers** | ~10-11M ops/sec | Consistent performance | -| **With options** | ~4-9M ops/sec | Depends on option complexity | -| **Locale formatting** | ~85K ops/sec | Most expensive operation | -| **Partial functions** | ~6-8M ops/sec | ~10-20% overhead, amortized | +| **Basic conversion** | ~16-27M ops/sec | Fastest operations (large numbers) | +| **Small numbers** | ~18-20M ops/sec | Consistent performance | +| **With options** | ~5-13M ops/sec | Depends on option complexity | +| **Locale formatting** | ~91K ops/sec | Most expensive operation | +| **Stress testing** | ~2-10M ops/sec | Handles edge cases gracefully | ### 📊 Detailed Benchmark Results -#### Basic Performance (5-run average, excluding outliers) -- **filesize(0)**: 10.1M ops/sec -- **filesize(512)**: 12.3M ops/sec -- **filesize(1024)**: 10.2M ops/sec -- **filesize(1MB)**: 11.3M ops/sec -- **filesize(1GB)**: 11.1M ops/sec -- **With bits=true**: 9.3M ops/sec -- **With standard="iec"**: 9.6M ops/sec -- **With fullform=true**: 4.4M ops/sec -- **Object output**: 5.1M ops/sec +#### Basic Performance (5-run average) +- **filesize(0)**: 18.6M ops/sec +- **filesize(512)**: 20.3M ops/sec +- **filesize(1024)**: 18.7M ops/sec +- **filesize(1MB)**: 23.5M ops/sec +- **filesize(1GB)**: 23.6M ops/sec +- **filesize(1TB)**: 26.9M ops/sec +- **With bits=true**: 16.8M ops/sec +- **With standard="iec"**: 16.6M ops/sec +- **With round=4**: 13.4M ops/sec #### Options Performance Impact -- **Default options**: 6.4M ops/sec (baseline) -- **bits=true**: 1.66x slower -- **pad=true**: 2.74x slower -- **locale="en-US"**: 75x slower (significant overhead) -- **standard="iec"**: 1.12x slower -- **output="object"**: 0.96x faster -- **Complex combinations**: 1.6-2.1x slower +- **bits=true**: 12.5M ops/sec +- **pad=true**: 5.6M ops/sec +- **locale="en-US"**: 91K ops/sec (significant overhead) +- **standard="iec"**: 8.8M ops/sec +- **standard="jedec"**: 9.0M ops/sec +- **output="array"**: 10.2M ops/sec +- **output="object"**: 9.2M ops/sec +- **fullform=true**: 7.8M ops/sec +- **precision=3**: 6.3M ops/sec +- **separator=","**: 7.2M ops/sec #### Stress Test Results -- **Edge cases**: 2.0M ops/sec (90% success rate) -- **Very large numbers**: 3.7M ops/sec (100% success) -- **BigInt values**: 2.8M ops/sec (100% success) -- **Memory pressure**: 48K ops/sec (100% success) -- **Performance consistency**: 84.7% (10 runs average) +- **Edge cases**: 2.3M ops/sec (90% success rate) +- **Very large numbers**: 4.6M ops/sec (100% success) +- **Very small numbers**: 10.4M ops/sec (100% success) +- **Negative numbers**: 5.4M ops/sec (100% success) +- **Random options**: 2.3M ops/sec (100% success) +- **BigInt values**: 3.7M ops/sec (100% success) +- **Memory pressure**: 49K ops/sec (100% success) +- **Error conditions**: 715K ops/sec (~40% success rate) #### Partial Function Performance -- **Direct calls**: 8.0M ops/sec (baseline) -- **Simple partial**: 6.7M ops/sec (1.20x slower) -- **Complex partial**: 5.6M ops/sec (1.42x slower) -- **Partial with locale**: 84K ops/sec (95x slower) +Partial functions maintain excellent performance with minimal overhead: +- **Acceptable overhead**: 1.1-1.4x slower for most configurations +- **Locale partials**: Significant overhead (~180x slower) due to locale formatting +- **Creation cost**: Amortized across multiple uses ### 💡 Performance Insights -**Excellent Performance (>1M ops/sec)** +**Excellent Performance (>10M ops/sec)** - Basic conversions with minimal options +- Large number processing (1TB+ values) - Standard output formats (string, array, object) - IEC and JEDEC standards -**Good Performance (100K-1M ops/sec)** +**Good Performance (1-10M ops/sec)** - Complex option combinations - Precision and rounding operations - Fullform output +- Stress test scenarios **Use Sparingly (<100K ops/sec)** -- Locale formatting (significant overhead) -- Complex locale configurations +- Locale formatting (significant overhead ~91K ops/sec) +- Memory pressure conditions ### 🎯 Optimization Tips @@ -215,7 +223,7 @@ The latest version includes significant performance improvements: **Overall performance improvement: 30-70% faster** across common use cases while maintaining full backward compatibility. -*Benchmarks run on macOS ARM64, Node.js v23.10.0, 12 CPU cores, 24GB RAM* +*Benchmarks run on macOS ARM64, Node.js v24.8.0, 12 CPU cores, 24GB RAM (5-run averages)* ## API Reference @@ -447,23 +455,61 @@ filesize.js/ 6. Push to the branch (`git push origin feature/amazing-feature`) 7. Open a Pull Request +### Development Workflow + +filesize.js includes an optimized development workflow with modern build tools: + +* **🔄 Live Reload**: Use `npm run dev` for automatic rebuilds during development +* **📊 Bundle Analysis**: Monitor build sizes with `npm run build:analyze` +* **⚡ Fast Testing**: Live test running with `npm run test:watch` +* **🔧 Auto-fixing**: Automatic linting fixes with `npm run lint:fix` +* **📈 Performance**: Optimized Rollup configuration with enhanced tree shaking + +**Build Output Analysis:** +- Minified ES Module: ~1.8KB (gzipped) +- UMD Bundle: ~1.9KB (gzipped) +- Comprehensive source maps included + ### Development Commands ```bash # Install dependencies npm install +# Development mode with live rebuild +npm run dev + +# Build distribution +npm run build + +# Build with bundle size analysis +npm run build:analyze + +# Live rebuild during development +npm run build:watch + # Run linting npm run lint +# Auto-fix linting issues +npm run lint:fix + # Run tests npm test -# Build distribution -npm run build +# Live testing during development +npm run test:watch + +# Run only unit tests +npm run mocha + +# Bundle size analysis +npm run analyze:size -# Run all checks (lint + test) -npm run ci +# Benchmarking +npm run benchmark +npm run benchmark:basic +npm run benchmark:stress ``` ## License diff --git a/dist/filesize.cjs b/dist/filesize.cjs index 54ffaf0..baafdf4 100644 --- a/dist/filesize.cjs +++ b/dist/filesize.cjs @@ -3,7 +3,7 @@ * * @copyright 2025 Jason Mulligan * @license BSD-3-Clause - * @version 11.0.10 + * @version 11.0.11 */ 'use strict'; @@ -89,6 +89,163 @@ const DECIMAL_POWERS = [ const LOG_2_1024 = Math.log(1024); const LOG_10_1000 = Math.log(1000); +// Cached configuration lookup for better performance +const STANDARD_CONFIGS = { + [SI]: {isDecimal: true, ceil: 1000, actualStandard: JEDEC}, + [IEC]: {isDecimal: false, ceil: 1024, actualStandard: IEC}, + [JEDEC]: {isDecimal: false, ceil: 1024, actualStandard: JEDEC} +}; + +/** + * Optimized base configuration lookup + * @param {string} standard - Standard type + * @param {number} base - Base number + * @returns {Object} Configuration object + */ +function getBaseConfiguration (standard, base) { + // Use cached lookup table for better performance + if (STANDARD_CONFIGS[standard]) { + return STANDARD_CONFIGS[standard]; + } + + // Base override + if (base === 2) { + return {isDecimal: false, ceil: 1024, actualStandard: IEC}; + } + + // Default + return {isDecimal: true, ceil: 1000, actualStandard: JEDEC}; +} + +/** + * Optimized zero value handling + * @param {number} precision - Precision value + * @param {string} actualStandard - Standard to use + * @param {boolean} bits - Whether to use bits + * @param {Object} symbols - Custom symbols + * @param {boolean} full - Whether to use full form + * @param {Array} fullforms - Custom full forms + * @param {string} output - Output format + * @param {string} spacer - Spacer character + * @returns {string|Array|Object|number} Formatted result + */ +function handleZeroValue (precision, actualStandard, bits, symbols, full, fullforms, output, spacer) { + const result = []; + result[0] = precision > 0 ? (0).toPrecision(precision) : 0; + const u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; + + if (output === EXPONENT) { + return 0; + } + + // Apply symbol customization + if (symbols[result[1]]) { + result[1] = symbols[result[1]]; + } + + // Apply full form + if (full) { + result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); + } + + // Return in requested format + return output === ARRAY ? result : output === OBJECT ? { + value: result[0], + symbol: result[1], + exponent: 0, + unit: u + } : result.join(spacer); +} + +/** + * Optimized value calculation with bits handling + * @param {number} num - Input number + * @param {number} e - Exponent + * @param {boolean} isDecimal - Whether to use decimal powers + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @returns {Object} Object with val and e properties + */ +function calculateOptimizedValue (num, e, isDecimal, bits, ceil) { + const d = isDecimal ? DECIMAL_POWERS[e] : BINARY_POWERS[e]; + let result = num / d; + + if (bits) { + result *= 8; + // Handle auto-increment for bits + if (result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return {result, e}; +} + +/** + * Optimized precision handling with scientific notation correction + * @param {number} value - Current value + * @param {number} precision - Precision to apply + * @param {number} e - Current exponent + * @param {number} num - Original number + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether calculating bits + * @param {number} ceil - Ceiling value + * @param {Function} roundingFunc - Rounding function + * @param {number} round - Round value + * @returns {Object} Object with value and e properties + */ +function applyPrecisionHandling (value, precision, e, num, isDecimal, bits, ceil, roundingFunc, round) { + let result = value.toPrecision(precision); + + // Handle scientific notation by recalculating with incremented exponent + if (result.includes(E) && e < 8) { + e++; + const {result: valueResult} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + const p = round > 0 ? Math.pow(10, round) : 1; + result = (p === 1 ? roundingFunc(valueResult) : roundingFunc(valueResult * p) / p).toPrecision(precision); + } + + return {value: result, e}; +} + +/** + * Optimized number formatting with locale, separator, and padding + * @param {number|string} value - Value to format + * @param {string|boolean} locale - Locale setting + * @param {Object} localeOptions - Locale options + * @param {string} separator - Custom separator + * @param {boolean} pad - Whether to pad + * @param {number} round - Round value + * @returns {string|number} Formatted value + */ +function applyNumberFormatting (value, locale, localeOptions, separator, pad, round) { + let result = value; + + // Apply locale formatting + if (locale === true) { + result = result.toLocaleString(); + } else if (locale.length > 0) { + result = result.toLocaleString(locale, localeOptions); + } else if (separator.length > 0) { + result = result.toString().replace(PERIOD, separator); + } + + // Apply padding + if (pad && round > 0) { + const resultStr = result.toString(); + const x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD); + const tmp = resultStr.split(x); + const s = tmp[1] || EMPTY; + const l = s.length; + const n = round - l; + + result = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; + } + + return result; +} + /** * Converts a file size in bytes to a human-readable string with appropriate units * @param {number|string|bigint} arg - The file size in bytes to convert @@ -140,29 +297,8 @@ function filesize (arg, { val = 0, u = EMPTY; - // Optimized base & standard synchronization with early returns - let isDecimal, ceil, actualStandard; - if (standard === SI) { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } else if (standard === IEC) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else if (standard === JEDEC) { - isDecimal = false; // JEDEC uses binary (1024) by default - ceil = 1024; - actualStandard = JEDEC; - } else if (base === 2) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } + // Optimized base & standard configuration lookup + const {isDecimal, ceil, actualStandard} = getBaseConfiguration(standard, base); const full = fullform === true, neg = num < 0, @@ -183,38 +319,12 @@ function filesize (arg, { // Fast path for zero if (num === 0) { - result[0] = precision > 0 ? (0).toPrecision(precision) : 0; - u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; - - if (output === EXPONENT) { - return 0; - } - - // Skip most processing for zero case - if (symbols[result[1]]) { - result[1] = symbols[result[1]]; - } - - if (full) { - result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); - } - - return output === ARRAY ? result : output === OBJECT ? { - value: result[0], - symbol: result[1], - exponent: 0, - unit: u - } : result.join(spacer); + return handleZeroValue(precision, actualStandard, bits, symbols, full, fullforms, output, spacer); } // Optimized exponent calculation using pre-computed log values if (e === -1 || isNaN(e)) { - if (isDecimal) { - e = Math.floor(Math.log(num) / LOG_10_1000); - } else { - e = Math.floor(Math.log(num) / LOG_2_1024); - } - + e = isDecimal ? Math.floor(Math.log(num) / LOG_10_1000) : Math.floor(Math.log(num) / LOG_2_1024); if (e < 0) { e = 0; } @@ -232,24 +342,10 @@ function filesize (arg, { return e; } - // Use pre-computed lookup tables (e is always <= 8, arrays have 9 elements) - let d; - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - - val = num / d; - - if (bits) { - val = val * 8; - - if (val >= ceil && e < 8) { - val = val / ceil; - e++; - } - } + // Calculate value with optimized lookup and bits handling + const {result: valueResult, e: valueExponent} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + val = valueResult; + e = valueExponent; // Optimize rounding calculation const p = e > 0 && round > 0 ? Math.pow(10, round) : 1; @@ -260,21 +356,11 @@ function filesize (arg, { e++; } - // Setting optional precision + // Apply precision handling if (precision > 0) { - result[0] = result[0].toPrecision(precision); - - if (result[0].includes(E) && e < 8) { - e++; - // Recalculate with new exponent (e is always <= 8) - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - val = num / d; - result[0] = (p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p).toPrecision(precision); - } + const precisionResult = applyPrecisionHandling(result[0], precision, e, num, isDecimal, bits, ceil, roundingFunc, round); + result[0] = precisionResult.value; + e = precisionResult.e; } // Cache symbol lookup @@ -291,25 +377,8 @@ function filesize (arg, { result[1] = symbols[result[1]]; } - // Optimized locale/separator handling - if (locale === true) { - result[0] = result[0].toLocaleString(); - } else if (locale.length > 0) { - result[0] = result[0].toLocaleString(locale, localeOptions); - } else if (separator.length > 0) { - result[0] = result[0].toString().replace(PERIOD, separator); - } - - if (pad && round > 0) { - const resultStr = result[0].toString(), - x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD), - tmp = resultStr.split(x), - s = tmp[1] || EMPTY, - l = s.length, - n = round - l; - - result[0] = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; - } + // Apply locale, separator, and padding formatting + result[0] = applyNumberFormatting(result[0], locale, localeOptions, separator, pad, round); if (full) { result[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S); @@ -319,7 +388,7 @@ function filesize (arg, { if (output === ARRAY) { return result; } - + if (output === OBJECT) { return { value: result[0], @@ -328,7 +397,7 @@ function filesize (arg, { unit: u }; } - + return spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer); } diff --git a/dist/filesize.js b/dist/filesize.js index a3572bd..0f06e20 100644 --- a/dist/filesize.js +++ b/dist/filesize.js @@ -3,7 +3,7 @@ * * @copyright 2025 Jason Mulligan * @license BSD-3-Clause - * @version 11.0.10 + * @version 11.0.11 */ // Error Messages const INVALID_NUMBER = "Invalid number"; @@ -85,7 +85,162 @@ const DECIMAL_POWERS = [ // Pre-computed log values for faster exponent calculation const LOG_2_1024 = Math.log(1024); -const LOG_10_1000 = Math.log(1000);/** +const LOG_10_1000 = Math.log(1000);// Cached configuration lookup for better performance +const STANDARD_CONFIGS = { + [SI]: {isDecimal: true, ceil: 1000, actualStandard: JEDEC}, + [IEC]: {isDecimal: false, ceil: 1024, actualStandard: IEC}, + [JEDEC]: {isDecimal: false, ceil: 1024, actualStandard: JEDEC} +}; + +/** + * Optimized base configuration lookup + * @param {string} standard - Standard type + * @param {number} base - Base number + * @returns {Object} Configuration object + */ +function getBaseConfiguration (standard, base) { + // Use cached lookup table for better performance + if (STANDARD_CONFIGS[standard]) { + return STANDARD_CONFIGS[standard]; + } + + // Base override + if (base === 2) { + return {isDecimal: false, ceil: 1024, actualStandard: IEC}; + } + + // Default + return {isDecimal: true, ceil: 1000, actualStandard: JEDEC}; +} + +/** + * Optimized zero value handling + * @param {number} precision - Precision value + * @param {string} actualStandard - Standard to use + * @param {boolean} bits - Whether to use bits + * @param {Object} symbols - Custom symbols + * @param {boolean} full - Whether to use full form + * @param {Array} fullforms - Custom full forms + * @param {string} output - Output format + * @param {string} spacer - Spacer character + * @returns {string|Array|Object|number} Formatted result + */ +function handleZeroValue (precision, actualStandard, bits, symbols, full, fullforms, output, spacer) { + const result = []; + result[0] = precision > 0 ? (0).toPrecision(precision) : 0; + const u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; + + if (output === EXPONENT) { + return 0; + } + + // Apply symbol customization + if (symbols[result[1]]) { + result[1] = symbols[result[1]]; + } + + // Apply full form + if (full) { + result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); + } + + // Return in requested format + return output === ARRAY ? result : output === OBJECT ? { + value: result[0], + symbol: result[1], + exponent: 0, + unit: u + } : result.join(spacer); +} + +/** + * Optimized value calculation with bits handling + * @param {number} num - Input number + * @param {number} e - Exponent + * @param {boolean} isDecimal - Whether to use decimal powers + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @returns {Object} Object with val and e properties + */ +function calculateOptimizedValue (num, e, isDecimal, bits, ceil) { + const d = isDecimal ? DECIMAL_POWERS[e] : BINARY_POWERS[e]; + let result = num / d; + + if (bits) { + result *= 8; + // Handle auto-increment for bits + if (result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return {result, e}; +} + +/** + * Optimized precision handling with scientific notation correction + * @param {number} value - Current value + * @param {number} precision - Precision to apply + * @param {number} e - Current exponent + * @param {number} num - Original number + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether calculating bits + * @param {number} ceil - Ceiling value + * @param {Function} roundingFunc - Rounding function + * @param {number} round - Round value + * @returns {Object} Object with value and e properties + */ +function applyPrecisionHandling (value, precision, e, num, isDecimal, bits, ceil, roundingFunc, round) { + let result = value.toPrecision(precision); + + // Handle scientific notation by recalculating with incremented exponent + if (result.includes(E) && e < 8) { + e++; + const {result: valueResult} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + const p = round > 0 ? Math.pow(10, round) : 1; + result = (p === 1 ? roundingFunc(valueResult) : roundingFunc(valueResult * p) / p).toPrecision(precision); + } + + return {value: result, e}; +} + +/** + * Optimized number formatting with locale, separator, and padding + * @param {number|string} value - Value to format + * @param {string|boolean} locale - Locale setting + * @param {Object} localeOptions - Locale options + * @param {string} separator - Custom separator + * @param {boolean} pad - Whether to pad + * @param {number} round - Round value + * @returns {string|number} Formatted value + */ +function applyNumberFormatting (value, locale, localeOptions, separator, pad, round) { + let result = value; + + // Apply locale formatting + if (locale === true) { + result = result.toLocaleString(); + } else if (locale.length > 0) { + result = result.toLocaleString(locale, localeOptions); + } else if (separator.length > 0) { + result = result.toString().replace(PERIOD, separator); + } + + // Apply padding + if (pad && round > 0) { + const resultStr = result.toString(); + const x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD); + const tmp = resultStr.split(x); + const s = tmp[1] || EMPTY; + const l = s.length; + const n = round - l; + + result = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; + } + + return result; +}/** * Converts a file size in bytes to a human-readable string with appropriate units * @param {number|string|bigint} arg - The file size in bytes to convert * @param {Object} [options={}] - Configuration options for formatting @@ -136,29 +291,8 @@ function filesize (arg, { val = 0, u = EMPTY; - // Optimized base & standard synchronization with early returns - let isDecimal, ceil, actualStandard; - if (standard === SI) { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } else if (standard === IEC) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else if (standard === JEDEC) { - isDecimal = false; // JEDEC uses binary (1024) by default - ceil = 1024; - actualStandard = JEDEC; - } else if (base === 2) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } + // Optimized base & standard configuration lookup + const {isDecimal, ceil, actualStandard} = getBaseConfiguration(standard, base); const full = fullform === true, neg = num < 0, @@ -179,38 +313,12 @@ function filesize (arg, { // Fast path for zero if (num === 0) { - result[0] = precision > 0 ? (0).toPrecision(precision) : 0; - u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; - - if (output === EXPONENT) { - return 0; - } - - // Skip most processing for zero case - if (symbols[result[1]]) { - result[1] = symbols[result[1]]; - } - - if (full) { - result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); - } - - return output === ARRAY ? result : output === OBJECT ? { - value: result[0], - symbol: result[1], - exponent: 0, - unit: u - } : result.join(spacer); + return handleZeroValue(precision, actualStandard, bits, symbols, full, fullforms, output, spacer); } // Optimized exponent calculation using pre-computed log values if (e === -1 || isNaN(e)) { - if (isDecimal) { - e = Math.floor(Math.log(num) / LOG_10_1000); - } else { - e = Math.floor(Math.log(num) / LOG_2_1024); - } - + e = isDecimal ? Math.floor(Math.log(num) / LOG_10_1000) : Math.floor(Math.log(num) / LOG_2_1024); if (e < 0) { e = 0; } @@ -228,24 +336,10 @@ function filesize (arg, { return e; } - // Use pre-computed lookup tables (e is always <= 8, arrays have 9 elements) - let d; - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - - val = num / d; - - if (bits) { - val = val * 8; - - if (val >= ceil && e < 8) { - val = val / ceil; - e++; - } - } + // Calculate value with optimized lookup and bits handling + const {result: valueResult, e: valueExponent} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + val = valueResult; + e = valueExponent; // Optimize rounding calculation const p = e > 0 && round > 0 ? Math.pow(10, round) : 1; @@ -256,21 +350,11 @@ function filesize (arg, { e++; } - // Setting optional precision + // Apply precision handling if (precision > 0) { - result[0] = result[0].toPrecision(precision); - - if (result[0].includes(E) && e < 8) { - e++; - // Recalculate with new exponent (e is always <= 8) - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - val = num / d; - result[0] = (p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p).toPrecision(precision); - } + const precisionResult = applyPrecisionHandling(result[0], precision, e, num, isDecimal, bits, ceil, roundingFunc, round); + result[0] = precisionResult.value; + e = precisionResult.e; } // Cache symbol lookup @@ -287,25 +371,8 @@ function filesize (arg, { result[1] = symbols[result[1]]; } - // Optimized locale/separator handling - if (locale === true) { - result[0] = result[0].toLocaleString(); - } else if (locale.length > 0) { - result[0] = result[0].toLocaleString(locale, localeOptions); - } else if (separator.length > 0) { - result[0] = result[0].toString().replace(PERIOD, separator); - } - - if (pad && round > 0) { - const resultStr = result[0].toString(), - x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD), - tmp = resultStr.split(x), - s = tmp[1] || EMPTY, - l = s.length, - n = round - l; - - result[0] = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; - } + // Apply locale, separator, and padding formatting + result[0] = applyNumberFormatting(result[0], locale, localeOptions, separator, pad, round); if (full) { result[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S); @@ -315,7 +382,7 @@ function filesize (arg, { if (output === ARRAY) { return result; } - + if (output === OBJECT) { return { value: result[0], @@ -324,7 +391,7 @@ function filesize (arg, { unit: u }; } - + return spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer); } diff --git a/dist/filesize.min.js b/dist/filesize.min.js index 2bb7685..f091779 100644 --- a/dist/filesize.min.js +++ b/dist/filesize.min.js @@ -1,5 +1,5 @@ /*! 2025 Jason Mulligan - @version 11.0.10 + @version 11.0.11 */ -const t="iec",i="jedec",e="bits",o="byte",n="bytes",r="array",l="object",s="string",a="exponent",b="round",p="",u={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"]}},c=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],f=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],d=Math.log(1024),m=Math.log(1e3);function g(g,{bits:y=!1,pad:B=!1,base:h=-1,round:M=2,locale:x="",localeOptions:E={},separator:P="",spacer:j=" ",symbols:T={},standard:w="",output:N=s,fullform:$=!1,fullforms:k=[],exponent:v=-1,roundingMethod:G=b,precision:K=0}={}){let S,Y,Z,O=v,z=Number(g),I=[],L=0,D=p;"si"===w?(S=!0,Y=1e3,Z=i):w===t?(S=!1,Y=1024,Z=t):w===i?(S=!1,Y=1024,Z=i):2===h?(S=!1,Y=1024,Z=t):(S=!0,Y=1e3,Z=i);const q=!0===$,A=z<0,C=Math[G];if("bigint"!=typeof g&&isNaN(g))throw new TypeError("Invalid number");if("function"!=typeof C)throw new TypeError("Invalid rounding method");if(A&&(z=-z),0===z)return I[0]=K>0?(0).toPrecision(K):0,D=I[1]=u.symbol[Z][y?e:n][0],N===a?0:(T[I[1]]&&(I[1]=T[I[1]]),q&&(I[1]=k[0]||u.fullform[Z][0]+(y?"bit":o)),N===r?I:N===l?{value:I[0],symbol:I[1],exponent:0,unit:D}:I.join(j));if((-1===O||isNaN(O))&&(O=S?Math.floor(Math.log(z)/m):Math.floor(Math.log(z)/d),O<0&&(O=0)),O>8&&(K>0&&(K+=8-O),O=8),N===a)return O;let F;F=S?f[O]:c[O],L=z/F,y&&(L*=8,L>=Y&&O<8&&(L/=Y,O++));const H=O>0&&M>0?Math.pow(10,M):1;I[0]=1===H?C(L):C(L*H)/H,I[0]===Y&&O<8&&-1===v&&(I[0]=1,O++),K>0&&(I[0]=I[0].toPrecision(K),I[0].includes("e")&&O<8&&(O++,F=S?f[O]:c[O],L=z/F,I[0]=(1===H?C(L):C(L*H)/H).toPrecision(K)));const J=u.symbol[Z][y?e:n];if(D=I[1]=S&&1===O?y?"kbit":"kB":J[O],A&&(I[0]=-I[0]),T[I[1]]&&(I[1]=T[I[1]]),!0===x?I[0]=I[0].toLocaleString():x.length>0?I[0]=I[0].toLocaleString(x,E):P.length>0&&(I[0]=I[0].toString().replace(".",P)),B&&M>0){const t=I[0].toString(),i=P||(t.match(/(\D)/g)||[]).pop()||".",e=t.split(i),o=e[1]||p,n=o.length,r=M-n;I[0]=`${e[0]}${i}${o.padEnd(n+r,"0")}`}return q&&(I[1]=k[O]||u.fullform[Z][O]+(y?"bit":o)+(1===I[0]?p:"s")),N===r?I:N===l?{value:I[0],symbol:I[1],exponent:O,unit:D}:" "===j?`${I[0]} ${I[1]}`:I.join(j)}function y({bits:t=!1,pad:i=!1,base:e=-1,round:o=2,locale:n="",localeOptions:r={},separator:l="",spacer:a=" ",symbols:p={},standard:u="",output:c=s,fullform:f=!1,fullforms:d=[],exponent:m=-1,roundingMethod:y=b,precision:B=0}={}){return s=>g(s,{bits:t,pad:i,base:e,round:o,locale:n,localeOptions:r,separator:l,spacer:a,symbols:p,standard:u,output:c,fullform:f,fullforms:d,exponent:m,roundingMethod:y,precision:B})}export{g as filesize,y as partial};//# sourceMappingURL=filesize.min.js.map +const t="iec",e="jedec",i="si",n="bits",a="byte",o="bytes",r="array",l="object",s="string",c="exponent",u="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"]}},d=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],f=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],p=Math.log(1024),m=Math.log(1e3),B={[i]:{isDecimal:!0,ceil:1e3,actualStandard:e},[t]:{isDecimal:!1,ceil:1024,actualStandard:t},[e]:{isDecimal:!1,ceil:1024,actualStandard:e}};function y(t,e,i,n,a){let o=t/(i?f[e]:d[e]);return n&&(o*=8,o>=a&&e<8&&(o/=a,e++)),{result:o,e:e}}function M(i,{bits:d=!1,pad:f=!1,base:M=-1,round:h=2,locale:g="",localeOptions:x={},separator:D="",spacer:E=" ",symbols:S={},standard:T="",output:v=s,fullform:N=!1,fullforms:$=[],exponent:j=-1,roundingMethod:k=u,precision:w=0}={}){let G=j,K=Number(i),P=[],Y=0,Z="";const{isDecimal:O,ceil:z,actualStandard:I}=function(i,n){return B[i]?B[i]:2===n?{isDecimal:!1,ceil:1024,actualStandard:t}:{isDecimal:!0,ceil:1e3,actualStandard:e}}(T,M),q=!0===N,A=K<0,C=Math[k];if("bigint"!=typeof i&&isNaN(i))throw new TypeError("Invalid number");if("function"!=typeof C)throw new TypeError("Invalid rounding method");if(A&&(K=-K),0===K)return function(t,e,i,s,u,d,f,p){const m=[];m[0]=t>0?(0).toPrecision(t):0;const B=m[1]=b.symbol[e][i?n:o][0];return f===c?0:(s[m[1]]&&(m[1]=s[m[1]]),u&&(m[1]=d[0]||b.fullform[e][0]+(i?"bit":a)),f===r?m:f===l?{value:m[0],symbol:m[1],exponent:0,unit:B}:m.join(p))}(w,I,d,S,q,$,v,E);if((-1===G||isNaN(G))&&(G=O?Math.floor(Math.log(K)/m):Math.floor(Math.log(K)/p),G<0&&(G=0)),G>8&&(w>0&&(w+=8-G),G=8),v===c)return G;const{result:F,e:H}=y(K,G,O,d,z);Y=F,G=H;const J=G>0&&h>0?Math.pow(10,h):1;if(P[0]=1===J?C(Y):C(Y*J)/J,P[0]===z&&G<8&&-1===j&&(P[0]=1,G++),w>0){const t=function(t,e,i,n,a,o,r,l,s){let c=t.toPrecision(e);if(c.includes("e")&&i<8){i++;const{result:t}=y(n,i,a,o,r),u=s>0?Math.pow(10,s):1;c=(1===u?l(t):l(t*u)/u).toPrecision(e)}return{value:c,e:i}}(P[0],w,G,K,O,d,z,C,h);P[0]=t.value,G=t.e}const L=b.symbol[I][d?n:o];return Z=P[1]=O&&1===G?d?"kbit":"kB":L[G],A&&(P[0]=-P[0]),S[P[1]]&&(P[1]=S[P[1]]),P[0]=function(t,e,i,n,a,o){let r=t;if(!0===e?r=r.toLocaleString():e.length>0?r=r.toLocaleString(e,i):n.length>0&&(r=r.toString().replace(".",n)),a&&o>0){const t=r.toString(),e=n||(t.match(/(\D)/g)||[]).pop()||".",i=t.split(e),a=i[1]||"",l=a.length,s=o-l;r=`${i[0]}${e}${a.padEnd(l+s,"0")}`}return r}(P[0],g,x,D,f,h),q&&(P[1]=$[G]||b.fullform[I][G]+(d?"bit":a)+(1===P[0]?"":"s")),v===r?P:v===l?{value:P[0],symbol:P[1],exponent:G,unit:Z}:" "===E?`${P[0]} ${P[1]}`:P.join(E)}function h({bits:t=!1,pad:e=!1,base:i=-1,round:n=2,locale:a="",localeOptions:o={},separator:r="",spacer:l=" ",symbols:c={},standard:b="",output:d=s,fullform:f=!1,fullforms:p=[],exponent:m=-1,roundingMethod:B=u,precision:y=0}={}){return s=>M(s,{bits:t,pad:e,base:i,round:n,locale:a,localeOptions:o,separator:r,spacer:l,symbols:c,standard:b,output:d,fullform:f,fullforms:p,exponent:m,roundingMethod:B,precision:y})}export{M as filesize,h as partial};//# sourceMappingURL=filesize.min.js.map diff --git a/dist/filesize.min.js.map b/dist/filesize.min.js.map index 28cd841..f6ce450 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/filesize.js"],"sourcesContent":["// Error Messages\nexport const INVALID_NUMBER = \"Invalid number\";\nexport const INVALID_ROUND = \"Invalid rounding method\";\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\tFUNCTION,\n\tIEC,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tJEDEC,\n\tLOG_2_1024,\n\tLOG_10_1000,\n\tOBJECT,\n\tPERIOD,\n\tROUND,\n\tS,\n\tSI,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n\tZERO\n} from \"./constants.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 or roundingMethod is invalid\n * @example\n * filesize(1024) // \"1 KB\"\n * filesize(1024, {bits: true}) // \"8 Kb\"\n * filesize(1024, {output: \"object\"}) // {value: 1, symbol: \"KB\", exponent: 1, unit: \"KB\"}\n */\nexport function filesize (arg, {\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\tlet e = exponent,\n\t\tnum = Number(arg),\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\t// Optimized base & standard synchronization with early returns\n\tlet isDecimal, ceil, actualStandard;\n\tif (standard === SI) {\n\t\tisDecimal = true;\n\t\tceil = 1000;\n\t\tactualStandard = JEDEC;\n\t} else if (standard === IEC) {\n\t\tisDecimal = false;\n\t\tceil = 1024;\n\t\tactualStandard = IEC;\n\t} else if (standard === JEDEC) {\n\t\tisDecimal = false; // JEDEC uses binary (1024) by default\n\t\tceil = 1024;\n\t\tactualStandard = JEDEC;\n\t} else if (base === 2) {\n\t\tisDecimal = false;\n\t\tceil = 1024;\n\t\tactualStandard = IEC;\n\t} else {\n\t\tisDecimal = true;\n\t\tceil = 1000;\n\t\tactualStandard = JEDEC;\n\t}\n\n\tconst full = fullform === true,\n\t\tneg = num < 0,\n\t\troundingFunc = Math[roundingMethod];\n\n\tif (typeof arg !== \"bigint\" && isNaN(arg)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\t// Flipping a negative number to determine the size\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\t// Fast path for zero\n\tif (num === 0) {\n\t\tresult[0] = precision > 0 ? (0).toPrecision(precision) : 0;\n\t\tu = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0];\n\t\t\n\t\tif (output === EXPONENT) {\n\t\t\treturn 0;\n\t\t}\n\t\t\n\t\t// Skip most processing for zero case\n\t\tif (symbols[result[1]]) {\n\t\t\tresult[1] = symbols[result[1]];\n\t\t}\n\t\t\n\t\tif (full) {\n\t\t\tresult[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE);\n\t\t}\n\t\t\n\t\treturn output === ARRAY ? result : output === OBJECT ? {\n\t\t\tvalue: result[0],\n\t\t\tsymbol: result[1],\n\t\t\texponent: 0,\n\t\t\tunit: u\n\t\t} : result.join(spacer);\n\t}\n\n\t// Optimized exponent calculation using pre-computed log values\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\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t}\n\n\t// Exceeding supported length, time to reduce & multiply\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\te = 8;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\t// Use pre-computed lookup tables (e is always <= 8, arrays have 9 elements)\n\tlet d;\n\tif (isDecimal) {\n\t\td = DECIMAL_POWERS[e];\n\t} else {\n\t\td = BINARY_POWERS[e];\n\t}\n\t\n\tval = num / d;\n\n\tif (bits) {\n\t\tval = val * 8;\n\n\t\tif (val >= ceil && e < 8) {\n\t\t\tval = val / ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\t// Optimize rounding calculation\n\tconst p = e > 0 && round > 0 ? Math.pow(10, round) : 1;\n\tresult[0] = p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p;\n\n\tif (result[0] === ceil && e < 8 && exponent === -1) {\n\t\tresult[0] = 1;\n\t\te++;\n\t}\n\n\t// Setting optional precision\n\tif (precision > 0) {\n\t\tresult[0] = result[0].toPrecision(precision);\n\n\t\tif (result[0].includes(E) && e < 8) {\n\t\t\te++;\n\t\t\t// Recalculate with new exponent (e is always <= 8)\n\t\t\tif (isDecimal) {\n\t\t\t\td = DECIMAL_POWERS[e];\n\t\t\t} else {\n\t\t\t\td = BINARY_POWERS[e];\n\t\t\t}\n\t\t\tval = num / d;\n\t\t\tresult[0] = (p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p).toPrecision(precision);\n\t\t}\n\t}\n\n\t// Cache symbol lookup\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tu = result[1] = (isDecimal && e === 1) ? (bits ? SI_KBIT : SI_KBYTE) : symbolTable[e];\n\n\t// Decorating a 'diff'\n\tif (neg) {\n\t\tresult[0] = -result[0];\n\t}\n\n\t// Applying custom symbol\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Optimized locale/separator handling\n\tif (locale === true) {\n\t\tresult[0] = result[0].toLocaleString();\n\t} else if (locale.length > 0) {\n\t\tresult[0] = result[0].toLocaleString(locale, localeOptions);\n\t} else if (separator.length > 0) {\n\t\tresult[0] = result[0].toString().replace(PERIOD, separator);\n\t}\n\n\tif (pad && round > 0) {\n\t\tconst resultStr = result[0].toString(),\n\t\t\tx = separator || ((resultStr.match(/(\\D)/g) || []).pop() || PERIOD),\n\t\t\ttmp = resultStr.split(x),\n\t\t\ts = tmp[1] || EMPTY,\n\t\t\tl = s.length,\n\t\t\tn = round - l;\n\n\t\tresult[0] = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`;\n\t}\n\n\tif (full) {\n\t\tresult[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S);\n\t}\n\n\t// Optimized return logic\n\tif (output === ARRAY) {\n\t\treturn result;\n\t}\n\t\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\t\n\treturn spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Default options to apply to the returned function\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.0 KiB\"\n * formatBytes(2048) // \"2.0 KiB\"\n */\n// Partial application for functional programming\nexport function partial ({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\treturn arg => filesize(arg, {\n\t\tbits,\n\t\tpad,\n\t\tbase,\n\t\tround,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tspacer,\n\t\tsymbols,\n\t\tstandard,\n\t\toutput,\n\t\tfullform,\n\t\tfullforms,\n\t\texponent,\n\t\troundingMethod,\n\t\tprecision\n\t});\n}\n"],"names":["IEC","JEDEC","BITS","BYTE","BYTES","ARRAY","OBJECT","STRING","EXPONENT","ROUND","EMPTY","STRINGS","symbol","iec","bits","bytes","jedec","fullform","BINARY_POWERS","DECIMAL_POWERS","LOG_2_1024","Math","log","LOG_10_1000","filesize","arg","pad","base","round","locale","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","isDecimal","ceil","actualStandard","e","num","Number","result","val","u","full","neg","roundingFunc","isNaN","TypeError","toPrecision","value","unit","join","floor","d","p","pow","includes","symbolTable","toLocaleString","length","toString","replace","resultStr","x","match","pop","tmp","split","s","l","n","padEnd","partial"],"mappings":"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"} \ No newline at end of file +{"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\";\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\tJEDEC,\n\tOBJECT,\n\tPERIOD,\n\tSI,\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 * @returns {string|Array|Object|number} Formatted result\n */\nexport function handleZeroValue (precision, actualStandard, bits, symbols, full, fullforms, output, spacer) {\n\tconst result = [];\n\tresult[0] = precision > 0 ? (0).toPrecision(precision) : 0;\n\tconst u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0];\n\n\tif (output === EXPONENT) {\n\t\treturn 0;\n\t}\n\n\t// Apply symbol customization\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Apply full form\n\tif (full) {\n\t\tresult[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE);\n\t}\n\n\t// Return in requested format\n\treturn output === ARRAY ? result : output === OBJECT ? {\n\t\tvalue: result[0],\n\t\tsymbol: result[1],\n\t\texponent: 0,\n\t\tunit: u\n\t} : result.join(spacer);\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 * @returns {Object} Object with val and e properties\n */\nexport function calculateOptimizedValue (num, e, isDecimal, bits, ceil) {\n\tconst d = isDecimal ? DECIMAL_POWERS[e] : BINARY_POWERS[e];\n\tlet result = num / d;\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits\n\t\tif (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 * @returns {Object} Object with value and e properties\n */\nexport function applyPrecisionHandling (value, precision, e, num, isDecimal, bits, ceil, roundingFunc, round) {\n\tlet result = value.toPrecision(precision);\n\n\t// Handle scientific notation by recalculating with incremented exponent\n\tif (result.includes(E) && e < 8) {\n\t\te++;\n\t\tconst {result: valueResult} = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\t\tconst p = round > 0 ? Math.pow(10, round) : 1;\n\t\tresult = (p === 1 ? roundingFunc(valueResult) : roundingFunc(valueResult * p) / p).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 (value, locale, localeOptions, separator, pad, round) {\n\tlet result = value;\n\n\t// Apply locale formatting\n\tif (locale === true) {\n\t\tresult = result.toLocaleString();\n\t} else if (locale.length > 0) {\n\t\tresult = result.toLocaleString(locale, localeOptions);\n\t} else if (separator.length > 0) {\n\t\tresult = result.toString().replace(PERIOD, separator);\n\t}\n\n\t// Apply padding\n\tif (pad && round > 0) {\n\t\tconst resultStr = result.toString();\n\t\tconst x = separator || ((resultStr.match(/(\\D)/g) || []).pop() || PERIOD);\n\t\tconst tmp = resultStr.split(x);\n\t\tconst s = tmp[1] || EMPTY;\n\t\tconst l = s.length;\n\t\tconst n = round - l;\n\n\t\tresult = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`;\n\t}\n\n\treturn result;\n}\n","import {\n\tARRAY,\n\tBIT,\n\tBITS,\n\tBYTE,\n\tBYTES,\n\tEMPTY,\n\tEXPONENT,\n\tFUNCTION,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tLOG_10_1000,\n\tLOG_2_1024,\n\tOBJECT,\n\tROUND,\n\tS,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n} from \"./constants.js\";\nimport {\n\tapplyNumberFormatting,\n\tapplyPrecisionHandling,\n\tcalculateOptimizedValue,\n\tgetBaseConfiguration,\n\thandleZeroValue\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 or roundingMethod is invalid\n * @example\n * filesize(1024) // \"1 KB\"\n * filesize(1024, {bits: true}) // \"8 Kb\"\n * filesize(1024, {output: \"object\"}) // {value: 1, symbol: \"KB\", exponent: 1, unit: \"KB\"}\n */\nexport function filesize (arg, {\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\tlet e = exponent,\n\t\tnum = Number(arg),\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\t// Optimized base & standard configuration lookup\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 arg !== \"bigint\" && isNaN(arg)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\t// Flipping a negative number to determine the size\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\t// Fast path for zero\n\tif (num === 0) {\n\t\treturn handleZeroValue(precision, actualStandard, bits, symbols, full, fullforms, output, spacer);\n\t}\n\n\t// Optimized exponent calculation using pre-computed log values\n\tif (e === -1 || isNaN(e)) {\n\t\te = isDecimal ? Math.floor(Math.log(num) / LOG_10_1000) : Math.floor(Math.log(num) / LOG_2_1024);\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t}\n\n\t// Exceeding supported length, time to reduce & multiply\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\te = 8;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\t// Calculate value with optimized lookup and bits handling\n\tconst {result: valueResult, e: valueExponent} = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\tval = valueResult;\n\te = valueExponent;\n\n\t// Optimize rounding calculation\n\tconst p = e > 0 && round > 0 ? Math.pow(10, round) : 1;\n\tresult[0] = p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p;\n\n\tif (result[0] === ceil && e < 8 && exponent === -1) {\n\t\tresult[0] = 1;\n\t\te++;\n\t}\n\n\t// Apply precision handling\n\tif (precision > 0) {\n\t\tconst precisionResult = applyPrecisionHandling(result[0], precision, e, num, isDecimal, bits, ceil, roundingFunc, round);\n\t\tresult[0] = precisionResult.value;\n\t\te = precisionResult.e;\n\t}\n\n\t// Cache symbol lookup\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tu = result[1] = (isDecimal && e === 1) ? (bits ? SI_KBIT : SI_KBYTE) : symbolTable[e];\n\n\t// Decorating a 'diff'\n\tif (neg) {\n\t\tresult[0] = -result[0];\n\t}\n\n\t// Applying custom symbol\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Apply locale, separator, and padding formatting\n\tresult[0] = applyNumberFormatting(result[0], locale, localeOptions, separator, pad, round);\n\n\tif (full) {\n\t\tresult[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S);\n\t}\n\n\t// Optimized return logic\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\treturn spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Default options to apply to the returned function\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.0 KiB\"\n * formatBytes(2048) // \"2.0 KiB\"\n */\n// Partial application for functional programming\nexport function partial ({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\treturn arg => filesize(arg, {\n\t\tbits,\n\t\tpad,\n\t\tbase,\n\t\tround,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tspacer,\n\t\tsymbols,\n\t\tstandard,\n\t\toutput,\n\t\tfullform,\n\t\tfullforms,\n\t\texponent,\n\t\troundingMethod,\n\t\tprecision\n\t});\n}\n"],"names":["IEC","JEDEC","SI","BITS","BYTE","BYTES","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","result","filesize","arg","pad","base","round","locale","EMPTY","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","Number","val","u","getBaseConfiguration","full","neg","roundingFunc","isNaN","TypeError","toPrecision","value","unit","join","handleZeroValue","floor","valueResult","valueExponent","p","pow","precisionResult","includes","applyPrecisionHandling","symbolTable","toLocaleString","length","toString","replace","resultStr","x","match","pop","tmp","split","s","l","n","padEnd","applyNumberFormatting","partial"],"mappings":";;;;AACO,MAIMA,EAAM,MACNC,EAAQ,QACRC,EAAK,KAILC,EAAO,OACPC,EAAO,OACPC,EAAQ,QAKRC,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,KC3D9BE,EAAmB,CACxBtB,CAACA,GAAK,CAACuB,WAAW,EAAMC,KAAM,IAAMC,eAAgB1B,GACpDD,CAACA,GAAM,CAACyB,WAAW,EAAOC,KAAM,KAAMC,eAAgB3B,GACtDC,CAACA,GAAQ,CAACwB,WAAW,EAAOC,KAAM,KAAMC,eAAgB1B,IAyElD,SAAS2B,EAAyBC,EAAKC,EAAGL,EAAWX,EAAMY,GAEjE,IAAIK,EAASF,GADHJ,EAAYN,EAAeW,GAAKZ,EAAcY,IAYxD,OATIhB,IACHiB,GAAU,EAENA,GAAUL,GAAQI,EAAI,IACzBC,GAAUL,EACVI,MAIK,CAACC,SAAQD,IACjB,CCtDO,SAASE,EAAUC,GAAKnB,KAC9BA,GAAO,EAAKoB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKC,cACdA,EAAgB,CAAA,EAAEC,UAClBA,EAAYF,GAAKG,OACjBA,EFjCoB,IEiCNC,QACdA,EAAU,CAAA,EAAEC,SACZA,EAAWL,GAAKM,OAChBA,EAASpC,EAAMS,SACfA,GAAW,EAAK4B,UAChBA,EAAY,GAAEC,SACdA,GAAW,EAAEC,eACbA,EAAiBrC,EAAKsC,UACtBA,EAAY,GACT,IACH,IAAIlB,EAAIgB,EACPjB,EAAMoB,OAAOhB,GACbF,EAAS,GACTmB,EAAM,EACNC,EFlDmB,GEqDpB,MAAM1B,UAACA,EAASC,KAAEA,EAAIC,eAAEA,GDjDlB,SAA+BgB,EAAUR,GAE/C,OAAIX,EAAiBmB,GACbnB,EAAiBmB,GAIZ,IAATR,EACI,CAACV,WAAW,EAAOC,KAAM,KAAMC,eAAgB3B,GAIhD,CAACyB,WAAW,EAAMC,KAAM,IAAMC,eAAgB1B,EACtD,CCoC2CmD,CAAqBT,EAAUR,GAEnEkB,GAAoB,IAAbpC,EACZqC,EAAMzB,EAAM,EACZ0B,EAAelC,KAAK0B,GAErB,GAAmB,iBAARd,GAAoBuB,MAAMvB,GACpC,MAAM,IAAIwB,UFxFkB,kBE2F7B,GFzEuB,mBEyEZF,EACV,MAAM,IAAIE,UF3FiB,2BEoG5B,GALIH,IACHzB,GAAOA,GAII,IAARA,EACH,OD3CK,SAA0BmB,EAAWrB,EAAgBb,EAAM4B,EAASW,EAAMR,EAAWD,EAAQH,GACnG,MAAMV,EAAS,GACfA,EAAO,GAAKiB,EAAY,GAAI,GAAIU,YAAYV,GAAa,EACzD,MAAMG,EAAIpB,EAAO,GAAKpB,EAAQC,OAAOe,GAAgBb,EAAOX,EAAOE,GAAO,GAE1E,OAAIuC,IAAWnC,EACP,GAIJiC,EAAQX,EAAO,MAClBA,EAAO,GAAKW,EAAQX,EAAO,KAIxBsB,IACHtB,EAAO,GAAKc,EAAU,IAAMlC,EAAQM,SAASU,GAAgB,IAAMb,EDlElD,MCkE+DV,IAI1EwC,IAAWtC,EAAQyB,EAASa,IAAWrC,EAAS,CACtDoD,MAAO5B,EAAO,GACdnB,OAAQmB,EAAO,GACfe,SAAU,EACVc,KAAMT,GACHpB,EAAO8B,KAAKpB,GACjB,CCiBSqB,CAAgBd,EAAWrB,EAAgBb,EAAM4B,EAASW,EAAMR,EAAWD,EAAQH,GAmB3F,KAfU,IAANX,GAAY0B,MAAM1B,MACrBA,EAAIL,EAAYJ,KAAK0C,MAAM1C,KAAKC,IAAIO,GAAON,GAAeF,KAAK0C,MAAM1C,KAAKC,IAAIO,GAAOT,GACjFU,EAAI,IACPA,EAAI,IAKFA,EAAI,IACHkB,EAAY,IACfA,GAAa,EAAIlB,GAElBA,EAAI,GAGDc,IAAWnC,EACd,OAAOqB,EAIR,MAAOC,OAAQiC,EAAalC,EAAGmC,GAAiBrC,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,GACjGwB,EAAMc,EACNlC,EAAImC,EAGJ,MAAMC,EAAIpC,EAAI,GAAKM,EAAQ,EAAIf,KAAK8C,IAAI,GAAI/B,GAAS,EASrD,GARAL,EAAO,GAAW,IAANmC,EAAUX,EAAaL,GAAOK,EAAaL,EAAMgB,GAAKA,EAE9DnC,EAAO,KAAOL,GAAQI,EAAI,QAAKgB,IAClCf,EAAO,GAAK,EACZD,KAIGkB,EAAY,EAAG,CAClB,MAAMoB,EDhBD,SAAiCT,EAAOX,EAAWlB,EAAGD,EAAKJ,EAAWX,EAAMY,EAAM6B,EAAcnB,GACtG,IAAIL,EAAS4B,EAAMD,YAAYV,GAG/B,GAAIjB,EAAOsC,SDtGK,MCsGUvC,EAAI,EAAG,CAChCA,IACA,MAAOC,OAAQiC,GAAepC,EAAwBC,EAAKC,EAAGL,EAAWX,EAAMY,GACzEwC,EAAI9B,EAAQ,EAAIf,KAAK8C,IAAI,GAAI/B,GAAS,EAC5CL,GAAgB,IAANmC,EAAUX,EAAaS,GAAeT,EAAaS,EAAcE,GAAKA,GAAGR,YAAYV,EAChG,CAEA,MAAO,CAACW,MAAO5B,EAAQD,IACxB,CCI0BwC,CAAuBvC,EAAO,GAAIiB,EAAWlB,EAAGD,EAAKJ,EAAWX,EAAMY,EAAM6B,EAAcnB,GAClHL,EAAO,GAAKqC,EAAgBT,MAC5B7B,EAAIsC,EAAgBtC,CACrB,CAGA,MAAMyC,EAAc5D,EAAQC,OAAOe,GAAgBb,EAAOX,EAAOE,GAqBjE,OApBA8C,EAAIpB,EAAO,GAAMN,GAAmB,IAANK,EAAYhB,EFvIpB,OACC,KEsIgDyD,EAAYzC,GAG/EwB,IACHvB,EAAO,IAAMA,EAAO,IAIjBW,EAAQX,EAAO,MAClBA,EAAO,GAAKW,EAAQX,EAAO,KAI5BA,EAAO,GDZD,SAAgC4B,EAAOtB,EAAQE,EAAeC,EAAWN,EAAKE,GACpF,IAAIL,EAAS4B,EAYb,IATe,IAAXtB,EACHN,EAASA,EAAOyC,iBACNnC,EAAOoC,OAAS,EAC1B1C,EAASA,EAAOyC,eAAenC,EAAQE,GAC7BC,EAAUiC,OAAS,IAC7B1C,EAASA,EAAO2C,WAAWC,QDjIP,ICiIuBnC,IAIxCN,GAAOE,EAAQ,EAAG,CACrB,MAAMwC,EAAY7C,EAAO2C,WACnBG,EAAIrC,IAAeoC,EAAUE,MAAM,UAAY,IAAIC,ODvIrC,ICwIdC,EAAMJ,EAAUK,MAAMJ,GACtBK,EAAIF,EAAI,ID1IK,GC2IbG,EAAID,EAAET,OACNW,EAAIhD,EAAQ+C,EAElBpD,EAAS,GAAGiD,EAAI,KAAKH,IAAIK,EAAEG,OAAOF,EAAIC,ED1IpB,MC2InB,CAEA,OAAOrD,CACR,CCbauD,CAAsBvD,EAAO,GAAIM,EAAQE,EAAeC,EAAWN,EAAKE,GAEhFiB,IACHtB,EAAO,GAAKc,EAAUf,IAAMnB,EAAQM,SAASU,GAAgBG,IAAMhB,EF3JlD,ME2J+DV,IAAuB,IAAd2B,EAAO,GFxI7E,GAEJ,ME0IZa,IAAWtC,EACPyB,EAGJa,IAAWrC,EACP,CACNoD,MAAO5B,EAAO,GACdnB,OAAQmB,EAAO,GACfe,SAAUhB,EACV8B,KAAMT,GFlJY,MEsJbV,EAAmB,GAAGV,EAAO,MAAMA,EAAO,KAAOA,EAAO8B,KAAKpB,EACrE,CA4BO,SAAS8C,GAASzE,KACxBA,GAAO,EAAKoB,IACZA,GAAM,EAAKC,KACXA,GAAO,EAAEC,MACTA,EAAQ,EAACC,OACTA,EAASC,GAAKC,cACdA,EAAgB,CAAA,EAAEC,UAClBA,EAAYF,GAAKG,OACjBA,EF3LoB,IE2LNC,QACdA,EAAU,CAAA,EAAEC,SACZA,EAAWL,GAAKM,OAChBA,EAASpC,EAAMS,SACfA,GAAW,EAAK4B,UAChBA,EAAY,GAAEC,SACdA,GAAW,EAAEC,eACbA,EAAiBrC,EAAKsC,UACtBA,EAAY,GACT,IACH,OAAOf,GAAOD,EAASC,EAAK,CAC3BnB,OACAoB,MACAC,OACAC,QACAC,SACAE,gBACAC,YACAC,SACAC,UACAC,WACAC,SACA3B,WACA4B,YACAC,WACAC,iBACAC,aAEF,QAAAhB,cAAAuD"} \ No newline at end of file diff --git a/dist/filesize.umd.js b/dist/filesize.umd.js index fa6522d..87417aa 100644 --- a/dist/filesize.umd.js +++ b/dist/filesize.umd.js @@ -3,7 +3,7 @@ * * @copyright 2025 Jason Mulligan * @license BSD-3-Clause - * @version 11.0.10 + * @version 11.0.11 */ (function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports):typeof define==='function'&&define.amd?define(['exports'],f):(g=typeof globalThis!=='undefined'?globalThis:g||self,f(g.filesize={}));})(this,(function(exports){'use strict';// Error Messages const INVALID_NUMBER = "Invalid number"; @@ -85,7 +85,162 @@ const DECIMAL_POWERS = [ // Pre-computed log values for faster exponent calculation const LOG_2_1024 = Math.log(1024); -const LOG_10_1000 = Math.log(1000);/** +const LOG_10_1000 = Math.log(1000);// Cached configuration lookup for better performance +const STANDARD_CONFIGS = { + [SI]: {isDecimal: true, ceil: 1000, actualStandard: JEDEC}, + [IEC]: {isDecimal: false, ceil: 1024, actualStandard: IEC}, + [JEDEC]: {isDecimal: false, ceil: 1024, actualStandard: JEDEC} +}; + +/** + * Optimized base configuration lookup + * @param {string} standard - Standard type + * @param {number} base - Base number + * @returns {Object} Configuration object + */ +function getBaseConfiguration (standard, base) { + // Use cached lookup table for better performance + if (STANDARD_CONFIGS[standard]) { + return STANDARD_CONFIGS[standard]; + } + + // Base override + if (base === 2) { + return {isDecimal: false, ceil: 1024, actualStandard: IEC}; + } + + // Default + return {isDecimal: true, ceil: 1000, actualStandard: JEDEC}; +} + +/** + * Optimized zero value handling + * @param {number} precision - Precision value + * @param {string} actualStandard - Standard to use + * @param {boolean} bits - Whether to use bits + * @param {Object} symbols - Custom symbols + * @param {boolean} full - Whether to use full form + * @param {Array} fullforms - Custom full forms + * @param {string} output - Output format + * @param {string} spacer - Spacer character + * @returns {string|Array|Object|number} Formatted result + */ +function handleZeroValue (precision, actualStandard, bits, symbols, full, fullforms, output, spacer) { + const result = []; + result[0] = precision > 0 ? (0).toPrecision(precision) : 0; + const u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; + + if (output === EXPONENT) { + return 0; + } + + // Apply symbol customization + if (symbols[result[1]]) { + result[1] = symbols[result[1]]; + } + + // Apply full form + if (full) { + result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); + } + + // Return in requested format + return output === ARRAY ? result : output === OBJECT ? { + value: result[0], + symbol: result[1], + exponent: 0, + unit: u + } : result.join(spacer); +} + +/** + * Optimized value calculation with bits handling + * @param {number} num - Input number + * @param {number} e - Exponent + * @param {boolean} isDecimal - Whether to use decimal powers + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @returns {Object} Object with val and e properties + */ +function calculateOptimizedValue (num, e, isDecimal, bits, ceil) { + const d = isDecimal ? DECIMAL_POWERS[e] : BINARY_POWERS[e]; + let result = num / d; + + if (bits) { + result *= 8; + // Handle auto-increment for bits + if (result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return {result, e}; +} + +/** + * Optimized precision handling with scientific notation correction + * @param {number} value - Current value + * @param {number} precision - Precision to apply + * @param {number} e - Current exponent + * @param {number} num - Original number + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether calculating bits + * @param {number} ceil - Ceiling value + * @param {Function} roundingFunc - Rounding function + * @param {number} round - Round value + * @returns {Object} Object with value and e properties + */ +function applyPrecisionHandling (value, precision, e, num, isDecimal, bits, ceil, roundingFunc, round) { + let result = value.toPrecision(precision); + + // Handle scientific notation by recalculating with incremented exponent + if (result.includes(E) && e < 8) { + e++; + const {result: valueResult} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + const p = round > 0 ? Math.pow(10, round) : 1; + result = (p === 1 ? roundingFunc(valueResult) : roundingFunc(valueResult * p) / p).toPrecision(precision); + } + + return {value: result, e}; +} + +/** + * Optimized number formatting with locale, separator, and padding + * @param {number|string} value - Value to format + * @param {string|boolean} locale - Locale setting + * @param {Object} localeOptions - Locale options + * @param {string} separator - Custom separator + * @param {boolean} pad - Whether to pad + * @param {number} round - Round value + * @returns {string|number} Formatted value + */ +function applyNumberFormatting (value, locale, localeOptions, separator, pad, round) { + let result = value; + + // Apply locale formatting + if (locale === true) { + result = result.toLocaleString(); + } else if (locale.length > 0) { + result = result.toLocaleString(locale, localeOptions); + } else if (separator.length > 0) { + result = result.toString().replace(PERIOD, separator); + } + + // Apply padding + if (pad && round > 0) { + const resultStr = result.toString(); + const x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD); + const tmp = resultStr.split(x); + const s = tmp[1] || EMPTY; + const l = s.length; + const n = round - l; + + result = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; + } + + return result; +}/** * Converts a file size in bytes to a human-readable string with appropriate units * @param {number|string|bigint} arg - The file size in bytes to convert * @param {Object} [options={}] - Configuration options for formatting @@ -136,29 +291,8 @@ function filesize (arg, { val = 0, u = EMPTY; - // Optimized base & standard synchronization with early returns - let isDecimal, ceil, actualStandard; - if (standard === SI) { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } else if (standard === IEC) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else if (standard === JEDEC) { - isDecimal = false; // JEDEC uses binary (1024) by default - ceil = 1024; - actualStandard = JEDEC; - } else if (base === 2) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } + // Optimized base & standard configuration lookup + const {isDecimal, ceil, actualStandard} = getBaseConfiguration(standard, base); const full = fullform === true, neg = num < 0, @@ -179,38 +313,12 @@ function filesize (arg, { // Fast path for zero if (num === 0) { - result[0] = precision > 0 ? (0).toPrecision(precision) : 0; - u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; - - if (output === EXPONENT) { - return 0; - } - - // Skip most processing for zero case - if (symbols[result[1]]) { - result[1] = symbols[result[1]]; - } - - if (full) { - result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); - } - - return output === ARRAY ? result : output === OBJECT ? { - value: result[0], - symbol: result[1], - exponent: 0, - unit: u - } : result.join(spacer); + return handleZeroValue(precision, actualStandard, bits, symbols, full, fullforms, output, spacer); } // Optimized exponent calculation using pre-computed log values if (e === -1 || isNaN(e)) { - if (isDecimal) { - e = Math.floor(Math.log(num) / LOG_10_1000); - } else { - e = Math.floor(Math.log(num) / LOG_2_1024); - } - + e = isDecimal ? Math.floor(Math.log(num) / LOG_10_1000) : Math.floor(Math.log(num) / LOG_2_1024); if (e < 0) { e = 0; } @@ -228,24 +336,10 @@ function filesize (arg, { return e; } - // Use pre-computed lookup tables (e is always <= 8, arrays have 9 elements) - let d; - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - - val = num / d; - - if (bits) { - val = val * 8; - - if (val >= ceil && e < 8) { - val = val / ceil; - e++; - } - } + // Calculate value with optimized lookup and bits handling + const {result: valueResult, e: valueExponent} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + val = valueResult; + e = valueExponent; // Optimize rounding calculation const p = e > 0 && round > 0 ? Math.pow(10, round) : 1; @@ -256,21 +350,11 @@ function filesize (arg, { e++; } - // Setting optional precision + // Apply precision handling if (precision > 0) { - result[0] = result[0].toPrecision(precision); - - if (result[0].includes(E) && e < 8) { - e++; - // Recalculate with new exponent (e is always <= 8) - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - val = num / d; - result[0] = (p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p).toPrecision(precision); - } + const precisionResult = applyPrecisionHandling(result[0], precision, e, num, isDecimal, bits, ceil, roundingFunc, round); + result[0] = precisionResult.value; + e = precisionResult.e; } // Cache symbol lookup @@ -287,25 +371,8 @@ function filesize (arg, { result[1] = symbols[result[1]]; } - // Optimized locale/separator handling - if (locale === true) { - result[0] = result[0].toLocaleString(); - } else if (locale.length > 0) { - result[0] = result[0].toLocaleString(locale, localeOptions); - } else if (separator.length > 0) { - result[0] = result[0].toString().replace(PERIOD, separator); - } - - if (pad && round > 0) { - const resultStr = result[0].toString(), - x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD), - tmp = resultStr.split(x), - s = tmp[1] || EMPTY, - l = s.length, - n = round - l; - - result[0] = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; - } + // Apply locale, separator, and padding formatting + result[0] = applyNumberFormatting(result[0], locale, localeOptions, separator, pad, round); if (full) { result[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S); @@ -315,7 +382,7 @@ function filesize (arg, { if (output === ARRAY) { return result; } - + if (output === OBJECT) { return { value: result[0], @@ -324,7 +391,7 @@ function filesize (arg, { unit: u }; } - + return spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer); } diff --git a/dist/filesize.umd.min.js b/dist/filesize.umd.min.js index 4edda17..914f6cf 100644 --- a/dist/filesize.umd.min.js +++ b/dist/filesize.umd.min.js @@ -1,5 +1,5 @@ /*! 2025 Jason Mulligan - @version 11.0.10 + @version 11.0.11 */ -!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="iec",i="jedec",o="bits",n="byte",r="bytes",l="array",s="object",a="string",b="exponent",f="round",p="",u={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"]}},c=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],d=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],m=Math.log(1024),g=Math.log(1e3);function y(t,{bits:y=!1,pad:h=!1,base:B=-1,round:M=2,locale:x="",localeOptions:T={},separator:j="",spacer:E=" ",symbols:P={},standard:w="",output:N=a,fullform:$=!1,fullforms:k=[],exponent:v=-1,roundingMethod:z=f,precision:G=0}={}){let K,S,Y,Z=v,O=Number(t),I=[],L=0,D=p;"si"===w?(K=!0,S=1e3,Y=i):w===e?(K=!1,S=1024,Y=e):w===i?(K=!1,S=1024,Y=i):2===B?(K=!1,S=1024,Y=e):(K=!0,S=1e3,Y=i);const q=!0===$,A=O<0,C=Math[z];if("bigint"!=typeof t&&isNaN(t))throw new TypeError("Invalid number");if("function"!=typeof C)throw new TypeError("Invalid rounding method");if(A&&(O=-O),0===O)return I[0]=G>0?(0).toPrecision(G):0,D=I[1]=u.symbol[Y][y?o:r][0],N===b?0:(P[I[1]]&&(I[1]=P[I[1]]),q&&(I[1]=k[0]||u.fullform[Y][0]+(y?"bit":n)),N===l?I:N===s?{value:I[0],symbol:I[1],exponent:0,unit:D}:I.join(E));if((-1===Z||isNaN(Z))&&(Z=K?Math.floor(Math.log(O)/g):Math.floor(Math.log(O)/m),Z<0&&(Z=0)),Z>8&&(G>0&&(G+=8-Z),Z=8),N===b)return Z;let F;F=K?d[Z]:c[Z],L=O/F,y&&(L*=8,L>=S&&Z<8&&(L/=S,Z++));const H=Z>0&&M>0?Math.pow(10,M):1;I[0]=1===H?C(L):C(L*H)/H,I[0]===S&&Z<8&&-1===v&&(I[0]=1,Z++),G>0&&(I[0]=I[0].toPrecision(G),I[0].includes("e")&&Z<8&&(Z++,F=K?d[Z]:c[Z],L=O/F,I[0]=(1===H?C(L):C(L*H)/H).toPrecision(G)));const J=u.symbol[Y][y?o:r];if(D=I[1]=K&&1===Z?y?"kbit":"kB":J[Z],A&&(I[0]=-I[0]),P[I[1]]&&(I[1]=P[I[1]]),!0===x?I[0]=I[0].toLocaleString():x.length>0?I[0]=I[0].toLocaleString(x,T):j.length>0&&(I[0]=I[0].toString().replace(".",j)),h&&M>0){const t=I[0].toString(),e=j||(t.match(/(\D)/g)||[]).pop()||".",i=t.split(e),o=i[1]||p,n=o.length,r=M-n;I[0]=`${i[0]}${e}${o.padEnd(n+r,"0")}`}return q&&(I[1]=k[Z]||u.fullform[Y][Z]+(y?"bit":n)+(1===I[0]?p:"s")),N===l?I:N===s?{value:I[0],symbol:I[1],exponent:Z,unit:D}:" "===E?`${I[0]} ${I[1]}`:I.join(E)}t.filesize=y,t.partial=function({bits:t=!1,pad:e=!1,base:i=-1,round:o=2,locale:n="",localeOptions:r={},separator:l="",spacer:s=" ",symbols:b={},standard:p="",output:u=a,fullform:c=!1,fullforms:d=[],exponent:m=-1,roundingMethod:g=f,precision:h=0}={}){return a=>y(a,{bits:t,pad:e,base:i,round:o,locale:n,localeOptions:r,separator:l,spacer:s,symbols:b,standard:p,output:u,fullform:c,fullforms:d,exponent:m,roundingMethod:g,precision:h})}});//# 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="iec",i="jedec",n="si",o="bits",a="byte",r="bytes",s="array",l="object",u="string",c="exponent",b="round",d={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"]}},f=[1,1024,1048576,1073741824,1099511627776,0x4000000000000,0x1000000000000000,11805916207174113e5,12089258196146292e8],p=[1,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24],m=Math.log(1024),y=Math.log(1e3),B={[n]:{isDecimal:!0,ceil:1e3,actualStandard:i},[e]:{isDecimal:!1,ceil:1024,actualStandard:e},[i]:{isDecimal:!1,ceil:1024,actualStandard:i}};function h(t,e,i,n,o){let a=t/(i?p[e]:f[e]);return n&&(a*=8,a>=o&&e<8&&(a/=o,e++)),{result:a,e:e}}function M(t,{bits:n=!1,pad:f=!1,base:p=-1,round:M=2,locale:g="",localeOptions:x={},separator:T="",spacer:D=" ",symbols:E={},standard:S="",output:j=u,fullform:v=!1,fullforms:N=[],exponent:$=-1,roundingMethod:k=b,precision:w=0}={}){let G=$,K=Number(t),P=[],Y=0,Z="";const{isDecimal:O,ceil:z,actualStandard:I}=function(t,n){return B[t]?B[t]:2===n?{isDecimal:!1,ceil:1024,actualStandard:e}:{isDecimal:!0,ceil:1e3,actualStandard:i}}(S,p),q=!0===v,A=K<0,C=Math[k];if("bigint"!=typeof t&&isNaN(t))throw new TypeError("Invalid number");if("function"!=typeof C)throw new TypeError("Invalid rounding method");if(A&&(K=-K),0===K)return function(t,e,i,n,u,b,f,p){const m=[];m[0]=t>0?(0).toPrecision(t):0;const y=m[1]=d.symbol[e][i?o:r][0];return f===c?0:(n[m[1]]&&(m[1]=n[m[1]]),u&&(m[1]=b[0]||d.fullform[e][0]+(i?"bit":a)),f===s?m:f===l?{value:m[0],symbol:m[1],exponent:0,unit:y}:m.join(p))}(w,I,n,E,q,N,j,D);if((-1===G||isNaN(G))&&(G=O?Math.floor(Math.log(K)/y):Math.floor(Math.log(K)/m),G<0&&(G=0)),G>8&&(w>0&&(w+=8-G),G=8),j===c)return G;const{result:F,e:H}=h(K,G,O,n,z);Y=F,G=H;const J=G>0&&M>0?Math.pow(10,M):1;if(P[0]=1===J?C(Y):C(Y*J)/J,P[0]===z&&G<8&&-1===$&&(P[0]=1,G++),w>0){const t=function(t,e,i,n,o,a,r,s,l){let u=t.toPrecision(e);if(u.includes("e")&&i<8){i++;const{result:t}=h(n,i,o,a,r),c=l>0?Math.pow(10,l):1;u=(1===c?s(t):s(t*c)/c).toPrecision(e)}return{value:u,e:i}}(P[0],w,G,K,O,n,z,C,M);P[0]=t.value,G=t.e}const L=d.symbol[I][n?o:r];return Z=P[1]=O&&1===G?n?"kbit":"kB":L[G],A&&(P[0]=-P[0]),E[P[1]]&&(P[1]=E[P[1]]),P[0]=function(t,e,i,n,o,a){let r=t;if(!0===e?r=r.toLocaleString():e.length>0?r=r.toLocaleString(e,i):n.length>0&&(r=r.toString().replace(".",n)),o&&a>0){const t=r.toString(),e=n||(t.match(/(\D)/g)||[]).pop()||".",i=t.split(e),o=i[1]||"",s=o.length,l=a-s;r=`${i[0]}${e}${o.padEnd(s+l,"0")}`}return r}(P[0],g,x,T,f,M),q&&(P[1]=N[G]||d.fullform[I][G]+(n?"bit":a)+(1===P[0]?"":"s")),j===s?P:j===l?{value:P[0],symbol:P[1],exponent:G,unit:Z}:" "===D?`${P[0]} ${P[1]}`:P.join(D)}t.filesize=M,t.partial=function({bits:t=!1,pad:e=!1,base:i=-1,round:n=2,locale:o="",localeOptions:a={},separator:r="",spacer:s=" ",symbols:l={},standard:c="",output:d=u,fullform:f=!1,fullforms:p=[],exponent:m=-1,roundingMethod:y=b,precision:B=0}={}){return u=>M(u,{bits:t,pad:e,base:i,round:n,locale:o,localeOptions:a,separator:r,spacer:s,symbols:l,standard:c,output:d,fullform:f,fullforms:p,exponent:m,roundingMethod:y,precision:B})}});//# sourceMappingURL=filesize.umd.min.js.map diff --git a/dist/filesize.umd.min.js.map b/dist/filesize.umd.min.js.map index 3cd0679..f3241d1 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/filesize.js"],"sourcesContent":["// Error Messages\nexport const INVALID_NUMBER = \"Invalid number\";\nexport const INVALID_ROUND = \"Invalid rounding method\";\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\tFUNCTION,\n\tIEC,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tJEDEC,\n\tLOG_2_1024,\n\tLOG_10_1000,\n\tOBJECT,\n\tPERIOD,\n\tROUND,\n\tS,\n\tSI,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n\tZERO\n} from \"./constants.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 or roundingMethod is invalid\n * @example\n * filesize(1024) // \"1 KB\"\n * filesize(1024, {bits: true}) // \"8 Kb\"\n * filesize(1024, {output: \"object\"}) // {value: 1, symbol: \"KB\", exponent: 1, unit: \"KB\"}\n */\nexport function filesize (arg, {\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\tlet e = exponent,\n\t\tnum = Number(arg),\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\t// Optimized base & standard synchronization with early returns\n\tlet isDecimal, ceil, actualStandard;\n\tif (standard === SI) {\n\t\tisDecimal = true;\n\t\tceil = 1000;\n\t\tactualStandard = JEDEC;\n\t} else if (standard === IEC) {\n\t\tisDecimal = false;\n\t\tceil = 1024;\n\t\tactualStandard = IEC;\n\t} else if (standard === JEDEC) {\n\t\tisDecimal = false; // JEDEC uses binary (1024) by default\n\t\tceil = 1024;\n\t\tactualStandard = JEDEC;\n\t} else if (base === 2) {\n\t\tisDecimal = false;\n\t\tceil = 1024;\n\t\tactualStandard = IEC;\n\t} else {\n\t\tisDecimal = true;\n\t\tceil = 1000;\n\t\tactualStandard = JEDEC;\n\t}\n\n\tconst full = fullform === true,\n\t\tneg = num < 0,\n\t\troundingFunc = Math[roundingMethod];\n\n\tif (typeof arg !== \"bigint\" && isNaN(arg)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\t// Flipping a negative number to determine the size\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\t// Fast path for zero\n\tif (num === 0) {\n\t\tresult[0] = precision > 0 ? (0).toPrecision(precision) : 0;\n\t\tu = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0];\n\t\t\n\t\tif (output === EXPONENT) {\n\t\t\treturn 0;\n\t\t}\n\t\t\n\t\t// Skip most processing for zero case\n\t\tif (symbols[result[1]]) {\n\t\t\tresult[1] = symbols[result[1]];\n\t\t}\n\t\t\n\t\tif (full) {\n\t\t\tresult[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE);\n\t\t}\n\t\t\n\t\treturn output === ARRAY ? result : output === OBJECT ? {\n\t\t\tvalue: result[0],\n\t\t\tsymbol: result[1],\n\t\t\texponent: 0,\n\t\t\tunit: u\n\t\t} : result.join(spacer);\n\t}\n\n\t// Optimized exponent calculation using pre-computed log values\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\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t}\n\n\t// Exceeding supported length, time to reduce & multiply\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\te = 8;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\t// Use pre-computed lookup tables (e is always <= 8, arrays have 9 elements)\n\tlet d;\n\tif (isDecimal) {\n\t\td = DECIMAL_POWERS[e];\n\t} else {\n\t\td = BINARY_POWERS[e];\n\t}\n\t\n\tval = num / d;\n\n\tif (bits) {\n\t\tval = val * 8;\n\n\t\tif (val >= ceil && e < 8) {\n\t\t\tval = val / ceil;\n\t\t\te++;\n\t\t}\n\t}\n\n\t// Optimize rounding calculation\n\tconst p = e > 0 && round > 0 ? Math.pow(10, round) : 1;\n\tresult[0] = p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p;\n\n\tif (result[0] === ceil && e < 8 && exponent === -1) {\n\t\tresult[0] = 1;\n\t\te++;\n\t}\n\n\t// Setting optional precision\n\tif (precision > 0) {\n\t\tresult[0] = result[0].toPrecision(precision);\n\n\t\tif (result[0].includes(E) && e < 8) {\n\t\t\te++;\n\t\t\t// Recalculate with new exponent (e is always <= 8)\n\t\t\tif (isDecimal) {\n\t\t\t\td = DECIMAL_POWERS[e];\n\t\t\t} else {\n\t\t\t\td = BINARY_POWERS[e];\n\t\t\t}\n\t\t\tval = num / d;\n\t\t\tresult[0] = (p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p).toPrecision(precision);\n\t\t}\n\t}\n\n\t// Cache symbol lookup\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tu = result[1] = (isDecimal && e === 1) ? (bits ? SI_KBIT : SI_KBYTE) : symbolTable[e];\n\n\t// Decorating a 'diff'\n\tif (neg) {\n\t\tresult[0] = -result[0];\n\t}\n\n\t// Applying custom symbol\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Optimized locale/separator handling\n\tif (locale === true) {\n\t\tresult[0] = result[0].toLocaleString();\n\t} else if (locale.length > 0) {\n\t\tresult[0] = result[0].toLocaleString(locale, localeOptions);\n\t} else if (separator.length > 0) {\n\t\tresult[0] = result[0].toString().replace(PERIOD, separator);\n\t}\n\n\tif (pad && round > 0) {\n\t\tconst resultStr = result[0].toString(),\n\t\t\tx = separator || ((resultStr.match(/(\\D)/g) || []).pop() || PERIOD),\n\t\t\ttmp = resultStr.split(x),\n\t\t\ts = tmp[1] || EMPTY,\n\t\t\tl = s.length,\n\t\t\tn = round - l;\n\n\t\tresult[0] = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`;\n\t}\n\n\tif (full) {\n\t\tresult[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S);\n\t}\n\n\t// Optimized return logic\n\tif (output === ARRAY) {\n\t\treturn result;\n\t}\n\t\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\t\n\treturn spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Default options to apply to the returned function\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.0 KiB\"\n * formatBytes(2048) // \"2.0 KiB\"\n */\n// Partial application for functional programming\nexport function partial ({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\treturn arg => filesize(arg, {\n\t\tbits,\n\t\tpad,\n\t\tbase,\n\t\tround,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tspacer,\n\t\tsymbols,\n\t\tstandard,\n\t\toutput,\n\t\tfullform,\n\t\tfullforms,\n\t\texponent,\n\t\troundingMethod,\n\t\tprecision\n\t});\n}\n"],"names":["g","f","exports","module","define","amd","globalThis","self","filesize","this","IEC","JEDEC","BITS","BYTE","BYTES","ARRAY","OBJECT","STRING","EXPONENT","ROUND","EMPTY","STRINGS","symbol","iec","bits","bytes","jedec","fullform","BINARY_POWERS","DECIMAL_POWERS","LOG_2_1024","Math","log","LOG_10_1000","arg","pad","base","round","locale","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","isDecimal","ceil","actualStandard","e","num","Number","result","val","u","full","neg","roundingFunc","isNaN","TypeError","toPrecision","value","unit","join","floor","d","p","pow","includes","symbolTable","toLocaleString","length","toString","replace","resultStr","x","match","pop","tmp","split","s","l","n","padEnd","partial"],"mappings":"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"} \ No newline at end of file +{"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\";\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\tJEDEC,\n\tOBJECT,\n\tPERIOD,\n\tSI,\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 * @returns {string|Array|Object|number} Formatted result\n */\nexport function handleZeroValue (precision, actualStandard, bits, symbols, full, fullforms, output, spacer) {\n\tconst result = [];\n\tresult[0] = precision > 0 ? (0).toPrecision(precision) : 0;\n\tconst u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0];\n\n\tif (output === EXPONENT) {\n\t\treturn 0;\n\t}\n\n\t// Apply symbol customization\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Apply full form\n\tif (full) {\n\t\tresult[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE);\n\t}\n\n\t// Return in requested format\n\treturn output === ARRAY ? result : output === OBJECT ? {\n\t\tvalue: result[0],\n\t\tsymbol: result[1],\n\t\texponent: 0,\n\t\tunit: u\n\t} : result.join(spacer);\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 * @returns {Object} Object with val and e properties\n */\nexport function calculateOptimizedValue (num, e, isDecimal, bits, ceil) {\n\tconst d = isDecimal ? DECIMAL_POWERS[e] : BINARY_POWERS[e];\n\tlet result = num / d;\n\n\tif (bits) {\n\t\tresult *= 8;\n\t\t// Handle auto-increment for bits\n\t\tif (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 * @returns {Object} Object with value and e properties\n */\nexport function applyPrecisionHandling (value, precision, e, num, isDecimal, bits, ceil, roundingFunc, round) {\n\tlet result = value.toPrecision(precision);\n\n\t// Handle scientific notation by recalculating with incremented exponent\n\tif (result.includes(E) && e < 8) {\n\t\te++;\n\t\tconst {result: valueResult} = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\t\tconst p = round > 0 ? Math.pow(10, round) : 1;\n\t\tresult = (p === 1 ? roundingFunc(valueResult) : roundingFunc(valueResult * p) / p).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 (value, locale, localeOptions, separator, pad, round) {\n\tlet result = value;\n\n\t// Apply locale formatting\n\tif (locale === true) {\n\t\tresult = result.toLocaleString();\n\t} else if (locale.length > 0) {\n\t\tresult = result.toLocaleString(locale, localeOptions);\n\t} else if (separator.length > 0) {\n\t\tresult = result.toString().replace(PERIOD, separator);\n\t}\n\n\t// Apply padding\n\tif (pad && round > 0) {\n\t\tconst resultStr = result.toString();\n\t\tconst x = separator || ((resultStr.match(/(\\D)/g) || []).pop() || PERIOD);\n\t\tconst tmp = resultStr.split(x);\n\t\tconst s = tmp[1] || EMPTY;\n\t\tconst l = s.length;\n\t\tconst n = round - l;\n\n\t\tresult = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`;\n\t}\n\n\treturn result;\n}\n","import {\n\tARRAY,\n\tBIT,\n\tBITS,\n\tBYTE,\n\tBYTES,\n\tEMPTY,\n\tEXPONENT,\n\tFUNCTION,\n\tINVALID_NUMBER,\n\tINVALID_ROUND,\n\tLOG_10_1000,\n\tLOG_2_1024,\n\tOBJECT,\n\tROUND,\n\tS,\n\tSI_KBIT,\n\tSI_KBYTE,\n\tSPACE,\n\tSTRING,\n\tSTRINGS,\n} from \"./constants.js\";\nimport {\n\tapplyNumberFormatting,\n\tapplyPrecisionHandling,\n\tcalculateOptimizedValue,\n\tgetBaseConfiguration,\n\thandleZeroValue\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 or roundingMethod is invalid\n * @example\n * filesize(1024) // \"1 KB\"\n * filesize(1024, {bits: true}) // \"8 Kb\"\n * filesize(1024, {output: \"object\"}) // {value: 1, symbol: \"KB\", exponent: 1, unit: \"KB\"}\n */\nexport function filesize (arg, {\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\tlet e = exponent,\n\t\tnum = Number(arg),\n\t\tresult = [],\n\t\tval = 0,\n\t\tu = EMPTY;\n\n\t// Optimized base & standard configuration lookup\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 arg !== \"bigint\" && isNaN(arg)) {\n\t\tthrow new TypeError(INVALID_NUMBER);\n\t}\n\n\tif (typeof roundingFunc !== FUNCTION) {\n\t\tthrow new TypeError(INVALID_ROUND);\n\t}\n\n\t// Flipping a negative number to determine the size\n\tif (neg) {\n\t\tnum = -num;\n\t}\n\n\t// Fast path for zero\n\tif (num === 0) {\n\t\treturn handleZeroValue(precision, actualStandard, bits, symbols, full, fullforms, output, spacer);\n\t}\n\n\t// Optimized exponent calculation using pre-computed log values\n\tif (e === -1 || isNaN(e)) {\n\t\te = isDecimal ? Math.floor(Math.log(num) / LOG_10_1000) : Math.floor(Math.log(num) / LOG_2_1024);\n\t\tif (e < 0) {\n\t\t\te = 0;\n\t\t}\n\t}\n\n\t// Exceeding supported length, time to reduce & multiply\n\tif (e > 8) {\n\t\tif (precision > 0) {\n\t\t\tprecision += 8 - e;\n\t\t}\n\t\te = 8;\n\t}\n\n\tif (output === EXPONENT) {\n\t\treturn e;\n\t}\n\n\t// Calculate value with optimized lookup and bits handling\n\tconst {result: valueResult, e: valueExponent} = calculateOptimizedValue(num, e, isDecimal, bits, ceil);\n\tval = valueResult;\n\te = valueExponent;\n\n\t// Optimize rounding calculation\n\tconst p = e > 0 && round > 0 ? Math.pow(10, round) : 1;\n\tresult[0] = p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p;\n\n\tif (result[0] === ceil && e < 8 && exponent === -1) {\n\t\tresult[0] = 1;\n\t\te++;\n\t}\n\n\t// Apply precision handling\n\tif (precision > 0) {\n\t\tconst precisionResult = applyPrecisionHandling(result[0], precision, e, num, isDecimal, bits, ceil, roundingFunc, round);\n\t\tresult[0] = precisionResult.value;\n\t\te = precisionResult.e;\n\t}\n\n\t// Cache symbol lookup\n\tconst symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];\n\tu = result[1] = (isDecimal && e === 1) ? (bits ? SI_KBIT : SI_KBYTE) : symbolTable[e];\n\n\t// Decorating a 'diff'\n\tif (neg) {\n\t\tresult[0] = -result[0];\n\t}\n\n\t// Applying custom symbol\n\tif (symbols[result[1]]) {\n\t\tresult[1] = symbols[result[1]];\n\t}\n\n\t// Apply locale, separator, and padding formatting\n\tresult[0] = applyNumberFormatting(result[0], locale, localeOptions, separator, pad, round);\n\n\tif (full) {\n\t\tresult[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S);\n\t}\n\n\t// Optimized return logic\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\treturn spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer);\n}\n\n/**\n * Creates a partially applied version of filesize with preset options\n * @param {Object} [options={}] - Default options to apply to the returned function\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.0 KiB\"\n * formatBytes(2048) // \"2.0 KiB\"\n */\n// Partial application for functional programming\nexport function partial ({\n\tbits = false,\n\tpad = false,\n\tbase = -1,\n\tround = 2,\n\tlocale = EMPTY,\n\tlocaleOptions = {},\n\tseparator = EMPTY,\n\tspacer = SPACE,\n\tsymbols = {},\n\tstandard = EMPTY,\n\toutput = STRING,\n\tfullform = false,\n\tfullforms = [],\n\texponent = -1,\n\troundingMethod = ROUND,\n\tprecision = 0\n} = {}) {\n\treturn arg => filesize(arg, {\n\t\tbits,\n\t\tpad,\n\t\tbase,\n\t\tround,\n\t\tlocale,\n\t\tlocaleOptions,\n\t\tseparator,\n\t\tspacer,\n\t\tsymbols,\n\t\tstandard,\n\t\toutput,\n\t\tfullform,\n\t\tfullforms,\n\t\texponent,\n\t\troundingMethod,\n\t\tprecision\n\t});\n}\n"],"names":["g","f","exports","module","define","amd","globalThis","self","filesize","this","IEC","JEDEC","SI","BITS","BYTE","BYTES","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","result","arg","pad","base","round","locale","EMPTY","localeOptions","separator","spacer","symbols","standard","output","fullforms","exponent","roundingMethod","precision","Number","val","u","getBaseConfiguration","full","neg","roundingFunc","isNaN","TypeError","toPrecision","value","unit","join","handleZeroValue","floor","valueResult","valueExponent","p","pow","precisionResult","includes","applyPrecisionHandling","symbolTable","toLocaleString","length","toString","replace","resultStr","x","match","pop","tmp","split","s","l","n","padEnd","applyNumberFormatting","partial"],"mappings":"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"} \ No newline at end of file diff --git a/docs/TECHNICAL_DOCUMENTATION.md b/docs/TECHNICAL_DOCUMENTATION.md index 7ec927e..963856a 100644 --- a/docs/TECHNICAL_DOCUMENTATION.md +++ b/docs/TECHNICAL_DOCUMENTATION.md @@ -106,14 +106,18 @@ The filesize.js library implements several mathematical algorithms to convert ra The basic conversion from bytes to higher-order units follows the general formula: ```math -\text{value} = \frac{\text{bytes}}{\text{base}^{\text{exponent}}} +\text{value} = \frac{\text{bytes}}{\text{divisor}[\text{exponent}]} ``` Where: - $\text{bytes}$ is the input byte value -- $\text{base}$ is either 2 (binary) or 10 (decimal) depending on the standard +- $\text{divisor}[\text{exponent}]$ is a pre-computed lookup table value - $\text{exponent}$ determines the unit scale (0=bytes, 1=KB/KiB, 2=MB/MiB, etc.) +**Implementation Note**: For performance optimization, the library uses pre-computed lookup tables (`BINARY_POWERS` and `DECIMAL_POWERS`) instead of calculating powers at runtime: +- Binary: `[1, 1024, 1048576, 1073741824, ...]` (powers of 1024) +- Decimal: `[1, 1000, 1000000, 1000000000, ...]` (powers of 1000) + ### Exponent Calculation The appropriate exponent for automatic unit selection is calculated using logarithms: @@ -137,32 +141,47 @@ Where: ### Binary vs Decimal Standards #### Binary Standard (IEC) -Uses powers of 2 with base 1024: +Uses pre-computed powers of 1024: ```math -\text{value} = \frac{\text{bytes}}{2^{10 \cdot e}} = \frac{\text{bytes}}{1024^e} +\text{value} = \frac{\text{bytes}}{\text{BINARY\_POWERS}[e]} ``` +Where `BINARY_POWERS[e] = 1024^e` for efficiency. + Units: B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB -#### Decimal Standard (SI) -Uses powers of 10 with base 1000: +#### Decimal Standard (SI/JEDEC) +Uses pre-computed powers of 1000: ```math -\text{value} = \frac{\text{bytes}}{10^{3 \cdot e}} = \frac{\text{bytes}}{1000^e} +\text{value} = \frac{\text{bytes}}{\text{DECIMAL\_POWERS}[e]} ``` +Where `DECIMAL_POWERS[e] = 1000^e` for efficiency. + Units: B, KB, MB, GB, TB, PB, EB, ZB, YB (uses JEDEC-style symbols) ### Bits Conversion -When converting to bits instead of bytes, the formula becomes: +When converting to bits instead of bytes, the implementation follows this sequence: + +1. First calculate the base value: $\text{value} = \frac{\text{bytes}}{\text{divisor}[e]}$ +2. Then multiply by 8: $\text{value}_{\text{bits}} = \text{value} \times 8$ +3. Check for overflow and auto-increment if needed +**Bits-Specific Overflow Handling**: ```math -\text{value}_{\text{bits}} = \frac{8 \cdot \text{bytes}}{\text{base}^e} +\text{if } \text{value}_{\text{bits}} \geq \text{ceil} \text{ and } e < 8 \text{ then:} +``` +```math +\begin{cases} +\text{value}_{\text{bits}} = \frac{\text{value}_{\text{bits}}}{\text{ceil}} \\ +e = e + 1 +\end{cases} ``` -This multiplication by 8 reflects the conversion from bytes to bits (1 byte = 8 bits). +This ensures proper unit progression for bit values (e.g., 8192 Kbit becomes 8 Mbit). ### Precision and Rounding @@ -182,14 +201,23 @@ When precision is specified ($p > 0$), the value is adjusted to show $p$ signifi \text{precise\_value} = \text{toPrecision}(\text{rounded\_value}, p) ``` -The precision parameter takes precedence over round when both are specified. If scientific notation results (contains 'E'), the exponent is incremented and the calculation is repeated to avoid exponential notation in output. +**Scientific Notation Avoidance**: If the precision formatting results in scientific notation (contains 'E') and $e < 8$, the algorithm: +1. Increments the exponent: $e = e + 1$ +2. Recalculates the value using the new exponent +3. Re-applies rounding and precision formatting +4. This ensures output remains in standard decimal notation + +The precision parameter takes precedence over round when both are specified. ### Overflow Handling -When a calculated value equals or exceeds the base threshold, the algorithm increments the exponent: +The library implements two distinct overflow handling mechanisms: + +#### 1. Main Flow Overflow (After Rounding) +When the rounded value exactly equals the ceiling value: ```math -\text{if } \text{value} \geq \text{base} \text{ and } e < 8 \text{ then:} +\text{if } \text{value} = \text{ceil} \text{ and } e < 8 \text{ and } \text{exponent} = -1 \text{ then:} ``` ```math \begin{cases} @@ -198,7 +226,22 @@ e = e + 1 \end{cases} ``` -This ensures proper unit progression (e.g., 1024 KB becomes 1 MB). +**Note**: This only applies when exponent is auto-calculated (`exponent = -1`), not when manually specified. + +#### 2. Bits-Specific Overflow (During Value Calculation) +For bits conversion, overflow is checked immediately after multiplication: + +```math +\text{if } \text{value}_{\text{bits}} \geq \text{ceil} \text{ and } e < 8 \text{ then:} +``` +```math +\begin{cases} +\text{value}_{\text{bits}} = \frac{\text{value}_{\text{bits}}}{\text{ceil}} \\ +e = e + 1 +\end{cases} +``` + +Both mechanisms ensure proper unit progression (e.g., 1024 KB becomes 1 MB). ### Exponent Boundary Conditions @@ -245,33 +288,35 @@ The algorithmic complexity of the conversion process is: ### Implementation Examples #### Default Conversion (1536 bytes) -Given: bytes = 1536, default settings (base = 10, JEDEC standard) +Given: bytes = 1536, default settings (decimal, JEDEC standard) -1. Calculate exponent: $e = \lfloor \log_{1000}(1536) \rfloor = \lfloor 1.062 \rfloor = 1$ -2. Calculate value: $\text{value} = \frac{1536}{1000^1} = 1.536$ -3. Apply rounding (2 decimal places): $1.536 \rightarrow 1.54$ -4. Result: "1.54 kB" +1. Calculate exponent: $e = \lfloor \frac{\ln(1536)}{\ln(1000)} \rfloor = \lfloor 1.062 \rfloor = 1$ +2. Lookup divisor: DECIMAL_POWERS[1] = 1000 +3. Calculate value: $value = \frac{1536}{1000} = 1.536$ +4. Apply rounding (2 decimal places): $1.536 \to 1.54$ +5. Result: "1.54 KB" #### Binary Conversion (1536 bytes) Given: bytes = 1536, base = 2 (IEC standard) -1. Calculate exponent: $e = \lfloor \log_{1024}(1536) \rfloor = \lfloor 1.084 \rfloor = 1$ -2. Calculate value: $\text{value} = \frac{1536}{1024^1} = 1.5$ -3. Result: "1.5 KiB" +1. Calculate exponent: $e = \lfloor \frac{\ln(1536)}{\ln(1024)} \rfloor = \lfloor 1.084 \rfloor = 1$ +2. Lookup divisor: BINARY_POWERS[1] = 1024 +3. Calculate value: $value = \frac{1536}{1024} = 1.5$ +4. Result: "1.5 KiB" #### Bits Conversion with Default Base (1024 bytes) Given: bytes = 1024, bits = true, default settings (base = 10) -1. Calculate exponent: $e = \lfloor \log_{1000}(1024) \rfloor = \lfloor 1.003 \rfloor = 1$ -2. Calculate value: $\text{value} = \frac{1024 \cdot 8}{1000^1} = 8.192$ -3. Apply rounding (2 decimal places): $8.192 \rightarrow 8.19$ +1. Calculate exponent: $e = \lfloor \frac{\ln(1024)}{\ln(1000)} \rfloor = \lfloor 1.003 \rfloor = 1$ +2. Calculate value: $value = \frac{1024 \times 8}{1000} = 8.192$ +3. Apply rounding (2 decimal places): $8.192 \to 8.19$ 4. Result: "8.19 kbit" #### Bits Conversion with Binary Base (1024 bytes) Given: bytes = 1024, bits = true, base = 2 -1. Calculate exponent: $e = \lfloor \log_{1024}(1024) \rfloor = 1$ -2. Calculate value: $\text{value} = \frac{1024 \cdot 8}{1024^1} = 8$ +1. Calculate exponent: $e = \lfloor \frac{\ln(1024)}{\ln(1024)} \rfloor = 1$ +2. Calculate value: $value = \frac{1024 \times 8}{1024} = 8$ 3. Result: "8 Kibit" ## Data Flow @@ -283,78 +328,85 @@ flowchart TD Start([Input: bytes, options]) --> Validate{Valid Input?} Validate -->|No| Error[Throw TypeError] - Validate -->|Yes| Normalize[Normalize Base & Standard] + Validate -->|Yes| ValidateRounding{Valid Rounding Method?} - Normalize --> CalcExp[Calculate Exponent] - CalcExp --> CheckExp{Exponent > 8?} - CheckExp -->|Yes| LimitExp[Limit to 8, Adjust Precision] - CheckExp -->|No| CheckZero{Input = 0?} - LimitExp --> CheckZero + ValidateRounding -->|No| Error + ValidateRounding -->|Yes| Normalize[Normalize Base & Standard] - CheckZero -->|Yes| ZeroCase[Set result = 0, unit = base unit] - CheckZero -->|No| Convert[Convert Value & Calculate Unit] + Normalize --> HandleNegative{Input < 0?} + HandleNegative -->|Yes| FlipSign[Store negative flag, use absolute value] + HandleNegative -->|No| CheckZero{Input = 0?} + FlipSign --> CheckZero - Convert --> CheckBits{Bits Mode?} - CheckBits -->|Yes| MultiplyBy8[Multiply by 8] - CheckBits -->|No| Round[Apply Rounding] - MultiplyBy8 --> Round + CheckZero -->|Yes| ZeroCase[Use handleZeroValue helper] + CheckZero -->|No| CalcExp[Calculate Exponent using logarithms] - Round --> CheckOverflow{Value >= ceil?} - CheckOverflow -->|Yes| Increment[Increment Exponent] - CheckOverflow -->|No| Format[Apply Formatting] - Increment --> Format + CalcExp --> CheckExp{Exponent > 8?} + CheckExp -->|Yes| LimitExp[Limit to 8, Adjust Precision] + CheckExp -->|No| CheckExpOutput{Output = 'exponent'?} + LimitExp --> CheckExpOutput + + CheckExpOutput -->|Yes| ReturnExp[Return exponent value] + CheckExpOutput -->|No| CalcValue[Calculate value using optimized lookup
Includes bits conversion if needed] - ZeroCase --> Format + CalcValue --> Round[Apply Rounding with power of 10] + Round --> CheckOverflow{Value >= ceil & e < 8?} + CheckOverflow -->|Yes| Increment[Set value=1, increment exponent] + CheckOverflow -->|No| CheckPrecision{Precision > 0?} + Increment --> CheckPrecision - Format --> Locale{Locale Set?} - Locale -->|Yes| LocaleFormat[Apply Locale Formatting] - Locale -->|No| Separator{Custom Separator?} - LocaleFormat --> Padding - Separator -->|Yes| CustomSep[Apply Custom Separator] - Separator -->|No| Padding{Padding Enabled?} - CustomSep --> Padding + CheckPrecision -->|Yes| ApplyPrecision[Apply precision handling
Handle scientific notation] + CheckPrecision -->|No| GetSymbol[Lookup symbol from table] + ApplyPrecision --> GetSymbol - Padding -->|Yes| PadDecimal[Pad Decimal Places] - Padding -->|No| FullForm{Full Form?} - PadDecimal --> FullForm + GetSymbol --> RestoreSign{Was negative?} + RestoreSign -->|Yes| ApplyNegative[Apply negative sign to value] + RestoreSign -->|No| CheckCustomSymbols{Custom symbols?} + ApplyNegative --> CheckCustomSymbols - FullForm -->|Yes| ExpandUnit[Use Full Unit Names] - FullForm -->|No| CustomSymbols{Custom Symbols?} - ExpandUnit --> CustomSymbols + CheckCustomSymbols -->|Yes| ApplySymbols[Apply custom symbols] + CheckCustomSymbols -->|No| FormatNumber[Apply number formatting
locale, separator, padding] + ApplySymbols --> FormatNumber - CustomSymbols -->|Yes| ApplySymbols[Apply Custom Symbols] - CustomSymbols -->|No| Output[Generate Output] - ApplySymbols --> Output + FormatNumber --> CheckFullForm{Full form enabled?} + CheckFullForm -->|Yes| ExpandUnit[Use full unit names] + CheckFullForm -->|No| GenerateOutput[Generate output based on format] + ExpandUnit --> GenerateOutput - Output --> Return([Return: Formatted Result]) + ZeroCase --> GenerateOutput + ReturnExp --> Return([Return: Formatted Result]) + GenerateOutput --> Return style Start fill:#166534,stroke:#15803d,stroke-width:2px,color:#ffffff style Error fill:#dc2626,stroke:#b91c1c,stroke-width:2px,color:#ffffff style Return fill:#1e40af,stroke:#1e3a8a,stroke-width:2px,color:#ffffff + style CalcValue fill:#7c2d12,stroke:#92400e,stroke-width:2px,color:#ffffff + style ApplyPrecision fill:#d97706,stroke:#b45309,stroke-width:2px,color:#ffffff ``` ### Standard Selection Logic ```mermaid flowchart TD - Input[Input: standard, base] --> CheckStandard{Standard = SI?} + Input[Input: standard, base] --> CheckCached{Standard in
cached configs?} - CheckStandard -->|Yes| SetDecimal[base = 10
standard = JEDEC] - CheckStandard -->|No| CheckIEC{Standard = IEC or JEDEC?} + CheckCached -->|Yes: SI| ReturnSI[isDecimal: true
ceil: 1000
actualStandard: JEDEC] + CheckCached -->|Yes: IEC| ReturnIEC[isDecimal: false
ceil: 1024
actualStandard: IEC] + CheckCached -->|Yes: JEDEC| ReturnJEDEC[isDecimal: false
ceil: 1024
actualStandard: JEDEC] + CheckCached -->|No| CheckBase{Base = 2?} - CheckIEC -->|Yes| SetBinary[base = 2] - CheckIEC -->|No| CheckBase{Base = 2?} + CheckBase -->|Yes| ReturnBase2[isDecimal: false
ceil: 1024
actualStandard: IEC] + CheckBase -->|No| ReturnDefault[isDecimal: true
ceil: 1000
actualStandard: JEDEC] - CheckBase -->|Yes| SetIEC[standard = IEC] - CheckBase -->|No| SetDefault[base = 10
standard = JEDEC] - - SetDecimal --> Result[Final: base, standard] - SetBinary --> Result - SetIEC --> Result - SetDefault --> Result + ReturnSI --> Result[Final Configuration] + ReturnIEC --> Result + ReturnJEDEC --> Result + ReturnBase2 --> Result + ReturnDefault --> Result style Input fill:#166534,stroke:#15803d,stroke-width:2px,color:#ffffff style Result fill:#1e40af,stroke:#1e3a8a,stroke-width:2px,color:#ffffff + style CheckCached fill:#7c2d12,stroke:#92400e,stroke-width:2px,color:#ffffff ``` ## API Reference @@ -755,23 +807,30 @@ export function SystemMetrics() { ```mermaid graph TB subgraph "Locale Processing" - A["Input Locale"] --> B{"Locale Type"} - B -->|"true"| C["System Locale"] - B -->|"string"| D["Specific Locale"] - B -->|"empty"| E["No Localization"] + A["Input: value, locale, localeOptions, separator, pad, round"] --> B{"Locale === true?"} + B -->|"Yes"| C["toLocaleString()"] + B -->|"No"| D{"Locale.length > 0?"} + + D -->|"Yes"| E["toLocaleString(locale, localeOptions)"] + D -->|"No"| F{"Separator.length > 0?"} - C --> F["navigator.language"] - D --> G["Custom Locale"] - F --> H["toLocaleString()"] - G --> H + F -->|"Yes"| G["toString().replace('.', separator)"] + F -->|"No"| H["Keep original value"] - H --> I["Formatted Number"] - E --> J["toString()"] - J --> K["Apply Custom Separator"] + C --> I["Check Padding"] + E --> I + G --> I + H --> I + + I --> J{"Pad enabled & round > 0?"} + J -->|"Yes"| K["Calculate decimal separator
Pad decimal places with zeros"] + J -->|"No"| L["Return formatted value"] + + K --> L end style A fill:#166534,stroke:#15803d,stroke-width:2px,color:#ffffff - style I fill:#1e40af,stroke:#1e3a8a,stroke-width:2px,color:#ffffff + style L fill:#1e40af,stroke:#1e3a8a,stroke-width:2px,color:#ffffff style K fill:#d97706,stroke:#b45309,stroke-width:2px,color:#ffffff ``` diff --git a/package-lock.json b/package-lock.json index c88b901..eb4f820 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,24 @@ { "name": "filesize", - "version": "11.0.10", + "version": "11.0.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "filesize", - "version": "11.0.10", + "version": "11.0.11", "license": "BSD-3-Clause", "devDependencies": { "@rollup/plugin-terser": "^0.4.4", "auto-changelog": "^2.5.0", "c8": "^10.1.3", - "eslint": "^9.30.1", + "eslint": "^9.36.0", "husky": "^9.1.7", "mocha": "^11.7.1", - "rollup": "^4.44.2" + "rollup": "^4.52.0" }, "engines": { - "node": ">= 10.4.0" + "node": ">= 10.8.0" } }, "node_modules/@bcoe/v8-coverage": { @@ -136,9 +136,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", "dev": true, "license": "MIT", "engines": { @@ -351,9 +351,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz", - "integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.0.tgz", + "integrity": "sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A==", "cpu": [ "arm" ], @@ -365,9 +365,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz", - "integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.0.tgz", + "integrity": "sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ==", "cpu": [ "arm64" ], @@ -379,9 +379,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz", - "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.0.tgz", + "integrity": "sha512-YCdWlY/8ltN6H78HnMsRHYlPiKvqKagBP1r+D7SSylxX+HnsgXGCmLiV3Y4nSyY9hW8qr8U9LDUx/Lo7M6MfmQ==", "cpu": [ "arm64" ], @@ -393,9 +393,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz", - "integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.0.tgz", + "integrity": "sha512-z4nw6y1j+OOSGzuVbSWdIp1IUks9qNw4dc7z7lWuWDKojY38VMWBlEN7F9jk5UXOkUcp97vA1N213DF+Lz8BRg==", "cpu": [ "x64" ], @@ -407,9 +407,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz", - "integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.0.tgz", + "integrity": "sha512-Q/dv9Yvyr5rKlK8WQJZVrp5g2SOYeZUs9u/t2f9cQ2E0gJjYB/BWoedXfUT0EcDJefi2zzVfhcOj8drWCzTviw==", "cpu": [ "arm64" ], @@ -421,9 +421,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz", - "integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.0.tgz", + "integrity": "sha512-kdBsLs4Uile/fbjZVvCRcKB4q64R+1mUq0Yd7oU1CMm1Av336ajIFqNFovByipciuUQjBCPMxwJhCgfG2re3rg==", "cpu": [ "x64" ], @@ -435,9 +435,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz", - "integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.0.tgz", + "integrity": "sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ==", "cpu": [ "arm" ], @@ -449,9 +449,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz", - "integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.0.tgz", + "integrity": "sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw==", "cpu": [ "arm" ], @@ -463,9 +463,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz", - "integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.0.tgz", + "integrity": "sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw==", "cpu": [ "arm64" ], @@ -477,9 +477,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz", - "integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.0.tgz", + "integrity": "sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw==", "cpu": [ "arm64" ], @@ -491,9 +491,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz", - "integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.0.tgz", + "integrity": "sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg==", "cpu": [ "loong64" ], @@ -505,9 +505,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz", - "integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.0.tgz", + "integrity": "sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw==", "cpu": [ "ppc64" ], @@ -519,9 +519,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz", - "integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.0.tgz", + "integrity": "sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ==", "cpu": [ "riscv64" ], @@ -533,9 +533,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz", - "integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.0.tgz", + "integrity": "sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw==", "cpu": [ "riscv64" ], @@ -547,9 +547,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz", - "integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.0.tgz", + "integrity": "sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg==", "cpu": [ "s390x" ], @@ -561,9 +561,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz", - "integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.0.tgz", + "integrity": "sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA==", "cpu": [ "x64" ], @@ -575,9 +575,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz", - "integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.0.tgz", + "integrity": "sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ==", "cpu": [ "x64" ], @@ -589,9 +589,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz", - "integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.0.tgz", + "integrity": "sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw==", "cpu": [ "arm64" ], @@ -603,9 +603,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz", - "integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.0.tgz", + "integrity": "sha512-YQugafP/rH0eOOHGjmNgDURrpYHrIX0yuojOI8bwCyXwxC9ZdTd3vYkmddPX0oHONLXu9Rb1dDmT0VNpjkzGGw==", "cpu": [ "arm64" ], @@ -617,9 +617,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz", - "integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.0.tgz", + "integrity": "sha512-zYdUYhi3Qe2fndujBqL5FjAFzvNeLxtIqfzNEVKD1I7C37/chv1VxhscWSQHTNfjPCrBFQMnynwA3kpZpZ8w4A==", "cpu": [ "ia32" ], @@ -630,10 +630,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.0.tgz", + "integrity": "sha512-fGk03kQylNaCOQ96HDMeT7E2n91EqvCDd3RwvT5k+xNdFCeMGnj5b5hEgTGrQuyidqSsD3zJDQ21QIaxXqTBJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz", - "integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.0.tgz", + "integrity": "sha512-6iKDCVSIUQ8jPMoIV0OytRKniaYyy5EbY/RRydmLW8ZR3cEBhxbWl5ro0rkUNe0ef6sScvhbY79HrjRm8i3vDQ==", "cpu": [ "x64" ], @@ -1107,9 +1121,9 @@ } }, "node_modules/eslint": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", - "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1119,7 +1133,7 @@ "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.35.0", + "@eslint/js": "9.36.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -2180,9 +2194,9 @@ } }, "node_modules/rollup": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz", - "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.0.tgz", + "integrity": "sha512-+IuescNkTJQgX7AkIDtITipZdIGcWF0pnVvZTWStiazUmcGA2ag8dfg0urest2XlXUi9kuhfQ+qmdc5Stc3z7g==", "dev": true, "license": "MIT", "dependencies": { @@ -2196,27 +2210,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.2", - "@rollup/rollup-android-arm64": "4.50.2", - "@rollup/rollup-darwin-arm64": "4.50.2", - "@rollup/rollup-darwin-x64": "4.50.2", - "@rollup/rollup-freebsd-arm64": "4.50.2", - "@rollup/rollup-freebsd-x64": "4.50.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.2", - "@rollup/rollup-linux-arm-musleabihf": "4.50.2", - "@rollup/rollup-linux-arm64-gnu": "4.50.2", - "@rollup/rollup-linux-arm64-musl": "4.50.2", - "@rollup/rollup-linux-loong64-gnu": "4.50.2", - "@rollup/rollup-linux-ppc64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-musl": "4.50.2", - "@rollup/rollup-linux-s390x-gnu": "4.50.2", - "@rollup/rollup-linux-x64-gnu": "4.50.2", - "@rollup/rollup-linux-x64-musl": "4.50.2", - "@rollup/rollup-openharmony-arm64": "4.50.2", - "@rollup/rollup-win32-arm64-msvc": "4.50.2", - "@rollup/rollup-win32-ia32-msvc": "4.50.2", - "@rollup/rollup-win32-x64-msvc": "4.50.2", + "@rollup/rollup-android-arm-eabi": "4.52.0", + "@rollup/rollup-android-arm64": "4.52.0", + "@rollup/rollup-darwin-arm64": "4.52.0", + "@rollup/rollup-darwin-x64": "4.52.0", + "@rollup/rollup-freebsd-arm64": "4.52.0", + "@rollup/rollup-freebsd-x64": "4.52.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.0", + "@rollup/rollup-linux-arm-musleabihf": "4.52.0", + "@rollup/rollup-linux-arm64-gnu": "4.52.0", + "@rollup/rollup-linux-arm64-musl": "4.52.0", + "@rollup/rollup-linux-loong64-gnu": "4.52.0", + "@rollup/rollup-linux-ppc64-gnu": "4.52.0", + "@rollup/rollup-linux-riscv64-gnu": "4.52.0", + "@rollup/rollup-linux-riscv64-musl": "4.52.0", + "@rollup/rollup-linux-s390x-gnu": "4.52.0", + "@rollup/rollup-linux-x64-gnu": "4.52.0", + "@rollup/rollup-linux-x64-musl": "4.52.0", + "@rollup/rollup-openharmony-arm64": "4.52.0", + "@rollup/rollup-win32-arm64-msvc": "4.52.0", + "@rollup/rollup-win32-ia32-msvc": "4.52.0", + "@rollup/rollup-win32-x64-gnu": "4.52.0", + "@rollup/rollup-win32-x64-msvc": "4.52.0", "fsevents": "~2.3.2" } }, diff --git a/package.json b/package.json index 101c116..b5cf20d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "filesize", "description": "JavaScript library to generate a human readable String describing the file size", - "version": "11.0.10", + "version": "11.0.11", "homepage": "https://filesizejs.com", "author": "Jason Mulligan ", "repository": { @@ -29,17 +29,24 @@ "sourceType": "module", "types": "types/filesize.d.ts", "engines": { - "node": ">= 10.4.0" + "node": ">= 10.8.0" }, "scripts": { "build": "npm run rollup", + "build:watch": "rollup --config --watch", + "build:analyze": "npm run rollup && npm run analyze:size", + "analyze:size": "echo 'Bundle size analysis:' && du -h dist/* && echo 'Gzipped sizes:' && gzip -c dist/filesize.min.js | wc -c | awk '{print $1\" bytes (gzipped)\"}' && gzip -c dist/filesize.umd.min.js | wc -c | awk '{print $1\" bytes (umd gzipped)\"}'", "changelog": "auto-changelog -p", "lint": "eslint *.js src/*.js tests/**/*.js", - "fix": "eslint --fix *.js src/*.js tests/**/*.js", + "lint:fix": "eslint --fix *.js src/*.js tests/**/*.js", + "fix": "npm run lint:fix", "mocha": "c8 mocha tests/**/*.js", "rollup": "rollup --config", "test": "npm run lint && npm run mocha", + "test:watch": "npm run mocha -- --watch", + "prepack": "npm run build", "prepare": "husky", + "dev": "npm run build:watch", "benchmark": "node benchmarks/index.js", "benchmark:basic": "node benchmarks/basic-performance.js", "benchmark:options": "node benchmarks/options-benchmark.js", @@ -51,10 +58,10 @@ "@rollup/plugin-terser": "^0.4.4", "auto-changelog": "^2.5.0", "c8": "^10.1.3", - "eslint": "^9.30.1", + "eslint": "^9.36.0", "husky": "^9.1.7", "mocha": "^11.7.1", - "rollup": "^4.44.2" + "rollup": "^4.52.0" }, "keywords": [ "file", diff --git a/rollup.config.js b/rollup.config.js index e38fe0d..4466f56 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,8 +1,10 @@ import terser from "@rollup/plugin-terser"; import { createRequire } from "node:module"; + const require = createRequire(import.meta.url); const pkg = require("./package.json"); const year = new Date().getFullYear(); + const bannerLong = `/** * ${pkg.name} * @@ -10,20 +12,82 @@ const bannerLong = `/** * @license ${pkg.license} * @version ${pkg.version} */`; + const bannerShort = `/*! ${year} ${pkg.author} @version ${pkg.version} */`; -const defaultOutBase = {compact: true, banner: bannerLong, name: pkg.name}; -const cjOutBase = {...defaultOutBase, compact: false, format: "cjs", exports: "named"}; -const esmOutBase = {...defaultOutBase, format: "esm"}; -const umdOutBase = {...defaultOutBase, format: "umd"}; -const minOutBase = {banner: bannerShort, name: pkg.name, plugins: [terser()], sourcemap: true}; + +// Optimized terser configuration for better compression +const terserOptions = { + compress: { + passes: 2, + drop_console: false, + drop_debugger: true, + pure_funcs: ['console.log'], + unsafe_arrows: true, + unsafe_methods: true + }, + mangle: { + properties: { + regex: /^_/ + } + }, + format: { + comments: "some" + } +}; + +const defaultOutBase = { + compact: true, + banner: bannerLong, + name: pkg.name, + generatedCode: { + constBindings: true, + arrowFunctions: true, + objectShorthand: true + } +}; + +const cjOutBase = { + ...defaultOutBase, + compact: false, + format: "cjs", + exports: "named", + interop: "compat" +}; + +const esmOutBase = { + ...defaultOutBase, + format: "esm" +}; + +const umdOutBase = { + ...defaultOutBase, + format: "umd" +}; + +const minOutBase = { + banner: bannerShort, + name: pkg.name, + plugins: [terser(terserOptions)], + sourcemap: true, + generatedCode: { + constBindings: true, + arrowFunctions: true, + objectShorthand: true + } +}; export default [ { input: "./src/filesize.js", + treeshake: { + moduleSideEffects: false, + propertyReadSideEffects: false, + unknownGlobalSideEffects: false + }, output: [ { ...cjOutBase, diff --git a/src/filesize.js b/src/filesize.js index 5d63330..c7bdb1a 100644 --- a/src/filesize.js +++ b/src/filesize.js @@ -1,33 +1,32 @@ import { ARRAY, - BINARY_POWERS, BIT, BITS, BYTE, BYTES, - DECIMAL_POWERS, - E, EMPTY, EXPONENT, FUNCTION, - IEC, INVALID_NUMBER, INVALID_ROUND, - JEDEC, - LOG_2_1024, LOG_10_1000, + LOG_2_1024, OBJECT, - PERIOD, ROUND, S, - SI, SI_KBIT, SI_KBYTE, SPACE, STRING, STRINGS, - ZERO } from "./constants.js"; +import { + applyNumberFormatting, + applyPrecisionHandling, + calculateOptimizedValue, + getBaseConfiguration, + handleZeroValue +} from "./helpers.js"; /** * Converts a file size in bytes to a human-readable string with appropriate units @@ -80,29 +79,8 @@ export function filesize (arg, { val = 0, u = EMPTY; - // Optimized base & standard synchronization with early returns - let isDecimal, ceil, actualStandard; - if (standard === SI) { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } else if (standard === IEC) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else if (standard === JEDEC) { - isDecimal = false; // JEDEC uses binary (1024) by default - ceil = 1024; - actualStandard = JEDEC; - } else if (base === 2) { - isDecimal = false; - ceil = 1024; - actualStandard = IEC; - } else { - isDecimal = true; - ceil = 1000; - actualStandard = JEDEC; - } + // Optimized base & standard configuration lookup + const {isDecimal, ceil, actualStandard} = getBaseConfiguration(standard, base); const full = fullform === true, neg = num < 0, @@ -123,38 +101,12 @@ export function filesize (arg, { // Fast path for zero if (num === 0) { - result[0] = precision > 0 ? (0).toPrecision(precision) : 0; - u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; - - if (output === EXPONENT) { - return 0; - } - - // Skip most processing for zero case - if (symbols[result[1]]) { - result[1] = symbols[result[1]]; - } - - if (full) { - result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); - } - - return output === ARRAY ? result : output === OBJECT ? { - value: result[0], - symbol: result[1], - exponent: 0, - unit: u - } : result.join(spacer); + return handleZeroValue(precision, actualStandard, bits, symbols, full, fullforms, output, spacer); } // Optimized exponent calculation using pre-computed log values if (e === -1 || isNaN(e)) { - if (isDecimal) { - e = Math.floor(Math.log(num) / LOG_10_1000); - } else { - e = Math.floor(Math.log(num) / LOG_2_1024); - } - + e = isDecimal ? Math.floor(Math.log(num) / LOG_10_1000) : Math.floor(Math.log(num) / LOG_2_1024); if (e < 0) { e = 0; } @@ -172,24 +124,10 @@ export function filesize (arg, { return e; } - // Use pre-computed lookup tables (e is always <= 8, arrays have 9 elements) - let d; - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - - val = num / d; - - if (bits) { - val = val * 8; - - if (val >= ceil && e < 8) { - val = val / ceil; - e++; - } - } + // Calculate value with optimized lookup and bits handling + const {result: valueResult, e: valueExponent} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + val = valueResult; + e = valueExponent; // Optimize rounding calculation const p = e > 0 && round > 0 ? Math.pow(10, round) : 1; @@ -200,21 +138,11 @@ export function filesize (arg, { e++; } - // Setting optional precision + // Apply precision handling if (precision > 0) { - result[0] = result[0].toPrecision(precision); - - if (result[0].includes(E) && e < 8) { - e++; - // Recalculate with new exponent (e is always <= 8) - if (isDecimal) { - d = DECIMAL_POWERS[e]; - } else { - d = BINARY_POWERS[e]; - } - val = num / d; - result[0] = (p === 1 ? roundingFunc(val) : roundingFunc(val * p) / p).toPrecision(precision); - } + const precisionResult = applyPrecisionHandling(result[0], precision, e, num, isDecimal, bits, ceil, roundingFunc, round); + result[0] = precisionResult.value; + e = precisionResult.e; } // Cache symbol lookup @@ -231,25 +159,8 @@ export function filesize (arg, { result[1] = symbols[result[1]]; } - // Optimized locale/separator handling - if (locale === true) { - result[0] = result[0].toLocaleString(); - } else if (locale.length > 0) { - result[0] = result[0].toLocaleString(locale, localeOptions); - } else if (separator.length > 0) { - result[0] = result[0].toString().replace(PERIOD, separator); - } - - if (pad && round > 0) { - const resultStr = result[0].toString(), - x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD), - tmp = resultStr.split(x), - s = tmp[1] || EMPTY, - l = s.length, - n = round - l; - - result[0] = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; - } + // Apply locale, separator, and padding formatting + result[0] = applyNumberFormatting(result[0], locale, localeOptions, separator, pad, round); if (full) { result[1] = fullforms[e] || STRINGS.fullform[actualStandard][e] + (bits ? BIT : BYTE) + (result[0] === 1 ? EMPTY : S); @@ -259,7 +170,7 @@ export function filesize (arg, { if (output === ARRAY) { return result; } - + if (output === OBJECT) { return { value: result[0], @@ -268,7 +179,7 @@ export function filesize (arg, { unit: u }; } - + return spacer === SPACE ? `${result[0]} ${result[1]}` : result.join(spacer); } diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..cbbe029 --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,176 @@ +import { + ARRAY, + BINARY_POWERS, + BIT, + BITS, + BYTE, + BYTES, + DECIMAL_POWERS, + E, + EMPTY, + EXPONENT, + IEC, + JEDEC, + OBJECT, + PERIOD, + SI, + STRINGS, + ZERO +} from "./constants.js"; + +// Cached configuration lookup for better performance +const STANDARD_CONFIGS = { + [SI]: {isDecimal: true, ceil: 1000, actualStandard: JEDEC}, + [IEC]: {isDecimal: false, ceil: 1024, actualStandard: IEC}, + [JEDEC]: {isDecimal: false, ceil: 1024, actualStandard: JEDEC} +}; + +/** + * Optimized base configuration lookup + * @param {string} standard - Standard type + * @param {number} base - Base number + * @returns {Object} Configuration object + */ +export function getBaseConfiguration (standard, base) { + // Use cached lookup table for better performance + if (STANDARD_CONFIGS[standard]) { + return STANDARD_CONFIGS[standard]; + } + + // Base override + if (base === 2) { + return {isDecimal: false, ceil: 1024, actualStandard: IEC}; + } + + // Default + return {isDecimal: true, ceil: 1000, actualStandard: JEDEC}; +} + +/** + * Optimized zero value handling + * @param {number} precision - Precision value + * @param {string} actualStandard - Standard to use + * @param {boolean} bits - Whether to use bits + * @param {Object} symbols - Custom symbols + * @param {boolean} full - Whether to use full form + * @param {Array} fullforms - Custom full forms + * @param {string} output - Output format + * @param {string} spacer - Spacer character + * @returns {string|Array|Object|number} Formatted result + */ +export function handleZeroValue (precision, actualStandard, bits, symbols, full, fullforms, output, spacer) { + const result = []; + result[0] = precision > 0 ? (0).toPrecision(precision) : 0; + const u = result[1] = STRINGS.symbol[actualStandard][bits ? BITS : BYTES][0]; + + if (output === EXPONENT) { + return 0; + } + + // Apply symbol customization + if (symbols[result[1]]) { + result[1] = symbols[result[1]]; + } + + // Apply full form + if (full) { + result[1] = fullforms[0] || STRINGS.fullform[actualStandard][0] + (bits ? BIT : BYTE); + } + + // Return in requested format + return output === ARRAY ? result : output === OBJECT ? { + value: result[0], + symbol: result[1], + exponent: 0, + unit: u + } : result.join(spacer); +} + +/** + * Optimized value calculation with bits handling + * @param {number} num - Input number + * @param {number} e - Exponent + * @param {boolean} isDecimal - Whether to use decimal powers + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @returns {Object} Object with val and e properties + */ +export function calculateOptimizedValue (num, e, isDecimal, bits, ceil) { + const d = isDecimal ? DECIMAL_POWERS[e] : BINARY_POWERS[e]; + let result = num / d; + + if (bits) { + result *= 8; + // Handle auto-increment for bits + if (result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return {result, e}; +} + +/** + * Optimized precision handling with scientific notation correction + * @param {number} value - Current value + * @param {number} precision - Precision to apply + * @param {number} e - Current exponent + * @param {number} num - Original number + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether calculating bits + * @param {number} ceil - Ceiling value + * @param {Function} roundingFunc - Rounding function + * @param {number} round - Round value + * @returns {Object} Object with value and e properties + */ +export function applyPrecisionHandling (value, precision, e, num, isDecimal, bits, ceil, roundingFunc, round) { + let result = value.toPrecision(precision); + + // Handle scientific notation by recalculating with incremented exponent + if (result.includes(E) && e < 8) { + e++; + const {result: valueResult} = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + const p = round > 0 ? Math.pow(10, round) : 1; + result = (p === 1 ? roundingFunc(valueResult) : roundingFunc(valueResult * p) / p).toPrecision(precision); + } + + return {value: result, e}; +} + +/** + * Optimized number formatting with locale, separator, and padding + * @param {number|string} value - Value to format + * @param {string|boolean} locale - Locale setting + * @param {Object} localeOptions - Locale options + * @param {string} separator - Custom separator + * @param {boolean} pad - Whether to pad + * @param {number} round - Round value + * @returns {string|number} Formatted value + */ +export function applyNumberFormatting (value, locale, localeOptions, separator, pad, round) { + let result = value; + + // Apply locale formatting + if (locale === true) { + result = result.toLocaleString(); + } else if (locale.length > 0) { + result = result.toLocaleString(locale, localeOptions); + } else if (separator.length > 0) { + result = result.toString().replace(PERIOD, separator); + } + + // Apply padding + if (pad && round > 0) { + const resultStr = result.toString(); + const x = separator || ((resultStr.match(/(\D)/g) || []).pop() || PERIOD); + const tmp = resultStr.split(x); + const s = tmp[1] || EMPTY; + const l = s.length; + const n = round - l; + + result = `${tmp[0]}${x}${s.padEnd(l + n, ZERO)}`; + } + + return result; +} diff --git a/tests/unit/filesize-helpers.test.js b/tests/unit/filesize-helpers.test.js new file mode 100644 index 0000000..e3e31ff --- /dev/null +++ b/tests/unit/filesize-helpers.test.js @@ -0,0 +1,200 @@ +/** + * Unit tests for exported helper functions + * Tests the individual helper functions for better test coverage + */ + +import assert from 'assert'; +import { + getBaseConfiguration, + handleZeroValue, + calculateOptimizedValue, + applyPrecisionHandling, + applyNumberFormatting +} from '../../src/helpers.js'; + +describe('Helper Functions', () => { + describe('getBaseConfiguration', () => { + it('should return SI configuration', () => { + const config = getBaseConfiguration('si', -1); + assert.deepStrictEqual(config, { + isDecimal: true, + ceil: 1000, + actualStandard: 'jedec' + }); + }); + + it('should return IEC configuration', () => { + const config = getBaseConfiguration('iec', -1); + assert.deepStrictEqual(config, { + isDecimal: false, + ceil: 1024, + actualStandard: 'iec' + }); + }); + + it('should return JEDEC configuration', () => { + const config = getBaseConfiguration('jedec', -1); + assert.deepStrictEqual(config, { + isDecimal: false, + ceil: 1024, + actualStandard: 'jedec' + }); + }); + + it('should handle base=2 override', () => { + const config = getBaseConfiguration('', 2); + assert.deepStrictEqual(config, { + isDecimal: false, + ceil: 1024, + actualStandard: 'iec' + }); + }); + + it('should return default configuration', () => { + const config = getBaseConfiguration('', -1); + assert.deepStrictEqual(config, { + isDecimal: true, + ceil: 1000, + actualStandard: 'jedec' + }); + }); + }); + + describe('handleZeroValue', () => { + it('should handle zero with string output', () => { + const result = handleZeroValue(0, 'jedec', false, {}, false, [], 'string', ' '); + assert.strictEqual(result, '0 B'); + }); + + it('should handle zero with array output', () => { + const result = handleZeroValue(0, 'jedec', false, {}, false, [], 'array', ' '); + assert.deepStrictEqual(result, [0, 'B']); + }); + + it('should handle zero with object output', () => { + const result = handleZeroValue(0, 'jedec', false, {}, false, [], 'object', ' '); + assert.deepStrictEqual(result, { + value: 0, + symbol: 'B', + exponent: 0, + unit: 'B' + }); + }); + + it('should handle zero with exponent output', () => { + const result = handleZeroValue(0, 'jedec', false, {}, false, [], 'exponent', ' '); + assert.strictEqual(result, 0); + }); + + it('should handle zero with bits', () => { + const result = handleZeroValue(0, 'jedec', true, {}, false, [], 'string', ' '); + assert.strictEqual(result, '0 bit'); + }); + + it('should handle zero with custom symbols', () => { + const result = handleZeroValue(0, 'jedec', false, { 'B': 'Bytes' }, false, [], 'string', ' '); + assert.strictEqual(result, '0 Bytes'); + }); + + it('should handle zero with fullform', () => { + const result = handleZeroValue(0, 'jedec', false, {}, true, [], 'string', ' '); + assert.strictEqual(result, '0 byte'); + }); + + it('should handle zero with precision', () => { + const result = handleZeroValue(2, 'jedec', false, {}, false, [], 'string', ' '); + assert.strictEqual(result, '0.0 B'); + }); + }); + + describe('calculateOptimizedValue', () => { + it('should calculate value without bits', () => { + const result = calculateOptimizedValue(1024, 1, false, false, 1024); + assert.deepStrictEqual(result, { result: 1, e: 1 }); + }); + + it('should calculate value with bits', () => { + const result = calculateOptimizedValue(1024, 1, false, true, 1024); + assert.deepStrictEqual(result, { result: 8, e: 1 }); + }); + + it('should handle bits auto-increment', () => { + const result = calculateOptimizedValue(128, 0, false, true, 1024); + assert.deepStrictEqual(result, { result: 1, e: 1 }); + }); + + it('should use decimal powers', () => { + const result = calculateOptimizedValue(1000, 1, true, false, 1000); + assert.deepStrictEqual(result, { result: 1, e: 1 }); + }); + + it('should not increment when e >= 8', () => { + // Use a proper YiB value for exponent 8 + const yibValue = Math.pow(1024, 8); // 1 YiB in bytes + const resultObj = calculateOptimizedValue(yibValue, 8, false, true, 1024); + assert.strictEqual(resultObj.e, 8); + assert(resultObj.result >= 8); // Should be 8 bits (1 byte * 8) + }); + }); + + describe('applyPrecisionHandling', () => { + it('should apply precision without scientific notation', () => { + const result = applyPrecisionHandling(1.5, 2, 1, 1024, false, false, 1024, Math.round, 2); + assert.deepStrictEqual(result, { value: '1.5', e: 1 }); + }); + + it('should handle scientific notation with increment', () => { + // Test with a large number that would produce scientific notation + const result = applyPrecisionHandling(1000000000000, 1, 3, 1e15, true, false, 1000, Math.round, 2); + assert(typeof result.value === 'string'); + assert(typeof result.e === 'number'); + }); + + it('should not increment when e >= 8', () => { + const result = applyPrecisionHandling(1.5, 2, 8, 1024, false, false, 1024, Math.round, 2); + assert.deepStrictEqual(result, { value: '1.5', e: 8 }); + }); + }); + + describe('applyNumberFormatting', () => { + it('should format with system locale', () => { + const result = applyNumberFormatting(1.5, true, {}, '', false, 2); + assert(typeof result === 'string'); + }); + + it('should format with specific locale', () => { + const result = applyNumberFormatting(1.5, 'en-US', {}, '', false, 2); + assert(typeof result === 'string'); + }); + + it('should apply custom separator', () => { + const result = applyNumberFormatting(1.5, '', {}, ',', false, 2); + assert.strictEqual(result, '1,5'); + }); + + it('should apply padding', () => { + const result = applyNumberFormatting(1, '', {}, '', true, 2); + assert.strictEqual(result, '1.00'); + }); + + it('should apply padding with custom separator', () => { + const result = applyNumberFormatting(1.5, '', {}, ',', true, 3); + assert.strictEqual(result, '1,500'); + }); + + it('should handle no formatting', () => { + const result = applyNumberFormatting(1.5, '', {}, '', false, 2); + assert.strictEqual(result, 1.5); + }); + + it('should handle padding with existing decimals', () => { + const result = applyNumberFormatting(1.5, '', {}, '', true, 3); + assert.strictEqual(result, '1.500'); + }); + + it('should handle padding with no round', () => { + const result = applyNumberFormatting(1.5, '', {}, '', true, 0); + assert.strictEqual(result, 1.5); + }); + }); +}); diff --git a/types/constants.d.ts b/types/constants.d.ts index 4da91d1..4b9e9c4 100644 --- a/types/constants.d.ts +++ b/types/constants.d.ts @@ -26,6 +26,7 @@ export const EXPONENT: "exponent"; export const ROUND: "round"; // Special Characters and Values +export const E: "e"; export const EMPTY: ""; export const PERIOD: "."; export const S: "s"; @@ -48,4 +49,33 @@ export const STRINGS: { iec: ["", "kibi", "mebi", "gibi", "tebi", "pebi", "exbi", "zebi", "yobi"]; jedec: ["", "kilo", "mega", "giga", "tera", "peta", "exa", "zetta", "yotta"]; }; -}; \ No newline at end of file +}; + +// Pre-computed lookup tables for performance optimization +export const BINARY_POWERS: readonly [ + 1, // 2^0 + 1024, // 2^10 + 1048576, // 2^20 + 1073741824, // 2^30 + 1099511627776, // 2^40 + 1125899906842624, // 2^50 + 1152921504606846976, // 2^60 + 1180591620717411303424, // 2^70 + 1208925819614629174706176 // 2^80 +]; + +export const DECIMAL_POWERS: readonly [ + 1, // 10^0 + 1000, // 10^3 + 1000000, // 10^6 + 1000000000, // 10^9 + 1000000000000, // 10^12 + 1000000000000000, // 10^15 + 1000000000000000000, // 10^18 + 1000000000000000000000, // 10^21 + 1000000000000000000000000 // 10^24 +]; + +// Pre-computed log values for faster exponent calculation +export const LOG_2_1024: number; +export const LOG_10_1000: number; \ No newline at end of file diff --git a/types/helpers.d.ts b/types/helpers.d.ts new file mode 100644 index 0000000..3c10088 --- /dev/null +++ b/types/helpers.d.ts @@ -0,0 +1,123 @@ +/** + * Configuration object returned by getBaseConfiguration + */ +export interface BaseConfiguration { + /** Whether to use decimal (base 10) calculations */ + isDecimal: boolean; + /** Ceiling value for auto-increment calculations */ + ceil: number; + /** The actual standard to use for formatting */ + actualStandard: string; +} + +/** + * Value calculation result + */ +export interface OptimizedValueResult { + /** The calculated result value */ + result: number; + /** The adjusted exponent */ + e: number; +} + +/** + * Precision handling result + */ +export interface PrecisionHandlingResult { + /** The formatted value */ + value: string | number; + /** The adjusted exponent */ + e: number; +} + +/** + * Optimized base configuration lookup + * @param standard - Standard type + * @param base - Base number + * @returns Configuration object + */ +export function getBaseConfiguration(standard: string, base: number): BaseConfiguration; + +/** + * Optimized zero value handling + * @param precision - Precision value + * @param actualStandard - Standard to use + * @param bits - Whether to use bits + * @param symbols - Custom symbols + * @param full - Whether to use full form + * @param fullforms - Custom full forms + * @param output - Output format + * @param spacer - Spacer character + * @returns Formatted result + */ +export function handleZeroValue( + precision: number, + actualStandard: string, + bits: boolean, + symbols: Record, + full: boolean, + fullforms: string[], + output: string, + spacer: string +): string | [number | string, string] | { value: number | string; symbol: string; exponent: number; unit: string } | number; + +/** + * Optimized value calculation with bits handling + * @param num - Input number + * @param e - Exponent + * @param isDecimal - Whether to use decimal powers + * @param bits - Whether to calculate bits + * @param ceil - Ceiling value for auto-increment + * @returns Object with result and e properties + */ +export function calculateOptimizedValue( + num: number, + e: number, + isDecimal: boolean, + bits: boolean, + ceil: number +): OptimizedValueResult; + +/** + * Optimized precision handling with scientific notation correction + * @param value - Current value + * @param precision - Precision to apply + * @param e - Current exponent + * @param num - Original number + * @param isDecimal - Whether using decimal base + * @param bits - Whether calculating bits + * @param ceil - Ceiling value + * @param roundingFunc - Rounding function + * @param round - Round value + * @returns Object with value and e properties + */ +export function applyPrecisionHandling( + value: number, + precision: number, + e: number, + num: number, + isDecimal: boolean, + bits: boolean, + ceil: number, + roundingFunc: (x: number) => number, + round: number +): PrecisionHandlingResult; + +/** + * Optimized number formatting with locale, separator, and padding + * @param value - Value to format + * @param locale - Locale setting + * @param localeOptions - Locale options + * @param separator - Custom separator + * @param pad - Whether to pad + * @param round - Round value + * @returns Formatted value + */ +export function applyNumberFormatting( + value: number | string, + locale: string | boolean, + localeOptions: Intl.NumberFormatOptions, + separator: string, + pad: boolean, + round: number +): string | number; From df0978af725626117c6f7bd86c53daec17a99540 Mon Sep 17 00:00:00 2001 From: Jason Mulligan Date: Sun, 21 Sep 2025 09:21:04 -0400 Subject: [PATCH 2/2] Updating CHANGELOG.md --- CHANGELOG.md | 31 ++++++++----------------------- package-lock.json | 2 +- package.json | 4 ++-- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b485ff..acdfe75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,15 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [11.0.11](https://github.com/avoidwork/filesize.js/compare/11.0.10...11.0.11) + +- Updates [`#207`](https://github.com/avoidwork/filesize.js/pull/207) + #### [11.0.10](https://github.com/avoidwork/filesize.js/compare/11.0.9...11.0.10) +> 19 September 2025 + +- Version bump [`cc9e109`](https://github.com/avoidwork/filesize.js/commit/cc9e109fda32f5949c4315b752c7d6baa5393482) - Updating README.md [`bc34e1d`](https://github.com/avoidwork/filesize.js/commit/bc34e1dbe51bbde362a01cef1319f9d1dcd6f193) #### [11.0.9](https://github.com/avoidwork/filesize.js/compare/11.0.8...11.0.9) @@ -31,33 +38,11 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Fixing the upper boundary of 'precision' [`#204`](https://github.com/avoidwork/filesize.js/pull/204) - Version bump [`a382bfb`](https://github.com/avoidwork/filesize.js/commit/a382bfb5cc3c5c3bb4d06e1c8078fffa8f555fce) -#### [11.0.6](https://github.com/avoidwork/filesize.js/compare/11.0.5...11.0.6) +#### [11.0.6](https://github.com/avoidwork/filesize.js/compare/11.0.2...11.0.6) > 19 September 2025 - Taking a mulligan on 'precision' [`#203`](https://github.com/avoidwork/filesize.js/pull/203) -- Version bump [`63abcfb`](https://github.com/avoidwork/filesize.js/commit/63abcfbff702b14594abecc8dfaf1cd2efc75103) - -#### [11.0.5](https://github.com/avoidwork/filesize.js/compare/11.0.4...11.0.5) - -> 19 September 2025 - -- Revert "Fixing the output when supplying 'precision' (#201)" [`c5edf39`](https://github.com/avoidwork/filesize.js/commit/c5edf392f46274c9e7b2397c2e453b7e8adc7b7e) -- Revert "Fixing how 'precision' adjusts the exponent if there's digits (#202)" [`b4dbda4`](https://github.com/avoidwork/filesize.js/commit/b4dbda46e2f288d24a3305e584d2f4ac5f7c05ec) -- Reverting changes [`d3b3e69`](https://github.com/avoidwork/filesize.js/commit/d3b3e6989be832937c9c34e847a5bb7562c4767f) - -#### [11.0.4](https://github.com/avoidwork/filesize.js/compare/11.0.3...11.0.4) - -> 19 September 2025 - -- Fixing how 'precision' adjusts the exponent if there's digits [`#202`](https://github.com/avoidwork/filesize.js/pull/202) -- Version bump [`3916707`](https://github.com/avoidwork/filesize.js/commit/3916707b7c90a58545396611e997b383f163fcf8) - -#### [11.0.3](https://github.com/avoidwork/filesize.js/compare/11.0.2...11.0.3) - -> 19 September 2025 - -- Fixing the output when supplying 'precision' [`#201`](https://github.com/avoidwork/filesize.js/pull/201) - Bump rollup from 4.50.1 to 4.50.2 [`#199`](https://github.com/avoidwork/filesize.js/pull/199) - Bump actions/setup-node from 4 to 5 [`#198`](https://github.com/avoidwork/filesize.js/pull/198) - Bump rollup from 4.50.0 to 4.50.1 [`#197`](https://github.com/avoidwork/filesize.js/pull/197) diff --git a/package-lock.json b/package-lock.json index eb4f820..970618c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "c8": "^10.1.3", "eslint": "^9.36.0", "husky": "^9.1.7", - "mocha": "^11.7.1", + "mocha": "^11.7.2", "rollup": "^4.52.0" }, "engines": { diff --git a/package.json b/package.json index b5cf20d..88f42f1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "files": [ "dist/filesize.js", "dist/filesize.cjs", - "types" + "types/filesize.d.ts" ], "license": "BSD-3-Clause", "source": "src/filesize.js", @@ -60,7 +60,7 @@ "c8": "^10.1.3", "eslint": "^9.36.0", "husky": "^9.1.7", - "mocha": "^11.7.1", + "mocha": "^11.7.2", "rollup": "^4.52.0" }, "keywords": [