UNPKG

protoobject

Version:

A universal class for creating any JSON objects and simple manipulations with them.

391 lines 15.9 kB
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) { if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); }; import { promises as fs, createReadStream, createWriteStream, watch, } from "node:fs"; import { join, dirname, extname } from "node:path"; import { EventEmitter } from "node:events"; import { ProtoObject } from "./proto-object.js"; import { StaticImplements } from "../decorators/static-implements.js"; /* eslint-disable no-unused-vars */ /** * File operation types */ export var FileOperationType; (function (FileOperationType) { FileOperationType["SAVE"] = "SAVE"; FileOperationType["LOAD"] = "LOAD"; FileOperationType["DELETE"] = "DELETE"; FileOperationType["WATCH"] = "WATCH"; })(FileOperationType || (FileOperationType = {})); /** * File formats supported */ export var FileFormat; (function (FileFormat) { FileFormat["JSON"] = ".json"; FileFormat["CSV"] = ".csv"; FileFormat["TEXT"] = ".txt"; })(FileFormat || (FileFormat = {})); /* eslint-enable no-unused-vars */ /** * File system watcher for ProtoObject files */ export class ProtoObjectFileWatcher extends EventEmitter { constructor() { super(...arguments); this.watchers = new Map(); } /** * Watch a file for changes */ watchFile(filePath) { if (this.watchers.has(filePath)) { return; // Already watching } const watcher = watch(filePath, (eventType, filename) => { this.emit("fileChanged", { filePath, eventType, filename, timestamp: new Date(), }); }); this.watchers.set(filePath, watcher); } /** * Stop watching a file */ unwatchFile(filePath) { const watcher = this.watchers.get(filePath); if (watcher) { watcher.close(); this.watchers.delete(filePath); } } /** * Stop watching all files */ unwatchAll() { this.watchers.forEach((watcher) => watcher.close()); this.watchers.clear(); } } /** * Base class for File System enabled ProtoObjects */ let ProtoObjectFS = (() => { let _classDecorators = [StaticImplements()]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = ProtoObject; var ProtoObjectFS = _classThis = class extends _classSuper { constructor(data) { super(data); } /** * Save object to file */ async saveToFile(filePath, format = FileFormat.JSON) { try { // Ensure directory exists await fs.mkdir(dirname(filePath), { recursive: true }); let content; switch (format) { case FileFormat.JSON: content = JSON.stringify(this.toJSON(), null, 2); break; case FileFormat.CSV: content = this.toCSV(); break; case FileFormat.TEXT: content = this.toString(); break; default: throw new Error(`Unsupported format: ${format}`); } await fs.writeFile(filePath, content, "utf8"); return { success: true, operation: FileOperationType.SAVE, filePath, }; } catch (error) { return { success: false, operation: FileOperationType.SAVE, filePath, error: error, }; } } /** * Load object from file */ static async loadFromFile(filePath) { try { const content = await fs.readFile(filePath, "utf8"); const format = extname(filePath); switch (format) { case FileFormat.JSON: { const data = JSON.parse(content); return this.fromJSON(data); } case FileFormat.CSV: throw new Error("CSV loading not implemented yet"); case FileFormat.TEXT: throw new Error("Text loading not implemented yet"); default: throw new Error(`Unsupported format: ${format}`); } } catch (error) { throw new Error(`Failed to load from file ${filePath}: ${error}`); } } /** * Load multiple objects from directory */ static async loadManyFromDirectory(directoryPath, pattern = "*.json") { try { const files = await fs.readdir(directoryPath); const jsonFiles = files.filter((file) => { if (pattern === "*.json") return file.endsWith(".json"); if (pattern === "*.csv") return file.endsWith(".csv"); return true; }); const objects = []; for (const file of jsonFiles) { try { const object = await this.loadFromFile(join(directoryPath, file)); objects.push(object); } catch (error) { console.error(`Error loading ${file}:`, error); } } return objects; } catch (error) { throw new Error(`Failed to load from directory ${directoryPath}: ${error}`); } } /** * Delete file */ async deleteFile(filePath) { try { await fs.unlink(filePath); return { success: true, operation: FileOperationType.DELETE, filePath, }; } catch (error) { return { success: false, operation: FileOperationType.DELETE, filePath, error: error, }; } } /** * Save multiple objects to directory */ /* eslint-disable no-unused-vars */ static async saveManyToDirectory(objects, directoryPath, fileNameGenerator = (obj, i) => `object_${i}.json`) { /* eslint-enable no-unused-vars */ const results = []; // Ensure directory exists await fs.mkdir(directoryPath, { recursive: true }); for (let i = 0; i < objects.length; i++) { const obj = objects[i]; const fileName = fileNameGenerator(obj, i); const filePath = join(directoryPath, fileName); const result = await obj.saveToFile(filePath); results.push(result); } return results; } /** * Convert to CSV format */ toCSV(fieldMapping) { const data = this.toJSON(); const fields = fieldMapping ? Object.keys(fieldMapping) : Object.keys(data); // Header const headers = fields.map((field) => fieldMapping ? fieldMapping[field] : field); // Values const values = fields.map((field) => { const value = data[field]; if (value === null || value === undefined) return ""; if (typeof value === "string" && value.includes(",")) { return `"${value.replace(/"/g, '""')}"`; } return String(value); }); return `${headers.join(",")}\n${values.join(",")}`; } /** * Batch save with streaming for large datasets */ static async saveManyToFileStream(objects, filePath, format = FileFormat.JSON) { try { // Ensure directory exists await fs.mkdir(dirname(filePath), { recursive: true }); const writeStream = createWriteStream(filePath); if (format === FileFormat.JSON) { writeStream.write("[\n"); for (let i = 0; i < objects.length; i++) { const obj = objects[i]; const json = JSON.stringify(obj.toJSON(), null, 2); if (i > 0) writeStream.write(",\n"); writeStream.write(json); } writeStream.write("\n]"); } else if (format === FileFormat.CSV) { // Write CSV header if (objects.length > 0) { const headers = Object.keys(objects[0].toJSON()).join(","); writeStream.write(headers + "\n"); for (const obj of objects) { const csvLine = obj.toCSV(); const values = csvLine.split("\n")[1]; // Get only values, skip header writeStream.write(values + "\n"); } } } writeStream.end(); return new Promise((resolve, reject) => { writeStream.on("finish", () => { resolve({ success: true, operation: FileOperationType.SAVE, filePath, }); }); writeStream.on("error", (error) => { reject({ success: false, operation: FileOperationType.SAVE, filePath, error, }); }); }); } catch (error) { return { success: false, operation: FileOperationType.SAVE, filePath, error: error, }; } } /** * Load large datasets with streaming */ /* eslint-disable no-unused-vars */ static async loadManyFromFileStream(filePath, callback) { /* eslint-enable no-unused-vars */ const readStream = createReadStream(filePath); let buffer = ""; return new Promise((resolve, reject) => { readStream.on("data", async (chunk) => { buffer += chunk.toString(); // Simple JSON array parsing (for demo purposes) if (buffer.includes("},{")) { const objects = buffer.split("},{"); buffer = objects.pop() || ""; // Keep the last incomplete object for (let objStr of objects) { try { // Fix JSON formatting if (!objStr.startsWith("{")) objStr = "{" + objStr; if (!objStr.endsWith("}")) objStr = objStr + "}"; const data = JSON.parse(objStr); const object = this.fromJSON(data); await callback(object); } catch (error) { console.error("Error parsing object:", error); } } } }); readStream.on("end", () => { resolve(); }); readStream.on("error", (error) => { reject(error); }); }); } /** * Create backup of object with timestamp */ async createBackup(backupDirectory) { const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); const className = this.constructor.name; const backupFileName = `${className}_backup_${timestamp}.json`; const backupPath = join(backupDirectory, backupFileName); return this.saveToFile(backupPath, FileFormat.JSON); } }; __setFunctionName(_classThis, "ProtoObjectFS"); (() => { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); ProtoObjectFS = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); __runInitializers(_classThis, _classExtraInitializers); })(); return ProtoObjectFS = _classThis; })(); export { ProtoObjectFS }; //# sourceMappingURL=proto-object-fs.js.map