Repository navigation
Conversation
`:hover|a` printed as `:hoverhover|a`. The pseudo consumed the word `hover`, and then `namespace()` looked back at that same token and used it again as the prefix of `|a`. Each parse and print added another copy. When the `|` is reached from the main loop, the token before it has already been consumed, so only a skipped `&` can still be a prefix. The `|` now starts an empty namespace there, the way it already does after `]` in `[x]|a`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
A
|straight after a pseudo reuses the pseudo's name as its namespace, so the name is printed twice:Every parse and print adds another copy, so running the output back through the parser keeps growing it:
:hovernshoverns|a, then:hovernshovernshovernshoverns|a.pseudo()consumes the wordhoverthroughsplitWord(). The loop then reaches the|and callsnamespace()throughcombinator(), andnamespace()looks back at the previous token, which is that samehoverword, and uses it again as the prefix.The fix
When
word()oruniversal()see a|next, the token before it is still theirs, so the lookback is right. When the|is reached from the main loop instead, the token before it has already been consumed by something else, and only a skipped&(fromnesting()) can still be a prefix.namespace()now takes aprefixedflag, andcombinator()passesfalse.:hover|anow parses as the pseudo followed by|a, a tag with an empty namespace. That is what[x]|aalready gives, since]is not a prefix token either.Verification
Two tests in
namespaces.mjs, one for|bafter a pseudo-class and one for|*after a pseudo-element. All four of their checks fail onmain.I also ran a lossless round trip over 50,000 random selectors built from common fragments. Lossy output that changes when printed and parsed again went from 127 cases to 21, and none of the 21 involve a pseudo. They come from the Sass and Less interpolation spelling.
npm testis green: lint, type check, and coverage gates.