Skip to content

Commit

Permalink
[FEATURE] Support arithmetic operators in CSS functions (#607)
Browse files Browse the repository at this point in the history
This is the enhancement from #390.

`calc` was already supported.

Closes #390
  • Loading branch information
JakeQZ authored Jun 23, 2024
1 parent 046ab81 commit dddbba0
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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 a class diagram to the README (#482)
- Add support for the `dvh`, `lvh` and `svh` length units (#415)
Expand Down
11 changes: 10 additions & 1 deletion src/Value/Value.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,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;
Expand Down
109 changes: 109 additions & 0 deletions tests/Value/ValueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

declare(strict_types=1);

namespace Sabberworm\CSS\Tests\Value;

use PHPUnit\Framework\TestCase;
use Sabberworm\CSS\Parsing\ParserState;
use Sabberworm\CSS\Settings;
use Sabberworm\CSS\Value\Value;

/**
* @covers \Sabberworm\CSS\Value\Value
*/
final class ValueTest extends TestCase
{
/**
* @return array<string, array{0: string}>
*/
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<string, array{0: string, 1: string}>
* 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<string, array{0: string, 1: string}>
*/
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);
}
}

0 comments on commit dddbba0

Please sign in to comment.