browser.js
  1  /**
  2   * This is the web browser implementation of `debug()`.
  3   *
  4   * Expose `debug()` as the module.
  5   */
  6  
  7  exports = module.exports = require('./debug');
  8  exports.log = log;
  9  exports.formatArgs = formatArgs;
 10  exports.save = save;
 11  exports.load = load;
 12  exports.useColors = useColors;
 13  exports.storage = 'undefined' != typeof chrome
 14                 && 'undefined' != typeof chrome.storage
 15                    ? chrome.storage.local
 16                    : localstorage();
 17  
 18  /**
 19   * Colors.
 20   */
 21  
 22  exports.colors = [
 23    'lightseagreen',
 24    'forestgreen',
 25    'goldenrod',
 26    'dodgerblue',
 27    'darkorchid',
 28    'crimson'
 29  ];
 30  
 31  /**
 32   * Currently only WebKit-based Web Inspectors, Firefox >= v31,
 33   * and the Firebug extension (any Firefox version) are known
 34   * to support "%c" CSS customizations.
 35   *
 36   * TODO: add a `localStorage` variable to explicitly enable/disable colors
 37   */
 38  
 39  function useColors() {
 40    // NB: In an Electron preload script, document will be defined but not fully
 41    // initialized. Since we know we're in Chrome, we'll just detect this case
 42    // explicitly
 43    if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
 44      return true;
 45    }
 46  
 47    // is webkit? http://stackoverflow.com/a/16459606/376773
 48    // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
 49    return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
 50      // is firebug? http://stackoverflow.com/a/398120/376773
 51      (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
 52      // is firefox >= v31?
 53      // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
 54      (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
 55      // double check webkit in userAgent just in case we are in a worker
 56      (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
 57  }
 58  
 59  /**
 60   * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
 61   */
 62  
 63  exports.formatters.j = function(v) {
 64    try {
 65      return JSON.stringify(v);
 66    } catch (err) {
 67      return '[UnexpectedJSONParseError]: ' + err.message;
 68    }
 69  };
 70  
 71  
 72  /**
 73   * Colorize log arguments if enabled.
 74   *
 75   * @api public
 76   */
 77  
 78  function formatArgs(args) {
 79    var useColors = this.useColors;
 80  
 81    args[0] = (useColors ? '%c' : '')
 82      + this.namespace
 83      + (useColors ? ' %c' : ' ')
 84      + args[0]
 85      + (useColors ? '%c ' : ' ')
 86      + '+' + exports.humanize(this.diff);
 87  
 88    if (!useColors) return;
 89  
 90    var c = 'color: ' + this.color;
 91    args.splice(1, 0, c, 'color: inherit')
 92  
 93    // the final "%c" is somewhat tricky, because there could be other
 94    // arguments passed either before or after the %c, so we need to
 95    // figure out the correct index to insert the CSS into
 96    var index = 0;
 97    var lastC = 0;
 98    args[0].replace(/%[a-zA-Z%]/g, function(match) {
 99      if ('%%' === match) return;
100      index++;
101      if ('%c' === match) {
102        // we only are interested in the *last* %c
103        // (the user may have provided their own)
104        lastC = index;
105      }
106    });
107  
108    args.splice(lastC, 0, c);
109  }
110  
111  /**
112   * Invokes `console.log()` when available.
113   * No-op when `console.log` is not a "function".
114   *
115   * @api public
116   */
117  
118  function log() {
119    // this hackery is required for IE8/9, where
120    // the `console.log` function doesn't have 'apply'
121    return 'object' === typeof console
122      && console.log
123      && Function.prototype.apply.call(console.log, console, arguments);
124  }
125  
126  /**
127   * Save `namespaces`.
128   *
129   * @param {String} namespaces
130   * @api private
131   */
132  
133  function save(namespaces) {
134    try {
135      if (null == namespaces) {
136        exports.storage.removeItem('debug');
137      } else {
138        exports.storage.debug = namespaces;
139      }
140    } catch(e) {}
141  }
142  
143  /**
144   * Load `namespaces`.
145   *
146   * @return {String} returns the previously persisted debug modes
147   * @api private
148   */
149  
150  function load() {
151    var r;
152    try {
153      r = exports.storage.debug;
154    } catch(e) {}
155  
156    // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
157    if (!r && typeof process !== 'undefined' && 'env' in process) {
158      r = process.env.DEBUG;
159    }
160  
161    return r;
162  }
163  
164  /**
165   * Enable namespaces listed in `localStorage.debug` initially.
166   */
167  
168  exports.enable(load());
169  
170  /**
171   * Localstorage attempts to return the localstorage.
172   *
173   * This is necessary because safari throws
174   * when a user disables cookies/localstorage
175   * and you attempt to access it.
176   *
177   * @return {LocalStorage}
178   * @api private
179   */
180  
181  function localstorage() {
182    try {
183      return window.localStorage;
184    } catch (e) {}
185  }