import { Stats, type OpenMode } from 'node:fs'; import * as Node from 'node:fs/promises'; export type FileStats = Stats export class FileHandle { private path: string constructor( path: string ) { this.path = path } public async text(encoding?: BufferEncoding) { if (!encoding) { encoding = "utf-8" } const fileContent = await Node.readFile(this.path, {encoding: encoding}) return fileContent } public async write(text: string, append?: boolean) { if (!append) { append = true } const flag : OpenMode = append ? "a+" : "w" await Node.writeFile(this.path, text, {flag: flag}) } public async lastChange() { const stats = await Node.stat(this.path) return stats.mtime } public async getStats() { const stats = await Node.stat(this.path) return stats } } /** * Checks if the file exists * * @param path `string` path for the file * @returns if the file is readable */ export async function doesFileExist(path: string): Promise { try { await Node.access(path) } catch { return false } return true } export async function loadFile(path: string, create?: boolean): Promise { const DEFAULT_MODE = 0o600 // Safe to use // worst case: create = false -> create = false if (!create) { create = false } let fd : Node.FileHandle | null = null try { fd = await Node.open(path, "r+", DEFAULT_MODE) } catch { } // We have a FD, return it if (fd) { await fd.close() return new FileHandle(path) } if (!create) { // UGLY: make more specific throw new Error("The required file does not exist") } // We do want this to throw without catching here fd = await Node.open(path, "w", DEFAULT_MODE) await fd.close() return new FileHandle(path) }