index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*!
  2. * bytes
  3. * Copyright(c) 2012-2014 TJ Holowaychuk
  4. * Copyright(c) 2015 Jed Watson
  5. * MIT Licensed
  6. */
  7. 'use strict';
  8. /**
  9. * Module exports.
  10. * @public
  11. */
  12. module.exports = bytes;
  13. module.exports.format = format;
  14. module.exports.parse = parse;
  15. /**
  16. * Module variables.
  17. * @private
  18. */
  19. var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
  20. var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
  21. var map = {
  22. b: 1,
  23. kb: 1 << 10,
  24. mb: 1 << 20,
  25. gb: 1 << 30,
  26. tb: Math.pow(1024, 4),
  27. pb: Math.pow(1024, 5),
  28. };
  29. var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i;
  30. /**
  31. * Convert the given value in bytes into a string or parse to string to an integer in bytes.
  32. *
  33. * @param {string|number} value
  34. * @param {{
  35. * case: [string],
  36. * decimalPlaces: [number]
  37. * fixedDecimals: [boolean]
  38. * thousandsSeparator: [string]
  39. * unitSeparator: [string]
  40. * }} [options] bytes options.
  41. *
  42. * @returns {string|number|null}
  43. */
  44. function bytes(value, options) {
  45. if (typeof value === 'string') {
  46. return parse(value);
  47. }
  48. if (typeof value === 'number') {
  49. return format(value, options);
  50. }
  51. return null;
  52. }
  53. /**
  54. * Format the given value in bytes into a string.
  55. *
  56. * If the value is negative, it is kept as such. If it is a float,
  57. * it is rounded.
  58. *
  59. * @param {number} value
  60. * @param {object} [options]
  61. * @param {number} [options.decimalPlaces=2]
  62. * @param {number} [options.fixedDecimals=false]
  63. * @param {string} [options.thousandsSeparator=]
  64. * @param {string} [options.unit=]
  65. * @param {string} [options.unitSeparator=]
  66. *
  67. * @returns {string|null}
  68. * @public
  69. */
  70. function format(value, options) {
  71. if (!Number.isFinite(value)) {
  72. return null;
  73. }
  74. var mag = Math.abs(value);
  75. var thousandsSeparator = (options && options.thousandsSeparator) || '';
  76. var unitSeparator = (options && options.unitSeparator) || '';
  77. var decimalPlaces = (options && options.decimalPlaces !== undefined) ? options.decimalPlaces : 2;
  78. var fixedDecimals = Boolean(options && options.fixedDecimals);
  79. var unit = (options && options.unit) || '';
  80. if (!unit || !map[unit.toLowerCase()]) {
  81. if (mag >= map.pb) {
  82. unit = 'PB';
  83. } else if (mag >= map.tb) {
  84. unit = 'TB';
  85. } else if (mag >= map.gb) {
  86. unit = 'GB';
  87. } else if (mag >= map.mb) {
  88. unit = 'MB';
  89. } else if (mag >= map.kb) {
  90. unit = 'KB';
  91. } else {
  92. unit = 'B';
  93. }
  94. }
  95. var val = value / map[unit.toLowerCase()];
  96. var str = val.toFixed(decimalPlaces);
  97. if (!fixedDecimals) {
  98. str = str.replace(formatDecimalsRegExp, '$1');
  99. }
  100. if (thousandsSeparator) {
  101. str = str.split('.').map(function (s, i) {
  102. return i === 0
  103. ? s.replace(formatThousandsRegExp, thousandsSeparator)
  104. : s
  105. }).join('.');
  106. }
  107. return str + unitSeparator + unit;
  108. }
  109. /**
  110. * Parse the string value into an integer in bytes.
  111. *
  112. * If no unit is given, it is assumed the value is in bytes.
  113. *
  114. * @param {number|string} val
  115. *
  116. * @returns {number|null}
  117. * @public
  118. */
  119. function parse(val) {
  120. if (typeof val === 'number' && !isNaN(val)) {
  121. return val;
  122. }
  123. if (typeof val !== 'string') {
  124. return null;
  125. }
  126. // Test if the string passed is valid
  127. var results = parseRegExp.exec(val);
  128. var floatValue;
  129. var unit = 'b';
  130. if (!results) {
  131. // Nothing could be extracted from the given string
  132. floatValue = parseInt(val, 10);
  133. unit = 'b'
  134. } else {
  135. // Retrieve the value and the unit
  136. floatValue = parseFloat(results[1]);
  137. unit = results[4].toLowerCase();
  138. }
  139. if (isNaN(floatValue)) {
  140. return null;
  141. }
  142. return Math.floor(map[unit] * floatValue);
  143. }