UNPKG

@iyulab/oops

Version:

Core SDK for Oops - Safe text file editing with automatic backup

270 lines 10.5 kB
"use strict"; /** * Simple Version Management System * Implements Git-style version numbering without Git dependency */ 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.SimpleVersionManager = void 0; const file_system_1 = require("./file-system"); const errors_1 = require("./errors"); const path = __importStar(require("path")); const crypto = __importStar(require("crypto")); class SimpleVersionManager { versionsPath; filePath; constructor(workspacePath, filePath) { const fileHash = this.generateFileHash(filePath); this.versionsPath = path.join(workspacePath, 'versions', fileHash); this.filePath = filePath; } /** * Initialize version system for a file */ async initialize() { await file_system_1.FileSystem.mkdir(this.versionsPath); } /** * Create initial version (1) */ async createInitialVersion(message = 'Initial version') { const content = await file_system_1.FileSystem.readFile(this.filePath); const version = 1; const versionInfo = { version, message, timestamp: new Date(), checksum: this.generateChecksum(content), content, }; await this.saveVersion(versionInfo); await this.setCurrentVersion(version); return versionInfo; } /** * Commit changes as new version */ async commitVersion(message) { const currentContent = await file_system_1.FileSystem.readFile(this.filePath); const currentVersion = await this.getCurrentVersion(); // Check if there are changes if (currentVersion) { const lastVersion = await this.getVersion(currentVersion); if (lastVersion && lastVersion.content === currentContent) { throw new errors_1.OopsError('No changes detected since last version', 'VERSION_NO_CHANGES'); } } // Determine next version const nextVersion = await this.getNextVersion(); const versionInfo = { version: nextVersion, message, timestamp: new Date(), checksum: this.generateChecksum(currentContent), content: currentContent, }; await this.saveVersion(versionInfo); await this.setCurrentVersion(nextVersion); return { version: nextVersion, message, previousVersion: currentVersion || undefined, }; } /** * Get all versions in chronological order */ async getAllVersions() { const versionsFile = path.join(this.versionsPath, 'versions.json'); if (!(await file_system_1.FileSystem.exists(versionsFile))) { return []; } const data = await file_system_1.FileSystem.readFile(versionsFile); const versions = JSON.parse(data); // Convert timestamp strings back to Date objects return versions.map((v) => ({ ...v, timestamp: new Date(v.timestamp), })); } /** * Get specific version */ async getVersion(version) { const versions = await this.getAllVersions(); return versions.find(v => v.version === version) || null; } /** * Checkout specific version */ async checkoutVersion(version) { const versionInfo = await this.getVersion(version); if (!versionInfo) { throw new errors_1.OopsError(`Version ${version} not found`, 'VERSION_NOT_FOUND'); } // Write version content to file await file_system_1.FileSystem.writeFile(this.filePath, versionInfo.content); await this.setCurrentVersion(version); } /** * Get current version */ async getCurrentVersion() { const currentFile = path.join(this.versionsPath, 'current.txt'); if (!(await file_system_1.FileSystem.exists(currentFile))) { return null; } const versionStr = await file_system_1.FileSystem.readFile(currentFile); return parseInt(versionStr, 10); } /** * Get diff between versions */ async getDiff(fromVersion, toVersion) { let fromContent; let toContent; if (!fromVersion && !toVersion) { // Diff working directory against last version const currentVersion = await this.getCurrentVersion(); if (!currentVersion) { return 'No versions to compare with'; } const lastVersionInfo = await this.getVersion(currentVersion); fromContent = lastVersionInfo ? lastVersionInfo.content : ''; toContent = await file_system_1.FileSystem.readFile(this.filePath); } else if (fromVersion && !toVersion) { // Diff specific version against working directory const fromVersionInfo = await this.getVersion(fromVersion); if (!fromVersionInfo) { throw new errors_1.OopsError(`Version ${fromVersion} not found`, 'VERSION_NOT_FOUND'); } fromContent = fromVersionInfo.content; toContent = await file_system_1.FileSystem.readFile(this.filePath); } else if (fromVersion && toVersion) { // Diff between two versions const fromVersionInfo = await this.getVersion(fromVersion); const toVersionInfo = await this.getVersion(toVersion); if (!fromVersionInfo) { throw new errors_1.OopsError(`Version ${fromVersion} not found`, 'VERSION_NOT_FOUND'); } if (!toVersionInfo) { throw new errors_1.OopsError(`Version ${toVersion} not found`, 'VERSION_NOT_FOUND'); } fromContent = fromVersionInfo.content; toContent = toVersionInfo.content; } else { return 'Invalid diff parameters'; } return this.generateSimpleDiff(fromContent, toContent); } /** * Check if file has changes since last version */ async hasChanges() { const currentVersion = await this.getCurrentVersion(); if (!currentVersion) { return true; // No versions means there are changes to track } const lastVersion = await this.getVersion(currentVersion); if (!lastVersion) { return true; } const currentContent = await file_system_1.FileSystem.readFile(this.filePath); return lastVersion.content !== currentContent; } // Private helper methods async saveVersion(versionInfo) { const versionsFile = path.join(this.versionsPath, 'versions.json'); let versions = []; if (await file_system_1.FileSystem.exists(versionsFile)) { const data = await file_system_1.FileSystem.readFile(versionsFile); versions = JSON.parse(data); } versions.push(versionInfo); await file_system_1.FileSystem.writeFile(versionsFile, JSON.stringify(versions, null, 2)); } async setCurrentVersion(version) { const currentFile = path.join(this.versionsPath, 'current.txt'); await file_system_1.FileSystem.writeFile(currentFile, version.toString()); } async getNextVersion() { const versions = await this.getAllVersions(); if (versions.length === 0) { return 1; } // Find the highest version number and increment by 1 const maxVersion = Math.max(...versions.map(v => v.version)); return maxVersion + 1; } generateFileHash(filePath) { return crypto.createHash('sha256').update(filePath).digest('hex').slice(0, 8); } generateChecksum(content) { return crypto.createHash('sha256').update(content).digest('hex').slice(0, 8); } generateSimpleDiff(fromContent, toContent) { const fromLines = fromContent.split('\n'); const toLines = toContent.split('\n'); const fileName = path.basename(this.filePath); let diff = `diff --git a/${fileName} b/${fileName}\n`; diff += `--- a/${fileName}\n`; diff += `+++ b/${fileName}\n`; // Simple line-by-line diff const maxLines = Math.max(fromLines.length, toLines.length); let hasChanges = false; for (let i = 0; i < maxLines; i++) { const fromLine = fromLines[i] || ''; const toLine = toLines[i] || ''; if (fromLine !== toLine) { if (!hasChanges) { diff += `@@ -${i + 1},${fromLines.length - i} +${i + 1},${toLines.length - i} @@\n`; hasChanges = true; } if (fromLine) { diff += `-${fromLine}\n`; } if (toLine) { diff += `+${toLine}\n`; } } } return hasChanges ? diff : 'No differences found'; } } exports.SimpleVersionManager = SimpleVersionManager; //# sourceMappingURL=simple-version.js.map