UNPKG

willow-cli

Version:

CLI for installing Willow Design System components

200 lines (199 loc) 6.83 kB
import chalk from 'chalk'; /** * Enhanced logging utility with consistent formatting and context */ export class Logger { static indent = 0; static debugMode = process.env.WILLOW_DEBUG === 'true'; static setDebugMode(enabled) { this.debugMode = enabled; } static increaseIndent() { this.indent += 2; } static decreaseIndent() { this.indent = Math.max(0, this.indent - 2); } static resetIndent() { this.indent = 0; } static getIndent() { return ' '.repeat(this.indent); } static getTimestamp() { return new Date().toLocaleTimeString(); } static info(message, options = {}) { const { prefix, indent = 0, timestamp = false } = options; const indentStr = ' '.repeat(this.indent + indent); const prefixStr = prefix ? `${prefix} ` : ''; const timestampStr = timestamp ? `[${this.getTimestamp()}] ` : ''; console.log(`${indentStr}${timestampStr}${prefixStr}${message}`); } static success(message, options = {}) { const { prefix = '✅', indent = 0, timestamp = false } = options; const indentStr = ' '.repeat(this.indent + indent); const timestampStr = timestamp ? `[${this.getTimestamp()}] ` : ''; console.log(chalk.green(`${indentStr}${timestampStr}${prefix} ${message}`)); } static warning(message, options = {}) { const { prefix = '⚠️', indent = 0, timestamp = false } = options; const indentStr = ' '.repeat(this.indent + indent); const timestampStr = timestamp ? `[${this.getTimestamp()}] ` : ''; console.log(chalk.yellow(`${indentStr}${timestampStr}${prefix} ${message}`)); } static error(message, options = {}) { const { prefix = '❌', indent = 0, timestamp = false } = options; const indentStr = ' '.repeat(this.indent + indent); const timestampStr = timestamp ? `[${this.getTimestamp()}] ` : ''; console.error(chalk.red(`${indentStr}${timestampStr}${prefix} ${message}`)); } static debug(message, options = {}) { if (!this.debugMode) return; const { prefix = '🐛', indent = 0, timestamp = true } = options; const indentStr = ' '.repeat(this.indent + indent); const timestampStr = timestamp ? `[${this.getTimestamp()}] ` : ''; console.log(chalk.gray(`${indentStr}${timestampStr}${prefix} ${message}`)); } static step(message) { console.log(chalk.blue(`⏳ ${message}...`)); } static substep(message) { this.info(chalk.gray(` ${message}`)); } static title(message) { console.log(chalk.blue.bold(`\n🎨 ${message}`)); } static section(message) { console.log(chalk.blue(`\n📦 ${message}`)); } static spacer() { console.log(); } static divider() { console.log(chalk.gray('─'.repeat(60))); } static table(headers, rows) { // Simple table implementation const colWidths = headers.map((header, i) => Math.max(header.length, ...rows.map(row => (row[i] || '').length))); // Header const headerRow = headers.map((header, i) => header.padEnd(colWidths[i])).join(' │ '); console.log(chalk.blue(`│ ${headerRow} │`)); // Separator const separator = colWidths.map(width => '─'.repeat(width)).join('─┼─'); console.log(chalk.blue(`├─${separator}─┤`)); // Rows rows.forEach(row => { const rowStr = row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(' │ '); console.log(`│ ${rowStr} │`); }); } static list(items, options = {}) { const { ordered = false, indent = 0 } = options; const indentStr = ' '.repeat(this.indent + indent); items.forEach((item, index) => { const marker = ordered ? `${index + 1}.` : '•'; console.log(`${indentStr}${marker} ${item}`); }); } static group(title, callback) { this.section(title); this.increaseIndent(); try { callback(); } finally { this.decreaseIndent(); } } } /** * Simple step logger for tracking progress */ export class StepLogger { currentStep = 0; totalSteps; steps; constructor(steps) { this.steps = steps; this.totalSteps = steps.length; this.logProgress(); } next(message) { if (this.currentStep < this.totalSteps) { Logger.success(message || this.steps[this.currentStep]); this.currentStep++; this.logProgress(); } } fail(message) { Logger.error(message || `Failed: ${this.steps[this.currentStep]}`); } skip(message) { Logger.warning(message || `Skipped: ${this.steps[this.currentStep]}`); this.currentStep++; this.logProgress(); } logProgress() { if (this.currentStep < this.totalSteps) { Logger.step(`(${this.currentStep + 1}/${this.totalSteps}) ${this.steps[this.currentStep]}`); } } complete() { Logger.success(`All ${this.totalSteps} steps completed!`); } } /** * Utility functions for common logging patterns */ export function logFileOperation(operation, filePath) { const icons = { create: '📝', update: '✏️', delete: '🗑️', }; const messages = { create: 'Created', update: 'Updated', delete: 'Deleted', }; Logger.info(`${icons[operation]} ${messages[operation]}: ${filePath}`); } export function logDependencyInstall(deps, manager = 'npm') { Logger.info(`📦 Installing dependencies with ${manager}:`); Logger.list(deps, { indent: 2 }); } export function logComponentInstall(componentName, success) { if (success) { Logger.success(`Installed component: ${componentName}`); } else { Logger.error(`Failed to install component: ${componentName}`); } } export function logValidationResult(valid, issues = [], warnings = []) { if (valid) { Logger.success('Project validation passed'); } else { Logger.error('Project validation failed'); if (issues.length > 0) { Logger.warning('Issues found:'); Logger.list(issues, { indent: 2 }); } } if (warnings.length > 0) { Logger.warning('Warnings:'); Logger.list(warnings, { indent: 2 }); } } export function logEnvironmentInfo(info) { Logger.section('Environment Information'); Object.entries(info).forEach(([key, value]) => { Logger.info(`${key}: ${value}`, { indent: 2 }); }); } // Convenience exports export const log = Logger; export { Logger as default };