UNPKG

@workspace-fs/core

Version:

Multi-project workspace manager for Firesystem with support for multiple sources

153 lines (131 loc) 4.1 kB
import { TypedEventEmitter } from "@firesystem/core"; import type { Project, SyncOptions, ProjectDiff, WorkspaceEventPayloads, } from "../types"; export class ProjectOperations { constructor( private getProject: (projectId: string) => Project | null, private events: TypedEventEmitter<WorkspaceEventPayloads>, ) {} /** * Copy files between projects */ async copyFiles( sourceId: string, pattern: string, targetId: string, targetPath: string, ): Promise<void> { const sourceProject = this.getProject(sourceId); const targetProject = this.getProject(targetId); if (!sourceProject) throw new Error(`Source project ${sourceId} not found`); if (!targetProject) throw new Error(`Target project ${targetId} not found`); const files = await sourceProject.fs.glob(pattern); let copied = 0; for (const file of files) { const stat = await sourceProject.fs.stat(file); if (stat.type === "file") { const content = await sourceProject.fs.readFile(file); const targetFilePath = (targetPath + file).replace(/\/+/g, "/"); await targetProject.fs.writeFile( targetFilePath, content.content, content.metadata, ); copied++; } } this.events.emit("project:files-copied", { sourceId, targetId, fileCount: copied, }); } /** * Sync projects */ async syncProjects( sourceId: string, targetId: string, options: SyncOptions = {}, ): Promise<void> { const sourceProject = this.getProject(sourceId); const targetProject = this.getProject(targetId); if (!sourceProject) throw new Error(`Source project ${sourceId} not found`); if (!targetProject) throw new Error(`Target project ${targetId} not found`); const files = await sourceProject.fs.glob("**/*"); const total = files.length; let copied = 0; for (const file of files) { if (options.filter && !options.filter(file)) continue; const stat = await sourceProject.fs.stat(file); if (stat.type === "file") { const exists = await targetProject.fs.exists(file); if (!exists || options.overwrite) { const content = await sourceProject.fs.readFile(file); await targetProject.fs.writeFile( file, content.content, content.metadata, ); copied++; if (options.progress) { options.progress(copied, total); } } } } } /** * Compare projects */ async compareProjects( projectId1: string, projectId2: string, ): Promise<ProjectDiff> { const project1 = this.getProject(projectId1); const project2 = this.getProject(projectId2); if (!project1) throw new Error(`Project ${projectId1} not found`); if (!project2) throw new Error(`Project ${projectId2} not found`); const files1 = new Set(await project1.fs.glob("**/*")); const files2 = new Set(await project2.fs.glob("**/*")); const diff: ProjectDiff = { added: [], modified: [], deleted: [], unchanged: [], }; // Files in project2 but not in project1 (added) for (const file of files2) { if (!files1.has(file)) { diff.added.push(file); } } // Files in project1 but not in project2 (deleted) for (const file of files1) { if (!files2.has(file)) { diff.deleted.push(file); } } // Files in both - check if modified for (const file of files1) { if (files2.has(file)) { const stat1 = await project1.fs.stat(file); const stat2 = await project2.fs.stat(file); if (stat1.type === "file" && stat2.type === "file") { const content1 = await project1.fs.readFile(file); const content2 = await project2.fs.readFile(file); if (content1.content !== content2.content) { diff.modified.push(file); } else { diff.unchanged.push(file); } } } } return diff; } }