2023-10-25 06:00:59 +02:00
|
|
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
|
|
import { parse, stringify } from "yaml";
|
|
|
|
import { z } from "zod";
|
|
|
|
|
2024-01-31 11:09:25 +01:00
|
|
|
/**
|
|
|
|
* This file uses the synchronous functions from the fs
|
|
|
|
* module because these functions should only be used
|
|
|
|
* to load configs at the beginning of runtime
|
|
|
|
*
|
|
|
|
* Hint: This means you shouldn't load configs in the
|
|
|
|
* middle of doing other shit, only when you start the
|
|
|
|
* program.
|
|
|
|
*/
|
|
|
|
|
2023-10-25 06:00:59 +02:00
|
|
|
/**
|
|
|
|
* 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<T>(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<string, any>;
|
|
|
|
let changed = false;
|
|
|
|
|
|
|
|
function mix(
|
|
|
|
obj: Record<string, unknown>,
|
|
|
|
obj2: Record<string, unknown>
|
|
|
|
) {
|
|
|
|
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<string, unknown>,
|
|
|
|
obj2[key] as Record<string, unknown>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2023-09-07 01:27:56 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-25 06:00:59 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Write a YAML config to disk
|
|
|
|
* @param configPath
|
|
|
|
* @param config
|
|
|
|
*/
|
|
|
|
export function writeConfig<T>(configPath: string, config: T) {
|
2024-01-31 11:09:25 +01:00
|
|
|
// Write config to disk unconditionally
|
2023-10-25 06:00:59 +02:00
|
|
|
writeFileSync(
|
|
|
|
configPath,
|
|
|
|
stringify(config, {
|
|
|
|
indent: 4
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|