PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / trunk
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress vtrunk
4.17.2 4.17.1 4.17.0 4.16.19 4.16.18 4.16.17 4.16.16 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5a 1.1.6 1.1.7 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.7 1.7.1 1.7.2 1.8 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.1.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.2 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 3.0 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.15.0 4.15.1 4.15.10 4.15.11 4.15.12 4.15.13 4.15.14 4.15.15 4.15.16 4.15.17 4.15.18 4.15.19 4.15.2 4.15.20 4.15.20.1 4.15.21 4.15.22 4.15.23 4.15.24 4.15.25 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.10 4.16.11 4.16.12 4.16.13 4.16.14 4.16.15 4.16.2 4.16.3 4.16.4 4.16.5 4.16.6 4.16.7 4.16.8 4.16.9 4.2.0 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.7.0 4.8.0 4.9.0
wp-user-avatar / third-party / vendor / symfony / css-selector / Parser / Parser.php
wp-user-avatar / third-party / vendor / symfony / css-selector / Parser Last commit date
Handler 2 months ago Shortcut 2 months ago Tokenizer 2 months ago Parser.php 2 months ago ParserInterface.php 2 months ago Reader.php 2 months ago Token.php 2 months ago TokenStream.php 2 months ago
Parser.php
279 lines
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 namespace ProfilePressVendor\Symfony\Component\CssSelector\Parser;
12
13 use ProfilePressVendor\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
14 use ProfilePressVendor\Symfony\Component\CssSelector\Node;
15 use ProfilePressVendor\Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
16 /**
17 * CSS selector parser.
18 *
19 * This component is a port of the Python cssselect library,
20 * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
21 *
22 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
23 *
24 * @internal
25 */
26 class Parser implements ParserInterface
27 {
28 private $tokenizer;
29 public function __construct(?Tokenizer $tokenizer = null)
30 {
31 $this->tokenizer = $tokenizer ?? new Tokenizer();
32 }
33 /**
34 * {@inheritdoc}
35 */
36 public function parse(string $source): array
37 {
38 $reader = new Reader($source);
39 $stream = $this->tokenizer->tokenize($reader);
40 return $this->parseSelectorList($stream);
41 }
42 /**
43 * Parses the arguments for ":nth-child()" and friends.
44 *
45 * @param Token[] $tokens
46 *
47 * @throws SyntaxErrorException
48 */
49 public static function parseSeries(array $tokens): array
50 {
51 foreach ($tokens as $token) {
52 if ($token->isString()) {
53 throw SyntaxErrorException::stringAsFunctionArgument();
54 }
55 }
56 $joined = trim(implode('', array_map(function (Token $token) {
57 return $token->getValue();
58 }, $tokens)));
59 $int = function ($string) {
60 if (!is_numeric($string)) {
61 throw SyntaxErrorException::stringAsFunctionArgument();
62 }
63 return (int) $string;
64 };
65 switch (\true) {
66 case 'odd' === $joined:
67 return [2, 1];
68 case 'even' === $joined:
69 return [2, 0];
70 case 'n' === $joined:
71 return [1, 0];
72 case !str_contains($joined, 'n'):
73 return [0, $int($joined)];
74 }
75 $split = explode('n', $joined);
76 $first = $split[0] ?? null;
77 return [$first ? '-' === $first || '+' === $first ? $int($first . '1') : $int($first) : 1, isset($split[1]) && $split[1] ? $int($split[1]) : 0];
78 }
79 private function parseSelectorList(TokenStream $stream): array
80 {
81 $stream->skipWhitespace();
82 $selectors = [];
83 while (\true) {
84 $selectors[] = $this->parserSelectorNode($stream);
85 if ($stream->getPeek()->isDelimiter([','])) {
86 $stream->getNext();
87 $stream->skipWhitespace();
88 } else {
89 break;
90 }
91 }
92 return $selectors;
93 }
94 private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
95 {
96 [$result, $pseudoElement] = $this->parseSimpleSelector($stream);
97 while (\true) {
98 $stream->skipWhitespace();
99 $peek = $stream->getPeek();
100 if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
101 break;
102 }
103 if (null !== $pseudoElement) {
104 throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
105 }
106 if ($peek->isDelimiter(['+', '>', '~'])) {
107 $combinator = $stream->getNext()->getValue();
108 $stream->skipWhitespace();
109 } else {
110 $combinator = ' ';
111 }
112 [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
113 $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
114 }
115 return new Node\SelectorNode($result, $pseudoElement);
116 }
117 /**
118 * Parses next simple node (hash, class, pseudo, negation).
119 *
120 * @throws SyntaxErrorException
121 */
122 private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = \false): array
123 {
124 $stream->skipWhitespace();
125 $selectorStart = \count($stream->getUsed());
126 $result = $this->parseElementNode($stream);
127 $pseudoElement = null;
128 while (\true) {
129 $peek = $stream->getPeek();
130 if ($peek->isWhitespace() || $peek->isFileEnd() || $peek->isDelimiter([',', '+', '>', '~']) || $insideNegation && $peek->isDelimiter([')'])) {
131 break;
132 }
133 if (null !== $pseudoElement) {
134 throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
135 }
136 if ($peek->isHash()) {
137 $result = new Node\HashNode($result, $stream->getNext()->getValue());
138 } elseif ($peek->isDelimiter(['.'])) {
139 $stream->getNext();
140 $result = new Node\ClassNode($result, $stream->getNextIdentifier());
141 } elseif ($peek->isDelimiter(['['])) {
142 $stream->getNext();
143 $result = $this->parseAttributeNode($result, $stream);
144 } elseif ($peek->isDelimiter([':'])) {
145 $stream->getNext();
146 if ($stream->getPeek()->isDelimiter([':'])) {
147 $stream->getNext();
148 $pseudoElement = $stream->getNextIdentifier();
149 continue;
150 }
151 $identifier = $stream->getNextIdentifier();
152 if (\in_array(strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) {
153 // Special case: CSS 2.1 pseudo-elements can have a single ':'.
154 // Any new pseudo-element must have two.
155 $pseudoElement = $identifier;
156 continue;
157 }
158 if (!$stream->getPeek()->isDelimiter(['('])) {
159 $result = new Node\PseudoNode($result, $identifier);
160 continue;
161 }
162 $stream->getNext();
163 $stream->skipWhitespace();
164 if ('not' === strtolower($identifier)) {
165 if ($insideNegation) {
166 throw SyntaxErrorException::nestedNot();
167 }
168 [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, \true);
169 $next = $stream->getNext();
170 if (null !== $argumentPseudoElement) {
171 throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
172 }
173 if (!$next->isDelimiter([')'])) {
174 throw SyntaxErrorException::unexpectedToken('")"', $next);
175 }
176 $result = new Node\NegationNode($result, $argument);
177 } else {
178 $arguments = [];
179 $next = null;
180 while (\true) {
181 $stream->skipWhitespace();
182 $next = $stream->getNext();
183 if ($next->isIdentifier() || $next->isString() || $next->isNumber() || $next->isDelimiter(['+', '-'])) {
184 $arguments[] = $next;
185 } elseif ($next->isDelimiter([')'])) {
186 break;
187 } else {
188 throw SyntaxErrorException::unexpectedToken('an argument', $next);
189 }
190 }
191 if (empty($arguments)) {
192 throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
193 }
194 $result = new Node\FunctionNode($result, $identifier, $arguments);
195 }
196 } else {
197 throw SyntaxErrorException::unexpectedToken('selector', $peek);
198 }
199 }
200 if (\count($stream->getUsed()) === $selectorStart) {
201 throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
202 }
203 return [$result, $pseudoElement];
204 }
205 private function parseElementNode(TokenStream $stream): Node\ElementNode
206 {
207 $peek = $stream->getPeek();
208 if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
209 if ($peek->isIdentifier()) {
210 $namespace = $stream->getNext()->getValue();
211 } else {
212 $stream->getNext();
213 $namespace = null;
214 }
215 if ($stream->getPeek()->isDelimiter(['|'])) {
216 $stream->getNext();
217 $element = $stream->getNextIdentifierOrStar();
218 } else {
219 $element = $namespace;
220 $namespace = null;
221 }
222 } else {
223 $element = $namespace = null;
224 }
225 return new Node\ElementNode($namespace, $element);
226 }
227 private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode
228 {
229 $stream->skipWhitespace();
230 $attribute = $stream->getNextIdentifierOrStar();
231 if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
232 throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
233 }
234 if ($stream->getPeek()->isDelimiter(['|'])) {
235 $stream->getNext();
236 if ($stream->getPeek()->isDelimiter(['='])) {
237 $namespace = null;
238 $stream->getNext();
239 $operator = '|=';
240 } else {
241 $namespace = $attribute;
242 $attribute = $stream->getNextIdentifier();
243 $operator = null;
244 }
245 } else {
246 $namespace = $operator = null;
247 }
248 if (null === $operator) {
249 $stream->skipWhitespace();
250 $next = $stream->getNext();
251 if ($next->isDelimiter([']'])) {
252 return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
253 } elseif ($next->isDelimiter(['='])) {
254 $operator = '=';
255 } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!']) && $stream->getPeek()->isDelimiter(['='])) {
256 $operator = $next->getValue() . '=';
257 $stream->getNext();
258 } else {
259 throw SyntaxErrorException::unexpectedToken('operator', $next);
260 }
261 }
262 $stream->skipWhitespace();
263 $value = $stream->getNext();
264 if ($value->isNumber()) {
265 // if the value is a number, it's casted into a string
266 $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
267 }
268 if (!($value->isIdentifier() || $value->isString())) {
269 throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
270 }
271 $stream->skipWhitespace();
272 $next = $stream->getNext();
273 if (!$next->isDelimiter([']'])) {
274 throw SyntaxErrorException::unexpectedToken('"]"', $next);
275 }
276 return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
277 }
278 }
279