friendship ended with social-app. php is my new best friend
1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\CssSelector\XPath\Extension; 13 14use Symfony\Component\CssSelector\Exception\ExpressionErrorException; 15use Symfony\Component\CssSelector\XPath\XPathExpr; 16 17/** 18 * XPath expression translator pseudo-class extension. 19 * 20 * This component is a port of the Python cssselect library, 21 * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. 22 * 23 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com> 24 * 25 * @internal 26 */ 27class PseudoClassExtension extends AbstractExtension 28{ 29 public function getPseudoClassTranslators(): array 30 { 31 return [ 32 'root' => $this->translateRoot(...), 33 'scope' => $this->translateScopePseudo(...), 34 'first-child' => $this->translateFirstChild(...), 35 'last-child' => $this->translateLastChild(...), 36 'first-of-type' => $this->translateFirstOfType(...), 37 'last-of-type' => $this->translateLastOfType(...), 38 'only-child' => $this->translateOnlyChild(...), 39 'only-of-type' => $this->translateOnlyOfType(...), 40 'empty' => $this->translateEmpty(...), 41 ]; 42 } 43 44 public function translateRoot(XPathExpr $xpath): XPathExpr 45 { 46 return $xpath->addCondition('not(parent::*)'); 47 } 48 49 public function translateScopePseudo(XPathExpr $xpath): XPathExpr 50 { 51 return $xpath->addCondition('1'); 52 } 53 54 public function translateFirstChild(XPathExpr $xpath): XPathExpr 55 { 56 return $xpath 57 ->addStarPrefix() 58 ->addNameTest() 59 ->addCondition('position() = 1'); 60 } 61 62 public function translateLastChild(XPathExpr $xpath): XPathExpr 63 { 64 return $xpath 65 ->addStarPrefix() 66 ->addNameTest() 67 ->addCondition('position() = last()'); 68 } 69 70 /** 71 * @throws ExpressionErrorException 72 */ 73 public function translateFirstOfType(XPathExpr $xpath): XPathExpr 74 { 75 if ('*' === $xpath->getElement()) { 76 throw new ExpressionErrorException('"*:first-of-type" is not implemented.'); 77 } 78 79 return $xpath 80 ->addStarPrefix() 81 ->addCondition('position() = 1'); 82 } 83 84 /** 85 * @throws ExpressionErrorException 86 */ 87 public function translateLastOfType(XPathExpr $xpath): XPathExpr 88 { 89 if ('*' === $xpath->getElement()) { 90 throw new ExpressionErrorException('"*:last-of-type" is not implemented.'); 91 } 92 93 return $xpath 94 ->addStarPrefix() 95 ->addCondition('position() = last()'); 96 } 97 98 public function translateOnlyChild(XPathExpr $xpath): XPathExpr 99 { 100 return $xpath 101 ->addStarPrefix() 102 ->addNameTest() 103 ->addCondition('last() = 1'); 104 } 105 106 public function translateOnlyOfType(XPathExpr $xpath): XPathExpr 107 { 108 $element = $xpath->getElement(); 109 110 return $xpath->addCondition(\sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element)); 111 } 112 113 public function translateEmpty(XPathExpr $xpath): XPathExpr 114 { 115 return $xpath->addCondition('not(*) and not(string-length())'); 116 } 117 118 public function getName(): string 119 { 120 return 'pseudo-class'; 121 } 122}