1import chalk, { Chalk } from 'chalk'; 2import readline from 'readline'; 3 4type LogLevel = 'log' | 'debug' | 'info' | 'warn' | 'error'; 5 6type LoggerResolver = (level: LogLevel, color: Chalk | null, args: string[]) => void; 7 8const CONSOLE_RESOLVER: LoggerResolver = (level: LogLevel, color: Chalk | null, args: string[]) => { 9 return console[level](...(color ? args.map((arg) => color(arg)) : args)); 10}; 11 12/** 13 * Basic logger just for simple console logging with colored output. 14 */ 15export class Logger { 16 constructor(readonly resolver: LoggerResolver = CONSOLE_RESOLVER) {} 17 18 verbose(...args: any[]): void { 19 this.resolver('debug', chalk.dim, args); 20 } 21 22 debug(...args: any[]): void { 23 this.resolver('debug', chalk.gray, args); 24 } 25 26 log(...args: any[]): void { 27 this.resolver('log', null, args); 28 } 29 30 success(...args: any[]): void { 31 this.resolver('log', chalk.green, args); 32 } 33 34 info(...args: any[]): void { 35 this.resolver('info', chalk.cyan, args); 36 } 37 38 warn(...args: any[]): void { 39 this.resolver('warn', chalk.yellow.bold, args); 40 } 41 42 error(...args: any[]): void { 43 this.resolver('error', chalk.red.bold, args); 44 } 45 46 batch(): LoggerBatch { 47 return new LoggerBatch(this.resolver); 48 } 49 50 clearLine() { 51 readline.moveCursor(process.stdout, 0, -1); 52 readline.clearLine(process.stdout, 0); 53 } 54} 55 56/** 57 * Batched logger, it batches all logs until they're flushed. 58 * Useful for asynchronous simultaneous operations to preserve logs order. 59 */ 60export class LoggerBatch extends Logger { 61 readonly batchedLogs: [LogLevel, Chalk | null, any[]][] = []; 62 63 constructor(readonly parentResolver: LoggerResolver = CONSOLE_RESOLVER) { 64 super((level, color, args) => { 65 this.batchedLogs.push([level, color, args]); 66 }); 67 this.batchedLogs = []; 68 } 69 70 flush() { 71 this.batchedLogs.forEach(([level, color, args]) => this.parentResolver(level, color, args)); 72 this.batchedLogs.length = 0; 73 } 74} 75 76export default new Logger(); 77