redux-logger-default-css
Version:
Logger for Redux
886 lines (742 loc) • 24 kB
JavaScript
var repeat = function repeat(str, times) {
return new Array(times + 1).join(str);
};
var pad = function pad(num, maxLength) {
return repeat('0', maxLength - num.toString().length) + num;
};
var formatTime = function formatTime(time) {
return pad(time.getHours(), 2) + ':' + pad(time.getMinutes(), 2) + ':' + pad(time.getSeconds(), 2) + '.' + pad(time.getMilliseconds(), 3);
};
// Use performance API if it's available in order to get better precision
var timer = typeof performance !== 'undefined' && performance !== null && typeof performance.now === 'function' ? performance : Date;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
} else {
return Array.from(arr);
}
};
var $scope;
var conflict;
var conflictResolution = [];
if ((typeof global === 'undefined' ? 'undefined' : _typeof(global)) === 'object' && global) {
$scope = global;
} else if (typeof window !== 'undefined') {
$scope = window;
} else {
$scope = {};
}
conflict = $scope.DeepDiff;
if (conflict) {
conflictResolution.push(function () {
if ('undefined' !== typeof conflict && $scope.DeepDiff === accumulateDiff) {
$scope.DeepDiff = conflict;
conflict = undefined;
}
});
}
// nodejs compatible on server side and in the browser.
function inherits$$1(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
}
function Diff(kind, path) {
Object.defineProperty(this, 'kind', {
value: kind,
enumerable: true
});
if (path && path.length) {
Object.defineProperty(this, 'path', {
value: path,
enumerable: true
});
}
}
function DiffEdit(path, origin, value) {
DiffEdit.super_.call(this, 'E', path);
Object.defineProperty(this, 'lhs', {
value: origin,
enumerable: true
});
Object.defineProperty(this, 'rhs', {
value: value,
enumerable: true
});
}
inherits$$1(DiffEdit, Diff);
function DiffNew(path, value) {
DiffNew.super_.call(this, 'N', path);
Object.defineProperty(this, 'rhs', {
value: value,
enumerable: true
});
}
inherits$$1(DiffNew, Diff);
function DiffDeleted(path, value) {
DiffDeleted.super_.call(this, 'D', path);
Object.defineProperty(this, 'lhs', {
value: value,
enumerable: true
});
}
inherits$$1(DiffDeleted, Diff);
function DiffArray(path, index, item) {
DiffArray.super_.call(this, 'A', path);
Object.defineProperty(this, 'index', {
value: index,
enumerable: true
});
Object.defineProperty(this, 'item', {
value: item,
enumerable: true
});
}
inherits$$1(DiffArray, Diff);
function arrayRemove(arr, from, to) {
var rest = arr.slice((to || from) + 1 || arr.length);
arr.length = from < 0 ? arr.length + from : from;
arr.push.apply(arr, rest);
return arr;
}
function realTypeOf(subject) {
var type = typeof subject === 'undefined' ? 'undefined' : _typeof(subject);
if (type !== 'object') {
return type;
}
if (subject === Math) {
return 'math';
} else if (subject === null) {
return 'null';
} else if (Array.isArray(subject)) {
return 'array';
} else if (Object.prototype.toString.call(subject) === '[object Date]') {
return 'date';
} else if (typeof subject.toString === 'function' && /^\/.*\//.test(subject.toString())) {
return 'regexp';
}
return 'object';
}
function deepDiff(lhs, rhs, changes, prefilter, path, key, stack) {
path = path || [];
stack = stack || [];
var currentPath = path.slice(0);
if (typeof key !== 'undefined') {
if (prefilter) {
if (typeof prefilter === 'function' && prefilter(currentPath, key)) {
return;
} else if ((typeof prefilter === 'undefined' ? 'undefined' : _typeof(prefilter)) === 'object') {
if (prefilter.prefilter && prefilter.prefilter(currentPath, key)) {
return;
}
if (prefilter.normalize) {
var alt = prefilter.normalize(currentPath, key, lhs, rhs);
if (alt) {
lhs = alt[0];
rhs = alt[1];
}
}
}
}
currentPath.push(key);
}
// Use string comparison for regexes
if (realTypeOf(lhs) === 'regexp' && realTypeOf(rhs) === 'regexp') {
lhs = lhs.toString();
rhs = rhs.toString();
}
var ltype = typeof lhs === 'undefined' ? 'undefined' : _typeof(lhs);
var rtype = typeof rhs === 'undefined' ? 'undefined' : _typeof(rhs);
var ldefined = ltype !== 'undefined' || stack && stack[stack.length - 1].lhs && stack[stack.length - 1].lhs.hasOwnProperty(key);
var rdefined = rtype !== 'undefined' || stack && stack[stack.length - 1].rhs && stack[stack.length - 1].rhs.hasOwnProperty(key);
if (!ldefined && rdefined) {
changes(new DiffNew(currentPath, rhs));
} else if (!rdefined && ldefined) {
changes(new DiffDeleted(currentPath, lhs));
} else if (realTypeOf(lhs) !== realTypeOf(rhs)) {
changes(new DiffEdit(currentPath, lhs, rhs));
} else if (realTypeOf(lhs) === 'date' && lhs - rhs !== 0) {
changes(new DiffEdit(currentPath, lhs, rhs));
} else if (ltype === 'object' && lhs !== null && rhs !== null) {
if (!stack.filter(function (x) {
return x.lhs === lhs;
}).length) {
stack.push({ lhs: lhs, rhs: rhs });
if (Array.isArray(lhs)) {
var i,
len = lhs.length;
for (i = 0; i < lhs.length; i++) {
if (i >= rhs.length) {
changes(new DiffArray(currentPath, i, new DiffDeleted(undefined, lhs[i])));
} else {
deepDiff(lhs[i], rhs[i], changes, prefilter, currentPath, i, stack);
}
}
while (i < rhs.length) {
changes(new DiffArray(currentPath, i, new DiffNew(undefined, rhs[i++])));
}
} else {
var akeys = Object.keys(lhs);
var pkeys = Object.keys(rhs);
akeys.forEach(function (k, i) {
var other = pkeys.indexOf(k);
if (other >= 0) {
deepDiff(lhs[k], rhs[k], changes, prefilter, currentPath, k, stack);
pkeys = arrayRemove(pkeys, other);
} else {
deepDiff(lhs[k], undefined, changes, prefilter, currentPath, k, stack);
}
});
pkeys.forEach(function (k) {
deepDiff(undefined, rhs[k], changes, prefilter, currentPath, k, stack);
});
}
stack.length = stack.length - 1;
} else if (lhs !== rhs) {
// lhs is contains a cycle at this element and it differs from rhs
changes(new DiffEdit(currentPath, lhs, rhs));
}
} else if (lhs !== rhs) {
if (!(ltype === 'number' && isNaN(lhs) && isNaN(rhs))) {
changes(new DiffEdit(currentPath, lhs, rhs));
}
}
}
function accumulateDiff(lhs, rhs, prefilter, accum) {
accum = accum || [];
deepDiff(lhs, rhs, function (diff) {
if (diff) {
accum.push(diff);
}
}, prefilter);
return accum.length ? accum : undefined;
}
function applyArrayChange(arr, index, change) {
if (change.path && change.path.length) {
var it = arr[index],
i,
u = change.path.length - 1;
for (i = 0; i < u; i++) {
it = it[change.path[i]];
}
switch (change.kind) {
case 'A':
applyArrayChange(it[change.path[i]], change.index, change.item);
break;
case 'D':
delete it[change.path[i]];
break;
case 'E':
case 'N':
it[change.path[i]] = change.rhs;
break;
}
} else {
switch (change.kind) {
case 'A':
applyArrayChange(arr[index], change.index, change.item);
break;
case 'D':
arr = arrayRemove(arr, index);
break;
case 'E':
case 'N':
arr[index] = change.rhs;
break;
}
}
return arr;
}
function applyChange(target, source, change) {
if (target && source && change && change.kind) {
var it = target,
i = -1,
last = change.path ? change.path.length - 1 : 0;
while (++i < last) {
if (typeof it[change.path[i]] === 'undefined') {
it[change.path[i]] = typeof change.path[i] === 'number' ? [] : {};
}
it = it[change.path[i]];
}
switch (change.kind) {
case 'A':
applyArrayChange(change.path ? it[change.path[i]] : it, change.index, change.item);
break;
case 'D':
delete it[change.path[i]];
break;
case 'E':
case 'N':
it[change.path[i]] = change.rhs;
break;
}
}
}
function revertArrayChange(arr, index, change) {
if (change.path && change.path.length) {
// the structure of the object at the index has changed...
var it = arr[index],
i,
u = change.path.length - 1;
for (i = 0; i < u; i++) {
it = it[change.path[i]];
}
switch (change.kind) {
case 'A':
revertArrayChange(it[change.path[i]], change.index, change.item);
break;
case 'D':
it[change.path[i]] = change.lhs;
break;
case 'E':
it[change.path[i]] = change.lhs;
break;
case 'N':
delete it[change.path[i]];
break;
}
} else {
// the array item is different...
switch (change.kind) {
case 'A':
revertArrayChange(arr[index], change.index, change.item);
break;
case 'D':
arr[index] = change.lhs;
break;
case 'E':
arr[index] = change.lhs;
break;
case 'N':
arr = arrayRemove(arr, index);
break;
}
}
return arr;
}
function revertChange(target, source, change) {
if (target && source && change && change.kind) {
var it = target,
i,
u;
u = change.path.length - 1;
for (i = 0; i < u; i++) {
if (typeof it[change.path[i]] === 'undefined') {
it[change.path[i]] = {};
}
it = it[change.path[i]];
}
switch (change.kind) {
case 'A':
// Array was modified...
// it will be an array...
revertArrayChange(it[change.path[i]], change.index, change.item);
break;
case 'D':
// Item was deleted...
it[change.path[i]] = change.lhs;
break;
case 'E':
// Item was edited...
it[change.path[i]] = change.lhs;
break;
case 'N':
// Item is new...
delete it[change.path[i]];
break;
}
}
}
function applyDiff(target, source, filter) {
if (target && source) {
var onChange = function onChange(change) {
if (!filter || filter(target, source, change)) {
applyChange(target, source, change);
}
};
deepDiff(target, source, onChange);
}
}
Object.defineProperties(accumulateDiff, {
diff: {
value: accumulateDiff,
enumerable: true
},
observableDiff: {
value: deepDiff,
enumerable: true
},
applyDiff: {
value: applyDiff,
enumerable: true
},
applyChange: {
value: applyChange,
enumerable: true
},
revertChange: {
value: revertChange,
enumerable: true
},
isConflict: {
value: function value() {
return 'undefined' !== typeof conflict;
},
enumerable: true
},
noConflict: {
value: function value() {
if (conflictResolution) {
conflictResolution.forEach(function (it) {
it();
});
conflictResolution = null;
}
return accumulateDiff;
},
enumerable: true
}
});
// https://github.com/flitbit/diff#differences
var dictionary = {
E: {
color: '#2196F3',
text: 'CHANGED:'
},
N: {
color: '#4CAF50',
text: 'ADDED:'
},
D: {
color: '#F44336',
text: 'DELETED:'
},
A: {
color: '#2196F3',
text: 'ARRAY:'
}
};
function style(kind) {
return 'color: ' + dictionary[kind].color + '; font-weight: bold';
}
function render(diff) {
var kind = diff.kind,
path = diff.path,
lhs = diff.lhs,
rhs = diff.rhs,
index = diff.index,
item = diff.item;
switch (kind) {
case 'E':
return [path.join('.'), lhs, '→', rhs];
case 'N':
return [path.join('.'), rhs];
case 'D':
return [path.join('.')];
case 'A':
return [path.join('.') + '[' + index + ']', item];
default:
return [];
}
}
function diffLogger(prevState, newState, logger, isCollapsed) {
var diff = accumulateDiff(prevState, newState);
try {
if (isCollapsed) {
logger.groupCollapsed('diff');
} else {
logger.group('diff');
}
} catch (e) {
logger.log('diff');
}
if (diff) {
diff.forEach(function (elem) {
var kind = elem.kind;
var output = render(elem);
logger.log.apply(logger, ['%c ' + dictionary[kind].text, style(kind)].concat(toConsumableArray(output)));
});
} else {
logger.log('—— no diff ——');
}
try {
logger.groupEnd();
} catch (e) {
logger.log('—— diff end —— ');
}
}
/**
* Get log level string based on supplied params
*
* @param {string | function | object} level - console[level]
* @param {object} action - selected action
* @param {array} payload - selected payload
* @param {string} type - log entry type
*
* @returns {string} level
*/
function getLogLevel(level, action, payload, type) {
switch (typeof level === 'undefined' ? 'undefined' : _typeof(level)) {
case 'object':
return typeof level[type] === 'function' ? level[type].apply(level, toConsumableArray(payload)) : level[type];
case 'function':
return level(action);
default:
return level;
}
}
function defaultTitleFormatter(options) {
var timestamp = options.timestamp,
duration = options.duration;
return function (action, time, took) {
var parts = ['action'];
parts.push('%c' + String(action.type));
if (timestamp) parts.push('%c@ ' + time);
if (duration) parts.push('%c(in ' + took.toFixed(2) + ' ms)');
return parts.join(' ');
};
}
function printBuffer(buffer, options) {
var logger = options.logger,
actionTransformer = options.actionTransformer,
_options$titleFormatt = options.titleFormatter,
titleFormatter = _options$titleFormatt === undefined ? defaultTitleFormatter(options) : _options$titleFormatt,
collapsed = options.collapsed,
colors = options.colors,
level = options.level,
diff = options.diff,
useDefaultCss = options.useDefaultCss;
var isUsingDefaultFormatter = typeof options.titleFormatter === 'undefined';
buffer.forEach(function (logEntry, key) {
var started = logEntry.started,
startedTime = logEntry.startedTime,
action = logEntry.action,
prevState = logEntry.prevState,
error = logEntry.error;
var took = logEntry.took,
nextState = logEntry.nextState;
var nextEntry = buffer[key + 1];
if (nextEntry) {
nextState = nextEntry.prevState;
took = nextEntry.started - started;
}
// Message
var formattedAction = actionTransformer(action);
var isCollapsed = typeof collapsed === 'function' ? collapsed(function () {
return nextState;
}, action, logEntry) : collapsed;
var formattedTime = formatTime(startedTime);
var titleCSS = colors.title ? 'color: ' + colors.title(formattedAction) + ';' : '';
var headerCSS = ['color: gray; font-weight: lighter;'];
headerCSS.push(titleCSS);
if (options.timestamp) headerCSS.push('color: gray; font-weight: lighter;');
if (options.duration) headerCSS.push('color: gray; font-weight: lighter;');
var title = titleFormatter(formattedAction, formattedTime, took);
// Render
try {
var shouldStyleTitle = colors.title && (isUsingDefaultFormatter || useDefaultCss);
if (isCollapsed) {
if (shouldStyleTitle) {
logger.groupCollapsed.apply(logger, ['%c ' + title].concat(headerCSS));
} else logger.groupCollapsed(title);
} else if (shouldStyleTitle) {
logger.group.apply(logger, ['%c ' + title].concat(headerCSS));
} else {
logger.group(title);
}
} catch (e) {
logger.log(title);
}
var prevStateLevel = getLogLevel(level, formattedAction, [prevState], 'prevState');
var actionLevel = getLogLevel(level, formattedAction, [formattedAction], 'action');
var errorLevel = getLogLevel(level, formattedAction, [error, prevState], 'error');
var nextStateLevel = getLogLevel(level, formattedAction, [nextState], 'nextState');
if (prevStateLevel) {
if (colors.prevState) {
var styles = 'color: ' + colors.prevState(prevState) + '; font-weight: bold';
logger[prevStateLevel]('%c prev state', styles, prevState);
} else logger[prevStateLevel]('prev state', prevState);
}
if (actionLevel) {
if (colors.action) {
var _styles = 'color: ' + colors.action(formattedAction) + '; font-weight: bold';
logger[actionLevel]('%c action ', _styles, formattedAction);
} else logger[actionLevel]('action ', formattedAction);
}
if (error && errorLevel) {
if (colors.error) {
var _styles2 = 'color: ' + colors.error(error, prevState) + '; font-weight: bold;';
logger[errorLevel]('%c error ', _styles2, error);
} else logger[errorLevel]('error ', error);
}
if (nextStateLevel) {
if (colors.nextState) {
var _styles3 = 'color: ' + colors.nextState(nextState) + '; font-weight: bold';
logger[nextStateLevel]('%c next state', _styles3, nextState);
} else logger[nextStateLevel]('next state', nextState);
}
if (logger.withTrace) {
logger.groupCollapsed('TRACE');
logger.trace();
logger.groupEnd();
}
if (diff) {
diffLogger(prevState, nextState, logger, isCollapsed);
}
try {
logger.groupEnd();
} catch (e) {
logger.log('—— log end ——');
}
});
}
var defaults$1 = {
level: 'log',
logger: console,
logErrors: true,
collapsed: undefined,
predicate: undefined,
duration: false,
timestamp: true,
stateTransformer: function stateTransformer(state) {
return state;
},
actionTransformer: function actionTransformer(action) {
return action;
},
errorTransformer: function errorTransformer(error) {
return error;
},
colors: {
title: function title() {
return 'inherit';
},
prevState: function prevState() {
return '#9E9E9E';
},
action: function action() {
return '#03A9F4';
},
nextState: function nextState() {
return '#4CAF50';
},
error: function error() {
return '#F20404';
}
},
diff: false,
diffPredicate: undefined,
// Deprecated options
transformer: undefined
};
/* eslint max-len: ["error", 110, { "ignoreComments": true }] */
/**
* Creates logger with following options
*
* @namespace
* @param {object} options - options for logger
* @param {string | function | object} options.level - console[level]
* @param {boolean} options.duration - print duration of each action?
* @param {boolean} options.timestamp - print timestamp with each action?
* @param {object} options.colors - custom colors
* @param {object} options.logger - implementation of the `console` API
* @param {boolean} options.logErrors - should errors in action execution be caught, logged, and re-thrown?
* @param {boolean} options.collapsed - is group collapsed?
* @param {boolean} options.predicate - condition which resolves logger behavior
* @param {function} options.stateTransformer - transform state before print
* @param {function} options.actionTransformer - transform action before print
* @param {function} options.errorTransformer - transform error before print
*
* @returns {function} logger middleware
*/
function createLogger() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var loggerOptions = Object.assign({}, defaults$1, options);
var logger = loggerOptions.logger,
stateTransformer = loggerOptions.stateTransformer,
errorTransformer = loggerOptions.errorTransformer,
predicate = loggerOptions.predicate,
logErrors = loggerOptions.logErrors,
diffPredicate = loggerOptions.diffPredicate;
// Return if 'console' object is not defined
if (typeof logger === 'undefined') {
return function () {
return function (next) {
return function (action) {
return next(action);
};
};
};
}
// Detect if 'createLogger' was passed directly to 'applyMiddleware'.
if (options.getState && options.dispatch) {
// eslint-disable-next-line no-console
console.error('[redux-logger] redux-logger not installed. Make sure to pass logger instance as middleware:\n// Logger with default options\nimport { logger } from \'redux-logger\'\nconst store = createStore(\n reducer,\n applyMiddleware(logger)\n)\n// Or you can create your own logger with custom options http://bit.ly/redux-logger-options\nimport { createLogger } from \'redux-logger\'\nconst logger = createLogger({\n // ...options\n});\nconst store = createStore(\n reducer,\n applyMiddleware(logger)\n)\n');
return function () {
return function (next) {
return function (action) {
return next(action);
};
};
};
}
var logBuffer = [];
return function (_ref) {
var getState = _ref.getState;
return function (next) {
return function (action) {
// Exit early if predicate function returns 'false'
if (typeof predicate === 'function' && !predicate(getState, action)) {
return next(action);
}
var logEntry = {};
logBuffer.push(logEntry);
logEntry.started = timer.now();
logEntry.startedTime = new Date();
logEntry.prevState = stateTransformer(getState());
logEntry.action = action;
var returnedValue = void 0;
if (logErrors) {
try {
returnedValue = next(action);
} catch (e) {
logEntry.error = errorTransformer(e);
}
} else {
returnedValue = next(action);
}
logEntry.took = timer.now() - logEntry.started;
logEntry.nextState = stateTransformer(getState());
var diff = loggerOptions.diff && typeof diffPredicate === 'function' ? diffPredicate(getState, action) : loggerOptions.diff;
printBuffer(logBuffer, Object.assign({}, loggerOptions, { diff: diff }));
logBuffer.length = 0;
if (logEntry.error) throw logEntry.error;
return returnedValue;
};
};
};
}
// eslint-disable-next-line consistent-return
var defaultLogger = function defaultLogger() {
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
dispatch = _ref2.dispatch,
getState = _ref2.getState;
if (typeof dispatch === 'function' || typeof getState === 'function') {
return createLogger()({ dispatch: dispatch, getState: getState });
}
// eslint-disable-next-line no-console
console.error('\n[redux-logger v3] BREAKING CHANGE\n[redux-logger v3] Since 3.0.0 redux-logger exports by default logger with default settings.\n[redux-logger v3] Change\n[redux-logger v3] import createLogger from \'redux-logger\'\n[redux-logger v3] to\n[redux-logger v3] import { createLogger } from \'redux-logger\'\n');
};
export { defaults$1 as defaults, createLogger, defaultLogger as logger };export default defaultLogger;