Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Parser.php

function Parser::parseSimpleSelector

Parses next simple node (hash, class, pseudo, negation).

Throws

SyntaxErrorException

1 call to Parser::parseSimpleSelector()
Parser::parserSelectorNode in vendor/symfony/css-selector/Parser/Parser.php

File

vendor/symfony/css-selector/Parser/Parser.php, line 152

Class

Parser
CSS selector parser.

Namespace

Symfony\Component\CssSelector\Parser

Code

private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false, bool $isArgument = false) : array {
    $stream->skipWhitespace();
    $selectorStart = \count($stream->getUsed());
    $result = $this->parseElementNode($stream);
    $pseudoElement = null;
    while (true) {
        $peek = $stream->getPeek();
        if ($peek->isWhitespace() || $peek->isFileEnd() || $peek->isDelimiter([
            ',',
            '+',
            '>',
            '~',
        ]) || $isArgument && $peek->isDelimiter([
            ')',
        ])) {
            break;
        }
        if (null !== $pseudoElement) {
            throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
        }
        if ($peek->isHash()) {
            $result = new Node\HashNode($result, $stream->getNext()
                ->getValue());
        }
        elseif ($peek->isDelimiter([
            '.',
        ])) {
            $stream->getNext();
            $result = new Node\ClassNode($result, $stream->getNextIdentifier());
        }
        elseif ($peek->isDelimiter([
            '[',
        ])) {
            $stream->getNext();
            $result = $this->parseAttributeNode($result, $stream);
        }
        elseif ($peek->isDelimiter([
            ':',
        ])) {
            $stream->getNext();
            if ($stream->getPeek()
                ->isDelimiter([
                ':',
            ])) {
                $stream->getNext();
                $pseudoElement = $stream->getNextIdentifier();
                continue;
            }
            $identifier = $stream->getNextIdentifier();
            if (\in_array(strtolower($identifier), [
                'first-line',
                'first-letter',
                'before',
                'after',
            ])) {
                // Special case: CSS 2.1 pseudo-elements can have a single ':'.
                // Any new pseudo-element must have two.
                $pseudoElement = $identifier;
                continue;
            }
            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;
            }
            $stream->getNext();
            $stream->skipWhitespace();
            if ('not' === strtolower($identifier)) {
                if ($insideNegation) {
                    throw SyntaxErrorException::nestedNot();
                }
                [
                    $argument,
                    $argumentPseudoElement,
                ] = $this->parseSimpleSelector($stream, true, true);
                $next = $stream->getNext();
                if (null !== $argumentPseudoElement) {
                    throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
                }
                if (!$next->isDelimiter([
                    ')',
                ])) {
                    throw SyntaxErrorException::unexpectedToken('")"', $next);
                }
                $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;
                while (true) {
                    $stream->skipWhitespace();
                    $next = $stream->getNext();
                    if ($next->isIdentifier() || $next->isString() || $next->isNumber() || $next->isDelimiter([
                        '+',
                        '-',
                    ])) {
                        $arguments[] = $next;
                    }
                    elseif ($next->isDelimiter([
                        ')',
                    ])) {
                        break;
                    }
                    else {
                        throw SyntaxErrorException::unexpectedToken('an argument', $next);
                    }
                }
                if (!$arguments) {
                    throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
                }
                $result = new Node\FunctionNode($result, $identifier, $arguments);
            }
        }
        else {
            throw SyntaxErrorException::unexpectedToken('selector', $peek);
        }
    }
    if (\count($stream->getUsed()) === $selectorStart) {
        throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
    }
    return [
        $result,
        $pseudoElement,
    ];
}
RSS feed
Powered by Drupal