UNPKG

smart-renamer

Version:

🚀 Intelligent file naming suggestions based on project-specific naming conventions. Interactive CLI tool that asks yes/no for each file renaming.

153 lines • 5.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SuggestionEngine = void 0; const fs_1 = require("fs"); const path_1 = require("path"); const naming_validator_1 = require("./naming-validator"); class SuggestionEngine { projectRoot; constructor(projectRoot = process.cwd()) { this.projectRoot = projectRoot; } suggestName(filename, convention, exceptions = []) { const baseName = this.getBaseName(filename); const extension = (0, path_1.extname)(filename); if (exceptions.includes(baseName.toLowerCase())) { return { original: filename, suggested: filename, convention, confidence: 1.0 }; } const suggestedBaseName = naming_validator_1.NamingValidator.convertToConvention(baseName, convention); const suggestedFilename = suggestedBaseName + extension; const confidence = this.calculateConfidence(filename, suggestedFilename, convention); return { original: filename, suggested: suggestedFilename, convention, confidence }; } suggestMultipleNames(filename, primaryConvention, exceptions = []) { const conventions = ['camelCase', 'snake_case', 'kebab-case', 'PascalCase', 'UPPER_SNAKE_CASE']; return conventions.map(convention => { const suggestion = this.suggestName(filename, convention, exceptions); if (convention === primaryConvention) { suggestion.confidence = Math.min(suggestion.confidence + 0.2, 1.0); } return suggestion; }).sort((a, b) => b.confidence - a.confidence); } detectProjectConvention() { const files = this.getAllProjectFiles(); const filenames = files .filter(file => !file.isDirectory) .map(file => file.name); return naming_validator_1.NamingValidator.detectConvention(filenames); } analyzeProjectStructure() { const files = this.getAllProjectFiles(); const filenames = files .filter(file => !file.isDirectory) .map(file => file.name); const conventions = { 'camelCase': 0, 'snake_case': 0, 'kebab-case': 0, 'PascalCase': 0, 'UPPER_SNAKE_CASE': 0 }; for (const filename of filenames) { const baseName = this.getBaseName(filename); for (const [convention, pattern] of Object.entries(naming_validator_1.NamingValidator['CONVENTION_PATTERNS'])) { if (pattern.test(baseName)) { conventions[convention]++; } } } const totalFiles = filenames.length; const maxCount = Math.max(...Object.values(conventions)); const mostCommon = maxCount > 0 ? Object.entries(conventions).find(([, count]) => count === maxCount)?.[0] || null : null; const consistency = totalFiles > 0 ? (maxCount / totalFiles) : 0; return { totalFiles, conventions, mostCommon, consistency }; } getAllProjectFiles(dir = this.projectRoot, maxDepth = 3, currentDepth = 0) { if (currentDepth >= maxDepth) return []; const files = []; try { const entries = (0, fs_1.readdirSync)(dir); for (const entry of entries) { if (this.shouldIgnore(entry)) continue; const fullPath = (0, path_1.join)(dir, entry); const stats = (0, fs_1.statSync)(fullPath); const fileInfo = { name: entry, path: fullPath, extension: (0, path_1.extname)(entry), isDirectory: stats.isDirectory() }; files.push(fileInfo); if (stats.isDirectory()) { files.push(...this.getAllProjectFiles(fullPath, maxDepth, currentDepth + 1)); } } } catch (error) { console.warn(`Error reading directory ${dir}:`, error); } return files; } shouldIgnore(filename) { const ignorePatterns = [ 'node_modules', '.git', 'dist', 'build', '.DS_Store', 'Thumbs.db', 'CLAUDE.md' ]; return ignorePatterns.some(pattern => filename === pattern || filename.startsWith('.') && filename !== '.gitignore'); } getBaseName(filename) { const lastDotIndex = filename.lastIndexOf('.'); return lastDotIndex > 0 ? filename.substring(0, lastDotIndex) : filename; } calculateConfidence(original, suggested, convention) { if (original === suggested) return 1.0; const originalBase = this.getBaseName(original); const suggestedBase = this.getBaseName(suggested); let confidence = 0.5; const words1 = this.extractWords(originalBase); const words2 = this.extractWords(suggestedBase); if (words1.join('').toLowerCase() === words2.join('').toLowerCase()) { confidence += 0.3; } const pattern = naming_validator_1.NamingValidator['CONVENTION_PATTERNS'][convention]; if (pattern && pattern.test(suggestedBase)) { confidence += 0.2; } return Math.min(confidence, 1.0); } extractWords(name) { return name .replace(/([a-z])([A-Z])/g, '$1 $2') .replace(/[_-]/g, ' ') .split(/\s+/) .filter(word => word.length > 0); } } exports.SuggestionEngine = SuggestionEngine; //# sourceMappingURL=suggestion-engine.js.map