fix: exclude headings inside blockquotes from sidebar TOC#2691
fix: exclude headings inside blockquotes from sidebar TOC#2691Bowl42 wants to merge 3 commits intodocsifyjs:developfrom
Conversation
Headings inside blockquotes (e.g. `> # Title`) were being added to the sidebar table of contents, which is incorrect — they are quoted content, not page structure headings. The fix introduces an `insideBlockquote` flag on the compiler instance: - The blockquote compiler sets this flag to `true` before parsing its child tokens, and resets it to `false` afterward - The heading compiler checks this flag and skips adding the heading to `compiler.toc` when inside a blockquote The headings are still rendered correctly in the page content — they just no longer appear in the sidebar navigation. Fixes docsifyjs#1951 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@Bowl42 is attempting to deploy a commit to the Docsify Team on Vercel. A member of the Team first needs to authorize it. |
Replace the boolean `insideBlockquote` flag with a `blockquoteDepth` counter to correctly handle nested blockquotes. The boolean approach would reset to `false` when an inner blockquote finished parsing, causing headings in the outer blockquote after the nested one to incorrectly appear in the sidebar TOC. Also wrap the parse call in try/finally to ensure the counter is always decremented, and initialize `blockquoteDepth` in the Compiler constructor. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the markdown rendering pipeline to prevent headings rendered inside blockquotes from being added to the compiler-generated table of contents (TOC), likely to avoid polluting sidebar/subsidebar navigation with headings from callout blocks.
Changes:
- Track blockquote nesting depth on the
Compilerinstance (blockquoteDepth). - Increment/decrement
blockquoteDepthwhile parsingrenderer.blockquotetokens. - Gate TOC insertion in
headingCompilerso headings are only added when not inside a blockquote.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/core/render/compiler/heading.js | Skips pushing heading entries into compiler.toc when inside a blockquote. |
| src/core/render/compiler/blockquote.js | Adds depth tracking around blockquote parsing to support TOC suppression. |
| src/core/render/compiler.js | Initializes blockquoteDepth and passes compiler into blockquoteCompiler. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
sy-records
left a comment
There was a problem hiding this comment.
Thanks for your PR.
This can be placed on this instead of being imported into the compiler.
| compiler.blockquoteDepth++; | ||
| try { | ||
| const body = this.parser.parse(tokens); | ||
| return `${openTag}${body}${closeTag}`; | ||
| } finally { | ||
| compiler.blockquoteDepth--; | ||
| } |
There was a problem hiding this comment.
| compiler.blockquoteDepth++; | |
| try { | |
| const body = this.parser.parse(tokens); | |
| return `${openTag}${body}${closeTag}`; | |
| } finally { | |
| compiler.blockquoteDepth--; | |
| } | |
| this.__docsifyBlockquoteDepth = (this.__docsifyBlockquoteDepth || 0) + 1; | |
| let body; | |
| try { | |
| body = this.parser.parse(tokens); | |
| } finally { | |
| this.__docsifyBlockquoteDepth = Math.max(0, this._blockquoteDepth - 1); | |
| } |
| if (!compiler.blockquoteDepth) { | ||
| compiler.toc.push(nextToc); | ||
| } |
There was a problem hiding this comment.
| if (!compiler.blockquoteDepth) { | |
| compiler.toc.push(nextToc); | |
| } | |
| if (!this.__docsifyBlockquoteDepth || this.__docsifyBlockquoteDepth === 0) { | |
| compiler.toc.push(nextToc); | |
| } |
Summary
> # Title) are incorrectly added to the sidebar table of contents. They should only render as headings within the blockquote content, not appear as navigation items.heading.js) unconditionally pushes every heading tocompiler.toc, with no awareness of whether it's inside a blockquote. When the blockquote compiler (blockquote.js) callsthis.parser.parse(tokens), any headings within are processed and added to the TOC.blockquoteDepthcounter on the compiler instance. The blockquote compiler increments it before parsing child tokens and decrements it in afinallyblock. The heading compiler checks this counter and skips TOC insertion when depth > 0. A counter (rather than a boolean flag) correctly handles nested blockquotes.Changes
src/core/render/compiler.jsthis.blockquoteDepth = 0in the Compiler constructorcompiler: thistoblockquoteCompiler()so it can access the compiler instancesrc/core/render/compiler/blockquote.jscompilerfrom the options parametercompiler.blockquoteDepthbefore parsing child tokensfinallyblock to ensure cleanup even if parsing throwssrc/core/render/compiler/heading.jscompiler.toc.push(nextToc)in a check: only push when!compiler.blockquoteDepthTest plan
> # Quoted Title> > # Nested) also exclude headings from TOC> [!NOTE]) with headings also exclude those headings from TOCFixes #1951
🤖 Generated with Claude Code