debug.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /**
  2. * This is the common logic for both the Node.js and web browser
  3. * implementations of `debug()`.
  4. *
  5. * Expose `debug()` as the module.
  6. */
  7. exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
  8. exports.coerce = coerce;
  9. exports.disable = disable;
  10. exports.enable = enable;
  11. exports.enabled = enabled;
  12. exports.humanize = require('ms');
  13. /**
  14. * The currently active debug mode names, and names to skip.
  15. */
  16. exports.names = [];
  17. exports.skips = [];
  18. /**
  19. * Map of special "%n" handling functions, for the debug "format" argument.
  20. *
  21. * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
  22. */
  23. exports.formatters = {};
  24. /**
  25. * Previous log timestamp.
  26. */
  27. var prevTime;
  28. /**
  29. * Select a color.
  30. * @param {String} namespace
  31. * @return {Number}
  32. * @api private
  33. */
  34. function selectColor(namespace) {
  35. var hash = 0, i;
  36. for (i in namespace) {
  37. hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
  38. hash |= 0; // Convert to 32bit integer
  39. }
  40. return exports.colors[Math.abs(hash) % exports.colors.length];
  41. }
  42. /**
  43. * Create a debugger with the given `namespace`.
  44. *
  45. * @param {String} namespace
  46. * @return {Function}
  47. * @api public
  48. */
  49. function createDebug(namespace) {
  50. function debug() {
  51. // disabled?
  52. if (!debug.enabled) return;
  53. var self = debug;
  54. // set `diff` timestamp
  55. var curr = +new Date();
  56. var ms = curr - (prevTime || curr);
  57. self.diff = ms;
  58. self.prev = prevTime;
  59. self.curr = curr;
  60. prevTime = curr;
  61. // turn the `arguments` into a proper Array
  62. var args = new Array(arguments.length);
  63. for (var i = 0; i < args.length; i++) {
  64. args[i] = arguments[i];
  65. }
  66. args[0] = exports.coerce(args[0]);
  67. if ('string' !== typeof args[0]) {
  68. // anything else let's inspect with %O
  69. args.unshift('%O');
  70. }
  71. // apply any `formatters` transformations
  72. var index = 0;
  73. args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
  74. // if we encounter an escaped % then don't increase the array index
  75. if (match === '%%') return match;
  76. index++;
  77. var formatter = exports.formatters[format];
  78. if ('function' === typeof formatter) {
  79. var val = args[index];
  80. match = formatter.call(self, val);
  81. // now we need to remove `args[index]` since it's inlined in the `format`
  82. args.splice(index, 1);
  83. index--;
  84. }
  85. return match;
  86. });
  87. // apply env-specific formatting (colors, etc.)
  88. exports.formatArgs.call(self, args);
  89. var logFn = debug.log || exports.log || console.log.bind(console);
  90. logFn.apply(self, args);
  91. }
  92. debug.namespace = namespace;
  93. debug.enabled = exports.enabled(namespace);
  94. debug.useColors = exports.useColors();
  95. debug.color = selectColor(namespace);
  96. // env-specific initialization logic for debug instances
  97. if ('function' === typeof exports.init) {
  98. exports.init(debug);
  99. }
  100. return debug;
  101. }
  102. /**
  103. * Enables a debug mode by namespaces. This can include modes
  104. * separated by a colon and wildcards.
  105. *
  106. * @param {String} namespaces
  107. * @api public
  108. */
  109. function enable(namespaces) {
  110. exports.save(namespaces);
  111. exports.names = [];
  112. exports.skips = [];
  113. var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
  114. var len = split.length;
  115. for (var i = 0; i < len; i++) {
  116. if (!split[i]) continue; // ignore empty strings
  117. namespaces = split[i].replace(/\*/g, '.*?');
  118. if (namespaces[0] === '-') {
  119. exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
  120. } else {
  121. exports.names.push(new RegExp('^' + namespaces + '$'));
  122. }
  123. }
  124. }
  125. /**
  126. * Disable debug output.
  127. *
  128. * @api public
  129. */
  130. function disable() {
  131. exports.enable('');
  132. }
  133. /**
  134. * Returns true if the given mode name is enabled, false otherwise.
  135. *
  136. * @param {String} name
  137. * @return {Boolean}
  138. * @api public
  139. */
  140. function enabled(name) {
  141. var i, len;
  142. for (i = 0, len = exports.skips.length; i < len; i++) {
  143. if (exports.skips[i].test(name)) {
  144. return false;
  145. }
  146. }
  147. for (i = 0, len = exports.names.length; i < len; i++) {
  148. if (exports.names[i].test(name)) {
  149. return true;
  150. }
  151. }
  152. return false;
  153. }
  154. /**
  155. * Coerce `val`.
  156. *
  157. * @param {Mixed} val
  158. * @return {Mixed}
  159. * @api private
  160. */
  161. function coerce(val) {
  162. if (val instanceof Error) return val.stack || val.message;
  163. return val;
  164. }