browser.js
1 /* eslint-env browser */ 2 3 /** 4 * This is the web browser implementation of `debug()`. 5 */ 6 7 exports.formatArgs = formatArgs; 8 exports.save = save; 9 exports.load = load; 10 exports.useColors = useColors; 11 exports.storage = localstorage(); 12 exports.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 27 exports.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 115 function 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 let m; 129 130 // Is webkit? http://stackoverflow.com/a/16459606/376773 131 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 132 // eslint-disable-next-line no-return-assign 133 return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || 134 // Is firebug? http://stackoverflow.com/a/398120/376773 135 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || 136 // Is firefox >= v31? 137 // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages 138 (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) || 139 // Double check webkit in userAgent just in case we are in a worker 140 (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); 141 } 142 143 /** 144 * Colorize log arguments if enabled. 145 * 146 * @api public 147 */ 148 149 function formatArgs(args) { 150 args[0] = (this.useColors ? '%c' : '') + 151 this.namespace + 152 (this.useColors ? ' %c' : ' ') + 153 args[0] + 154 (this.useColors ? '%c ' : ' ') + 155 '+' + module.exports.humanize(this.diff); 156 157 if (!this.useColors) { 158 return; 159 } 160 161 const c = 'color: ' + this.color; 162 args.splice(1, 0, c, 'color: inherit'); 163 164 // The final "%c" is somewhat tricky, because there could be other 165 // arguments passed either before or after the %c, so we need to 166 // figure out the correct index to insert the CSS into 167 let index = 0; 168 let lastC = 0; 169 args[0].replace(/%[a-zA-Z%]/g, match => { 170 if (match === '%%') { 171 return; 172 } 173 index++; 174 if (match === '%c') { 175 // We only are interested in the *last* %c 176 // (the user may have provided their own) 177 lastC = index; 178 } 179 }); 180 181 args.splice(lastC, 0, c); 182 } 183 184 /** 185 * Invokes `console.debug()` when available. 186 * No-op when `console.debug` is not a "function". 187 * If `console.debug` is not available, falls back 188 * to `console.log`. 189 * 190 * @api public 191 */ 192 exports.log = console.debug || console.log || (() => {}); 193 194 /** 195 * Save `namespaces`. 196 * 197 * @param {String} namespaces 198 * @api private 199 */ 200 function save(namespaces) { 201 try { 202 if (namespaces) { 203 exports.storage.setItem('debug', namespaces); 204 } else { 205 exports.storage.removeItem('debug'); 206 } 207 } catch (error) { 208 // Swallow 209 // XXX (@Qix-) should we be logging these? 210 } 211 } 212 213 /** 214 * Load `namespaces`. 215 * 216 * @return {String} returns the previously persisted debug modes 217 * @api private 218 */ 219 function load() { 220 let r; 221 try { 222 r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ; 223 } catch (error) { 224 // Swallow 225 // XXX (@Qix-) should we be logging these? 226 } 227 228 // If debug isn't set in LS, and we're in Electron, try to load $DEBUG 229 if (!r && typeof process !== 'undefined' && 'env' in process) { 230 r = process.env.DEBUG; 231 } 232 233 return r; 234 } 235 236 /** 237 * Localstorage attempts to return the localstorage. 238 * 239 * This is necessary because safari throws 240 * when a user disables cookies/localstorage 241 * and you attempt to access it. 242 * 243 * @return {LocalStorage} 244 * @api private 245 */ 246 247 function localstorage() { 248 try { 249 // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context 250 // The Browser also has localStorage in the global context. 251 return localStorage; 252 } catch (error) { 253 // Swallow 254 // XXX (@Qix-) should we be logging these? 255 } 256 } 257 258 module.exports = require('./common')(exports); 259 260 const {formatters} = module.exports; 261 262 /** 263 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. 264 */ 265 266 formatters.j = function (v) { 267 try { 268 return JSON.stringify(v); 269 } catch (error) { 270 return '[UnexpectedJSONParseError]: ' + error.message; 271 } 272 };