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