Merge pull request #3 from PR0M3TH3AN/codex/add-configuration-loader-and-validation

Add config loader
This commit is contained in:
thePR0M3TH3AN
2025-07-10 10:24:49 -04:00
committed by GitHub
3 changed files with 76 additions and 2 deletions

View File

@@ -10,7 +10,8 @@
"@11ty/eleventy": "^2.0.1",
"gray-matter": "^4.0.3",
"marked": "^11.1.1",
"lunr": "^2.3.9"
"lunr": "^2.3.9",
"js-yaml": "^4.1.0"
},
"license": "MIT"
}

69
src/config/loadConfig.js Normal file
View File

@@ -0,0 +1,69 @@
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
function deepMerge(target, source) {
for (const key of Object.keys(source)) {
if (
source[key] &&
typeof source[key] === 'object' &&
!Array.isArray(source[key])
) {
target[key] = deepMerge(target[key] || {}, source[key]);
} else if (source[key] !== undefined) {
target[key] = source[key];
}
}
return target;
}
function loadConfig(configPath = path.join(process.cwd(), 'config.yaml')) {
let raw = {};
if (fs.existsSync(configPath)) {
try {
raw = yaml.load(fs.readFileSync(configPath, 'utf8')) || {};
} catch (e) {
console.error(`Failed to parse ${configPath}: ${e.message}`);
process.exit(1);
}
}
const defaults = {
site: {
title: 'DocForge',
description: '',
logo: '',
favicon: ''
},
navigation: {
search: true
},
footer: {},
theme: {
name: 'minimal',
darkMode: false
},
features: {},
plugins: []
};
const config = deepMerge(defaults, raw);
const errors = [];
if (
!config.site ||
typeof config.site.title !== 'string' ||
!config.site.title.trim()
) {
errors.push('site.title is required in config.yaml');
}
if (errors.length) {
errors.forEach(err => console.error(`Config error: ${err}`));
process.exit(1);
}
return config;
}
module.exports = loadConfig;

View File

@@ -3,6 +3,7 @@ const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');
const Eleventy = require('@11ty/eleventy');
const loadConfig = require('../config/loadConfig');
async function readDirRecursive(dir) {
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
@@ -50,7 +51,8 @@ function buildNav(pages) {
return tree.children || [];
}
async function generate({ contentDir = 'content', outputDir = '_site' } = {}) {
async function generate({ contentDir = 'content', outputDir = '_site', configPath } = {}) {
const config = loadConfig(configPath);
if (!fs.existsSync(contentDir)) {
console.error(`Content directory not found: ${contentDir}`);
return;
@@ -82,6 +84,7 @@ async function generate({ contentDir = 'content', outputDir = '_site' } = {}) {
const nav = buildNav(pages);
await fs.promises.mkdir(outputDir, { recursive: true });
await fs.promises.writeFile(path.join(outputDir, 'navigation.json'), JSON.stringify(nav, null, 2));
await fs.promises.writeFile(path.join(outputDir, 'config.json'), JSON.stringify(config, null, 2));
const elev = new Eleventy(contentDir, outputDir);
elev.setConfig({
@@ -93,6 +96,7 @@ async function generate({ contentDir = 'content', outputDir = '_site' } = {}) {
});
elev.configFunction = function(eleventyConfig) {
eleventyConfig.addGlobalData('navigation', nav);
eleventyConfig.addGlobalData('config', config);
};
await elev.write();