WebScriptsRename FilesRename All Files and Folders in src to kebab-case // rename-files.js import fs from 'fs' import { execSync } from 'node:child_process' import path from 'node:path' function toKebabCase(str) { return str .replace(/([a-z\d])([A-Z])/g, '$1-$2') // camelCase or PascalCase to kebab-case .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1-$2') // Handle cases like XMLHTTPRequest .replace(/[\s_]+/g, '-') // spaces or underscores to dashes .toLowerCase() } function isTrackedByGit(filePath) { try { execSync(`git ls-files --error-unmatch "${filePath}"`, { stdio: 'ignore' }) return true } catch { return false } } function renameWithGitMv(oldPath, newPath) { if (!fs.existsSync(oldPath)) { console.info(`Skipped (source doesn't exist): ${oldPath}`) return } if (oldPath === newPath) { console.info(`Skipped (already renamed): ${oldPath}`) return } if (isTrackedByGit(oldPath)) { const tempPath = `${newPath}_temp_${Date.now()}` execSync(`git mv "${oldPath}" "${tempPath}"`) execSync(`git mv "${tempPath}" "${newPath}"`) console.info(`Renamed (git mv): ${oldPath} -> ${newPath}`) } else { fs.renameSync(oldPath, newPath) console.info(`Renamed (fs.renameSync): ${oldPath} -> ${newPath}`) } } function convertSingleIndexFolders(dir) { const entries = fs.readdirSync(dir) entries.forEach((entry) => { const oldPath = path.join(dir, entry) const stat = fs.statSync(oldPath) if (stat.isDirectory()) { const subEntries = fs.readdirSync(oldPath) if (subEntries.length === 1 && subEntries[0] === 'index.tsx') { const newFileName = `${toKebabCase(entry)}.tsx` const newPath = path.join(dir, newFileName) const indexFilePath = path.join(oldPath, 'index.tsx') renameWithGitMv(indexFilePath, newPath) fs.rmdirSync(oldPath) console.info(`Converted folder to file: ${oldPath} -> ${newPath}`) return } } if (stat.isDirectory()) { convertSingleIndexFolders(oldPath) // Recursively handle subdirectories } }) } function renameFilesAndFolders(dir) { const entries = fs.readdirSync(dir).sort((a, b) => b.length - a.length) entries.forEach((entry) => { const oldPath = path.join(dir, entry) const stat = fs.statSync(oldPath) const newEntry = toKebabCase(entry) const newPath = path.join(dir, newEntry) if (oldPath !== newPath) { // Skip if already in kebab case if (entry === newEntry) { console.info(`Skipped (already kebab case): ${oldPath}`) return } // Rename files or directories using git mv renameWithGitMv(oldPath, newPath) if (stat.isDirectory()) { // Recursively rename contents if it's a directory renameFilesAndFolders(newPath) } console.info(`Renamed: ${oldPath} -> ${newPath}`) } else if (stat.isDirectory()) { // Process contents of directories that are already in kebab-case renameFilesAndFolders(newPath) } }) } convertSingleIndexFolders('./src') // Convert single index.tsx folders first renameFilesAndFolders('./src') // Replace with your root directory if different Then run: node rename-files.jsPreviousMiscellaneousNextGoogle Fonts