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