Skip to content

Instantly share code, notes, and snippets.

@NuroDev
Last active August 19, 2022 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NuroDev/69c702535416824dbec3c97fc32e88fa to your computer and use it in GitHub Desktop.
Save NuroDev/69c702535416824dbec3c97fc32e88fa to your computer and use it in GitHub Desktop.
πŸ“ Bytes ─ TypeScript ESM fork of the `bytes` NPM package
type ByteFormatStr = 'b' | 'gb' | 'kb' | 'mb' | 'pb' | 'tb';
interface ByteOptions {
decimalPlaces?: number;
fixedDecimals?: boolean;
thousandsSeparator?: string;
unit?: ByteFormatStr;
unitSeparator?: string;
}
/**
* @name bytes
*
* @description Convert the given value in bytes into a string or parse to string to an integer in bytes.
*
* @param {string | number} value
* @param {Object} [options] bytes options
*
* @returns {string | number | null}
*/
function bytes(value: `${number}${ByteFormatStr}`): number;
function bytes(value: number): string;
function bytes(value: number, options: ByteOptions): string;
function bytes(
...args: [number] | [number, ByteOptions] | [`${number}${ByteFormatStr}`]
): string | number | null {
const [value] = args;
const sizeMap: Record<ByteFormatStr, number> = {
b: 1,
gb: 1 << 30,
kb: 1 << 10,
mb: 1 << 20,
pb: Math.pow(1024, 5),
tb: Math.pow(1024, 4),
};
if (typeof value === 'string') {
if (typeof value === 'number' && !isNaN(value)) return value;
if (typeof value !== 'string') return null;
const results = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i.exec(value);
const floatValue = !results ? parseInt(value, 10) : parseFloat(results[1]);
const unit: ByteFormatStr = !results ? 'b' : (results[4].toLowerCase() as ByteFormatStr);
if (isNaN(floatValue)) return null;
return Math.floor(sizeMap[unit] * floatValue);
}
if (typeof value === 'number') {
const options = args[1] || {
decimalPlaces: 2,
fixedDecimals: false,
thousandsSeparator: '',
unit: '',
unitSeparator: '',
};
if (!Number.isFinite(value)) return null;
const mag = Math.abs(value);
let unit = options.unit;
if (!unit || !sizeMap[unit.toLowerCase()]) {
if (mag >= sizeMap.pb) {
unit = 'pb';
} else if (mag >= sizeMap.tb) {
unit = 'tb';
} else if (mag >= sizeMap.gb) {
unit = 'gb';
} else if (mag >= sizeMap.mb) {
unit = 'mb';
} else if (mag >= sizeMap.kb) {
unit = 'kb';
} else {
unit = 'b';
}
}
const val = value / sizeMap[unit.toLowerCase()];
let str = val.toFixed(options.decimalPlaces);
if (!Boolean(options.fixedDecimals)) {
str = str.replace(/(?:\.0*|(\.[^0]+)0+)$/, '$1');
}
if (options.thousandsSeparator) {
str = str
.split('.')
.map((s, i) =>
i === 0
? s.replace(/\B(?=(\d{3})+(?!\d))/g, options.thousandsSeparator || '')
: s,
)
.join('.');
}
return str + options.unitSeparator + unit;
}
return null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment