Skip to content

fix(prettier-plugin-liquid): preserve U+00A0 and don't drop borrowed closing tags#1191

Open
BJvdA wants to merge 2 commits intoShopify:mainfrom
BJvdA:fix/preserve-nbsp-html-text
Open

fix(prettier-plugin-liquid): preserve U+00A0 and don't drop borrowed closing tags#1191
BJvdA wants to merge 2 commits intoShopify:mainfrom
BJvdA:fix/preserve-nbsp-html-text

Conversation

@BJvdA
Copy link
Copy Markdown
Contributor

@BJvdA BJvdA commented Apr 22, 2026

What are you adding in this PR?

Fix a @shopify/prettier-plugin-liquid bug where formatting an HTML text node containing only a non-breaking space (U+00A0) inside borrowed-closing-tag contexts produced broken output:

Input:

<p><strong><em>\u00A0</em></strong></p>

Previous output (incorrect — both the NBSP and the </em> are lost):

<p>
  <strong><em></strong>
</p>

Expected output (preserves the NBSP and the </em>):

<p>
  <strong><em> </em></strong>
</p>

Root cause

printTextNode short-circuited whitespace-only text with return ''. Two problems:

  1. JavaScript's \s matches U+00A0, but in HTML a non-breaking space is a meaningful character and must not be collapsed away.
  2. The early return '' skipped printOpeningTagPrefix / printClosingTagSuffix, which is exactly where tag markers borrowed from the parent (see needsToBorrowParentClosingTagStartMarker) are emitted. When that runs on a whitespace-only text node, the borrowed </em> marker gets silently dropped.

Fix (packages/prettier-plugin-liquid/src/printer/printer-liquid-html.ts)

  • Use the HTML whitespace set [ \t\n\r\f] instead of \s for the short-circuit, the trim, and the word split — so U+00A0 (and other non-collapsible Unicode "whitespace") flows through as a regular character.
  • When the text really is pure HTML whitespace, still emit printOpeningTagPrefix / printClosingTagSuffix so any borrowed open/close markers survive.

Adds a regression case to the unit-paragraphs printer fixture covering <p><strong><em>\u00A0</em></strong></p>.

What's next? Any followup issues?

None.

What did you learn?

\s in JavaScript matches U+00A0 — which is fine for "is this byte whitespace-ish", but wrong any time you actually care about HTML semantics, where NBSP is non-collapsible content. Whenever a printer special-cases "whitespace-only" nodes, the early-return path also has to honor whatever work the surrounding tag-borrowing logic relies on.

Tophatting

  • I added screenshots of the changes (before and after the changes if applicable)

Repro / verification:

yarn workspace @shopify/prettier-plugin-liquid test

The new fixture under unit-paragraphs (it should preserve non-breaking spaces (U+00A0) as text and not drop borrowed closing tags) covers the regression.

Before you deploy

  • I included a patch bump changeset (.changeset/preserve-nbsp-html-text.md)

@BJvdA BJvdA requested a review from a team as a code owner April 22, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant