Skip to content

fix: preserve whitespace before a * namespace in attribute selectors#325

Open
spokodev wants to merge 1 commit into
postcss:mainfrom
spokodev:fix/attribute-asterisk-namespace-spaces
Open

fix: preserve whitespace before a * namespace in attribute selectors#325
spokodev wants to merge 1 commit into
postcss:mainfrom
spokodev:fix/attribute-asterisk-namespace-spaces

Conversation

@spokodev

Copy link
Copy Markdown

Problem

Leading whitespace before a * (universal) namespace in an attribute selector is dropped on a round-trip, while it is preserved for a named namespace or no namespace:

const parser = require("postcss-selector-parser");
const rt = (s) => { let o; parser((r) => (o = r.toString())).processSync(s); return o; };

rt("[ *|a ]");  // "[*|a ]"   ← leading space lost
rt("[ ns|a ]"); // "[ ns|a ]" (ok)
rt("[ |a ]");   // "[ |a ]"   (ok)
rt("[ a ]");    // "[ a ]"    (ok)

Root cause

In attribute(), the tokens.asterisk branch records the raw spacing with the wrong variable:

if (spaceBefore) {
  node.spaces.attribute.before = spaceBefore;
  spaceBefore = "";          // cleared here
}
if (commentBefore) {
  node.raws.spaces.attribute.before = spaceBefore;  // ← always "" now
  commentBefore = "";
}

spaceBefore has already been set to "", so raws.spaces.attribute.before is emptied. Since toString prefers the raw spacing when present, the leading whitespace disappears. The tokens.word branch right below does the same thing correctly with commentBefore.

Fix

Use commentBefore for the raw spacing, matching the word-namespace branch (one word).

Test plan

  • Added an attribute test for a universal namespace with surrounding spaces ([ *|bar ]); the tree was already correct, but the toString round-trip failed on main and passes with the fix.
  • A round-trip property check over generated selectors flagged this case; the fix clears it with no regressions. Full suite green (779), eslint/tsc clean.

The `*` branch of the attribute parser stored the raw leading whitespace
from `spaceBefore`, but that variable had just been cleared a few lines
above, so `raws.spaces.attribute.before` became empty and `[ *|a ]`
round-tripped to `[*|a ]`. The word-namespace branch already uses
`commentBefore` here; do the same for `*`.
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