Skip to content

Commit 104b94d

Browse files
authored
[TASK] Add Selector\Combinator class (#1487)
1 parent 0066316 commit 104b94d

2 files changed

Lines changed: 414 additions & 0 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sabberworm\CSS\Property\Selector;
6+
7+
use Sabberworm\CSS\Comment\Comment;
8+
use Sabberworm\CSS\OutputFormat;
9+
use Sabberworm\CSS\Parsing\ParserState;
10+
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
11+
use Sabberworm\CSS\Renderable;
12+
use Sabberworm\CSS\ShortClassNameProvider;
13+
14+
/**
15+
* Class representing a CSS selector combinator (space, `>`, `+`, or `~`).
16+
*
17+
* @phpstan-type ValidCombinatorValue ' '|'>'|'+'|'~'
18+
*/
19+
class Combinator implements Component, Renderable
20+
{
21+
use ShortClassNameProvider;
22+
23+
/**
24+
* @var ValidCombinatorValue
25+
*/
26+
private $value;
27+
28+
/**
29+
* @param ValidCombinatorValue $value
30+
*/
31+
public function __construct(string $value)
32+
{
33+
$this->setValue($value);
34+
}
35+
36+
/**
37+
* @param list<Comment> $comments
38+
*
39+
* @throws UnexpectedTokenException
40+
*
41+
* @internal
42+
*/
43+
public static function parse(ParserState $parserState, array &$comments = []): self
44+
{
45+
$consumedWhitespace = $parserState->consumeWhiteSpace($comments);
46+
47+
$nextToken = $parserState->peek();
48+
if (\in_array($nextToken, ['>', '+', '~'], true)) {
49+
$value = $nextToken;
50+
$parserState->consume(1);
51+
$parserState->consumeWhiteSpace($comments);
52+
} elseif ($consumedWhitespace !== '') {
53+
$value = ' ';
54+
} else {
55+
throw new UnexpectedTokenException(
56+
'combinator',
57+
$nextToken,
58+
'literal',
59+
$parserState->currentLine()
60+
);
61+
}
62+
63+
return new self($value);
64+
}
65+
66+
/**
67+
* @return ValidCombinatorValue
68+
*/
69+
public function getValue(): string
70+
{
71+
return $this->value;
72+
}
73+
74+
/**
75+
* @param non-empty-string $value
76+
*
77+
* @throws \UnexpectedValueException if `$value` is not either space, '>', '+' or '~'
78+
*/
79+
public function setValue(string $value): void
80+
{
81+
if (!\in_array($value, [' ', '>', '+', '~'], true)) {
82+
throw new \UnexpectedValueException('`' . $value . '` is not a valid selector combinator.');
83+
}
84+
85+
$this->value = $value;
86+
}
87+
88+
/**
89+
* @return int<0, max>
90+
*/
91+
public function getSpecificity(): int
92+
{
93+
return 0;
94+
}
95+
96+
public function render(OutputFormat $outputFormat): string
97+
{
98+
// TODO: allow optional spacing controlled via OutputFormat
99+
return $this->getValue();
100+
}
101+
102+
/**
103+
* @return array<string, bool|int|float|string|array<mixed>|null>
104+
*
105+
* @internal
106+
*/
107+
public function getArrayRepresentation(): array
108+
{
109+
return [
110+
'class' => $this->getShortClassName(),
111+
'value' => $this->value,
112+
];
113+
}
114+
}

0 commit comments

Comments
 (0)