Dependency updates and update version number

This commit is contained in:
Kode
2018-06-13 19:35:28 +01:00
parent 18ec208381
commit e3ec7de23a
1261 changed files with 45582 additions and 29687 deletions

View File

@@ -31,7 +31,7 @@ class CssSelectorConverter
/**
* @param bool $html Whether HTML support should be enabled. Disable it for XML documents
*/
public function __construct($html = true)
public function __construct(bool $html = true)
{
$this->translator = new Translator();

View File

@@ -31,7 +31,7 @@ abstract class AbstractNode implements NodeInterface
/**
* @return string
*/
public function getNodeName()
public function getNodeName(): string
{
if (null === $this->nodeName) {
$this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', get_called_class());

View File

@@ -29,14 +29,7 @@ class AttributeNode extends AbstractNode
private $operator;
private $value;
/**
* @param NodeInterface $selector
* @param string $namespace
* @param string $attribute
* @param string $operator
* @param string $value
*/
public function __construct(NodeInterface $selector, $namespace, $attribute, $operator, $value)
public function __construct(NodeInterface $selector, ?string $namespace, string $attribute, string $operator, ?string $value)
{
$this->selector = $selector;
$this->namespace = $namespace;
@@ -45,42 +38,27 @@ class AttributeNode extends AbstractNode
$this->value = $value;
}
/**
* @return NodeInterface
*/
public function getSelector()
public function getSelector(): NodeInterface
{
return $this->selector;
}
/**
* @return string
*/
public function getNamespace()
public function getNamespace(): ?string
{
return $this->namespace;
}
/**
* @return string
*/
public function getAttribute()
public function getAttribute(): string
{
return $this->attribute;
}
/**
* @return string
*/
public function getOperator()
public function getOperator(): string
{
return $this->operator;
}
/**
* @return string
*/
public function getValue()
public function getValue(): ?string
{
return $this->value;
}
@@ -88,7 +66,7 @@ class AttributeNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}
@@ -96,7 +74,7 @@ class AttributeNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
$attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute;

View File

@@ -26,28 +26,18 @@ class ClassNode extends AbstractNode
private $selector;
private $name;
/**
* @param NodeInterface $selector
* @param string $name
*/
public function __construct(NodeInterface $selector, $name)
public function __construct(NodeInterface $selector, string $name)
{
$this->selector = $selector;
$this->name = $name;
}
/**
* @return NodeInterface
*/
public function getSelector()
public function getSelector(): NodeInterface
{
return $this->selector;
}
/**
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
@@ -55,7 +45,7 @@ class ClassNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}
@@ -63,7 +53,7 @@ class ClassNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
}

View File

@@ -27,38 +27,24 @@ class CombinedSelectorNode extends AbstractNode
private $combinator;
private $subSelector;
/**
* @param NodeInterface $selector
* @param string $combinator
* @param NodeInterface $subSelector
*/
public function __construct(NodeInterface $selector, $combinator, NodeInterface $subSelector)
public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector)
{
$this->selector = $selector;
$this->combinator = $combinator;
$this->subSelector = $subSelector;
}
/**
* @return NodeInterface
*/
public function getSelector()
public function getSelector(): NodeInterface
{
return $this->selector;
}
/**
* @return string
*/
public function getCombinator()
public function getCombinator(): string
{
return $this->combinator;
}
/**
* @return NodeInterface
*/
public function getSubSelector()
public function getSubSelector(): NodeInterface
{
return $this->subSelector;
}
@@ -66,7 +52,7 @@ class CombinedSelectorNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
}
@@ -74,7 +60,7 @@ class CombinedSelectorNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
$combinator = ' ' === $this->combinator ? '<followed>' : $this->combinator;

View File

@@ -30,7 +30,7 @@ class ElementNode extends AbstractNode
* @param string|null $namespace
* @param string|null $element
*/
public function __construct($namespace = null, $element = null)
public function __construct(string $namespace = null, string $element = null)
{
$this->namespace = $namespace;
$this->element = $element;
@@ -55,7 +55,7 @@ class ElementNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return new Specificity(0, 0, $this->element ? 1 : 0);
}
@@ -63,7 +63,7 @@ class ElementNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
$element = $this->element ?: '*';

View File

