#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const json5 = require('json5'); const [srcFile, destFile] = process.argv.slice(2); if (!srcFile || !destFile) { console.error('Usage: merge-config.js '); process.exit(1); } function deepMerge(target, source) { for (const key of Object.keys(source)) { if (!(key in target)) { target[key] = source[key]; } else if (typeof source[key] === 'object' && !Array.isArray(source[key]) && typeof target[key] === 'object' && !Array.isArray(target[key])) { deepMerge(target[key], source[key]); } } return target; } function getTargetName(exampleFile) { let name = exampleFile.replace(/\.example$/, ''); const ext = path.extname(name); if (!ext || ext === '.example') { name += '.json'; } return name; } const srcContent = fs.readFileSync(srcFile, 'utf8'); let srcData; try { srcData = json5.parse(srcContent); } catch (e) { console.error(`--> [SKIP] Could not parse ${srcFile}: ${e.message}`); process.exit(0); } if (typeof srcData !== 'object' || Array.isArray(srcData)) { console.error(`--> [SKIP] ${srcFile} is not a JSON object, copying directly`); fs.copyFileSync(srcFile, destFile); process.exit(0); } let destData = {}; let existingKeys = []; if (fs.existsSync(destFile)) { try { const destContent = fs.readFileSync(destFile, 'utf8'); destData = json5.parse(destContent); existingKeys = Object.keys(destData); } catch (e) { console.error(`--> Warning: could not parse ${destFile}, overwriting from example`); } } const merged = deepMerge(destData, srcData); const newKeys = Object.keys(merged).filter(k => !existingKeys.includes(k)); if (newKeys.length > 0) { console.log(`--> Added ${newKeys.length} new key(s) to ${path.basename(destFile)}`); } fs.writeFileSync(destFile, JSON.stringify(merged, null, 4) + '\n'); console.log(`--> [OK] ${path.basename(destFile)} is up to date`);