csstree icon indicating copy to clipboard operation
csstree copied to clipboard

Add selector matching

Open strarsis opened this issue 5 years ago • 6 comments

It would be very useful if CSSTree could offer a method for matching CSS selector against Selector and similar nodes.

strarsis avatar Apr 27 '20 21:04 strarsis

Not sure I get your idea. Can you explain a bit, an example maybe?

lahmatiy avatar Apr 28 '20 10:04 lahmatiy

@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.

strarsis avatar Apr 28 '20 13:04 strarsis

Similar to using css-select against the AST of CSSTree.

strarsis avatar Apr 29 '20 17:04 strarsis

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 avatar Dec 13 '21 17:12 lahmatiy

@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 avatar Dec 13 '21 18:12 strarsis

@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.

lahmatiy avatar Dec 15 '21 14:12 lahmatiy