141 lines
4.3 KiB
JavaScript
141 lines
4.3 KiB
JavaScript
import { promises as fs, existsSync } from 'fs'
|
|
import { join } from 'path'
|
|
import globby from 'globby'
|
|
import process from 'node:process'
|
|
import chalk from 'chalk'
|
|
|
|
// Helper function to format size appropriately in KB or MB
|
|
function formatSize(sizeInBytes) {
|
|
const sizeInKB = sizeInBytes / 1024
|
|
if (sizeInKB < 1024) {
|
|
return `${sizeInKB.toFixed(2)} KB`
|
|
} else {
|
|
return `${(sizeInKB / 1024).toFixed(2)} MB`
|
|
}
|
|
}
|
|
|
|
// Function to calculate the size of a directory
|
|
async function calculateSize(targetPath) {
|
|
let totalSize = 0
|
|
const stats = await fs.lstat(targetPath)
|
|
if (stats.isDirectory()) {
|
|
const files = await fs.readdir(targetPath)
|
|
for (const file of files) {
|
|
const filePath = join(targetPath, file)
|
|
totalSize += await calculateSize(filePath)
|
|
}
|
|
} else {
|
|
totalSize = stats.size
|
|
}
|
|
return totalSize
|
|
}
|
|
|
|
// Function to delete a file or directory recursively
|
|
async function deleteRecursively(targetPath, fullDelete = false) {
|
|
try {
|
|
if (fullDelete && existsSync(targetPath)) {
|
|
const size = await calculateSize(targetPath)
|
|
await fs.rmdir(targetPath, { recursive: true }) // Use async version of rmdir
|
|
return size
|
|
}
|
|
|
|
const stats = await fs.lstat(targetPath)
|
|
let size = 0
|
|
if (stats.isDirectory()) {
|
|
const files = await fs.readdir(targetPath)
|
|
for (const file of files) {
|
|
const curPath = join(targetPath, file)
|
|
size += await deleteRecursively(curPath)
|
|
}
|
|
await fs.rmdir(targetPath)
|
|
} else {
|
|
size = stats.size
|
|
await fs.unlink(targetPath)
|
|
}
|
|
return size
|
|
} catch (error) {
|
|
console.error(chalk.red(`Error deleting ${targetPath}: ${error.message}`))
|
|
return 0 // Return 0 size if there's an error
|
|
}
|
|
}
|
|
|
|
// Function to clean directories based on provided patterns
|
|
async function cleanDirectories(patterns) {
|
|
const deletedCounts = {}
|
|
let totalSize = 0
|
|
|
|
for (let entry of patterns) {
|
|
const ignoreNodeModules = !entry.endsWith('!')
|
|
let pattern = ignoreNodeModules ? entry : entry.slice(0, -1)
|
|
|
|
let files = []
|
|
let fulleDelete = false
|
|
if (pattern === '@node_modules') {
|
|
pattern = '**/node_modules'
|
|
fulleDelete = true
|
|
files = await globby(pattern, {
|
|
onlyDirectories: true,
|
|
ignore: ['**/node_modules/**/node_modules'],
|
|
})
|
|
} else {
|
|
const options = {
|
|
ignore: ignoreNodeModules ? '**/node_modules/**' : '',
|
|
onlyDirectories: pattern.endsWith('/') ? true : false,
|
|
}
|
|
fulleDelete = options.onlyDirectories
|
|
|
|
files = await globby(pattern, options)
|
|
}
|
|
|
|
let count = 0
|
|
let patternSize = 0
|
|
for (const file of files) {
|
|
const fileSize = await deleteRecursively(file, fulleDelete)
|
|
count++
|
|
patternSize += fileSize
|
|
}
|
|
deletedCounts[pattern] = { count, size: patternSize }
|
|
totalSize += patternSize
|
|
}
|
|
|
|
// Determine the maximum lengths needed for even spacing
|
|
const maxPatternLength = Math.max(...Object.keys(deletedCounts).map((pattern) => pattern.length))
|
|
const maxCountLength = Math.max(
|
|
...Object.values(deletedCounts).map(
|
|
(item) => `${item.count} item${item.count !== 1 ? 's' : ''} deleted`.length,
|
|
),
|
|
)
|
|
const maxSizeLength = Math.max(
|
|
...Object.values(deletedCounts).map((item) => formatSize(item.size).length),
|
|
)
|
|
|
|
// Print details for each pattern with colors, formatted for alignment
|
|
console.log(chalk.blue('Summary of deleted items:'))
|
|
Object.keys(deletedCounts).forEach((pattern) => {
|
|
const itemCount =
|
|
`${deletedCounts[pattern].count} item${deletedCounts[pattern].count !== 1 ? 's' : ''} deleted`.padEnd(
|
|
maxCountLength,
|
|
)
|
|
console.log(
|
|
`${chalk.green(pattern.padEnd(maxPatternLength))} ${chalk.red(itemCount)} ${chalk.yellow(formatSize(deletedCounts[pattern].size).padStart(maxSizeLength))}`,
|
|
)
|
|
})
|
|
|
|
// Calculate total deleted items and size
|
|
console.log(
|
|
chalk.magenta(
|
|
`Total deleted items: ${Object.values(deletedCounts).reduce((acc, { count }) => acc + count, 0)}`,
|
|
),
|
|
)
|
|
console.log(chalk.cyan(`Total size of deleted items: ${formatSize(totalSize)}`))
|
|
}
|
|
|
|
// Get patterns from command-line arguments
|
|
const patterns = process.argv.slice(2)
|
|
|
|
if (patterns.length > 0) {
|
|
void cleanDirectories(patterns)
|
|
} else {
|
|
console.log(chalk.red('No patterns provided. Usage: node script.js [patterns]'))
|
|
}
|