MyIntervals / PHP-CSS-Parser

A Parser for CSS Files written in PHP. Allows extraction of CSS files into a data structure, manipulation of said structure and output as (optimized) CSS
http://www.sabberworm.com/blog/2010/6/10/php-css-parser
MIT License
1.75k stars 149 forks source link

Support for @supports syntax #127

Open bmbrands opened 6 years ago

bmbrands commented 6 years ago

The @supports syntax used in Bootstrap 4 is not supported.

When trying to compile it an exception is thrown:

Stack trace: line 113 of /lib/php-css-parser/Parser.php: Sabberworm\CSS\Parsing\SourceException thrown line 197 of /lib/php-css-parser/Parser.php: call to Sabberworm\CSS\Parser->parseList() line 119 of /lib/php-css-parser/Parser.php: call to Sabberworm\CSS\Parser->parseAtRule() line 96 of /lib/php-css-parser/Parser.php: call to Sabberworm\CSS\Parser->parseListItem() line 87 of /lib/php-css-parser/Parser.php: call to Sabberworm\CSS\Parser->parseList() line 82 of /lib/php-css-parser/Parser.php: call to Sabberworm\CSS\Parser->parseDocument() line 61 of /testcss.php: call to Sabberworm\CSS\Parser->parse()

Exception - Unexpected end of document [line no: 23]

raxbg commented 6 years ago

Seems to be working for me. Can you provide a more elaborated example?

sabberworm commented 6 years ago

@raxbg Maybe you’re parsing in lenient mode? @supports is currently unsupported so this issue is valid IMHO.

raxbg commented 6 years ago

Yes, I will probably work on this some time soon because I will need it 😄

raxbg commented 6 years ago

Hm, I was just about to start working on this, but yet again I cannot reproduce it even without lenient mode. @bmbrands can you provide an example CSS which triggers this error? @sabberworm @supports seems to be following similar syntax to the @media rules. Saying that @supports is unsupported does that mean that @media is also unsupported? Neither of them seems to throw error though. Do you have any changes in mind that you would like to see in order to consider these officially supported?

In my tests both @media and @supports are parsed as AtRuleBlockList with correct names and args. Examples from bootstrap 4:


name: string(5) "media"
args: string(18) "(min-width: 992px)"
name: string(8) "supports"
args: string(74) "((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d))"```
JakeQZ commented 2 years ago

Yep, I find the issue is in strict mode only. In lenient mode, @media and @supports are parsed correctly. In strict mode, an exception is thrown for either (and also any at-rule with nested rules, such as @keyframes and @document).

E.g. with the current code base the following test added to AtRuleBlockListTest will fail:

    /**
     * @test
     *
     * @param string $css
     *
     * @dataProvider mediaRuleDataProvider
     */
    public function parsesMediaRuleInStrictMode($css)
    {
        (new Parser($css, Settings::create()->beStrict()))->parse();

        self::assertTrue(true); // no exception was thrown
    }

The failure is:

Sabberworm\CSS\Parsing\UnexpectedTokenException: Identifier expected. Got “}” [line no: 1]

Perhaps it is simply that the final closing } isn't being consumed - it is clearly triggering the completion of the at-rule, otherwise subsequent rules would end up inside the at-rule (which they don't) - so the parser ends up seeing it again, but in lenient mode silently ignores this double-vision.

See also #75.

Note that @font-face is fine, but that doesn't have nested rules, just property-value pairs.