@@ -34,25 +34,19 @@ class FunctionNode extends AbstractNode
* @param string $name
* @param Token[] $arguments
*/
public function __construct(NodeInterface $selector, $name, array $arguments = array())
public function __construct(NodeInterface $selector, string $name, array $arguments = array())
{
$this->selector = $selector;
$this->name = strtolower($name);
$this->arguments = $arguments;
}
/**
* @return NodeInterface
*/
public function getSelector()
public function getSelector(): NodeInterface
{
return $this->selector;
}
/**
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
@@ -68,7 +62,7 @@ class FunctionNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}
@@ -76,7 +70,7 @@ class FunctionNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
$arguments = implode(', ', array_map(function (Token $token) {
return "'".$token->getValue()."'";

View File

@@ -26,28 +26,18 @@ class HashNode extends AbstractNode
private $selector;
private $id;
/**
* @param NodeInterface $selector
* @param string $id
*/
public function __construct(NodeInterface $selector, $id)
public function __construct(NodeInterface $selector, string $id)
{
$this->selector = $selector;
$this->id = $id;
}
/**
* @return NodeInterface
*/
public function getSelector()
public function getSelector(): NodeInterface
{
return $this->selector;
}
/**
* @return string
*/
public function getId()
public function getId(): string
{
return $this->id;
}
@@ -55,7 +45,7 @@ class HashNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
}
@@ -63,7 +53,7 @@ class HashNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
}

View File

@@ -51,7 +51,7 @@ class NegationNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
}
@@ -59,7 +59,7 @@ class NegationNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector);
}

View File

@@ -23,24 +23,9 @@ namespace Symfony\Component\CssSelector\Node;
*/
interface NodeInterface
{
/**
* Returns node's name.
*
* @return string
*/
public function getNodeName();
public function getNodeName(): string;
/**
* Returns node's specificity.
*
* @return Specificity
*/
public function getSpecificity();
public function getSpecificity(): Specificity;
/**
* Returns node's string representation.
*
* @return string
*/
public function __toString();
public function __toString(): string;
}

View File

@@ -26,28 +26,18 @@ class PseudoNode extends AbstractNode
private $selector;
private $identifier;
/**
* @param NodeInterface $selector
* @param string $identifier
*/
public function __construct(NodeInterface $selector, $identifier)
public function __construct(NodeInterface $selector, string $identifier)
{
$this->selector = $selector;
$this->identifier = strtolower($identifier);
}
/**
* @return NodeInterface
*/
public function getSelector()
public function getSelector(): NodeInterface
{
return $this->selector;
}
/**
* @return string
*/
public function getIdentifier()
public function getIdentifier(): string
{
return $this->identifier;
}
@@ -55,7 +45,7 @@ class PseudoNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}
@@ -63,7 +53,7 @@ class PseudoNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
}

View File

@@ -26,28 +26,18 @@ class SelectorNode extends AbstractNode
private $tree;
private $pseudoElement;
/**
* @param NodeInterface $tree
* @param null|string $pseudoElement
*/
public function __construct(NodeInterface $tree, $pseudoElement = null)
public function __construct(NodeInterface $tree, string $pseudoElement = null)
{
$this->tree = $tree;
$this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
}
/**
* @return NodeInterface
*/
public function getTree()
public function getTree(): NodeInterface
{
return $this->tree;
}
/**
* @return null|string
*/
public function getPseudoElement()
public function getPseudoElement(): ?string
{
return $this->pseudoElement;
}
@@ -55,7 +45,7 @@ class SelectorNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function getSpecificity()
public function getSpecificity(): Specificity
{
return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
}
@@ -63,7 +53,7 @@ class SelectorNode extends AbstractNode
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : '');
}

View File

