Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 23ed186

Browse files
committed
use parseSelectorList
1 parent 36c0052 commit 23ed186

File tree

4 files changed

+42
-45
lines changed

4 files changed

+42
-45
lines changed

src/Symfony/Component/CssSelector/Parser/Parser.php

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,17 @@ public static function parseSeries(array $tokens): array
8989
];
9090
}
9191

92-
private function parseSelectorList(TokenStream $stream): array
92+
private function parseSelectorList(TokenStream $stream, bool $isArgument = false): array
9393
{
9494
$stream->skipWhitespace();
9595
$selectors = [];
9696

9797
while (true) {
98-
$selectors[] = $this->parserSelectorNode($stream);
98+
if ($isArgument && $stream->getPeek()->isDelimiter([')'])) {
99+
break;
100+
}
101+
102+
$selectors[] = $this->parserSelectorNode($stream, $isArgument);
99103

100104
if ($stream->getPeek()->isDelimiter([','])) {
101105
$stream->getNext();
@@ -108,15 +112,19 @@ private function parseSelectorList(TokenStream $stream): array
108112
return $selectors;
109113
}
110114

111-
private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
115+
private function parserSelectorNode(TokenStream $stream, bool $isArgument = false): Node\SelectorNode
112116
{
113-
[$result, $pseudoElement] = $this->parseSimpleSelector($stream);
117+
[$result, $pseudoElement] = $this->parseSimpleSelector($stream, false, $isArgument);
114118

115119
while (true) {
116120
$stream->skipWhitespace();
117121
$peek = $stream->getPeek();
118122

119-
if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
123+
if (
124+
$peek->isFileEnd()
125+
|| $peek->isDelimiter([','])
126+
|| ($isArgument && $peek->isDelimiter([')']))
127+
) {
120128
break;
121129
}
122130

@@ -131,7 +139,7 @@ private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
131139
$combinator = ' ';
132140
}
133141

134-
[$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
142+
[$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream, false, $isArgument);
135143
$result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
136144
}
137145

@@ -143,7 +151,7 @@ private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
143151
*
144152
* @throws SyntaxErrorException
145153
*/
146-
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array
154+
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false, bool $isArgument = false): array
147155
{
148156
$stream->skipWhitespace();
149157

@@ -156,7 +164,7 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
156164
if ($peek->isWhitespace()
157165
|| $peek->isFileEnd()
158166
|| $peek->isDelimiter([',', '+', '>', '~'])
159-
|| ($insideNegation && $peek->isDelimiter([')']))
167+
|| ($isArgument && $peek->isDelimiter([')']))
160168
) {
161169
break;
162170
}
@@ -206,7 +214,7 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
206214
throw SyntaxErrorException::nestedNot();
207215
}
208216

209-
[$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true);
217+
[$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true, true);
210218
$next = $stream->getNext();
211219

212220
if (null !== $argumentPseudoElement) {
@@ -219,11 +227,21 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
219227

220228
$result = new Node\NegationNode($result, $argument);
221229
} elseif ('is' === strtolower($identifier)) {
222-
$selectors = $this->parseSimpleSelectorArguments($stream);
230+
$selectors = $this->parseSelectorList($stream, true);
231+
232+
$next = $stream->getNext();
233+
if (!$next->isDelimiter([')'])) {
234+
throw SyntaxErrorException::unexpectedToken('")"', $next);
235+
}
223236

224237
$result = new Node\MatchingNode($result, $selectors);
225238
} elseif ('where' === strtolower($identifier)) {
226-
$selectors = $this->parseSimpleSelectorArguments($stream);
239+
$selectors = $this->parseSelectorList($stream, true);
240+
241+
$next = $stream->getNext();
242+
if (!$next->isDelimiter([')'])) {
243+
throw SyntaxErrorException::unexpectedToken('")"', $next);
244+
}
227245

228246
$result = new Node\SpecificityAdjustmentNode($result, $selectors);
229247
} else {
@@ -265,32 +283,6 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
265283
return [$result, $pseudoElement];
266284
}
267285

268-
private function parseSimpleSelectorArguments(TokenStream $stream): array
269-
{
270-
$arguments = [];
271-
while (true) {
272-
[$result, $pseudoElement] = $this->parseSimpleSelector($stream, true);
273-
if ($pseudoElement) {
274-
throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'function');
275-
}
276-
$stream->skipWhitespace();
277-
$next = $stream->getNext();
278-
279-
if ($next->isFileEnd() || $next->isDelimiter([','])) {
280-
$stream->getNext();
281-
$stream->skipWhitespace();
282-
$arguments[] = $result;
283-
} elseif ($next->isDelimiter([')'])) {
284-
$arguments[] = $result;
285-
break;
286-
} else {
287-
throw SyntaxErrorException::unexpectedToken('argument', $next);
288-
}
289-
}
290-
291-
return $arguments;
292-
}
293-
294286
private function parseElementNode(TokenStream $stream): Node\ElementNode
295287
{
296288
$peek = $stream->getPeek();

src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ public function getParserTestData()
148148
// unicode escape: \20 == (space)
149149
['*[aval="\'\20 \'"]', ['Attribute[Element[*][aval = \'\' \'\']]']],
150150
["*[aval=\"'\\20\r\n '\"]", ['Attribute[Element[*][aval = \'\' \'\']]']],
151-
['div:is(.foo, #bar)', ['Matching[Element[div]:is(Class[Element[*].foo], Hash[Element[*]#bar])]']],
152-
[':is(:hover, :visited)', ['Matching[Element[*]:is(Pseudo[Element[*]:hover], Pseudo[Element[*]:visited])]']],
153-
['div:where(.foo, #bar)', ['SpecificityAdjustment[Element[div]:where(Class[Element[*].foo], Hash[Element[*]#bar])]']],
154-
[':where(:hover, :visited)', ['SpecificityAdjustment[Element[*]:where(Pseudo[Element[*]:hover], Pseudo[Element[*]:visited])]']],
151+
['div:is(.foo, #bar)', ['Matching[Element[div]:is(Selector[Class[Element[*].foo]], Selector[Hash[Element[*]#bar]])]']],
152+
[':is(:hover, :visited)', ['Matching[Element[*]:is(Selector[Pseudo[Element[*]:hover]], Selector[Pseudo[Element[*]:visited]])]']],
153+
['div:where(.foo, #bar)', ['SpecificityAdjustment[Element[div]:where(Selector[Class[Element[*].foo]], Selector[Hash[Element[*]#bar]])]']],
154+
[':where(:hover, :visited)', ['SpecificityAdjustment[Element[*]:where(Selector[Pseudo[Element[*]:hover]], Selector[Pseudo[Element[*]:visited]])]']],
155155
];
156156
}
157157

