Skip to content

Commit 913f196

Browse files
committed
[FEATURE] Support arithmetic operators in CSS functions
This is the enhancement from #390.
1 parent a06d326 commit 913f196

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

src/Value/Value.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,16 @@ public static function parsePrimitiveValue(ParserState $oParserState)
164164
} elseif ($oParserState->comes("U+")) {
165165
$oValue = self::parseUnicodeRangeValue($oParserState);
166166
} else {
167-
$oValue = self::parseIdentifierOrFunction($oParserState);
167+
$sNextChar = $oParserState->peek(1);
168+
try {
169+
$oValue = self::parseIdentifierOrFunction($oParserState);
170+
} catch (UnexpectedTokenException $e) {
171+
if (\in_array($sNextChar, ['+', '-', '*', '/'], true)) {
172+
$oValue = $oParserState->consume(1);
173+
} else {
174+
throw $e;
175+
}
176+
}
168177
}
169178
$oParserState->consumeWhiteSpace();
170179
return $oValue;

tests/Value/ValueTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
namespace Sabberworm\CSS\Tests\Value;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Sabberworm\CSS\Parsing\ParserState;
7+
use Sabberworm\CSS\Settings;
8+
use Sabberworm\CSS\Value\Value;
9+
10+
/**
11+
* @covers \Sabberworm\CSS\Value\Value
12+
*/
13+
final class ValueTest extends TestCase
14+
{
15+
/**
16+
* @return array<string, array{0: string}>
17+
*/
18+
public static function provideArithmeticOperator(): array
19+
{
20+
$units = ['+', '-', '*', '/'];
21+
22+
return \array_combine(
23+
$units,
24+
\array_map(
25+
function (string $unit): array {
26+
return [$unit];
27+
},
28+
$units
29+
)
30+
);
31+
}
32+
33+
/**
34+
* @test
35+
*
36+
* @dataProvider provideArithmeticOperator
37+
*/
38+
public function parsesArithmeticInFunctions(string $operator): void
39+
{
40+
$subject = Value::parseValue(new ParserState('max(300px, 50vh ' . $operator . ' 10px);', Settings::create()));
41+
42+
self::assertSame('max(300px,50vh ' . $operator . ' 10px)', (string) $subject);
43+
}
44+
45+
/**
46+
* @test
47+
*/
48+
public function parsesArithmeticWithMultipleOperatorsInFunctions(): void
49+
{
50+
$subject = Value::parseValue(new ParserState('calc(300px + 10% + 10vw);', Settings::create()));
51+
52+
self::assertSame('calc(300px + 10% + 10vw)', (string) $subject);
53+
}
54+
55+
/**
56+
* @return array<string, array{0: string, 1: string}>
57+
*/
58+
public static function provideMalformedLengthOperands(): array
59+
{
60+
return [
61+
'LHS missing value' => ['vh', '10px'],
62+
'RHS missing value' => ['50vh', 'px'],
63+
'LHS missing unit' => ['50', '10px'],
64+
'RHS missing unit' => ['50vh', '10'],
65+
];
66+
}
67+
68+
/**
69+
* @test
70+
*
71+
* @dataProvider provideMalformedLengthOperands
72+
*/
73+
public function parsesArithmeticWithMalformedOperandsInFunctions(string $leftOperand, string $rightOperand): void
74+
{
75+
$subject = Value::parseValue(new ParserState(
76+
'max(300px, ' . $leftOperand . ' + ' . $rightOperand . ');',
77+
Settings::create()
78+
));
79+
80+
self::assertSame('max(300px,' . $leftOperand . ' + ' . $rightOperand . ')', (string) $subject);
81+
}
82+
}

0 commit comments

Comments
 (0)