-
Notifications
You must be signed in to change notification settings - Fork 144
/
Copy pathCSSBlockList.php
155 lines (143 loc) · 5.43 KB
/
CSSBlockList.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<?php
declare(strict_types=1);
namespace Sabberworm\CSS\CSSList;
use Sabberworm\CSS\CSSElement;
use Sabberworm\CSS\Property\Selector;
use Sabberworm\CSS\Rule\Rule;
use Sabberworm\CSS\RuleSet\DeclarationBlock;
use Sabberworm\CSS\RuleSet\RuleSet;
use Sabberworm\CSS\Value\CSSFunction;
use Sabberworm\CSS\Value\Value;
use Sabberworm\CSS\Value\ValueList;
/**
* A `CSSBlockList` is a `CSSList` whose `DeclarationBlock`s are guaranteed to contain valid declaration blocks or
* at-rules.
*
* Most `CSSList`s conform to this category but some at-rules (such as `@keyframes`) do not.
*/
abstract class CSSBlockList extends CSSList
{
/**
* Gets all `DeclarationBlock` objects recursively, no matter how deeply nested the selectors are.
*
* @return list<DeclarationBlock>
*/
public function getAllDeclarationBlocks(): array
{
$result = [];
foreach ($this->contents as $item) {
if ($item instanceof DeclarationBlock) {
$result[] = $item;
} elseif ($item instanceof CSSBlockList) {
$result = \array_merge($result, $item->getAllDeclarationBlocks());
}
}
return $result;
}
/**
* @param list<DeclarationBlock> $result
*/
protected function allDeclarationBlocks(array &$result): void
{
foreach ($this->contents as $item) {
if ($item instanceof DeclarationBlock) {
$result[] = $item;
} elseif ($item instanceof CSSBlockList) {
$item->allDeclarationBlocks($result);
}
}
}
/**
* Returns all `RuleSet` objects recursively found in the tree, no matter how deeply nested the rule sets are.
*
* @return list<RuleSet>
*/
public function getAllRuleSets(): array
{
$result = [];
foreach ($this->contents as $item) {
if ($item instanceof RuleSet) {
$result[] = $item;
} elseif ($item instanceof CSSBlockList) {
$result = \array_merge($result, $item->getAllRuleSets());
}
}
return $result;
}
/**
* @param CSSElement|string $element
* @param list<Value> $result
*/
protected function allValues(
$element,
array &$result,
?string $searchString = null,
bool $searchInFunctionArguments = false
): void {
if ($element instanceof CSSBlockList) {
foreach ($element->getContents() as $content) {
$this->allValues($content, $result, $searchString, $searchInFunctionArguments);
}
} elseif ($element instanceof RuleSet) {
foreach ($element->getRules($searchString) as $rule) {
$this->allValues($rule, $result, $searchString, $searchInFunctionArguments);
}
} elseif ($element instanceof Rule) {
$this->allValues($element->getValue(), $result, $searchString, $searchInFunctionArguments);
} elseif ($element instanceof ValueList) {
if ($searchInFunctionArguments || !($element instanceof CSSFunction)) {
foreach ($element->getListComponents() as $component) {
$this->allValues($component, $result, $searchString, $searchInFunctionArguments);
}
}
} elseif ($element instanceof Value) {
$result[] = $element;
}
}
/**
* @param list<Selector> $result
*/
protected function allSelectors(array &$result, ?string $specificitySearch = null): void
{
$declarationBlocks = [];
$this->allDeclarationBlocks($declarationBlocks);
foreach ($declarationBlocks as $declarationBlock) {
foreach ($declarationBlock->getSelectors() as $selector) {
if ($specificitySearch === null) {
$result[] = $selector;
} else {
$comparator = '===';
$expressionParts = \explode(' ', $specificitySearch);
$targetSpecificity = $expressionParts[0];
if (\count($expressionParts) > 1) {
$comparator = $expressionParts[0];
$targetSpecificity = $expressionParts[1];
}
$targetSpecificity = (int) $targetSpecificity;
$selectorSpecificity = $selector->getSpecificity();
$comparatorMatched = false;
switch ($comparator) {
case '<=':
$comparatorMatched = $selectorSpecificity <= $targetSpecificity;
break;
case '<':
$comparatorMatched = $selectorSpecificity < $targetSpecificity;
break;
case '>=':
$comparatorMatched = $selectorSpecificity >= $targetSpecificity;
break;
case '>':
$comparatorMatched = $selectorSpecificity > $targetSpecificity;
break;
default:
$comparatorMatched = $selectorSpecificity === $targetSpecificity;
break;
}
if ($comparatorMatched) {
$result[] = $selector;
}
}
}
}
}
}