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