diff --git a/src/Css/CssDocument.php b/src/Css/CssDocument.php index 3d792a8f..9c00785a 100644 --- a/src/Css/CssDocument.php +++ b/src/Css/CssDocument.php @@ -13,6 +13,7 @@ use Sabberworm\CSS\Renderable as CssRenderable; use Sabberworm\CSS\RuleSet\DeclarationBlock as CssDeclarationBlock; use Sabberworm\CSS\RuleSet\RuleSet as CssRuleSet; +use Sabberworm\CSS\Settings as ParserSettings; /** * Parses and stores a CSS document from a string of CSS, and provides methods to obtain the CSS in parts or as data @@ -36,7 +37,7 @@ class CssDocument private $isImportRuleAllowed = true; /** - * @param string $css + * @param string $css {@see https://github.com/squizlabs/PHP_CodeSniffer/issues/3521} * @param bool $debug * If this is `true`, an exception will be thrown if invalid CSS is encountered. * Otherwise the parser will try to do the best it can. @@ -44,17 +45,25 @@ class CssDocument public function __construct(string $css, bool $debug) { // CSS Parser currently throws exception with nested at-rules (like `@media`) in strict parsing mode - // @see https://github.com/sabberworm/PHP-CSS-Parser/issues/127 - $parserSettings = \Sabberworm\CSS\Settings::create()->withLenientParsing( - !$debug || - \preg_match('/@(?:media|supports|(?:-webkit-|-moz-|-ms-|-o-)?+(keyframes|document))\\b/', $css) === 1 - ); + $parserSettings = ParserSettings::create()->withLenientParsing(!$debug || static::hasNestedAtRule($css)); // CSS Parser currently throws exception with non-empty whitespace-only CSS in strict parsing mode, so `trim()` // @see https://github.com/sabberworm/PHP-CSS-Parser/issues/349 $this->sabberwormCssDocument = (new CssParser(\trim($css), $parserSettings))->parse(); } + /** + * Tests if a string of CSS appears to contain an at-rule with nested rules + * (`@media`, `@supports`, `@keyframes`, `@document`, + * the latter two additionally with vendor prefixes that may commonly be used). + * + * @see https://github.com/sabberworm/PHP-CSS-Parser/issues/127 + */ + private static function hasNestedAtRule(string $css): bool + { + return \preg_match('/@(?:media|supports|(?:-webkit-|-moz-|-ms-|-o-)?+(keyframes|document))\\b/', $css) === 1; + } + /** * Collates the media query, selectors and declarations for individual rules from the parsed CSS, in order. * diff --git a/tests/Unit/Css/CssDocumentTest.php b/tests/Unit/Css/CssDocumentTest.php index 5a099db3..bc7b18ad 100644 --- a/tests/Unit/Css/CssDocumentTest.php +++ b/tests/Unit/Css/CssDocumentTest.php @@ -24,6 +24,11 @@ final class CssDocumentTest extends TestCase . ' font-family: "Foo Sans";' . "\n" . ' src: url("/foo-sans.woff2") format("woff2");' . "\n}"; + private static function createDebugSubject(string $css): CssDocument + { + return new CssDocument($css, true); + } + /** * @test * @@ -436,8 +441,6 @@ public function provideCssWithoutNonConditionalAtRules(): array /** * @test * - * @param string $css - * * @dataProvider provideValidAtCharsetRules * @dataProvider provideInvalidAtCharsetRules */ @@ -453,8 +456,6 @@ public function discardsValidOrInvalidAtCharsetRuleNotInDebugMode(string $css): /** * @test * - * @param string $css - * * @dataProvider provideValidAtCharsetRules */ public function discardsValidAtCharsetRuleInDebugMode(string $css): void @@ -469,8 +470,6 @@ public function discardsValidAtCharsetRuleInDebugMode(string $css): void /** * @test * - * @param string $css - * * @dataProvider provideInvalidAtCharsetRules */ public function throwsExceptionForOrDiscardsInvalidAtCharsetRuleInDebugMode(string $css): void @@ -513,9 +512,6 @@ public function provideInvalidAtCharsetRules(): array /** * @test * - * @param string $atRuleCss - * @param string $cssBefore - * * @dataProvider provideInvalidNonConditionalAtRule */ public function discardsInvalidNonConditionalAtRuleNotInDebugMode(string $atRuleCss, string $cssBefore = ''): void @@ -590,11 +586,6 @@ public function notRendersAtMediaRuleInNonConditionalAtRules(): void self::assertSame('', $result); } - private static function createDebugSubject(string $css): CssDocument - { - return new CssDocument($css, true); - } - /** * Asserts that two strings are the same after `trim`ming both of them. *