Skip to content

Commit 86aeaa7

Browse files
authored
[TASK] Always calculate selector specificity on demand (#1028)
This avoids additional state that makes it hard to compare selectors for equality. Also, this will improve performance for cases where the specificity is not needed. Closes #1021
1 parent 08010a2 commit 86aeaa7

File tree

2 files changed

+16
-73
lines changed

2 files changed

+16
-73
lines changed

src/Property/Selector.php

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Sabberworm\CSS\Property;
66

77
use Sabberworm\CSS\OutputFormat;
8+
use Sabberworm\CSS\Property\Selector\SpecificityCalculator;
89
use Sabberworm\CSS\Renderable;
910

1011
/**
@@ -13,43 +14,6 @@
1314
*/
1415
class Selector implements Renderable
1516
{
16-
/**
17-
* regexp for specificity calculations
18-
*
19-
* @var string
20-
*/
21-
private const NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
22-
(\\.[\\w]+) # classes
23-
|
24-
\\[(\\w+) # attributes
25-
|
26-
(\\:( # pseudo classes
27-
link|visited|active
28-
|hover|focus
29-
|lang
30-
|target
31-
|enabled|disabled|checked|indeterminate
32-
|root
33-
|nth-child|nth-last-child|nth-of-type|nth-last-of-type
34-
|first-child|last-child|first-of-type|last-of-type
35-
|only-child|only-of-type
36-
|empty|contains
37-
))
38-
/ix';
39-
40-
/**
41-
* regexp for specificity calculations
42-
*
43-
* @var string
44-
*/
45-
private const ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
46-
((^|[\\s\\+\\>\\~]+)[\\w]+ # elements
47-
|
48-
\\:{1,2}( # pseudo-elements
49-
after|before|first-letter|first-line|selection
50-
))
51-
/ix';
52-
5317
/**
5418
* regexp for specificity calculations
5519
*
@@ -72,11 +36,6 @@ class Selector implements Renderable
7236
*/
7337
private $selector;
7438

75-
/**
76-
* @var int|null
77-
*/
78-
private $specificity;
79-
8039
/**
8140
* @return bool
8241
*
@@ -87,15 +46,9 @@ public static function isValid(string $selector)
8746
return \preg_match(static::SELECTOR_VALIDATION_RX, $selector);
8847
}
8948

90-
/**
91-
* @param bool $calculateSpecificity @deprecated since V8.8.0, will be removed in V9.0.0
92-
*/
93-
public function __construct(string $selector, bool $calculateSpecificity = false)
49+
public function __construct(string $selector)
9450
{
9551
$this->setSelector($selector);
96-
if ($calculateSpecificity) {
97-
$this->getSpecificity();
98-
}
9952
}
10053

10154
public function getSelector(): string
@@ -106,7 +59,6 @@ public function getSelector(): string
10659
public function setSelector(string $selector): void
10760
{
10861
$this->selector = \trim($selector);
109-
$this->specificity = null;
11062
}
11163

11264
/**
@@ -122,16 +74,7 @@ public function __toString(): string
12274
*/
12375
public function getSpecificity(): int
12476
{
125-
if ($this->specificity === null) {
126-
$a = 0;
127-
/// @todo should exclude \# as well as "#"
128-
$aMatches = null;
129-
$b = \substr_count($this->selector, '#');
130-
$c = \preg_match_all(self::NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX, $this->selector, $aMatches);
131-
$d = \preg_match_all(self::ELEMENTS_AND_PSEUDO_ELEMENTS_RX, $this->selector, $aMatches);
132-
$this->specificity = ($a * 1000) + ($b * 100) + ($c * 10) + $d;
133-
}
134-
return $this->specificity;
77+
return SpecificityCalculator::calculate($this->selector);
13578
}
13679

13780
public function render(OutputFormat $outputFormat): string

tests/ParserTest.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,26 +246,26 @@ public function unicodeRangeParsing(): void
246246
public function specificity(): void
247247
{
248248
$document = self::parsedStructureForFile('specificity');
249-
self::assertEquals([new Selector('#test .help', true)], $document->getSelectorsBySpecificity('> 100'));
249+
self::assertEquals([new Selector('#test .help')], $document->getSelectorsBySpecificity('> 100'));
250250
self::assertEquals(
251-
[new Selector('#test .help', true), new Selector('#file', true)],
251+
[new Selector('#test .help'), new Selector('#file')],
252252
$document->getSelectorsBySpecificity('>= 100')
253253
);
254-
self::assertEquals([new Selector('#file', true)], $document->getSelectorsBySpecificity('=== 100'));
255-
self::assertEquals([new Selector('#file', true)], $document->getSelectorsBySpecificity('== 100'));
254+
self::assertEquals([new Selector('#file')], $document->getSelectorsBySpecificity('=== 100'));
255+
self::assertEquals([new Selector('#file')], $document->getSelectorsBySpecificity('== 100'));
256256
self::assertEquals([
257-
new Selector('#file', true),
258-
new Selector('.help:hover', true),
259-
new Selector('li.green', true),
260-
new Selector('ol li::before', true),
257+
new Selector('#file'),
258+
new Selector('.help:hover'),
259+
new Selector('li.green'),
260+
new Selector('ol li::before'),
261261
], $document->getSelectorsBySpecificity('<= 100'));
262262
self::assertEquals([
263-
new Selector('.help:hover', true),
264-
new Selector('li.green', true),
265-
new Selector('ol li::before', true),
263+
new Selector('.help:hover'),
264+
new Selector('li.green'),
265+
new Selector('ol li::before'),
266266
], $document->getSelectorsBySpecificity('< 100'));
267-
self::assertEquals([new Selector('li.green', true)], $document->getSelectorsBySpecificity('11'));
268-
self::assertEquals([new Selector('ol li::before', true)], $document->getSelectorsBySpecificity('3'));
267+
self::assertEquals([new Selector('li.green')], $document->getSelectorsBySpecificity('11'));
268+
self::assertEquals([new Selector('ol li::before')], $document->getSelectorsBySpecificity('3'));
269269
}
270270

271271
/**

0 commit comments

Comments
 (0)