diff --git a/docusaurus-utils/sidebar/classifiers.js b/docusaurus-utils/sidebar/classifiers.js new file mode 100644 index 000000000..c43368e50 --- /dev/null +++ b/docusaurus-utils/sidebar/classifiers.js @@ -0,0 +1,50 @@ +const { + isIndexDocument, + getRFCOccurrenceMapKey +} = require("./helpers"); +const { isNumber } = require('./utils') + +// By convention, Docusaurus considers some docs are "indexes": +// - index.md +// - readme.md +// - /.md +// +// This function is the default implementation of this convention +// +// Those index docs produce a different behavior +// - Slugs do not end with a weird "/index" suffix +// - Auto-generated sidebar categories link to them as intro +const isCategoryIndex = (rfcOccurrenceMap) => ({ + fileName, + directories, + extension +}) => { + const isIndexByName = isIndexDocument(fileName, directories[0]); + const isRFCWithMultipleVersions = isVersionedRFC(fileName, directories, extension, rfcOccurrenceMap); + + return (isIndexByName || isRFCWithMultipleVersions) +} + +function isVersionedRFC(fileName, directories, extension, rfcOccurrenceMap) { + if (extension.toLowerCase() !== ".md") { + return false; + } + + if (!isNumber(directories[0])) { + return false; + } + + if (rfcOccurrenceMap) { + const key = getRFCOccurrenceMapKey(fileName, extension, directories.reverse().join("/")); + + if (rfcOccurrenceMap[key] >= 2) { + return true + } + } + + return false; +} + +module.exports = { + isCategoryIndex +} \ No newline at end of file diff --git a/docusaurus-utils/sidebar/generator.js b/docusaurus-utils/sidebar/generator.js index b487f8cfd..f9af7d39a 100644 --- a/docusaurus-utils/sidebar/generator.js +++ b/docusaurus-utils/sidebar/generator.js @@ -5,9 +5,15 @@ const { separateFoldersAndFilesOrder, orderAlphabeticallyAndByNumber } = require("./modifiers") +const { isCategoryIndex } = require("./classifiers") +const { rawDocsToRFCOccurrenceMap } = require("./helpers") async function sidebarItemsGenerator({defaultSidebarItemsGenerator, ...args}) { - const defaultSidebarItems = await defaultSidebarItemsGenerator(args); + const rfcOccurrenceMap = rawDocsToRFCOccurrenceMap(args.docs) + const defaultSidebarItems = await defaultSidebarItemsGenerator({ + ...args, + isCategoryIndex: isCategoryIndex(rfcOccurrenceMap) + }); /* We'll have multiple O(N) passes through the items depending on the reducer implementation, diff --git a/docusaurus-utils/sidebar/helpers.js b/docusaurus-utils/sidebar/helpers.js index b45c4caf9..56df611f9 100644 --- a/docusaurus-utils/sidebar/helpers.js +++ b/docusaurus-utils/sidebar/helpers.js @@ -1,3 +1,5 @@ +const path = require("path") + function isIndexDocument(documentId, parentDirectory) { if (!documentId) { return false @@ -10,6 +12,41 @@ function isIndexDocument(documentId, parentDirectory) { ) } +function rawDocsToRFCOccurrenceMap(rawDocs) { + /* + Map containing occurrences of items + The key is made of (Root Numbered Folder + lowercase(Filename + Extension)) + The value is number of occurrences + */ + const occurrenceMap = {} + + rawDocs.forEach(rawDoc => { + const { name, ext } = path.parse(rawDoc.source) + const key = getRFCOccurrenceMapKey(name, ext, rawDoc.sourceDirName) + + if (key) { + occurrenceMap[key] = (occurrenceMap[key] || 0) + 1; + } + }) + + return occurrenceMap +} + +function getRFCOccurrenceMapKey(fileName, ext, dir) { + const parsedDir = dir[0] !== "/" ? `/${dir}` : dir.toString(); + const parsedExt = ext[0] === "." ? ext.slice(1) : ext; + + const match = parsedDir.match(/.*\/\d+(?=\/|$)/) + if (match) { + const rootNumberedRFC = match[0] + return `${rootNumberedRFC}/${fileName.toLowerCase()}.${parsedExt.toLowerCase()}` + } else { + return undefined + } +} + module.exports = { - isIndexDocument + isIndexDocument, + getRFCOccurrenceMapKey, + rawDocsToRFCOccurrenceMap } \ No newline at end of file diff --git a/docusaurus-utils/sidebar/utils.js b/docusaurus-utils/sidebar/utils.js index 208eabda9..b811c5bc1 100644 --- a/docusaurus-utils/sidebar/utils.js +++ b/docusaurus-utils/sidebar/utils.js @@ -1,8 +1,8 @@ function isNumber(value) { - if (true === Array.isArray(value)) { + if (Array.isArray(value)) { return false; } - return !isNaN(parseInt(value, 10)); + return !isNaN(value); } /*