csstree
csstree copied to clipboard
Add selector matching
It would be very useful if CSSTree could offer a method for matching CSS selector against Selector and similar nodes.
Not sure I get your idea. Can you explain a bit, an example maybe?
@lahmatiy: Sure, so let's say I got CSS parsed into CSSTree:
.test1 { color: red; }
.test2 { color: blue; }
.test3 { color: yellow; }
body.test { background: grey; }
Now I want to use the selector string body.test against each Selector node and find out what selector nodes match, in this case the Selector for last Rule node.
Similar to using css-select against the AST of CSSTree.
If I get it right, you want something like this:
findRulesBySelector(ast, 'body.test') // returns Rules[]
If so, I suggest to implement a helper which simplify selector matching for a pattern (the name is subject to discuss):
isSelectorMatch(rule.prelude, 'body.test') // returns true when selector contains `body.test` part
isSelectorMatch(rule.prelude, '> img') // will return true for `a > img`, `#id > img:hover`
isSelectorMatch(rule.prelude, ':hover') // true for `a:hover`, `a:hover::before`, `div:not(:hover)` etc
This is more universal since can be used with walk(), find() and findAll() depending on your needs as well as to be complemented with additional checks:
const rulesForGeneratedElements = findAll(ast, node =>
node.type === 'Rule'
&& isSelectorMatch(node.prelude, '::before') &&
&& isSelectorMatch(node.prelude, '::after')
);
What do you think?
@lahmatiy: The reason for this is to improve performance by avoiding stringification and parsing for each selector. Would this helper function avoid stringification and parsing for each selector and compare it on the AST level instead?
@strarsis Ah, I see. Well I'm sure that serialization (stringification) is not needed in this case. But you're right, a pattern parsing will be performed for each match. However, that's about performance optimizations not about a design of the feature. isSelectorMatch(), for instance, may has some kind of caching for patterns (strings) to avoid parsing on each call. The main problem for me now is to understand how such a matching should work and how a pattern should look like in order to solve as many cases as possible.