react-saasify-chrisvxd
Version:
React components for Saasify web clients.
249 lines (209 loc) • 5.72 kB
JavaScript
const chalk = require('chalk');
const readline = require('readline');
const prettyError = require('./prettyError');
const emoji = require('./emoji');
const {countBreaks} = require('grapheme-breaker');
const stripAnsi = require('strip-ansi');
const ora = require('ora');
const WorkerFarm = require('@parcel/workers');
const path = require('path');
const fs = require('fs');
class Logger {
constructor(options) {
this.lines = 0;
this.spinner = null;
this.setOptions(options);
}
setOptions(options) {
this.logLevel =
options && isNaN(options.logLevel) === false
? Number(options.logLevel)
: 3;
this.color =
options && typeof options.color === 'boolean'
? options.color
: chalk.supportsColor;
this.emoji = (options && options.emoji) || emoji;
this.chalk = new chalk.constructor({enabled: this.color});
this.isTest =
options && typeof options.isTest === 'boolean'
? options.isTest
: process.env.NODE_ENV === 'test';
}
countLines(message) {
return stripAnsi(message)
.split('\n')
.reduce((p, line) => {
if (process.stdout.columns) {
return p + Math.ceil((line.length || 1) / process.stdout.columns);
}
return p + 1;
}, 0);
}
writeRaw(message) {
this.stopSpinner();
this.lines += this.countLines(message) - 1;
process.stdout.write(message);
}
write(message, persistent = false) {
if (this.logLevel > 3) {
return this.verbose(message);
}
if (!persistent) {
this.lines += this.countLines(message);
}
this.stopSpinner();
this._log(message);
}
verbose(message) {
if (this.logLevel < 4) {
return;
}
let currDate = new Date();
message = `[${currDate.toLocaleTimeString()}]: ${message}`;
if (this.logLevel > 4) {
if (!this.logFile) {
this.logFile = fs.createWriteStream(
path.join(process.cwd(), `parcel-debug-${currDate.toISOString()}.log`)
);
}
this.logFile.write(stripAnsi(message) + '\n');
}
this._log(message);
}
log(message) {
if (this.logLevel < 3) {
return;
}
this.write(message);
}
persistent(message) {
if (this.logLevel < 3) {
return;
}
this.write(this.chalk.bold(message), true);
}
warn(err) {
if (this.logLevel < 2) {
return;
}
this._writeError(err, this.emoji.warning, this.chalk.yellow);
}
error(err) {
if (this.logLevel < 1) {
return;
}
this._writeError(err, this.emoji.error, this.chalk.red.bold);
}
success(message) {
this.log(`${this.emoji.success} ${this.chalk.green.bold(message)}`);
}
formatError(err, opts) {
return prettyError(err, opts);
}
_writeError(err, emoji, color) {
let {message, stack} = this.formatError(err, {color: this.color});
this.write(color(`${emoji} ${message}`));
if (stack) {
this.write(stack);
}
}
clear() {
if (!this.color || this.isTest || this.logLevel > 3) {
return;
}
while (this.lines > 0) {
readline.clearLine(process.stdout, 0);
readline.moveCursor(process.stdout, 0, -1);
this.lines--;
}
readline.cursorTo(process.stdout, 0);
this.stopSpinner();
}
progress(message) {
if (this.logLevel < 3) {
return;
}
if (this.logLevel > 3) {
return this.verbose(message);
}
let styledMessage = this.chalk.gray.bold(message);
if (!this.spinner) {
this.spinner = ora({
text: styledMessage,
stream: process.stdout,
enabled: this.isTest ? false : undefined // fall back to ora default unless we need to explicitly disable it.
}).start();
} else {
this.spinner.text = styledMessage;
}
}
stopSpinner() {
if (this.spinner) {
this.spinner.stop();
this.spinner = null;
}
}
handleMessage(options) {
this[options.method](...options.args);
}
_log(message) {
// eslint-disable-next-line no-console
console.log(message);
}
table(columns, table) {
// Measure column widths
let colWidths = [];
for (let row of table) {
let i = 0;
for (let item of row) {
colWidths[i] = Math.max(colWidths[i] || 0, stringWidth(item));
i++;
}
}
// Render rows
for (let row of table) {
let items = row.map((item, i) => {
// Add padding between columns unless the alignment is the opposite to the
// next column and pad to the column width.
let padding =
!columns[i + 1] || columns[i + 1].align === columns[i].align ? 4 : 0;
return pad(item, colWidths[i] + padding, columns[i].align);
});
this.log(items.join(''));
}
}
}
// Pad a string with spaces on either side
function pad(text, length, align = 'left') {
let pad = ' '.repeat(length - stringWidth(text));
if (align === 'right') {
return pad + text;
}
return text + pad;
}
// Count visible characters in a string
function stringWidth(string) {
return countBreaks(stripAnsi('' + string));
}
// If we are in a worker, make a proxy class which will
// send the logger calls to the main process via IPC.
// These are handled in WorkerFarm and directed to handleMessage above.
if (WorkerFarm.isWorker()) {
class LoggerProxy {}
for (let method of Object.getOwnPropertyNames(Logger.prototype)) {
LoggerProxy.prototype[method] = (...args) => {
WorkerFarm.callMaster(
{
location: __filename,
method,
args
},
false
);
};
}
module.exports = new LoggerProxy();
} else {
module.exports = new Logger();
}