@@ -182,6 +182,7 @@ public function getParserExceptionTestData()
182182
[':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()],
183183
[':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
184184
['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
185+
[':not(:not(a))', SyntaxErrorException::nestedNot()->getMessage()],
185186
];
186187
}
187188

src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,14 @@ public function getHtmlIdsTestData()
358358
[':is(#first-li, #second-li)', ['first-li', 'second-li']],
359359
['a:is(#name-anchor, #tag-anchor)', ['name-anchor', 'tag-anchor']],
360360
[':is(.c)', ['first-ol', 'third-li', 'fourth-li']],
361+
['a:is(:not(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
362+
['a:not(:is(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
361363
[':where(#first-li, #second-li)', ['first-li', 'second-li']],
362364
['a:where(#name-anchor, #tag-anchor)', ['name-anchor', 'tag-anchor']],
363365
[':where(.c)', ['first-ol', 'third-li', 'fourth-li']],
366+
['a:where(:not(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
367+
['a:not(:where(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
368+
['a:where(:is(#name-anchor), :where(#tag-anchor))', ['name-anchor', 'tag-anchor']],
364369
// HTML-specific
365370
[':link', ['link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']],
366371
[':visited', []],
@@ -419,8 +424,7 @@ public function getHtmlShakespearTestData()
419424
['div[class|=dialog]', 50], // ? Seems right
420425
['div[class!=madeup]', 243], // ? Seems right
421426
['div[class~=dialog]', 51], // ? Seems right
422-
['div:is(#speech1, #speech17)', 2],
423-
['div:where(#speech1, #speech17)', 2],
427+
['div:is(div#test .dialog) .direction', 4],
424428
];
425429
}
426430
}

src/Symfony/Component/CssSelector/XPath/XPathExpr.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ public function getElement(): string
4646
/**
4747
* @return $this
4848
*/
49-
public function addCondition(string $condition, string $conjunction = 'and'): static
49+
public function addCondition(string $condition, string $operator = 'and'): static
5050
{
51-
$this->condition = $this->condition ? sprintf('(%s) %s (%s)', $this->condition, $conjunction, $condition) : $condition;
51+
$this->condition = $this->condition ? sprintf('(%s) %s (%s)', $this->condition, $operator, $condition) : $condition;
5252

5353
return $this;
5454
}

0 commit comments

Comments
 (0)