UNPKG

igir

Version:

🕹 A zero-setup ROM collection manager that sorts, filters, extracts or archives, patches, and reports on collections of any size on any OS.

146 lines (145 loc) • 5.65 kB
import chalk from 'chalk'; import moment from 'moment'; import Package from '../globals/package.js'; import { LogLevel, LogLevelInverted } from './logLevel.js'; import MultiBar from './multiBar.js'; /** * {@link Logger} is a class that deals with the formatting and outputting log messages to a stream. */ export default class Logger { logLevel; stream; multiBar; loggerPrefix; constructor(logLevel, stream, multiBar, loggerPrefix) { this.logLevel = logLevel; this.stream = stream; this.multiBar = multiBar ?? MultiBar.create({ writable: stream }); this.loggerPrefix = loggerPrefix; } getLogLevel() { return this.logLevel; } setLogLevel(logLevel) { this.logLevel = logLevel; } getStream() { return this.stream; } print = (logLevel, message = '') => { if (this.logLevel > logLevel) { return; } this.stream.write(`${this.formatMessage(logLevel, String(message).toString())}\n`); }; /** * Print a newline. */ newLine() { this.print(LogLevel.ALWAYS); } /** * Format a log message for a given {@link LogLevelValue}. */ formatMessage(logLevel, message) { // Don't format "ALWAYS" or "NEVER" if (logLevel >= LogLevel.ALWAYS) { return message; } const chalkFuncs = { [LogLevel.ALWAYS]: (msg) => msg, [LogLevel.TRACE]: chalk.grey, [LogLevel.DEBUG]: chalk.magenta, [LogLevel.INFO]: chalk.cyan, [LogLevel.WARN]: chalk.yellow, [LogLevel.ERROR]: chalk.red, [LogLevel.NOTICE]: chalk.underline, [LogLevel.NEVER]: (msg) => msg, }; const chalkFunc = chalkFuncs[logLevel]; const loggerTime = this.logLevel <= LogLevel.TRACE ? `[${moment().format('HH:mm:ss.SSS')}] ` : ''; const levelPrefix = `${chalkFunc(LogLevelInverted[logLevel])}: `; const loggerPrefix = this.logLevel <= LogLevel.TRACE && this.loggerPrefix ? chalk.dim(`${this.loggerPrefix}: `) : ''; return message .replace(/Error: /, '') // strip `new Error()` prefix .replace(/(\r?\n)(\r?\n)+/, '$1') .split('\n') .map((m) => (m.trim() ? loggerTime + levelPrefix + loggerPrefix + m : m)) .join('\n'); } trace = (message = '') => { this.print(LogLevel.TRACE, message); }; debug = (message = '') => { this.print(LogLevel.DEBUG, message); }; info = (message = '') => { this.print(LogLevel.INFO, message); }; warn = (message = '') => { this.print(LogLevel.WARN, message); }; error = (message = '') => { this.print(LogLevel.ERROR, message); }; notice = (message = '') => { this.print(LogLevel.NOTICE, message); }; /** * Print the CLI header. */ printHeader() { const logo = ` @@@@@@ @@@@@@ @@@@@@ @@@@@@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@@@@@ @@ @@@@@@ @@@@@@@@@ @@@ @@@@ @@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@@@@@@@@@@@ @@ @@ @@`.replace(/^[\r\n]+/, ''); const logoSplit = logo.split('\n'); const midLine = Math.min(Math.ceil(logoSplit.length / 2), logoSplit.length - 1); const maxLineLen = logoSplit.reduce((max, line) => Math.max(max, line.length), 0); logoSplit[midLine - 2] = `${logoSplit[midLine - 2].padEnd(maxLineLen, ' ')} ROM collection manager`; logoSplit[midLine - 1] = `${logoSplit[midLine - 1].padEnd(maxLineLen, ' ')} ${Package.HOMEPAGE}`; logoSplit[midLine + 1] = `${logoSplit[midLine + 1].padEnd(maxLineLen, ' ')} v${Package.VERSION}`; this.print(LogLevel.ALWAYS, `${logoSplit.join('\n')}\n`); } /** * Print a colorized yargs help string. */ colorizeYargs(help) { this.print(LogLevel.ALWAYS, help .replace(/^(Usage:.+)/, chalk.bold('$1')) .replaceAll(/(\[commands\.*\])/g, chalk.magenta('$1')) .replaceAll(new RegExp(`(${Package.NAME}) (( ?[a-z0-9])+)`, 'g'), `$1 ${chalk.magenta('$2')}`) .replaceAll(/(\[options\.*\])/g, chalk.cyan('$1')) .replaceAll(/([^a-zA-Z0-9-])(-[a-zA-Z0-9]([a-zA-Z0-9]|\n[ \t]*)*)/g, `$1${chalk.cyanBright('$2')}`) .replaceAll(/(--[a-zA-Z0-9][a-zA-Z0-9-]+(\n[ \t]+)?[a-zA-Z0-9-]+) ((?:[^ -])[^"][^ \n]*|"(?:[^"\\]|\\.)*")/g, `$1 ${chalk.underline('$3')}`) .replaceAll(/(--[a-zA-Z0-9][a-zA-Z0-9-]+(\n[ \t]+)?[a-zA-Z0-9-]+)/g, chalk.cyan('$1')) .replaceAll(/(<[a-zA-Z]+>)/g, chalk.blue('$1')) .replaceAll(/(\[(array|boolean|count|number|string)\])/g, chalk.grey('$1')) .replaceAll(/(\[default: ([^[\]]+(\[[^\]]+\])?)*\])/g, chalk.green('$1')) .replaceAll(/(\[required\])/g, chalk.red('$1')) .replaceAll(/(\{[a-zA-Z]+\})/g, chalk.yellow('$1')) .replaceAll(new RegExp(` (${Package.NAME}) `, 'g'), ` ${chalk.blueBright('$1')} `)); } /** * Create a {@link ProgressBar} with a reference to this {@link Logger}. */ addProgressBar(options) { return this.multiBar.addSingleBar(this, options); } /** * Return a copy of this Logger with a new string prefix. */ withLoggerPrefix(prefix) { return new Logger(this.logLevel, this.stream, this.multiBar, prefix); } }