UNPKG

claudes-office

Version:

CLI tool to initialize Claude's office in your project

274 lines 9.61 kB
"use strict"; /** * File comparison utilities for the update command * These utilities help detect differences between files and directories */ 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.compareFiles = compareFiles; exports.compareDirectories = compareDirectories; exports.formatDifferences = formatDifferences; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const diff = __importStar(require("diff")); /** * Compare two files and return the differences * @param filePath1 - Path to the first file * @param filePath2 - Path to the second file * @param options - Comparison options * @returns The comparison result */ async function compareFiles(filePath1, filePath2, options = {}) { try { // Read file contents const content1 = await fs.readFile(filePath1, 'utf8'); const content2 = await fs.readFile(filePath2, 'utf8'); // Normalize content if needed let normalizedContent1 = content1; let normalizedContent2 = content2; if (options.ignoreWhitespace) { normalizedContent1 = normalizedContent1.replace(/\s+/g, ' ').trim(); normalizedContent2 = normalizedContent2.replace(/\s+/g, ' ').trim(); } if (options.ignoreCase) { normalizedContent1 = normalizedContent1.toLowerCase(); normalizedContent2 = normalizedContent2.toLowerCase(); } // Calculate differences const differences = diff.diffLines(normalizedContent1, normalizedContent2); // Calculate statistics const stats = { additions: 0, deletions: 0, changes: 0, }; differences.forEach(part => { if (part.added) { stats.additions += part.count || 0; } else if (part.removed) { stats.deletions += part.count || 0; } }); // If there are both additions and deletions, count them as changes const minChanges = Math.min(stats.additions, stats.deletions); stats.changes = minChanges; stats.additions -= minChanges; stats.deletions -= minChanges; return { identical: differences.length === 1 && !differences[0].added && !differences[0].removed, differences, stats, }; } catch (error) { // If one of the files doesn't exist, they are not identical if (error.code === 'ENOENT') { return { identical: false, differences: [{ value: 'One or both files do not exist', added: false, removed: false, }], stats: { additions: 0, deletions: 0, changes: 0, }, }; } throw error; } } /** * Compare two directories and return the differences * @param dir1 - Path to the first directory * @param dir2 - Path to the second directory * @param options - Comparison options * @returns The comparison result */ async function compareDirectories(dir1, dir2, options = {}) { // Get all items in both directories recursively const items1 = await getDirectoryItems(dir1); const items2 = await getDirectoryItems(dir2); // Organize items by relative path const itemMap1 = new Map(); const itemMap2 = new Map(); items1.forEach(item => itemMap1.set(item.relativePath, item)); items2.forEach(item => itemMap2.set(item.relativePath, item)); // Find items in only one directory const onlyInDir1 = []; const onlyInDir2 = []; const inBothDirs = []; // Items only in dir1 items1.forEach(item => { if (!itemMap2.has(item.relativePath)) { // Skip ignored patterns if (shouldIgnore(item.relativePath, options.ignorePatterns)) { return; } onlyInDir1.push(item); } else { inBothDirs.push(item); } }); // Items only in dir2 items2.forEach(item => { if (!itemMap1.has(item.relativePath)) { // Skip ignored patterns if (shouldIgnore(item.relativePath, options.ignorePatterns)) { return; } onlyInDir2.push(item); } }); // Compare files that exist in both directories const differentFiles = []; for (const item of inBothDirs) { if (!item.isDirectory) { // Skip ignored patterns if (shouldIgnore(item.relativePath, options.ignorePatterns)) { continue; } const filePath1 = path.join(dir1, item.relativePath); const filePath2 = path.join(dir2, item.relativePath); const comparison = await compareFiles(filePath1, filePath2, options); if (!comparison.identical) { differentFiles.push({ relativePath: item.relativePath, comparison, }); } } } return { onlyInDir1, onlyInDir2, inBothDirs, differentFiles, }; } /** * Get all items in a directory recursively * @param dirPath - Path to the directory * @param basePath - Base path for calculating relative paths * @returns Array of directory items */ async function getDirectoryItems(dirPath, basePath = dirPath) { const items = []; try { const entries = await fs.readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const entryPath = path.join(dirPath, entry.name); const relativePath = path.relative(basePath, entryPath); if (entry.isDirectory()) { items.push({ path: entryPath, isDirectory: true, relativePath, }); // Recursively process subdirectories const subItems = await getDirectoryItems(entryPath, basePath); items.push(...subItems); } else { items.push({ path: entryPath, isDirectory: false, relativePath, }); } } } catch (error) { // If directory doesn't exist, return empty array if (error.code === 'ENOENT') { return []; } throw error; } return items; } /** * Check if a path should be ignored based on ignore patterns * @param relativePath - Relative path to check * @param ignorePatterns - Patterns to ignore * @returns Whether the path should be ignored */ function shouldIgnore(relativePath, ignorePatterns) { if (!ignorePatterns || ignorePatterns.length === 0) { return false; } // Simple glob pattern matching // For a real implementation, you'd want to use a proper glob library return ignorePatterns.some(pattern => { // Exact match if (pattern === relativePath) { return true; } // Directory wildcard (e.g., "dir/**") if (pattern.endsWith('/**') && relativePath.startsWith(pattern.slice(0, -3))) { return true; } // File extension wildcard (e.g., "*.js") if (pattern.startsWith('*.') && relativePath.endsWith(pattern.slice(1))) { return true; } return false; }); } /** * Format differences for human-readable output * @param differences - Array of diff changes * @returns Formatted string with differences */ function formatDifferences(differences) { let result = ''; differences.forEach(part => { // Add prefix for added/removed lines const prefix = part.added ? '+ ' : part.removed ? '- ' : ' '; // Split by lines and add prefix to each line const lines = part.value.split('\n'); lines.forEach(line => { if (line) { result += prefix + line + '\n'; } }); }); return result; } //# sourceMappingURL=fileComparison.js.map