• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MyIntervals / PHP-CSS-Parser / 21949973460

12 Feb 2026 02:10PM UTC coverage: 72.779% (-0.03%) from 72.813%
21949973460

Pull #1508

github

web-flow
Merge cdee95362 into 1ce344765
Pull Request #1508: [TASK] Rename `Rule\Rule` to `Property\Declaration`

36 of 77 new or added lines in 2 files covered. (46.75%)

1548 of 2127 relevant lines covered (72.78%)

33.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.37
/src/Property/Declaration.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Sabberworm\CSS\Property;
6

7
use Sabberworm\CSS\Comment\Comment;
8
use Sabberworm\CSS\Comment\Commentable;
9
use Sabberworm\CSS\Comment\CommentContainer;
10
use Sabberworm\CSS\CSSElement;
11
use Sabberworm\CSS\OutputFormat;
12
use Sabberworm\CSS\Parsing\ParserState;
13
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
14
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
15
use Sabberworm\CSS\Position\Position;
16
use Sabberworm\CSS\Position\Positionable;
17
use Sabberworm\CSS\Value\RuleValueList;
18
use Sabberworm\CSS\Value\Value;
19

20
use function Safe\preg_match;
21

22
/**
23
 * `Declaration`s just have a string key (the property name) and a 'Value'.
24
 *
25
 * In CSS, `Declaration`s are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
26
 */
