doorgan/lib/config/index.ts

58 lines
1.6 KiB
TypeScript

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)
}
}