| 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 | createDebug.destroy = destroy;
|
|---|
| 16 |
|
|---|
| 17 | Object.keys(env).forEach(key => {
|
|---|
| 18 | createDebug[key] = env[key];
|
|---|
| 19 | });
|
|---|
| 20 |
|
|---|
| 21 | /**
|
|---|
| 22 | * The currently active debug mode names, and names to skip.
|
|---|
| 23 | */
|
|---|
| 24 |
|
|---|
| 25 | createDebug.names = [];
|
|---|
| 26 | createDebug.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 | createDebug.formatters = {};
|
|---|
| 34 |
|
|---|
| 35 | /**
|
|---|
| 36 | * Selects a color for a debug namespace
|
|---|
| 37 | * @param {String} namespace The namespace string for the debug instance to be colored
|
|---|
| 38 | * @return {Number|String} An ANSI color code for the given namespace
|
|---|
| 39 | * @api private
|
|---|
| 40 | */
|
|---|
| 41 | function selectColor(namespace) {
|
|---|
| 42 | let hash = 0;
|
|---|
| 43 |
|
|---|
| 44 | for (let i = 0; i < namespace.length; i++) {
|
|---|
| 45 | hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
|
|---|
| 46 | hash |= 0; // Convert to 32bit integer
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
|
|---|
| 50 | }
|
|---|
| 51 | createDebug.selectColor = selectColor;
|
|---|
| 52 |
|
|---|
| 53 | /**
|
|---|
| 54 | * Create a debugger with the given `namespace`.
|
|---|
| 55 | *
|
|---|
| 56 | * @param {String} namespace
|
|---|
| 57 | * @return {Function}
|
|---|
| 58 | * @api public
|
|---|
| 59 | */
|
|---|
| 60 | function createDebug(namespace) {
|
|---|
| 61 | let prevTime;
|
|---|
| 62 | let enableOverride = null;
|
|---|
| 63 | let namespacesCache;
|
|---|
| 64 | let enabledCache;
|
|---|
| 65 |
|
|---|
| 66 | function debug(...args) {
|
|---|
| 67 | // Disabled?
|
|---|
| 68 | if (!debug.enabled) {
|
|---|
| 69 | return;
|
|---|
| 70 | }
|
|---|
| 71 |
|
|---|
| 72 | const self = debug;
|
|---|
| 73 |
|
|---|
| 74 | // Set `diff` timestamp
|
|---|
| 75 | const curr = Number(new Date());
|
|---|
| 76 | const ms = curr - (prevTime || curr);
|
|---|
| 77 | self.diff = ms;
|
|---|
| 78 | self.prev = prevTime;
|
|---|
| 79 | self.curr = curr;
|
|---|
| 80 | prevTime = curr;
|
|---|
| 81 |
|
|---|
| 82 | args[0] = createDebug.coerce(args[0]);
|
|---|
| 83 |
|
|---|
| 84 | if (typeof args[0] !== 'string') {
|
|---|
| 85 | // Anything else let's inspect with %O
|
|---|
| 86 | args.unshift('%O');
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | // Apply any `formatters` transformations
|
|---|
| 90 | let index = 0;
|
|---|
| 91 | args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
|
|---|
| 92 | // If we encounter an escaped % then don't increase the array index
|
|---|
| 93 | if (match === '%%') {
|
|---|
| 94 | return '%';
|
|---|
| 95 | }
|
|---|
| 96 | index++;
|
|---|
| 97 | const formatter = createDebug.formatters[format];
|
|---|
| 98 | if (typeof formatter === 'function') {
|
|---|
| 99 | const val = args[index];
|
|---|
| 100 | match = formatter.call(self, val);
|
|---|
| 101 |
|
|---|
| 102 | // Now we need to remove `args[index]` since it's inlined in the `format`
|
|---|
| 103 | args.splice(index, 1);
|
|---|
| 104 | index--;
|
|---|
| 105 | }
|
|---|
| 106 | return match;
|
|---|
| 107 | });
|
|---|
| 108 |
|
|---|
| 109 | // Apply env-specific formatting (colors, etc.)
|
|---|
| 110 | createDebug.formatArgs.call(self, args);
|
|---|
| 111 |
|
|---|
| 112 | const logFn = self.log || createDebug.log;
|
|---|
| 113 | logFn.apply(self, args);
|
|---|
| 114 | }
|
|---|
| 115 |
|
|---|
| 116 | debug.namespace = namespace;
|
|---|
| 117 | debug.useColors = createDebug.useColors();
|
|---|
| 118 | debug.color = createDebug.selectColor(namespace);
|
|---|
| 119 | debug.extend = extend;
|
|---|
| 120 | debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
|
|---|
| 121 |
|
|---|
| 122 | Object.defineProperty(debug, 'enabled', {
|
|---|
| 123 | enumerable: true,
|
|---|
| 124 | configurable: false,
|
|---|
| 125 | get: () => {
|
|---|
| 126 | if (enableOverride !== null) {
|
|---|
| 127 | return enableOverride;
|
|---|
| 128 | }
|
|---|
| 129 | if (namespacesCache !== createDebug.namespaces) {
|
|---|
| 130 | namespacesCache = createDebug.namespaces;
|
|---|
| 131 | enabledCache = createDebug.enabled(namespace);
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | return enabledCache;
|
|---|
| 135 | },
|
|---|
| 136 | set: v => {
|
|---|
| 137 | enableOverride = v;
|
|---|
| 138 | }
|
|---|
| 139 | });
|
|---|
| 140 |
|
|---|
| 141 | // Env-specific initialization logic for debug instances
|
|---|
| 142 | if (typeof createDebug.init === 'function') {
|
|---|
| 143 | createDebug.init(debug);
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | return debug;
|
|---|
| 147 | }
|
|---|
| 148 |
|
|---|
| 149 | function extend(namespace, delimiter) {
|
|---|
| 150 | const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
|
|---|
| 151 | newDebug.log = this.log;
|
|---|
| 152 | return newDebug;
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | /**
|
|---|
| 156 | * Enables a debug mode by namespaces. This can include modes
|
|---|
| 157 | * separated by a colon and wildcards.
|
|---|
| 158 | *
|
|---|
| 159 | * @param {String} namespaces
|
|---|
| 160 | * @api public
|
|---|
| 161 | */
|
|---|
| 162 | function enable(namespaces) {
|
|---|
| 163 | createDebug.save(namespaces);
|
|---|
| 164 | createDebug.namespaces = namespaces;
|
|---|
| 165 |
|
|---|
| 166 | createDebug.names = [];
|
|---|
| 167 | createDebug.skips = [];
|
|---|
| 168 |
|
|---|
| 169 | const split = (typeof namespaces === 'string' ? namespaces : '')
|
|---|
| 170 | .trim()
|
|---|
| 171 | .replace(/\s+/g, ',')
|
|---|
| 172 | .split(',')
|
|---|
| 173 | .filter(Boolean);
|
|---|
| 174 |
|
|---|
| 175 | for (const ns of split) {
|
|---|
| 176 | if (ns[0] === '-') {
|
|---|
| 177 | createDebug.skips.push(ns.slice(1));
|
|---|
| 178 | } else {
|
|---|
| 179 | createDebug.names.push(ns);
|
|---|
| 180 | }
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | /**
|
|---|
| 185 | * Checks if the given string matches a namespace template, honoring
|
|---|
| 186 | * asterisks as wildcards.
|
|---|
| 187 | *
|
|---|
| 188 | * @param {String} search
|
|---|
| 189 | * @param {String} template
|
|---|
| 190 | * @return {Boolean}
|
|---|
| 191 | */
|
|---|
| 192 | function matchesTemplate(search, template) {
|
|---|
| 193 | let searchIndex = 0;
|
|---|
| 194 | let templateIndex = 0;
|
|---|
| 195 | let starIndex = -1;
|
|---|
| 196 | let matchIndex = 0;
|
|---|
| 197 |
|
|---|
| 198 | while (searchIndex < search.length) {
|
|---|
| 199 | if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
|
|---|
| 200 | // Match character or proceed with wildcard
|
|---|
| 201 | if (template[templateIndex] === '*') {
|
|---|
| 202 | starIndex = templateIndex;
|
|---|
| 203 | matchIndex = searchIndex;
|
|---|
| 204 | templateIndex++; // Skip the '*'
|
|---|
| 205 | } else {
|
|---|
| 206 | searchIndex++;
|
|---|
| 207 | templateIndex++;
|
|---|
| 208 | }
|
|---|
| 209 | } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition
|
|---|
| 210 | // Backtrack to the last '*' and try to match more characters
|
|---|
| 211 | templateIndex = starIndex + 1;
|
|---|
| 212 | matchIndex++;
|
|---|
| 213 | searchIndex = matchIndex;
|
|---|
| 214 | } else {
|
|---|
| 215 | return false; // No match
|
|---|
| 216 | }
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 | // Handle trailing '*' in template
|
|---|
| 220 | while (templateIndex < template.length && template[templateIndex] === '*') {
|
|---|
| 221 | templateIndex++;
|
|---|
| 222 | }
|
|---|
| 223 |
|
|---|
| 224 | return templateIndex === template.length;
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | /**
|
|---|
| 228 | * Disable debug output.
|
|---|
| 229 | *
|
|---|
| 230 | * @return {String} namespaces
|
|---|
| 231 | * @api public
|
|---|
| 232 | */
|
|---|
| 233 | function disable() {
|
|---|
| 234 | const namespaces = [
|
|---|
| 235 | ...createDebug.names,
|
|---|
| 236 | ...createDebug.skips.map(namespace => '-' + namespace)
|
|---|
| 237 | ].join(',');
|
|---|
| 238 | createDebug.enable('');
|
|---|
| 239 | return namespaces;
|
|---|
| 240 | }
|
|---|
| 241 |
|
|---|
| 242 | /**
|
|---|
| 243 | * Returns true if the given mode name is enabled, false otherwise.
|
|---|
| 244 | *
|
|---|
| 245 | * @param {String} name
|
|---|
| 246 | * @return {Boolean}
|
|---|
| 247 | * @api public
|
|---|
| 248 | */
|
|---|
| 249 | function enabled(name) {
|
|---|
| 250 | for (const skip of createDebug.skips) {
|
|---|
| 251 | if (matchesTemplate(name, skip)) {
|
|---|
| 252 | return false;
|
|---|
| 253 | }
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | for (const ns of createDebug.names) {
|
|---|
| 257 | if (matchesTemplate(name, ns)) {
|
|---|
| 258 | return true;
|
|---|
| 259 | }
|
|---|
| 260 | }
|
|---|
| 261 |
|
|---|
| 262 | return false;
|
|---|
| 263 | }
|
|---|
| 264 |
|
|---|
| 265 | /**
|
|---|
| 266 | * Coerce `val`.
|
|---|
| 267 | *
|
|---|
| 268 | * @param {Mixed} val
|
|---|
| 269 | * @return {Mixed}
|
|---|
| 270 | * @api private
|
|---|
| 271 | */
|
|---|
| 272 | function coerce(val) {
|
|---|
| 273 | if (val instanceof Error) {
|
|---|
| 274 | return val.stack || val.message;
|
|---|
| 275 | }
|
|---|
| 276 | return val;
|
|---|
| 277 | }
|
|---|
| 278 |
|
|---|
| 279 | /**
|
|---|
| 280 | * XXX DO NOT USE. This is a temporary stub function.
|
|---|
| 281 | * XXX It WILL be removed in the next major release.
|
|---|
| 282 | */
|
|---|
| 283 | function destroy() {
|
|---|
| 284 | console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | createDebug.enable(createDebug.load());
|
|---|
| 288 |
|
|---|
| 289 | return createDebug;
|
|---|
| 290 | }
|
|---|
| 291 |
|
|---|
| 292 | module.exports = setup;
|
|---|