UNPKG

pury

Version:

šŸ›”ļø AI-powered security scanner with advanced threat detection, dual reporting system (detailed & summary), and comprehensive code analysis

147 lines • 6.41 kB
import { Command } from 'commander'; import { resolve } from 'path'; import { promises as fs } from 'fs'; import { FileScanner } from '../../scanner/file-scanner.js'; import { QualityAnalyzer } from '../../analyzers/quality-analyzer.js'; import { logger } from '../../utils/logger.js'; import { fileExists } from '../../utils/file-utils.js'; export function createCleanLogsCommand() { return new Command('clean-logs') .description('Remove console.log and other debug statements from code') .argument('[path]', 'Path to clean (defaults to current directory)', '.') .option('--apply', 'Actually apply the changes (default is dry-run)') .option('--backup', 'Create backup files before modifying') .option('--exclude <patterns...>', 'Patterns to exclude from cleaning') .option('--include <patterns...>', 'Patterns to include in cleaning', [ '**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx' ]) .action(async (path, options) => { try { await runCleanLogs(path, options); } catch (error) { logger.error(`Clean logs failed: ${error.message}`); process.exit(1); } }); } async function runCleanLogs(cleanPath, options) { const resolvedPath = resolve(cleanPath); if (!(await fileExists(resolvedPath))) { throw new Error(`Path does not exist: ${resolvedPath}`); } logger.info(`${options.apply ? 'Cleaning' : 'Analyzing'} debug statements in: ${resolvedPath}`); // Initialize scanner const scanner = new FileScanner(options.include || ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx'], options.exclude || ['node_modules/**', 'dist/**', '*.min.js']); // Initialize quality analyzer const analyzer = new QualityAnalyzer('high'); const spinner = logger.spinner('Scanning for debug statements...'); try { // Scan files const files = await scanner.scan({ path: resolvedPath, recursive: true, followSymlinks: false }); spinner.succeed(`Scanned ${files.length} files`); if (files.length === 0) { logger.warn('No files found to process'); return; } // Analyze for console statements logger.info('Analyzing for debug statements...'); const cleaningResult = await analyzer.cleanConsoleStatements(files); // Show results logger.info(`\nCleaning Results:`); logger.info(`Files with debug statements: ${cleaningResult.filesModified}`); logger.info(`Total statements found: ${cleaningResult.statementsRemoved}`); if (cleaningResult.changes.length === 0) { logger.success('No debug statements found - code is already clean!'); return; } // Show preview of changes logger.info('\nPreview of changes:'); for (const change of cleaningResult.changes.slice(0, 10)) { // Show first 10 changes logger.info(`\nšŸ“ ${change.file}:${change.line}`); logger.info(` - ${change.original}`); logger.info(` + ${change.modified}`); } if (cleaningResult.changes.length > 10) { logger.info(`\n... and ${cleaningResult.changes.length - 10} more changes`); } if (options.apply) { // Apply changes logger.info('\nApplying changes...'); const changeSpinner = logger.spinner('Modifying files...'); try { await applyChanges(cleaningResult.changes, options.backup); changeSpinner.succeed(`Successfully cleaned ${cleaningResult.filesModified} files`); logger.success(`\nāœ… Cleaning completed!`); logger.success(`šŸ“ Modified ${cleaningResult.filesModified} files`); logger.success(`šŸ—‘ļø Removed ${cleaningResult.statementsRemoved} debug statements`); if (options.backup) { logger.info('šŸ’¾ Backup files created with .backup extension'); } } catch (error) { changeSpinner.fail('Failed to apply changes'); throw error; } } else { logger.info('\nšŸ’” This was a dry run. Use --apply to actually make changes.'); logger.info('šŸ’” Use --backup to create backup files before modifying.'); } } catch (error) { spinner.fail('Failed to scan files'); throw error; } } async function applyChanges(changes, createBackup) { // Group changes by file const changesByFile = new Map(); for (const change of changes) { if (!changesByFile.has(change.file)) { changesByFile.set(change.file, []); } changesByFile.get(change.file).push(change); } // Apply changes file by file for (const [filePath, fileChanges] of changesByFile) { try { // Create backup if requested if (createBackup) { const originalContent = await fs.readFile(filePath, 'utf8'); await fs.writeFile(`${filePath}.backup`, originalContent, 'utf8'); } // Read current file content const content = await fs.readFile(filePath, 'utf8'); const lines = content.split('\n'); // Sort changes by line number in descending order to avoid line shifting issues fileChanges.sort((a, b) => b.line - a.line); // Apply changes for (const change of fileChanges) { const lineIndex = change.line - 1; if (lineIndex >= 0 && lineIndex < lines.length && lines[lineIndex]) { // Simple replacement - in practice, you might want more sophisticated matching if (lines[lineIndex].includes(change.original.trim())) { lines[lineIndex] = change.modified; } } } // Write modified content back const modifiedContent = lines.join('\n'); await fs.writeFile(filePath, modifiedContent, 'utf8'); } catch (error) { logger.error(`Failed to modify file ${filePath}: ${error.message}`); throw error; } } } //# sourceMappingURL=clean-logs.js.map