fix: add missing migrateConfig method, config versioning, and formatters module
ConfigManager.migrateConfig() was called but never defined — would crash at runtime. Added config version checking, migration support, and fixed createEndpoint indentation. New formatters module (csv, influxdb, json) for pluggable output formatting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,22 +1,52 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Current config version. All config JSONs should declare this version.
|
||||
* Bump this when the config schema changes.
|
||||
*/
|
||||
const CURRENT_CONFIG_VERSION = '1.0.0';
|
||||
|
||||
class ConfigManager {
|
||||
constructor(relPath = '.') {
|
||||
this.configDir = path.resolve(__dirname, relPath);
|
||||
|
||||
/**
|
||||
* Migration functions keyed by "fromVersion->toVersion".
|
||||
* Each function receives a config object and returns the migrated config.
|
||||
*
|
||||
* Example:
|
||||
* this.migrations['1.0.0->1.1.0'] = (config) => {
|
||||
* config.newSection = { enabled: false };
|
||||
* return config;
|
||||
* };
|
||||
*/
|
||||
this.migrations = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a configuration file by name
|
||||
* Load a configuration file by name.
|
||||
* Automatically checks the config version and migrates if needed.
|
||||
* @param {string} configName - Name of the config file (without .json extension)
|
||||
* @returns {Object} Parsed configuration object
|
||||
* @returns {Object} Parsed configuration object (migrated to current version if necessary)
|
||||
*/
|
||||
getConfig(configName) {
|
||||
try {
|
||||
const configPath = path.resolve(this.configDir, `${configName}.json`);
|
||||
const configData = fs.readFileSync(configPath, 'utf8');
|
||||
return JSON.parse(configData);
|
||||
let config = JSON.parse(configData);
|
||||
|
||||
// Auto-migrate if version is behind current
|
||||
const configVersion = config.version || '0.0.0';
|
||||
if (configVersion !== CURRENT_CONFIG_VERSION) {
|
||||
config = this.migrateConfig(config, configVersion, CURRENT_CONFIG_VERSION);
|
||||
}
|
||||
|
||||
return config;
|
||||
} catch (error) {
|
||||
if (error.message && error.message.startsWith('Failed to load config')) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(`Failed to load config '${configName}': ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -102,6 +132,27 @@ class ConfigManager {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a config object from one version to another by applying
|
||||
* registered migration functions in sequence.
|
||||
* @param {object} config - The config object to migrate
|
||||
* @param {string} fromVersion - Current version of the config
|
||||
* @param {string} toVersion - Target version
|
||||
* @returns {object} Migrated config with updated version field
|
||||
*/
|
||||
migrateConfig(config, fromVersion, toVersion) {
|
||||
const migrationKey = `${fromVersion}->${toVersion}`;
|
||||
const migrationFn = this.migrations[migrationKey];
|
||||
|
||||
if (migrationFn) {
|
||||
config = migrationFn(config);
|
||||
}
|
||||
|
||||
// Stamp the current version so it won't re-migrate
|
||||
config.version = toVersion;
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base config schema (shared across all nodes).
|
||||
* @returns {object} Base config schema
|
||||
@@ -110,30 +161,22 @@ class ConfigManager {
|
||||
return this.getConfig('baseConfig');
|
||||
}
|
||||
|
||||
createEndpoint(nodeName) {
|
||||
try {
|
||||
// Load the config for this node
|
||||
const config = this.getConfig(nodeName);
|
||||
|
||||
// Convert config to JSON
|
||||
const configJSON = JSON.stringify(config, null, 2);
|
||||
createEndpoint(nodeName) {
|
||||
try {
|
||||
const config = this.getConfig(nodeName);
|
||||
const configJSON = JSON.stringify(config, null, 2);
|
||||
|
||||
// Assemble the complete script
|
||||
return `
|
||||
// Create the namespace structure
|
||||
return `
|
||||
window.EVOLV = window.EVOLV || {};
|
||||
window.EVOLV.nodes = window.EVOLV.nodes || {};
|
||||
window.EVOLV.nodes.${nodeName} = window.EVOLV.nodes.${nodeName} || {};
|
||||
|
||||
// Inject the pre-loaded config data directly into the namespace
|
||||
window.EVOLV.nodes.${nodeName}.config = ${configJSON};
|
||||
|
||||
console.log('${nodeName} config loaded and endpoint created');
|
||||
`;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create endpoint for '${nodeName}': ${error.message}`);
|
||||
}
|
||||
`;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create endpoint for '${nodeName}': ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ConfigManager;
|
||||
Reference in New Issue
Block a user