filesops
Version:
Advanced file operations library with search, type detection, size calculation, and permission utilities
301 lines • 10.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SizeCalculator = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const util_1 = require("util");
const stat = (0, util_1.promisify)(fs.stat);
const readdir = (0, util_1.promisify)(fs.readdir);
/**
* File and directory size calculation utilities
*/
class SizeCalculator {
/**
* Convert bytes to human-readable format
*/
static formatBytes(bytes, decimals = 2) {
if (bytes === 0)
return '0 B';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const i = Math.floor(Math.log(bytes) / Math.log(k));
const size = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
return `${size} ${this.UNITS[i]}`;
}
/**
* Get detailed size information for a given byte count
*/
static getSizeInfo(bytes) {
return {
bytes,
kilobytes: bytes / 1024,
megabytes: bytes / (1024 * 1024),
gigabytes: bytes / (1024 * 1024 * 1024),
terabytes: bytes / (1024 * 1024 * 1024 * 1024),
formatted: this.formatBytes(bytes),
};
}
/**
* Get file size
*/
static async getFileSize(filePath) {
try {
const stats = await stat(filePath);
return this.getSizeInfo(stats.size);
}
catch (error) {
throw new Error(`Unable to get size for file: ${filePath}`);
}
}
/**
* Calculate directory size recursively
*/
static async getDirectorySize(dirPath, includeHidden = false) {
const size = await this.calculateDirectorySizeRecursive(dirPath, includeHidden);
return this.getSizeInfo(size);
}
static async calculateDirectorySizeRecursive(dirPath, includeHidden) {
let totalSize = 0;
try {
const items = await readdir(dirPath);
for (const item of items) {
if (!includeHidden && item.startsWith('.')) {
continue;
}
const itemPath = path.join(dirPath, item);
try {
const stats = await stat(itemPath);
if (stats.isFile()) {
totalSize += stats.size;
}
else if (stats.isDirectory()) {
totalSize += await this.calculateDirectorySizeRecursive(itemPath, includeHidden);
}
}
catch (error) {
// Skip files/directories that can't be accessed
continue;
}
}
}
catch (error) {
// Skip directories that can't be read
}
return totalSize;
}
/**
* Get size statistics for a directory (file count, total size, largest files)
*/
static async getDirectoryStats(dirPath, includeHidden = false) {
const stats = await this.gatherDirectoryStats(dirPath, includeHidden);
return {
totalSize: this.getSizeInfo(stats.totalSize),
fileCount: stats.fileCount,
directoryCount: stats.directoryCount,
largestFiles: stats.largestFiles
.sort((a, b) => b.size - a.size)
.slice(0, 10)
.map(file => ({
path: file.path,
size: this.getSizeInfo(file.size),
})),
averageFileSize: this.getSizeInfo(stats.fileCount > 0 ? stats.totalSize / stats.fileCount : 0),
};
}
static async gatherDirectoryStats(dirPath, includeHidden, stats = { totalSize: 0, fileCount: 0, directoryCount: 0, largestFiles: [] }) {
try {
const items = await readdir(dirPath);
for (const item of items) {
if (!includeHidden && item.startsWith('.')) {
continue;
}
const itemPath = path.join(dirPath, item);
try {
const itemStats = await stat(itemPath);
if (itemStats.isFile()) {
stats.totalSize += itemStats.size;
stats.fileCount++;
stats.largestFiles.push({ path: itemPath, size: itemStats.size });
}
else if (itemStats.isDirectory()) {
stats.directoryCount++;
await this.gatherDirectoryStats(itemPath, includeHidden, stats);
}
}
catch (error) {
// Skip files/directories that can't be accessed
continue;
}
}
}
catch (error) {
// Skip directories that can't be read
}
return stats;
}
/**
* Compare sizes of multiple files or directories
*/
static async compareItems(paths) {
const results = [];
for (const itemPath of paths) {
try {
const stats = await stat(itemPath);
let size;
if (stats.isFile()) {
size = this.getSizeInfo(stats.size);
}
else if (stats.isDirectory()) {
size = await this.getDirectorySize(itemPath);
}
else {
continue;
}
results.push({
path: itemPath,
size,
isDirectory: stats.isDirectory(),
});
}
catch (error) {
// Skip items that can't be accessed
continue;
}
}
return results.sort((a, b) => b.size.bytes - a.size.bytes);
}
/**
* Find the largest files in a directory
*/
static async findLargestFiles(dirPath, limit = 10, includeHidden = false) {
const files = [];
await this.collectFiles(dirPath, files, includeHidden);
return files
.sort((a, b) => b.size - a.size)
.slice(0, limit)
.map(file => ({
path: file.path,
size: this.getSizeInfo(file.size),
}));
}
static async collectFiles(dirPath, files, includeHidden) {
try {
const items = await readdir(dirPath);
for (const item of items) {
if (!includeHidden && item.startsWith('.')) {
continue;
}
const itemPath = path.join(dirPath, item);
try {
const stats = await stat(itemPath);
if (stats.isFile()) {
files.push({ path: itemPath, size: stats.size });
}
else if (stats.isDirectory()) {
await this.collectFiles(itemPath, files, includeHidden);
}
}
catch (error) {
// Skip files/directories that can't be accessed
continue;
}
}
}
catch (error) {
// Skip directories that can't be read
}
}
/**
* Calculate size of files matching a pattern
*/
static async getSizeByPattern(dirPath, pattern, includeHidden = false) {
let totalSize = 0;
await this.collectSizeByPattern(dirPath, pattern, includeHidden, (size) => {
totalSize += size;
});
return this.getSizeInfo(totalSize);
}
static async collectSizeByPattern(dirPath, pattern, includeHidden, callback) {
try {
const items = await readdir(dirPath);
for (const item of items) {
if (!includeHidden && item.startsWith('.')) {
continue;
}
const itemPath = path.join(dirPath, item);
try {
const stats = await stat(itemPath);
if (stats.isFile() && pattern.test(item)) {
callback(stats.size);
}
else if (stats.isDirectory()) {
await this.collectSizeByPattern(itemPath, pattern, includeHidden, callback);
}
}
catch (error) {
// Skip files/directories that can't be accessed
continue;
}
}
}
catch (error) {
// Skip directories that can't be read
}
}
/**
* Parse human-readable size string to bytes
*/
static parseSize(sizeString) {
const match = sizeString.match(/^(\d+(?:\.\d+)?)\s*([KMGTPE]?B?)$/i);
if (!match) {
throw new Error(`Invalid size format: ${sizeString}`);
}
const value = parseFloat(match[1]);
const unit = (match[2] || 'B').toUpperCase();
const multipliers = {
'B': 1,
'KB': 1024,
'MB': 1024 * 1024,
'GB': 1024 * 1024 * 1024,
'TB': 1024 * 1024 * 1024 * 1024,
'PB': 1024 * 1024 * 1024 * 1024 * 1024,
};
return Math.round(value * (multipliers[unit] || 1));
}
}
exports.SizeCalculator = SizeCalculator;
SizeCalculator.UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
//# sourceMappingURL=size.js.map