Kozea/tinycss2

Parsing qualified-rules inside @media{} blocks (and other at-rules)

Closed this issue · 2 comments

Hi! Thanks for Tinycss2, it's made it rather easy to write a css rule-pruner for my website.

When trying to parse a stylesheet with an @media at-rule, it seems the qualified-rule blocks within are not actually parsed as such. They're just token streams with blocks. This makes maniplating the prelude of rules within @media different and quite difficult.

Is this a bug, or just a consequence of the current architecture of tinycss2?

Here's an example:

import tinycss2
rules = tinycss2.parse_stylesheet('''
a {display:none;}
@media(max-width:900px) {
    b {display:none;}
}''')

rules is

[<QualifiedRule … { … }>,
<WhitespaceToken>,
<AtRule @media … { … }>]

(Note the QualifiedRule)

rules[3].type is an at-rule, of lower_at_keyword media, with content:

[<WhitespaceToken>,
 <IdentToken b>,
 <WhitespaceToken>,
 <CurlyBracketsBlock { … }>,
 <WhitespaceToken>]

Note that there's no QualifiedRule.

Thanks
Callan


Edit:

In the mean time for anyone else with this issue, here's a workaround: when enumerating the tree, re-parse the at-rule content as if it were the root:

rule.content = tinycss2.parse_stylesheet(tinycss2.serialize(rule.content)) 

This serialises back again OK.

liZe commented

Hello!

This behavior is a consequence of the specification:

This specification places no limits on what an at-rule’s block may contain. Individual at-rules must define whether they accept a block, and if so, how to parse it…

It means that tinycss2 can’t parse the rule block because it doesn’t necessarily contains rules. But:

(preferably using one of the parser algorithms or entry points defined in this specification)

And that’s actually what you do. You can even use parse_rule_list instead of serializing the rule content.

Hi @liZe, thanks for the response -- that makes total sense, I ended up using:

rule.content = tinycss2.parse_rule_list(rule.content)

Which works perfectly.

Thanks again for your help,
Cal