import { SmartFile } from './classes.smartfile.js'; import * as plugins from './plugins.js'; export interface IVirtualDirectoryConstructorOptions { mode: ''; } /** * a virtual directory exposes a fs api * Use SmartFileFactory to create instances of this class */ export class VirtualDirectory { // STATIC public static async fromFsDirPath( pathArg: string, smartFs?: any, factory?: any ): Promise { if (!smartFs || !factory) { throw new Error('No SmartFs/Factory instance available. Create VirtualDirectory through SmartFileFactory.'); } const newVirtualDir = new VirtualDirectory(smartFs, factory); // Use smartFs to list directory and factory to create SmartFiles const entries = await smartFs.directory(pathArg).list({ recursive: true }); const smartfiles = await Promise.all( entries .filter((entry: any) => entry.isFile) .map((entry: any) => factory.fromFilePath(entry.path, pathArg)) ); newVirtualDir.addSmartfiles(smartfiles); return newVirtualDir; } public static async fromVirtualDirTransferableObject( virtualDirTransferableObjectArg: plugins.smartfileInterfaces.VirtualDirTransferableObject, smartFs?: any, factory?: any ): Promise { const newVirtualDir = new VirtualDirectory(smartFs, factory); for (const fileArg of virtualDirTransferableObjectArg.files) { const smartFile = SmartFile.enfoldFromJson(fileArg) as SmartFile; // Update smartFs reference if available if (smartFs) { (smartFile as any).smartFs = smartFs; } newVirtualDir.addSmartfiles([smartFile]); } return newVirtualDir; } public static fromFileArray(files: SmartFile[], smartFs?: any, factory?: any): VirtualDirectory { const vdir = new VirtualDirectory(smartFs, factory); vdir.addSmartfiles(files); return vdir; } public static empty(smartFs?: any, factory?: any): VirtualDirectory { return new VirtualDirectory(smartFs, factory); } // INSTANCE public smartfileArray: SmartFile[] = []; private smartFs?: any; private factory?: any; constructor(smartFs?: any, factory?: any) { this.smartFs = smartFs; this.factory = factory; } // ============================================ // Collection Mutations // ============================================ public addSmartfiles(smartfileArrayArg: SmartFile[]) { this.smartfileArray = this.smartfileArray.concat(smartfileArrayArg); } public addSmartfile(smartfileArg: SmartFile): void { this.smartfileArray.push(smartfileArg); } public removeByPath(pathArg: string): boolean { const initialLength = this.smartfileArray.length; this.smartfileArray = this.smartfileArray.filter(f => f.path !== pathArg); return this.smartfileArray.length < initialLength; } public clear(): void { this.smartfileArray = []; } public merge(otherVDir: VirtualDirectory): void { this.addSmartfiles(otherVDir.smartfileArray); } // ============================================ // Collection Queries // ============================================ public exists(pathArg: string): boolean { return this.smartfileArray.some(f => f.path === pathArg); } public has(pathArg: string): boolean { return this.exists(pathArg); } public async getFileByPath(pathArg: string): Promise { return this.smartfileArray.find(f => f.path === pathArg); } public listFiles(): SmartFile[] { return [...this.smartfileArray]; } public listDirectories(): string[] { const dirs = new Set(); for (const file of this.smartfileArray) { const dir = plugins.path.dirname(file.path); if (dir !== '.') { dirs.add(dir); } } return Array.from(dirs).sort(); } public filter(predicate: (file: SmartFile) => boolean): VirtualDirectory { const newVDir = new VirtualDirectory(this.smartFs, this.factory); newVDir.addSmartfiles(this.smartfileArray.filter(predicate)); return newVDir; } public map(fn: (file: SmartFile) => SmartFile): VirtualDirectory { const newVDir = new VirtualDirectory(this.smartFs, this.factory); newVDir.addSmartfiles(this.smartfileArray.map(fn)); return newVDir; } public find(predicate: (file: SmartFile) => boolean): SmartFile | undefined { return this.smartfileArray.find(predicate); } public size(): number { return this.smartfileArray.length; } public isEmpty(): boolean { return this.smartfileArray.length === 0; } public async toVirtualDirTransferableObject(): Promise { return { files: this.smartfileArray.map((smartfileArg) => smartfileArg.foldToJson(), ), }; } public async saveToDisk(dirArg: string) { console.log(`writing VirtualDirectory with ${this.smartfileArray.length} files to directory: --> ${dirArg}`); for (const smartfileArg of this.smartfileArray) { const filePath = await smartfileArg.writeToDir(dirArg); console.log(`wrote ${smartfileArg.relative} to --> ${filePath}`); } } public async shiftToSubdirectory(subDir: string): Promise { const newVirtualDir = new VirtualDirectory(this.smartFs, this.factory); for (const file of this.smartfileArray) { if (file.path.startsWith(subDir)) { const adjustedFilePath = plugins.path.relative(subDir, file.path); file.path = adjustedFilePath; newVirtualDir.addSmartfiles([file]); } } return newVirtualDir; } public async loadFromDisk(dirArg: string): Promise { // Load from disk, replacing current collection this.clear(); const loaded = await VirtualDirectory.fromFsDirPath(dirArg, this.smartFs, this.factory); this.addSmartfiles(loaded.smartfileArray); } public async addVirtualDirectory( virtualDir: VirtualDirectory, newRoot: string, ): Promise { for (const file of virtualDir.smartfileArray) { file.path = plugins.path.join(newRoot, file.path); } this.addSmartfiles(virtualDir.smartfileArray); } }