Skip to content

fix: preserve selector delimiters after escaped backslashes - #354

Merged
MoOx merged 3 commits into
postcss:mainfrom
wozhenbang2004:fix/escaped-backslash-delimiters
Nov 8, 2026
Merged

MoOx merged 3 commits into
postcss:mainfrom
wozhenbang2004:fix/escaped-backslash-delimiters

Conversation

@wozhenbang2004

Copy link
Copy Markdown
Contributor

When a class name ends in an escaped backslash, a following . or # starts a new selector node. splitWord() currently treats every delimiter immediately preceded by a backslash as escaped and merges the nodes.

Count consecutive backslashes before the delimiter so an even number leaves it active and an odd number still escapes it. The regression tests exercise both delimiters, escaped delimiters after a backslash, and lossless round trips.

The two new delimiter cases fail on the unmodified parser. npm test passed all 905 tests on Node.js 24, including the coverage thresholds.

wozhenbang2004 and others added 3 commits November 5, 2026 11:00
* origin/main:
  feat: support the case-sensitive attribute flag (s) per Selectors Level 4 (postcss#327)
  fix: escape values assigned to an id through the value setter (postcss#326)
  fix: escape class values supplied to the constructor (postcss#349)
  fix: preserve the spaces declared on selector and root containers (postcss#356)
  fix: forward the default options given to the parser factory (postcss#345)
  7.1.8
  fix: remove four more quadratic paths from selector parsing

# Conflicts:
#	src/parser.js
@MoOx

MoOx commented Nov 8, 2026

Copy link
Copy Markdown
Collaborator

I merged current main into your branch rather than asking you to rebase, because the conflict came from our side: 7.1.8 hoisted the @keyframes percent test out of the per-index filter, since evaluating it for every . made a digit-prefixed word quadratic. Resolving in favour of your version alone would have put that regression back.

Your isEscaped is kept as is. I checked it separately and it stays linear overall: the backslash runs do not overlap, so the total work is bounded by their sum. At a constant 200 KB of input the cost is flat from 10 to 50 000 delimiters.

npm test passes with 985 tests, and I confirmed both properties: .a\\.b now parses as two classes instead of one, and parsing a digit-prefixed word stays flat at 3 ms from 12 000 to 48 000 characters.

Tell me if you would rather resolve it yourself and I will drop my merge commit.

@MoOx
MoOx merged commit 815dc18 into postcss:main Nov 8, 2026
MoOx added a commit to theRizwan/postcss-selector-parser that referenced this pull request Nov 8, 2026
* origin/main:
  fix: preserve selector delimiters after escaped backslashes (postcss#354)
  fix: keep the processor's entry points usable when destructured
  feat: support the case-sensitive attribute flag (s) per Selectors Level 4 (postcss#327)
  fix: escape values assigned to an id through the value setter (postcss#326)
  fix: escape class values supplied to the constructor (postcss#349)
  fix: preserve the spaces declared on selector and root containers (postcss#356)
  fix: forward the default options given to the parser factory (postcss#345)
  7.1.8
  fix: remove four more quadratic paths from selector parsing
  chore(deps): bump tinypool and oxfmt (postcss#351)
  7.1.7
  docs: add CVE-2026-104844 to the 7.1.6 changelog entry
  fix: keep whitespace around the namespace separator in attribute selectors (postcss#339)
  fix: invalidate stale raw spelling on combinator value assignment (postcss#342)
  fix: set parents for all variadic inserted nodes (postcss#343)
  Consume whitespace after hexadecimal CSS escapes (postcss#340)
  fix: lossless mode drops whitespace when a selector ends empty (postcss#337)
  chore(deps-dev): bump source-map-js from 1.2.1 to 1.2.2 (postcss#347)
  7.1.6
  fix: parse flat selectors in linear time, closing a CPU exhaustion vulnerability

# Conflicts:
#	src/parser.js
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.

2 participants