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

MyIntervals / PHP-CSS-Parser / 14441024686

14 Apr 2025 08:28AM UTC coverage: 56.257% (+0.03%) from 56.225%
14441024686

push

github

web-flow
[CLEANUP] `allSelectors()` -> `getAllSelectors()` (#1245)

The renamed (internal) method now returns the result,
instead of having a reference parameter for it.

Closes #994.

0 of 4 new or added lines in 2 files covered. (0.0%)

998 of 1774 relevant lines covered (56.26%)

7.91 hits per line

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

58.23
/src/CSSList/CSSBlockList.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Sabberworm\CSS\CSSList;
6

7
use Sabberworm\CSS\CSSElement;
8
use Sabberworm\CSS\Property\Selector;
9
use Sabberworm\CSS\Rule\Rule;
10
use Sabberworm\CSS\RuleSet\DeclarationBlock;
11
use Sabberworm\CSS\RuleSet\RuleSet;
12
use Sabberworm\CSS\Value\CSSFunction;
13
use Sabberworm\CSS\Value\Value;
14
use Sabberworm\CSS\Value\ValueList;
15

16
/**
17
 * A `CSSBlockList` is a `CSSList` whose `DeclarationBlock`s are guaranteed to contain valid declaration blocks or
18
 * at-rules.
19
 *
20
 * Most `CSSList`s conform to this category but some at-rules (such as `@keyframes`) do not.
21
 */
22
abstract class CSSBlockList extends CSSList
23
{
24
    /**
25
     * Gets all `DeclarationBlock` objects recursively, no matter how deeply nested the selectors are.
26
     *
27
     * @return list<DeclarationBlock>
28
     */
29
    public function getAllDeclarationBlocks(): array
6✔
30
    {
31
        $result = [];
6✔
32

33
        foreach ($this->contents as $item) {
6✔
34
            if ($item instanceof DeclarationBlock) {
5✔
35
                $result[] = $item;
3✔
36
            } elseif ($item instanceof CSSBlockList) {
3✔
37
                $result = \array_merge($result, $item->getAllDeclarationBlocks());
1✔
38
            }
39
        }
40

41
        return $result;
6✔
42
    }
43

44
    /**
45
     * Returns all `RuleSet` objects recursively found in the tree, no matter how deeply nested the rule sets are.
46
     *
47
     * @return list<RuleSet>
48
     */
49
    public function getAllRuleSets(): array
9✔
50
    {
51
        $result = [];
9✔
52

53
        foreach ($this->contents as $item) {
9✔
54
            if ($item instanceof RuleSet) {
8✔
55
                $result[] = $item;
6✔
56
            } elseif ($item instanceof CSSBlockList) {
4✔
57
                $result = \array_merge($result, $item->getAllRuleSets());
2✔
58
            }
59
        }
60

61
        return $result;
9✔
62
    }
63

64
    /**
65
     * Returns all `Value` objects found recursively in `Rule`s in the tree.
66
     *
67
     * @param CSSElement|null $element
68
     *        This is the `CSSList` or `RuleSet` to start the search from (defaults to the whole document).
69
     * @param string|null $ruleSearchPattern
70
     *        This allows filtering rules by property name
71
     *        (e.g. if "color" is passed, only `Value`s from `color` properties will be returned,
72
     *        or if "font-" is provided, `Value`s from all font rules, like `font-size`, and including `font` itself,
73
     *        will be returned).
74
     * @param bool $searchInFunctionArguments whether to also return `Value` objects used as `CSSFunction` arguments.
75
     *
76
     * @return list<Value>
77
     *
78
     * @see RuleSet->getRules()
79
     */
80
    public function getAllValues(
9✔
81
        ?CSSElement $element = null,
82
        ?string $ruleSearchPattern = null,
83
        bool $searchInFunctionArguments = false
84
    ): array {
85
        $element = $element ?? $this;
9✔
86

87
        $result = [];
9✔
88
        if ($element instanceof CSSBlockList) {
9✔
89
            foreach ($element->getContents() as $contentItem) {
8✔
90
                // Statement at-rules are skipped since they do not contain values.
91
                if ($contentItem instanceof CSSElement) {
7✔
92
                    $result = \array_merge(
7✔
93
                        $result,
7✔
94
                        $this->getAllValues($contentItem, $ruleSearchPattern, $searchInFunctionArguments)
7✔
95
                    );
96
                }
97
            }
98
        } elseif ($element instanceof RuleSet) {
8✔
99
            foreach ($element->getRules($ruleSearchPattern) as $rule) {
8✔
100
                $result = \array_merge(
8✔
101
                    $result,
8✔
102
                    $this->getAllValues($rule, $ruleSearchPattern, $searchInFunctionArguments)
8✔
103
                );
104
            }
105
        } elseif ($element instanceof Rule) {
8✔
106
            $value = $element->getValue();
8✔
107
            // `string` values are discarded.
108
            if ($value instanceof CSSElement) {
8✔
109
                $result = \array_merge(
8✔
110
                    $result,
8✔
111
                    $this->getAllValues($value, $ruleSearchPattern, $searchInFunctionArguments)
8✔
112
                );
113
            }
114
        } elseif ($element instanceof ValueList) {
8✔
115
            if ($searchInFunctionArguments || !($element instanceof CSSFunction)) {
2✔
116
                foreach ($element->getListComponents() as $component) {
2✔
117
                    // `string` components are discarded.
118
                    if ($component instanceof CSSElement) {
1✔
119
                        $result = \array_merge(
1✔
120
                            $result,
1✔
121
                            $this->getAllValues($component, $ruleSearchPattern, $searchInFunctionArguments)
1✔
122
                        );
123
                    }
124
                }
125
            }
126
        } elseif ($element instanceof Value) {
7✔
127
            $result[] = $element;
7✔
128
        }
129

130
        return $result;
9✔
131
    }
132

133
    /**
134
     * @return list<Selector>
135
     */
NEW
136
    protected function getAllSelectors(?string $specificitySearch = null): array
×
137
    {
NEW
138
        $result = [];
×
139

140
        foreach ($this->getAllDeclarationBlocks() as $declarationBlock) {
×
141
            foreach ($declarationBlock->getSelectors() as $selector) {
×
142
                if ($specificitySearch === null) {
×
143
                    $result[] = $selector;
×
144
                } else {
145
                    $comparator = '===';
×
146
                    $expressionParts = \explode(' ', $specificitySearch);
×
147
                    $targetSpecificity = $expressionParts[0];
×
148
                    if (\count($expressionParts) > 1) {
×
149
                        $comparator = $expressionParts[0];
×
150
                        $targetSpecificity = $expressionParts[1];
×
151
                    }
152
                    $targetSpecificity = (int) $targetSpecificity;
×
153
                    $selectorSpecificity = $selector->getSpecificity();
×
154
                    $comparatorMatched = false;
×
155
                    switch ($comparator) {
×
156
                        case '<=':
×
157
                            $comparatorMatched = $selectorSpecificity <= $targetSpecificity;
×
158
                            break;
×
159
                        case '<':
×
160
                            $comparatorMatched = $selectorSpecificity < $targetSpecificity;
×
161
                            break;
×
162
                        case '>=':
×
163
                            $comparatorMatched = $selectorSpecificity >= $targetSpecificity;
×
164
                            break;
×
165
                        case '>':
×
166
                            $comparatorMatched = $selectorSpecificity > $targetSpecificity;
×
167
                            break;
×
168
                        default:
169
                            $comparatorMatched = $selectorSpecificity === $targetSpecificity;
×
170
                            break;
×
171
                    }
172
                    if ($comparatorMatched) {
×
173
                        $result[] = $selector;
×
174
                    }
175
                }
176
            }
177
        }
178

NEW
179
        return $result;
×
180
    }
181
}
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