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

MyIntervals / PHP-CSS-Parser / 13539082239

26 Feb 2025 07:57AM UTC coverage: 54.784%. Remained the same
13539082239

Pull #1002

github

web-flow
Merge b8b058c9b into b3abf1a5d
Pull Request #1002: [CLEANUP] Avoid Hungarian notation in `DeclarationBlock`

17 of 19 new or added lines in 1 file covered. (89.47%)

1042 of 1902 relevant lines covered (54.78%)

12.13 hits per line

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

89.71
/src/RuleSet/DeclarationBlock.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Sabberworm\CSS\RuleSet;
6

7
use Sabberworm\CSS\CSSList\CSSList;
8
use Sabberworm\CSS\CSSList\KeyFrame;
9
use Sabberworm\CSS\OutputFormat;
10
use Sabberworm\CSS\Parsing\OutputException;
11
use Sabberworm\CSS\Parsing\ParserState;
12
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
13
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
14
use Sabberworm\CSS\Property\KeyframeSelector;
15
use Sabberworm\CSS\Property\Selector;
16

17
/**
18
 * This class represents a `RuleSet` constrained by a `Selector`.
19
 *
20
 * It contains an array of selector objects (comma-separated in the CSS) as well as the rules to be applied to the
21
 * matching elements.
22
 *
23
 * Declaration blocks usually appear directly inside a `Document` or another `CSSList` (mostly a `MediaQuery`).
24
 */
25
class DeclarationBlock extends RuleSet
26
{
27
    /**
28
     * @var array<int, Selector|string>
29
     */
30
    private $selectors = [];
31

32
    /**
33
     * @param CSSList|null $list
34
     *
35
     * @return DeclarationBlock|false
36
     *
37
     * @throws UnexpectedTokenException
38
     * @throws UnexpectedEOFException
39
     *
40
     * @internal since V8.8.0
41
     */
42
    public static function parse(ParserState $parserState, $list = null)
64✔
43
    {
44
        $comments = [];
64✔
45
        $result = new DeclarationBlock($parserState->currentLine());
64✔
46
        try {
47
            $aSelectorParts = [];
64✔
48
            do {
49
                $aSelectorParts[] = $parserState->consume(1)
64✔
50
                    . $parserState->consumeUntil(['{', '}', '\'', '"'], false, false, $comments);
63✔
51
                if (\in_array($parserState->peek(), ['\'', '"'], true) && \substr(\end($aSelectorParts), -1) != '\\') {
62✔
52
                    if (!isset($stringWrapperCharacter)) {
4✔
53
                        $stringWrapperCharacter = $parserState->peek();
4✔
54
                    } elseif ($stringWrapperCharacter === $parserState->peek()) {
4✔
55
                        unset($stringWrapperCharacter);
4✔
56
                    }
57
                }
58
            } while (!\in_array($parserState->peek(), ['{', '}'], true) || isset($stringWrapperCharacter));
62✔
59
            $result->setSelectors(\implode('', $aSelectorParts), $list);
62✔
60
            if ($parserState->comes('{')) {
62✔
61
                $parserState->consume(1);
62✔
62
            }
63
        } catch (UnexpectedTokenException $e) {
8✔
64
            if ($parserState->getSettings()->bLenientParsing) {
8✔
65
                if (!$parserState->comes('}')) {
6✔
66
                    $parserState->consumeUntil('}', false, true);
6✔
67
                }
68
                return false;
4✔
69
            } else {
70
                throw $e;
2✔
71
            }
72
        }
73
        $result->setComments($comments);
62✔
74
        RuleSet::parseRuleSet($parserState, $result);
62✔
75
        return $result;
55✔
76
    }
77

78
    /**
79
     * @param array<int, Selector|string>|string $selector
80
     * @param CSSList|null $list
81
     *
82
     * @throws UnexpectedTokenException
83
     */
84
    public function setSelectors($selector, $list = null): void
62✔
85
    {
86
        if (\is_array($selector)) {
62✔
NEW
87
            $this->selectors = $selector;
×
88
        } else {
89
            $this->selectors = \explode(',', $selector);
62✔
90
        }
91
        foreach ($this->selectors as $key => $selector) {
62✔
92
            if (!($selector instanceof Selector)) {
62✔
93
                if ($list === null || !($list instanceof KeyFrame)) {
62✔
94
                    if (!Selector::isValid($selector)) {
61✔
95
                        throw new UnexpectedTokenException(
4✔
96
                            "Selector did not match '" . Selector::SELECTOR_VALIDATION_RX . "'.",
4✔
97
                            $selector,
98
                            'custom'
4✔
99
                        );
100
                    }
101
                    $this->selectors[$key] = new Selector($selector);
61✔
102
                } else {
103
                    if (!KeyframeSelector::isValid($selector)) {
6✔
104
                        throw new UnexpectedTokenException(
×
105
                            "Selector did not match '" . KeyframeSelector::SELECTOR_VALIDATION_RX . "'.",
×
106
                            $selector,
107
                            'custom'
×
108
                        );
109
                    }
110
                    $this->selectors[$key] = new KeyframeSelector($selector);
6✔
111
                }
112
            }
113
        }
114
    }
62✔
115

116
    /**
117
     * Remove one of the selectors of the block.
118
     *
119
     * @param Selector|string $selector
120
     */
121
    public function removeSelector($selector): bool
1✔
122
    {
123
        if ($selector instanceof Selector) {
1✔
NEW
124
            $selector = $selector->getSelector();
×
125
        }
126
        foreach ($this->selectors as $key => $subSelector) {
1✔
127
            if ($subSelector->getSelector() === $selector) {
1✔
128
                unset($this->selectors[$key]);
1✔
129
                return true;
1✔
130
            }
131
        }
132
        return false;
1✔
133
    }
134

135
    /**
136
     * @return array<int, Selector|string>
137
     */
138
    public function getSelectors()
6✔
139
    {
140
        return $this->selectors;
6✔
141
    }
142

143
    /**
144
     * @throws OutputException
145
     */
146
    public function __toString(): string
×
147
    {
148
        return $this->render(new OutputFormat());
×
149
    }
150

151
    /**
152
     * @throws OutputException
153
     */
154
    public function render(OutputFormat $outputFormat): string
42✔
155
    {
156
        $result = $outputFormat->comments($this);
42✔
157
        if (\count($this->selectors) === 0) {
42✔
158
            // If all the selectors have been removed, this declaration block becomes invalid
159
            throw new OutputException('Attempt to print declaration block with missing selector', $this->lineNumber);
1✔
160
        }
161
        $result .= $outputFormat->sBeforeDeclarationBlock;
42✔
162
        $result .= $outputFormat->implode(
42✔
163
            $outputFormat->spaceBeforeSelectorSeparator() . ',' . $outputFormat->spaceAfterSelectorSeparator(),
42✔
164
            $this->selectors
42✔
165
        );
166
        $result .= $outputFormat->sAfterDeclarationBlockSelectors;
42✔
167
        $result .= $outputFormat->spaceBeforeOpeningBrace() . '{';
42✔
168
        $result .= $this->renderRules($outputFormat);
42✔
169
        $result .= '}';
42✔
170
        $result .= $outputFormat->sAfterDeclarationBlock;
42✔
171
        return $result;
42✔
172
    }
173
}
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