feat(config): add default configuration path resolver and merge missing feature flags

This commit is contained in:
MasterAcnolo
2026-10-28 21:40:13 +01:00
parent 634108784e
commit 650696b9f5

View File

@@ -57,6 +57,40 @@ function resolveConfigPath() {
*/ */
const featuresPath = resolveConfigPath(); const featuresPath = resolveConfigPath();
/**
* Resolves the bundled default configuration path.
*
* @returns {string} Absolute path to the default configuration file
*/
function getDefaultConfigPath() {
return devMode
? path.join(__dirname, "config", "config.default.json")
: path.join(process.resourcesPath, "config", "config.default.json");
}
/**
* Adds missing default feature flags without overwriting user settings.
*
* Unknown user-defined keys are intentionally preserved.
*
* @param {Object} defaults - Default feature flags
* @param {Object} current - User feature flags
* @returns {{features: Object, changed: boolean}} Merged features and migration state
*/
function mergeMissingFeatures(defaults, current) {
if (!defaults || typeof defaults !== "object" || Array.isArray(defaults)) {
throw new Error("Default configuration must be a JSON object");
}
if (!current || typeof current !== "object" || Array.isArray(current)) {
throw new Error("User configuration must be a JSON object");
}
const features = { ...defaults, ...current };
const changed = Object.keys(defaults).some((key) => !Object.prototype.hasOwnProperty.call(current, key));
return { features, changed };
}
/** /**
* Loads and parses the feature configuration file. * Loads and parses the feature configuration file.
* *
@@ -64,8 +98,15 @@ const featuresPath = resolveConfigPath();
* @throws {Error} If the configuration file is missing or invalid * @throws {Error} If the configuration file is missing or invalid
*/ */
function loadFeatures() { function loadFeatures() {
const raw = fs.readFileSync(featuresPath, "utf-8"); const defaults = JSON.parse(fs.readFileSync(getDefaultConfigPath(), "utf-8"));
return JSON.parse(raw); const current = JSON.parse(fs.readFileSync(featuresPath, "utf-8"));
const { features, changed } = mergeMissingFeatures(defaults, current);
if (changed) {
fs.writeFileSync(featuresPath, JSON.stringify(features, null, 2), "utf-8");
}
return features;
} }
/** /**
@@ -77,8 +118,7 @@ function loadFeatures() {
*/ */
function reloadFeatures() { function reloadFeatures() {
try { try {
const raw = fs.readFileSync(featuresPath, "utf-8"); return loadFeatures();
return JSON.parse(raw);
} catch (err) { } catch (err) {
// Fallback to cached snapshot if file read fails // Fallback to cached snapshot if file read fails
return configFeatures; return configFeatures;
@@ -128,4 +168,9 @@ module.exports = {
* Path to the active configuration file * Path to the active configuration file
*/ */
featuresPath, featuresPath,
/**
* Merges missing default feature flags into user configuration without overwriting existing settings.
*/
mergeMissingFeatures,
}; };