3 * Copyright(c) 2012-2014 TJ Holowaychuk
4 * Copyright(c) 2015 Jed Watson
15 module.exports = bytes;
16 module.exports.format = format;
17 module.exports.parse = parse;
24 var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
26 var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
33 tb: ((1 << 30) * 1024)
36 // TODO: use is-finite module?
37 var numberIsFinite = Number.isFinite || function (v) { return typeof v === 'number' && isFinite(v); };
39 var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb)$/i;
42 * Convert the given value in bytes into a string or parse to string to an integer in bytes.
44 * @param {string|number} value
47 * decimalPlaces: [number]
48 * fixedDecimals: [boolean]
49 * thousandsSeparator: [string]
50 * unitSeparator: [string]
51 * }} [options] bytes options.
53 * @returns {string|number|null}
56 function bytes(value, options) {
57 if (typeof value === 'string') {
61 if (typeof value === 'number') {
62 return format(value, options);
69 * Format the given value in bytes into a string.
71 * If the value is negative, it is kept as such. If it is a float,
74 * @param {number} value
75 * @param {object} [options]
76 * @param {number} [options.decimalPlaces=2]
77 * @param {number} [options.fixedDecimals=false]
78 * @param {string} [options.thousandsSeparator=]
79 * @param {string} [options.unitSeparator=]
81 * @returns {string|null}
85 function format(value, options) {
86 if (!numberIsFinite(value)) {
90 var mag = Math.abs(value);
91 var thousandsSeparator = (options && options.thousandsSeparator) || '';
92 var unitSeparator = (options && options.unitSeparator) || '';
93 var decimalPlaces = (options && options.decimalPlaces !== undefined) ? options.decimalPlaces : 2;
94 var fixedDecimals = Boolean(options && options.fixedDecimals);
99 } else if (mag >= map.gb) {
101 } else if (mag >= map.mb) {
103 } else if (mag >= map.kb) {
107 var val = value / map[unit.toLowerCase()];
108 var str = val.toFixed(decimalPlaces);
110 if (!fixedDecimals) {
111 str = str.replace(formatDecimalsRegExp, '$1');
114 if (thousandsSeparator) {
115 str = str.replace(formatThousandsRegExp, thousandsSeparator);
118 return str + unitSeparator + unit;
122 * Parse the string value into an integer in bytes.
124 * If no unit is given, it is assumed the value is in bytes.
126 * @param {number|string} val
128 * @returns {number|null}
132 function parse(val) {
133 if (typeof val === 'number' && !isNaN(val)) {
137 if (typeof val !== 'string') {
141 // Test if the string passed is valid
142 var results = parseRegExp.exec(val);
147 // Nothing could be extracted from the given string
148 floatValue = parseInt(val, 10);
151 // Retrieve the value and the unit
152 floatValue = parseFloat(results[1]);
153 unit = results[4].toLowerCase();
156 return Math.floor(map[unit] * floatValue);