diff --git a/src/util/config.ts b/src/util/config.ts index a015fe1..df48126 100644 --- a/src/util/config.ts +++ b/src/util/config.ts @@ -1,13 +1,73 @@ -import YAML from "yaml"; -import fs from "fs"; +import { existsSync, readFileSync, writeFileSync } from "fs"; +import { parse, stringify } from "yaml"; +import { z } from "zod"; -export function loadConfig(filepath: string, def: T) { - try { - const data = fs.readFileSync(filepath).toString(); - const parsed = YAML.parse(data); - return parsed as T; - } catch (err) { - console.error("Unable to load config:", err); - return def; +/** + * Load a YAML config file and set default values if config path is nonexistent + * + * Usage: + * ```ts + * const config = loadConfig("config/services.yml", { + * enableMPP: false + * }); + * ``` + * @param configPath Path to load config from + * @param defaultConfig Config to use if none is present (will save to path if used) + * @returns Parsed YAML config + */ +export function loadConfig(configPath: string, defaultConfig: T): T { + // Config exists? + if (existsSync(configPath)) { + // Load config + const data = readFileSync(configPath); + const config = parse(data.toString()); + + const defRecord = defaultConfig as Record; + let changed = false; + + function mix( + obj: Record, + obj2: Record + ) { + for (const key of Object.keys(obj2)) { + if (typeof obj[key] == "undefined") { + obj[key] = obj2[key]; + changed = true; + } + + if (typeof obj[key] == "object" && !Array.isArray(obj[key])) { + mix( + obj[key] as Record, + obj2[key] as Record + ); + } + } + } + + // Apply any missing default values + mix(config, defRecord); + + // Save config if modified + if (changed) writeConfig(configPath, config); + + return config as T; + } else { + // Write default config to disk and use that + writeConfig(configPath, defaultConfig); + return defaultConfig as T; } } + +/** + * Write a YAML config to disk + * @param configPath + * @param config + */ +export function writeConfig(configPath: string, config: T) { + writeFileSync( + configPath, + stringify(config, { + indent: 4 + }) + ); +}