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

MyIntervals / PHP-CSS-Parser / 12820464988

17 Jan 2025 12:55AM UTC coverage: 39.862% (+1.3%) from 38.583%
12820464988

Pull #790

github

web-flow
Merge defbc9eb2 into d783f0e94
Pull Request #790: [BUGFIX] Parse @font-face src property as comma-delimited list

3 of 4 new or added lines in 1 file covered. (75.0%)

27 existing lines in 1 file now uncovered.

806 of 2022 relevant lines covered (39.86%)

5.34 hits per line

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

50.94
/src/Rule/Rule.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Sabberworm\CSS\Rule;
6

7
use Sabberworm\CSS\Comment\Comment;
8
use Sabberworm\CSS\Comment\Commentable;
9
use Sabberworm\CSS\OutputFormat;
10
use Sabberworm\CSS\Parsing\ParserState;
11
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
12
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
13
use Sabberworm\CSS\Renderable;
14
use Sabberworm\CSS\Value\RuleValueList;
15
use Sabberworm\CSS\Value\Value;
16

17
/**
18
 * `Rule`s just have a string key (the rule) and a 'Value'.
19
 *
20
 * In CSS, `Rule`s are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
21
 */
22
class Rule implements Renderable, Commentable
23
{
24
    /**
25
     * @var string
26
     */
27
    private $sRule;
28

29
    /**
30
     * @var RuleValueList|string|null
31
     */
32
    private $mValue;
33

34
    /**
35
     * @var bool
36
     */
37
    private $bIsImportant;
38

39
    /**
40
     * @var array<int, int>
41
     */
42
    private $aIeHack;
43

44
    /**
45
     * @var int
46
     */
47
    protected $iLineNo;
48

49
    /**
50
     * @var int
51
     */
52
    protected $iColNo;
53

54
    /**
55
     * @var array<array-key, Comment>
56
     */
57
    protected $aComments;
58

59
    /**
60
     * @param string $sRule
61
     * @param int $iLineNo
62
     * @param int $iColNo
63
     */
64
    public function __construct($sRule, $iLineNo = 0, $iColNo = 0)
1✔
65
    {
66
        $this->sRule = $sRule;
1✔
67
        $this->mValue = null;
1✔
68
        $this->bIsImportant = false;
1✔
69
        $this->aIeHack = [];
1✔
70
        $this->iLineNo = $iLineNo;
1✔
71
        $this->iColNo = $iColNo;
1✔
72
        $this->aComments = [];
1✔
73
    }
1✔
74

75
    /**
76
     * @throws UnexpectedEOFException
77
     * @throws UnexpectedTokenException
78
     */
79
    public static function parse(ParserState $oParserState): Rule
60✔
80
    {
81
        $aComments = $oParserState->consumeWhiteSpace();
60✔
82
        $oRule = new Rule(
60✔
83
            $oParserState->parseIdentifier(!$oParserState->comes('--')),
60✔
84
            $oParserState->currentLine(),
59✔
85
            $oParserState->currentColumn()
59✔
86
        );
87
        $oRule->setComments($aComments);
59✔
88
        $oRule->addComments($oParserState->consumeWhiteSpace());
59✔
89
        $oParserState->consume(':');
59✔
90
        $oValue = Value::parseValue($oParserState, self::listDelimiterForRule($oRule->getRule()));
59✔
91
        $oRule->setValue($oValue);
53✔
92
        if ($oParserState->getSettings()->bLenientParsing) {
53✔
93
            while ($oParserState->comes('\\')) {
48✔
94
                $oParserState->consume('\\');
2✔
95
                $oRule->addIeHack($oParserState->consume());
2✔
96
                $oParserState->consumeWhiteSpace();
2✔
97
            }
98
        }
99
        $oParserState->consumeWhiteSpace();
53✔
100
        if ($oParserState->comes('!')) {
53✔
101
            $oParserState->consume('!');
8✔
102
            $oParserState->consumeWhiteSpace();
8✔
103
            $oParserState->consume('important');
8✔
104
            $oRule->setIsImportant(true);
8✔
105
        }
106
        $oParserState->consumeWhiteSpace();
53✔
107
        while ($oParserState->comes(';')) {
53✔
108
            $oParserState->consume(';');
50✔
109
        }
110

111
        $oParserState->consumeWhiteSpace();
53✔
112

113
        return $oRule;
53✔
114
    }
115

116
    /**
117
     * @param string $sRule
118
     *
119
     * @return array<int, string>
120
     * The first item is the innermost separator (or, put another way, the highest-precedence operator).
121
     * The sequence continues to the outermost separator (or lowest-precedence operator).
122
     */
123
    private static function listDelimiterForRule($sRule): array
1✔
124
    {
125
        if (\preg_match('/^font($|-)/', $sRule)) {
1✔
UNCOV
126
            return [',', '/', ' '];
×
127
        }
128

129
        switch ($sRule) {
1✔
130
            case 'src':
1✔
131
                return [' ', ','];
1✔
132
            default:
NEW
133
                return [',', ' ', '/'];
×
134
        }
135
    }
136

137
    /**
138
     * @return int
139
     */
UNCOV
140
    public function getLineNo()
×
141
    {
142
        return $this->iLineNo;
×
143
    }
144

145
    /**
146
     * @return int
147
     */
UNCOV
148
    public function getColNo()
×
149
    {
150
        return $this->iColNo;
×
151
    }
152

153
    /**
154
     * @param int $iLine
155
     * @param int $iColumn
156
     */
UNCOV
157
    public function setPosition($iLine, $iColumn): void
×
158
    {
159
        $this->iColNo = $iColumn;
×
UNCOV
160
        $this->iLineNo = $iLine;
×
161
    }
×
162

163
    /**
164
     * @param string $sRule
165
     */
UNCOV
166
    public function setRule($sRule): void
×
167
    {
168
        $this->sRule = $sRule;
×
UNCOV
169
    }
×
170

171
    /**
172
     * @return string
173
     */
174
    public function getRule()
1✔
175
    {
176
        return $this->sRule;
1✔
177
    }
178

179
    /**
180
     * @return RuleValueList|string|null
181
     */
182
    public function getValue()
1✔
183
    {
184
        return $this->mValue;
1✔
185
    }
186

187
    /**
188
     * @param RuleValueList|string|null $mValue
189
     */
190
    public function setValue($mValue): void
1✔
191
    {
192
        $this->mValue = $mValue;
1✔
193
    }
1✔
194

195
    /**
196
     * Adds a value to the existing value. Value will be appended if a `RuleValueList` exists of the given type.
197
     * Otherwise, the existing value will be wrapped by one.
198
     *
199
     * @param RuleValueList|array<int, RuleValueList> $mValue
200
     * @param string $sType
201
     */
UNCOV
202
    public function addValue($mValue, $sType = ' '): void
×
203
    {
204
        if (!\is_array($mValue)) {
×
UNCOV
205
            $mValue = [$mValue];
×
206
        }
207
        if (!$this->mValue instanceof RuleValueList || $this->mValue->getListSeparator() !== $sType) {
×
UNCOV
208
            $mCurrentValue = $this->mValue;
×
209
            $this->mValue = new RuleValueList($sType, $this->iLineNo);
×
210
            if ($mCurrentValue) {
×
211
                $this->mValue->addListComponent($mCurrentValue);
×
212
            }
213
        }
UNCOV
214
        foreach ($mValue as $mValueItem) {
×
UNCOV
215
            $this->mValue->addListComponent($mValueItem);
×
216
        }
217
    }
×
218

219
    /**
220
     * @param int $iModifier
221
     */
UNCOV
222
    public function addIeHack($iModifier): void
×
223
    {
224
        $this->aIeHack[] = $iModifier;
×
UNCOV
225
    }
×
226

227
    /**
228
     * @param array<int, int> $aModifiers
229
     *
230
     * @return void
231
     */
UNCOV
232
    public function setIeHack(array $aModifiers): void
×
233
    {
234
        $this->aIeHack = $aModifiers;
×
UNCOV
235
    }
×
236

237
    /**
238
     * @return array<int, int>
239
     */
UNCOV
240
    public function getIeHack()
×
241
    {
242
        return $this->aIeHack;
×
243
    }
244

245
    /**
246
     * @param bool $bIsImportant
247
     */
UNCOV
248
    public function setIsImportant($bIsImportant): void
×
249
    {
250
        $this->bIsImportant = $bIsImportant;
×
UNCOV
251
    }
×
252

253
    /**
254
     * @return bool
255
     */
UNCOV
256
    public function getIsImportant()
×
257
    {
258
        return $this->bIsImportant;
×
259
    }
260

UNCOV
261
    public function __toString(): string
×
262
    {
263
        return $this->render(new OutputFormat());
×
264
    }
265

UNCOV
266
    public function render(OutputFormat $oOutputFormat): string
×
267
    {
268
        $sResult = "{$oOutputFormat->comments($this)}{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}";
×
UNCOV
269
        if ($this->mValue instanceof Value) { // Can also be a ValueList
×
270
            $sResult .= $this->mValue->render($oOutputFormat);
×
271
        } else {
272
            $sResult .= $this->mValue;
×
273
        }
274
        if (!empty($this->aIeHack)) {
×
UNCOV
275
            $sResult .= ' \\' . \implode('\\', $this->aIeHack);
×
276
        }
277
        if ($this->bIsImportant) {
×
UNCOV
278
            $sResult .= ' !important';
×
279
        }
280
        $sResult .= ';';
×
UNCOV
281
        return $sResult;
×
282
    }
283

284
    /**
285
     * @param array<array-key, Comment> $aComments
286
     */
287
    public function addComments(array $aComments): void
1✔
288
    {
289
        $this->aComments = \array_merge($this->aComments, $aComments);
1✔
290
    }
1✔
291

292
    /**
293
     * @return array<array-key, Comment>
294
     */
UNCOV
295
    public function getComments()
×
296
    {
297
        return $this->aComments;
×
298
    }
299

300
    /**
301
     * @param array<array-key, Comment> $aComments
302
     */
303
    public function setComments(array $aComments): void
1✔
304
    {
305
        $this->aComments = $aComments;
1✔
306
    }
1✔
307
}
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

© 2025 Coveralls, Inc