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