diff --git a/src/routes/about.js b/src/routes/about.js deleted file mode 100644 index e5cc365..0000000 --- a/src/routes/about.js +++ /dev/null @@ -1,5 +0,0 @@ -// src/routes/about.js -const express = require("express"); -const router = express.Router(); - -module.exports = router; diff --git a/src/routes/docs.js b/src/routes/docs.js index a6de0bd..41b4d28 100644 --- a/src/routes/docs.js +++ b/src/routes/docs.js @@ -12,15 +12,16 @@ const docsDir = path.join(__dirname, "../../content/docs"); let docsCache = {}; // { [path]: { modules: {}, crossCuttingSummary: {} } } - async function loadDocFile(filePath) { if (docsCache[filePath]) return docsCache[filePath]; try { const fullPath = path.join(docsDir, filePath + ".yaml"); const fileContent = await fs.readFile(fullPath, "utf-8"); const parsed = yaml.load(fileContent); - const crossCuttingSummary = parsed.crossCuttingSummary || null; - delete parsed.crossCuttingSummary; + const crossCuttingSummary = parsed["Cross Cutting Summary"] || null; + console.log( + `Cross cutting summary: ${JSON.stringify(crossCuttingSummary, 0, 2)}` + ); docsCache[filePath] = { modules: parsed, crossCuttingSummary, @@ -31,33 +32,34 @@ return null; } } -function filterSecurityAndStabilityKeys(docResult) { - if (!docResult || !docResult.modules) { - return docResult; - } - const filteredModules = {}; +// function filterSecurityAndStabilityKeys(docResult) { +// if (!docResult || !docResult.modules) { +// return docResult; +// } - for (const [key, value] of Object.entries(docResult.modules)) { - // Skip modules whose keys start with 'securityAndStability:' - if (key.startsWith("securityAndStability:")) { - continue; - } +// const filteredModules = {}; - // For other modules, remove the securityAndStability property if it exists - if (value && typeof value === "object") { - const { securityAndStability, ...moduleWithoutSecurity } = value; - filteredModules[key] = moduleWithoutSecurity; - } else { - filteredModules[key] = value; - } - } +// for (const [key, value] of Object.entries(docResult.modules)) { +// // Skip modules whose keys start with 'securityAndStability:' +// if (key.startsWith("securityAndStability:")) { +// continue; +// } - return { - ...docResult, - modules: filteredModules, - }; -} +// // For other modules, remove the securityAndStability property if it exists +// if (value && typeof value === "object") { +// const { securityAndStability, ...moduleWithoutSecurity } = value; +// filteredModules[key] = moduleWithoutSecurity; +// } else { +// filteredModules[key] = value; +// } +// } + +// return { +// ...docResult, +// modules: filteredModules, +// }; +// } // Helper function to filter security from a single module function filterModuleSecurityKeys(moduleDoc) { @@ -69,7 +71,7 @@ return moduleWithoutSecurity; } // /docs/summary - aggregate crossCuttingSummary from all cached docs -router.get("/summary", async (req, res) => { +router.get("/summary", async (req, res, next) => { const summaries = []; const files = await fs.readdir(docsDir); const yamlFiles = files @@ -95,8 +97,8 @@ }); // /docs/:path - show all modules in a YAML file -router.get("/:path", async (req, res) => { - const { path: docPath } = req.params; +router.get("/:moduleType", async (req, res, next) => { + const { moduleType: docPath } = req.params; const doc = await loadDocFile(docPath); const context = await docsContext(req.isAuthenticated, { @@ -121,8 +123,8 @@ }); // /docs/:path/:module - show single module from YAML file -router.get("/:path/:module", async (req, res, next) => { - const { path: docPath, module } = req.params; +router.get("/:moduleType/:module", async (req, res, next) => { + const { moduleType: docPath, module } = req.params; const doc = await loadDocFile(docPath); if (!doc) return next(new HttpError("Documentation not found", 404)); const moduleDoc = doc.modules[module]; @@ -146,7 +148,7 @@ }); // /docs - list all doc files -router.get("/", async (req, res) => { +router.get("/", async (req, res, next) => { try { const files = await fs.readdir(docsDir); const yamlFiles = files diff --git a/src/services/sitemapService.js b/src/services/sitemapService.js index 7be050e..a32c462 100644 --- a/src/services/sitemapService.js +++ b/src/services/sitemapService.js @@ -4,6 +4,7 @@ const fs = require("fs").promises; const { getAllPosts } = require("../utils/postFileUtils"); const hash = require("../utils/hash"); +const yaml = require("js-yaml"); const glob = require("fast-glob"); const { qualifySitemapLinks } = require("../utils/qualifyLinks"); @@ -122,6 +123,47 @@ })); } + async getDocsEntries(filePath) { + const docsDir = path.resolve(__dirname, "../../content/docs"); + const files = await fs.readdir(docsDir); + const entries = []; + + for (const file of files) { + if (!file.endsWith(".yaml")) continue; + + const moduleType = file.replace(/\.yaml$/, ""); + const filePath = path.join(docsDir, file); + const raw = await fs.readFile(filePath, "utf8"); + const parsed = yaml.load(raw); + + // Parent entry: /docs/:moduleType + const parentEntry = { + loc: `/docs/${moduleType}`, + label: moduleType, // Use 'label' to match your JSON structure + changefreq: "monthly", + priority: 0.7, + children: [], + }; + + // For each module inside modules, create child entries + const modules = parsed || {}; + for (const [moduleKey, moduleData] of Object.entries(modules)) { + parentEntry.children.push({ + loc: `/docs/${moduleType}/${moduleKey}`, + label: (moduleData && moduleData.title) || moduleKey, // Use 'label' to match structure + changefreq: "monthly", + priority: 0.5, + }); + } + + entries.push(parentEntry); + console.log( + `Added docs entry: ${parentEntry.loc} with ${parentEntry.children.length} children` + ); + } + + return entries; + } injectPlaceholder(tree, key, items) { for (const node of tree) { if (Array.isArray(node.children)) { @@ -130,7 +172,10 @@ ); if (index !== -1) { - const placeholder = node.children[index]; + console.log( + `Found placeholder #inject:${key}, injecting ${items.length} items` + ); + // Replace the placeholder with the actual items node.children.splice(index, 1, ...items); return true; } @@ -142,6 +187,7 @@ } return false; } + async _loadStaticLayout() { try { const data = await fs.readFile(this.staticSitemapPath, "utf-8"); @@ -185,10 +231,12 @@ slug: tag.slug, count: tag.count, })); + const docsEntries = await this.getDocsEntries(); this.injectPlaceholder(staticPagesJsonTree, "pages", pageItems); this.injectPlaceholder(staticPagesJsonTree, "blog-posts", postItems); this.injectPlaceholder(staticPagesJsonTree, "tags", tagItems); + this.injectPlaceholder(staticPagesJsonTree, "docs", docsEntries); return qualifySitemapLinks(staticPagesJsonTree); } diff --git a/src/utils/generateDocsMenuModel.js b/src/utils/generateDocsMenuModel.js index a98dcf7..3420c9c 100644 --- a/src/utils/generateDocsMenuModel.js +++ b/src/utils/generateDocsMenuModel.js @@ -24,7 +24,7 @@ isActive: path === currentPath, modules: filteredModules.map(([modKey, modData]) => ({ name: modKey, - displayName: formatModuleName(modKey), + displayName: modKey, isActive: path === currentPath && modKey === currentModule, })), }; diff --git a/src/utils/hbsHelpers.js b/src/utils/hbsHelpers.js index 097eaf5..789c063 100644 --- a/src/utils/hbsHelpers.js +++ b/src/utils/hbsHelpers.js @@ -33,6 +33,17 @@ hbs.handlebars.registerHelper("isArray", function (value) { return Array.isArray(value); }); + hbs.handlebars.registerHelper( + "extractCrossCuttingSummary", + function (context) { + for (const key in context) { + if (key.replace(/\s+/g, "").toLowerCase() === "crosscuttingsummary") { + return context[key]; + } + } + return null; + } + ); } module.exports = { registerHelpers }; diff --git a/src/views/docs/path.handlebars b/src/views/docs/path.handlebars index d804338..f3aedf4 100644 --- a/src/views/docs/path.handlebars +++ b/src/views/docs/path.handlebars @@ -1,33 +1,32 @@
{{this}}
{{/if}} - {{/if}} - + {{/each}}