You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
4.8 KiB
183 lines
4.8 KiB
/** @module env/log */
|
|
'use strict';
|
|
const util = require('util');
|
|
const EventEmitter = require('events');
|
|
const _ = require('lodash');
|
|
const table = require('text-table');
|
|
const chalk = require('chalk');
|
|
const logSymbols = require('log-symbols');
|
|
|
|
// Padding step
|
|
const step = ' ';
|
|
let padding = ' ';
|
|
|
|
function pad(status) {
|
|
const max = 'identical'.length;
|
|
const delta = max - status.length;
|
|
return delta ? ' '.repeat(delta) + status : status;
|
|
}
|
|
|
|
// Borrowed from https://github.com/mikeal/logref/blob/master/main.js#L6-15
|
|
function formatter(msg, ctx) {
|
|
while (msg.includes('%')) {
|
|
const start = msg.indexOf('%');
|
|
let end = msg.indexOf(' ', start);
|
|
|
|
if (end === -1) {
|
|
end = msg.length;
|
|
}
|
|
|
|
msg = msg.slice(0, start) + ctx[msg.slice(start + 1, end)] + msg.slice(end);
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
const getDefaultColors = () => ({
|
|
skip: 'yellow',
|
|
force: 'yellow',
|
|
create: 'green',
|
|
invoke: 'bold',
|
|
conflict: 'red',
|
|
identical: 'cyan',
|
|
info: 'gray'
|
|
});
|
|
|
|
const initParams = params => {
|
|
params = params || {};
|
|
return Object.assign(
|
|
{}, params, {
|
|
colors: Object.assign(getDefaultColors(), params.colors || {})});
|
|
};
|
|
|
|
module.exports = params => {
|
|
params = initParams(params);
|
|
const customConsole = params.console || console;
|
|
const stderr = params.stderr || params.stdout || process.stderr;
|
|
|
|
// `this.log` is a [logref](https://github.com/mikeal/logref)
|
|
// compatible logger, with an enhanced API.
|
|
//
|
|
// It also has EventEmitter like capabilities, so you can call on / emit
|
|
// on it, namely used to increase or decrease the padding.
|
|
//
|
|
// All logs are done against STDERR, letting you stdout for meaningfull
|
|
// value and redirection, should you need to generate output this way.
|
|
//
|
|
// Log functions take two arguments, a message and a context. For any
|
|
// other kind of paramters, `console.error` is used, so all of the
|
|
// console format string goodies you're used to work fine.
|
|
//
|
|
// - msg - The message to show up
|
|
// - context - The optional context to escape the message against
|
|
//
|
|
// @param {Object} params
|
|
// @param {Object} params.colors status mappings
|
|
//
|
|
// Returns the logger
|
|
function log(msg, ctx) {
|
|
msg = msg || '';
|
|
|
|
if (typeof ctx === 'object' && !Array.isArray(ctx)) {
|
|
customConsole.error(formatter(msg, ctx));
|
|
} else {
|
|
customConsole.error.apply(customConsole, arguments);
|
|
}
|
|
|
|
return log;
|
|
}
|
|
|
|
_.extend(log, EventEmitter.prototype);
|
|
|
|
// A simple write method, with formatted message.
|
|
//
|
|
// Returns the logger
|
|
log.write = function () {
|
|
stderr.write(util.format.apply(util, arguments));
|
|
return this;
|
|
};
|
|
|
|
// Same as `log.write()` but automatically appends a `\n` at the end
|
|
// of the message.
|
|
log.writeln = function () {
|
|
this.write.apply(this, arguments);
|
|
this.write('\n');
|
|
return this;
|
|
};
|
|
|
|
// Convenience helper to write sucess status, this simply prepends the
|
|
// message with a gren `✔`.
|
|
log.ok = function () {
|
|
this.write(logSymbols.success + ' ' + util.format.apply(util, arguments) + '\n');
|
|
return this;
|
|
};
|
|
|
|
log.error = function () {
|
|
this.write(logSymbols.error + ' ' + util.format.apply(util, arguments) + '\n');
|
|
return this;
|
|
};
|
|
|
|
log.on('up', () => {
|
|
padding += step;
|
|
});
|
|
|
|
log.on('down', () => {
|
|
padding = padding.replace(step, '');
|
|
});
|
|
|
|
for (const status of Object.keys(params.colors)) {
|
|
// Each predefined status has its logging method utility, handling
|
|
// status color and padding before the usual `.write()`
|
|
//
|
|
// Example
|
|
//
|
|
// this.log
|
|
// .write()
|
|
// .info('Doing something')
|
|
// .force('Forcing filepath %s, 'some path')
|
|
// .conflict('on %s' 'model.js')
|
|
// .write()
|
|
// .ok('This is ok');
|
|
//
|
|
// The list of default status and mapping colors
|
|
//
|
|
// skip yellow
|
|
// force yellow
|
|
// create green
|
|
// invoke bold
|
|
// conflict red
|
|
// identical cyan
|
|
// info grey
|
|
//
|
|
// Returns the logger
|
|
log[status] = function () {
|
|
const color = params.colors[status];
|
|
this.write(chalk[color](pad(status))).write(padding);
|
|
this.write(util.format.apply(util, arguments) + '\n');
|
|
return this;
|
|
};
|
|
}
|
|
|
|
// A basic wrapper around `cli-table` package, resetting any single
|
|
// char to empty strings, this is used for aligning options and
|
|
// arguments without too much Math on our side.
|
|
//
|
|
// - opts - A list of rows or an Hash of options to pass through cli
|
|
// table.
|
|
//
|
|
// Returns the table reprensetation
|
|
log.table = opts => {
|
|
const tableData = [];
|
|
|
|
opts = Array.isArray(opts) ? {rows: opts} : opts;
|
|
opts.rows = opts.rows || [];
|
|
|
|
for (const row of opts.rows) {
|
|
tableData.push(row);
|
|
}
|
|
|
|
return table(tableData);
|
|
};
|
|
|
|
return log;
|
|
};
|
|
|