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