You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
4.0 KiB

8 years ago
  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 = debug;
  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, lowercased letter, i.e. "n".
  22. */
  23. exports.formatters = {};
  24. /**
  25. * Previously assigned color.
  26. */
  27. var prevColor = 0;
  28. /**
  29. * Previous log timestamp.
  30. */
  31. var prevTime;
  32. /**
  33. * Select a color.
  34. *
  35. * @return {Number}
  36. * @api private
  37. */
  38. function selectColor() {
  39. return exports.colors[prevColor++ % exports.colors.length];
  40. }
  41. /**
  42. * Create a debugger with the given `namespace`.
  43. *
  44. * @param {String} namespace
  45. * @return {Function}
  46. * @api public
  47. */
  48. function debug(namespace) {
  49. // define the `disabled` version
  50. function disabled() {
  51. }
  52. disabled.enabled = false;
  53. // define the `enabled` version
  54. function enabled() {
  55. var self = enabled;
  56. // set `diff` timestamp
  57. var curr = +new Date();
  58. var ms = curr - (prevTime || curr);
  59. self.diff = ms;
  60. self.prev = prevTime;
  61. self.curr = curr;
  62. prevTime = curr;
  63. // add the `color` if not set
  64. if (null == self.useColors) self.useColors = exports.useColors();
  65. if (null == self.color && self.useColors) self.color = selectColor();
  66. var args = Array.prototype.slice.call(arguments);
  67. args[0] = exports.coerce(args[0]);
  68. if ('string' !== typeof args[0]) {
  69. // anything else let's inspect with %o
  70. args = ['%o'].concat(args);
  71. }
  72. // apply any `formatters` transformations
  73. var index = 0;
  74. args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
  75. // if we encounter an escaped % then don't increase the array index
  76. if (match === '%%') return match;
  77. index++;
  78. var formatter = exports.formatters[format];
  79. if ('function' === typeof formatter) {
  80. var val = args[index];
  81. match = formatter.call(self, val);
  82. // now we need to remove `args[index]` since it's inlined in the `format`
  83. args.splice(index, 1);
  84. index--;
  85. }
  86. return match;
  87. });
  88. if ('function' === typeof exports.formatArgs) {
  89. args = exports.formatArgs.apply(self, args);
  90. }
  91. var logFn = enabled.log || exports.log || console.log.bind(console);
  92. logFn.apply(self, args);
  93. }
  94. enabled.enabled = true;
  95. var fn = exports.enabled(namespace) ? enabled : disabled;
  96. fn.namespace = namespace;
  97. return fn;
  98. }
  99. /**
  100. * Enables a debug mode by namespaces. This can include modes
  101. * separated by a colon and wildcards.
  102. *
  103. * @param {String} namespaces
  104. * @api public
  105. */
  106. function enable(namespaces) {
  107. exports.save(namespaces);
  108. var split = (namespaces || '').split(/[\s,]+/);
  109. var len = split.length;
  110. for (var i = 0; i < len; i++) {
  111. if (!split[i]) continue; // ignore empty strings
  112. namespaces = split[i].replace(/\*/g, '.*?');
  113. if (namespaces[0] === '-') {
  114. exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
  115. } else {
  116. exports.names.push(new RegExp('^' + namespaces + '$'));
  117. }
  118. }
  119. }
  120. /**
  121. * Disable debug output.
  122. *
  123. * @api public
  124. */
  125. function disable() {
  126. exports.enable('');
  127. }
  128. /**
  129. * Returns true if the given mode name is enabled, false otherwise.
  130. *
  131. * @param {String} name
  132. * @return {Boolean}
  133. * @api public
  134. */
  135. function enabled(name) {
  136. var i, len;
  137. for (i = 0, len = exports.skips.length; i < len; i++) {
  138. if (exports.skips[i].test(name)) {
  139. return false;
  140. }
  141. }
  142. for (i = 0, len = exports.names.length; i < len; i++) {
  143. if (exports.names[i].test(name)) {
  144. return true;
  145. }
  146. }
  147. return false;
  148. }
  149. /**
  150. * Coerce `val`.
  151. *
  152. * @param {Mixed} val
  153. * @return {Mixed}
  154. * @api private
  155. */
  156. function coerce(val) {
  157. if (val instanceof Error) return val.stack || val.message;
  158. return val;
  159. }