@@ -33,32 +33,19 @@ class Specificity
private $b;
private $c;
/**
* @param int $a
* @param int $b
* @param int $c
*/
public function __construct($a, $b, $c)
public function __construct(int $a, int $b, int $c)
{
$this->a = $a;
$this->b = $b;
$this->c = $c;
}
/**
* @return self
*/
public function plus(Specificity $specificity)
public function plus(self $specificity): self
{
return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
}
/**
* Returns global specificity value.
*
* @return int
*/
public function getValue()
public function getValue(): int
{
return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
}
@@ -69,7 +56,7 @@ class Specificity
*
* @return int
*/
public function compareTo(Specificity $specificity)
public function compareTo(self $specificity)
{
if ($this->a !== $specificity->a) {
return $this->a > $specificity->a ? 1 : -1;

View File

@@ -29,7 +29,7 @@ class CommentHandler implements HandlerInterface
/**
* {@inheritdoc}
*/
public function handle(Reader $reader, TokenStream $stream)
public function handle(Reader $reader, TokenStream $stream): bool
{
if ('/*' !== $reader->getSubstring(2)) {
return false;

View File

@@ -29,5 +29,5 @@ interface HandlerInterface
/**
* @return bool
*/
public function handle(Reader $reader, TokenStream $stream);
public function handle(Reader $reader, TokenStream $stream): bool;
}

View File

@@ -41,7 +41,7 @@ class HashHandler implements HandlerInterface
/**
* {@inheritdoc}
*/
public function handle(Reader $reader, TokenStream $stream)
public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern($this->patterns->getHashPattern());

View File

@@ -41,7 +41,7 @@ class IdentifierHandler implements HandlerInterface
/**
* {@inheritdoc}
*/
public function handle(Reader $reader, TokenStream $stream)
public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern($this->patterns->getIdentifierPattern());

View File

@@ -38,7 +38,7 @@ class NumberHandler implements HandlerInterface
/**
* {@inheritdoc}
*/
public function handle(Reader $reader, TokenStream $stream)
public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern($this->patterns->getNumberPattern());

View File

@@ -43,7 +43,7 @@ class StringHandler implements HandlerInterface
/**
* {@inheritdoc}
*/
public function handle(Reader $reader, TokenStream $stream)
public function handle(Reader $reader, TokenStream $stream): bool
{
$quote = $reader->getSubstring(1);

View File

@@ -30,7 +30,7 @@ class WhitespaceHandler implements HandlerInterface
/**
* {@inheritdoc}
*/
public function handle(Reader $reader, TokenStream $stream)
public function handle(Reader $reader, TokenStream $stream): bool
{
$match = $reader->findPattern('~^[ \t\r\n\f]+~');

View File

@@ -37,7 +37,7 @@ class Parser implements ParserInterface
/**
* {@inheritdoc}
*/
public function parse($source)
public function parse(string $source): array
{
$reader = new Reader($source);
$stream = $this->tokenizer->tokenize($reader);
@@ -50,11 +50,9 @@ class Parser implements ParserInterface
*
* @param Token[] $tokens
*
* @return array
*
* @throws SyntaxErrorException
*/
public static function parseSeries(array $tokens)
public static function parseSeries(array $tokens): array
{
foreach ($tokens as $token) {
if ($token->isString()) {
@@ -94,12 +92,7 @@ class Parser implements ParserInterface
);
}
/**
* Parses selector nodes.
*
* @return array
*/
private function parseSelectorList(TokenStream $stream)
private function parseSelectorList(TokenStream $stream): array
{
$stream->skipWhitespace();
$selectors = array();
@@ -118,14 +111,7 @@ class Parser implements ParserInterface
return $selectors;
}
/**
* Parses next selector or combined node.
*
* @return Node\SelectorNode
*
* @throws SyntaxErrorException
*/
private function parserSelectorNode(TokenStream $stream)
private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
{
list($result, $pseudoElement) = $this->parseSimpleSelector($stream);
@@ -158,14 +144,9 @@ class Parser implements ParserInterface
/**
* Parses next simple node (hash, class, pseudo, negation).
*
* @param TokenStream $stream
* @param bool $insideNegation
*
* @return array
*
* @throws SyntaxErrorException
*/
private function parseSimpleSelector(TokenStream $stream, $insideNegation = false)
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array
{
$stream->skipWhitespace();
@@ -279,12 +260,7 @@ class Parser implements ParserInterface
return array($result, $pseudoElement);
}
/**
* Parses next element node.
*
* @return Node\ElementNode
*/
private function parseElementNode(TokenStream $stream)
private function parseElementNode(TokenStream $stream): Node\ElementNode
{
$peek = $stream->getPeek();
@@ -310,14 +286,7 @@ class Parser implements ParserInterface
return new Node\ElementNode($namespace, $element);
}
/**
* Parses next attribute node.
*
* @return Node\AttributeNode
*
* @throws SyntaxErrorException
*/
private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream)
private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode
{
$stream->skipWhitespace();
$attribute = $stream->getNextIdentifierOrStar();

View File

@@ -28,9 +28,7 @@ interface ParserInterface
/**
* Parses given selector source into an array of tokens.
*
* @param string $source
*
* @return SelectorNode[]
*/
public function parse($source);
public function parse(string $source): array;
}

View File

@@ -27,56 +27,33 @@ class Reader
private $length;
private $position = 0;
/**
* @param string $source
*/
public function __construct($source)
public function __construct(string $source)
{
$this->source = $source;
$this->length = strlen($source);
}
/**
* @return bool
*/
public function isEOF()
public function isEOF(): bool
{
return $this->position >= $this->length;
}
/**
* @return int
*/
public function getPosition()
public function getPosition(): int
{
return $this->position;
}
/**
* @return int
*/
public function getRemainingLength()
public function getRemainingLength(): int
{
return $this->length - $this->position;
}
/**
* @param int $length
* @param int $offset
*
* @return string
*/
public function getSubstring($length, $offset = 0)
public function getSubstring(int $length, int $offset = 0): string
{
return substr($this->source, $this->position + $offset, $length);
}
/**
* @param string $string
*
* @return int
*/
public function getOffset($string)
public function getOffset(string $string)
{
$position = strpos($this->source, $string, $this->position);
@@ -84,11 +61,9 @@ class Reader
}
/**
* @param string $pattern
*
* @return array|false
*/
public function findPattern($pattern)
public function findPattern(string $pattern)
{
$source = substr($this->source, $this->position);
@@ -99,10 +74,7 @@ class Reader
return false;
}
/**
* @param int $length
*/
public function moveForward($length)
public function moveForward(int $length)
{
$this->position += $length;
}

View File

@@ -31,7 +31,7 @@ class ClassParser implements ParserInterface
/**
* {@inheritdoc}
*/
public function parse($source)
public function parse(string $source): array
{
// Matches an optional namespace, optional element, and required class
// $source = 'test|input.ab6bd_field';

View File

@@ -30,7 +30,7 @@ class ElementParser implements ParserInterface
/**
* {@inheritdoc}
*/
public function parse($source)
public function parse(string $source): array
{
// Matches an optional namespace, required element or `*`
// $source = 'testns|testel';

View File

@@ -34,7 +34,7 @@ class EmptyStringParser implements ParserInterface
/**
* {@inheritdoc}
*/
public function parse($source)
public function parse(string $source): array
{
// Matches an empty string
if ('' == $source) {

View File

@@ -31,7 +31,7 @@ class HashParser implements ParserInterface
/**
* {@inheritdoc}
*/
public function parse($source)
public function parse(string $source): array
{
// Matches an optional namespace, optional element, and required id
// $source = 'test|input#ab6bd_field';

View File

@@ -35,54 +35,34 @@ class Token
private $value;
private $position;
/**
* @param int $type
* @param string $value
* @param int $position
*/
public function __construct($type, $value, $position)
public function __construct(?string $type, ?string $value, ?int $position)
{
$this->type = $type;
$this->value = $value;
$this->position = $position;
}
/**
* @return int
*/
public function getType()
public function getType(): ?int
{
return $this->type;
}
/**
* @return string
*/
public function getValue()
public function getValue(): ?string
{
return $this->value;
}
/**
* @return int
*/
public function getPosition()
public function getPosition(): ?int
{
return $this->position;
}
/**
* @return bool
*/
public function isFileEnd()
public function isFileEnd(): bool
{
return self::TYPE_FILE_END === $this->type;
}
/**
* @return bool
*/
public function isDelimiter(array $values = array())
public function isDelimiter(array $values = array()): bool
{
if (self::TYPE_DELIMITER !== $this->type) {
return false;
@@ -95,50 +75,32 @@ class Token
return in_array($this->value, $values);
}
/**
* @return bool
*/
public function isWhitespace()
public function isWhitespace(): bool
{
return self::TYPE_WHITESPACE === $this->type;
}
/**
* @return bool
*/
public function isIdentifier()
public function isIdentifier(): bool
{
return self::TYPE_IDENTIFIER === $this->type;
}
/**
* @return bool
*/
public function isHash()
public function isHash(): bool
{
return self::TYPE_HASH === $this->type;
}
/**
* @return bool
*/
public function isNumber()
public function isNumber(): bool
{
return self::TYPE_NUMBER === $this->type;
}
/**
* @return bool
*/
public function isString()
public function isString(): bool
{
return self::TYPE_STRING === $this->type;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
if ($this->value) {
return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position);

View File

@@ -30,36 +30,21 @@ class TokenizerEscaping
$this->patterns = $patterns;
}
/**
* @param string $value
*
* @return string
*/
public function escapeUnicode($value)
public function escapeUnicode(string $value): string
{
$value = $this->replaceUnicodeSequences($value);
return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
}
/**
* @param string $value
*
* @return string
*/
public function escapeUnicodeAndNewLine($value)
public function escapeUnicodeAndNewLine(string $value): string
{
$value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);
return $this->escapeUnicode($value);
}
/**
* @param string $value
*
* @return string
*/
private function replaceUnicodeSequences($value)
private function replaceUnicodeSequences(string $value): string
{
return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
$c = hexdec($match[1]);

View File

@@ -46,66 +46,43 @@ class TokenizerPatterns
$this->nonAsciiPattern = '[^\x00-\x7F]';
$this->nmCharPattern = '[_a-z0-9-]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
$this->nmStartPattern = '[_a-z]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
$this->identifierPattern = '(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
$this->identifierPattern = '-?(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
$this->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
$this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
$this->quotedStringPattern = '([^\n\r\f%s]|'.$this->stringEscapePattern.')*';
}
/**
* @return string
*/
public function getNewLineEscapePattern()
public function getNewLineEscapePattern(): string
{
return '~^'.$this->newLineEscapePattern.'~';
}
/**
* @return string
*/
public function getSimpleEscapePattern()
public function getSimpleEscapePattern(): string
{
return '~^'.$this->simpleEscapePattern.'~';
}
/**
* @return string
*/
public function getUnicodeEscapePattern()
public function getUnicodeEscapePattern(): string
{
return '~^'.$this->unicodeEscapePattern.'~i';
}
/**
* @return string
*/
public function getIdentifierPattern()
public function getIdentifierPattern(): string
{
return '~^'.$this->identifierPattern.'~i';
}
/**
* @return string
*/
public function getHashPattern()
public function getHashPattern(): string
{
return '~^'.$this->hashPattern.'~i';
}
/**
* @return string
*/
public function getNumberPattern()
public function getNumberPattern(): string
{
return '~^'.$this->numberPattern.'~';
}
/**
* @param string $quote
*
* @return string
*/
public function getQuotedStringPattern($quote)
public function getQuotedStringPattern(string $quote): string
{
return '~^'.sprintf($this->quotedStringPattern, $quote).'~i';
}

View File

@@ -59,7 +59,7 @@ class CssSelectorConverterTest extends TestCase
array('h1', 'h1'),
array('foo|h1', 'foo:h1'),
array('h1, h2, h3', 'h1 | h2 | h3'),
array('h1:nth-child(3n+1)', "*/*[name() = 'h1' and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"),
array('h1:nth-child(3n+1)', "*/*[(name() = 'h1') and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"),
array('h1 > p', 'h1/p'),
array('h1#foo', "h1[@id = 'foo']"),
array('h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),

View File

@@ -186,6 +186,7 @@ class ParserTest extends TestCase
array('foo:after', 'Element[foo]', 'after'),
array('foo::selection', 'Element[foo]', 'selection'),
array('lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'),
array('video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'),
);
}

View File

@@ -102,18 +102,20 @@ class TranslatorTest extends TestCase
array('e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"),
array('e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"),
array('e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"),
array('e[foo!="bar"]', "e[not(@foo) or @foo != 'bar']"),
array('e[foo!="bar"][foo!="baz"]', "e[(not(@foo) or @foo != 'bar') and (not(@foo) or @foo != 'baz')]"),
array('e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"),
array('e:nth-child(1)', "*/*[name() = 'e' and (position() = 1)]"),
array('e:nth-last-child(1)', "*/*[name() = 'e' and (position() = last() - 0)]"),
array('e:nth-last-child(2n+2)', "*/*[name() = 'e' and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"),
array('e:nth-child(1)', "*/*[(name() = 'e') and (position() = 1)]"),
array('e:nth-last-child(1)', "*/*[(name() = 'e') and (position() = last() - 0)]"),
array('e:nth-last-child(2n+2)', "*/*[(name() = 'e') and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"),
array('e:nth-of-type(1)', '*/e[position() = 1]'),
array('e:nth-last-of-type(1)', '*/e[position() = last() - 0]'),
array('div e:nth-last-of-type(1) .aclass', "div/descendant-or-self::*/e[position() = last() - 0]/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' aclass ')]"),
array('e:first-child', "*/*[name() = 'e' and (position() = 1)]"),
array('e:last-child', "*/*[name() = 'e' and (position() = last())]"),
array('e:first-child', "*/*[(name() = 'e') and (position() = 1)]"),
array('e:last-child', "*/*[(name() = 'e') and (position() = last())]"),
array('e:first-of-type', '*/e[position() = 1]'),
array('e:last-of-type', '*/e[position() = last()]'),
array('e:only-child', "*/*[name() = 'e' and (last() = 1)]"),
array('e:only-child', "*/*[(name() = 'e') and (last() = 1)]"),
array('e:only-of-type', 'e[last() = 1]'),
array('e:empty', 'e[not(*) and not(string-length())]'),
array('e:EmPTY', 'e[not(*) and not(string-length())]'),
@@ -127,7 +129,7 @@ class TranslatorTest extends TestCase
array('e:nOT(*)', 'e[0]'),
array('e f', 'e/descendant-or-self::*/f'),
array('e > f', 'e/f'),
array('e + f', "e/following-sibling::*[name() = 'f' and (position() = 1)]"),
array('e + f', "e/following-sibling::*[(name() = 'f') and (position() = 1)]"),
array('e ~ f', 'e/following-sibling::f'),
array('div#container p', "div[@id = 'container']/descendant-or-self::*/p"),
);

View File

@@ -43,38 +43,17 @@ class AttributeMatchingExtension extends AbstractExtension
);
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateExists(XPathExpr $xpath, $attribute, $value)
public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($attribute);
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateEquals(XPathExpr $xpath, $attribute, $value)
public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value)));
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateIncludes(XPathExpr $xpath, $attribute, $value)
public function translateIncludes(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(concat(\' \', normalize-space(%1$s), \' \'), %2$s)',
@@ -83,14 +62,7 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateDashMatch(XPathExpr $xpath, $attribute, $value)
public function translateDashMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf(
'%1$s and (%1$s = %2$s or starts-with(%1$s, %3$s))',
@@ -100,14 +72,7 @@ class AttributeMatchingExtension extends AbstractExtension
));
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translatePrefixMatch(XPathExpr $xpath, $attribute, $value)
public function translatePrefixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and starts-with(%1$s, %2$s)',
@@ -116,14 +81,7 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateSuffixMatch(XPathExpr $xpath, $attribute, $value)
public function translateSuffixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and substring(%1$s, string-length(%1$s)-%2$s) = %3$s',
@@ -133,14 +91,7 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateSubstringMatch(XPathExpr $xpath, $attribute, $value)
public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(%1$s, %2$s)',
@@ -149,14 +100,7 @@ class AttributeMatchingExtension extends AbstractExtension
) : '0');
}
/**
* @param XPathExpr $xpath
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*/
public function translateDifferent(XPathExpr $xpath, $attribute, $value)
public function translateDifferent(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
{
return $xpath->addCondition(sprintf(
$value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s',

View File

@@ -28,7 +28,7 @@ class CombinationExtension extends AbstractExtension
/**
* {@inheritdoc}
*/
public function getCombinationTranslators()
public function getCombinationTranslators(): array
{
return array(
' ' => array($this, 'translateDescendant'),
@@ -41,7 +41,7 @@ class CombinationExtension extends AbstractExtension
/**
* @return XPathExpr
*/
public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath)
public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
{
return $xpath->join('/descendant-or-self::*/', $combinedXpath);
}

View File

@@ -46,16 +46,9 @@ class FunctionExtension extends AbstractExtension
}
/**
* @param XPathExpr $xpath
* @param FunctionNode $function
* @param bool $last
* @param bool $addNameTest
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateNthChild(XPathExpr $xpath, FunctionNode $function, $last = false, $addNameTest = true)
public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr
{
try {
list($a, $b) = Parser::parseSeries($function->getArguments());
@@ -110,28 +103,20 @@ class FunctionExtension extends AbstractExtension
// -1n+6 means elements 6 and previous
}
/**
* @return XPathExpr
*/
public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function)
public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
return $this->translateNthChild($xpath, $function, true);
}
/**
* @return XPathExpr
*/
public function translateNthOfType(XPathExpr $xpath, FunctionNode $function)
public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
return $this->translateNthChild($xpath, $function, false, false);
}
/**
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function)
public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
@@ -141,11 +126,9 @@ class FunctionExtension extends AbstractExtension
}
/**
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateContains(XPathExpr $xpath, FunctionNode $function)
public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {
@@ -164,11 +147,9 @@ class FunctionExtension extends AbstractExtension
}
/**
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function translateLang(XPathExpr $xpath, FunctionNode $function)
public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
$arguments = $function->getArguments();
foreach ($arguments as $token) {

View File

@@ -33,21 +33,15 @@ class NodeExtension extends AbstractExtension
private $flags;
/**
* @param int $flags
*/
public function __construct($flags = 0)
public function __construct(int $flags = 0)
{
$this->flags = $flags;
}
/**
* @param int $flag
* @param bool $on
*
* @return $this
*/
public function setFlag($flag, $on)
public function setFlag(int $flag, bool $on)
{
if ($on && !$this->hasFlag($flag)) {
$this->flags += $flag;
@@ -60,12 +54,7 @@ class NodeExtension extends AbstractExtension
return $this;
}
/**
* @param int $flag
*
* @return bool
*/
public function hasFlag($flag)
public function hasFlag(int $flag): bool
{
return (bool) ($this->flags & $flag);
}
@@ -88,26 +77,17 @@ class NodeExtension extends AbstractExtension
);
}
/**
* @return XPathExpr
*/
public function translateSelector(Node\SelectorNode $node, Translator $translator)
public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
{
return $translator->nodeToXPath($node->getTree());
}
/**
* @return XPathExpr
*/
public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator)
public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
{
return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
}
/**
* @return XPathExpr
*/
public function translateNegation(Node\NegationNode $node, Translator $translator)
public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
$subXpath = $translator->nodeToXPath($node->getSubSelector());
@@ -120,30 +100,21 @@ class NodeExtension extends AbstractExtension
return $xpath->addCondition('0');
}
/**
* @return XPathExpr
*/
public function translateFunction(Node\FunctionNode $node, Translator $translator)
public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addFunction($xpath, $node);
}
/**
* @return XPathExpr
*/
public function translatePseudo(Node\PseudoNode $node, Translator $translator)
public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addPseudoClass($xpath, $node->getIdentifier());
}
/**
* @return XPathExpr
*/
public function translateAttribute(Node\AttributeNode $node, Translator $translator)
public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
{
$name = $node->getAttribute();
$safe = $this->isSafeName($name);
@@ -168,30 +139,21 @@ class NodeExtension extends AbstractExtension
return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
}
/**
* @return XPathExpr
*/
public function translateClass(Node\ClassNode $node, Translator $translator)
public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
}
/**
* @return XPathExpr
*/
public function translateHash(Node\HashNode $node, Translator $translator)
public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
}
/**
* @return XPathExpr
*/
public function translateElement(Node\ElementNode $node)
public function translateElement(Node\ElementNode $node): XPathExpr
{
$element = $node->getElement();
@@ -228,14 +190,7 @@ class NodeExtension extends AbstractExtension
return 'node';
}
/**
* Tests if given name is safe.
*
* @param string $name
*
* @return bool
*/
private function isSafeName($name)
private function isSafeName(string $name): bool
{
return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
}

View File

@@ -61,12 +61,7 @@ class Translator implements TranslatorInterface
;
}
/**
* @param string $element
*
* @return string
*/
public static function getXpathLiteral($element)
public static function getXpathLiteral(string $element): string
{
if (false === strpos($element, "'")) {
return "'".$element."'";
@@ -95,7 +90,7 @@ class Translator implements TranslatorInterface
/**
* {@inheritdoc}
*/
public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::')
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
{
$selectors = $this->parseSelectors($cssExpr);
@@ -114,17 +109,12 @@ class Translator implements TranslatorInterface
/**
* {@inheritdoc}
*/
public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::')
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
{
return ($prefix ?: '').$this->nodeToXPath($selector);
}
/**
* Registers an extension.
*
* @return $this
*/
public function registerExtension(Extension\ExtensionInterface $extension)
public function registerExtension(Extension\ExtensionInterface $extension): self
{
$this->extensions[$extension->getName()] = $extension;
@@ -138,13 +128,9 @@ class Translator implements TranslatorInterface
}
/**
* @param string $name
*
* @return Extension\ExtensionInterface
*
* @throws ExpressionErrorException
*/
public function getExtension($name)
public function getExtension(string $name): Extension\ExtensionInterface
{
if (!isset($this->extensions[$name])) {
throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
@@ -153,12 +139,7 @@ class Translator implements TranslatorInterface
return $this->extensions[$name];
}
/**
* Registers a shortcut parser.
*
* @return $this
*/
public function registerParserShortcut(ParserInterface $shortcut)
public function registerParserShortcut(ParserInterface $shortcut): self
{
$this->shortcutParsers[] = $shortcut;
@@ -166,11 +147,9 @@ class Translator implements TranslatorInterface
}
/**
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function nodeToXPath(NodeInterface $node)
public function nodeToXPath(NodeInterface $node): XPathExpr
{
if (!isset($this->nodeTranslators[$node->getNodeName()])) {
throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
@@ -180,15 +159,9 @@ class Translator implements TranslatorInterface
}
/**
* @param string $combiner
* @param NodeInterface $xpath
* @param NodeInterface $combinedXpath
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addCombination($combiner, NodeInterface $xpath, NodeInterface $combinedXpath)
public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
{
if (!isset($this->combinationTranslators[$combiner])) {
throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
@@ -198,11 +171,9 @@ class Translator implements TranslatorInterface
}
/**
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addFunction(XPathExpr $xpath, FunctionNode $function)
public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
{
if (!isset($this->functionTranslators[$function->getName()])) {
throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
@@ -212,14 +183,9 @@ class Translator implements TranslatorInterface
}
/**
* @param XPathExpr $xpath
* @param string $pseudoClass
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addPseudoClass(XPathExpr $xpath, $pseudoClass)
public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
{
if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
@@ -229,16 +195,9 @@ class Translator implements TranslatorInterface
}
/**
* @param XPathExpr $xpath
* @param string $operator
* @param string $attribute
* @param string $value
*
* @return XPathExpr
*
* @throws ExpressionErrorException
*/
public function addAttributeMatching(XPathExpr $xpath, $operator, $attribute, $value)
public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, $value): XPathExpr
{
if (!isset($this->attributeMatchingTranslators[$operator])) {
throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator));
@@ -248,11 +207,9 @@ class Translator implements TranslatorInterface
}
/**
* @param string $css
*
* @return SelectorNode[]
*/
private function parseSelectors($css)
private function parseSelectors(string $css)
{
foreach ($this->shortcutParsers as $shortcut) {
$tokens = $shortcut->parse($css);

View File

@@ -27,21 +27,11 @@ interface TranslatorInterface
{
/**
* Translates a CSS selector to an XPath expression.
*
* @param string $cssExpr
* @param string $prefix
*
* @return string
*/
public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::');
public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string;
/**
* Translates a parsed selector node to an XPath expression.
*
* @param SelectorNode $selector
* @param string $prefix
*
* @return string
*/
public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::');
public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string;
}

View File

@@ -27,13 +27,7 @@ class XPathExpr
private $element;
private $condition;
/**
* @param string $path
* @param string $element
* @param string $condition
* @param bool $starPrefix
*/
public function __construct($path = '', $element = '*', $condition = '', $starPrefix = false)
public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false)
{
$this->path = $path;
$this->element = $element;
@@ -44,38 +38,24 @@ class XPathExpr
}
}
/**
* @return string
*/
public function getElement()
public function getElement(): string
{
return $this->element;
}
/**
* @param $condition
*
* @return $this
*/
public function addCondition($condition)
public function addCondition(string $condition): self
{
$this->condition = $this->condition ? sprintf('%s and (%s)', $this->condition, $condition) : $condition;
$this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
return $this;
}
/**
* @return string
*/
public function getCondition()
public function getCondition(): string
{
return $this->condition;
}
/**
* @return $this
*/
public function addNameTest()
public function addNameTest(): self
{
if ('*' !== $this->element) {
$this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
@@ -85,10 +65,7 @@ class XPathExpr
return $this;
}
/**
* @return $this
*/
public function addStarPrefix()
public function addStarPrefix(): self
{
$this->path .= '*/';
@@ -98,12 +75,9 @@ class XPathExpr
/**
* Joins another XPathExpr with a combiner.
*
* @param string $combiner
* @param XPathExpr $expr
*
* @return $this
*/
public function join($combiner, XPathExpr $expr)
public function join(string $combiner, self $expr): self
{
$path = $this->__toString().$combiner;
@@ -118,10 +92,7 @@ class XPathExpr
return $this;
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
$path = $this->path.$this->element;
$condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';

View File

@@ -20,7 +20,7 @@
}
],
"require": {
"php": "^5.5.9|>=7.0.8"
"php": "^7.1.3"
},
"autoload": {
"psr-4": { "Symfony\\Component\\CssSelector\\": "" },
@@ -31,7 +31,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
"dev-master": "4.1-dev"
}
}
}