UNPKG

@firesystem/core

Version:

Virtual File System core interfaces and types

489 lines (483 loc) 14.1 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { BaseFileSystem: () => BaseFileSystem, EventEmitter: () => EventEmitter, FileSystemEvents: () => FileSystemEvents, TypedEventEmitter: () => TypedEventEmitter, basename: () => basename, dirname: () => dirname, extname: () => extname, isAbsolute: () => isAbsolute, join: () => join, normalizePath: () => normalizePath, withEvents: () => withEvents }); module.exports = __toCommonJS(index_exports); // src/types/FileSystemEvents.ts var FileSystemEvents = { // Initialization events INITIALIZING: "fs:initializing", INITIALIZED: "fs:initialized", INIT_PROGRESS: "fs:init:progress", INIT_ERROR: "fs:init:error", // Operation lifecycle events OPERATION_START: "fs:operation:start", OPERATION_END: "fs:operation:end", OPERATION_ERROR: "fs:operation:error", // File events (complement to watch) FILE_READING: "fs:file:reading", FILE_READ: "fs:file:read", FILE_WRITING: "fs:file:writing", FILE_WRITTEN: "fs:file:written", FILE_DELETING: "fs:file:deleting", FILE_DELETED: "fs:file:deleted", // Directory events DIR_READING: "fs:dir:reading", DIR_READ: "fs:dir:read", DIR_CREATING: "fs:dir:creating", DIR_CREATED: "fs:dir:created", DIR_DELETING: "fs:dir:deleting", DIR_DELETED: "fs:dir:deleted", // Batch operations BATCH_START: "fs:batch:start", BATCH_PROGRESS: "fs:batch:progress", BATCH_END: "fs:batch:end", // Storage events STORAGE_CLEARING: "fs:storage:clearing", STORAGE_CLEARED: "fs:storage:cleared", STORAGE_SIZE_CALCULATED: "fs:storage:size" }; // src/utils/paths.ts function normalizePath(path) { if (!path) return "/"; if (!path.startsWith("/")) { path = "/" + path; } path = path.replace(/\/+/g, "/"); if (path.length > 1 && path.endsWith("/")) { path = path.slice(0, -1); } return path; } function dirname(path) { const normalized = normalizePath(path); const lastSlash = normalized.lastIndexOf("/"); return lastSlash === 0 ? "/" : normalized.slice(0, lastSlash); } function basename(path) { const normalized = normalizePath(path); const lastSlash = normalized.lastIndexOf("/"); return normalized.slice(lastSlash + 1); } function join(...segments) { const joined = segments.join("/"); return normalizePath(joined); } function isAbsolute(path) { return path.startsWith("/"); } function extname(path) { const base = basename(path); const lastDot = base.lastIndexOf("."); return lastDot === -1 ? "" : base.slice(lastDot); } // src/utils/EventEmitter.ts var EventEmitter = class { constructor() { this.events = /* @__PURE__ */ new Map(); } on(event, handler) { if (!this.events.has(event)) { this.events.set(event, /* @__PURE__ */ new Set()); } this.events.get(event).add(handler); return { dispose: () => this.off(event, handler) }; } once(event, handler) { const wrappedHandler = (...args) => { handler(...args); this.off(event, wrappedHandler); }; return this.on(event, wrappedHandler); } emit(event, ...args) { const handlers = this.events.get(event); if (!handlers || handlers.size === 0) { return false; } handlers.forEach((handler) => { try { handler(...args); } catch (error) { console.error(`Error in event handler for ${String(event)}:`, error); } }); return true; } off(event, handler) { if (!handler) { this.events.delete(event); return; } const handlers = this.events.get(event); if (handlers) { handlers.delete(handler); if (handlers.size === 0) { this.events.delete(event); } } } removeAllListeners(event) { if (event) { this.events.delete(event); } else { this.events.clear(); } } }; var TypedEventEmitter = class { constructor() { this.emitter = new EventEmitter(); } on(event, handler) { return this.emitter.on(event, handler); } once(event, handler) { return this.emitter.once(event, handler); } emit(event, payload) { return this.emitter.emit(event, payload); } off(event, handler) { this.emitter.off(event, handler); } removeAllListeners(event) { this.emitter.removeAllListeners(event); } }; // src/mixins/withEvents.ts function withEvents(Base) { return class extends Base { constructor() { super(...arguments); this.events = new TypedEventEmitter(); } // Override methods to emit events async readFile(path) { const startTime = Date.now(); const operationId = `read-${path}-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "readFile", path, id: operationId }); this.events.emit(FileSystemEvents.FILE_READING, { path }); try { const result = await super.readFile(path); this.events.emit(FileSystemEvents.FILE_READ, { path, size: result.size || 0 }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "readFile", path, id: operationId, duration: Date.now() - startTime }); return result; } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "readFile", path, error }); throw error; } } async writeFile(path, content, metadata) { const startTime = Date.now(); const operationId = `write-${path}-${startTime}`; const size = typeof content === "string" ? content.length : JSON.stringify(content).length; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "writeFile", path, id: operationId }); this.events.emit(FileSystemEvents.FILE_WRITING, { path, size }); try { const result = await super.writeFile(path, content, metadata); this.events.emit(FileSystemEvents.FILE_WRITTEN, { path, size }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "writeFile", path, id: operationId, duration: Date.now() - startTime }); return result; } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "writeFile", path, error }); throw error; } } async deleteFile(path) { const startTime = Date.now(); const operationId = `delete-${path}-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "deleteFile", path, id: operationId }); this.events.emit(FileSystemEvents.FILE_DELETING, { path }); try { await super.deleteFile(path); this.events.emit(FileSystemEvents.FILE_DELETED, { path }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "deleteFile", path, id: operationId, duration: Date.now() - startTime }); } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "deleteFile", path, error }); throw error; } } async readDir(path) { const startTime = Date.now(); const operationId = `readDir-${path}-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "readDir", path, id: operationId }); this.events.emit(FileSystemEvents.DIR_READING, { path }); try { const result = await super.readDir(path); this.events.emit(FileSystemEvents.DIR_READ, { path, count: result.length }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "readDir", path, id: operationId, duration: Date.now() - startTime }); return result; } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "readDir", path, error }); throw error; } } async mkdir(path, recursive = false) { const startTime = Date.now(); const operationId = `mkdir-${path}-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "mkdir", path, id: operationId }); this.events.emit(FileSystemEvents.DIR_CREATING, { path, recursive }); try { const result = await super.mkdir(path, recursive); this.events.emit(FileSystemEvents.DIR_CREATED, { path }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "mkdir", path, id: operationId, duration: Date.now() - startTime }); return result; } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "mkdir", path, error }); throw error; } } async rmdir(path, recursive = false) { const startTime = Date.now(); const operationId = `rmdir-${path}-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "rmdir", path, id: operationId }); this.events.emit(FileSystemEvents.DIR_DELETING, { path, recursive }); try { await super.rmdir(path, recursive); this.events.emit(FileSystemEvents.DIR_DELETED, { path }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "rmdir", path, id: operationId, duration: Date.now() - startTime }); } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "rmdir", path, error }); throw error; } } async clear() { const startTime = Date.now(); const operationId = `clear-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "clear", id: operationId }); this.events.emit(FileSystemEvents.STORAGE_CLEARING, void 0); try { await super.clear(); const duration = Date.now() - startTime; this.events.emit(FileSystemEvents.STORAGE_CLEARED, { duration }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "clear", id: operationId, duration }); } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "clear", error }); throw error; } } async size() { const startTime = Date.now(); const operationId = `size-${startTime}`; this.events.emit(FileSystemEvents.OPERATION_START, { operation: "size", id: operationId }); try { const size = await super.size(); this.events.emit(FileSystemEvents.STORAGE_SIZE_CALCULATED, { size }); this.events.emit(FileSystemEvents.OPERATION_END, { operation: "size", id: operationId, duration: Date.now() - startTime }); return size; } catch (error) { this.events.emit(FileSystemEvents.OPERATION_ERROR, { operation: "size", error }); throw error; } } }; } // src/base/BaseFileSystem.ts var BaseFileSystem = class { // Implementações padrão dos novos métodos /** * Por padrão, permite modificação se o arquivo existe ou se pode ser criado */ async canModify(path) { try { const stat = await this.stat(path); return !stat.readonly; } catch { const parentPath = this.getParentPath(path); if (parentPath === "/") { return true; } return this.canCreateIn(parentPath); } } /** * Por padrão, permite criar se o diretório existe e não é readonly */ async canCreateIn(parentPath) { try { const stat = await this.stat(parentPath); return stat.type === "directory" && !stat.readonly; } catch { return false; } } /** * Implementação padrão de escrita atômica usando temp + rename */ async writeFileAtomic(path, content, metadata) { const normalizedPath = normalizePath(path); const tempPath = `${normalizedPath}.tmp${Date.now()}`; try { await this.writeFile(tempPath, content, metadata); if (await this.exists(normalizedPath)) { await this.deleteFile(normalizedPath); } return await this.rename(tempPath, normalizedPath); } catch (error) { try { await this.deleteFile(tempPath); } catch { } throw error; } } /** * Helper para extrair diretório pai */ getParentPath(path) { const normalized = normalizePath(path); const lastSlash = normalized.lastIndexOf("/"); return lastSlash <= 0 ? "/" : normalized.substring(0, lastSlash); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BaseFileSystem, EventEmitter, FileSystemEvents, TypedEventEmitter, basename, dirname, extname, isAbsolute, join, normalizePath, withEvents }); //# sourceMappingURL=index.cjs.map