Upstream avoidwork/filesize.js state of the touched files before 15b1dba9c6
This commit is contained in:
commit
6758bfef36
3 files changed
+3218
No files matched your search
Generated
+1631
File diff suppressed because it is too large.
Load diff
+489
@@ -0,0 +1,489 @@
|
||||
import {
|
||||
ARRAY,
|
||||
BINARY_POWERS,
|
||||
BIT,
|
||||
BITS,
|
||||
BYTE,
|
||||
BYTES,
|
||||
DECIMAL_POWERS,
|
||||
E,
|
||||
EMPTY,
|
||||
EXPONENT,
|
||||
IEC,
|
||||
JEDEC,
|
||||
LOG_10_1000,
|
||||
LOG_2_1024,
|
||||
OBJECT,
|
||||
PERIOD,
|
||||
S,
|
||||
SI,
|
||||
SI_KBIT,
|
||||
SI_KBYTE,
|
||||
SPACE,
|
||||
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
|
||||
* @param {boolean} pad - Whether to pad decimal places
|
||||
* @param {number} round - Number of decimal places for padding
|
||||
* @param {string} [symbol] - Symbol to use (defaults based on bits/standard)
|
||||
* @returns {string|Array|Object|number} Formatted result
|
||||
*/
|
||||
export function handleZeroValue(
|
||||
precision,
|
||||
actualStandard,
|
||||
bits,
|
||||
symbols,
|
||||
full,
|
||||
fullforms,
|
||||
output,
|
||||
spacer,
|
||||
pad,
|
||||
round,
|
||||
symbol,
|
||||
) {
|
||||
let value;
|
||||
if (precision > 0) {
|
||||
value = (0).toPrecision(precision);
|
||||
} else if (pad && round > 0) {
|
||||
value = (0).toFixed(round);
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
if (output === EXPONENT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set default symbol if not provided
|
||||
if (!symbol) {
|
||||
symbol = bits
|
||||
? STRINGS.symbol[actualStandard].bits[0]
|
||||
: STRINGS.symbol[actualStandard].bytes[0];
|
||||
}
|
||||
|
||||
// Apply symbol customization
|
||||
if (symbols[symbol]) {
|
||||
symbol = symbols[symbol];
|
||||
}
|
||||
|
||||
// Apply full form
|
||||
if (full) {
|
||||
if (fullforms[0]) {
|
||||
symbol = fullforms[0];
|
||||
} else {
|
||||
symbol = STRINGS.fullform[actualStandard][0];
|
||||
if (bits) {
|
||||
symbol += BIT;
|
||||
} else {
|
||||
symbol += BYTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return in requested format
|
||||
if (output === ARRAY) {
|
||||
return [value, symbol];
|
||||
}
|
||||
|
||||
if (output === OBJECT) {
|
||||
return { value, symbol, exponent: 0, unit: symbol };
|
||||
}
|
||||
|
||||
return value + spacer + symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN)
|
||||
* @returns {Object} Object with result and e properties
|
||||
*/
|
||||
export function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = true) {
|
||||
let d;
|
||||
if (isDecimal) {
|
||||
d = DECIMAL_POWERS[e];
|
||||
} else {
|
||||
d = BINARY_POWERS[e];
|
||||
}
|
||||
let result = num / d;
|
||||
|
||||
if (bits) {
|
||||
result *= 8;
|
||||
// Handle auto-increment for bits (only when exponent is auto)
|
||||
if (autoExponent && result >= ceil && e < 8) {
|
||||
result /= ceil;
|
||||
e++;
|
||||
}
|
||||
}
|
||||
|
||||
return { result, e };
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized precision handling with scientific notation correction
|
||||
* @param {number} value - Current value
|
||||
* @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
|
||||
* @param {number} exponent - Forced exponent (-1 for auto)
|
||||
* @returns {Object} Object with value and e properties
|
||||
*/
|
||||
export function applyPrecisionHandling(
|
||||
value,
|
||||
precision,
|
||||
e,
|
||||
num,
|
||||
isDecimal,
|
||||
bits,
|
||||
ceil,
|
||||
roundingFunc,
|
||||
round,
|
||||
exponent,
|
||||
) {
|
||||
if (typeof value === "string") {
|
||||
value = parseFloat(value);
|
||||
}
|
||||
|
||||
let result = value.toPrecision(precision);
|
||||
|
||||
const autoExponent = exponent === -1 || isNaN(exponent);
|
||||
|
||||
// Handle scientific notation by recalculating with incremented exponent
|
||||
if (result.includes(E) && e < 8 && autoExponent) {
|
||||
e++;
|
||||
const { result: valueResult } = calculateOptimizedValue(num, e, isDecimal, bits, ceil);
|
||||
let p;
|
||||
if (round > 0) {
|
||||
p = Math.pow(10, round);
|
||||
} else {
|
||||
p = 1;
|
||||
}
|
||||
let computed;
|
||||
if (p === 1) {
|
||||
computed = roundingFunc(valueResult);
|
||||
} else {
|
||||
computed = roundingFunc(valueResult * p) / p;
|
||||
}
|
||||
result = computed.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,
|
||||
roundingFunc,
|
||||
) {
|
||||
let result = value;
|
||||
|
||||
// When padding alongside a locale, let the locale formatter emit the fixed
|
||||
// number of fraction digits. The manual string padding below cannot tell a
|
||||
// locale-inserted grouping separator from the decimal separator, so it
|
||||
// dropped digits (e.g. "1,234,500" became "1,234").
|
||||
const localePad =
|
||||
pad && round > 0 ? { minimumFractionDigits: round, maximumFractionDigits: round } : undefined;
|
||||
|
||||
// Apply locale formatting
|
||||
if (locale === true) {
|
||||
result = result.toLocaleString(undefined, localePad);
|
||||
} else if (locale.length > 0) {
|
||||
result = result.toLocaleString(locale, { ...localeOptions, ...localePad });
|
||||
} else if (separator.length > 0) {
|
||||
// Round before separator replacement to ensure excess decimal places
|
||||
// are truncated when pad is also set (fixes padding + separator bug).
|
||||
if (pad && round > 0) {
|
||||
const p = Math.pow(10, round);
|
||||
result = roundingFunc(result * p) / p;
|
||||
}
|
||||
result = result.toString().replace(PERIOD, separator);
|
||||
}
|
||||
|
||||
// Apply padding for the non-locale paths, where the string has a single
|
||||
// decimal separator and no grouping is inserted.
|
||||
if (pad && round > 0 && locale !== true && locale.length === 0) {
|
||||
const resultStr = result.toString();
|
||||
const x = separator || PERIOD;
|
||||
const tmp = resultStr.split(x);
|
||||
const s = tmp[1] || EMPTY;
|
||||
|
||||
result = `${tmp[0]}${x}${s.padEnd(round, ZERO)}`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates exponent from the input value using pre-computed log values and clamps to supported range
|
||||
* Also adjusts precision when exponent exceeds the lookup table bounds
|
||||
* @param {number} num - Input file size in bytes
|
||||
* @param {number} e - Current exponent value
|
||||
* @param {number} exponent - Original user-provided exponent option (-1 for auto)
|
||||
* @param {boolean} isDecimal - Whether to use decimal (SI) base
|
||||
* @param {number} precision - Current precision value (modified when e > 8)
|
||||
* @returns {Object} Object with computed e value and possibly adjusted precision
|
||||
*/
|
||||
export function calculateExponent(num, e, exponent, isDecimal, precision) {
|
||||
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);
|
||||
}
|
||||
if (e < 0) {
|
||||
e = 0;
|
||||
}
|
||||
} else if (e < 0) {
|
||||
// A forced exponent below the auto sentinel (-1) has no meaning and
|
||||
// would otherwise index the power-of-ten/two lookup tables out of
|
||||
// bounds (producing NaN). Clamp to 0, mirroring the e > 8 clamp below.
|
||||
e = 0;
|
||||
}
|
||||
|
||||
if (e > 8) {
|
||||
if (precision > 0) {
|
||||
precision += 8 - e;
|
||||
}
|
||||
return { e: 8, precision };
|
||||
}
|
||||
|
||||
return { e, precision };
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies rounding to the raw calculated value and handles auto-increment ceiling
|
||||
* @param {number} val - Raw value before rounding
|
||||
* @param {number} ceil - Ceiling threshold (1000 for SI, 1024 for IEC)
|
||||
* @param {number} e - Current exponent value
|
||||
* @param {number} round - Number of decimal places
|
||||
* @param {Function} roundingFunc - Rounding method (Math.round, Math.floor, Math.ceil)
|
||||
* @param {boolean} autoExponent - Whether exponent is auto-calculated (-1 or NaN)
|
||||
* @returns {Object} Object with rounded value and possibly incremented exponent
|
||||
*/
|
||||
export function applyRounding(val, ceil, e, round, roundingFunc, autoExponent) {
|
||||
let p;
|
||||
if (e > 0 && round > 0) {
|
||||
p = Math.pow(10, round);
|
||||
} else {
|
||||
p = 1;
|
||||
}
|
||||
let r;
|
||||
if (p === 1) {
|
||||
r = roundingFunc(val);
|
||||
} else {
|
||||
r = roundingFunc(val * p) / p;
|
||||
}
|
||||
|
||||
if (r === ceil && e < 8 && autoExponent) {
|
||||
r = 1;
|
||||
e++;
|
||||
}
|
||||
|
||||
return { value: r, e };
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the unit symbol for the given standard, bits mode, and exponent
|
||||
* Handles SI standard special case where exponent 1 always uses "kB" or "kbit"
|
||||
* @param {string} actualStandard - The resolved standard (iec, jedec)
|
||||
* @param {boolean} bits - Whether formatting bit values
|
||||
* @param {number} e - Current exponent index
|
||||
* @param {boolean} isDecimal - Whether using decimal (SI) base
|
||||
* @returns {string} The resolved unit symbol string
|
||||
*/
|
||||
export function resolveSymbol(actualStandard, bits, e, isDecimal) {
|
||||
const symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES];
|
||||
let result;
|
||||
if (isDecimal && e === 1) {
|
||||
if (bits) {
|
||||
result = SI_KBIT;
|
||||
} else {
|
||||
result = SI_KBYTE;
|
||||
}
|
||||
} else {
|
||||
result = symbolTable[e];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates the result: applies negation, custom symbols, number formatting, and full form names
|
||||
* Mutates the result array in-place for both value (index 0) and symbol (index 1)
|
||||
* @param {Array} result - Result array with numeric value at [0] and string symbol at [1]
|
||||
* @param {boolean} neg - Whether the original input was negative
|
||||
* @param {Object} symbols - Custom symbol override map
|
||||
* @param {string|boolean} locale - Locale string for formatting
|
||||
* @param {Object} localeOptions - Additional locale formatting options
|
||||
* @param {string} separator - Custom decimal separator
|
||||
* @param {boolean} pad - Whether zero-pad decimals
|
||||
* @param {number} round - Target decimal count for padding
|
||||
* @param {boolean} full - Whether to use full unit names
|
||||
* @param {Array} fullforms - Custom full unit name overrides
|
||||
* @param {string} actualStandard - Unit standard for full form lookup
|
||||
* @param {number} e - Current exponent index
|
||||
* @param {boolean} bits - Whether formatting bit values
|
||||
* @returns {void} Mutates result array in place
|
||||
*/
|
||||
export function decorateResult(
|
||||
result,
|
||||
neg,
|
||||
symbols,
|
||||
locale,
|
||||
localeOptions,
|
||||
separator,
|
||||
pad,
|
||||
round,
|
||||
full,
|
||||
fullforms,
|
||||
actualStandard,
|
||||
e,
|
||||
bits,
|
||||
roundingFunc,
|
||||
) {
|
||||
if (neg) {
|
||||
// `precision` leaves the value as a string from toPrecision (e.g. "1.50").
|
||||
// Negating that arithmetically coerces it back to a number and drops the
|
||||
// trailing zeros the option asked for, so prefix the sign instead.
|
||||
result[0] = typeof result[0] === "string" ? `-${result[0]}` : -result[0];
|
||||
}
|
||||
|
||||
if (symbols[result[1]]) {
|
||||
result[1] = symbols[result[1]];
|
||||
}
|
||||
|
||||
// Capture the numeric value before formatting; a comma decimal separator
|
||||
// (via separator or a locale such as de-DE) would otherwise make parseFloat
|
||||
// read "1,5" as 1 and select the singular unit name.
|
||||
let numericValue;
|
||||
if (typeof result[0] === "string") {
|
||||
numericValue = parseFloat(result[0]);
|
||||
} else {
|
||||
numericValue = result[0];
|
||||
}
|
||||
|
||||
result[0] = applyNumberFormatting(
|
||||
result[0],
|
||||
locale,
|
||||
localeOptions,
|
||||
separator,
|
||||
pad,
|
||||
round,
|
||||
roundingFunc,
|
||||
);
|
||||
|
||||
if (full) {
|
||||
let unit;
|
||||
if (bits) {
|
||||
unit = BIT;
|
||||
} else {
|
||||
unit = BYTE;
|
||||
}
|
||||
// Determine singular/plural suffix
|
||||
let suffix;
|
||||
if (numericValue === 1) {
|
||||
suffix = EMPTY;
|
||||
} else {
|
||||
suffix = S;
|
||||
}
|
||||
// Determine symbol — custom fullforms are the complete name, defaults get unit+suffix
|
||||
if (fullforms[e]) {
|
||||
result[1] = fullforms[e];
|
||||
} else {
|
||||
result[1] = STRINGS.fullform[actualStandard][e] + unit + suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the computed result array into the requested output type
|
||||
* @param {Array} result - Result array with formatted value at [0] and symbol at [1]
|
||||
* @param {number} e - Current exponent
|
||||
* @param {string} u - Original resolved symbol (before custom override)
|
||||
* @param {string} output - Output type (ARRAY, OBJECT, STRING)
|
||||
* @param {string} spacer - String separator between value and unit
|
||||
* @returns {string|Array|Object|number} Formatted result in requested type
|
||||
*/
|
||||
export function formatOutput(result, e, u, output, spacer) {
|
||||
if (output === ARRAY) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (output === OBJECT) {
|
||||
return {
|
||||
value: result[0],
|
||||
symbol: result[1],
|
||||
exponent: e,
|
||||
unit: u,
|
||||
};
|
||||
}
|
||||
|
||||
let formatted;
|
||||
if (spacer === SPACE) {
|
||||
formatted = `${result[0]} ${result[1]}`;
|
||||
} else {
|
||||
formatted = result.join(spacer);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user