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

MyIntervals / PHP-CSS-Parser / 29003399430

09 Jul 2026 08:02AM UTC coverage: 71.517% (-1.1%) from 72.604%
29003399430

Pull #1484

github

web-flow
Merge 3a5543ec6 into 3316f7374
Pull Request #1484: Remove `thecodingmachine/safe` dependency

25 of 78 new or added lines in 12 files covered. (32.05%)

7 existing lines in 5 files now uncovered.

1622 of 2268 relevant lines covered (71.52%)

37.55 hits per line

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

53.66
/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\ShortClassNameProvider;
18
use Sabberworm\CSS\Value\RuleValueList;
19
use Sabberworm\CSS\Value\Value;
20

21
/**
22
 * `Declaration`s just have a string key (the property name) and a 'Value'.
23
 *
24
 * In CSS, `Declaration`s are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
25
 */
26
class Declaration implements Commentable, CSSElement, Positionable
27
{
28
    use CommentContainer;
29
    use Position;
30
    use ShortClassNameProvider;
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)
8✔
53
    {
54
        $this->propertyName = $propertyName;
8✔
55
        $this->setPosition($lineNumber, $columnNumber);
8✔
56
    }
8✔
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✔
82
            $parserState->consume('!');
×
83
            $parserState->consumeWhiteSpace();
×
84
            $parserState->consume('important');
×
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
        /** @phpstan-ignore theCodingMachineSafe.function */
107
        $matchResult = \preg_match('/^font($|-)/', $propertyName);
1✔
108
        if ($matchResult === false) {
1✔
NEW
109
            throw new \RuntimeException('Unexpected error');
×
110
        }
111
        if ($matchResult === 1) {
1✔
UNCOV
112
            return [',', '/', ' '];
×
113
        }
114

115
        switch ($propertyName) {
1✔
116
            case 'src':
1✔
117
                return [' ', ','];
1✔
118
            default:
119
                return [',', ' ', '/'];
×
120
        }
121
    }
122

123
    /**
124
     * @param non-empty-string $propertyName
125
     */
126
    public function setPropertyName(string $propertyName): void
×
127
    {
128
        $this->propertyName = $propertyName;
×
129
    }
×
130

131
    /**
132
     * @return non-empty-string
133
     */
134
    public function getPropertyName(): string
1✔
135
    {
136
        return $this->propertyName;
1✔
137
    }
138

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

149
    /**
150
     * @return non-empty-string
151
     *
152
     * @deprecated in v9.2, will be removed in v10.0; use `getPropertyName()` instead.
153
     */
154
    public function getRule(): string
×
155
    {
156
        return $this->propertyName;
×
157
    }
158

159
    /**
160
     * @return RuleValueList|string|null
161
     */
162
    public function getValue()
1✔
163
    {
164
        return $this->value;
1✔
165
    }
166

167
    /**
168
     * @param RuleValueList|string|null $value
169
     */
170
    public function setValue($value): void
2✔
171
    {
172
        $this->value = $value;
2✔
173
    }
2✔
174

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

198
    public function setIsImportant(bool $isImportant): void
2✔
199
    {
200
        $this->isImportant = $isImportant;
2✔
201
    }
2✔
202

203
    public function getIsImportant(): bool
×
204
    {
205
        return $this->isImportant;
×
206
    }
207

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

227
    /**
228
     * @return array<string, bool|int|float|string|array<mixed>|null>
229
     *
230
     * @internal
231
     */
232
    public function getArrayRepresentation(): array
5✔
233
    {
234
        return [
235
            'class' => $this->getShortClassName(),
5✔
236
            'propertyName' => $this->propertyName,
5✔
237
            // We're using the term "property value" here to match the wording used in the specs:
238
            // https://www.w3.org/TR/CSS22/syndata.html#declaration
239
            'propertyValue' => $this->value,
5✔
240
            'important' => $this->isImportant,
5✔
241
        ];
242
    }
243
}
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