Skip to content

Fix: Whitespace characters will incorrectly trigger foster parenting.#31

Open
zimya wants to merge 3 commits into
syntax-tree:mainfrom
zimya:main
Open

Fix: Whitespace characters will incorrectly trigger foster parenting.#31
zimya wants to merge 3 commits into
syntax-tree:mainfrom
zimya:main

Conversation

@zimya

@zimya zimya commented Mar 22, 2026

Copy link
Copy Markdown

Initial checklist

  • I read the support docs
  • I read the contributing guide
  • I agree to follow the code of conduct
  • I searched issues and discussions and couldn’t find anything or linked relevant results below
  • I made sure the docs are up to date
  • I included tests (or that’s not needed)

Description of changes

Fixes #30

This PR fixes an issue where structural whitespace (like newlines) inside table elements gets incorrectly foster-parented outside the table when passing a hast tree through rehype-raw.

Currently, hast-util-raw unconditionally maps all text nodes to Token.TokenType.CHARACTER when feeding tokens to parse5. When parse5 receives a CHARACTER token inside restricted table modes (e.g., in table body, in row), it treats it as illegal text and triggers HTML5 Foster Parenting, extracting the newlines and flattening the table.

This PR added a regex check (/^[ \t\n\f\r]+$/) in the text() handler. If the text node contains only HTML whitespace characters, it is correctly mapped to Token.TokenType.WHITESPACE_CHARACTER. This allows parse5 to safely ignore/append the formatting whitespace without breaking the table structure.

@github-actions github-actions Bot added the 👋 phase/new Post is being triaged automatically label Mar 22, 2026
@github-actions

github-actions Bot commented Mar 22, 2026

Copy link
Copy Markdown

Hi! It seems you removed the template which we require. Here are our templates (pick the one you want to use and click *raw* to see its source):

I won’t send you any further notifications about this, but I’ll keep on updating this comment, and hide it when done!

Thanks,
— bb

@zimya zimya changed the title Fix: Whitespace characters will not trigger foster parenting. Fix: Whitespace characters will incorrectly trigger foster parenting. Mar 22, 2026
@ChristianMurphy

Copy link
Copy Markdown
Member

Could you add a test for this?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses incorrect HTML5 foster parenting triggered by structural whitespace within table-related insertion modes when feeding tokens into parse5, improving table structure preservation when running a HAST tree through hast-util-raw/rehype-raw.

Changes:

  • Classify whitespace-only text nodes as Token.TokenType.WHITESPACE_CHARACTER instead of always CHARACTER.
  • Make namespace detection in startTag() resilient when there is no current open element.
  • Minor formatting/indentation adjustment in documentMode() (no functional change).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/index.js Outdated
Comment on lines 197 to 205
const isWhitespace = /^[ \t\n\f\r]+$/.test(node.value)
const tokenType = isWhitespace
? Token.TokenType.WHITESPACE_CHARACTER
: Token.TokenType.CHARACTER

/** @type {Token.CharacterToken} */
const token = {
type: Token.TokenType.CHARACTER,
type: tokenType,
chars: node.value,

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a regression test for this new whitespace-token behavior (e.g., a <table> with \n / formatting-only text nodes between table elements) to ensure raw() no longer causes parse5 foster parenting to move those text nodes outside the table.

Copilot uses AI. Check for mistakes.
Comment thread lib/index.js Outdated
Comment on lines +197 to +198
const isWhitespace = /^[ \t\n\f\r]+$/.test(node.value)
const tokenType = isWhitespace

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /^[ \t\n\f\r]+$/ regex literal is evaluated each time text() runs, creating a new RegExp object per text node. Consider hoisting it to module scope (or reusing a shared constant) to avoid unnecessary allocations in large documents.

Copilot uses AI. Check for mistakes.
@zimya

zimya commented Mar 24, 2026

Copy link
Copy Markdown
Author

Thank you for the review! I've hoisted the RegExp to the module scope as whitespaceExpression to avoid unnecessary allocations, and added a regression test checking that whitespace text nodes within tables are kept inside the table and not foster-parented.

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

Labels

👋 phase/new Post is being triaged automatically

Development

Successfully merging this pull request may close these issues.

Newlines inside tables are incorrectly extracted when using rehype-raw and remark-gfm

3 participants