diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index 99986d04a..ac4f7aa6f 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -141,7 +141,9 @@ export class GenerateDocs extends Script { this.WriteMarkdownFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage(), [ "src/UI/SpecialVisualizations.ts", - ]) + ], { + tocMaxDepth: 3 + }) if (!existsSync("./Docs/Themes")) { mkdirSync("./Docs/Themes") @@ -217,7 +219,8 @@ export class GenerateDocs extends Script { markdown: string, autogenSource: string[], options?: { - noTableOfContents?: boolean + noTableOfContents?: boolean, + tocMaxDepth?: number } ): void { for (const source of autogenSource) { @@ -236,7 +239,7 @@ export class GenerateDocs extends Script { let md = markdown if (options?.noTableOfContents !== false) { - md = TableOfContents.insertTocIntoMd(md) + md = TableOfContents.insertTocIntoMd(md, options?.tocMaxDepth) } md = md.replace(/\n\n\n+/g, "\n\n") diff --git a/src/UI/Base/TableOfContents.ts b/src/UI/Base/TableOfContents.ts index 5240d7b44..0ad35b7eb 100644 --- a/src/UI/Base/TableOfContents.ts +++ b/src/UI/Base/TableOfContents.ts @@ -48,13 +48,21 @@ export default class TableOfContents { return TableOfContents.mergeLevel(result) } - public static insertTocIntoMd(md: string): string { - const htmlSource = marked.parse(md) + public static insertTocIntoMd(md: string, maxDepth: number): string { + // parse_html has a limit on how much html it can parse. We strip away the actual content, only keeping the titles + const mdStripped = md.split("\n\n").filter(l => l.trim().startsWith("#")).join("\n\n") + const htmlSource = marked.parse(mdStripped) const el = parse_html(htmlSource) const structure = TableOfContents.generateStructure(el) + if(structure.length <= 1){ + return md + } const firstTitle = structure[1] let minDepth = undefined do { + // The document probably has a _single_ title at the top, denoting the title of the document + // We don't care for that title in the table of content; it'll just be clutter and use a single, valuable level + // So: we search this element, check if there indeed is only one and, if that is the case, erase it minDepth = Math.min(...structure.map((s) => s.depth)) const minDepthCount = structure.filter((s) => s.depth === minDepth) if (minDepthCount.length > 1) { @@ -65,6 +73,7 @@ export default class TableOfContents { structure.findIndex((s) => s.depth === minDepth), 1 ) + // As long as we have a lone top level, we continue cleaning up; hence the 'do-while' } while (structure.length > 0) if (structure.length <= 1) { @@ -84,7 +93,7 @@ export default class TableOfContents { if (depthDiff === 0) { topLevelCount++ toc += `${topLevelCount}. ${link}\n` - } else if (depthDiff <= 3) { + } else if (depthDiff <= 3 &&(maxDepth === undefined || depthDiff < maxDepth)) { toc += `${separators[depthDiff]} ${link}\n` } } @@ -101,23 +110,18 @@ export default class TableOfContents { } public static generateStructure( - html: Element + html: Element | ChildNode ): { depth: number; title: string; el: Element }[] { if (html === undefined) { return [] } - return [].concat( - ...Array.from(html.childNodes ?? []).map((child) => { + return Array.from(html.childNodes ?? []).flatMap((child) => { const tag: string = child["tagName"]?.toLowerCase() - if (!tag) { - return [] - } - if (tag.match(/h[0-9]/)) { + if (tag?.match(/h[0-9]/)) { const depth = Number(tag.substring(1)) - return [{ depth, title: child.textContent, el: child }] + return [{ depth, title: child.textContent, el: child }] } return TableOfContents.generateStructure(child) }) - ) } }