From c10ef87c4ec2c603f04bbdeddcbf8365c76e6058 Mon Sep 17 00:00:00 2001 From: JakeQZ Date: Sun, 23 Jun 2024 08:03:08 +0100 Subject: [PATCH 1/4] [FEATURE] Support arithmetic operators in CSS functions (#607) This is the enhancement from #390. `calc` was already supported. --- CHANGELOG.md | 2 +- src/Value/Value.php | 11 +++- tests/Value/ValueTest.php | 109 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 tests/Value/ValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e29397aa..217e5c36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## x.y.z ### Added +- Support arithmetic operators in CSS function arguments (#607) - Add support for inserting an item in a CSS list (#545) - - Add support for the `dvh`, `lvh` and `svh` length units (#415) ### Changed diff --git a/src/Value/Value.php b/src/Value/Value.php index 6be2110c..4b174db0 100644 --- a/src/Value/Value.php +++ b/src/Value/Value.php @@ -163,7 +163,16 @@ public static function parsePrimitiveValue(ParserState $oParserState) } elseif ($oParserState->comes("U+")) { $oValue = self::parseUnicodeRangeValue($oParserState); } else { - $oValue = self::parseIdentifierOrFunction($oParserState); + $sNextChar = $oParserState->peek(1); + try { + $oValue = self::parseIdentifierOrFunction($oParserState); + } catch (UnexpectedTokenException $e) { + if (\in_array($sNextChar, ['+', '-', '*', '/'], true)) { + $oValue = $oParserState->consume(1); + } else { + throw $e; + } + } } $oParserState->consumeWhiteSpace(); return $oValue; diff --git a/tests/Value/ValueTest.php b/tests/Value/ValueTest.php new file mode 100644 index 00000000..11526f9f --- /dev/null +++ b/tests/Value/ValueTest.php @@ -0,0 +1,109 @@ + + */ + public static function provideArithmeticOperator(): array + { + $units = ['+', '-', '*', '/']; + + return \array_combine( + $units, + \array_map( + function (string $unit): array { + return [$unit]; + }, + $units + ) + ); + } + + /** + * @test + * + * @dataProvider provideArithmeticOperator + */ + public function parsesArithmeticInFunctions(string $operator): void + { + $subject = Value::parseValue(new ParserState('max(300px, 50vh ' . $operator . ' 10px);', Settings::create())); + + self::assertSame('max(300px,50vh ' . $operator . ' 10px)', (string) $subject); + } + + /** + * @return array + * The first datum is a template for the parser (using `sprintf` insertion marker `%s` for some expression). + * The second is for the expected result, which may have whitespace and trailing semicolon removed. + */ + public static function provideCssFunctionTemplates(): array + { + return [ + 'calc' => [ + 'to be parsed' => 'calc(%s);', + 'expected' => 'calc(%s)', + ], + 'max' => [ + 'to be parsed' => 'max(300px, %s);', + 'expected' => 'max(300px,%s)', + ], + ]; + } + + /** + * @test + * + * @dataProvider provideCssFunctionTemplates + */ + public function parsesArithmeticWithMultipleOperatorsInFunctions( + string $parserTemplate, + string $expectedResultTemplate + ): void { + static $expression = '300px + 10% + 10vw'; + + $subject = Value::parseValue(new ParserState(\sprintf($parserTemplate, $expression), Settings::create())); + + self::assertSame(\sprintf($expectedResultTemplate, $expression), (string) $subject); + } + + /** + * @return array + */ + public static function provideMalformedLengthOperands(): array + { + return [ + 'LHS missing number' => ['vh', '10px'], + 'RHS missing number' => ['50vh', 'px'], + 'LHS missing unit' => ['50', '10px'], + 'RHS missing unit' => ['50vh', '10'], + ]; + } + + /** + * @test + * + * @dataProvider provideMalformedLengthOperands + */ + public function parsesArithmeticWithMalformedOperandsInFunctions(string $leftOperand, string $rightOperand): void + { + $subject = Value::parseValue(new ParserState( + 'max(300px, ' . $leftOperand . ' + ' . $rightOperand . ');', + Settings::create() + )); + + self::assertSame('max(300px,' . $leftOperand . ' + ' . $rightOperand . ')', (string) $subject); + } +} From 3ec785892fd84e99bda6fac5d3c3f7d6ae472d44 Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Fri, 28 Jun 2024 01:32:06 +0100 Subject: [PATCH 2/4] Remove `strict_types` for PHP5. --- tests/Value/ValueTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Value/ValueTest.php b/tests/Value/ValueTest.php index 11526f9f..981db32b 100644 --- a/tests/Value/ValueTest.php +++ b/tests/Value/ValueTest.php @@ -1,7 +1,5 @@ Date: Fri, 28 Jun 2024 01:33:38 +0100 Subject: [PATCH 3/4] Remove return value specifiers for PHP5. --- tests/Value/ValueTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Value/ValueTest.php b/tests/Value/ValueTest.php index 981db32b..add1ad1a 100644 --- a/tests/Value/ValueTest.php +++ b/tests/Value/ValueTest.php @@ -15,14 +15,14 @@ final class ValueTest extends TestCase /** * @return array */ - public static function provideArithmeticOperator(): array + public static function provideArithmeticOperator() { $units = ['+', '-', '*', '/']; return \array_combine( $units, \array_map( - function (string $unit): array { + function (string $unit) { return [$unit]; }, $units @@ -35,7 +35,7 @@ function (string $unit): array { * * @dataProvider provideArithmeticOperator */ - public function parsesArithmeticInFunctions(string $operator): void + public function parsesArithmeticInFunctions(string $operator) { $subject = Value::parseValue(new ParserState('max(300px, 50vh ' . $operator . ' 10px);', Settings::create())); @@ -47,7 +47,7 @@ public function parsesArithmeticInFunctions(string $operator): void * The first datum is a template for the parser (using `sprintf` insertion marker `%s` for some expression). * The second is for the expected result, which may have whitespace and trailing semicolon removed. */ - public static function provideCssFunctionTemplates(): array + public static function provideCssFunctionTemplates() { return [ 'calc' => [ @@ -69,7 +69,7 @@ public static function provideCssFunctionTemplates(): array public function parsesArithmeticWithMultipleOperatorsInFunctions( string $parserTemplate, string $expectedResultTemplate - ): void { + ) { static $expression = '300px + 10% + 10vw'; $subject = Value::parseValue(new ParserState(\sprintf($parserTemplate, $expression), Settings::create())); @@ -80,7 +80,7 @@ public function parsesArithmeticWithMultipleOperatorsInFunctions( /** * @return array */ - public static function provideMalformedLengthOperands(): array + public static function provideMalformedLengthOperands() { return [ 'LHS missing number' => ['vh', '10px'], @@ -95,7 +95,7 @@ public static function provideMalformedLengthOperands(): array * * @dataProvider provideMalformedLengthOperands */ - public function parsesArithmeticWithMalformedOperandsInFunctions(string $leftOperand, string $rightOperand): void + public function parsesArithmeticWithMalformedOperandsInFunctions(string $leftOperand, string $rightOperand) { $subject = Value::parseValue(new ParserState( 'max(300px, ' . $leftOperand . ' + ' . $rightOperand . ');', From fe8759b07430414e7f2e1083175a19ab67f81e9d Mon Sep 17 00:00:00 2001 From: Jake Hotson Date: Fri, 28 Jun 2024 01:39:57 +0100 Subject: [PATCH 4/4] Remove parameter types for PHP5. --- tests/Value/ValueTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Value/ValueTest.php b/tests/Value/ValueTest.php index add1ad1a..ac259466 100644 --- a/tests/Value/ValueTest.php +++ b/tests/Value/ValueTest.php @@ -22,7 +22,7 @@ public static function provideArithmeticOperator() return \array_combine( $units, \array_map( - function (string $unit) { + function ($unit) { return [$unit]; }, $units @@ -35,7 +35,7 @@ function (string $unit) { * * @dataProvider provideArithmeticOperator */ - public function parsesArithmeticInFunctions(string $operator) + public function parsesArithmeticInFunctions($operator) { $subject = Value::parseValue(new ParserState('max(300px, 50vh ' . $operator . ' 10px);', Settings::create())); @@ -67,8 +67,8 @@ public static function provideCssFunctionTemplates() * @dataProvider provideCssFunctionTemplates */ public function parsesArithmeticWithMultipleOperatorsInFunctions( - string $parserTemplate, - string $expectedResultTemplate + $parserTemplate, + $expectedResultTemplate ) { static $expression = '300px + 10% + 10vw'; @@ -95,7 +95,7 @@ public static function provideMalformedLengthOperands() * * @dataProvider provideMalformedLengthOperands */ - public function parsesArithmeticWithMalformedOperandsInFunctions(string $leftOperand, string $rightOperand) + public function parsesArithmeticWithMalformedOperandsInFunctions($leftOperand, $rightOperand) { $subject = Value::parseValue(new ParserState( 'max(300px, ' . $leftOperand . ' + ' . $rightOperand . ');',