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