Skip to content

fix(css, less, scss, stylus) keep escaped characters in selector names - #4513

Open
maximilliangrand wants to merge 1 commit into
highlightjs:mainfrom
maximilliangrand:fix/css-escaped-selector-names
Open

fix(css, less, scss, stylus) keep escaped characters in selector names#4513
maximilliangrand wants to merge 1 commit into
highlightjs:mainfrom
maximilliangrand:fix/css-escaped-selector-names

Conversation

@maximilliangrand

Copy link
Copy Markdown

Fixes #3965.

The bug

Class and id names may contain CSS escape sequences, which Tailwind emits for its variant separators. The selector patterns stopped at the backslash, so the name was cut short and the remainder rescanned:

.dark\:hover\:bg-sky-500:hover {}

On 11.12.0 that scopes .dark as the class, then the escaped \:hover as a pseudo class and 500 as a number. All four css-like grammars are affected.

Root cause

Each grammar spelled its own class and id pattern from a plain character class with no notion of escapes:

  • src/languages/css.js:17 (IDENT_RE, used by selector-class) and :40
  • src/languages/scss.js:38 and :43
  • src/languages/less.js:188 and :189, via INTERP_IDENT_RE
  • src/languages/stylus.js:76 and :82

The fix

Adds ESCAPE_RE and SELECTOR_IDENT_RE to src/languages/lib/css-shared.js and uses them for the class and id patterns in all four grammars, following your note on the issue about pushing a shared name pattern down into css-shared.js. Each grammar keeps its own leading-character rules, so the change is additive.

The hex branches of the escape are kept disjoint: a six digit run is only taken when a seventh follows, and every shorter run has to reach a non-hex character. Without that, \0 plus 0 and \00 are both valid splits of the same text and test/regex fails with exponential backtracking on "\00".repeat(n).

Tests

Four escape cases added to test/markup/css/css_consistency.txt and mirrored into less, scss and stylus with tools/css, so the shared fixture is what proves the four grammars now agree.

With the source change reverted those four css_consistency tests fail (598 passing, 4 failing); with it applied the markup suite is 602 passing and the full suite 1649 passing, 3 pending, matching main.

Assisted-by: Claude Opus 4.8 (high)

Class and id names may contain CSS escape sequences, as Tailwind emits for
variant separators (`.dark\:hover\:bg-sky-500`). The selector patterns stopped
at the backslash, so the name was cut short and the rest was rescanned: the
escaped `\:hover` was scoped as a pseudo class and the trailing `500` as a
number.

Adds a shared ESCAPE_RE and SELECTOR_IDENT_RE to lib/css-shared.js and uses
them for the class and id patterns in all four css-like grammars, so they stay
consistent. The hex branches of the escape are kept disjoint so the surrounding
quantifier cannot backtrack exponentially.

Fixes highlightjs#3965

Assisted-by: Claude Opus 4.8 (high)
Comment on lines +14 to +16
+ '[\\da-fA-F]{6}(?=[\\da-fA-F])'
+ '|[\\da-fA-F]{1,6}(?![\\da-fA-F]) ?'
+ '|[^\\da-fA-F\\r\\n]'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we add a few comments on what each of these is hoping to match?

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.

(css) Escaped special character in selector class name breaks highlighting

2 participants