From ccbd200464f1ee5f3e59de1f42e809093c04792c Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jun 2026 16:38:48 +0200 Subject: [PATCH] feat: auto-merge all Nitro config .example files with missing key detection --- package.json | 1 + scripts/merge-config.cjs | 69 ++++++++++++++++++++++++++++++++++++++++ update-Nitrov3.sh | 30 ++++++++--------- yarn.lock | 5 +++ 4 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 scripts/merge-config.cjs diff --git a/package.json b/package.json index ab7642e..bbee6f7 100755 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@inertiajs/react": "^3.2.0", "@vitejs/plugin-react": "^6.0.2", "flowbite": "2.5.2", + "json5": "^2.2.3", "react": "^19.2.6", "react-dom": "^19.2.6", "sass": "1.83.4", diff --git a/scripts/merge-config.cjs b/scripts/merge-config.cjs new file mode 100644 index 0000000..958de08 --- /dev/null +++ b/scripts/merge-config.cjs @@ -0,0 +1,69 @@ +#!/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`); diff --git a/update-Nitrov3.sh b/update-Nitrov3.sh index 13f5263..ae38505 100755 --- a/update-Nitrov3.sh +++ b/update-Nitrov3.sh @@ -134,23 +134,21 @@ yarn build echo "--> Synchronizing Gamedata configurations..." mkdir -p "$GAMEDATA_CONF_DIR" -# --- Renderer Config Sync (always from latest example) --- -if [ -f "$NITRO_SRC_DIR/renderer-config.example" ]; then - echo "--> Updating renderer-config.json from latest example..." - cp "$NITRO_SRC_DIR/renderer-config.example" "$GAMEDATA_CONF_DIR/renderer-config.json" -fi +MERGE_SCRIPT="$(dirname "$0")/scripts/merge-config.cjs" -# --- UI Config Sync (always from latest example) --- -if [ -f "$NITRO_SRC_DIR/ui-config.json.example" ]; then - echo "--> Updating ui-config.json from latest example..." - cp "$NITRO_SRC_DIR/ui-config.json.example" "$GAMEDATA_CONF_DIR/ui-config.json" -fi - -# --- UITexts Sync (always from latest example) --- -if [ -f "$NITRO_SRC_DIR/UITexts.json5.example" ]; then - echo "--> Updating UITexts.json5 from latest example..." - cp "$NITRO_SRC_DIR/UITexts.json5.example" "$GAMEDATA_CONF_DIR/UITexts.json5" -fi +echo "--> Merging Nitro config examples into Gamedata/config..." +for example_file in "$NITRO_SRC_DIR"/*.example; do + [ -f "$example_file" ] || continue + base=$(basename "$example_file") + target_name="${base%.example}" + case "$target_name" in + *.*) ;; # already has extension (e.g., .json, .json5) + *) target_name="$target_name.json" ;; # no extension -> add .json + esac + target_path="$GAMEDATA_CONF_DIR/$target_name" + echo "--> Processing $base -> $target_name..." + node "$MERGE_SCRIPT" "$example_file" "$target_path" +done # ---------------------------------------- diff --git a/yarn.lock b/yarn.lock index 95b14ce..5c99fd2 100755 --- a/yarn.lock +++ b/yarn.lock @@ -2195,6 +2195,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + keyv@^4.5.4: version "4.5.4" resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"