• 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
7function 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		let i;
170		const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
171		const len = split.length;
172
173		for (i = 0; i < len; i++) {
174			if (!split[i]) {
175				// ignore empty strings
176				continue;
177			}
178
179			namespaces = split[i].replace(/\*/g, '.*?');
180
181			if (namespaces[0] === '-') {
182				createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
183			} else {
184				createDebug.names.push(new RegExp('^' + namespaces + '$'));
185			}
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	/**
262	* XXX DO NOT USE. This is a temporary stub function.
263	* XXX It WILL be removed in the next major release.
264	*/
265	function destroy() {
266		console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
267	}
268
269	createDebug.enable(createDebug.load());
270
271	return createDebug;
272}
273
274module.exports = setup;
275