'use strict'; const units = { b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3, tb: 1024 ** 4, pb: 1024 ** 5, }; const formatThousands = /\B(?=(\d{3})+(?!\d))/g; const trimZeros = /(?:\.0*|(\.[^0]+)0+)$/; const parsePattern = /^([-+]?\d+(?:\.\d+)?) *(kb|mb|gb|tb|pb)$/i; function bytes(value, options) { return typeof value === 'string' ? parse(value) : typeof value === 'number' ? format(value, options) : null; } function format(value, opts = {}) { if (!Number.isFinite(value)) return null; const mag = Math.abs(value); const { decimalPlaces = 2, fixedDecimals = false, thousandsSeparator = '', unitSeparator = '', unit = getAutoUnit(mag), } = opts; const lowerUnit = unit.toLowerCase(); const factor = units[lowerUnit] || 1; let result = (value / factor).toFixed(decimalPlaces); if (!fixedDecimals) result = result.replace(trimZeros, '$1'); if (thousandsSeparator) { const parts = result.split('.'); parts[0] = parts[0].replace(formatThousands, thousandsSeparator); result = parts.join('.'); } return result + unitSeparator + unit.toUpperCase(); } function parse(str) { if (typeof str === 'number') return str; if (typeof str !== 'string') return null; const match = parsePattern.exec(str.trim()); const num = match ? parseFloat(match[1]) : parseInt(str, 10); const unit = match ? match[2].toLowerCase() : 'b'; return isNaN(num) ? null : Math.floor(num * (units[unit] || 1)); } function getAutoUnit(value) { if (value >= units.pb) return 'PB'; if (value >= units.tb) return 'TB'; if (value >= units.gb) return 'GB'; if (value >= units.mb) return 'MB'; if (value >= units.kb) return 'KB'; return 'B'; } module.exports = bytes; module.exports.format = format; module.exports.parse = parse;