import type { Config } from "#/lib/config/types.ts"; import { configSchema } from "#/lib/config/types.zod.ts"; import { parse } from "jsr:@std/yaml"; import { debounce } from "jsr:@std/async/debounce"; export * from "#/lib/config/types.ts" export class ConfigLoader { private currentConfig: Config private path: string constructor(firstConfig: Config, path:string) { this.path = path this.currentConfig = firstConfig const run = debounce(async (e: Deno.FsEvent)=>{ console.log("config file hmr", e); const fileText = await Deno.readTextFile(path) const parsed = parse(fileText) return [await configSchema.parseAsync(parsed), path] }, 250) const watch = async ()=>{ const watcher = Deno.watchFs(path) for await (const event of watcher) { if(event.kind === "remove") { return } run(event) } } watch() } static async New(...paths: string[]) { const [config, configPath] = await this.firstLoad(paths) return new ConfigLoader(config, configPath) } config(): Config { return this.currentConfig } static async firstLoad(paths: string[]): Promise<[Config, string]>{ const errs = [] for (const path of paths) { let fileText:string try { fileText = await Deno.readTextFile(path) } catch (e) { errs.push(e) console.error(`Failed to load config from ${path}: ${e}`) continue } const parsed = parse(fileText) return [await configSchema.parseAsync(parsed), path] } throw new AggregateError(errs) } }