• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* eslint-env browser */
2
3/**
4 * This is the web browser implementation of `debug()`.
5 */
6
7exports.formatArgs = formatArgs;
8exports.save = save;
9exports.load = load;
10exports.useColors = useColors;
11exports.storage = localstorage();
12exports.destroy = (() => {
13	let warned = false;
14
15	return () => {
16		if (!warned) {
17			warned = true;
18			console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
19		}
20	};
21})();
22
23/**
24 * Colors.
25 */
26
27exports.colors = [
28	'#0000CC',
29	'#0000FF',
30	'#0033CC',
31	'#0033FF',
32	'#0066CC',
33	'#0066FF',
34	'#0099CC',
35	'#0099FF',
36	'#00CC00',
37	'#00CC33',
38	'#00CC66',
39	'#00CC99',
40	'#00CCCC',
41	'#00CCFF',
42	'#3300CC',
43	'#3300FF',
44	'#3333CC',
45	'#3333FF',
46	'#3366CC',
47	'#3366FF',
48	'#3399CC',
49	'#3399FF',
50	'#33CC00',
51	'#33CC33',
52	'#33CC66',
53	'#33CC99',
54	'#33CCCC',
55	'#33CCFF',
56	'#6600CC',
57	'#6600FF',
58	'#6633CC',
59	'#6633FF',
60	'#66CC00',
61	'#66CC33',
62	'#9900CC',
63	'#9900FF',
64	'#9933CC',
65	'#9933FF',
66	'#99CC00',
67	'#99CC33',
68	'#CC0000',
69	'#CC0033',
70	'#CC0066',
71	'#CC0099',
72	'#CC00CC',
73	'#CC00FF',
74	'#CC3300',
75	'#CC3333',
76	'#CC3366',
77	'#CC3399',
78	'#CC33CC',
79	'#CC33FF',
80	'#CC6600',
81	'#CC6633',
82	'#CC9900',
83	'#CC9933',
84	'#CCCC00',
85	'#CCCC33',
86	'#FF0000',
87	'#FF0033',
88	'#FF0066',
89	'#FF0099',
90	'#FF00CC',
91	'#FF00FF',
92	'#FF3300',
93	'#FF3333',
94	'#FF3366',
95	'#FF3399',
96	'#FF33CC',
97	'#FF33FF',
98	'#FF6600',
99	'#FF6633',
100	'#FF9900',
101	'#FF9933',
102	'#FFCC00',
103	'#FFCC33'
104];
105
106/**
107 * Currently only WebKit-based Web Inspectors, Firefox >= v31,
108 * and the Firebug extension (any Firefox version) are known
109 * to support "%c" CSS customizations.
110 *
111 * TODO: add a `localStorage` variable to explicitly enable/disable colors
112 */
113
114// eslint-disable-next-line complexity
115function useColors() {
116	// NB: In an Electron preload script, document will be defined but not fully
117	// initialized. Since we know we're in Chrome, we'll just detect this case
118	// explicitly
119	if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
120		return true;
121	}
122
123	// Internet Explorer and Edge do not support colors.
124	if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
125		return false;
126	}
127
128	// Is webkit? http://stackoverflow.com/a/16459606/376773
129	// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
130	return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
131		// Is firebug? http://stackoverflow.com/a/398120/376773
132		(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
133		// Is firefox >= v31?
134		// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
135		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
136		// Double check webkit in userAgent just in case we are in a worker
137		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
138}
139
140/**
141 * Colorize log arguments if enabled.
142 *
143 * @api public
144 */
145
146function formatArgs(args) {
147	args[0] = (this.useColors ? '%c' : '') +
148		this.namespace +
149		(this.useColors ? ' %c' : ' ') +
150		args[0] +
151		(this.useColors ? '%c ' : ' ') +
152		'+' + module.exports.humanize(this.diff);
153
154	if (!this.useColors) {
155		return;
156	}
157
158	const c = 'color: ' + this.color;
159	args.splice(1, 0, c, 'color: inherit');
160
161	// The final "%c" is somewhat tricky, because there could be other
162	// arguments passed either before or after the %c, so we need to
163	// figure out the correct index to insert the CSS into
164	let index = 0;
165	let lastC = 0;
166	args[0].replace(/%[a-zA-Z%]/g, match => {
167		if (match === '%%') {
168			return;
169		}
170		index++;
171		if (match === '%c') {
172			// We only are interested in the *last* %c
173			// (the user may have provided their own)
174			lastC = index;
175		}
176	});
177
178	args.splice(lastC, 0, c);
179}
180
181/**
182 * Invokes `console.debug()` when available.
183 * No-op when `console.debug` is not a "function".
184 * If `console.debug` is not available, falls back
185 * to `console.log`.
186 *
187 * @api public
188 */
189exports.log = console.debug || console.log || (() => {});
190
191/**
192 * Save `namespaces`.
193 *
194 * @param {String} namespaces
195 * @api private
196 */
197function save(namespaces) {
198	try {
199		if (namespaces) {
200			exports.storage.setItem('debug', namespaces);
201		} else {
202			exports.storage.removeItem('debug');
203		}
204	} catch (error) {
205		// Swallow
206		// XXX (@Qix-) should we be logging these?
207	}
208}
209
210/**
211 * Load `namespaces`.
212 *
213 * @return {String} returns the previously persisted debug modes
214 * @api private
215 */
216function load() {
217	let r;
218	try {
219		r = exports.storage.getItem('debug');
220	} catch (error) {
221		// Swallow
222		// XXX (@Qix-) should we be logging these?
223	}
224
225	// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
226	if (!r && typeof process !== 'undefined' && 'env' in process) {
227		r = process.env.DEBUG;
228	}
229
230	return r;
231}
232
233/**
234 * Localstorage attempts to return the localstorage.
235 *
236 * This is necessary because safari throws
237 * when a user disables cookies/localstorage
238 * and you attempt to access it.
239 *
240 * @return {LocalStorage}
241 * @api private
242 */
243
244function localstorage() {
245	try {
246		// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
247		// The Browser also has localStorage in the global context.
248		return localStorage;
249	} catch (error) {
250		// Swallow
251		// XXX (@Qix-) should we be logging these?
252	}
253}
254
255module.exports = require('./common')(exports);
256
257const {formatters} = module.exports;
258
259/**
260 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
261 */
262
263formatters.j = function (v) {
264	try {
265		return JSON.stringify(v);
266	} catch (error) {
267		return '[UnexpectedJSONParseError]: ' + error.message;
268	}
269};
270