const fs = require('fs'); const yaml = require('js-yaml'); const path = require('path'); // HTML转义函数,防止XSS攻击 function escapeHtml(unsafe) { if (unsafe === undefined || unsafe === null) { return ''; } return String(unsafe) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** * 加载单个配置文件 * @param {string} filePath 配置文件路径 * @returns {Object|null} 配置对象,如果文件不存在或加载失败则返回null */ function loadSingleConfig(filePath) { if (fs.existsSync(filePath)) { try { const fileContent = fs.readFileSync(filePath, 'utf8'); const fileConfig = yaml.load(fileContent); console.log(`Loaded configuration from ${filePath}`); return fileConfig; } catch (e) { console.error(`Error loading configuration from ${filePath}:`, e); return null; } } return null; } /** * 加载模块化配置目录 * @param {string} dirPath 配置目录路径 * @returns {Object|null} 配置对象,如果目录不存在或加载失败则返回null */ function loadModularConfig(dirPath) { if (!fs.existsSync(dirPath)) { return null; } const config = { site: {}, navigation: [], fonts: {}, profile: {}, social: [], categories: [] }; // 加载基础配置 const siteConfigPath = path.join(dirPath, 'site.yml'); if (fs.existsSync(siteConfigPath)) { try { const fileContent = fs.readFileSync(siteConfigPath, 'utf8'); const siteConfig = yaml.load(fileContent); // 将site.yml中的内容分配到正确的配置字段 config.site = siteConfig; // 提取特殊字段到顶层配置 if (siteConfig.fonts) config.fonts = siteConfig.fonts; if (siteConfig.profile) config.profile = siteConfig.profile; if (siteConfig.social) config.social = siteConfig.social; console.log(`Loaded site configuration from ${siteConfigPath}`); } catch (e) { console.error(`Error loading site configuration from ${siteConfigPath}:`, e); } } const navConfigPath = path.join(dirPath, 'navigation.yml'); if (fs.existsSync(navConfigPath)) { try { const fileContent = fs.readFileSync(navConfigPath, 'utf8'); config.navigation = yaml.load(fileContent); console.log(`Loaded navigation configuration from ${navConfigPath}`); } catch (e) { console.error(`Error loading navigation configuration from ${navConfigPath}:`, e); } } // 加载页面配置 const pagesPath = path.join(dirPath, 'pages'); if (fs.existsSync(pagesPath)) { const files = fs.readdirSync(pagesPath).filter(file => file.endsWith('.yml') || file.endsWith('.yaml')); files.forEach(file => { try { const filePath = path.join(pagesPath, file); const fileContent = fs.readFileSync(filePath, 'utf8'); const fileConfig = yaml.load(fileContent); // 提取文件名(不含扩展名)作为配置键 const configKey = path.basename(file, path.extname(file)); // 特殊处理home.yml中的categories字段 if (configKey === 'home' && fileConfig.categories) { config.categories = fileConfig.categories; } // 将页面配置添加到主配置对象 config[configKey] = fileConfig; console.log(`Loaded page configuration from ${filePath}`); } catch (e) { console.error(`Error loading page configuration from ${path.join(pagesPath, file)}:`, e); } }); } return config; } // 读取配置文件 function loadConfig() { // 初始化空配置对象 let config = { site: {}, navigation: [], fonts: {}, profile: {}, social: [], categories: [] }; // 检查所有可能的配置来源是否存在 const hasUserModularConfig = fs.existsSync('config/user'); const hasUserLegacyConfig = fs.existsSync('config.user.yml'); const hasDefaultModularConfig = fs.existsSync('config/_default'); const hasDefaultLegacyConfig = fs.existsSync('config.yml'); // 根据优先级顺序选择最高优先级的配置 if (hasUserModularConfig) { // 1. 最高优先级: config/user/ 目录 console.log('Using modular user configuration from config/user/ (highest priority)'); config = loadModularConfig('config/user'); } else if (hasUserLegacyConfig) { // 2. 次高优先级: config.user.yml (传统用户配置) console.log('Using legacy user configuration from config.user.yml'); const userConfigFile = fs.readFileSync('config.user.yml', 'utf8'); config = yaml.load(userConfigFile); } else if (hasDefaultModularConfig) { // 3. 其次优先级: config/_default/ 目录 console.log('Using modular default configuration from config/_default/'); // 从模块化默认配置加载 config = loadModularConfig('config/_default'); // 检查并加载home.yml中的categories(如果loadModularConfig未正确处理) const homePath = path.join('config', '_default', 'pages', 'home.yml'); if (fs.existsSync(homePath) && (!config.categories || config.categories.length === 0)) { try { const homeContent = fs.readFileSync(homePath, 'utf8'); const homeConfig = yaml.load(homeContent); if (homeConfig && homeConfig.categories) { // 直接设置categories config.categories = homeConfig.categories; // 确保home配置也正确设置 if (!config.home) { config.home = homeConfig; } } } catch (e) { console.error(`Error loading home.yml: ${e.message}`); } } } else if (hasDefaultLegacyConfig) { // 4. 最低优先级: config.yml (传统默认配置) console.log('Using legacy default config.yml'); const defaultConfigFile = fs.readFileSync('config.yml', 'utf8'); config = yaml.load(defaultConfigFile); } else { console.log('No configuration found, using default empty config'); } // 确保配置具有必要的结构 config.site = config.site || {}; config.navigation = config.navigation || []; config.fonts = config.fonts || {}; config.profile = config.profile || {}; config.social = config.social || []; config.categories = config.categories || []; // 处理书签文件(保持现有功能,但使用新逻辑) try { let bookmarksConfig = null; let bookmarksSource = null; // 按照相同的优先级顺序处理书签配置 // 1. 模块化用户书签配置 (最高优先级) if (fs.existsSync('config/user/pages/bookmarks.yml')) { const userBookmarksFile = fs.readFileSync('config/user/pages/bookmarks.yml', 'utf8'); bookmarksConfig = yaml.load(userBookmarksFile); bookmarksSource = 'config/user/pages/bookmarks.yml'; } // 2. 传统用户书签配置 else if (fs.existsSync('bookmarks.user.yml')) { const userBookmarksFile = fs.readFileSync('bookmarks.user.yml', 'utf8'); bookmarksConfig = yaml.load(userBookmarksFile); bookmarksSource = 'bookmarks.user.yml'; } // 3. 模块化默认书签配置 else if (fs.existsSync('config/_default/pages/bookmarks.yml')) { const defaultBookmarksFile = fs.readFileSync('config/_default/pages/bookmarks.yml', 'utf8'); bookmarksConfig = yaml.load(defaultBookmarksFile); bookmarksSource = 'config/_default/pages/bookmarks.yml'; } // 4. 传统默认书签配置 (最低优先级) else if (fs.existsSync('bookmarks.yml')) { const bookmarksFile = fs.readFileSync('bookmarks.yml', 'utf8'); bookmarksConfig = yaml.load(bookmarksFile); bookmarksSource = 'bookmarks.yml'; } // 添加书签页面配置 if (bookmarksConfig) { config.bookmarks = bookmarksConfig; console.log(`Using bookmarks configuration from ${bookmarksSource}`); // 移除自动添加书签页面到导航的逻辑 } } catch (e) { console.error('Error loading bookmarks configuration:', e); } return config; } // 生成导航菜单 function generateNavigation(navigation, config) { return navigation.map(nav => { // 根据页面ID获取对应的子菜单项(分类) let submenuItems = ''; // 首页页面添加子菜单(分类) if (nav.id === 'home' && Array.isArray(config.categories)) { submenuItems = `
`; } // 书签页面添加子菜单(分类) else if (nav.id === 'bookmarks' && config.bookmarks && Array.isArray(config.bookmarks.categories)) { submenuItems = ` `; } // 项目页面添加子菜单 else if (nav.id === 'projects' && config.projects && Array.isArray(config.projects.categories)) { submenuItems = ` `; } // 文章页面添加子菜单 else if (nav.id === 'articles' && config.articles && Array.isArray(config.articles.categories)) { submenuItems = ` `; } // 友链页面添加子菜单 else if (nav.id === 'friends' && config.friends && Array.isArray(config.friends.categories)) { submenuItems = ` `; } // 通用处理:任意自定义页面的子菜单生成 else if (config[nav.id] && config[nav.id].categories && Array.isArray(config[nav.id].categories)) { submenuItems = ` `; } return ` `; }).join('\n'); } // 生成网站卡片HTML function generateSiteCards(sites) { if (!sites || !Array.isArray(sites) || sites.length === 0) { return `暂无网站
`; } return sites.map(site => `${escapeHtml(site.description || '')}
`).join('\n'); } // 生成分类板块 function generateCategories(categories) { if (!categories || !Array.isArray(categories) || categories.length === 0) { return `请在配置文件中添加分类
${escapeHtml(profile.description || '快速访问您的常用网站')}
请配置 ${pageId} 页面
${escapeHtml(subtitle)}
${escapeHtml(subtitle)}
在所有页面中找到的匹配项
请配置 ${pageId} 页面