#!/usr/bin/env node
/**
* Script to help migrate console.log statements to Winston logger
* This script analyzes files and suggests replacements
*/
import fs from 'fs';
import path from 'path';
import * as glob from 'glob';
// Patterns to match different console methods
const consolePatterns = [
{ pattern: /console\.log\(/g, level: 'info' },
{ pattern: /console\.error\(/g, level: 'error' },
{ pattern: /console\.warn\(/g, level: 'warn' },
{ pattern: /console\.debug\(/g, level: 'debug' },
{ pattern: /console\.info\(/g, level: 'info' }
];
// Map of file paths to suggested logger names
const moduleLoggerMap: Record<string, string> = {
'syllogistic': 'Loggers.syllogistic',
'propositional': 'Loggers.propositional',
'predicate': 'Loggers.predicate',
'mathematical': 'Loggers.mathematical',
'advancedMathematical': 'Loggers.advancedMath',
'parser': 'Loggers.parser',
'visualization': 'Loggers.visualization',
'truthTable': 'Loggers.truthTable',
'vennDiagram': 'Loggers.vennDiagram',
'tools': 'Loggers.tools',
'api': 'Loggers.api',
'server': 'Loggers.server'
};
/**
* Determine the appropriate logger for a file
*/
function getLoggerForFile(filePath: string): string {
const normalizedPath = filePath.toLowerCase();
for (const [key, logger] of Object.entries(moduleLoggerMap)) {
if (normalizedPath.includes(key.toLowerCase())) {
return logger;
}
}
return 'Loggers.general';
}
/**
* Analyze a file for console statements
*/
function analyzeFile(filePath: string): {
hasConsole: boolean;
count: number;
suggestions: string[]
} {
const content = fs.readFileSync(filePath, 'utf-8');
const suggestions: string[] = [];
let totalCount = 0;
// Check for existing logger import
const hasLoggerImport = content.includes('from \'../utils/logger\'') ||
content.includes('from \'./utils/logger\'') ||
content.includes('from \'../../utils/logger\'');
// Count console statements
consolePatterns.forEach(({ pattern, level }) => {
const matches = content.match(pattern);
if (matches) {
totalCount += matches.length;
suggestions.push(`- Replace ${matches.length} console.${pattern.source.match(/console\.(\w+)/)?.[1]} with logger.${level}`);
}
});
if (totalCount > 0 && !hasLoggerImport) {
const logger = getLoggerForFile(filePath);
const importPath = calculateImportPath(filePath);
suggestions.unshift(`- Add import: import { ${logger} as logger } from '${importPath}';`);
}
return {
hasConsole: totalCount > 0,
count: totalCount,
suggestions
};
}
/**
* Calculate the correct import path for the logger
*/
function calculateImportPath(filePath: string): string {
const depth = filePath.split('/src/')[1]?.split('/').length - 1 || 0;
const prefix = '../'.repeat(depth);
return `${prefix}utils/logger`;
}
/**
* Main migration analysis
*/
function analyzeMigration() {
console.log('Analyzing console.log usage in the project...\n');
// Find all TypeScript files
const files = glob.sync('src/**/*.ts', {
cwd: process.cwd(),
ignore: ['**/node_modules/**', '**/dist/**', '**/logger.ts', '**/migrate-logs.ts']
});
let totalFiles = 0;
let totalConsoleStatements = 0;
const fileSuggestions: Array<{ file: string; count: number; suggestions: string[] }> = [];
files.forEach((file: string) => {
const fullPath = path.join(process.cwd(), file);
const analysis = analyzeFile(fullPath);
if (analysis.hasConsole) {
totalFiles++;
totalConsoleStatements += analysis.count;
fileSuggestions.push({
file,
count: analysis.count,
suggestions: analysis.suggestions
});
}
});
// Output results
console.log(`Summary:`);
console.log(`- Total files with console statements: ${totalFiles}`);
console.log(`- Total console statements: ${totalConsoleStatements}\n`);
// Sort by count (files with most console statements first)
fileSuggestions.sort((a, b) => b.count - a.count);
console.log('Migration suggestions by file:\n');
fileSuggestions.forEach(({ file, count, suggestions }) => {
console.log(`File: ${file} (${count} statements)`);
suggestions.forEach(suggestion => console.log(` ${suggestion}`));
console.log();
});
// Generate a sample migration for the top file
if (fileSuggestions.length > 0) {
console.log('Example migration for the file with most console statements:');
const topFile = fileSuggestions[0];
console.log(`\nFile: ${topFile.file}`);
console.log('\n// Add this import at the top:');
const logger = getLoggerForFile(topFile.file);
const importPath = calculateImportPath(topFile.file);
console.log(`import { ${logger} as logger } from '${importPath}';`);
console.log('\n// Then replace:');
console.log('console.log("Processing formula:", formula);');
console.log('// With:');
console.log('logger.info("Processing formula", { formula });');
console.log('\n// Or for errors:');
console.log('console.error("Failed to parse:", error);');
console.log('// With:');
console.log('logger.error("Failed to parse", { error });');
}
console.log('\nMigration analysis complete!');
console.log('\nNext steps:');
console.log('1. Start migrating files with the most console statements first');
console.log('2. Use the logger suggestions above for each file');
console.log('3. Test each migration to ensure functionality remains intact');
}
// Run the analysis
analyzeMigration();