organ-ai-zer
Version:
AI-powered file organizer CLI tool
151 lines • 6.71 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.FileOrganizer = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
class FileOrganizer {
async applySuggestions(suggestions, baseDirectory) {
const sourceDirectories = new Set();
for (const suggestion of suggestions) {
try {
// Track source directories for cleanup
const sourceDir = path.dirname(suggestion.file.path);
sourceDirectories.add(sourceDir);
await this.moveFile(suggestion, baseDirectory);
console.log(`✅ Moved: ${suggestion.file.name} → ${suggestion.suggestedPath}`);
}
catch (error) {
console.error(`❌ Failed to move ${suggestion.file.name}: ${error}`);
}
}
// Clean up empty directories
await this.cleanupEmptyDirectories(Array.from(sourceDirectories));
}
async moveFile(suggestion, baseDirectory) {
// Resolve target path relative to base directory
const targetPath = baseDirectory ?
path.resolve(baseDirectory, suggestion.suggestedPath) :
path.resolve(suggestion.suggestedPath);
const targetDir = path.dirname(targetPath);
// Ensure target directory exists
await fs.ensureDir(targetDir);
// Check if target file already exists
if (await fs.pathExists(targetPath)) {
const newPath = await this.generateUniqueFilename(targetPath);
suggestion.suggestedPath = path.relative(baseDirectory || process.cwd(), newPath);
}
// Move the file
await fs.move(path.resolve(suggestion.file.path), targetPath);
}
async generateUniqueFilename(filePath) {
const dir = path.dirname(filePath);
const ext = path.extname(filePath);
const name = path.basename(filePath, ext);
let counter = 1;
let newPath = filePath;
while (await fs.pathExists(newPath)) {
newPath = path.join(dir, `${name}_${counter}${ext}`);
counter++;
}
return newPath;
}
async createBackup(directory) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const resolvedDir = path.resolve(directory);
const parentDir = path.dirname(resolvedDir);
const dirName = path.basename(resolvedDir);
const backupPath = path.join(parentDir, `backup_${dirName}_${timestamp}`);
await fs.copy(directory, backupPath);
return backupPath;
}
async cleanupEmptyDirectories(directories) {
// Sort directories by depth (deepest first) to ensure we clean up child directories before parents
const sortedDirectories = directories.sort((a, b) => b.split('/').length - a.split('/').length);
for (const directory of sortedDirectories) {
try {
await this.cleanupEmptyDirectory(directory);
}
catch (error) {
console.warn(`⚠️ Could not cleanup directory ${directory}: ${error}`);
}
}
}
async cleanupEmptyDirectory(directory) {
try {
// Check if directory exists
if (!(await fs.pathExists(directory))) {
return;
}
// Read directory contents
const contents = await fs.readdir(directory);
// If directory is empty, remove it
if (contents.length === 0) {
await fs.remove(directory);
console.log(`🗑️ Removed empty directory: ${directory}`);
// Recursively check parent directory
const parentDir = path.dirname(directory);
if (parentDir !== directory) { // Avoid infinite recursion at root
await this.cleanupEmptyDirectory(parentDir);
}
}
// If directory only contains hidden files (like .DS_Store), we might want to remove it too
else if (contents.every(item => item.startsWith('.'))) {
// Only remove if all files are common system files
const systemFiles = ['.DS_Store', '.Thumbs.db', 'desktop.ini'];
if (contents.every(item => systemFiles.includes(item))) {
// Remove system files first
for (const file of contents) {
await fs.remove(path.join(directory, file));
}
// Then remove the directory
await fs.remove(directory);
console.log(`🗑️ Removed directory with only system files: ${directory}`);
// Recursively check parent directory
const parentDir = path.dirname(directory);
if (parentDir !== directory) {
await this.cleanupEmptyDirectory(parentDir);
}
}
}
}
catch (error) {
// Silently ignore errors during cleanup - it's not critical
console.warn(`⚠️ Could not cleanup directory ${directory}: ${error}`);
}
}
}
exports.FileOrganizer = FileOrganizer;
//# sourceMappingURL=file-organizer.js.map