UNPKG

feature-toggle

Version:

A painless feature toggle system in JavaScript. Decouple development and deployment.

1,844 lines (1,538 loc) 58.2 kB
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.setFeatures=e():"undefined"!=typeof global?global.setFeatures=e():"undefined"!=typeof self&&(self.setFeatures=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 'use strict'; var union = require('mout/array/union'), contains = require('mout/array/contains'), EventEmitter = require('events').EventEmitter, stampit = require('stampit'), /** * Grab the url parameters and build a map of * parameter names and values. * @return {Object} params object */ getParams = function getParams() { var params = {}; if (window.location.search) { var parts = window.location.search.slice(1).split('&'); parts.forEach(function (part) { var pair = part.split('='); pair[0] = decodeURIComponent(pair[0]); pair[1] = decodeURIComponent(pair[1]); params[pair[0]] = (pair[1] !== 'undefined') ? pair[1] : true; }); } return params; }, /** * Get a list of feature names from the url * parameters. * @return {Array} Features list */ getParamFeatures = function getParamFeatures() { var features = getParams().ft; return features ? features.split(',') : undefined; }, /** * Get a list of deselected features that need * to be turned off. This list will override * settings from baseFeatures. * @return {Array} Features list */ getInactiveFeatures = function getInactiveFeatures() { var features = getParams()['ft-off']; return features ? features.split(',') : undefined; }, /** * Combine the list of base features with * the features passed in via URL parameters. * @type {Array} active features */ getActiveFeatures = function getActiveFeatures(baseFeatures, paramFeatures, inactiveFeatures) { var features = union(baseFeatures, paramFeatures); inactiveFeatures = inactiveFeatures || []; return features.filter(function (feature) { return inactiveFeatures.indexOf(feature) === -1; }); }, /** * Takes an array of features and creates a class for * each of them on the body tag. * New features should be hidden in CSS by default * and revealed only when the feature toggle is set: * * .new-feature { display: none; } * .ft-new-feature .new-feature { display: block; } * * @param {Array} features An array of active features. */ setFlags = function setFlags(features) { var featureClasses = features.map(function (feature) { return 'ft-' + feature; }).join(' '), classNames = document.getElementsByTagName('body')[0] .className.split(' ').filter(function (className) { return !className.match(/^ft/); }); document.getElementsByTagName('body')[0].className = classNames.join(' ') + ' ' + featureClasses; }, /** * Take an optional list of features, set the feature * classes on the body tag, and return the feature * toggle object. * @param {Array} baseFeatures List of base features. * @return {Object} feature object */ setFeatures = function setFeatures(baseFeatures) { var paramFeatures = getParamFeatures(), inactiveFeatures = getInactiveFeatures(), activeFeatures = getActiveFeatures(baseFeatures, paramFeatures, inactiveFeatures), methods = { /** * Check to see if a feature is active. * @param {String} feature * @return {Boolean} */ active: function active(feature) { var testFeature = feature && feature.trim && feature.trim(); return contains(activeFeatures, testFeature); }, /** * Activate a list of features. * @emits activated * @param {Array} features * @return {Object} this (for chaining) */ /** * activated event. * * @event activated * @type {Array} activated features */ activate: function activate(features) { activeFeatures = union(activeFeatures, features); setFlags(activeFeatures); this.emit('activated', features); return this; }, /** * Deactivate a list of features. * @emits deactivated * @param {Array} features * @return {Object} this (for chaining) */ /** * deactivated event. * * @event deactivated * @type {Array} deactivated features */ deactivate: function deactivate(features) { activeFeatures = activeFeatures.filter(function (feature) { return !contains(features, feature); }); setFlags(activeFeatures); this.emit('deactivated', features); return this; } }, // Creates the feature toggle object by // composing the methods above with an // event emitter using the Stampit // prototypal inheritance library. ft = stampit.compose( stampit.convertConstructor(EventEmitter), stampit(methods) ).create(); // Kick things off by setting feature classes // for the currently active features. setFlags(activeFeatures); return ft; }; module.exports = setFeatures; },{"events":3,"mout/array/contains":6,"mout/array/union":9,"stampit":38}],2:[function(require,module,exports){ // // The shims in this file are not fully implemented shims for the ES5 // features, but do work for the particular usecases there is in // the other modules. // var toString = Object.prototype.toString; var hasOwnProperty = Object.prototype.hasOwnProperty; // Array.isArray is supported in IE9 function isArray(xs) { return toString.call(xs) === '[object Array]'; } exports.isArray = typeof Array.isArray === 'function' ? Array.isArray : isArray; // Array.prototype.indexOf is supported in IE9 exports.indexOf = function indexOf(xs, x) { if (xs.indexOf) return xs.indexOf(x); for (var i = 0; i < xs.length; i++) { if (x === xs[i]) return i; } return -1; }; // Array.prototype.filter is supported in IE9 exports.filter = function filter(xs, fn) { if (xs.filter) return xs.filter(fn); var res = []; for (var i = 0; i < xs.length; i++) { if (fn(xs[i], i, xs)) res.push(xs[i]); } return res; }; // Array.prototype.forEach is supported in IE9 exports.forEach = function forEach(xs, fn, self) { if (xs.forEach) return xs.forEach(fn, self); for (var i = 0; i < xs.length; i++) { fn.call(self, xs[i], i, xs); } }; // Array.prototype.map is supported in IE9 exports.map = function map(xs, fn) { if (xs.map) return xs.map(fn); var out = new Array(xs.length); for (var i = 0; i < xs.length; i++) { out[i] = fn(xs[i], i, xs); } return out; }; // Array.prototype.reduce is supported in IE9 exports.reduce = function reduce(array, callback, opt_initialValue) { if (array.reduce) return array.reduce(callback, opt_initialValue); var value, isValueSet = false; if (2 < arguments.length) { value = opt_initialValue; isValueSet = true; } for (var i = 0, l = array.length; l > i; ++i) { if (array.hasOwnProperty(i)) { if (isValueSet) { value = callback(value, array[i], i, array); } else { value = array[i]; isValueSet = true; } } } return value; }; // String.prototype.substr - negative index don't work in IE8 if ('ab'.substr(-1) !== 'b') { exports.substr = function (str, start, length) { // did we get a negative start, calculate how much it is from the beginning of the string if (start < 0) start = str.length + start; // call the original function return str.substr(start, length); }; } else { exports.substr = function (str, start, length) { return str.substr(start, length); }; } // String.prototype.trim is supported in IE9 exports.trim = function (str) { if (str.trim) return str.trim(); return str.replace(/^\s+|\s+$/g, ''); }; // Function.prototype.bind is supported in IE9 exports.bind = function () { var args = Array.prototype.slice.call(arguments); var fn = args.shift(); if (fn.bind) return fn.bind.apply(fn, args); var self = args.shift(); return function () { fn.apply(self, args.concat([Array.prototype.slice.call(arguments)])); }; }; // Object.create is supported in IE9 function create(prototype, properties) { var object; if (prototype === null) { object = { '__proto__' : null }; } else { if (typeof prototype !== 'object') { throw new TypeError( 'typeof prototype[' + (typeof prototype) + '] != \'object\'' ); } var Type = function () {}; Type.prototype = prototype; object = new Type(); object.__proto__ = prototype; } if (typeof properties !== 'undefined' && Object.defineProperties) { Object.defineProperties(object, properties); } return object; } exports.create = typeof Object.create === 'function' ? Object.create : create; // Object.keys and Object.getOwnPropertyNames is supported in IE9 however // they do show a description and number property on Error objects function notObject(object) { return ((typeof object != "object" && typeof object != "function") || object === null); } function keysShim(object) { if (notObject(object)) { throw new TypeError("Object.keys called on a non-object"); } var result = []; for (var name in object) { if (hasOwnProperty.call(object, name)) { result.push(name); } } return result; } // getOwnPropertyNames is almost the same as Object.keys one key feature // is that it returns hidden properties, since that can't be implemented, // this feature gets reduced so it just shows the length property on arrays function propertyShim(object) { if (notObject(object)) { throw new TypeError("Object.getOwnPropertyNames called on a non-object"); } var result = keysShim(object); if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) { result.push('length'); } return result; } var keys = typeof Object.keys === 'function' ? Object.keys : keysShim; var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ? Object.getOwnPropertyNames : propertyShim; if (new Error().hasOwnProperty('description')) { var ERROR_PROPERTY_FILTER = function (obj, array) { if (toString.call(obj) === '[object Error]') { array = exports.filter(array, function (name) { return name !== 'description' && name !== 'number' && name !== 'message'; }); } return array; }; exports.keys = function (object) { return ERROR_PROPERTY_FILTER(object, keys(object)); }; exports.getOwnPropertyNames = function (object) { return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object)); }; } else { exports.keys = keys; exports.getOwnPropertyNames = getOwnPropertyNames; } // Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements function valueObject(value, key) { return { value: value[key] }; } if (typeof Object.getOwnPropertyDescriptor === 'function') { try { Object.getOwnPropertyDescriptor({'a': 1}, 'a'); exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; } catch (e) { // IE8 dom element issue - use a try catch and default to valueObject exports.getOwnPropertyDescriptor = function (value, key) { try { return Object.getOwnPropertyDescriptor(value, key); } catch (e) { return valueObject(value, key); } }; } } else { exports.getOwnPropertyDescriptor = valueObject; } },{}],3:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. var util = require('util'); function EventEmitter() { this._events = this._events || {}; this._maxListeners = this._maxListeners || undefined; } module.exports = EventEmitter; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. EventEmitter.defaultMaxListeners = 10; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function(n) { if (!util.isNumber(n) || n < 0) throw TypeError('n must be a positive number'); this._maxListeners = n; return this; }; EventEmitter.prototype.emit = function(type) { var er, handler, len, args, i, listeners; if (!this._events) this._events = {}; // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events.error || (util.isObject(this._events.error) && !this._events.error.length)) { er = arguments[1]; if (er instanceof Error) { throw er; // Unhandled 'error' event } else { throw TypeError('Uncaught, unspecified "error" event.'); } return false; } } handler = this._events[type]; if (util.isUndefined(handler)) return false; if (util.isFunction(handler)) { switch (arguments.length) { // fast cases case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; // slower default: len = arguments.length; args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; handler.apply(this, args); } } else if (util.isObject(handler)) { len = arguments.length; args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; listeners = handler.slice(); len = listeners.length; for (i = 0; i < len; i++) listeners[i].apply(this, args); } return true; }; EventEmitter.prototype.addListener = function(type, listener) { var m; if (!util.isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events) this._events = {}; // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (this._events.newListener) this.emit('newListener', type, util.isFunction(listener.listener) ? listener.listener : listener); if (!this._events[type]) // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; else if (util.isObject(this._events[type])) // If we've already got an array, just append. this._events[type].push(listener); else // Adding the second element, need to change to array. this._events[type] = [this._events[type], listener]; // Check for listener leak if (util.isObject(this._events[type]) && !this._events[type].warned) { var m; if (!util.isUndefined(this._maxListeners)) { m = this._maxListeners; } else { m = EventEmitter.defaultMaxListeners; } if (m && m > 0 && this._events[type].length > m) { this._events[type].warned = true; console.error('(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', this._events[type].length); console.trace(); } } return this; }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function(type, listener) { if (!util.isFunction(listener)) throw TypeError('listener must be a function'); function g() { this.removeListener(type, g); listener.apply(this, arguments); } g.listener = listener; this.on(type, g); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function(type, listener) { var list, position, length, i; if (!util.isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events || !this._events[type]) return this; list = this._events[type]; length = list.length; position = -1; if (list === listener || (util.isFunction(list.listener) && list.listener === listener)) { delete this._events[type]; if (this._events.removeListener) this.emit('removeListener', type, listener); } else if (util.isObject(list)) { for (i = length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { position = i; break; } } if (position < 0) return this; if (list.length === 1) { list.length = 0; delete this._events[type]; } else { list.splice(position, 1); } if (this._events.removeListener) this.emit('removeListener', type, listener); } return this; }; EventEmitter.prototype.removeAllListeners = function(type) { var key, listeners; if (!this._events) return this; // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) this._events = {}; else if (this._events[type]) delete this._events[type]; return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { for (key in this._events) { if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = {}; return this; } listeners = this._events[type]; if (util.isFunction(listeners)) { this.removeListener(type, listeners); } else { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } delete this._events[type]; return this; }; EventEmitter.prototype.listeners = function(type) { var ret; if (!this._events || !this._events[type]) ret = []; else if (util.isFunction(this._events[type])) ret = [this._events[type]]; else ret = this._events[type].slice(); return ret; }; EventEmitter.listenerCount = function(emitter, type) { var ret; if (!emitter._events || !emitter._events[type]) ret = 0; else if (util.isFunction(emitter._events[type])) ret = 1; else ret = emitter._events[type].length; return ret; }; },{"util":4}],4:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. var shims = require('_shims'); var formatRegExp = /%[sdj%]/g; exports.format = function(f) { if (!isString(f)) { var objects = []; for (var i = 0; i < arguments.length; i++) { objects.push(inspect(arguments[i])); } return objects.join(' '); } var i = 1; var args = arguments; var len = args.length; var str = String(f).replace(formatRegExp, function(x) { if (x === '%%') return '%'; if (i >= len) return x; switch (x) { case '%s': return String(args[i++]); case '%d': return Number(args[i++]); case '%j': try { return JSON.stringify(args[i++]); } catch (_) { return '[Circular]'; } default: return x; } }); for (var x = args[i]; i < len; x = args[++i]) { if (isNull(x) || !isObject(x)) { str += ' ' + x; } else { str += ' ' + inspect(x); } } return str; }; /** * Echos the value of a value. Trys to print the value out * in the best way possible given the different types. * * @param {Object} obj The object to print out. * @param {Object} opts Optional options object that alters the output. */ /* legacy: obj, showHidden, depth, colors*/ function inspect(obj, opts) { // default options var ctx = { seen: [], stylize: stylizeNoColor }; // legacy... if (arguments.length >= 3) ctx.depth = arguments[2]; if (arguments.length >= 4) ctx.colors = arguments[3]; if (isBoolean(opts)) { // legacy... ctx.showHidden = opts; } else if (opts) { // got an "options" object exports._extend(ctx, opts); } // set default options if (isUndefined(ctx.showHidden)) ctx.showHidden = false; if (isUndefined(ctx.depth)) ctx.depth = 2; if (isUndefined(ctx.colors)) ctx.colors = false; if (isUndefined(ctx.customInspect)) ctx.customInspect = true; if (ctx.colors) ctx.stylize = stylizeWithColor; return formatValue(ctx, obj, ctx.depth); } exports.inspect = inspect; // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = { 'bold' : [1, 22], 'italic' : [3, 23], 'underline' : [4, 24], 'inverse' : [7, 27], 'white' : [37, 39], 'grey' : [90, 39], 'black' : [30, 39], 'blue' : [34, 39], 'cyan' : [36, 39], 'green' : [32, 39], 'magenta' : [35, 39], 'red' : [31, 39], 'yellow' : [33, 39] }; // Don't use 'blue' not visible on cmd.exe inspect.styles = { 'special': 'cyan', 'number': 'yellow', 'boolean': 'yellow', 'undefined': 'grey', 'null': 'bold', 'string': 'green', 'date': 'magenta', // "name": intentionally not styling 'regexp': 'red' }; function stylizeWithColor(str, styleType) { var style = inspect.styles[styleType]; if (style) { return '\u001b[' + inspect.colors[style][0] + 'm' + str + '\u001b[' + inspect.colors[style][1] + 'm'; } else { return str; } } function stylizeNoColor(str, styleType) { return str; } function arrayToHash(array) { var hash = {}; shims.forEach(array, function(val, idx) { hash[val] = true; }); return hash; } function formatValue(ctx, value, recurseTimes) { // Provide a hook for user-specified inspect functions. // Check that value is an object with an inspect function on it if (ctx.customInspect && value && isFunction(value.inspect) && // Filter out the util module, it's inspect function is special value.inspect !== exports.inspect && // Also filter out any prototype objects using the circular check. !(value.constructor && value.constructor.prototype === value)) { var ret = value.inspect(recurseTimes); if (!isString(ret)) { ret = formatValue(ctx, ret, recurseTimes); } return ret; } // Primitive types cannot have properties var primitive = formatPrimitive(ctx, value); if (primitive) { return primitive; } // Look up the keys of the object. var keys = shims.keys(value); var visibleKeys = arrayToHash(keys); if (ctx.showHidden) { keys = shims.getOwnPropertyNames(value); } // Some type of object without properties can be shortcutted. if (keys.length === 0) { if (isFunction(value)) { var name = value.name ? ': ' + value.name : ''; return ctx.stylize('[Function' + name + ']', 'special'); } if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } if (isDate(value)) { return ctx.stylize(Date.prototype.toString.call(value), 'date'); } if (isError(value)) { return formatError(value); } } var base = '', array = false, braces = ['{', '}']; // Make Array say that they are Array if (isArray(value)) { array = true; braces = ['[', ']']; } // Make functions say that they are functions if (isFunction(value)) { var n = value.name ? ': ' + value.name : ''; base = ' [Function' + n + ']'; } // Make RegExps say that they are RegExps if (isRegExp(value)) { base = ' ' + RegExp.prototype.toString.call(value); } // Make dates with properties first say the date if (isDate(value)) { base = ' ' + Date.prototype.toUTCString.call(value); } // Make error with message first say the error if (isError(value)) { base = ' ' + formatError(value); } if (keys.length === 0 && (!array || value.length == 0)) { return braces[0] + base + braces[1]; } if (recurseTimes < 0) { if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } else { return ctx.stylize('[Object]', 'special'); } } ctx.seen.push(value); var output; if (array) { output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); } else { output = keys.map(function(key) { return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); }); } ctx.seen.pop(); return reduceToSingleString(output, base, braces); } function formatPrimitive(ctx, value) { if (isUndefined(value)) return ctx.stylize('undefined', 'undefined'); if (isString(value)) { var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') .replace(/'/g, "\\'") .replace(/\\"/g, '"') + '\''; return ctx.stylize(simple, 'string'); } if (isNumber(value)) return ctx.stylize('' + value, 'number'); if (isBoolean(value)) return ctx.stylize('' + value, 'boolean'); // For some reason typeof null is "object", so special case here. if (isNull(value)) return ctx.stylize('null', 'null'); } function formatError(value) { return '[' + Error.prototype.toString.call(value) + ']'; } function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { var output = []; for (var i = 0, l = value.length; i < l; ++i) { if (hasOwnProperty(value, String(i))) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), true)); } else { output.push(''); } } shims.forEach(keys, function(key) { if (!key.match(/^\d+$/)) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key, true)); } }); return output; } function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { var name, str, desc; desc = shims.getOwnPropertyDescriptor(value, key) || { value: value[key] }; if (desc.get) { if (desc.set) { str = ctx.stylize('[Getter/Setter]', 'special'); } else { str = ctx.stylize('[Getter]', 'special'); } } else { if (desc.set) { str = ctx.stylize('[Setter]', 'special'); } } if (!hasOwnProperty(visibleKeys, key)) { name = '[' + key + ']'; } if (!str) { if (shims.indexOf(ctx.seen, desc.value) < 0) { if (isNull(recurseTimes)) { str = formatValue(ctx, desc.value, null); } else { str = formatValue(ctx, desc.value, recurseTimes - 1); } if (str.indexOf('\n') > -1) { if (array) { str = str.split('\n').map(function(line) { return ' ' + line; }).join('\n').substr(2); } else { str = '\n' + str.split('\n').map(function(line) { return ' ' + line; }).join('\n'); } } } else { str = ctx.stylize('[Circular]', 'special'); } } if (isUndefined(name)) { if (array && key.match(/^\d+$/)) { return str; } name = JSON.stringify('' + key); if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { name = name.substr(1, name.length - 2); name = ctx.stylize(name, 'name'); } else { name = name.replace(/'/g, "\\'") .replace(/\\"/g, '"') .replace(/(^"|"$)/g, "'"); name = ctx.stylize(name, 'string'); } } return name + ': ' + str; } function reduceToSingleString(output, base, braces) { var numLinesEst = 0; var length = shims.reduce(output, function(prev, cur) { numLinesEst++; if (cur.indexOf('\n') >= 0) numLinesEst++; return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; }, 0); if (length > 60) { return braces[0] + (base === '' ? '' : base + '\n ') + ' ' + output.join(',\n ') + ' ' + braces[1]; } return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } // NOTE: These type checking functions intentionally don't use `instanceof` // because it is fragile and can be easily faked with `Object.create()`. function isArray(ar) { return shims.isArray(ar); } exports.isArray = isArray; function isBoolean(arg) { return typeof arg === 'boolean'; } exports.isBoolean = isBoolean; function isNull(arg) { return arg === null; } exports.isNull = isNull; function isNullOrUndefined(arg) { return arg == null; } exports.isNullOrUndefined = isNullOrUndefined; function isNumber(arg) { return typeof arg === 'number'; } exports.isNumber = isNumber; function isString(arg) { return typeof arg === 'string'; } exports.isString = isString; function isSymbol(arg) { return typeof arg === 'symbol'; } exports.isSymbol = isSymbol; function isUndefined(arg) { return arg === void 0; } exports.isUndefined = isUndefined; function isRegExp(re) { return isObject(re) && objectToString(re) === '[object RegExp]'; } exports.isRegExp = isRegExp; function isObject(arg) { return typeof arg === 'object' && arg; } exports.isObject = isObject; function isDate(d) { return isObject(d) && objectToString(d) === '[object Date]'; } exports.isDate = isDate; function isError(e) { return isObject(e) && objectToString(e) === '[object Error]'; } exports.isError = isError; function isFunction(arg) { return typeof arg === 'function'; } exports.isFunction = isFunction; function isPrimitive(arg) { return arg === null || typeof arg === 'boolean' || typeof arg === 'number' || typeof arg === 'string' || typeof arg === 'symbol' || // ES6 symbol typeof arg === 'undefined'; } exports.isPrimitive = isPrimitive; function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.binarySlice === 'function' ; } exports.isBuffer = isBuffer; function objectToString(o) { return Object.prototype.toString.call(o); } function pad(n) { return n < 10 ? '0' + n.toString(10) : n.toString(10); } var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // 26 Feb 16:19:34 function timestamp() { var d = new Date(); var time = [pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds())].join(':'); return [d.getDate(), months[d.getMonth()], time].join(' '); } // log is just a thin wrapper to console.log that prepends a timestamp exports.log = function() { console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); }; /** * Inherit the prototype methods from one constructor into another. * * The Function.prototype.inherits from lang.js rewritten as a standalone * function (not on Function.prototype). NOTE: If this file is to be loaded * during bootstrapping this function needs to be rewritten using some native * functions as prototype setup using normal JavaScript does not work as * expected during bootstrapping (see mirror.js in r114903). * * @param {function} ctor Constructor function which needs to inherit the * prototype. * @param {function} superCtor Constructor function to inherit prototype from. */ exports.inherits = function(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = shims.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; exports._extend = function(origin, add) { // Don't do anything if add isn't an object if (!add || !isObject(add)) return origin; var keys = shims.keys(add); var i = keys.length; while (i--) { origin[keys[i]] = add[keys[i]]; } return origin; }; function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } },{"_shims":2}],5:[function(require,module,exports){ /** * Appends an array to the end of another. * The first array will be modified. */ function append(arr1, arr2) { if (arr2 == null) { return arr1; } var pad = arr1.length, i = -1, len = arr2.length; while (++i < len) { arr1[pad + i] = arr2[i]; } return arr1; } module.exports = append; },{}],6:[function(require,module,exports){ var indexOf = require('./indexOf'); /** * If array contains values. */ function contains(arr, val) { return indexOf(arr, val) !== -1; } module.exports = contains; },{"./indexOf":8}],7:[function(require,module,exports){ var makeIterator = require('../function/makeIterator_'); /** * Array filter */ function filter(arr, callback, thisObj) { callback = makeIterator(callback, thisObj); var results = []; if (arr == null) { return results; } var i = -1, len = arr.length, value; while (++i < len) { value = arr[i]; if (callback(value, i, arr)) { results.push(value); } } return results; } module.exports = filter; },{"../function/makeIterator_":11}],8:[function(require,module,exports){ /** * Array.indexOf */ function indexOf(arr, item, fromIndex) { fromIndex = fromIndex || 0; if (arr == null) { return -1; } var len = arr.length, i = fromIndex < 0 ? len + fromIndex : fromIndex; while (i < len) { // we iterate over sparse items since there is no way to make it // work properly on IE 7-8. see #64 if (arr[i] === item) { return i; } i++; } return -1; } module.exports = indexOf; },{}],9:[function(require,module,exports){ var unique = require('./unique'); var append = require('./append'); /** * Concat multiple arrays and remove duplicates */ function union(arrs) { var results = []; var i = -1, len = arguments.length; while (++i < len) { append(results, arguments[i]); } return unique(results); } module.exports = union; },{"./append":5,"./unique":10}],10:[function(require,module,exports){ var indexOf = require('./indexOf'); var filter = require('./filter'); /** * @return {array} Array of unique items */ function unique(arr){ return filter(arr, isUnique); } function isUnique(item, i, arr){ return indexOf(arr, item, i+1) === -1; } module.exports = unique; },{"./filter":7,"./indexOf":8}],11:[function(require,module,exports){ var prop = require('./prop'); var deepMatches = require('../object/deepMatches'); /** * Converts argument into a valid iterator. * Used internally on most array/object/collection methods that receives a * callback/iterator providing a shortcut syntax. */ function makeIterator(src, thisObj){ switch(typeof src) { case 'function': // function is the first to improve perf (most common case) return (typeof thisObj !== 'undefined')? function(val, i, arr){ return src.call(thisObj, val, i, arr); } : src; case 'object': // typeof null == "object" return (src != null)? function(val){ return deepMatches(val, src); } : src; case 'string': case 'number': return prop(src); default: return src; } } module.exports = makeIterator; },{"../object/deepMatches":16,"./prop":12}],12:[function(require,module,exports){ /** * Returns a function that gets a property of the passed object */ function prop(name){ return function(obj){ return obj[name]; }; } module.exports = prop; },{}],13:[function(require,module,exports){ var isKind = require('./isKind'); /** */ var isArray = Array.isArray || function (val) { return isKind(val, 'Array'); }; module.exports = isArray; },{"./isKind":14}],14:[function(require,module,exports){ var kindOf = require('./kindOf'); /** * Check if value is from a specific "kind". */ function isKind(val, kind){ return kindOf(val) === kind; } module.exports = isKind; },{"./kindOf":15}],15:[function(require,module,exports){ var _rKind = /^\[object (.*)\]$/, _toString = Object.prototype.toString, UNDEF; /** * Gets the "kind" of value. (e.g. "String", "Number", etc) */ function kindOf(val) { if (val === null) { return 'Null'; } else if (val === UNDEF) { return 'Undefined'; } else { return _rKind.exec( _toString.call(val) )[1]; } } module.exports = kindOf; },{}],16:[function(require,module,exports){ var forOwn = require('./forOwn'); var isArray = require('../lang/isArray'); function containsMatch(array, pattern) { var i = -1, length = array.length; while (++i < length) { if (deepMatches(array[i], pattern)) { return true; } } return false; } function matchArray(target, pattern) { var i = -1, patternLength = pattern.length; while (++i < patternLength) { if (!containsMatch(target, pattern[i])) { return false; } } return true; } function matchObject(target, pattern) { var result = true; forOwn(pattern, function(val, key) { if (!deepMatches(target[key], val)) { // Return false to break out of forOwn early return (result = false); } }); return result; } /** * Recursively check if the objects match. */ function deepMatches(target, pattern){ if (target && typeof target === 'object') { if (isArray(target) && isArray(pattern)) { return matchArray(target, pattern); } else { return matchObject(target, pattern); } } else { return target === pattern; } } module.exports = deepMatches; },{"../lang/isArray":13,"./forOwn":18}],17:[function(require,module,exports){ var _hasDontEnumBug, _dontEnums; function checkDontEnum(){ _dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ]; _hasDontEnumBug = true; for (var key in {'toString': null}) { _hasDontEnumBug = false; } } /** * Similar to Array/forEach but works over object properties and fixes Don't * Enum bug on IE. * based on: http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation */ function forIn(obj, fn, thisObj){ var key, i = 0; // no need to check if argument is a real object that way we can use // it for arrays, functions, date, etc. //post-pone check till needed if (_hasDontEnumBug == null) checkDontEnum(); for (key in obj) { if (exec(fn, obj, key, thisObj) === false) { break; } } if (_hasDontEnumBug) { while (key = _dontEnums[i++]) { // since we aren't using hasOwn check we need to make sure the // property was overwritten if (obj[key] !== Object.prototype[key]) { if (exec(fn, obj, key, thisObj) === false) { break; } } } } } function exec(fn, obj, key, thisObj){ return fn.call(thisObj, obj[key], key, obj); } module.exports = forIn; },{}],18:[function(require,module,exports){ var hasOwn = require('./hasOwn'); var forIn = require('./forIn'); /** * Similar to Array/forEach but works over object properties and fixes Don't * Enum bug on IE. * based on: http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation */ function forOwn(obj, fn, thisObj){ forIn(obj, function(val, key){ if (hasOwn(obj, key)) { return fn.call(thisObj, obj[key], key, obj); } }); } module.exports = forOwn; },{"./forIn":17,"./hasOwn":19}],19:[function(require,module,exports){ /** * Safer Object.hasOwnProperty */ function hasOwn(obj, prop){ return Object.prototype.hasOwnProperty.call(obj, prop); } module.exports = hasOwn; },{}],20:[function(require,module,exports){ var forIn = require('mout/object/forIn'); function copyProp(val, key){ this[key] = val; } module.exports = function mixInChain(target, objects){ var i = 0, n = arguments.length, obj; while(++i < n){ obj = arguments[i]; if (obj != null) { forIn(obj, copyProp, target); } } return target; }; },{"mout/object/forIn":33}],21:[function(require,module,exports){ /** * Array forEach */ function forEach(arr, callback, thisObj) { if (arr == null) { return; } var i = -1, len = arr.length; while (++i < len) { // we iterate over sparse items since there is no way to make it // work properly on IE 7-8. see #64 if ( callback.call(thisObj, arr[i], i, arr) === false ) { break; } } } module.exports = forEach; },{}],22:[function(require,module,exports){ var forEach = require('./forEach'); var makeIterator = require('../function/makeIterator_'); /** * Array map */ function map(arr, callback, thisObj) { callback = makeIterator(callback, thisObj); var results = []; if (arr == null){ return results; } var i = -1, len = arr.length; while (++i < len) { results[i] = callback(arr[i], i, arr); } return results; } module.exports = map; },{"../function/makeIterator_":23,"./forEach":21}],23:[function(require,module,exports){ var prop = require('./prop'); var deepMatches = require('../object/deepMatches'); /** * Converts argument into a valid iterator. * Used internally on most array/object/collection methods that receives a * callback/iterator providing a shortcut syntax. */ function makeIterator(src, thisObj){ switch(typeof src) { case 'object': // typeof null == "object" return (src != null)? function(val, key, target){ return deepMatches(val, src); } : src; case 'string': case 'number': return prop(src); case 'function': if (typeof thisObj === 'undefined') { return src; } else { return function(val, i, arr){ return src.call(thisObj, val, i, arr); }; } default: return src; } } module.exports = makeIterator; },{"../object/deepMatches":32,"./prop":24}],24:[function(require,module,exports){ module.exports=require(12) },{}],25:[function(require,module,exports){ var kindOf = require('./kindOf'); var isPlainObject = require('./isPlainObject'); var mixIn = require('../object/mixIn'); /** * Clone native types. */ function clone(val){ switch (kindOf(val)) { case 'Object': return cloneObject(val); case 'Array': return cloneArray(val); case 'RegExp': return cloneRegExp(val); case 'Date': return cloneDate(val); default: return val; } } function cloneObject(source) { if (isPlainObject(source)) { return mixIn({}, source); } else { return source; } } function cloneRegExp(r) { var flags = ''; flags += r.multiline ? 'm' : ''; flags += r.global ? 'g' : ''; flags += r.ignorecase ? 'i' : ''; return new RegExp(r.source, flags); } function cloneDate(date) { return new Date(+date); } function cloneArray(arr) { return arr.slice(); } module.exports = clone; },{"../object/mixIn":37,"./isPlainObject":30,"./kindOf":31}],26:[function(require,module,exports){ var clone = require('./clone'); var forOwn = require('../object/forOwn'); var kindOf = require('./kindOf'); var isPlainObject = require('./isPlainObject'); /** * Recursively clone native types. */ function deepClone(val, instanceClone) { switch ( kindOf(val) ) { case 'Object': return cloneObject(val, instanceClone); case 'Array': return cloneArray(val, instanceClone); default: return clone(val); } } function cloneObject(source, instanceClone) { if (isPlainObject(source)) { var out = {}; forOwn(source, function(val, key) { this[key] = deepClone(val, instanceClone); }, out); return out; } else if (instanceClone) { return instanceClone(source); } else { return source; } } function cloneArray(arr, instanceClone) { var out = [], i = -1, n = arr.length, val; while (++i < n) { out[i] = deepClone(arr[i], instanceClone); } return out; } module.exports = deepClone; },{"../object/forOwn":34,"./clone":25,"./isPlainObject":30,"./kindOf":31}],27:[function(require,module,exports){ module.exports=require(13) },{"./isKind":28}],28:[function(require,module,exports){ module.exports=require(14) },{"./kindOf":31}],29:[function(require,module,exports){ var isKind = require('./isKind'); /** */ function isObject(val) { return isKind(val, 'Object'); } module.exports = isObject; },{"./isKind":28}],30:[function(require,module,exports){ /** * Checks if the value is created by the `Object` constructor. */ function isPlainObject(value) { return (!!value && typeof value === 'object' && value.constructor === Object); } module.exports = isPlainObject; },{}],31:[function(require,module,exports){ module.exports=require(15) },{}],32:[function(require,module,exports){ arguments[4][16][0].apply(exports,arguments) },{"../lang/isArray":27,"./for