From defbc9eb28e468bffcb759b7a42c9fb31cb834f0 Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Fri, 17 Jan 2025 00:46:45 +0000 Subject: [PATCH 1/4] [BUGFIX] Parse @font-face src property as comma-delimited list Fixes #789. Also adds an initial `TestCase` for `Rule/Rule`. --- CHANGELOG.md | 1 + src/Rule/Rule.php | 10 ++++++- tests/Rule/RuleTest.php | 58 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tests/Rule/RuleTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a0fabf7d..4fa23627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Please also have a look at our ### Fixed +- Parse `@font-face` `src` property as comma-delimited list (#790) - Fix type errors in PHP strict mode (#664) - Fix undefined local variable in `CalcFunction::parse()` (#593) - Fix PHP notice caused by parsing invalid color values having less than 6 diff --git a/src/Rule/Rule.php b/src/Rule/Rule.php index 9770a0ad..cd831b7c 100644 --- a/src/Rule/Rule.php +++ b/src/Rule/Rule.php @@ -117,13 +117,21 @@ public static function parse(ParserState $oParserState): Rule * @param string $sRule * * @return array + * The first item is the innermost separator (or, put another way, the highest-precedence operator). + * The sequence continues to the outermost separator (or lowest-precedence operator). */ private static function listDelimiterForRule($sRule): array { if (\preg_match('/^font($|-)/', $sRule)) { return [',', '/', ' ']; } - return [',', ' ', '/']; + + switch ($sRule) { + case 'src': + return [' ', ',']; + default: + return [',', ' ', '/']; + } } /** diff --git a/tests/Rule/RuleTest.php b/tests/Rule/RuleTest.php new file mode 100644 index 00000000..b3c577be --- /dev/null +++ b/tests/Rule/RuleTest.php @@ -0,0 +1,58 @@ +}> + */ + public static function provideRulesAndExpectedParsedValueListTypes(): array + { + return [ + 'src (e.g. in @font-face)' => [ + " + src: url('../fonts/open-sans-italic-300.woff2') format('woff2'), + url('../fonts/open-sans-italic-300.ttf') format('truetype'); + ", + [RuleValueList::class, RuleValueList::class], + ], + ]; + } + + /** + * @test + * + * @param array $expectedTypeClassnames + * + * @dataProvider provideRulesAndExpectedParsedValueListTypes + */ + public function parsesValuesIntoExpectedTypeList(string $rule, array $expectedTypeClassnames): void + { + $subject = Rule::parse(new ParserState($rule, Settings::create())); + + $value = $subject->getValue(); + self::assertInstanceOf(ValueList::class, $value); + + $actualClassnames = \array_map( + function ($component): string { + return \get_class($component); + }, + $value->getListComponents() + ); + + self::assertSame($expectedTypeClassnames, $actualClassnames); + } +} From ba73f72c77a88e386ed6d7b7e18be233223f0c09 Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Fri, 17 Jan 2025 18:10:34 +0000 Subject: [PATCH 2/4] Changes suggested in review. --- src/Rule/Rule.php | 8 +++++--- tests/Rule/RuleTest.php | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Rule/Rule.php b/src/Rule/Rule.php index cd831b7c..c8f39b1c 100644 --- a/src/Rule/Rule.php +++ b/src/Rule/Rule.php @@ -114,11 +114,13 @@ public static function parse(ParserState $oParserState): Rule } /** - * @param string $sRule - * - * @return array + * Returns a list of delimiters (or separators). * The first item is the innermost separator (or, put another way, the highest-precedence operator). * The sequence continues to the outermost separator (or lowest-precedence operator). + * + * @param string $sRule + * + * @return list */ private static function listDelimiterForRule($sRule): array { diff --git a/tests/Rule/RuleTest.php b/tests/Rule/RuleTest.php index b3c577be..9240e053 100644 --- a/tests/Rule/RuleTest.php +++ b/tests/Rule/RuleTest.php @@ -17,7 +17,7 @@ final class RuleTest extends TestCase { /** - * @return array}> + * @return array}> */ public static function provideRulesAndExpectedParsedValueListTypes(): array { @@ -35,7 +35,7 @@ public static function provideRulesAndExpectedParsedValueListTypes(): array /** * @test * - * @param array $expectedTypeClassnames + * @param list $expectedTypeClassnames * * @dataProvider provideRulesAndExpectedParsedValueListTypes */ @@ -47,8 +47,11 @@ public function parsesValuesIntoExpectedTypeList(string $rule, array $expectedTy self::assertInstanceOf(ValueList::class, $value); $actualClassnames = \array_map( - function ($component): string { - return \get_class($component); + /** + * @param Value|string $component + */ + static function ($component): string { + return \is_string($component) ? 'string' : \get_class($component); }, $value->getListComponents() ); From 43cbb858f8fb5b8cda89e57ff86c19a2b9688d02 Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Fri, 17 Jan 2025 18:18:20 +0000 Subject: [PATCH 3/4] Move `RuleTest.php` into `tests/Unit` directory. --- tests/Unit/.gitkeep | 0 tests/{ => Unit}/Rule/RuleTest.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/Unit/.gitkeep rename tests/{ => Unit}/Rule/RuleTest.php (100%) diff --git a/tests/Unit/.gitkeep b/tests/Unit/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/Rule/RuleTest.php b/tests/Unit/Rule/RuleTest.php similarity index 100% rename from tests/Rule/RuleTest.php rename to tests/Unit/Rule/RuleTest.php From 11e1eb3cb8bf2e98fcaaf6284e41d7958417b4d4 Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Fri, 17 Jan 2025 19:27:58 +0000 Subject: [PATCH 4/4] Further changes suggested in review. --- tests/Unit/Rule/RuleTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Rule/RuleTest.php b/tests/Unit/Rule/RuleTest.php index 9240e053..8265aa64 100644 --- a/tests/Unit/Rule/RuleTest.php +++ b/tests/Unit/Rule/RuleTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Sabberworm\CSS\Tests\Value; +namespace Sabberworm\CSS\Tests\Unit\Rule; use PHPUnit\Framework\TestCase; use Sabberworm\CSS\Parsing\ParserState; @@ -17,7 +17,7 @@ final class RuleTest extends TestCase { /** - * @return array}> + * @return array}> */ public static function provideRulesAndExpectedParsedValueListTypes(): array {