Repository navigation
Conversation
The node for `ns|a` prints as `ns|a`, but its `sourceIndex` and `source.start` pointed at the `a`, so slicing the input from `sourceIndex` did not give the node back. The same held for `*|*`, `|a` and `&|a`. The selector around it already started at the namespace. The node now starts at its prefix, or at the `|` when the namespace is empty. Where it ends is unchanged.
|
Thanks for these four. CI is green on all of them, and I reproduced each of the four defects on released 7.2.0 before reading the diffs, so none of this is in doubt. The three months #335 and #336 sat unreviewed were on me, not on you. Two questions, and the first one is the one I actually care about. Would you be willing to contribute the harness itself? Your descriptions keep mentioning the thing that found these: a lossless round trip over 50,000 generated selectors in #358, and in this PR the invariant that If the generator and the invariants lived in the test suite, behind a flag or a longer-running job so they do not slow the normal run, the project would catch this class of bug itself, and a future PR in this area would come with a number anyone can reproduce. I would take that as its own PR, gladly, and it would be worth more to me than the individual fixes. And how do you use this package? None of your eight PRs or two issues mentions a project, a build, or a case you hit in practice, which makes me think these all come out of the sweep rather than out of something breaking on you. That is a fine way to find bugs and I am not complaining about it. But it changes how I prioritise: a defect that bites a real consumer goes in the next patch, while one that only an invariant can reach can wait for a minor. Knowing which is which, from you, saves me guessing. On this PR specifically: it is the one of the four I want to be most careful with, because it threads a |
|
Yes, happy to do the harness as its own PR. Rough plan: a seeded generator that builds selectors from fragments (namespaces, combinators, comments, escapes, Sass/Less interpolation), so any failure prints the seed and the input and you can rerun it. The checks would be the ones that found these: the lossless round trip, lossy output staying the same on a second parse, Some of these still fail on On usage, you guessed right. These came from the sweep. I don't use postcss-selector-parser directly, only through Tailwind, and none of them broke anything for me. So treat all four as invariant-only. On this one, fine by me. If it helps with #341 I can narrow the |
The bug
A tag or universal selector with a namespace prints its namespace, but its
sourceIndexandsource.startpoint past it, at the name:So
input.slice(node.sourceIndex)does not start with the node, and tools that map nodes back to the input point at the wrong place. The same happens for*|*,|aand&|a. The selector around it already starts at the namespace, and an attribute's[ns|x]starts at its[.The fix
namespace()knows where the node starts: at the prefix token, or at the|when the namespace is empty. It now passes that token on toword()/splitWord()anduniversal(), which use it for the first node'ssourceIndexandsource.start. Where the node ends is unchanged, and so are the class and id nodes that follow it in the same word, as inns|b.c.Verification
Four tests in
sourceIndex.mjs: a namespaced tag after a combinator,*|*, an empty namespace followed by a class, and a namespaced tag on a later line. All four fail onmain.I checked the same invariant over 50,000 random selectors: for every tag and universal node, the input sliced at
sourceIndexshould start with the node's own text. Onmain2,306 universal nodes broke it. On this branch none do. The tag nodes that still break it are all Sass interpolations, which is #243.npm testis green: lint, type check, and coverage gates.