Commaaa2
This commit is contained in:
11
vendor/symfony/css-selector/CHANGELOG.md
vendored
11
vendor/symfony/css-selector/CHANGELOG.md
vendored
@@ -1,6 +1,17 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
7.1
|
||||
---
|
||||
|
||||
* Add support for `:is()`
|
||||
* Add support for `:where()`
|
||||
|
||||
6.3
|
||||
---
|
||||
|
||||
* Add support for `:scope`
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ use Symfony\Component\CssSelector\XPath\Translator;
|
||||
*/
|
||||
class CssSelectorConverter
|
||||
{
|
||||
private $translator;
|
||||
private Translator $translator;
|
||||
private array $cache;
|
||||
|
||||
private static array $xmlCache = [];
|
||||
@@ -62,6 +62,6 @@ class CssSelectorConverter
|
||||
*/
|
||||
public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
|
||||
{
|
||||
return $this->cache[$prefix][$cssExpr] ?? $this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix);
|
||||
return $this->cache[$prefix][$cssExpr] ??= $this->translator->cssToXPath($cssExpr, $prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ class SyntaxErrorException extends ParseException
|
||||
return new self('Got nested ::not().');
|
||||
}
|
||||
|
||||
public static function notAtTheStartOfASelector(string $pseudoElement): self
|
||||
{
|
||||
return new self(sprintf('Got immediate child pseudo-element ":%s" not at the start of a selector', $pseudoElement));
|
||||
}
|
||||
|
||||
public static function stringAsFunctionArgument(): self
|
||||
{
|
||||
return new self('String not allowed as function argument.');
|
||||
|
||||
2
vendor/symfony/css-selector/LICENSE
vendored
2
vendor/symfony/css-selector/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2023 Fabien Potencier
|
||||
Copyright (c) 2004-present Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -23,19 +23,13 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class AttributeNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private ?string $namespace;
|
||||
private string $attribute;
|
||||
private string $operator;
|
||||
private ?string $value;
|
||||
|
||||
public function __construct(NodeInterface $selector, ?string $namespace, string $attribute, string $operator, ?string $value)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->namespace = $namespace;
|
||||
$this->attribute = $attribute;
|
||||
$this->operator = $operator;
|
||||
$this->value = $value;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
private ?string $namespace,
|
||||
private string $attribute,
|
||||
private string $operator,
|
||||
private ?string $value,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSelector(): NodeInterface
|
||||
@@ -63,9 +57,6 @@ class AttributeNode extends AbstractNode
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
|
||||
14
vendor/symfony/css-selector/Node/ClassNode.php
vendored
14
vendor/symfony/css-selector/Node/ClassNode.php
vendored
@@ -23,13 +23,10 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class ClassNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private string $name;
|
||||
|
||||
public function __construct(NodeInterface $selector, string $name)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->name = $name;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
private string $name,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSelector(): NodeInterface
|
||||
@@ -42,9 +39,6 @@ class ClassNode extends AbstractNode
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
|
||||
@@ -23,15 +23,11 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class CombinedSelectorNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private string $combinator;
|
||||
private $subSelector;
|
||||
|
||||
public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->combinator = $combinator;
|
||||
$this->subSelector = $subSelector;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
private string $combinator,
|
||||
private NodeInterface $subSelector,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSelector(): NodeInterface
|
||||
@@ -49,9 +45,6 @@ class CombinedSelectorNode extends AbstractNode
|
||||
return $this->subSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
|
||||
|
||||
14
vendor/symfony/css-selector/Node/ElementNode.php
vendored
14
vendor/symfony/css-selector/Node/ElementNode.php
vendored
@@ -23,13 +23,10 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class ElementNode extends AbstractNode
|
||||
{
|
||||
private ?string $namespace;
|
||||
private ?string $element;
|
||||
|
||||
public function __construct(string $namespace = null, string $element = null)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->element = $element;
|
||||
public function __construct(
|
||||
private ?string $namespace = null,
|
||||
private ?string $element = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getNamespace(): ?string
|
||||
@@ -42,9 +39,6 @@ class ElementNode extends AbstractNode
|
||||
return $this->element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return new Specificity(0, 0, $this->element ? 1 : 0);
|
||||
|
||||
@@ -25,18 +25,17 @@ use Symfony\Component\CssSelector\Parser\Token;
|
||||
*/
|
||||
class FunctionNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private string $name;
|
||||
private array $arguments;
|
||||
|
||||
/**
|
||||
* @param Token[] $arguments
|
||||
*/
|
||||
public function __construct(NodeInterface $selector, string $name, array $arguments = [])
|
||||
{
|
||||
$this->selector = $selector;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
string $name,
|
||||
private array $arguments = [],
|
||||
) {
|
||||
$this->name = strtolower($name);
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
public function getSelector(): NodeInterface
|
||||
@@ -57,9 +56,6 @@ class FunctionNode extends AbstractNode
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
@@ -67,9 +63,7 @@ class FunctionNode extends AbstractNode
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
$arguments = implode(', ', array_map(function (Token $token) {
|
||||
return "'".$token->getValue()."'";
|
||||
}, $this->arguments));
|
||||
$arguments = implode(', ', array_map(fn (Token $token) => "'".$token->getValue()."'", $this->arguments));
|
||||
|
||||
return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : '');
|
||||
}
|
||||
|
||||
14
vendor/symfony/css-selector/Node/HashNode.php
vendored
14
vendor/symfony/css-selector/Node/HashNode.php
vendored
@@ -23,13 +23,10 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class HashNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private string $id;
|
||||
|
||||
public function __construct(NodeInterface $selector, string $id)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->id = $id;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
private string $id,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSelector(): NodeInterface
|
||||
@@ -42,9 +39,6 @@ class HashNode extends AbstractNode
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
|
||||
|
||||
@@ -23,13 +23,10 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class NegationNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private $subSelector;
|
||||
|
||||
public function __construct(NodeInterface $selector, NodeInterface $subSelector)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
$this->subSelector = $subSelector;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
private NodeInterface $subSelector,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getSelector(): NodeInterface
|
||||
@@ -42,9 +39,6 @@ class NegationNode extends AbstractNode
|
||||
return $this->subSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
|
||||
|
||||
@@ -21,11 +21,9 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface NodeInterface
|
||||
interface NodeInterface extends \Stringable
|
||||
{
|
||||
public function getNodeName(): string;
|
||||
|
||||
public function getSpecificity(): Specificity;
|
||||
|
||||
public function __toString(): string;
|
||||
}
|
||||
|
||||
11
vendor/symfony/css-selector/Node/PseudoNode.php
vendored
11
vendor/symfony/css-selector/Node/PseudoNode.php
vendored
@@ -23,12 +23,12 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class PseudoNode extends AbstractNode
|
||||
{
|
||||
private $selector;
|
||||
private string $identifier;
|
||||
|
||||
public function __construct(NodeInterface $selector, string $identifier)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
public function __construct(
|
||||
private NodeInterface $selector,
|
||||
string $identifier,
|
||||
) {
|
||||
$this->identifier = strtolower($identifier);
|
||||
}
|
||||
|
||||
@@ -42,9 +42,6 @@ class PseudoNode extends AbstractNode
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
|
||||
|
||||
@@ -23,12 +23,12 @@ namespace Symfony\Component\CssSelector\Node;
|
||||
*/
|
||||
class SelectorNode extends AbstractNode
|
||||
{
|
||||
private $tree;
|
||||
private ?string $pseudoElement;
|
||||
|
||||
public function __construct(NodeInterface $tree, string $pseudoElement = null)
|
||||
{
|
||||
$this->tree = $tree;
|
||||
public function __construct(
|
||||
private NodeInterface $tree,
|
||||
?string $pseudoElement = null,
|
||||
) {
|
||||
$this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
|
||||
}
|
||||
|
||||
@@ -42,9 +42,6 @@ class SelectorNode extends AbstractNode
|
||||
return $this->pseudoElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSpecificity(): Specificity
|
||||
{
|
||||
return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
|
||||
|
||||
14
vendor/symfony/css-selector/Node/Specificity.php
vendored
14
vendor/symfony/css-selector/Node/Specificity.php
vendored
@@ -29,15 +29,11 @@ class Specificity
|
||||
public const B_FACTOR = 10;
|
||||
public const C_FACTOR = 1;
|
||||
|
||||
private int $a;
|
||||
private int $b;
|
||||
private int $c;
|
||||
|
||||
public function __construct(int $a, int $b, int $c)
|
||||
{
|
||||
$this->a = $a;
|
||||
$this->b = $b;
|
||||
$this->c = $c;
|
||||
public function __construct(
|
||||
private int $a,
|
||||
private int $b,
|
||||
private int $c,
|
||||
) {
|
||||
}
|
||||
|
||||
public function plus(self $specificity): self
|
||||
|
||||
@@ -26,9 +26,6 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
*/
|
||||
class CommentHandler implements HandlerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Reader $reader, TokenStream $stream): bool
|
||||
{
|
||||
if ('/*' !== $reader->getSubstring(2)) {
|
||||
|
||||
@@ -29,18 +29,12 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
*/
|
||||
class HashHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
private $escaping;
|
||||
|
||||
public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
$this->escaping = $escaping;
|
||||
public function __construct(
|
||||
private TokenizerPatterns $patterns,
|
||||
private TokenizerEscaping $escaping,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Reader $reader, TokenStream $stream): bool
|
||||
{
|
||||
$match = $reader->findPattern($this->patterns->getHashPattern());
|
||||
|
||||
@@ -29,18 +29,12 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
*/
|
||||
class IdentifierHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
private $escaping;
|
||||
|
||||
public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
$this->escaping = $escaping;
|
||||
public function __construct(
|
||||
private TokenizerPatterns $patterns,
|
||||
private TokenizerEscaping $escaping,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Reader $reader, TokenStream $stream): bool
|
||||
{
|
||||
$match = $reader->findPattern($this->patterns->getIdentifierPattern());
|
||||
|
||||
@@ -28,16 +28,11 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
*/
|
||||
class NumberHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
|
||||
public function __construct(TokenizerPatterns $patterns)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
public function __construct(
|
||||
private TokenizerPatterns $patterns,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Reader $reader, TokenStream $stream): bool
|
||||
{
|
||||
$match = $reader->findPattern($this->patterns->getNumberPattern());
|
||||
|
||||
@@ -31,18 +31,12 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
*/
|
||||
class StringHandler implements HandlerInterface
|
||||
{
|
||||
private $patterns;
|
||||
private $escaping;
|
||||
|
||||
public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
$this->escaping = $escaping;
|
||||
public function __construct(
|
||||
private TokenizerPatterns $patterns,
|
||||
private TokenizerEscaping $escaping,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Reader $reader, TokenStream $stream): bool
|
||||
{
|
||||
$quote = $reader->getSubstring(1);
|
||||
|
||||
@@ -27,9 +27,6 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
|
||||
*/
|
||||
class WhitespaceHandler implements HandlerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Reader $reader, TokenStream $stream): bool
|
||||
{
|
||||
$match = $reader->findPattern('~^[ \t\r\n\f]+~');
|
||||
|
||||
72
vendor/symfony/css-selector/Parser/Parser.php
vendored
72
vendor/symfony/css-selector/Parser/Parser.php
vendored
@@ -19,7 +19,7 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
|
||||
* CSS selector parser.
|
||||
*
|
||||
* This component is a port of the Python cssselect library,
|
||||
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
|
||||
* which is copyright Ian Bicking, @see https://github.com/scrapy/cssselect.
|
||||
*
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
@@ -27,16 +27,13 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
|
||||
*/
|
||||
class Parser implements ParserInterface
|
||||
{
|
||||
private $tokenizer;
|
||||
private Tokenizer $tokenizer;
|
||||
|
||||
public function __construct(Tokenizer $tokenizer = null)
|
||||
public function __construct(?Tokenizer $tokenizer = null)
|
||||
{
|
||||
$this->tokenizer = $tokenizer ?? new Tokenizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(string $source): array
|
||||
{
|
||||
$reader = new Reader($source);
|
||||
@@ -60,9 +57,7 @@ class Parser implements ParserInterface
|
||||
}
|
||||
}
|
||||
|
||||
$joined = trim(implode('', array_map(function (Token $token) {
|
||||
return $token->getValue();
|
||||
}, $tokens)));
|
||||
$joined = trim(implode('', array_map(fn (Token $token) => $token->getValue(), $tokens)));
|
||||
|
||||
$int = function ($string) {
|
||||
if (!is_numeric($string)) {
|
||||
@@ -92,13 +87,17 @@ class Parser implements ParserInterface
|
||||
];
|
||||
}
|
||||
|
||||
private function parseSelectorList(TokenStream $stream): array
|
||||
private function parseSelectorList(TokenStream $stream, bool $isArgument = false): array
|
||||
{
|
||||
$stream->skipWhitespace();
|
||||
$selectors = [];
|
||||
|
||||
while (true) {
|
||||
$selectors[] = $this->parserSelectorNode($stream);
|
||||
if ($isArgument && $stream->getPeek()->isDelimiter([')'])) {
|
||||
break;
|
||||
}
|
||||
|
||||
$selectors[] = $this->parserSelectorNode($stream, $isArgument);
|
||||
|
||||
if ($stream->getPeek()->isDelimiter([','])) {
|
||||
$stream->getNext();
|
||||
@@ -111,15 +110,19 @@ class Parser implements ParserInterface
|
||||
return $selectors;
|
||||
}
|
||||
|
||||
private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
|
||||
private function parserSelectorNode(TokenStream $stream, bool $isArgument = false): Node\SelectorNode
|
||||
{
|
||||
[$result, $pseudoElement] = $this->parseSimpleSelector($stream);
|
||||
[$result, $pseudoElement] = $this->parseSimpleSelector($stream, false, $isArgument);
|
||||
|
||||
while (true) {
|
||||
$stream->skipWhitespace();
|
||||
$peek = $stream->getPeek();
|
||||
|
||||
if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
|
||||
if (
|
||||
$peek->isFileEnd()
|
||||
|| $peek->isDelimiter([','])
|
||||
|| ($isArgument && $peek->isDelimiter([')']))
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -134,7 +137,7 @@ class Parser implements ParserInterface
|
||||
$combinator = ' ';
|
||||
}
|
||||
|
||||
[$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
|
||||
[$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream, false, $isArgument);
|
||||
$result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
|
||||
}
|
||||
|
||||
@@ -146,7 +149,7 @@ class Parser implements ParserInterface
|
||||
*
|
||||
* @throws SyntaxErrorException
|
||||
*/
|
||||
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array
|
||||
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false, bool $isArgument = false): array
|
||||
{
|
||||
$stream->skipWhitespace();
|
||||
|
||||
@@ -159,7 +162,7 @@ class Parser implements ParserInterface
|
||||
if ($peek->isWhitespace()
|
||||
|| $peek->isFileEnd()
|
||||
|| $peek->isDelimiter([',', '+', '>', '~'])
|
||||
|| ($insideNegation && $peek->isDelimiter([')']))
|
||||
|| ($isArgument && $peek->isDelimiter([')']))
|
||||
) {
|
||||
break;
|
||||
}
|
||||
@@ -197,7 +200,18 @@ class Parser implements ParserInterface
|
||||
|
||||
if (!$stream->getPeek()->isDelimiter(['('])) {
|
||||
$result = new Node\PseudoNode($result, $identifier);
|
||||
|
||||
if ('Pseudo[Element[*]:scope]' === $result->__toString()) {
|
||||
$used = \count($stream->getUsed());
|
||||
if (!(2 === $used
|
||||
|| 3 === $used && $stream->getUsed()[0]->isWhiteSpace()
|
||||
|| $used >= 3 && $stream->getUsed()[$used - 3]->isDelimiter([','])
|
||||
|| $used >= 4
|
||||
&& $stream->getUsed()[$used - 3]->isWhiteSpace()
|
||||
&& $stream->getUsed()[$used - 4]->isDelimiter([','])
|
||||
)) {
|
||||
throw SyntaxErrorException::notAtTheStartOfASelector('scope');
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -209,7 +223,7 @@ class Parser implements ParserInterface
|
||||
throw SyntaxErrorException::nestedNot();
|
||||
}
|
||||
|
||||
[$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true);
|
||||
[$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true, true);
|
||||
$next = $stream->getNext();
|
||||
|
||||
if (null !== $argumentPseudoElement) {
|
||||
@@ -221,6 +235,24 @@ class Parser implements ParserInterface
|
||||
}
|
||||
|
||||
$result = new Node\NegationNode($result, $argument);
|
||||
} elseif ('is' === strtolower($identifier)) {
|
||||
$selectors = $this->parseSelectorList($stream, true);
|
||||
|
||||
$next = $stream->getNext();
|
||||
if (!$next->isDelimiter([')'])) {
|
||||
throw SyntaxErrorException::unexpectedToken('")"', $next);
|
||||
}
|
||||
|
||||
$result = new Node\MatchingNode($result, $selectors);
|
||||
} elseif ('where' === strtolower($identifier)) {
|
||||
$selectors = $this->parseSelectorList($stream, true);
|
||||
|
||||
$next = $stream->getNext();
|
||||
if (!$next->isDelimiter([')'])) {
|
||||
throw SyntaxErrorException::unexpectedToken('")"', $next);
|
||||
}
|
||||
|
||||
$result = new Node\SpecificityAdjustmentNode($result, $selectors);
|
||||
} else {
|
||||
$arguments = [];
|
||||
$next = null;
|
||||
@@ -242,7 +274,7 @@ class Parser implements ParserInterface
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($arguments)) {
|
||||
if (!$arguments) {
|
||||
throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
|
||||
}
|
||||
|
||||
|
||||
13
vendor/symfony/css-selector/Parser/Reader.php
vendored
13
vendor/symfony/css-selector/Parser/Reader.php
vendored
@@ -23,13 +23,12 @@ namespace Symfony\Component\CssSelector\Parser;
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
private string $source;
|
||||
private int $length;
|
||||
private int $position = 0;
|
||||
|
||||
public function __construct(string $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
public function __construct(
|
||||
private string $source,
|
||||
) {
|
||||
$this->length = \strlen($source);
|
||||
}
|
||||
|
||||
@@ -53,7 +52,7 @@ class Reader
|
||||
return substr($this->source, $this->position + $offset, $length);
|
||||
}
|
||||
|
||||
public function getOffset(string $string)
|
||||
public function getOffset(string $string): int|false
|
||||
{
|
||||
$position = strpos($this->source, $string, $this->position);
|
||||
|
||||
@@ -71,12 +70,12 @@ class Reader
|
||||
return false;
|
||||
}
|
||||
|
||||
public function moveForward(int $length)
|
||||
public function moveForward(int $length): void
|
||||
{
|
||||
$this->position += $length;
|
||||
}
|
||||
|
||||
public function moveToEnd()
|
||||
public function moveToEnd(): void
|
||||
{
|
||||
$this->position = $this->length;
|
||||
}
|
||||
|
||||
@@ -28,9 +28,6 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
*/
|
||||
class ClassParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(string $source): array
|
||||
{
|
||||
// Matches an optional namespace, optional element, and required class
|
||||
|
||||
@@ -27,9 +27,6 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
*/
|
||||
class ElementParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(string $source): array
|
||||
{
|
||||
// Matches an optional namespace, required element or `*`
|
||||
|
||||
@@ -31,9 +31,6 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
*/
|
||||
class EmptyStringParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(string $source): array
|
||||
{
|
||||
// Matches an empty string
|
||||
|
||||
@@ -28,9 +28,6 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
*/
|
||||
class HashParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(string $source): array
|
||||
{
|
||||
// Matches an optional namespace, optional element, and required id
|
||||
|
||||
18
vendor/symfony/css-selector/Parser/Token.php
vendored
18
vendor/symfony/css-selector/Parser/Token.php
vendored
@@ -31,15 +31,11 @@ class Token
|
||||
public const TYPE_NUMBER = 'number';
|
||||
public const TYPE_STRING = 'string';
|
||||
|
||||
private ?string $type;
|
||||
private ?string $value;
|
||||
private ?int $position;
|
||||
|
||||
public function __construct(?string $type, ?string $value, ?int $position)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->value = $value;
|
||||
$this->position = $position;
|
||||
public function __construct(
|
||||
private ?string $type,
|
||||
private ?string $value,
|
||||
private ?int $position,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getType(): ?int
|
||||
@@ -68,11 +64,11 @@ class Token
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($values)) {
|
||||
if (!$values) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return \in_array($this->value, $values);
|
||||
return \in_array($this->value, $values, true);
|
||||
}
|
||||
|
||||
public function isWhitespace(): bool
|
||||
|
||||
@@ -37,7 +37,7 @@ class TokenStream
|
||||
private array $used = [];
|
||||
|
||||
private int $cursor = 0;
|
||||
private $peeked;
|
||||
private ?Token $peeked;
|
||||
private bool $peeking = false;
|
||||
|
||||
/**
|
||||
@@ -145,7 +145,7 @@ class TokenStream
|
||||
/**
|
||||
* Skips next whitespace if any.
|
||||
*/
|
||||
public function skipWhitespace()
|
||||
public function skipWhitespace(): void
|
||||
{
|
||||
$peek = $this->getPeek();
|
||||
|
||||
|
||||
@@ -23,11 +23,9 @@ namespace Symfony\Component\CssSelector\Parser\Tokenizer;
|
||||
*/
|
||||
class TokenizerEscaping
|
||||
{
|
||||
private $patterns;
|
||||
|
||||
public function __construct(TokenizerPatterns $patterns)
|
||||
{
|
||||
$this->patterns = $patterns;
|
||||
public function __construct(
|
||||
private TokenizerPatterns $patterns,
|
||||
) {
|
||||
}
|
||||
|
||||
public function escapeUnicode(string $value): string
|
||||
|
||||
@@ -23,41 +23,26 @@ namespace Symfony\Component\CssSelector\XPath\Extension;
|
||||
*/
|
||||
abstract class AbstractExtension implements ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNodeTranslators(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCombinationTranslators(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctionTranslators(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPseudoClassTranslators(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributeMatchingTranslators(): array
|
||||
{
|
||||
return [];
|
||||
|
||||
@@ -26,20 +26,17 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
*/
|
||||
class AttributeMatchingExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributeMatchingTranslators(): array
|
||||
{
|
||||
return [
|
||||
'exists' => [$this, 'translateExists'],
|
||||
'=' => [$this, 'translateEquals'],
|
||||
'~=' => [$this, 'translateIncludes'],
|
||||
'|=' => [$this, 'translateDashMatch'],
|
||||
'^=' => [$this, 'translatePrefixMatch'],
|
||||
'$=' => [$this, 'translateSuffixMatch'],
|
||||
'*=' => [$this, 'translateSubstringMatch'],
|
||||
'!=' => [$this, 'translateDifferent'],
|
||||
'exists' => $this->translateExists(...),
|
||||
'=' => $this->translateEquals(...),
|
||||
'~=' => $this->translateIncludes(...),
|
||||
'|=' => $this->translateDashMatch(...),
|
||||
'^=' => $this->translatePrefixMatch(...),
|
||||
'$=' => $this->translateSuffixMatch(...),
|
||||
'*=' => $this->translateSubstringMatch(...),
|
||||
'!=' => $this->translateDifferent(...),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -109,9 +106,6 @@ class AttributeMatchingExtension extends AbstractExtension
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'attribute-matching';
|
||||
|
||||
@@ -25,16 +25,13 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
*/
|
||||
class CombinationExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCombinationTranslators(): array
|
||||
{
|
||||
return [
|
||||
' ' => [$this, 'translateDescendant'],
|
||||
'>' => [$this, 'translateChild'],
|
||||
'+' => [$this, 'translateDirectAdjacent'],
|
||||
'~' => [$this, 'translateIndirectAdjacent'],
|
||||
' ' => $this->translateDescendant(...),
|
||||
'>' => $this->translateChild(...),
|
||||
'+' => $this->translateDirectAdjacent(...),
|
||||
'~' => $this->translateIndirectAdjacent(...),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -61,9 +58,6 @@ class CombinationExtension extends AbstractExtension
|
||||
return $xpath->join('/following-sibling::', $combinedXpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'combination';
|
||||
|
||||
@@ -30,18 +30,15 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
*/
|
||||
class FunctionExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctionTranslators(): array
|
||||
{
|
||||
return [
|
||||
'nth-child' => [$this, 'translateNthChild'],
|
||||
'nth-last-child' => [$this, 'translateNthLastChild'],
|
||||
'nth-of-type' => [$this, 'translateNthOfType'],
|
||||
'nth-last-of-type' => [$this, 'translateNthLastOfType'],
|
||||
'contains' => [$this, 'translateContains'],
|
||||
'lang' => [$this, 'translateLang'],
|
||||
'nth-child' => $this->translateNthChild(...),
|
||||
'nth-last-child' => $this->translateNthLastChild(...),
|
||||
'nth-of-type' => $this->translateNthOfType(...),
|
||||
'nth-last-of-type' => $this->translateNthLastOfType(...),
|
||||
'contains' => $this->translateContains(...),
|
||||
'lang' => $this->translateLang(...),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -161,9 +158,6 @@ class FunctionExtension extends AbstractExtension
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'function';
|
||||
|
||||
@@ -36,30 +36,24 @@ class HtmlExtension extends AbstractExtension
|
||||
->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPseudoClassTranslators(): array
|
||||
{
|
||||
return [
|
||||
'checked' => [$this, 'translateChecked'],
|
||||
'link' => [$this, 'translateLink'],
|
||||
'disabled' => [$this, 'translateDisabled'],
|
||||
'enabled' => [$this, 'translateEnabled'],
|
||||
'selected' => [$this, 'translateSelected'],
|
||||
'invalid' => [$this, 'translateInvalid'],
|
||||
'hover' => [$this, 'translateHover'],
|
||||
'visited' => [$this, 'translateVisited'],
|
||||
'checked' => $this->translateChecked(...),
|
||||
'link' => $this->translateLink(...),
|
||||
'disabled' => $this->translateDisabled(...),
|
||||
'enabled' => $this->translateEnabled(...),
|
||||
'selected' => $this->translateSelected(...),
|
||||
'invalid' => $this->translateInvalid(...),
|
||||
'hover' => $this->translateHover(...),
|
||||
'visited' => $this->translateVisited(...),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctionTranslators(): array
|
||||
{
|
||||
return [
|
||||
'lang' => [$this, 'translateLang'],
|
||||
'lang' => $this->translateLang(...),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -177,9 +171,6 @@ class HtmlExtension extends AbstractExtension
|
||||
return $xpath->addCondition('0');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'html';
|
||||
|
||||
@@ -31,11 +31,9 @@ class NodeExtension extends AbstractExtension
|
||||
public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
|
||||
public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
|
||||
|
||||
private int $flags;
|
||||
|
||||
public function __construct(int $flags = 0)
|
||||
{
|
||||
$this->flags = $flags;
|
||||
public function __construct(
|
||||
private int $flags = 0,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,21 +57,20 @@ class NodeExtension extends AbstractExtension
|
||||
return (bool) ($this->flags & $flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNodeTranslators(): array
|
||||
{
|
||||
return [
|
||||
'Selector' => [$this, 'translateSelector'],
|
||||
'CombinedSelector' => [$this, 'translateCombinedSelector'],
|
||||
'Negation' => [$this, 'translateNegation'],
|
||||
'Function' => [$this, 'translateFunction'],
|
||||
'Pseudo' => [$this, 'translatePseudo'],
|
||||
'Attribute' => [$this, 'translateAttribute'],
|
||||
'Class' => [$this, 'translateClass'],
|
||||
'Hash' => [$this, 'translateHash'],
|
||||
'Element' => [$this, 'translateElement'],
|
||||
'Selector' => $this->translateSelector(...),
|
||||
'CombinedSelector' => $this->translateCombinedSelector(...),
|
||||
'Negation' => $this->translateNegation(...),
|
||||
'Matching' => $this->translateMatching(...),
|
||||
'SpecificityAdjustment' => $this->translateSpecificityAdjustment(...),
|
||||
'Function' => $this->translateFunction(...),
|
||||
'Pseudo' => $this->translatePseudo(...),
|
||||
'Attribute' => $this->translateAttribute(...),
|
||||
'Class' => $this->translateClass(...),
|
||||
'Hash' => $this->translateHash(...),
|
||||
'Element' => $this->translateElement(...),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -100,6 +97,36 @@ class NodeExtension extends AbstractExtension
|
||||
return $xpath->addCondition('0');
|
||||
}
|
||||
|
||||
public function translateMatching(Node\MatchingNode $node, Translator $translator): XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->selector);
|
||||
|
||||
foreach ($node->arguments as $argument) {
|
||||
$expr = $translator->nodeToXPath($argument);
|
||||
$expr->addNameTest();
|
||||
if ($condition = $expr->getCondition()) {
|
||||
$xpath->addCondition($condition, 'or');
|
||||
}
|
||||
}
|
||||
|
||||
return $xpath;
|
||||
}
|
||||
|
||||
public function translateSpecificityAdjustment(Node\SpecificityAdjustmentNode $node, Translator $translator): XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->selector);
|
||||
|
||||
foreach ($node->arguments as $argument) {
|
||||
$expr = $translator->nodeToXPath($argument);
|
||||
$expr->addNameTest();
|
||||
if ($condition = $expr->getCondition()) {
|
||||
$xpath->addCondition($condition, 'or');
|
||||
}
|
||||
}
|
||||
|
||||
return $xpath;
|
||||
}
|
||||
|
||||
public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
|
||||
{
|
||||
$xpath = $translator->nodeToXPath($node->getSelector());
|
||||
@@ -182,9 +209,6 @@ class NodeExtension extends AbstractExtension
|
||||
return $xpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'node';
|
||||
|
||||
@@ -26,20 +26,18 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
|
||||
*/
|
||||
class PseudoClassExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPseudoClassTranslators(): array
|
||||
{
|
||||
return [
|
||||
'root' => [$this, 'translateRoot'],
|
||||
'first-child' => [$this, 'translateFirstChild'],
|
||||
'last-child' => [$this, 'translateLastChild'],
|
||||
'first-of-type' => [$this, 'translateFirstOfType'],
|
||||
'last-of-type' => [$this, 'translateLastOfType'],
|
||||
'only-child' => [$this, 'translateOnlyChild'],
|
||||
'only-of-type' => [$this, 'translateOnlyOfType'],
|
||||
'empty' => [$this, 'translateEmpty'],
|
||||
'root' => $this->translateRoot(...),
|
||||
'scope' => $this->translateScopePseudo(...),
|
||||
'first-child' => $this->translateFirstChild(...),
|
||||
'last-child' => $this->translateLastChild(...),
|
||||
'first-of-type' => $this->translateFirstOfType(...),
|
||||
'last-of-type' => $this->translateLastOfType(...),
|
||||
'only-child' => $this->translateOnlyChild(...),
|
||||
'only-of-type' => $this->translateOnlyOfType(...),
|
||||
'empty' => $this->translateEmpty(...),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -48,6 +46,11 @@ class PseudoClassExtension extends AbstractExtension
|
||||
return $xpath->addCondition('not(parent::*)');
|
||||
}
|
||||
|
||||
public function translateScopePseudo(XPathExpr $xpath): XPathExpr
|
||||
{
|
||||
return $xpath->addCondition('1');
|
||||
}
|
||||
|
||||
public function translateFirstChild(XPathExpr $xpath): XPathExpr
|
||||
{
|
||||
return $xpath
|
||||
@@ -112,9 +115,6 @@ class PseudoClassExtension extends AbstractExtension
|
||||
return $xpath->addCondition('not(*) and not(string-length())');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'pseudo-class';
|
||||
|
||||
12
vendor/symfony/css-selector/XPath/Translator.php
vendored
12
vendor/symfony/css-selector/XPath/Translator.php
vendored
@@ -30,7 +30,7 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
|
||||
*/
|
||||
class Translator implements TranslatorInterface
|
||||
{
|
||||
private $mainParser;
|
||||
private ParserInterface $mainParser;
|
||||
|
||||
/**
|
||||
* @var ParserInterface[]
|
||||
@@ -48,7 +48,7 @@ class Translator implements TranslatorInterface
|
||||
private array $pseudoClassTranslators = [];
|
||||
private array $attributeMatchingTranslators = [];
|
||||
|
||||
public function __construct(ParserInterface $parser = null)
|
||||
public function __construct(?ParserInterface $parser = null)
|
||||
{
|
||||
$this->mainParser = $parser ?? new Parser();
|
||||
|
||||
@@ -87,9 +87,6 @@ class Translator implements TranslatorInterface
|
||||
return sprintf('concat(%s)', implode(', ', $parts));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
|
||||
{
|
||||
$selectors = $this->parseSelectors($cssExpr);
|
||||
@@ -106,9 +103,6 @@ class Translator implements TranslatorInterface
|
||||
return implode(' | ', $selectors);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
|
||||
{
|
||||
return ($prefix ?: '').$this->nodeToXPath($selector);
|
||||
@@ -220,7 +214,7 @@ class Translator implements TranslatorInterface
|
||||
foreach ($this->shortcutParsers as $shortcut) {
|
||||
$tokens = $shortcut->parse($css);
|
||||
|
||||
if (!empty($tokens)) {
|
||||
if ($tokens) {
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
||||
22
vendor/symfony/css-selector/XPath/XPathExpr.php
vendored
22
vendor/symfony/css-selector/XPath/XPathExpr.php
vendored
@@ -23,16 +23,12 @@ namespace Symfony\Component\CssSelector\XPath;
|
||||
*/
|
||||
class XPathExpr
|
||||
{
|
||||
private string $path;
|
||||
private string $element;
|
||||
private string $condition;
|
||||
|
||||
public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->element = $element;
|
||||
$this->condition = $condition;
|
||||
|
||||
public function __construct(
|
||||
private string $path = '',
|
||||
private string $element = '*',
|
||||
private string $condition = '',
|
||||
bool $starPrefix = false,
|
||||
) {
|
||||
if ($starPrefix) {
|
||||
$this->addStarPrefix();
|
||||
}
|
||||
@@ -46,9 +42,9 @@ class XPathExpr
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function addCondition(string $condition): static
|
||||
public function addCondition(string $condition, string $operator = 'and'): static
|
||||
{
|
||||
$this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
|
||||
$this->condition = $this->condition ? sprintf('(%s) %s (%s)', $this->condition, $operator, $condition) : $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -104,7 +100,7 @@ class XPathExpr
|
||||
public function __toString(): string
|
||||
{
|
||||
$path = $this->path.$this->element;
|
||||
$condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';
|
||||
$condition = '' === $this->condition ? '' : '['.$this->condition.']';
|
||||
|
||||
return $path.$condition;
|
||||
}
|
||||
|
||||
2
vendor/symfony/css-selector/composer.json
vendored
2
vendor/symfony/css-selector/composer.json
vendored
@@ -20,7 +20,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.2"
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\CssSelector\\": "" },
|
||||
|
||||
Reference in New Issue
Block a user