common.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**
  2. * This is the common logic for both the Node.js and web browser
  3. * implementations of `debug()`.
  4. */
  5. function setup(env) {
  6. createDebug.debug = createDebug;
  7. createDebug.default = createDebug;
  8. createDebug.coerce = coerce;
  9. createDebug.disable = disable;
  10. createDebug.enable = enable;
  11. createDebug.enabled = enabled;
  12. createDebug.humanize = require('ms');
  13. createDebug.destroy = destroy;
  14. Object.keys(env).forEach(key => {
  15. createDebug[key] = env[key];
  16. });
  17. /**
  18. * The currently active debug mode names, and names to skip.
  19. */
  20. createDebug.names = [];
  21. createDebug.skips = [];
  22. /**
  23. * Map of special "%n" handling functions, for the debug "format" argument.
  24. *
  25. * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
  26. */
  27. createDebug.formatters = {};
  28. /**
  29. * Selects a color for a debug namespace
  30. * @param {String} namespace The namespace string for the debug instance to be colored
  31. * @return {Number|String} An ANSI color code for the given namespace
  32. * @api private
  33. */
  34. function selectColor(namespace) {
  35. let hash = 0;
  36. for (let i = 0; i < namespace.length; i++) {
  37. hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
  38. hash |= 0; // Convert to 32bit integer
  39. }
  40. return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
  41. }
  42. createDebug.selectColor = selectColor;
  43. /**
  44. * Create a debugger with the given `namespace`.
  45. *
  46. * @param {String} namespace
  47. * @return {Function}
  48. * @api public
  49. */
  50. function createDebug(namespace) {
  51. let prevTime;
  52. let enableOverride = null;
  53. let namespacesCache;
  54. let enabledCache;
  55. function debug(...args) {
  56. // Disabled?
  57. if (!debug.enabled) {
  58. return;
  59. }
  60. const self = debug;
  61. // Set `diff` timestamp
  62. const curr = Number(new Date());
  63. const ms = curr - (prevTime || curr);
  64. self.diff = ms;
  65. self.prev = prevTime;
  66. self.curr = curr;
  67. prevTime = curr;
  68. args[0] = createDebug.coerce(args[0]);
  69. if (typeof args[0] !== 'string') {
  70. // Anything else let's inspect with %O
  71. args.unshift('%O');
  72. }
  73. // Apply any `formatters` transformations
  74. let index = 0;
  75. args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
  76. // If we encounter an escaped % then don't increase the array index
  77. if (match === '%%') {
  78. return '%';
  79. }
  80. index++;
  81. const formatter = createDebug.formatters[format];
  82. if (typeof formatter === 'function') {
  83. const val = args[index];
  84. match = formatter.call(self, val);
  85. // Now we need to remove `args[index]` since it's inlined in the `format`
  86. args.splice(index, 1);
  87. index--;
  88. }
  89. return match;
  90. });
  91. // Apply env-specific formatting (colors, etc.)
  92. createDebug.formatArgs.call(self, args);
  93. const logFn = self.log || createDebug.log;
  94. logFn.apply(self, args);
  95. }
  96. debug.namespace = namespace;
  97. debug.useColors = createDebug.useColors();
  98. debug.color = createDebug.selectColor(namespace);
  99. debug.extend = extend;
  100. debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
  101. Object.defineProperty(debug, 'enabled', {
  102. enumerable: true,
  103. configurable: false,
  104. get: () => {
  105. if (enableOverride !== null) {
  106. return enableOverride;
  107. }
  108. if (namespacesCache !== createDebug.namespaces) {
  109. namespacesCache = createDebug.namespaces;
  110. enabledCache = createDebug.enabled(namespace);
  111. }
  112. return enabledCache;
  113. },
  114. set: v => {
  115. enableOverride = v;
  116. }
  117. });
  118. // Env-specific initialization logic for debug instances
  119. if (typeof createDebug.init === 'function') {
  120. createDebug.init(debug);
  121. }
  122. return debug;
  123. }
  124. function extend(namespace, delimiter) {
  125. const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
  126. newDebug.log = this.log;
  127. return newDebug;
  128. }
  129. /**
  130. * Enables a debug mode by namespaces. This can include modes
  131. * separated by a colon and wildcards.
  132. *
  133. * @param {String} namespaces
  134. * @api public
  135. */
  136. function enable(namespaces) {
  137. createDebug.save(namespaces);
  138. createDebug.namespaces = namespaces;
  139. createDebug.names = [];
  140. createDebug.skips = [];
  141. let i;
  142. const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
  143. const len = split.length;
  144. for (i = 0; i < len; i++) {
  145. if (!split[i]) {
  146. // ignore empty strings
  147. continue;
  148. }
  149. namespaces = split[i].replace(/\*/g, '.*?');
  150. if (namespaces[0] === '-') {
  151. createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
  152. } else {
  153. createDebug.names.push(new RegExp('^' + namespaces + '$'));
  154. }
  155. }
  156. }
  157. /**
  158. * Disable debug output.
  159. *
  160. * @return {String} namespaces
  161. * @api public
  162. */
  163. function disable() {
  164. const namespaces = [
  165. ...createDebug.names.map(toNamespace),
  166. ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
  167. ].join(',');
  168. createDebug.enable('');
  169. return namespaces;
  170. }
  171. /**
  172. * Returns true if the given mode name is enabled, false otherwise.
  173. *
  174. * @param {String} name
  175. * @return {Boolean}
  176. * @api public
  177. */
  178. function enabled(name) {
  179. if (name[name.length - 1] === '*') {
  180. return true;
  181. }
  182. let i;
  183. let len;
  184. for (i = 0, len = createDebug.skips.length; i < len; i++) {
  185. if (createDebug.skips[i].test(name)) {
  186. return false;
  187. }
  188. }
  189. for (i = 0, len = createDebug.names.length; i < len; i++) {
  190. if (createDebug.names[i].test(name)) {
  191. return true;
  192. }
  193. }
  194. return false;
  195. }
  196. /**
  197. * Convert regexp to namespace
  198. *
  199. * @param {RegExp} regxep
  200. * @return {String} namespace
  201. * @api private
  202. */
  203. function toNamespace(regexp) {
  204. return regexp.toString()
  205. .substring(2, regexp.toString().length - 2)
  206. .replace(/\.\*\?$/, '*');
  207. }
  208. /**
  209. * Coerce `val`.
  210. *
  211. * @param {Mixed} val
  212. * @return {Mixed}
  213. * @api private
  214. */
  215. function coerce(val) {
  216. if (val instanceof Error) {
  217. return val.stack || val.message;
  218. }
  219. return val;
  220. }
  221. /**
  222. * XXX DO NOT USE. This is a temporary stub function.
  223. * XXX It WILL be removed in the next major release.
  224. */
  225. function destroy() {
  226. console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
  227. }
  228. createDebug.enable(createDebug.load());
  229. return createDebug;
  230. }
  231. module.exports = setup;