27
class Declaration implements Commentable, CSSElement, Positionable
28
{
29
    use CommentContainer;
30
    use Position;
31

32
    /**
33
     * @var non-empty-string
34
     */
35
    private $propertyName;
36

37
    /**
38
     * @var RuleValueList|string|null
39
     */
40
    private $value;
41

42
    /**
43
     * @var bool
44
     */
45
    private $isImportant = false;
46

47
    /**
48
     * @param non-empty-string $propertyName
49
     * @param int<1, max>|null $lineNumber
50
     * @param int<0, max>|null $columnNumber
51
     */
52
    public function __construct(string $propertyName, ?int $lineNumber = null, ?int $columnNumber = null)
3✔
53
    {
54
        $this->propertyName = $propertyName;
3✔
55
        $this->setPosition($lineNumber, $columnNumber);
3✔
56
    }
3✔
57

58
    /**
59
     * @param list<Comment> $commentsBefore
60
     *
61
     * @throws UnexpectedEOFException
62
     * @throws UnexpectedTokenException
63
     *
64
     * @internal since V8.8.0
65
     */
66
    public static function parse(ParserState $parserState, array $commentsBefore = []): self
1✔
67
    {
68
        $comments = $commentsBefore;
1✔
69
        $parserState->consumeWhiteSpace($comments);
1✔
70
        $declaration = new self(
1✔
71
            $parserState->parseIdentifier(!$parserState->comes('--')),
1✔
72
            $parserState->currentLine(),
1✔
73
            $parserState->currentColumn()
1✔
74
        );
75
        $parserState->consumeWhiteSpace($comments);
1✔
76
        $declaration->setComments($comments);
1✔
77
        $parserState->consume(':');
1✔
78
        $value = Value::parseValue($parserState, self::getDelimitersForPropertyValue($declaration->getPropertyName()));
1✔
79
        $declaration->setValue($value);
1✔
80
        $parserState->consumeWhiteSpace();
1✔
81
        if ($parserState->comes('!')) {
1✔
NEW
82
            $parserState->consume('!');
×
NEW
83
            $parserState->consumeWhiteSpace();
×
NEW
84
            $parserState->consume('important');
×
NEW
85
            $declaration->setIsImportant(true);
×
86
        }
87
        $parserState->consumeWhiteSpace();
1✔
88
        while ($parserState->comes(';')) {
1✔
89
            $parserState->consume(';');
1✔
90
        }
91

92
        return $declaration;
1✔
93
    }
94

95
    /**
96
     * Returns a list of delimiters (or separators).
97
     * The first item is the innermost separator (or, put another way, the highest-precedence operator).
98
     * The sequence continues to the outermost separator (or lowest-precedence operator).
99
     *
100
     * @param non-empty-string $propertyName
101
     *
102
     * @return list<non-empty-string>
103
     */
104
    private static function getDelimitersForPropertyValue(string $propertyName): array
1✔
105
    {
106
        if (preg_match('/^font($|-)/', $propertyName) === 1) {
1✔
NEW
107
            return [',', '/', ' '];
×
108
        }
109

110
        switch ($propertyName) {
1✔
111
            case 'src':
1✔
112
                return [' ', ','];
1✔
113
            default:
NEW
114
                return [',', ' ', '/'];
×
115
        }
116
    }
117

118
    /**
119
     * @param non-empty-string $propertyName
120
     */
NEW
121
    public function setPropertyName(string $propertyName): void
×
122
    {
NEW
123
        $this->propertyName = $propertyName;
×
NEW
124
    }
×
125

126
    /**
127
     * @return non-empty-string
128
     */
129
    public function getPropertyName(): string
1✔
130
    {
131
        return $this->propertyName;
1✔
132
    }
133

134
    /**
135
     * @param non-empty-string $propertyName
136
     *
137
     * @deprecated in v9.2, will be removed in v10.0; use `setPropertyName()` instead.
138
     */
NEW
139
    public function setRule(string $propertyName): void
×
140
    {
NEW
141
        $this->propertyName = $propertyName;
×
NEW
142
    }
×
143

144
    /**
145
     * @return non-empty-string
146
     *
147
     * @deprecated in v9.2, will be removed in v10.0; use `getPropertyName()` instead.
148
     */
NEW
149
    public function getRule(): string
×
150
    {
NEW
151
        return $this->propertyName;
×
152
    }
153

154
    /**
155
     * @return RuleValueList|string|null
156
     */
157
    public function getValue()
1✔
158
    {
159
        return $this->value;
1✔
160
    }
161

162
    /**
163
     * @param RuleValueList|string|null $value
164
     */
165
    public function setValue($value): void
1✔
166
    {
167
        $this->value = $value;
1✔
168
    }
1✔
169

170
    /**
171
     * Adds a value to the existing value. Value will be appended if a `RuleValueList` exists of the given type.
172
     * Otherwise, the existing value will be wrapped by one.
173
     *
174
     * @param RuleValueList|array<int, RuleValueList> $value
175
     */
NEW
176
    public function addValue($value, string $type = ' '): void
×
177
    {
NEW
178
        if (!\is_array($value)) {
×
NEW
179
            $value = [$value];
×
180
        }
NEW
181
        if (!($this->value instanceof RuleValueList) || $this->value->getListSeparator() !== $type) {
×
NEW
182
            $currentValue = $this->value;
×
NEW
183
            $this->value = new RuleValueList($type, $this->getLineNumber());
×
NEW
184
            if ($currentValue !== null && $currentValue !== '') {
×
NEW
185
                $this->value->addListComponent($currentValue);
×
186
            }
187
        }
NEW
188
        foreach ($value as $valueItem) {
×
NEW
189
            $this->value->addListComponent($valueItem);
×
190
        }
NEW
191
    }
×
192

NEW
193
    public function setIsImportant(bool $isImportant): void
×
194
    {
NEW
195
        $this->isImportant = $isImportant;
×
NEW
196
    }
×
197

NEW
198
    public function getIsImportant(): bool
×
199
    {
NEW
200
        return $this->isImportant;
×
201
    }
202

203
    /**
204
     * @return non-empty-string
205
     */
NEW
206
    public function render(OutputFormat $outputFormat): string
×
207
    {
NEW
208
        $formatter = $outputFormat->getFormatter();
×
NEW
209
        $result = "{$formatter->comments($this)}{$this->propertyName}:{$formatter->spaceAfterRuleName()}";
×
NEW
210
        if ($this->value instanceof Value) { // Can also be a ValueList
×
NEW
211
            $result .= $this->value->render($outputFormat);
×
212
        } else {
NEW
213
            $result .= $this->value;
×
214
        }
NEW
215
        if ($this->isImportant) {
×
NEW
216
            $result .= ' !important';
×
217
        }
NEW
218
        $result .= ';';
×
NEW
219
        return $result;
×
220
    }
221

222
    /**
223
     * @return array<string, bool|int|float|string|array<mixed>|null>
224
     *
225
     * @internal
226
     */
227
    public function getArrayRepresentation(): array
1✔
228
    {
229
        throw new \BadMethodCallException('`getArrayRepresentation` is not yet implemented for `' . self::class . '`');
1✔
230
    }
231
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc