No description
This PR introduces a few more nodes in the `SelectorParser`: - A `list` node - A `complex` node - A `compound` node These names are closer to the CSS Selector AST names (https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Selectors/Selector_structure), and are also used in other libraries. The problem today is that there are situations where we parse a selector like: `#a.b > .c, .d` as: ```ts [ { kind: 'selector', value: '#a' }, { kind: 'selector', value: '.b' }, { kind: 'combinator', value: ' > ' }, { kind: 'selector', value: '.c' }, { kind: 'separator', value: ', ' }, { kind: 'selector', value: '.d' } ] ``` Which is a very simple structure, but this contains a flaw that is annoying to deal with in practice: In order to determine that we are dealing with multiple selectors, we have to loop through the nodes and see if a separator occurs somewhere. The other fun thing is that we already know the difference between selectors, combinators and separators. So if we tweak this structure a little bit during parsing, then we can answer the question from above in a much simpler way: With this PR, we will parse the selector as: ```ts [ { kind: 'list', nodes: [ { kind: 'complex', nodes: [ { kind: 'compound', nodes: [ { kind: 'selector', value: '#a' }, { kind: 'selector', value: '.b' } ] }, { kind: 'combinator', value: '>' }, { kind: 'selector', value: '.c' } ] }, { kind: 'selector', value: '.d' } ] } ] ``` It definitely looks more complex, but now that we have a `list` node, we already know that we are dealing with multiple selectors. If you squint your eyes, in the inner part there is a `compound` selector. This is essentially a node where each sub-node can be squished together with no spaces whatsoever. The `complex` selector is there just to group everything together. In other tools, a complex selector is often represented as: ```ts { kind: 'complex', combinator: '>', lhs: { … }, rhs: { … }, } ``` While I want to have the concept of a `complex` node, I didn't go with this syntax just because I want to keep the concept of `nodes` which means that we don't need any special handling when using `walk` (which loops over `.nodes` internally). The reason this complex node exists is because otherwise you would end up with this structure: ```ts [ { kind: 'list', nodes: [ { kind: 'compound', nodes: [ { kind: 'selector', value: '#a' }, { kind: 'selector', value: '.b' } ] }, { kind: 'combinator', value: '>' }, { kind: 'selector', value: '.c' } { kind: 'selector', value: '.d' } ] } ] ``` But if you look at the `list` node now, it's not clear that we are dealing with `2` selectors since there are 4 nodes. We could solve this by re-introducing the separator node (`,`). The fact that the `list` exists tells us that we're dealing with `n` selectors. But to know which selectors we're dealing with, then we have to look for that `,` node again, which introduces the original problem. This is just an internal refactor to make future changes easier. ## Test plan 1. Everything still works as expected (all tests pass) 2. No public API breaking changes, this parser was never exposed |
||
|---|---|---|
| .github | ||
| crates | ||
| integrations | ||
| packages | ||
| patches | ||
| playgrounds | ||
| scripts | ||
| .gitignore | ||
| .prettierignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| rust-toolchain.toml | ||
| turbo.json | ||
| vitest.config.ts | ||
A utility-first CSS framework for rapidly building custom user interfaces.
Documentation
For full documentation, visit tailwindcss.com.
Community
For help, discussion about best practices, or feature ideas:
Discuss Tailwind CSS on GitHub
Contributing
If you're interested in contributing to Tailwind CSS, please read our contributing docs before submitting a pull request.