Skip to content

fix(utils): stop comments from leaking into the excerpt - #12389

Open
pucedoteth wants to merge 4 commits into
facebook:mainfrom
pucedoteth:fix/excerpt-comment-leak
Open

fix(utils): stop comments from leaking into the excerpt#12389
pucedoteth wants to merge 4 commits into
facebook:mainfrom
pucedoteth:fix/excerpt-comment-leak

Conversation

@pucedoteth

Copy link
Copy Markdown

Motivation

createExcerpt() strips HTML with a per-line tag regex:

.replace(/<[^>]*>/g, '')

That regex cannot see a comment. It stops at the first >, and it has no state to carry an unterminated comment onto the next line. A document that opens with a comment therefore excerpts the comment itself:

document opens with excerpt today expected
<!--
Copyright (c) Meta Platforms, Inc.
-->
<!-- How to configure the sidebar.
<!-- TODO: rewrite this page
once v4 ships -->
<!-- TODO: rewrite this page Install the package.
<!-- a > b --> b --> Some content.
<!-- note
more --> Real text.
<!-- note Real text.

MDX's {/* ... */} form leaks the same way, and leaks even on a single line — {/* note */} comes out as {/ note /} once the emphasis and heading-id rules have run on it.

This is not confined to the excerpt. Both content plugins fall back to it for the page description:

const description = frontMatter.description ?? excerpt ?? '';

docs.ts and blogUtils.ts. So for any doc or blog post without an explicit description front matter, the leaked comment is published in <meta name="description">, the Open Graph tags and the blog feed.

That is what makes this more than cosmetic. Comments are precisely the syntax authors use for text addressed to editors rather than readers — license headers, prettier-ignore markers, "do not translate", "TODO: rewrite this". Those are the strings that end up in the search snippet and the social preview.

The fix

A small state machine strips both comment forms, tracking which delimiter is open so it survives across lines and so {/* inside an HTML comment can't hijack a span that is already open.

Placement matters: it runs after the inline-code escaping added in #11821. escapeMDX already escapes <, >, !, { and *, so by that point inline code cannot contain a literal <!-- or {/*, and comment syntax written inside backticks stays intact for free. There's a test pinning that.

Test Plan

8 tests added to the existing createExcerpt describe block. Reverting only markdownUtils.ts and keeping the tests turns 5 of them red, with exactly the values in the table above:

× creates excerpt ignoring a multiline HTML comment
    expected '<!--' to be 'How to configure the sidebar.'
× creates excerpt ignoring an HTML comment containing a closing bracket
    expected 'b -->' to be 'Some content.'
× creates excerpt from the text following a comment
    expected '<!-- note' to be 'Real text.'
× creates excerpt ignoring an MDX comment
    expected '{/ note /}' to be 'Some content.'
× creates excerpt ignoring a multiline MDX comment
    expected '{/* note' to be 'Some content.'

The other 3 pass before and after by design — they are regression guards for behaviour that is already correct: comment syntax inside inline code (#11821), comment syntax inside fenced code blocks, and a document that is nothing but a comment yielding no excerpt.

With the fix, markdownUtils.test.ts is 92/92 and the whole docusaurus-utils package is 407/408. The one failure is gitUtils.test.ts > rejects for cwd of untracked dir, which fails identically on a clean checkout here — it depends on whether the checkout's parent directory happens to be a git repo, and is unrelated to this change.

oxfmt and eslint are clean on both changed files (the 3 remaining max-len warnings in markdownUtils.ts are pre-existing, on the import/export comment block).

🤖 Generated with Claude Code

createExcerpt() removes HTML with a per-line `/<[^>]*>/` tag regex, which
cannot see a comment: it stops at the first ">", and it has no state to carry
an unterminated comment to the next line. So a document opening with a comment
excerpts the comment itself.

The excerpt becomes `description` in both the docs and blog plugins, so the
result is published in <meta name="description">, the Open Graph tags and the
blog feed. Comments are the syntax authors use for text addressed to editors
rather than readers, which makes this worse than cosmetic: a "<!-- TODO:
rewrite this page -->" note becomes the page's public description.

MDX's {/* ... */} form leaks the same way, and leaks even on a single line,
rendering as "{/ note /}" once the emphasis and heading-id rules have run.

Strip both forms with a small state machine that tracks the open delimiter
across lines. It runs after the inline-code escaping added in facebook#11821, so
comment syntax written inside inline code is already escaped by then and stays
intact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@meta-cla

meta-cla Bot commented Aug 25, 2026

Copy link
Copy Markdown

Hi @pucedoteth!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@netlify

netlify Bot commented Aug 25, 2026

Copy link
Copy Markdown

[V2]

Name Link
🔨 Latest commit 8178fe3
🔍 Latest deploy log https://app.netlify.com/projects/docusaurus-2/deploys/6a8f06290181f200089aafa1
😎 Deploy Preview https://deploy-preview-12389--docusaurus-2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@meta-cla

meta-cla Bot commented Aug 25, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla Bot added the CLA Signed Signed Facebook CLA label Aug 25, 2026
@meta-cla

meta-cla Bot commented Aug 25, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@slorber slorber added the Argos Add this label to run UI visual regression tests. See argos.yml GH action. label Aug 26, 2026
@slorber slorber added pr: bug fix This PR fixes a bug in a past release. Argos Add this label to run UI visual regression tests. See argos.yml GH action. and removed Argos Add this label to run UI visual regression tests. See argos.yml GH action. labels Aug 26, 2026
@argos-ci

argos-ci Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Awaiting the start of a new Argos build…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Argos Add this label to run UI visual regression tests. See argos.yml GH action. CLA Signed Signed Facebook CLA pr: bug fix This PR fixes a bug in a past release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants