From 489c667f53e4886bc0cfd90055aa43bc0f5ba5f8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:23:43 +0000
Subject: [PATCH 1/9] Initial plan
From de5c380befb6530d91b3ae8512198c5b454a3cfb Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:30:29 +0000
Subject: [PATCH 2/9] Initial exploration and understanding of the repository
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.phpunit.result.cache | 1 +
.../Tests/CssSelectorConverterTest.php | 83 ++++
.../Tests/Node/AbstractNodeTestCase.php | 34 ++
.../Tests/Node/AttributeNodeTest.php | 37 ++
.../CssSelector/Tests/Node/ClassNodeTest.php | 33 ++
.../Tests/Node/CombinedSelectorNodeTest.php | 35 ++
.../Tests/Node/ElementNodeTest.php | 35 ++
.../Tests/Node/FunctionNodeTest.php | 47 ++
.../CssSelector/Tests/Node/HashNodeTest.php | 33 ++
.../Tests/Node/NegationNodeTest.php | 33 ++
.../CssSelector/Tests/Node/PseudoNodeTest.php | 32 ++
.../Tests/Node/SelectorNodeTest.php | 34 ++
.../Tests/Node/SpecificityTest.php | 63 +++
.../Handler/AbstractHandlerTestCase.php | 70 +++
.../Parser/Handler/CommentHandlerTest.php | 55 +++
.../Tests/Parser/Handler/HashHandlerTest.php | 49 +++
.../Parser/Handler/IdentifierHandlerTest.php | 49 +++
.../Parser/Handler/NumberHandlerTest.php | 50 +++
.../Parser/Handler/StringHandlerTest.php | 50 +++
.../Parser/Handler/WhitespaceHandlerTest.php | 44 ++
.../CssSelector/Tests/Parser/ParserTest.php | 263 +++++++++++
.../CssSelector/Tests/Parser/ReaderTest.php | 102 +++++
.../Tests/Parser/Shortcut/ClassParserTest.php | 45 ++
.../Parser/Shortcut/ElementParserTest.php | 44 ++
.../Parser/Shortcut/EmptyStringParserTest.php | 36 ++
.../Tests/Parser/Shortcut/HashParserTest.php | 45 ++
.../Tests/Parser/TokenStreamTest.php | 97 ++++
.../CssSelector/Tests/XPath/Fixtures/ids.html | 52 +++
.../CssSelector/Tests/XPath/Fixtures/lang.xml | 11 +
.../Tests/XPath/Fixtures/shakespear.html | 308 +++++++++++++
.../Tests/XPath/TranslatorTest.php | 416 ++++++++++++++++++
.../Component/CssSelector/phpunit.xml.dist | 31 ++
32 files changed, 2317 insertions(+)
create mode 100644 .phpunit.result.cache
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
diff --git a/.phpunit.result.cache b/.phpunit.result.cache
new file mode 100644
index 0000000..fe33bcf
--- /dev/null
+++ b/.phpunit.result.cache
@@ -0,0 +1 @@
+{"version":1,"defects":[],"times":{"PoweredCache\\Core\\Core_Tests::test_setup":0.187,"PoweredCache\\Core\\Core_Tests::test_i18n":0.024,"PoweredCache\\Core\\Core_Tests::test_init":0,"Encryption_Test::testEncrypt":0.013,"Encryption_Test::testDecrypt":0,"PoweredCache\\Utils\\Util_Tests::testIsDirEmpty":0.004,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #0":0.002,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #1":0.002,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #2":0.002,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #3":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #0":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #1":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #2":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #3":0.002,"PoweredCache\\Utils\\Util_Tests::testGetClientIp":0.002,"PoweredCache\\Utils\\Util_Tests::testBypassRequest":0.002,"PoweredCache\\Utils\\Util_Tests::testIsLocalSiteWithLocalhost":0.003,"PoweredCache\\Utils\\Util_Tests::testIsLocalSiteWithEnvironmentTypeLocal":0.002,"PoweredCache\\Utils\\Util_Tests::testIsLocalSiteWithEnvironmentTypeProduction":0.01,"PoweredCache\\Utils\\Util_Tests::testPoweredCacheIsMobileWithMobileUserAgent":0.003,"PoweredCache\\Utils\\Util_Tests::testPoweredCacheIsMobileWithNonMobileUserAgent":0.002,"PoweredCache\\Utils\\Util_Tests::testGetExpiredFiles":0.002,"PoweredCache\\Utils\\Util_Tests::testGetUrlDir":0.003}}
\ No newline at end of file
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
new file mode 100644
index 0000000..d42ce90
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\CssSelectorConverter;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ParseException;
+
+class CssSelectorConverterTest extends TestCase
+{
+ public function testCssToXPath()
+ {
+ $converter = new CssSelectorConverter();
+
+ $this->assertEquals('descendant-or-self::*', $converter->toXPath(''));
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('h1'));
+ $this->assertEquals("descendant-or-self::h1[@id = 'foo']", $converter->toXPath('h1#foo'));
+ $this->assertEquals("descendant-or-self::h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", $converter->toXPath('h1.foo'));
+ $this->assertEquals('descendant-or-self::foo:h1', $converter->toXPath('foo|h1'));
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
+
+ // Test the cache layer
+ $converter = new CssSelectorConverter();
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
+ }
+
+ public function testCssToXPathXml()
+ {
+ $converter = new CssSelectorConverter(false);
+
+ $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
+
+ $converter = new CssSelectorConverter(false);
+ // Test the cache layer
+ $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
+ }
+
+ public function testParseExceptions()
+ {
+ $this->expectException(ParseException::class);
+ $this->expectExceptionMessage('Expected identifier, but found.');
+ $converter = new CssSelectorConverter();
+ $converter->toXPath('h1:');
+ }
+
+ /** @dataProvider getCssToXPathWithoutPrefixTestData */
+ public function testCssToXPathWithoutPrefix($css, $xpath)
+ {
+ $converter = new CssSelectorConverter();
+
+ $this->assertEquals($xpath, $converter->toXPath($css, ''), '->parse() parses an input string and returns a node');
+ }
+
+ public static function getCssToXPathWithoutPrefixTestData()
+ {
+ return [
+ ['h1', 'h1'],
+ ['foo|h1', 'foo:h1'],
+ ['h1, h2, h3', 'h1 | h2 | h3'],
+ ['h1:nth-child(3n+1)', "*/*[(name() = 'h1') and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"],
+ ['h1 > p', 'h1/p'],
+ ['h1#foo', "h1[@id = 'foo']"],
+ ['h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['h1[class*="foo bar"]', "h1[@class and contains(@class, 'foo bar')]"],
+ ['h1[foo|class*="foo bar"]', "h1[@foo:class and contains(@foo:class, 'foo bar')]"],
+ ['h1[class]', 'h1[@class]'],
+ ['h1 .foo', "h1/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['h1 #foo', "h1/descendant-or-self::*/*[@id = 'foo']"],
+ ['h1 [class*=foo]', "h1/descendant-or-self::*/*[@class and contains(@class, 'foo')]"],
+ ['div>.foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['div > .foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
new file mode 100644
index 0000000..99460ae
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NodeInterface;
+
+abstract class AbstractNodeTestCase extends TestCase
+{
+ /** @dataProvider getToStringConversionTestData */
+ public function testToStringConversion(NodeInterface $node, $representation)
+ {
+ $this->assertEquals($representation, (string) $node);
+ }
+
+ /** @dataProvider getSpecificityValueTestData */
+ public function testSpecificityValue(NodeInterface $node, $value)
+ {
+ $this->assertEquals($value, $node->getSpecificity()->getValue());
+ }
+
+ abstract public static function getToStringConversionTestData();
+
+ abstract public static function getSpecificityValueTestData();
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
new file mode 100644
index 0000000..5115605
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\AttributeNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class AttributeNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 'Powered_Cache_Attribute[Element[*][attribute]]'],
+ [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][attribute $= 'value']]"],
+ [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][namespace|attribute $= 'value']]"],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 10],
+ [new AttributeNode(new ElementNode(null, 'element'), null, 'attribute', 'exists', null), 11],
+ [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), 10],
+ [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
new file mode 100644
index 0000000..ae43a62
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class ClassNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new ClassNode(new ElementNode(), 'class'), 'Class[Element[*].class]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new ClassNode(new ElementNode(), 'class'), 10],
+ [new ClassNode(new ElementNode(null, 'element'), 'class'), 11],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
new file mode 100644
index 0000000..d9b2a38
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\CombinedSelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class CombinedSelectorNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 'CombinedSelector[Element[*] > Element[*]]'],
+ [new CombinedSelectorNode(new ElementNode(), ' ', new ElementNode()), 'CombinedSelector[Element[*] Element[*]]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 0],
+ [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode()), 1],
+ [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode(null, 'element')), 2],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
new file mode 100644
index 0000000..b3ef2b2
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class ElementNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new ElementNode(), 'Element[*]'],
+ [new ElementNode(null, 'element'), 'Element[element]'],
+ [new ElementNode('namespace', 'element'), 'Element[namespace|element]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new ElementNode(), 0],
+ [new ElementNode(null, 'element'), 1],
+ [new ElementNode('namespace', 'element'), 1],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
new file mode 100644
index 0000000..f99a66b
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+class FunctionNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new FunctionNode(new ElementNode(), 'function'), 'Function[Element[*]:function()]'],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+ ]), "Function[Element[*]:function(['value'])]"],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_STRING, 'value1', 0),
+ new Token(Token::TYPE_NUMBER, 'value2', 0),
+ ]), "Function[Element[*]:function(['value1', 'value2'])]"],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new FunctionNode(new ElementNode(), 'function'), 10],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+ ]), 10],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_STRING, 'value1', 0),
+ new Token(Token::TYPE_NUMBER, 'value2', 0),
+ ]), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
new file mode 100644
index 0000000..d43aac1
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\HashNode;
+
+class HashNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new HashNode(new ElementNode(), 'id'), 'Hash[Element[*]#id]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new HashNode(new ElementNode(), 'id'), 100],
+ [new HashNode(new ElementNode(null, 'id'), 'class'), 101],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
new file mode 100644
index 0000000..9aafe8f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NegationNode;
+
+class NegationNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 'Negation[Element[*]:not(Class[Element[*].class])]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
new file mode 100644
index 0000000..cf13881
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\PseudoNode;
+
+class PseudoNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new PseudoNode(new ElementNode(), 'pseudo'), 'Pseudo[Element[*]:pseudo]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new PseudoNode(new ElementNode(), 'pseudo'), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
new file mode 100644
index 0000000..142b104
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+
+class SelectorNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new SelectorNode(new ElementNode()), 'Selector[Element[*]]'],
+ [new SelectorNode(new ElementNode(), 'pseudo'), 'Selector[Element[*]::pseudo]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new SelectorNode(new ElementNode()), 0],
+ [new SelectorNode(new ElementNode(), 'pseudo'), 1],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
new file mode 100644
index 0000000..790f8c1
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\Specificity;
+
+class SpecificityTest extends TestCase
+{
+ /** @dataProvider getValueTestData */
+ public function testValue(Specificity $specificity, $value)
+ {
+ $this->assertEquals($value, $specificity->getValue());
+ }
+
+ /** @dataProvider getValueTestData */
+ public function testPlusValue(Specificity $specificity, $value)
+ {
+ $this->assertEquals($value + 123, $specificity->plus(new Specificity(1, 2, 3))->getValue());
+ }
+
+ public static function getValueTestData()
+ {
+ return [
+ [new Specificity(0, 0, 0), 0],
+ [new Specificity(0, 0, 2), 2],
+ [new Specificity(0, 3, 0), 30],
+ [new Specificity(4, 0, 0), 400],
+ [new Specificity(4, 3, 2), 432],
+ ];
+ }
+
+ /** @dataProvider getCompareTestData */
+ public function testCompareTo(Specificity $a, Specificity $b, $result)
+ {
+ $this->assertEquals($result, $a->compareTo($b));
+ }
+
+ public static function getCompareTestData()
+ {
+ return [
+ [new Specificity(0, 0, 0), new Specificity(0, 0, 0), 0],
+ [new Specificity(0, 0, 1), new Specificity(0, 0, 1), 0],
+ [new Specificity(0, 0, 2), new Specificity(0, 0, 1), 1],
+ [new Specificity(0, 0, 2), new Specificity(0, 0, 3), -1],
+ [new Specificity(0, 4, 0), new Specificity(0, 4, 0), 0],
+ [new Specificity(0, 6, 0), new Specificity(0, 5, 11), 1],
+ [new Specificity(0, 7, 0), new Specificity(0, 8, 0), -1],
+ [new Specificity(9, 0, 0), new Specificity(9, 0, 0), 0],
+ [new Specificity(11, 0, 0), new Specificity(10, 11, 0), 1],
+ [new Specificity(12, 11, 0), new Specificity(13, 0, 0), -1],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
new file mode 100644
index 0000000..b46f2f7
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * @author Jean-François Simon
+ */
+abstract class AbstractHandlerTestCase extends TestCase
+{
+ /** @dataProvider getHandleValueTestData */
+ public function testHandleValue($value, Token $expectedToken, $remainingContent)
+ {
+ $reader = new Reader($value);
+ $stream = new TokenStream();
+
+ $this->assertTrue($this->generateHandler()->handle($reader, $stream));
+ $this->assertEquals($expectedToken, $stream->getNext());
+ $this->assertRemainingContent($reader, $remainingContent);
+ }
+
+ /** @dataProvider getDontHandleValueTestData */
+ public function testDontHandleValue($value)
+ {
+ $reader = new Reader($value);
+ $stream = new TokenStream();
+
+ $this->assertFalse($this->generateHandler()->handle($reader, $stream));
+ $this->assertStreamEmpty($stream);
+ $this->assertRemainingContent($reader, $value);
+ }
+
+ abstract public static function getHandleValueTestData();
+
+ abstract public static function getDontHandleValueTestData();
+
+ abstract protected function generateHandler();
+
+ protected function assertStreamEmpty(TokenStream $stream)
+ {
+ $property = new \ReflectionProperty($stream, 'tokens');
+ $property->setAccessible(true);
+
+ $this->assertEquals([], $property->getValue($stream));
+ }
+
+ protected function assertRemainingContent(Reader $reader, $remainingContent)
+ {
+ if ('' === $remainingContent) {
+ $this->assertEquals(0, $reader->getRemainingLength());
+ $this->assertTrue($reader->isEOF());
+ } else {
+ $this->assertEquals(\strlen($remainingContent), $reader->getRemainingLength());
+ $this->assertEquals(0, $reader->getOffset($remainingContent));
+ }
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
new file mode 100644
index 0000000..459d8de
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\CommentHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+class CommentHandlerTest extends AbstractHandlerTestCase
+{
+ /** @dataProvider getHandleValueTestData */
+ public function testHandleValue($value, Token $unusedArgument, $remainingContent)
+ {
+ $reader = new Reader($value);
+ $stream = new TokenStream();
+
+ $this->assertTrue($this->generateHandler()->handle($reader, $stream));
+ // comments are ignored (not pushed as token in stream)
+ $this->assertStreamEmpty($stream);
+ $this->assertRemainingContent($reader, $remainingContent);
+ }
+
+ public static function getHandleValueTestData()
+ {
+ return [
+ // 2nd argument only exists for inherited method compatibility
+ ['/* comment */', new Token(null, null, null), ''],
+ ['/* comment */foo', new Token(null, null, null), 'foo'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['+'],
+ [' '],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ return new CommentHandler();
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
new file mode 100644
index 0000000..a96c861
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\HashHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class HashHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['#id', new Token(Token::TYPE_HASH, 'id', 0), ''],
+ ['#123', new Token(Token::TYPE_HASH, '123', 0), ''],
+
+ ['#id.class', new Token(Token::TYPE_HASH, 'id', 0), '.class'],
+ ['#id element', new Token(Token::TYPE_HASH, 'id', 0), ' element'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['id'],
+ ['123'],
+ ['<'],
+ ['<'],
+ ['#'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new HashHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
new file mode 100644
index 0000000..1cb9ffe
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\IdentifierHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class IdentifierHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['foo', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ''],
+ ['foo|bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '|bar'],
+ ['foo.class', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '.class'],
+ ['foo[attr]', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '[attr]'],
+ ['foo bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ' bar'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['+'],
+ [' '],
+ ['*|foo'],
+ ['/* comment */'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new IdentifierHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
new file mode 100644
index 0000000..e40b86f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\NumberHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class NumberHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['12', new Token(Token::TYPE_NUMBER, '12', 0), ''],
+ ['12.34', new Token(Token::TYPE_NUMBER, '12.34', 0), ''],
+ ['+12.34', new Token(Token::TYPE_NUMBER, '+12.34', 0), ''],
+ ['-12.34', new Token(Token::TYPE_NUMBER, '-12.34', 0), ''],
+
+ ['12 arg', new Token(Token::TYPE_NUMBER, '12', 0), ' arg'],
+ ['12]', new Token(Token::TYPE_NUMBER, '12', 0), ']'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['hello'],
+ ['>'],
+ ['+'],
+ [' '],
+ ['/* comment */'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new NumberHandler($patterns);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
new file mode 100644
index 0000000..d00233c
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\StringHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class StringHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['"hello"', new Token(Token::TYPE_STRING, 'hello', 1), ''],
+ ['"1"', new Token(Token::TYPE_STRING, '1', 1), ''],
+ ['" "', new Token(Token::TYPE_STRING, ' ', 1), ''],
+ ['""', new Token(Token::TYPE_STRING, '', 1), ''],
+ ["'hello'", new Token(Token::TYPE_STRING, 'hello', 1), ''],
+
+ ["'foo'bar", new Token(Token::TYPE_STRING, 'foo', 1), 'bar'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['hello'],
+ ['>'],
+ ['1'],
+ [' '],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new StringHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
new file mode 100644
index 0000000..1cd3e9d
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\WhitespaceHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+class WhitespaceHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ [' ', new Token(Token::TYPE_WHITESPACE, ' ', 0), ''],
+ ["\n", new Token(Token::TYPE_WHITESPACE, "\n", 0), ''],
+ ["\t", new Token(Token::TYPE_WHITESPACE, "\t", 0), ''],
+
+ [' foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), 'foo'],
+ [' .foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), '.foo'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['1'],
+ ['a'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ return new WhitespaceHandler();
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
new file mode 100644
index 0000000..a9ef9d6
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
@@ -0,0 +1,263 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+class ParserTest extends TestCase
+{
+ /** @dataProvider getParserTestData */
+ public function testParser($source, $representation)
+ {
+ $parser = new Parser();
+
+ $this->assertEquals($representation, array_map(function (SelectorNode $node) {
+ return (string) $node->getTree();
+ }, $parser->parse($source)));
+ }
+
+ /** @dataProvider getParserExceptionTestData */
+ public function testParserException($source, $message)
+ {
+ $parser = new Parser();
+
+ try {
+ $parser->parse($source);
+ $this->fail('Parser should throw a SyntaxErrorException.');
+ } catch (SyntaxErrorException $e) {
+ $this->assertEquals($message, $e->getMessage());
+ }
+ }
+
+ /** @dataProvider getPseudoElementsTestData */
+ public function testPseudoElements($source, $element, $pseudo)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($element, (string) $selector->getTree());
+ $this->assertEquals($pseudo, (string) $selector->getPseudoElement());
+ }
+
+ /** @dataProvider getSpecificityTestData */
+ public function testSpecificity($source, $value)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($value, $selector->getSpecificity()->getValue());
+ }
+
+ /** @dataProvider getParseSeriesTestData */
+ public function testParseSeries($series, $a, $b)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
+ $this->assertCount(1, $selectors);
+
+ /** @var FunctionNode $function */
+ $function = $selectors[0]->getTree();
+ $this->assertEquals([$a, $b], Parser::parseSeries($function->getArguments()));
+ }
+
+ /** @dataProvider getParseSeriesExceptionTestData */
+ public function testParseSeriesException($series)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
+ $this->assertCount(1, $selectors);
+
+ /** @var FunctionNode $function */
+ $function = $selectors[0]->getTree();
+ $this->expectException(SyntaxErrorException::class);
+ Parser::parseSeries($function->getArguments());
+ }
+
+ public static function getParserTestData()
+ {
+ return [
+ ['*', ['Element[*]']],
+ ['*|*', ['Element[*]']],
+ ['*|foo', ['Element[foo]']],
+ ['foo|*', ['Element[foo|*]']],
+ ['foo|bar', ['Element[foo|bar]']],
+ ['#foo#bar', ['Hash[Hash[Element[*]#foo]#bar]']],
+ ['div>.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div> .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div >.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div > .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ["div \n> \t \t .foo", ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['div, td.foo, div.bar span', ['Element[div]', 'Class[Element[td].foo]', 'CombinedSelector[Class[Element[div].bar] Element[span]]']],
+ ['div > p', ['CombinedSelector[Element[div] > Element[p]]']],
+ ['td:first', ['Pseudo[Element[td]:first]']],
+ ['td :first', ['CombinedSelector[Element[td] Pseudo[Element[*]:first]]']],
+ ['a[name]', ['Powered_Cache_Attribute[Element[a][name]]']],
+ ["a[ name\t]", ['Powered_Cache_Attribute[Element[a][name]]']],
+ ['a [name]', ['CombinedSelector[Element[a] Powered_Cache_Attribute[Element[*][name]]]']],
+ ['[name="foo"]', ["Powered_Cache_Attribute[Element[*][name = 'foo']]"]],
+ ["[name='foo[1]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[1]']]"]],
+ ["[name='foo[0][bar]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[0][bar]']]"]],
+ ['a[rel="include"]', ["Attribute[Element[a][rel = 'include']]"]],
+ ['a[rel = include]', ["Attribute[Element[a][rel = 'include']]"]],
+ ["a[hreflang |= 'en']", ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
+ ['a[hreflang|=en]', ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
+ ['div:nth-child(10)', ["Function[Element[div]:nth-child(['10'])]"]],
+ [':nth-child(2n+2)', ["Function[Element[*]:nth-child(['2', 'n', '+2'])]"]],
+ ['div:nth-of-type(10)', ["Function[Element[div]:nth-of-type(['10'])]"]],
+ ['div div:nth-of-type(10) .aclass', ["CombinedSelector[CombinedSelector[Element[div] Function[Element[div]:nth-of-type(['10'])]] Class[Element[*].aclass]]"]],
+ ['label:only', ['Pseudo[Element[label]:only]']],
+ ['a:lang(fr)', ["Function[Element[a]:lang(['fr'])]"]],
+ ['div:contains("foo")', ["Function[Element[div]:contains(['foo'])]"]],
+ ['div#foobar', ['Hash[Element[div]#foobar]']],
+ ['div:not(div.foo)', ['Negation[Element[div]:not(Class[Element[div].foo])]']],
+ ['td ~ th', ['CombinedSelector[Element[td] ~ Element[th]]']],
+ ['.foo[data-bar][data-baz=0]', ["Powered_Cache_Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]"]],
+ ['div#foo\.bar', ['Hash[Element[div]#foo.bar]']],
+ ['div.w-1\/3', ['Class[Element[div].w-1/3]']],
+ ['#test\:colon', ['Hash[Element[*]#test:colon]']],
+ [".a\xc1b", ["Class[Element[*].a\xc1b]"]],
+ // unicode escape: \22 == "
+ ['*[aval="\'\22\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"\'\']]']],
+ ['*[aval="\'\22 2\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"2\'\']]']],
+ // unicode escape: \20 == (space)
+ ['*[aval="\'\20 \'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
+ ["*[aval=\"'\\20\r\n '\"]", ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
+ ];
+ }
+
+ public static function getParserExceptionTestData()
+ {
+ return [
+ ['attributes(href)/html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
+ ['attributes(href)', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
+ ['html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '/', 4))->getMessage()],
+ [' ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 1))->getMessage()],
+ ['div, ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 5))->getMessage()],
+ [' , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 1))->getMessage()],
+ ['p, , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 3))->getMessage()],
+ ['div > ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 6))->getMessage()],
+ [' > div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '>', 2))->getMessage()],
+ ['foo|#bar', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_HASH, 'bar', 4))->getMessage()],
+ ['#.foo', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '#', 0))->getMessage()],
+ ['.#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
+ [':#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
+ ['[*]', SyntaxErrorException::unexpectedToken('"|"', new Token(Token::TYPE_DELIMITER, ']', 2))->getMessage()],
+ ['[foo|]', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_DELIMITER, ']', 5))->getMessage()],
+ ['[#]', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_DELIMITER, '#', 1))->getMessage()],
+ ['[foo=#]', SyntaxErrorException::unexpectedToken('string or identifier', new Token(Token::TYPE_DELIMITER, '#', 5))->getMessage()],
+ [':nth-child()', SyntaxErrorException::unexpectedToken('at least one argument', new Token(Token::TYPE_DELIMITER, ')', 11))->getMessage()],
+ ['[href]a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_IDENTIFIER, 'a', 6))->getMessage()],
+ ['[rel:stylesheet]', SyntaxErrorException::unexpectedToken('operator', new Token(Token::TYPE_DELIMITER, ':', 4))->getMessage()],
+ ['[rel=stylesheet', SyntaxErrorException::unexpectedToken('"]"', new Token(Token::TYPE_FILE_END, '', 15))->getMessage()],
+ [':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()],
+ [':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
+ ['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
+ ];
+ }
+
+ public static function getPseudoElementsTestData()
+ {
+ return [
+ ['foo', 'Element[foo]', ''],
+ ['*', 'Element[*]', ''],
+ [':empty', 'Pseudo[Element[*]:empty]', ''],
+ [':BEfore', 'Element[*]', 'before'],
+ [':aftER', 'Element[*]', 'after'],
+ [':First-Line', 'Element[*]', 'first-line'],
+ [':First-Letter', 'Element[*]', 'first-letter'],
+ ['::befoRE', 'Element[*]', 'before'],
+ ['::AFter', 'Element[*]', 'after'],
+ ['::firsT-linE', 'Element[*]', 'first-line'],
+ ['::firsT-letteR', 'Element[*]', 'first-letter'],
+ ['::Selection', 'Element[*]', 'selection'],
+ ['foo:after', 'Element[foo]', 'after'],
+ ['foo::selection', 'Element[foo]', 'selection'],
+ ['lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Powered_Cache_Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'],
+ ['video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'],
+ ];
+ }
+
+ public static function getSpecificityTestData()
+ {
+ return [
+ ['*', 0],
+ [' foo', 1],
+ [':empty ', 10],
+ [':before', 1],
+ ['*:before', 1],
+ [':nth-child(2)', 10],
+ ['.bar', 10],
+ ['[baz]', 10],
+ ['[baz="4"]', 10],
+ ['[baz^="4"]', 10],
+ ['#lipsum', 100],
+ [':not(*)', 0],
+ [':not(foo)', 1],
+ [':not(.foo)', 10],
+ [':not([foo])', 10],
+ [':not(:empty)', 10],
+ [':not(#foo)', 100],
+ ['foo:empty', 11],
+ ['foo:before', 2],
+ ['foo::before', 2],
+ ['foo:empty::before', 12],
+ ['#lorem + foo#ipsum:first-child > bar:first-line', 213],
+ ];
+ }
+
+ public static function getParseSeriesTestData()
+ {
+ return [
+ ['1n+3', 1, 3],
+ ['1n +3', 1, 3],
+ ['1n + 3', 1, 3],
+ ['1n+ 3', 1, 3],
+ ['1n-3', 1, -3],
+ ['1n -3', 1, -3],
+ ['1n - 3', 1, -3],
+ ['1n- 3', 1, -3],
+ ['n-5', 1, -5],
+ ['odd', 2, 1],
+ ['even', 2, 0],
+ ['3n', 3, 0],
+ ['n', 1, 0],
+ ['+n', 1, 0],
+ ['-n', -1, 0],
+ ['5', 0, 5],
+ ];
+ }
+
+ public static function getParseSeriesExceptionTestData()
+ {
+ return [
+ ['foo'],
+ ['n+'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
new file mode 100644
index 0000000..b160113
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
@@ -0,0 +1,102 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+
+class ReaderTest extends TestCase
+{
+ public function testIsEOF()
+ {
+ $reader = new Reader('');
+ $this->assertTrue($reader->isEOF());
+
+ $reader = new Reader('hello');
+ $this->assertFalse($reader->isEOF());
+
+ $this->assignPosition($reader, 2);
+ $this->assertFalse($reader->isEOF());
+
+ $this->assignPosition($reader, 5);
+ $this->assertTrue($reader->isEOF());
+ }
+
+ public function testGetRemainingLength()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals(5, $reader->getRemainingLength());
+
+ $this->assignPosition($reader, 2);
+ $this->assertEquals(3, $reader->getRemainingLength());
+
+ $this->assignPosition($reader, 5);
+ $this->assertEquals(0, $reader->getRemainingLength());
+ }
+
+ public function testGetSubstring()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals('he', $reader->getSubstring(2));
+ $this->assertEquals('el', $reader->getSubstring(2, 1));
+
+ $this->assignPosition($reader, 2);
+ $this->assertEquals('ll', $reader->getSubstring(2));
+ $this->assertEquals('lo', $reader->getSubstring(2, 1));
+ }
+
+ public function testGetOffset()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals(2, $reader->getOffset('ll'));
+ $this->assertFalse($reader->getOffset('w'));
+
+ $this->assignPosition($reader, 2);
+ $this->assertEquals(0, $reader->getOffset('ll'));
+ $this->assertFalse($reader->getOffset('he'));
+ }
+
+ public function testFindPattern()
+ {
+ $reader = new Reader('hello');
+
+ $this->assertFalse($reader->findPattern('/world/'));
+ $this->assertEquals(['hello', 'h'], $reader->findPattern('/^([a-z]).*/'));
+
+ $this->assignPosition($reader, 2);
+ $this->assertFalse($reader->findPattern('/^h.*/'));
+ $this->assertEquals(['llo'], $reader->findPattern('/^llo$/'));
+ }
+
+ public function testMoveForward()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals(0, $reader->getPosition());
+
+ $reader->moveForward(2);
+ $this->assertEquals(2, $reader->getPosition());
+ }
+
+ public function testToEnd()
+ {
+ $reader = new Reader('hello');
+ $reader->moveToEnd();
+ $this->assertTrue($reader->isEOF());
+ }
+
+ private function assignPosition(Reader $reader, int $value)
+ {
+ $position = new \ReflectionProperty($reader, 'position');
+ $position->setAccessible(true);
+ $position->setValue($reader, $value);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
new file mode 100644
index 0000000..188d29f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class ClassParserTest extends TestCase
+{
+ /** @dataProvider getParseTestData */
+ public function testParse($source, $representation)
+ {
+ $parser = new ClassParser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($representation, (string) $selector->getTree());
+ }
+
+ public static function getParseTestData()
+ {
+ return [
+ ['.testclass', 'Class[Element[*].testclass]'],
+ ['testel.testclass', 'Class[Element[testel].testclass]'],
+ ['testns|.testclass', 'Class[Element[testns|*].testclass]'],
+ ['testns|*.testclass', 'Class[Element[testns|*].testclass]'],
+ ['testns|testel.testclass', 'Class[Element[testns|testel].testclass]'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
new file mode 100644
index 0000000..58540ea
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class ElementParserTest extends TestCase
+{
+ /** @dataProvider getParseTestData */
+ public function testParse($source, $representation)
+ {
+ $parser = new ElementParser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($representation, (string) $selector->getTree());
+ }
+
+ public static function getParseTestData()
+ {
+ return [
+ ['*', 'Element[*]'],
+ ['testel', 'Element[testel]'],
+ ['testns|*', 'Element[testns|*]'],
+ ['testns|testel', 'Element[testns|testel]'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
new file mode 100644
index 0000000..b6540ff
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class EmptyStringParserTest extends TestCase
+{
+ public function testParse()
+ {
+ $parser = new EmptyStringParser();
+ $selectors = $parser->parse('');
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals('Element[*]', (string) $selector->getTree());
+
+ $selectors = $parser->parse('this will produce an empty array');
+ $this->assertCount(0, $selectors);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
new file mode 100644
index 0000000..9a92ca4
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class HashParserTest extends TestCase
+{
+ /** @dataProvider getParseTestData */
+ public function testParse($source, $representation)
+ {
+ $parser = new HashParser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($representation, (string) $selector->getTree());
+ }
+
+ public static function getParseTestData()
+ {
+ return [
+ ['#testid', 'Hash[Element[*]#testid]'],
+ ['testel#testid', 'Hash[Element[testel]#testid]'],
+ ['testns|#testid', 'Hash[Element[testns|*]#testid]'],
+ ['testns|*#testid', 'Hash[Element[testns|*]#testid]'],
+ ['testns|testel#testid', 'Hash[Element[testns|testel]#testid]'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
new file mode 100644
index 0000000..ec7f7f5
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+class TokenStreamTest extends TestCase
+{
+ public function testGetNext()
+ {
+ $stream = new TokenStream();
+ $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
+
+ $this->assertSame($t1, $stream->getNext());
+ $this->assertSame($t2, $stream->getNext());
+ $this->assertSame($t3, $stream->getNext());
+ }
+
+ public function testGetPeek()
+ {
+ $stream = new TokenStream();
+ $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
+
+ $this->assertSame($t1, $stream->getPeek());
+ $this->assertSame($t1, $stream->getNext());
+ $this->assertSame($t2, $stream->getPeek());
+ $this->assertSame($t2, $stream->getPeek());
+ $this->assertSame($t2, $stream->getNext());
+ }
+
+ public function testGetNextIdentifier()
+ {
+ $stream = new TokenStream();
+ $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+
+ $this->assertEquals('h1', $stream->getNextIdentifier());
+ }
+
+ public function testFailToGetNextIdentifier()
+ {
+ $this->expectException(SyntaxErrorException::class);
+
+ $stream = new TokenStream();
+ $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->getNextIdentifier();
+ }
+
+ public function testGetNextIdentifierOrStar()
+ {
+ $stream = new TokenStream();
+
+ $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $this->assertEquals('h1', $stream->getNextIdentifierOrStar());
+
+ $stream->push(new Token(Token::TYPE_DELIMITER, '*', 0));
+ $this->assertNull($stream->getNextIdentifierOrStar());
+ }
+
+ public function testFailToGetNextIdentifierOrStar()
+ {
+ $this->expectException(SyntaxErrorException::class);
+
+ $stream = new TokenStream();
+ $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->getNextIdentifierOrStar();
+ }
+
+ public function testSkipWhitespace()
+ {
+ $stream = new TokenStream();
+ $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $stream->push($t2 = new Token(Token::TYPE_WHITESPACE, ' ', 2));
+ $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'h1', 3));
+
+ $stream->skipWhitespace();
+ $this->assertSame($t1, $stream->getNext());
+
+ $stream->skipWhitespace();
+ $this->assertSame($t3, $stream->getNext());
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
new file mode 100644
index 0000000..1147bf3
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
new file mode 100644
index 0000000..14f8dbe
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
@@ -0,0 +1,11 @@
+
+ a
+ b
+ c
+ d
+ e
+ f
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
new file mode 100644
index 0000000..15d1ad3
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
As You Like It
+
+ by William Shakespeare
+
+
+
ACT I, SCENE III. A room in the palace.
+
+
Enter CELIA and ROSALIND
+
+
CELIA
+
+
Why, cousin! why, Rosalind! Cupid have mercy! not a word?
+
+
ROSALIND
+
+
Not one to throw at a dog.
+
+
CELIA
+
+
No, thy words are too precious to be cast away upon
+
curs; throw some of them at me; come, lame me with reasons.
+
+
ROSALIND
+
CELIA
+
+
But is all this for your father?
+
+
+
Then there were two cousins laid up; when the one
+
should be lamed with reasons and the other mad
+
without any.
+
+
ROSALIND
+
+
No, some of it is for my child's father. O, how
+
full of briers is this working-day world!
+
+
CELIA
+
+
They are but burs, cousin, thrown upon thee in
+
holiday foolery: if we walk not in the trodden
+
paths our very petticoats will catch them.
+
+
ROSALIND
+
+
I could shake them off my coat: these burs are in my heart.
+
+
CELIA
+
+
ROSALIND
+
+
I would try, if I could cry 'hem' and have him.
+
+
CELIA
+
+
Come, come, wrestle with thy affections.
+
+
ROSALIND
+
+
O, they take the part of a better wrestler than myself!
+
+
CELIA
+
+
O, a good wish upon you! you will try in time, in
+
despite of a fall. But, turning these jests out of
+
service, let us talk in good earnest: is it
+
possible, on such a sudden, you should fall into so
+
strong a liking with old Sir Rowland's youngest son?
+
+
ROSALIND
+
+
The duke my father loved his father dearly.
+
+
CELIA
+
+
Doth it therefore ensue that you should love his son
+
dearly? By this kind of chase, I should hate him,
+
for my father hated his father dearly; yet I hate
+
not Orlando.
+
+
ROSALIND
+
+
No, faith, hate him not, for my sake.
+
+
CELIA
+
+
Why should I not? doth he not deserve well?
+
+
ROSALIND
+
+
Let me love him for that, and do you love him
+
because I do. Look, here comes the duke.
+
+
CELIA
+
+
With his eyes full of anger.
+
Enter DUKE FREDERICK, with Lords
+
+
DUKE FREDERICK
+
+
Mistress, dispatch you with your safest haste
+
And get you from our court.
+
+
ROSALIND
+
+
DUKE FREDERICK
+
+
You, cousin
+
Within these ten days if that thou be'st found
+
So near our public court as twenty miles,
+
Thou diest for it.
+
+
ROSALIND
+
+
I do beseech your grace,
+
Let me the knowledge of my fault bear with me:
+
If with myself I hold intelligence
+
Or have acquaintance with mine own desires,
+
If that I do not dream or be not frantic,--
+
As I do trust I am not--then, dear uncle,
+
Never so much as in a thought unborn
+
Did I offend your highness.
+
+
DUKE FREDERICK
+
+
Thus do all traitors:
+
If their purgation did consist in words,
+
They are as innocent as grace itself:
+
Let it suffice thee that I trust thee not.
+
+
ROSALIND
+
+
Yet your mistrust cannot make me a traitor:
+
Tell me whereon the likelihood depends.
+
+
DUKE FREDERICK
+
+
Thou art thy father's daughter; there's enough.
+
+
ROSALIND
+
+
So was I when your highness took his dukedom;
+
So was I when your highness banish'd him:
+
Treason is not inherited, my lord;
+
Or, if we did derive it from our friends,
+
What's that to me? my father was no traitor:
+
Then, good my liege, mistake me not so much
+
To think my poverty is treacherous.
+
+
CELIA
+
+
Dear sovereign, hear me speak.
+
+
DUKE FREDERICK
+
+
Ay, Celia; we stay'd her for your sake,
+
Else had she with her father ranged along.
+
+
CELIA
+
+
I did not then entreat to have her stay;
+
It was your pleasure and your own remorse:
+
I was too young that time to value her;
+
But now I know her: if she be a traitor,
+
Why so am I; we still have slept together,
+
Rose at an instant, learn'd, play'd, eat together,
+
And wheresoever we went, like Juno's swans,
+
Still we went coupled and inseparable.
+
+
DUKE FREDERICK
+
+
She is too subtle for thee; and her smoothness,
+
Her very silence and her patience
+
Speak to the people, and they pity her.
+
Thou art a fool: she robs thee of thy name;
+
And thou wilt show more bright and seem more virtuous
+
When she is gone. Then open not thy lips:
+
Firm and irrevocable is my doom
+
Which I have pass'd upon her; she is banish'd.
+
+
CELIA
+
+
Pronounce that sentence then on me, my liege:
+
I cannot live out of her company.
+
+
DUKE FREDERICK
+
+
You are a fool. You, niece, provide yourself:
+
If you outstay the time, upon mine honour,
+
And in the greatness of my word, you die.
+
Exeunt DUKE FREDERICK and Lords
+
+
CELIA
+
+
O my poor Rosalind, whither wilt thou go?
+
Wilt thou change fathers? I will give thee mine.
+
I charge thee, be not thou more grieved than I am.
+
+
ROSALIND
+
+
CELIA
+
+
Thou hast not, cousin;
+
Prithee be cheerful: know'st thou not, the duke
+
Hath banish'd me, his daughter?
+
+
ROSALIND
+
+
CELIA
+
+
No, hath not? Rosalind lacks then the love
+
Which teacheth thee that thou and I am one:
+
Shall we be sunder'd? shall we part, sweet girl?
+
No: let my father seek another heir.
+
Therefore devise with me how we may fly,
+
Whither to go and what to bear with us;
+
And do not seek to take your change upon you,
+
To bear your griefs yourself and leave me out;
+
For, by this heaven, now at our sorrows pale,
+
Say what thou canst, I'll go along with thee.
+
+
ROSALIND
+
+
Why, whither shall we go?
+
+
CELIA
+
+
To seek my uncle in the forest of Arden.
+
+
ROSALIND
+
+
Alas, what danger will it be to us,
+
Maids as we are, to travel forth so far!
+
Beauty provoketh thieves sooner than gold.
+
+
CELIA
+
+
I'll put myself in poor and mean attire
+
And with a kind of umber smirch my face;
+
The like do you: so shall we pass along
+
And never stir assailants.
+
+
ROSALIND
+
+
Were it not better,
+
Because that I am more than common tall,
+
That I did suit me all points like a man?
+
A gallant curtle-axe upon my thigh,
+
A boar-spear in my hand; and--in my heart
+
Lie there what hidden woman's fear there will--
+
We'll have a swashing and a martial outside,
+
As many other mannish cowards have
+
That do outface it with their semblances.
+
+
CELIA
+
+
What shall I call thee when thou art a man?
+
+
ROSALIND
+
+
I'll have no worse a name than Jove's own page;
+
And therefore look you call me Ganymede.
+
But what will you be call'd?
+
+
CELIA
+
+
Something that hath a reference to my state
+
No longer Celia, but Aliena.
+
+
ROSALIND
+
+
But, cousin, what if we assay'd to steal
+
The clownish fool out of your father's court?
+
Would he not be a comfort to our travel?
+
+
CELIA
+
+
He'll go along o'er the wide world with me;
+
Leave me alone to woo him. Let's away,
+
And get our jewels and our wealth together,
+
Devise the fittest time and safest way
+
To hide us from pursuit that will be made
+
After my flight. Now go we in content
+
To liberty and not to banishment.
+
Exeunt
+
+
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
new file mode 100644
index 0000000..fad6105
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
@@ -0,0 +1,416 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\XPath;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+class TranslatorTest extends TestCase
+{
+ /** @dataProvider getXpathLiteralTestData */
+ public function testXpathLiteral($value, $literal)
+ {
+ $this->assertEquals($literal, Translator::getXpathLiteral($value));
+ }
+
+ /** @dataProvider getCssToXPathTestData */
+ public function testCssToXPath($css, $xpath)
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $this->assertEquals($xpath, $translator->cssToXPath($css, ''));
+ }
+
+ public function testCssToXPathPseudoElement()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $translator->cssToXPath('e::first-line');
+ }
+
+ public function testGetExtensionNotExistsExtension()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $translator->getExtension('fake');
+ }
+
+ public function testAddCombinationNotExistsExtension()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $parser = new Parser();
+ $xpath = $parser->parse('*')[0];
+ $combinedXpath = $parser->parse('*')[0];
+ $translator->addCombination('fake', $xpath, $combinedXpath);
+ }
+
+ public function testAddFunctionNotExistsFunction()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $function = new FunctionNode(new ElementNode(), 'fake');
+ $translator->addFunction($xpath, $function);
+ }
+
+ public function testAddPseudoClassNotExistsClass()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $translator->addPseudoClass($xpath, 'fake');
+ }
+
+ public function testAddAttributeMatchingClassNotExistsClass()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $translator->addAttributeMatching($xpath, '', '', '');
+ }
+
+ /** @dataProvider getXmlLangTestData */
+ public function testXmlLang($css, array $elementsId)
+ {
+ $translator = new Translator();
+ $document = new \SimpleXMLElement(file_get_contents(__DIR__.'/Fixtures/lang.xml'));
+ $elements = $document->xpath($translator->cssToXPath($css));
+ $this->assertCount(\count($elementsId), $elements);
+ foreach ($elements as $element) {
+ $this->assertContains((string) $element->attributes()->id, $elementsId);
+ }
+ }
+
+ /** @dataProvider getHtmlIdsTestData */
+ public function testHtmlIds($css, array $elementsId)
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $document = new \DOMDocument();
+ $document->strictErrorChecking = false;
+ $internalErrors = libxml_use_internal_errors(true);
+ $document->loadHTMLFile(__DIR__.'/Fixtures/ids.html');
+ $document = simplexml_import_dom($document);
+ $elements = $document->xpath($translator->cssToXPath($css));
+ $this->assertCount(\count($elementsId), $elements);
+ foreach ($elements as $element) {
+ if (null !== $element->attributes()->id) {
+ $this->assertContains((string) $element->attributes()->id, $elementsId);
+ }
+ }
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+ }
+
+ /** @dataProvider getHtmlShakespearTestData */
+ public function testHtmlShakespear($css, $count)
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $document = new \DOMDocument();
+ $document->strictErrorChecking = false;
+ $document->loadHTMLFile(__DIR__.'/Fixtures/shakespear.html');
+ $document = simplexml_import_dom($document);
+ $bodies = $document->xpath('//body');
+ $elements = $bodies[0]->xpath($translator->cssToXPath($css));
+ $this->assertCount($count, $elements);
+ }
+
+ public function testOnlyOfTypeFindsSingleChildrenOfGivenType()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $document = new \DOMDocument();
+ $document->loadHTML(<<<'HTML'
+
+
+
+ A
+
+
+ B
+ C
+
+
+
+HTML
+ );
+
+ $xpath = new \DOMXPath($document);
+ $nodeList = $xpath->query($translator->cssToXPath('span:only-of-type'));
+
+ $this->assertSame(1, $nodeList->length);
+ $this->assertSame('A', $nodeList->item(0)->textContent);
+ }
+
+ public static function getXpathLiteralTestData()
+ {
+ return [
+ ['foo', "'foo'"],
+ ["foo's bar", '"foo\'s bar"'],
+ ["foo's \"middle\" bar", 'concat(\'foo\', "\'", \'s "middle" bar\')'],
+ ["foo's 'middle' \"bar\"", 'concat(\'foo\', "\'", \'s \', "\'", \'middle\', "\'", \' "bar"\')'],
+ ];
+ }
+
+ public static function getCssToXPathTestData()
+ {
+ return [
+ ['*', '*'],
+ ['e', 'e'],
+ ['*|e', 'e'],
+ ['e|f', 'e:f'],
+ ['e[foo]', 'e[@foo]'],
+ ['e[foo|bar]', 'e[@foo:bar]'],
+ ['e[foo="bar"]', "e[@foo = 'bar']"],
+ ['e[foo~="bar"]', "e[@foo and contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]"],
+ ['e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"],
+ ['e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"],
+ ['e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"],
+ ['e[foo!="bar"]', "e[not(@foo) or @foo != 'bar']"],
+ ['e[foo!="bar"][foo!="baz"]', "e[(not(@foo) or @foo != 'bar') and (not(@foo) or @foo != 'baz')]"],
+ ['e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"],
+ ['e:nth-child(1)', "*/*[(name() = 'e') and (position() = 1)]"],
+ ['e:nth-last-child(1)', "*/*[(name() = 'e') and (position() = last() - 0)]"],
+ ['e:nth-last-child(2n+2)', "*/*[(name() = 'e') and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"],
+ ['e:nth-of-type(1)', '*/e[position() = 1]'],
+ ['e:nth-last-of-type(1)', '*/e[position() = last() - 0]'],
+ ['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 ')]"],
+ ['e:first-child', "*/*[(name() = 'e') and (position() = 1)]"],
+ ['e:last-child', "*/*[(name() = 'e') and (position() = last())]"],
+ ['e:first-of-type', '*/e[position() = 1]'],
+ ['e:last-of-type', '*/e[position() = last()]'],
+ ['e:only-child', "*/*[(name() = 'e') and (last() = 1)]"],
+ ['e:only-of-type', 'e[count(preceding-sibling::e)=0 and count(following-sibling::e)=0]'],
+ ['e:empty', 'e[not(*) and not(string-length())]'],
+ ['e:EmPTY', 'e[not(*) and not(string-length())]'],
+ ['e:root', 'e[not(parent::*)]'],
+ ['e:hover', 'e[0]'],
+ ['e:contains("foo")', "e[contains(string(.), 'foo')]"],
+ ['e:ConTains(foo)', "e[contains(string(.), 'foo')]"],
+ ['e.warning', "e[@class and contains(concat(' ', normalize-space(@class), ' '), ' warning ')]"],
+ ['e#myid', "e[@id = 'myid']"],
+ ['e:not(:nth-child(odd))', 'e[not(position() - 1 >= 0 and (position() - 1) mod 2 = 0)]'],
+ ['e:nOT(*)', 'e[0]'],
+ ['e f', 'e/descendant-or-self::*/f'],
+ ['e > f', 'e/f'],
+ ['e + f', "e/following-sibling::*[(name() = 'f') and (position() = 1)]"],
+ ['e ~ f', 'e/following-sibling::f'],
+ ['div#container p', "div[@id = 'container']/descendant-or-self::*/p"],
+ ];
+ }
+
+ public static function getXmlLangTestData()
+ {
+ return [
+ [':lang("EN")', ['first', 'second', 'third', 'fourth']],
+ [':lang("en-us")', ['second', 'fourth']],
+ [':lang(en-nz)', ['third']],
+ [':lang(fr)', ['fifth']],
+ [':lang(ru)', ['sixth']],
+ [":lang('ZH')", ['eighth']],
+ [':lang(de) :lang(zh)', ['eighth']],
+ [':lang(en), :lang(zh)', ['first', 'second', 'third', 'fourth', 'eighth']],
+ [':lang(es)', []],
+ ];
+ }
+
+ public static function getHtmlIdsTestData()
+ {
+ return [
+ ['div', ['outer-div', 'li-div', 'foobar-div']],
+ ['DIV', ['outer-div', 'li-div', 'foobar-div']], // case-insensitive in HTML
+ ['div div', ['li-div']],
+ ['div, div div', ['outer-div', 'li-div', 'foobar-div']],
+ ['a[name]', ['name-anchor']],
+ ['a[NAme]', ['name-anchor']], // case-insensitive in HTML:
+ ['a[rel]', ['tag-anchor', 'nofollow-anchor']],
+ ['a[rel="tag"]', ['tag-anchor']],
+ ['a[href*="localhost"]', ['tag-anchor']],
+ ['a[href*=""]', []],
+ ['a[href^="http"]', ['tag-anchor', 'nofollow-anchor']],
+ ['a[href^="http:"]', ['tag-anchor']],
+ ['a[href^=""]', []],
+ ['a[href$="org"]', ['nofollow-anchor']],
+ ['a[href$=""]', []],
+ ['div[foobar~="bc"]', ['foobar-div']],
+ ['div[foobar~="cde"]', ['foobar-div']],
+ ['[foobar~="ab bc"]', ['foobar-div']],
+ ['[foobar~=""]', []],
+ ['[foobar~=" \t"]', []],
+ ['div[foobar~="cd"]', []],
+ ['*[lang|="En"]', ['second-li']],
+ ['[lang|="En-us"]', ['second-li']],
+ // Powered_Cache_Attribute values are case sensitive
+ ['*[lang|="en"]', []],
+ ['[lang|="en-US"]', []],
+ ['*[lang|="e"]', []],
+ // ... :lang() is not.
+ [':lang("EN")', ['second-li', 'li-div']],
+ ['*:lang(en-US)', ['second-li', 'li-div']],
+ [':lang("e")', []],
+ ['li:nth-child(3)', ['third-li']],
+ ['li:nth-child(10)', []],
+ ['li:nth-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(2n+0)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(+2n+1)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
+ ['li:nth-child(odd)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
+ ['li:nth-child(2n+4)', ['fourth-li', 'sixth-li']],
+ ['li:nth-child(3n+1)', ['first-li', 'fourth-li', 'seventh-li']],
+ ['li:nth-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n+3)', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(-n)', []],
+ ['li:nth-child(-n-1)', []],
+ ['li:nth-child(-n+1)', ['first-li']],
+ ['li:nth-child(-n+3)', ['first-li', 'second-li', 'third-li']],
+ ['li:nth-last-child(0)', []],
+ ['li:nth-last-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(2n+2)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n-3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n+3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li']],
+ ['li:nth-last-child(-n)', []],
+ ['li:nth-last-child(-n-1)', []],
+ ['li:nth-last-child(-n+1)', ['seventh-li']],
+ ['li:nth-last-child(-n+3)', ['fifth-li', 'sixth-li', 'seventh-li']],
+ ['ol:first-of-type', ['first-ol']],
+ ['ol:nth-child(4)', ['first-ol']],
+ ['ol:nth-of-type(2)', ['second-ol']],
+ ['ol:nth-last-of-type(1)', ['second-ol']],
+ ['span:only-child', ['foobar-span', 'no-siblings-of-any-type']],
+ ['li div:only-child', ['li-div']],
+ ['div *:only-child', ['li-div', 'foobar-span']],
+ ['p:only-of-type', ['paragraph']],
+ [':only-of-type', ['html', 'li-div', 'foobar-span', 'no-siblings-of-any-type']],
+ ['div#foobar-div :only-of-type', ['foobar-span']],
+ ['a:empty', ['name-anchor']],
+ ['a:EMpty', ['name-anchor']],
+ ['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']],
+ [':root', ['html']],
+ ['html:root', ['html']],
+ ['li:root', []],
+ ['* :root', []],
+ ['*:contains("link")', ['html', 'nil', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
+ [':CONtains("link")', ['html', 'nil', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
+ ['*:contains("LInk")', []], // case sensitive
+ ['*:contains("e")', ['html', 'nil', 'outer-div', 'first-ol', 'first-li', 'paragraph', 'p-em']],
+ ['*:contains("E")', []], // case-sensitive
+ ['.a', ['first-ol']],
+ ['.b', ['first-ol']],
+ ['*.a', ['first-ol']],
+ ['ol.a', ['first-ol']],
+ ['.c', ['first-ol', 'third-li', 'fourth-li']],
+ ['*.c', ['first-ol', 'third-li', 'fourth-li']],
+ ['ol *.c', ['third-li', 'fourth-li']],
+ ['ol li.c', ['third-li', 'fourth-li']],
+ ['li ~ li.c', ['third-li', 'fourth-li']],
+ ['ol > li.c', ['third-li', 'fourth-li']],
+ ['#first-li', ['first-li']],
+ ['li#first-li', ['first-li']],
+ ['*#first-li', ['first-li']],
+ ['li div', ['li-div']],
+ ['li > div', ['li-div']],
+ ['div div', ['li-div']],
+ ['div > div', []],
+ ['div>.c', ['first-ol']],
+ ['div > .c', ['first-ol']],
+ ['div + div', ['foobar-div']],
+ ['a ~ a', ['tag-anchor', 'nofollow-anchor']],
+ ['a[rel="tag"] ~ a', ['nofollow-anchor']],
+ ['ol#first-ol li:last-child', ['seventh-li']],
+ ['ol#first-ol *:last-child', ['li-div', 'seventh-li']],
+ ['#outer-div:first-child', ['outer-div']],
+ ['#outer-div :first-child', ['name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-fieldset-disabled', 'area-href']],
+ ['a[href]', ['tag-anchor', 'nofollow-anchor']],
+ [':not(*)', []],
+ ['a:not([href])', ['name-anchor']],
+ ['ol :Not(li[class])', ['first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li']],
+ // HTML-specific
+ [':link', ['link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']],
+ [':visited', []],
+ [':enabled', ['link-href', 'tag-anchor', 'nofollow-anchor', 'checkbox-unchecked', 'text-checked', 'checkbox-checked', 'area-href']],
+ [':disabled', ['checkbox-disabled', 'checkbox-disabled-checked', 'fieldset', 'checkbox-fieldset-disabled']],
+ [':checked', ['checkbox-checked', 'checkbox-disabled-checked']],
+ ];
+ }
+
+ public static function getHtmlShakespearTestData()
+ {
+ return [
+ ['*', 246],
+ ['div:contains(CELIA)', 26],
+ ['div:only-child', 22], // ?
+ ['div:nth-child(even)', 106],
+ ['div:nth-child(2n)', 106],
+ ['div:nth-child(odd)', 137],
+ ['div:nth-child(2n+1)', 137],
+ ['div:nth-child(n)', 243],
+ ['div:last-child', 53],
+ ['div:first-child', 51],
+ ['div > div', 242],
+ ['div + div', 190],
+ ['div ~ div', 190],
+ ['body', 1],
+ ['body div', 243],
+ ['div', 243],
+ ['div div', 242],
+ ['div div div', 241],
+ ['div, div, div', 243],
+ ['div, a, span', 243],
+ ['.dialog', 51],
+ ['div.dialog', 51],
+ ['div .dialog', 51],
+ ['div.character, div.dialog', 99],
+ ['div.direction.dialog', 0],
+ ['div.dialog.direction', 0],
+ ['div.dialog.scene', 1],
+ ['div.scene.scene', 1],
+ ['div.scene .scene', 0],
+ ['div.direction .dialog ', 0],
+ ['div .dialog .direction', 4],
+ ['div.dialog .dialog .direction', 4],
+ ['#speech5', 1],
+ ['div#speech5', 1],
+ ['div #speech5', 1],
+ ['div.scene div.dialog', 49],
+ ['div#scene1 div.dialog div', 142],
+ ['#scene1 #speech1', 1],
+ ['div[class]', 103],
+ ['div[class=dialog]', 50],
+ ['div[class^=dia]', 51],
+ ['div[class$=log]', 50],
+ ['div[class*=sce]', 1],
+ ['div[class|=dialog]', 50], // ? Seems right
+ ['div[class!=madeup]', 243], // ? Seems right
+ ['div[class~=dialog]', 51], // ? Seems right
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist b/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
new file mode 100644
index 0000000..a8e537e
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Resources
+ ./Tests
+ ./vendor
+
+
+
+
From fd056142a54a6707becf71053685180a7976764d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:31:19 +0000
Subject: [PATCH 3/9] Add CI workflow for automated testing and code coverage
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.github/workflows/ci.yml | 99 ++++++++++++++++++++++++++++++++++++++++
.gitignore | 3 ++
.phpunit.result.cache | 1 -
3 files changed, 102 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/ci.yml
delete mode 100644 .phpunit.result.cache
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..67ee61d
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,99 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - master
+ - develop
+ pull_request:
+ branches:
+ - master
+ - develop
+
+jobs:
+ test:
+ name: Test (PHP ${{ matrix.php }})
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ php: ['7.4', '8.0', '8.1', '8.2']
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ coverage: xdebug
+ tools: composer
+
+ - name: Get Composer cache directory
+ id: composer-cache
+ run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install PHP dependencies
+ run: composer install --no-interaction --prefer-dist
+
+ - name: Run PHPUnit tests
+ run: vendor/bin/phpunit --colors=always
+
+ - name: Run PHPUnit tests with coverage
+ if: matrix.php == '8.1'
+ run: vendor/bin/phpunit --coverage-clover=coverage.xml --colors=always
+
+ - name: Upload coverage to Codecov
+ if: matrix.php == '8.1'
+ uses: codecov/codecov-action@v4
+ with:
+ files: ./coverage.xml
+ flags: unittests
+ name: codecov-php-${{ matrix.php }}
+ fail_ci_if_error: false
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ lint:
+ name: Lint (PHP ${{ matrix.php }})
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ php: ['7.4', '8.0', '8.1', '8.2']
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ tools: composer, cs2pr
+
+ - name: Get Composer cache directory
+ id: composer-cache
+ run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+
+ - name: Cache Composer dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install PHP dependencies
+ run: composer install --no-interaction --prefer-dist
+
+ - name: Run PHPCS
+ run: composer run-script lint
diff --git a/.gitignore b/.gitignore
index 4821b74..7bd7ce4 100755
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,6 @@ Thumbs.db
Desktop.ini
*.js.map
*.css.map
+
+# PHPUnit
+.phpunit.result.cache
diff --git a/.phpunit.result.cache b/.phpunit.result.cache
deleted file mode 100644
index fe33bcf..0000000
--- a/.phpunit.result.cache
+++ /dev/null
@@ -1 +0,0 @@
-{"version":1,"defects":[],"times":{"PoweredCache\\Core\\Core_Tests::test_setup":0.187,"PoweredCache\\Core\\Core_Tests::test_i18n":0.024,"PoweredCache\\Core\\Core_Tests::test_init":0,"Encryption_Test::testEncrypt":0.013,"Encryption_Test::testDecrypt":0,"PoweredCache\\Utils\\Util_Tests::testIsDirEmpty":0.004,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #0":0.002,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #1":0.002,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #2":0.002,"PoweredCache\\Utils\\Util_Tests::testIsIpInRange with data set #3":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #0":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #1":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #2":0.002,"PoweredCache\\Utils\\Util_Tests::testMaskString with data set #3":0.002,"PoweredCache\\Utils\\Util_Tests::testGetClientIp":0.002,"PoweredCache\\Utils\\Util_Tests::testBypassRequest":0.002,"PoweredCache\\Utils\\Util_Tests::testIsLocalSiteWithLocalhost":0.003,"PoweredCache\\Utils\\Util_Tests::testIsLocalSiteWithEnvironmentTypeLocal":0.002,"PoweredCache\\Utils\\Util_Tests::testIsLocalSiteWithEnvironmentTypeProduction":0.01,"PoweredCache\\Utils\\Util_Tests::testPoweredCacheIsMobileWithMobileUserAgent":0.003,"PoweredCache\\Utils\\Util_Tests::testPoweredCacheIsMobileWithNonMobileUserAgent":0.002,"PoweredCache\\Utils\\Util_Tests::testGetExpiredFiles":0.002,"PoweredCache\\Utils\\Util_Tests::testGetUrlDir":0.003}}
\ No newline at end of file
From fb27c29da0ea863053c59cd1166235517acfc488 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:34:26 +0000
Subject: [PATCH 4/9] Add CI and coverage badges to README, update gitignore
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.gitignore | 2 ++
README.md | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 7bd7ce4..d88c5c0 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ node_modules
bower_components
release
vendor
+includes/classes/Dependencies/**/Tests
.idea
*.log
@@ -32,3 +33,4 @@ Desktop.ini
# PHPUnit
.phpunit.result.cache
+coverage.xml
diff --git a/README.md b/README.md
index aeef787..ed6f92d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
Powered Cache
=============
- [](https://github.com/poweredcache/powered-cache/releases)  
+ [](https://github.com/poweredcache/powered-cache/releases)   [](https://github.com/poweredcache/powered-cache/actions/workflows/ci.yml) [](https://codecov.io/gh/poweredcache/powered-cache)
The most powerful caching and performance suite for WordPress. Easily Improve PageSpeed & Web Vitals Score.
From e136d5054af2b6d3e9a938aa9652c9031954ae37 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:37:30 +0000
Subject: [PATCH 5/9] Add explicit permissions to CI workflow for security
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.github/workflows/ci.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 67ee61d..64b6b10 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,6 +10,9 @@ on:
- master
- develop
+permissions:
+ contents: read
+
jobs:
test:
name: Test (PHP ${{ matrix.php }})
From 12f5cc87347b98cf80ac36234d18d9782a1fd57f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:43:07 +0000
Subject: [PATCH 6/9] Remove vendor test directory pattern from gitignore
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.gitignore | 1 -
1 file changed, 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index d88c5c0..4c7d8f9 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@ node_modules
bower_components
release
vendor
-includes/classes/Dependencies/**/Tests
.idea
*.log
From 90cc4f28bc40f73676625e5e93d8876595574a85 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:50:45 +0000
Subject: [PATCH 7/9] Remove Dependencies directory from repo and add to
gitignore
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.gitignore | 1 +
.../MatthiasMullie/Minify/CSS.php | 870 --------
.../MatthiasMullie/Minify/Exception.php | 22 -
.../Minify/Exceptions/BasicException.php | 24 -
.../Minify/Exceptions/FileImportException.php | 22 -
.../Minify/Exceptions/IOException.php | 22 -
.../Dependencies/MatthiasMullie/Minify/JS.php | 618 -----
.../MatthiasMullie/Minify/Minify.php | 560 -----
.../PathConverter/Converter.php | 204 --
.../PathConverter/ConverterInterface.php | 24 -
.../PathConverter/NoConverter.php | 23 -
.../MatthiasMullie/data/js/keywords_after.txt | 7 -
.../data/js/keywords_before.txt | 26 -
.../data/js/keywords_reserved.txt | 63 -
.../MatthiasMullie/data/js/operators.txt | 46 -
.../data/js/operators_after.txt | 43 -
.../data/js/operators_before.txt | 43 -
.../Component/CssSelector/CHANGELOG.md | 18 -
.../CssSelector/CssSelectorConverter.php | 69 -
.../Exception/ExceptionInterface.php | 24 -
.../Exception/ExpressionErrorException.php | 24 -
.../Exception/InternalErrorException.php | 24 -
.../CssSelector/Exception/ParseException.php | 24 -
.../Exception/SyntaxErrorException.php | 65 -
.../Symfony/Component/CssSelector/LICENSE | 19 -
.../CssSelector/Node/AbstractNode.php | 39 -
.../CssSelector/Node/AttributeNode.php | 82 -
.../Component/CssSelector/Node/ClassNode.php | 57 -
.../CssSelector/Node/CombinedSelectorNode.php | 66 -
.../CssSelector/Node/ElementNode.php | 59 -
.../CssSelector/Node/FunctionNode.php | 76 -
.../Component/CssSelector/Node/HashNode.php | 57 -
.../CssSelector/Node/NegationNode.php | 57 -
.../CssSelector/Node/NodeInterface.php | 31 -
.../Component/CssSelector/Node/PseudoNode.php | 57 -
.../CssSelector/Node/SelectorNode.php | 57 -
.../CssSelector/Node/Specificity.php | 73 -
.../Parser/Handler/CommentHandler.php | 48 -
.../Parser/Handler/HandlerInterface.php | 30 -
.../Parser/Handler/HashHandler.php | 58 -
.../Parser/Handler/IdentifierHandler.php | 58 -
.../Parser/Handler/NumberHandler.php | 54 -
.../Parser/Handler/StringHandler.php | 77 -
.../Parser/Handler/WhitespaceHandler.php | 46 -
.../Component/CssSelector/Parser/Parser.php | 353 ---
.../CssSelector/Parser/ParserInterface.php | 34 -
.../Component/CssSelector/Parser/Reader.php | 86 -
.../Parser/Shortcut/ClassParser.php | 51 -
.../Parser/Shortcut/ElementParser.php | 47 -
.../Parser/Shortcut/EmptyStringParser.php | 46 -
.../Parser/Shortcut/HashParser.php | 51 -
.../Component/CssSelector/Parser/Token.php | 111 -
.../CssSelector/Parser/TokenStream.php | 167 --
.../Parser/Tokenizer/Tokenizer.php | 73 -
.../Parser/Tokenizer/TokenizerEscaping.php | 65 -
.../Parser/Tokenizer/TokenizerPatterns.php | 89 -
.../Symfony/Component/CssSelector/README.md | 20 -
.../Tests/CssSelectorConverterTest.php | 83 -
.../Tests/Node/AbstractNodeTestCase.php | 34 -
.../Tests/Node/AttributeNodeTest.php | 37 -
.../CssSelector/Tests/Node/ClassNodeTest.php | 33 -
.../Tests/Node/CombinedSelectorNodeTest.php | 35 -
.../Tests/Node/ElementNodeTest.php | 35 -
.../Tests/Node/FunctionNodeTest.php | 47 -
.../CssSelector/Tests/Node/HashNodeTest.php | 33 -
.../Tests/Node/NegationNodeTest.php | 33 -
.../CssSelector/Tests/Node/PseudoNodeTest.php | 32 -
.../Tests/Node/SelectorNodeTest.php | 34 -
.../Tests/Node/SpecificityTest.php | 63 -
.../Handler/AbstractHandlerTestCase.php | 70 -
.../Parser/Handler/CommentHandlerTest.php | 55 -
.../Tests/Parser/Handler/HashHandlerTest.php | 49 -
.../Parser/Handler/IdentifierHandlerTest.php | 49 -
.../Parser/Handler/NumberHandlerTest.php | 50 -
.../Parser/Handler/StringHandlerTest.php | 50 -
.../Parser/Handler/WhitespaceHandlerTest.php | 44 -
.../CssSelector/Tests/Parser/ParserTest.php | 263 ---
.../CssSelector/Tests/Parser/ReaderTest.php | 102 -
.../Tests/Parser/Shortcut/ClassParserTest.php | 45 -
.../Parser/Shortcut/ElementParserTest.php | 44 -
.../Parser/Shortcut/EmptyStringParserTest.php | 36 -
.../Tests/Parser/Shortcut/HashParserTest.php | 45 -
.../Tests/Parser/TokenStreamTest.php | 97 -
.../CssSelector/Tests/XPath/Fixtures/ids.html | 52 -
.../CssSelector/Tests/XPath/Fixtures/lang.xml | 11 -
.../Tests/XPath/Fixtures/shakespear.html | 308 ---
.../Tests/XPath/TranslatorTest.php | 416 ----
.../XPath/Extension/AbstractExtension.php | 65 -
.../Extension/AttributeMatchingExtension.php | 119 -
.../XPath/Extension/CombinationExtension.php | 71 -
.../XPath/Extension/ExtensionInterface.php | 67 -
.../XPath/Extension/FunctionExtension.php | 171 --
.../XPath/Extension/HtmlExtension.php | 187 --
.../XPath/Extension/NodeExtension.php | 197 --
.../XPath/Extension/PseudoClassExtension.php | 122 -
.../CssSelector/XPath/Translator.php | 230 --
.../CssSelector/XPath/TranslatorInterface.php | 37 -
.../Component/CssSelector/XPath/XPathExpr.php | 111 -
.../Component/CssSelector/composer.json | 33 -
.../Component/CssSelector/phpunit.xml.dist | 31 -
.../Symfony/Polyfill/Php80/LICENSE | 19 -
.../Symfony/Polyfill/Php80/Php80.php | 115 -
.../Symfony/Polyfill/Php80/PhpToken.php | 106 -
.../Symfony/Polyfill/Php80/README.md | 25 -
.../Php80/Resources/stubs/Attribute.php | 31 -
.../Php80/Resources/stubs/PhpToken.php | 16 -
.../Php80/Resources/stubs/Stringable.php | 20 -
.../Resources/stubs/UnhandledMatchError.php | 16 -
.../Php80/Resources/stubs/ValueError.php | 16 -
.../Symfony/Polyfill/Php80/bootstrap.php | 42 -
.../Symfony/Polyfill/Php80/composer.json | 37 -
.../voku/helper/AbstractDomParser.php | 527 -----
.../voku/helper/AbstractSimpleHtmlDom.php | 255 ---
.../voku/helper/AbstractSimpleHtmlDomNode.php | 80 -
.../voku/helper/AbstractSimpleXmlDom.php | 217 --
.../voku/helper/AbstractSimpleXmlDomNode.php | 80 -
.../voku/helper/DomParserInterface.php | 201 --
.../voku/helper/HtmlDomHelper.php | 72 -
.../voku/helper/HtmlDomParser.php | 1228 ----------
.../Dependencies/voku/helper/HtmlMin.php | 1981 -----------------
.../helper/HtmlMinDomObserverInterface.php | 28 -
.../HtmlMinDomObserverOptimizeAttributes.php | 381 ----
.../voku/helper/HtmlMinInterface.php | 154 --
.../voku/helper/SelectorConverter.php | 75 -
.../voku/helper/SimpleHtmlAttributes.php | 269 ---
.../helper/SimpleHtmlAttributesInterface.php | 82 -
.../voku/helper/SimpleHtmlDom.php | 1011 ---------
.../voku/helper/SimpleHtmlDomBlank.php | 472 ----
.../voku/helper/SimpleHtmlDomInterface.php | 391 ----
.../voku/helper/SimpleHtmlDomNode.php | 161 --
.../voku/helper/SimpleHtmlDomNodeBlank.php | 106 -
.../helper/SimpleHtmlDomNodeInterface.php | 117 -
.../Dependencies/voku/helper/SimpleXmlDom.php | 843 -------
.../voku/helper/SimpleXmlDomBlank.php | 447 ----
.../voku/helper/SimpleXmlDomInterface.php | 367 ---
.../voku/helper/SimpleXmlDomNode.php | 161 --
.../voku/helper/SimpleXmlDomNodeBlank.php | 104 -
.../voku/helper/SimpleXmlDomNodeInterface.php | 117 -
.../Dependencies/voku/helper/XmlDomParser.php | 733 ------
139 files changed, 1 insertion(+), 19988 deletions(-)
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/JS.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Minify.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt
delete mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/README.md
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php
delete mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json
delete mode 100644 includes/classes/Dependencies/voku/helper/AbstractDomParser.php
delete mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php
delete mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php
delete mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php
delete mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php
delete mode 100644 includes/classes/Dependencies/voku/helper/DomParserInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/HtmlDomHelper.php
delete mode 100644 includes/classes/Dependencies/voku/helper/HtmlDomParser.php
delete mode 100644 includes/classes/Dependencies/voku/helper/HtmlMin.php
delete mode 100644 includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/HtmlMinDomObserverOptimizeAttributes.php
delete mode 100644 includes/classes/Dependencies/voku/helper/HtmlMinInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SelectorConverter.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDom.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php
delete mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php
delete mode 100644 includes/classes/Dependencies/voku/helper/XmlDomParser.php
diff --git a/.gitignore b/.gitignore
index 4c7d8f9..554862e 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ node_modules
bower_components
release
vendor
+includes/classes/Dependencies
.idea
*.log
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php b/includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php
deleted file mode 100644
index 6b13213..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php
+++ /dev/null
@@ -1,870 +0,0 @@
-
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
-
-use PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions\FileImportException;
-use PoweredCache\Dependencies\MatthiasMullie\PathConverter\Converter;
-use PoweredCache\Dependencies\MatthiasMullie\PathConverter\ConverterInterface;
-
-/**
- * CSS minifier.
- *
- * Please report bugs on https://github.com/matthiasmullie/minify/issues
- *
- * @author Matthias Mullie
- * @author Tijs Verkoyen
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-class CSS extends Minify
-{
- /**
- * @var int maximum inport size in kB
- */
- protected $maxImportSize = 5;
-
- /**
- * @var string[] valid import extensions
- */
- protected $importExtensions = array(
- 'gif' => 'data:image/gif',
- 'png' => 'data:image/png',
- 'jpe' => 'data:image/jpeg',
- 'jpg' => 'data:image/jpeg',
- 'jpeg' => 'data:image/jpeg',
- 'svg' => 'data:image/svg+xml',
- 'woff' => 'data:application/x-font-woff',
- 'woff2' => 'data:application/x-font-woff2',
- 'avif' => 'data:image/avif',
- 'apng' => 'data:image/apng',
- 'webp' => 'data:image/webp',
- 'tif' => 'image/tiff',
- 'tiff' => 'image/tiff',
- 'xbm' => 'image/x-xbitmap',
- );
-
- /**
- * Set the maximum size if files to be imported.
- *
- * Files larger than this size (in kB) will not be imported into the CSS.
- * Importing files into the CSS as data-uri will save you some connections,
- * but we should only import relatively small decorative images so that our
- * CSS file doesn't get too bulky.
- *
- * @param int $size Size in kB
- */
- public function setMaxImportSize($size)
- {
- $this->maxImportSize = $size;
- }
-
- /**
- * Set the type of extensions to be imported into the CSS (to save network
- * connections).
- * Keys of the array should be the file extensions & respective values
- * should be the data type.
- *
- * @param string[] $extensions Array of file extensions
- */
- public function setImportExtensions(array $extensions)
- {
- $this->importExtensions = $extensions;
- }
-
- /**
- * Move any import statements to the top.
- *
- * @param string $content Nearly finished CSS content
- *
- * @return string
- */
- protected function moveImportsToTop($content)
- {
- if (preg_match_all('/(;?)(@import (?url\()?(?P["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) {
- // remove from content
- foreach ($matches[0] as $import) {
- $content = str_replace($import, '', $content);
- }
-
- // add to top
- $content = implode(';', $matches[2]) . ';' . trim($content, ';');
- }
-
- return $content;
- }
-
- /**
- * Combine CSS from import statements.
- *
- * \@import's will be loaded and their content merged into the original file,
- * to save HTTP requests.
- *
- * @param string $source The file to combine imports for
- * @param string $content The CSS content to combine imports for
- * @param string[] $parents Parent paths, for circular reference checks
- *
- * @return string
- *
- * @throws FileImportException
- */
- protected function combineImports($source, $content, $parents)
- {
- $importRegexes = array(
- // @import url(xxx)
- '/
- # import statement
- @import
-
- # whitespace
- \s+
-
- # open url()
- url\(
-
- # (optional) open path enclosure
- (?P["\']?)
-
- # fetch path
- (?P.+?)
-
- # (optional) close path enclosure
- (?P=quotes)
-
- # close url()
- \)
-
- # (optional) trailing whitespace
- \s*
-
- # (optional) media statement(s)
- (?P[^;]*)
-
- # (optional) trailing whitespace
- \s*
-
- # (optional) closing semi-colon
- ;?
-
- /ix',
-
- // @import 'xxx'
- '/
-
- # import statement
- @import
-
- # whitespace
- \s+
-
- # open path enclosure
- (?P["\'])
-
- # fetch path
- (?P.+?)
-
- # close path enclosure
- (?P=quotes)
-
- # (optional) trailing whitespace
- \s*
-
- # (optional) media statement(s)
- (?P[^;]*)
-
- # (optional) trailing whitespace
- \s*
-
- # (optional) closing semi-colon
- ;?
-
- /ix',
- );
-
- // find all relative imports in css
- $matches = array();
- foreach ($importRegexes as $importRegex) {
- if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
- $matches = array_merge($matches, $regexMatches);
- }
- }
-
- $search = array();
- $replace = array();
-
- // loop the matches
- foreach ($matches as $match) {
- // get the path for the file that will be imported
- $importPath = dirname($source) . '/' . $match['path'];
-
- // only replace the import with the content if we can grab the
- // content of the file
- if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
- continue;
- }
-
- // check if current file was not imported previously in the same
- // import chain.
- if (in_array($importPath, $parents)) {
- throw new FileImportException('Failed to import file "' . $importPath . '": circular reference detected.');
- }
-
- // grab referenced file & minify it (which may include importing
- // yet other @import statements recursively)
- $minifier = new self($importPath);
- $minifier->setMaxImportSize($this->maxImportSize);
- $minifier->setImportExtensions($this->importExtensions);
- $importContent = $minifier->execute($source, $parents);
-
- // check if this is only valid for certain media
- if (!empty($match['media'])) {
- $importContent = '@media ' . $match['media'] . '{' . $importContent . '}';
- }
-
- // add to replacement array
- $search[] = $match[0];
- $replace[] = $importContent;
- }
-
- // replace the import statements
- return str_replace($search, $replace, $content);
- }
-
- /**
- * Import files into the CSS, base64-ized.
- *
- * @url(image.jpg) images will be loaded and their content merged into the
- * original file, to save HTTP requests.
- *
- * @param string $source The file to import files for
- * @param string $content The CSS content to import files for
- *
- * @return string
- */
- protected function importFiles($source, $content)
- {
- $regex = '/url\((["\']?)(.+?)\\1\)/i';
- if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
- $search = array();
- $replace = array();
-
- // loop the matches
- foreach ($matches as $match) {
- $extension = substr(strrchr($match[2], '.'), 1);
- if ($extension && !array_key_exists($extension, $this->importExtensions)) {
- continue;
- }
-
- // get the path for the file that will be imported
- $path = $match[2];
- $path = dirname($source) . '/' . $path;
-
- // only replace the import with the content if we're able to get
- // the content of the file, and it's relatively small
- if ($this->canImportFile($path) && $this->canImportBySize($path)) {
- // grab content && base64-ize
- $importContent = $this->load($path);
- $importContent = base64_encode($importContent);
-
- // build replacement
- $search[] = $match[0];
- $replace[] = 'url(' . $this->importExtensions[$extension] . ';base64,' . $importContent . ')';
- }
- }
-
- // replace the import statements
- $content = str_replace($search, $replace, $content);
- }
-
- return $content;
- }
-
- /**
- * Minify the data.
- * Perform CSS optimizations.
- *
- * @param string[optional] $path Path to write the data to
- * @param string[] $parents Parent paths, for circular reference checks
- *
- * @return string The minified data
- */
- public function execute($path = null, $parents = array())
- {
- $content = '';
-
- // loop CSS data (raw data and files)
- foreach ($this->data as $source => $css) {
- /*
- * Let's first take out strings & comments, since we can't just
- * remove whitespace anywhere. If whitespace occurs inside a string,
- * we should leave it alone. E.g.:
- * p { content: "a test" }
- */
- $this->extractStrings();
- $this->stripComments();
- $this->extractMath();
- $this->extractCustomProperties();
- $css = $this->replace($css);
-
- $css = $this->stripWhitespace($css);
- $css = $this->convertLegacyColors($css);
- $css = $this->cleanupModernColors($css);
- $css = $this->shortenHEXColors($css);
- $css = $this->shortenZeroes($css);
- $css = $this->shortenFontWeights($css);
- $css = $this->stripEmptyTags($css);
-
- // restore the string we've extracted earlier
- $css = $this->restoreExtractedData($css);
-
- $source = is_int($source) ? '' : $source;
- $parents = $source ? array_merge($parents, array($source)) : $parents;
- $css = $this->combineImports($source, $css, $parents);
- $css = $this->importFiles($source, $css);
-
- /*
- * If we'll save to a new path, we'll have to fix the relative paths
- * to be relative no longer to the source file, but to the new path.
- * If we don't write to a file, fall back to same path so no
- * conversion happens (because we still want it to go through most
- * of the move code, which also addresses url() & @import syntax...)
- */
- $converter = $this->getPathConverter($source, $path ?: $source);
- $css = $this->move($converter, $css);
-
- // combine css
- $content .= $css;
- }
-
- $content = $this->moveImportsToTop($content);
-
- return $content;
- }
-
- /**
- * Moving a css file should update all relative urls.
- * Relative references (e.g. ../images/image.gif) in a certain css file,
- * will have to be updated when a file is being saved at another location
- * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
- *
- * @param ConverterInterface $converter Relative path converter
- * @param string $content The CSS content to update relative urls for
- *
- * @return string
- */
- protected function move(ConverterInterface $converter, $content)
- {
- /*
- * Relative path references will usually be enclosed by url(). @import
- * is an exception, where url() is not necessary around the path (but is
- * allowed).
- * This *could* be 1 regular expression, where both regular expressions
- * in this array are on different sides of a |. But we're using named
- * patterns in both regexes, the same name on both regexes. This is only
- * possible with a (?J) modifier, but that only works after a fairly
- * recent PCRE version. That's why I'm doing 2 separate regular
- * expressions & combining the matches after executing of both.
- */
- $relativeRegexes = array(
- // url(xxx)
- '/
- # open url()
- url\(
-
- \s*
-
- # open path enclosure
- (?P["\'])?
-
- # fetch path
- (?P.+?)
-
- # close path enclosure
- (?(quotes)(?P=quotes))
-
- \s*
-
- # close url()
- \)
-
- /ix',
-
- // @import "xxx"
- '/
- # import statement
- @import
-
- # whitespace
- \s+
-
- # we don\'t have to check for @import url(), because the
- # condition above will already catch these
-
- # open path enclosure
- (?P["\'])
-
- # fetch path
- (?P.+?)
-
- # close path enclosure
- (?P=quotes)
-
- /ix',
- );
-
- // find all relative urls in css
- $matches = array();
- foreach ($relativeRegexes as $relativeRegex) {
- if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
- $matches = array_merge($matches, $regexMatches);
- }
- }
-
- $search = array();
- $replace = array();
-
- // loop all urls
- foreach ($matches as $match) {
- // determine if it's a url() or an @import match
- $type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
-
- $url = $match['path'];
- if ($this->canImportByPath($url)) {
- // attempting to interpret GET-params makes no sense, so let's discard them for awhile
- $params = strrchr($url, '?');
- $url = $params ? substr($url, 0, -strlen($params)) : $url;
-
- // fix relative url
- $url = $converter->convert($url);
-
- // now that the path has been converted, re-apply GET-params
- $url .= $params;
- }
-
- /*
- * Urls with control characters above 0x7e should be quoted.
- * According to Mozilla's parser, whitespace is only allowed at the
- * end of unquoted urls.
- * Urls with `)` (as could happen with data: uris) should also be
- * quoted to avoid being confused for the url() closing parentheses.
- * And urls with a # have also been reported to cause issues.
- * Urls with quotes inside should also remain escaped.
- *
- * @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
- * @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
- * @see https://github.com/matthiasmullie/minify/issues/193
- */
- $url = trim($url);
- if (preg_match('/[\s\)\'"#\x{7f}-\x{9f}]/u', $url)) {
- $url = $match['quotes'] . $url . $match['quotes'];
- }
-
- // build replacement
- $search[] = $match[0];
- if ($type === 'url') {
- $replace[] = 'url(' . $url . ')';
- } elseif ($type === 'import') {
- $replace[] = '@import "' . $url . '"';
- }
- }
-
- // replace urls
- return str_replace($search, $replace, $content);
- }
-
- /**
- * Shorthand HEX color codes.
- * #FF0000FF -> #f00 -> red
- * #FF00FF00 -> transparent.
- *
- * @param string $content The CSS content to shorten the HEX color codes for
- *
- * @return string
- */
- protected function shortenHexColors($content)
- {
- // shorten repeating patterns within HEX ..
- $content = preg_replace('/(?<=[: ])#([0-9a-f])\\1([0-9a-f])\\2([0-9a-f])\\3(?:([0-9a-f])\\4)?(?=[; }])/i', '#$1$2$3$4', $content);
-
- // remove alpha channel if it's pointless ..
- $content = preg_replace('/(?<=[: ])#([0-9a-f]{6})ff(?=[; }])/i', '#$1', $content);
- $content = preg_replace('/(?<=[: ])#([0-9a-f]{3})f(?=[; }])/i', '#$1', $content);
-
- // replace `transparent` with shortcut ..
- $content = preg_replace('/(?<=[: ])#[0-9a-f]{6}00(?=[; }])/i', '#fff0', $content);
-
- $colors = array(
- // make these more readable
- '#00f' => 'blue',
- '#dc143c' => 'crimson',
- '#0ff' => 'cyan',
- '#8b0000' => 'darkred',
- '#696969' => 'dimgray',
- '#ff69b4' => 'hotpink',
- '#0f0' => 'lime',
- '#fdf5e6' => 'oldlace',
- '#87ceeb' => 'skyblue',
- '#d8bfd8' => 'thistle',
- // we can shorten some even more by replacing them with their color name
- '#f0ffff' => 'azure',
- '#f5f5dc' => 'beige',
- '#ffe4c4' => 'bisque',
- '#a52a2a' => 'brown',
- '#ff7f50' => 'coral',
- '#ffd700' => 'gold',
- '#808080' => 'gray',
- '#008000' => 'green',
- '#4b0082' => 'indigo',
- '#fffff0' => 'ivory',
- '#f0e68c' => 'khaki',
- '#faf0e6' => 'linen',
- '#800000' => 'maroon',
- '#000080' => 'navy',
- '#808000' => 'olive',
- '#ffa500' => 'orange',
- '#da70d6' => 'orchid',
- '#cd853f' => 'peru',
- '#ffc0cb' => 'pink',
- '#dda0dd' => 'plum',
- '#800080' => 'purple',
- '#f00' => 'red',
- '#fa8072' => 'salmon',
- '#a0522d' => 'sienna',
- '#c0c0c0' => 'silver',
- '#fffafa' => 'snow',
- '#d2b48c' => 'tan',
- '#008080' => 'teal',
- '#ff6347' => 'tomato',
- '#ee82ee' => 'violet',
- '#f5deb3' => 'wheat',
- // or the other way around
- 'black' => '#000',
- 'fuchsia' => '#f0f',
- 'magenta' => '#f0f',
- 'white' => '#fff',
- 'yellow' => '#ff0',
- // and also `transparent`
- 'transparent' => '#fff0',
- );
-
- return preg_replace_callback(
- '/(?<=[: ])(' . implode('|', array_keys($colors)) . ')(?=[; }])/i',
- function ($match) use ($colors) {
- return $colors[strtolower($match[0])];
- },
- $content
- );
- }
-
- /**
- * Convert RGB|HSL color codes.
- * rgb(255,0,0,.5) -> rgb(255 0 0 / .5).
- * rgb(255,0,0) -> #f00.
- *
- * @param string $content The CSS content to shorten the RGB color codes for
- *
- * @return string
- */
- protected function convertLegacyColors($content)
- {
- /*
- https://drafts.csswg.org/css-color/#color-syntax-legacy
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
- */
-
- // convert legacy color syntax
- $content = preg_replace('/(rgb)a?\(\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0,1]?(?:\.[0-9]*)?)\s*\)/i', '$1($2 $3 $4 / $5)', $content);
- $content = preg_replace('/(rgb)a?\(\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*\)/i', '$1($2 $3 $4)', $content);
- $content = preg_replace('/(hsl)a?\(\s*([0-9]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9]{1,3}%)\s*,\s*([0-9]{1,3}%)\s*,\s*([0,1]?(?:\.[0-9]*)?)\s*\)/i', '$1($2 $3 $4 / $5)', $content);
- $content = preg_replace('/(hsl)a?\(\s*([0-9]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9]{1,3}%)\s*,\s*([0-9]{1,3}%)\s*\)/i', '$1($2 $3 $4)', $content);
-
- // convert `rgb` to `hex`
- $dec = '([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])';
- return preg_replace_callback(
- "/rgb\($dec $dec $dec\)/i",
- function ($match) {
- return sprintf('#%02x%02x%02x', $match[1], $match[2], $match[3]);
- },
- $content
- );
- }
-
- /**
- * Cleanup RGB|HSL|HWB|LCH|LAB
- * rgb(255 0 0 / 1) -> rgb(255 0 0).
- * rgb(255 0 0 / 0) -> transparent.
- *
- * @param string $content The CSS content to cleanup HSL|HWB|LCH|LAB
- *
- * @return string
- */
- protected function cleanupModernColors($content)
- {
- /*
- https://drafts.csswg.org/css-color/#color-syntax-modern
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
- https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab
- */
- $tag = '(rgb|hsl|hwb|(?:(?:ok)?(?:lch|lab)))';
-
- // remove alpha channel if it's pointless ..
- $content = preg_replace('/' . $tag . '\(\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+\/\s+1(?:(?:\.\d?)*|00%)?\s*\)/i', '$1($2 $3 $4)', $content);
-
- // replace `transparent` with shortcut ..
- $content = preg_replace('/' . $tag . '\(\s*[^\s]+\s+[^\s]+\s+[^\s]+\s+\/\s+0(?:[\.0%]*)?\s*\)/i', '#fff0', $content);
-
- return $content;
- }
-
- /**
- * Shorten CSS font weights.
- *
- * @param string $content The CSS content to shorten the font weights for
- *
- * @return string
- */
- protected function shortenFontWeights($content)
- {
- $weights = array(
- 'normal' => 400,
- 'bold' => 700,
- );
-
- $callback = function ($match) use ($weights) {
- return $match[1] . $weights[$match[2]];
- };
-
- return preg_replace_callback('/(font-weight\s*:\s*)(' . implode('|', array_keys($weights)) . ')(?=[;}])/', $callback, $content);
- }
-
- /**
- * Shorthand 0 values to plain 0, instead of e.g. -0em.
- *
- * @param string $content The CSS content to shorten the zero values for
- *
- * @return string
- */
- protected function shortenZeroes($content)
- {
- // we don't want to strip units in `calc()` expressions:
- // `5px - 0px` is valid, but `5px - 0` is not
- // `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but
- // `10 * 0` is invalid
- // we've extracted calcs earlier, so we don't need to worry about this
-
- // reusable bits of code throughout these regexes:
- // before & after are used to make sure we don't match lose unintended
- // 0-like values (e.g. in #000, or in http://url/1.0)
- // units can be stripped from 0 values, or used to recognize non 0
- // values (where wa may be able to strip a .0 suffix)
- $before = '(?<=[:(, ])';
- $after = '(?=[ ,);}])';
- $units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
-
- // strip units after zeroes (0px -> 0)
- // NOTE: it should be safe to remove all units for a 0 value, but in
- // practice, Webkit (especially Safari) seems to stumble over at least
- // 0%, potentially other units as well. Only stripping 'px' for now.
- // @see https://github.com/matthiasmullie/minify/issues/60
- $content = preg_replace('/' . $before . '(-?0*(\.0+)?)(?<=0)px' . $after . '/', '\\1', $content);
-
- // strip 0-digits (.0 -> 0)
- $content = preg_replace('/' . $before . '\.0+' . $units . '?' . $after . '/', '0\\1', $content);
- // strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
- $content = preg_replace('/' . $before . '(-?[0-9]+\.[0-9]+)0+' . $units . '?' . $after . '/', '\\1\\2', $content);
- // strip trailing 0: 50.00 -> 50, 50.00px -> 50px
- $content = preg_replace('/' . $before . '(-?[0-9]+)\.0+' . $units . '?' . $after . '/', '\\1\\2', $content);
- // strip leading 0: 0.1 -> .1, 01.1 -> 1.1
- $content = preg_replace('/' . $before . '(-?)0+([0-9]*\.[0-9]+)' . $units . '?' . $after . '/', '\\1\\2\\3', $content);
-
- // strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
- $content = preg_replace('/' . $before . '-?0+' . $units . '?' . $after . '/', '0\\1', $content);
-
- // IE doesn't seem to understand a unitless flex-basis value (correct -
- // it goes against the spec), so let's add it in again (make it `%`,
- // which is only 1 char: 0%, 0px, 0 anything, it's all just the same)
- // @see https://developer.mozilla.org/nl/docs/Web/CSS/flex
- $content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content);
- $content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
-
- return $content;
- }
-
- /**
- * Strip empty tags from source code.
- *
- * @param string $content
- *
- * @return string
- */
- protected function stripEmptyTags($content)
- {
- $content = preg_replace('/(?<=^)[^\{\};]+\{\s*\}/', '', $content);
- $content = preg_replace('/(?<=(\}|;))[^\{\};]+\{\s*\}/', '', $content);
-
- return $content;
- }
-
- /**
- * Strip comments from source code.
- */
- protected function stripComments()
- {
- $this->stripMultilineComments();
- }
-
- /**
- * Strip whitespace.
- *
- * @param string $content The CSS content to strip the whitespace for
- *
- * @return string
- */
- protected function stripWhitespace($content)
- {
- // remove leading & trailing whitespace
- $content = preg_replace('/^\s*/m', '', $content);
- $content = preg_replace('/\s*$/m', '', $content);
-
- // replace newlines with a single space
- $content = preg_replace('/\s+/', ' ', $content);
-
- // remove whitespace around meta characters
- // inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
- $content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
- $content = preg_replace('/([\[(:>\+])\s+/', '$1', $content);
- $content = preg_replace('/\s+([\]\)>\+])/', '$1', $content);
- $content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
-
- // whitespace around + and - can only be stripped inside some pseudo-
- // classes, like `:nth-child(3+2n)`
- // not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
- // selectors like `div.weird- p`
- $pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
- $content = preg_replace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
-
- // remove semicolon/whitespace followed by closing bracket
- $content = str_replace(';}', '}', $content);
-
- return trim($content);
- }
-
- /**
- * Replace all occurrences of functions that may contain math, where
- * whitespace around operators needs to be preserved (e.g. calc, clamp).
- */
- protected function extractMath()
- {
- $functions = array('calc', 'clamp', 'min', 'max');
- $pattern = '/\b(' . implode('|', $functions) . ')(\(.+?)(?=$|;|})/m';
-
- // PHP only supports $this inside anonymous functions since 5.4
- $minifier = $this;
- $callback = function ($match) use ($minifier, $pattern, &$callback) {
- $function = $match[1];
- $length = strlen($match[2]);
- $expr = '';
- $opened = 0;
-
- // the regular expression for extracting math has 1 significant problem:
- // it can't determine the correct closing parenthesis...
- // instead, it'll match a larger portion of code to where it's certain that
- // the calc() musts have ended, and we'll figure out which is the correct
- // closing parenthesis here, by counting how many have opened
- for ($i = 0; $i < $length; ++$i) {
- $char = $match[2][$i];
- $expr .= $char;
- if ($char === '(') {
- ++$opened;
- } elseif ($char === ')' && --$opened === 0) {
- break;
- }
- }
-
- // now that we've figured out where the calc() starts and ends, extract it
- $count = count($minifier->extracted);
- $placeholder = 'math(' . $count . ')';
- $minifier->extracted[$placeholder] = $function . '(' . trim(substr($expr, 1, -1)) . ')';
-
- // and since we've captured more code than required, we may have some leftover
- // calc() in here too - go recursive on the remaining but of code to go figure
- // that out and extract what is needed
- $rest = $minifier->str_replace_first($function . $expr, '', $match[0]);
- $rest = preg_replace_callback($pattern, $callback, $rest);
-
- return $placeholder . $rest;
- };
-
- $this->registerPattern($pattern, $callback);
- }
-
- /**
- * Replace custom properties, whose values may be used in scenarios where
- * we wouldn't want them to be minified (e.g. inside calc).
- */
- protected function extractCustomProperties()
- {
- // PHP only supports $this inside anonymous functions since 5.4
- $minifier = $this;
- $this->registerPattern(
- '/(?<=^|[;}{])\s*(--[^:;{}"\'\s]+)\s*:([^;{}]+)/m',
- function ($match) use ($minifier) {
- $placeholder = '--custom-' . count($minifier->extracted) . ':0';
- $minifier->extracted[$placeholder] = $match[1] . ':' . trim($match[2]);
-
- return $placeholder;
- }
- );
- }
-
- /**
- * Check if file is small enough to be imported.
- *
- * @param string $path The path to the file
- *
- * @return bool
- */
- protected function canImportBySize($path)
- {
- return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
- }
-
- /**
- * Check if file a file can be imported, going by the path.
- *
- * @param string $path
- *
- * @return bool
- */
- protected function canImportByPath($path)
- {
- return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
- }
-
- /**
- * Return a converter to update relative paths to be relative to the new
- * destination.
- *
- * @param string $source
- * @param string $target
- *
- * @return ConverterInterface
- */
- protected function getPathConverter($source, $target)
- {
- return new Converter($source, $target);
- }
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php
deleted file mode 100644
index 300e43c..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php
+++ /dev/null
@@ -1,22 +0,0 @@
-
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
-
-/**
- * Base Exception Class.
- *
- * @deprecated Use Exceptions\BasicException instead
- *
- * @author Matthias Mullie
- */
-abstract class Exception extends \Exception
-{
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php
deleted file mode 100644
index 6b095e7..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions;
-
-use PoweredCache\Dependencies\MatthiasMullie\Minify\Exception;
-
-/**
- * Basic Exception Class.
- *
- * @author Matthias Mullie
- */
-abstract class BasicException extends Exception
-{
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php
deleted file mode 100644
index 312d6ec..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php
+++ /dev/null
@@ -1,22 +0,0 @@
-
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions;
-
-/**
- * File Import Exception Class.
- *
- * @author Matthias Mullie
- */
-class FileImportException extends BasicException
-{
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php
deleted file mode 100644
index 174d738..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php
+++ /dev/null
@@ -1,22 +0,0 @@
-
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions;
-
-/**
- * IO Exception Class.
- *
- * @author Matthias Mullie
- */
-class IOException extends BasicException
-{
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/JS.php b/includes/classes/Dependencies/MatthiasMullie/Minify/JS.php
deleted file mode 100644
index f934969..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/Minify/JS.php
+++ /dev/null
@@ -1,618 +0,0 @@
-
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
-
-/**
- * JavaScript Minifier Class.
- *
- * Please report bugs on https://github.com/matthiasmullie/minify/issues
- *
- * @author Matthias Mullie
- * @author Tijs Verkoyen
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-class JS extends Minify
-{
- /**
- * Var-matching regex based on http://stackoverflow.com/a/9337047/802993.
- *
- * Note that regular expressions using that bit must have the PCRE_UTF8
- * pattern modifier (/u) set.
- *
- * @internal
- *
- * @var string
- */
- const REGEX_VARIABLE = '\b[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}0-9\x{0300}-\x{036f}\x{0483}-\x{0487}\x{0591}-\x{05bd}\x{05bf}\x{05c1}\x{05c2}\x{05c4}\x{05c5}\x{05c7}\x{0610}-\x{061a}\x{064b}-\x{0669}\x{0670}\x{06d6}-\x{06dc}\x{06df}-\x{06e4}\x{06e7}\x{06e8}\x{06ea}-\x{06ed}\x{06f0}-\x{06f9}\x{0711}\x{0730}-\x{074a}\x{07a6}-\x{07b0}\x{07c0}-\x{07c9}\x{07eb}-\x{07f3}\x{0816}-\x{0819}\x{081b}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082d}\x{0859}-\x{085b}\x{08e4}-\x{08fe}\x{0900}-\x{0903}\x{093a}-\x{093c}\x{093e}-\x{094f}\x{0951}-\x{0957}\x{0962}\x{0963}\x{0966}-\x{096f}\x{0981}-\x{0983}\x{09bc}\x{09be}-\x{09c4}\x{09c7}\x{09c8}\x{09cb}-\x{09cd}\x{09d7}\x{09e2}\x{09e3}\x{09e6}-\x{09ef}\x{0a01}-\x{0a03}\x{0a3c}\x{0a3e}-\x{0a42}\x{0a47}\x{0a48}\x{0a4b}-\x{0a4d}\x{0a51}\x{0a66}-\x{0a71}\x{0a75}\x{0a81}-\x{0a83}\x{0abc}\x{0abe}-\x{0ac5}\x{0ac7}-\x{0ac9}\x{0acb}-\x{0acd}\x{0ae2}\x{0ae3}\x{0ae6}-\x{0aef}\x{0b01}-\x{0b03}\x{0b3c}\x{0b3e}-\x{0b44}\x{0b47}\x{0b48}\x{0b4b}-\x{0b4d}\x{0b56}\x{0b57}\x{0b62}\x{0b63}\x{0b66}-\x{0b6f}\x{0b82}\x{0bbe}-\x{0bc2}\x{0bc6}-\x{0bc8}\x{0bca}-\x{0bcd}\x{0bd7}\x{0be6}-\x{0bef}\x{0c01}-\x{0c03}\x{0c3e}-\x{0c44}\x{0c46}-\x{0c48}\x{0c4a}-\x{0c4d}\x{0c55}\x{0c56}\x{0c62}\x{0c63}\x{0c66}-\x{0c6f}\x{0c82}\x{0c83}\x{0cbc}\x{0cbe}-\x{0cc4}\x{0cc6}-\x{0cc8}\x{0cca}-\x{0ccd}\x{0cd5}\x{0cd6}\x{0ce2}\x{0ce3}\x{0ce6}-\x{0cef}\x{0d02}\x{0d03}\x{0d3e}-\x{0d44}\x{0d46}-\x{0d48}\x{0d4a}-\x{0d4d}\x{0d57}\x{0d62}\x{0d63}\x{0d66}-\x{0d6f}\x{0d82}\x{0d83}\x{0dca}\x{0dcf}-\x{0dd4}\x{0dd6}\x{0dd8}-\x{0ddf}\x{0df2}\x{0df3}\x{0e31}\x{0e34}-\x{0e3a}\x{0e47}-\x{0e4e}\x{0e50}-\x{0e59}\x{0eb1}\x{0eb4}-\x{0eb9}\x{0ebb}\x{0ebc}\x{0ec8}-\x{0ecd}\x{0ed0}-\x{0ed9}\x{0f18}\x{0f19}\x{0f20}-\x{0f29}\x{0f35}\x{0f37}\x{0f39}\x{0f3e}\x{0f3f}\x{0f71}-\x{0f84}\x{0f86}\x{0f87}\x{0f8d}-\x{0f97}\x{0f99}-\x{0fbc}\x{0fc6}\x{102b}-\x{103e}\x{1040}-\x{1049}\x{1056}-\x{1059}\x{105e}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106d}\x{1071}-\x{1074}\x{1082}-\x{108d}\x{108f}-\x{109d}\x{135d}-\x{135f}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17d3}\x{17dd}\x{17e0}-\x{17e9}\x{180b}-\x{180d}\x{1810}-\x{1819}\x{18a9}\x{1920}-\x{192b}\x{1930}-\x{193b}\x{1946}-\x{194f}\x{19b0}-\x{19c0}\x{19c8}\x{19c9}\x{19d0}-\x{19d9}\x{1a17}-\x{1a1b}\x{1a55}-\x{1a5e}\x{1a60}-\x{1a7c}\x{1a7f}-\x{1a89}\x{1a90}-\x{1a99}\x{1b00}-\x{1b04}\x{1b34}-\x{1b44}\x{1b50}-\x{1b59}\x{1b6b}-\x{1b73}\x{1b80}-\x{1b82}\x{1ba1}-\x{1bad}\x{1bb0}-\x{1bb9}\x{1be6}-\x{1bf3}\x{1c24}-\x{1c37}\x{1c40}-\x{1c49}\x{1c50}-\x{1c59}\x{1cd0}-\x{1cd2}\x{1cd4}-\x{1ce8}\x{1ced}\x{1cf2}-\x{1cf4}\x{1dc0}-\x{1de6}\x{1dfc}-\x{1dff}\x{200c}\x{200d}\x{203f}\x{2040}\x{2054}\x{20d0}-\x{20dc}\x{20e1}\x{20e5}-\x{20f0}\x{2cef}-\x{2cf1}\x{2d7f}\x{2de0}-\x{2dff}\x{302a}-\x{302f}\x{3099}\x{309a}\x{a620}-\x{a629}\x{a66f}\x{a674}-\x{a67d}\x{a69f}\x{a6f0}\x{a6f1}\x{a802}\x{a806}\x{a80b}\x{a823}-\x{a827}\x{a880}\x{a881}\x{a8b4}-\x{a8c4}\x{a8d0}-\x{a8d9}\x{a8e0}-\x{a8f1}\x{a900}-\x{a909}\x{a926}-\x{a92d}\x{a947}-\x{a953}\x{a980}-\x{a983}\x{a9b3}-\x{a9c0}\x{a9d0}-\x{a9d9}\x{aa29}-\x{aa36}\x{aa43}\x{aa4c}\x{aa4d}\x{aa50}-\x{aa59}\x{aa7b}\x{aab0}\x{aab2}-\x{aab4}\x{aab7}\x{aab8}\x{aabe}\x{aabf}\x{aac1}\x{aaeb}-\x{aaef}\x{aaf5}\x{aaf6}\x{abe3}-\x{abea}\x{abec}\x{abed}\x{abf0}-\x{abf9}\x{fb1e}\x{fe00}-\x{fe0f}\x{fe20}-\x{fe26}\x{fe33}\x{fe34}\x{fe4d}-\x{fe4f}\x{ff10}-\x{ff19}\x{ff3f}]*\b';
-
- /**
- * Full list of JavaScript reserved words.
- * Will be loaded from /data/js/keywords_reserved.txt.
- *
- * @see https://mathiasbynens.be/notes/reserved-keywords
- *
- * @var string[]
- */
- protected $keywordsReserved = array();
-
- /**
- * List of JavaScript reserved words that accept a
- * after them. Some end of lines are not the end of a statement, like with
- * these keywords.
- *
- * E.g.: we shouldn't insert a ; after this else
- * else
- * console.log('this is quite fine')
- *
- * Will be loaded from /data/js/keywords_before.txt
- *
- * @var string[]
- */
- protected $keywordsBefore = array();
-
- /**
- * List of JavaScript reserved words that accept a
- * before them. Some end of lines are not the end of a statement, like when
- * continued by one of these keywords on the newline.
- *
- * E.g.: we shouldn't insert a ; before this instanceof
- * variable
- * instanceof String
- *
- * Will be loaded from /data/js/keywords_after.txt
- *
- * @var string[]
- */
- protected $keywordsAfter = array();
-
- /**
- * List of all JavaScript operators.
- *
- * Will be loaded from /data/js/operators.txt
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- *
- * @var string[]
- */
- protected $operators = array();
-
- /**
- * List of JavaScript operators that accept a after
- * them. Some end of lines are not the end of a statement, like with these
- * operators.
- *
- * Note: Most operators are fine, we've only removed ++ and --.
- * ++ & -- have to be joined with the value they're in-/decrementing.
- *
- * Will be loaded from /data/js/operators_before.txt
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- *
- * @var string[]
- */
- protected $operatorsBefore = array();
-
- /**
- * List of JavaScript operators that accept a before
- * them. Some end of lines are not the end of a statement, like when
- * continued by one of these operators on the newline.
- *
- * Note: Most operators are fine, we've only removed ), ], ++, --, ! and ~.
- * There can't be a newline separating ! or ~ and whatever it is negating.
- * ++ & -- have to be joined with the value they're in-/decrementing.
- * ) & ] are "special" in that they have lots or usecases. () for example
- * is used for function calls, for grouping, in if () and for (), ...
- *
- * Will be loaded from /data/js/operators_after.txt
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- *
- * @var string[]
- */
- protected $operatorsAfter = array();
-
- public function __construct()
- {
- call_user_func_array(array('\\PoweredCache\Dependencies\MatthiasMullie\Minify\\Minify', '__construct'), func_get_args());
-
- $dataDir = __DIR__ . '/../data/js/';
- $options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES;
- $this->keywordsReserved = file($dataDir . 'keywords_reserved.txt', $options);
- $this->keywordsBefore = file($dataDir . 'keywords_before.txt', $options);
- $this->keywordsAfter = file($dataDir . 'keywords_after.txt', $options);
- $this->operators = file($dataDir . 'operators.txt', $options);
- $this->operatorsBefore = file($dataDir . 'operators_before.txt', $options);
- $this->operatorsAfter = file($dataDir . 'operators_after.txt', $options);
- }
-
- /**
- * Minify the data.
- * Perform JS optimizations.
- *
- * @param string[optional] $path Path to write the data to
- *
- * @return string The minified data
- */
- public function execute($path = null)
- {
- $content = '';
-
- /*
- * Let's first take out strings, comments and regular expressions.
- * All of these can contain JS code-like characters, and we should make
- * sure any further magic ignores anything inside of these.
- *
- * Consider this example, where we should not strip any whitespace:
- * var str = "a test";
- *
- * Comments will be removed altogether, strings and regular expressions
- * will be replaced by placeholder text, which we'll restore later.
- */
- $this->extractStrings('\'"`');
- $this->stripComments();
- $this->extractRegex();
-
- // loop files
- foreach ($this->data as $source => $js) {
- // take out strings, comments & regex (for which we've registered
- // the regexes just a few lines earlier)
- $js = $this->replace($js);
-
- $js = $this->propertyNotation($js);
- $js = $this->shortenBools($js);
- $js = $this->stripWhitespace($js);
-
- // combine js: separating the scripts by a ;
- $content .= $js . ';';
- }
-
- // clean up leftover `;`s from the combination of multiple scripts
- $content = ltrim($content, ';');
- $content = (string) substr($content, 0, -1);
-
- /*
- * Earlier, we extracted strings & regular expressions and replaced them
- * with placeholder text. This will restore them.
- */
- $content = $this->restoreExtractedData($content);
-
- return $content;
- }
-
- /**
- * Strip comments from source code.
- */
- protected function stripComments()
- {
- $this->stripMultilineComments();
-
- // single-line comments
- $this->registerPattern('/\/\/.*$/m', '');
- }
-
- /**
- * JS can have /-delimited regular expressions, like: /ab+c/.match(string).
- *
- * The content inside the regex can contain characters that may be confused
- * for JS code: e.g. it could contain whitespace it needs to match & we
- * don't want to strip whitespace in there.
- *
- * The regex can be pretty simple: we don't have to care about comments,
- * (which also use slashes) because stripComments() will have stripped those
- * already.
- *
- * This method will replace all string content with simple REGEX#
- * placeholder text, so we've rid all regular expressions from characters
- * that may be misinterpreted. Original regex content will be saved in
- * $this->extracted and after doing all other minifying, we can restore the
- * original content via restoreRegex()
- */
- protected function extractRegex()
- {
- // PHP only supports $this inside anonymous functions since 5.4
- $minifier = $this;
- $callback = function ($match) use ($minifier) {
- $count = count($minifier->extracted);
- $placeholder = '"' . $count . '"';
- $minifier->extracted[$placeholder] = $match[0];
-
- return $placeholder;
- };
-
- // match all chars except `/` and `\`
- // `\` is allowed though, along with whatever char follows (which is the
- // one being escaped)
- // this should allow all chars, except for an unescaped `/` (= the one
- // closing the regex)
- // then also ignore bare `/` inside `[]`, where they don't need to be
- // escaped: anything inside `[]` can be ignored safely
- $pattern = '\\/(?!\*)(?:[^\\[\\/\\\\\n\r]++|(?:\\\\.)++|(?:\\[(?:[^\\]\\\\\n\r]++|(?:\\\\.)++)++\\])++)++\\/[gimuy]*';
-
- // a regular expression can only be followed by a few operators or some
- // of the RegExp methods (a `\` followed by a variable or value is
- // likely part of a division, not a regex)
- $keywords = array('do', 'in', 'new', 'else', 'throw', 'yield', 'delete', 'return', 'typeof');
- $before = '(^|[=:,;\+\-\*\?\/\}\(\{\[&\|!]|' . implode('|', $keywords) . ')\s*';
- $propertiesAndMethods = array(
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2
- 'constructor',
- 'flags',
- 'global',
- 'ignoreCase',
- 'multiline',
- 'source',
- 'sticky',
- 'unicode',
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Methods_2
- 'compile(',
- 'exec(',
- 'test(',
- 'toSource(',
- 'toString(',
- );
- $delimiters = array_fill(0, count($propertiesAndMethods), '/');
- $propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters);
- $after = '(?=\s*([\.,;:\)\}&\|+]|\/\/|$|\.(' . implode('|', $propertiesAndMethods) . ')))';
- $this->registerPattern('/' . $before . '\K' . $pattern . $after . '/', $callback);
-
- // regular expressions following a `)` are rather annoying to detect...
- // quite often, `/` after `)` is a division operator & if it happens to
- // be followed by another one (or a comment), it is likely to be
- // confused for a regular expression
- // however, it's perfectly possible for a regex to follow a `)`: after
- // a single-line `if()`, `while()`, ... statement, for example
- // since, when they occur like that, they're always the start of a
- // statement, there's only a limited amount of ways they can be useful:
- // by calling the regex methods directly
- // if a regex following `)` is not followed by `.`,
- // it's quite likely not a regex
- $before = '\)\s*';
- $after = '(?=\s*\.(' . implode('|', $propertiesAndMethods) . '))';
- $this->registerPattern('/' . $before . '\K' . $pattern . $after . '/', $callback);
-
- // 1 more edge case: a regex can be followed by a lot more operators or
- // keywords if there's a newline (ASI) in between, where the operator
- // actually starts a new statement
- // (https://github.com/matthiasmullie/minify/issues/56)
- $operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
- $operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
- $after = '(?=\s*\n\s*(' . implode('|', $operators) . '))';
- $this->registerPattern('/' . $pattern . $after . '/', $callback);
- }
-
- /**
- * Strip whitespace.
- *
- * We won't strip *all* whitespace, but as much as possible. The thing that
- * we'll preserve are newlines we're unsure about.
- * JavaScript doesn't require statements to be terminated with a semicolon.
- * It will automatically fix missing semicolons with ASI (automatic semi-
- * colon insertion) at the end of line causing errors (without semicolon.)
- *
- * Because it's sometimes hard to tell if a newline is part of a statement
- * that should be terminated or not, we'll just leave some of them alone.
- *
- * @param string $content The content to strip the whitespace for
- *
- * @return string
- */
- protected function stripWhitespace($content)
- {
- // uniform line endings, make them all line feed
- $content = str_replace(array("\r\n", "\r"), "\n", $content);
-
- // collapse all non-line feed whitespace into a single space
- $content = preg_replace('/[^\S\n]+/', ' ', $content);
-
- // strip leading & trailing whitespace
- $content = str_replace(array(" \n", "\n "), "\n", $content);
-
- // collapse consecutive line feeds into just 1
- $content = preg_replace('/\n+/', "\n", $content);
-
- $operatorsBefore = $this->getOperatorsForRegex($this->operatorsBefore, '/');
- $operatorsAfter = $this->getOperatorsForRegex($this->operatorsAfter, '/');
- $operators = $this->getOperatorsForRegex($this->operators, '/');
- $keywordsBefore = $this->getKeywordsForRegex($this->keywordsBefore, '/');
- $keywordsAfter = $this->getKeywordsForRegex($this->keywordsAfter, '/');
-
- // strip whitespace that ends in (or next line begin with) an operator
- // that allows statements to be broken up over multiple lines
- unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
- $content = preg_replace(
- array(
- '/(' . implode('|', $operatorsBefore) . ')\s+/',
- '/\s+(' . implode('|', $operatorsAfter) . ')/',
- ),
- '\\1',
- $content
- );
-
- // make sure + and - can't be mistaken for, or joined into ++ and --
- $content = preg_replace(
- array(
- '/(?%&|', $delimiter);
- $operators['='] = '(?keywordsReserved;
- $callback = function ($match) use ($minifier, $keywords) {
- $property = trim($minifier->extracted[$match[1]], '\'"');
-
- /*
- * Check if the property is a reserved keyword. In this context (as
- * property of an object literal/array) it shouldn't matter, but IE8
- * freaks out with "Expected identifier".
- */
- if (in_array($property, $keywords)) {
- return $match[0];
- }
-
- /*
- * See if the property is in a variable-like format (e.g.
- * array['key-here'] can't be replaced by array.key-here since '-'
- * is not a valid character there.
- */
- if (!preg_match('/^' . $minifier::REGEX_VARIABLE . '$/u', $property)) {
- return $match[0];
- }
-
- return '.' . $property;
- };
-
- /*
- * Figure out if previous character is a variable name (of the array
- * we want to use property notation on) - this is to make sure
- * standalone ['value'] arrays aren't confused for keys-of-an-array.
- * We can (and only have to) check the last character, because PHP's
- * regex implementation doesn't allow unfixed-length look-behind
- * assertions.
- */
- preg_match('/(\[[^\]]+\])[^\]]*$/', static::REGEX_VARIABLE, $previousChar);
- $previousChar = $previousChar[1];
-
- /*
- * Make sure word preceding the ['value'] is not a keyword, e.g.
- * return['x']. Because -again- PHP's regex implementation doesn't allow
- * unfixed-length look-behind assertions, I'm just going to do a lot of
- * separate look-behind assertions, one for each keyword.
- */
- $keywords = $this->getKeywordsForRegex($keywords);
- $keywords = '(?
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-
-namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
-
-use PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions\IOException;
-use Psr\Cache\CacheItemInterface;
-
-/**
- * Abstract minifier class.
- *
- * Please report bugs on https://github.com/matthiasmullie/minify/issues
- *
- * @author Matthias Mullie
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-abstract class Minify
-{
- /**
- * The data to be minified.
- *
- * @var string[]
- */
- protected $data = array();
-
- /**
- * Array of patterns to match.
- *
- * @var string[]
- */
- protected $patterns = array();
-
- /**
- * This array will hold content of strings and regular expressions that have
- * been extracted from the JS source code, so we can reliably match "code",
- * without having to worry about potential "code-like" characters inside.
- *
- * @internal
- *
- * @var string[]
- */
- public $extracted = array();
-
- /**
- * Init the minify class - optionally, code may be passed along already.
- */
- public function __construct(/* $data = null, ... */)
- {
- // it's possible to add the source through the constructor as well ;)
- if (func_num_args()) {
- call_user_func_array(array($this, 'add'), func_get_args());
- }
- }
-
- /**
- * Add a file or straight-up code to be minified.
- *
- * @param string|string[] $data
- *
- * @return static
- */
- public function add($data /* $data = null, ... */)
- {
- // bogus "usage" of parameter $data: scrutinizer warns this variable is
- // not used (we're using func_get_args instead to support overloading),
- // but it still needs to be defined because it makes no sense to have
- // this function without argument :)
- $args = array($data) + func_get_args();
-
- // this method can be overloaded
- foreach ($args as $data) {
- if (is_array($data)) {
- call_user_func_array(array($this, 'add'), $data);
- continue;
- }
-
- // redefine var
- $data = (string) $data;
-
- // load data
- $value = $this->load($data);
- $key = ($data != $value) ? $data : count($this->data);
-
- // replace CR linefeeds etc.
- // @see https://github.com/matthiasmullie/minify/pull/139
- $value = str_replace(array("\r\n", "\r"), "\n", $value);
-
- // store data
- $this->data[$key] = $value;
- }
-
- return $this;
- }
-
- /**
- * Add a file to be minified.
- *
- * @param string|string[] $data
- *
- * @return static
- *
- * @throws IOException
- */
- public function addFile($data /* $data = null, ... */)
- {
- // bogus "usage" of parameter $data: scrutinizer warns this variable is
- // not used (we're using func_get_args instead to support overloading),
- // but it still needs to be defined because it makes no sense to have
- // this function without argument :)
- $args = array($data) + func_get_args();
-
- // this method can be overloaded
- foreach ($args as $path) {
- if (is_array($path)) {
- call_user_func_array(array($this, 'addFile'), $path);
- continue;
- }
-
- // redefine var
- $path = (string) $path;
-
- // check if we can read the file
- if (!$this->canImportFile($path)) {
- throw new IOException('The file "' . $path . '" could not be opened for reading. Check if PHP has enough permissions.');
- }
-
- $this->add($path);
- }
-
- return $this;
- }
-
- /**
- * Minify the data & (optionally) saves it to a file.
- *
- * @param string[optional] $path Path to write the data to
- *
- * @return string The minified data
- */
- public function minify($path = null)
- {
- $content = $this->execute($path);
-
- // save to path
- if ($path !== null) {
- $this->save($content, $path);
- }
-
- return $content;
- }
-
- /**
- * Minify & gzip the data & (optionally) saves it to a file.
- *
- * @param string[optional] $path Path to write the data to
- * @param int[optional] $level Compression level, from 0 to 9
- *
- * @return string The minified & gzipped data
- */
- public function gzip($path = null, $level = 9)
- {
- $content = $this->execute($path);
- $content = gzencode($content, $level, FORCE_GZIP);
-
- // save to path
- if ($path !== null) {
- $this->save($content, $path);
- }
-
- return $content;
- }
-
- /**
- * Minify the data & write it to a CacheItemInterface object.
- *
- * @param CacheItemInterface $item Cache item to write the data to
- *
- * @return CacheItemInterface Cache item with the minifier data
- */
- public function cache(CacheItemInterface $item)
- {
- $content = $this->execute();
- $item->set($content);
-
- return $item;
- }
-
- /**
- * Minify the data.
- *
- * @param string[optional] $path Path to write the data to
- *
- * @return string The minified data
- */
- abstract public function execute($path = null);
-
- /**
- * Load data.
- *
- * @param string $data Either a path to a file or the content itself
- *
- * @return string
- */
- protected function load($data)
- {
- // check if the data is a file
- if ($this->canImportFile($data)) {
- $data = file_get_contents($data);
-
- // strip BOM, if any
- if (substr($data, 0, 3) == "\xef\xbb\xbf") {
- $data = substr($data, 3);
- }
- }
-
- return $data;
- }
-
- /**
- * Save to file.
- *
- * @param string $content The minified data
- * @param string $path The path to save the minified data to
- *
- * @throws IOException
- */
- protected function save($content, $path)
- {
- $handler = $this->openFileForWriting($path);
-
- $this->writeToFile($handler, $content);
-
- @fclose($handler);
- }
-
- /**
- * Register a pattern to execute against the source content.
- *
- * If $replacement is a string, it must be plain text. Placeholders like $1 or \2 don't work.
- * If you need that functionality, use a callback instead.
- *
- * @param string $pattern PCRE pattern
- * @param string|callable $replacement Replacement value for matched pattern
- */
- protected function registerPattern($pattern, $replacement = '')
- {
- // study the pattern, we'll execute it more than once
- $pattern .= 'S';
-
- $this->patterns[] = array($pattern, $replacement);
- }
-
- /**
- * Both JS and CSS use the same form of multi-line comment, so putting the common code here.
- */
- protected function stripMultilineComments()
- {
- // First extract comments we want to keep, so they can be restored later
- // PHP only supports $this inside anonymous functions since 5.4
- $minifier = $this;
- $callback = function ($match) use ($minifier) {
- $count = count($minifier->extracted);
- $placeholder = '/*' . $count . '*/';
- $minifier->extracted[$placeholder] = $match[0];
-
- return $placeholder;
- };
- $this->registerPattern('/
- # optional newline
- \n?
-
- # start comment
- \/\*
-
- # comment content
- (?:
- # either starts with an !
- !
- |
- # or, after some number of characters which do not end the comment
- (?:(?!\*\/).)*?
-
- # there is either a @license or @preserve tag
- @(?:license|preserve)
- )
-
- # then match to the end of the comment
- .*?\*\/\n?
-
- /ixs', $callback);
-
- // Then strip all other comments
- $this->registerPattern('/\/\*.*?\*\//s', '');
- }
-
- /**
- * We can't "just" run some regular expressions against JavaScript: it's a
- * complex language. E.g. having an occurrence of // xyz would be a comment,
- * unless it's used within a string. Of you could have something that looks
- * like a 'string', but inside a comment.
- * The only way to accurately replace these pieces is to traverse the JS one
- * character at a time and try to find whatever starts first.
- *
- * @param string $content The content to replace patterns in
- *
- * @return string The (manipulated) content
- */
- protected function replace($content)
- {
- $contentLength = strlen($content);
- $output = '';
- $processedOffset = 0;
- $positions = array_fill(0, count($this->patterns), -1);
- $matches = array();
-
- while ($processedOffset < $contentLength) {
- // find first match for all patterns
- foreach ($this->patterns as $i => $pattern) {
- list($pattern, $replacement) = $pattern;
-
- // we can safely ignore patterns for positions we've unset earlier,
- // because we know these won't show up anymore
- if (array_key_exists($i, $positions) == false) {
- continue;
- }
-
- // no need to re-run matches that are still in the part of the
- // content that hasn't been processed
- if ($positions[$i] >= $processedOffset) {
- continue;
- }
-
- $match = null;
- if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset)) {
- $matches[$i] = $match;
-
- // we'll store the match position as well; that way, we
- // don't have to redo all preg_matches after changing only
- // the first (we'll still know where those others are)
- $positions[$i] = $match[0][1];
- } else {
- // if the pattern couldn't be matched, there's no point in
- // executing it again in later runs on this same content;
- // ignore this one until we reach end of content
- unset($matches[$i], $positions[$i]);
- }
- }
-
- // no more matches to find: everything's been processed, break out
- if (!$matches) {
- // output the remaining content
- $output .= substr($content, $processedOffset);
- break;
- }
-
- // see which of the patterns actually found the first thing (we'll
- // only want to execute that one, since we're unsure if what the
- // other found was not inside what the first found)
- $matchOffset = min($positions);
- $firstPattern = array_search($matchOffset, $positions);
- $match = $matches[$firstPattern];
-
- // execute the pattern that matches earliest in the content string
- list(, $replacement) = $this->patterns[$firstPattern];
-
- // add the part of the input between $processedOffset and the first match;
- // that content wasn't matched by anything
- $output .= substr($content, $processedOffset, $matchOffset - $processedOffset);
- // add the replacement for the match
- $output .= $this->executeReplacement($replacement, $match);
- // advance $processedOffset past the match
- $processedOffset = $matchOffset + strlen($match[0][0]);
- }
-
- return $output;
- }
-
- /**
- * If $replacement is a callback, execute it, passing in the match data.
- * If it's a string, just pass it through.
- *
- * @param string|callable $replacement Replacement value
- * @param array $match Match data, in PREG_OFFSET_CAPTURE form
- *
- * @return string
- */
- protected function executeReplacement($replacement, $match)
- {
- if (!is_callable($replacement)) {
- return $replacement;
- }
- // convert $match from the PREG_OFFSET_CAPTURE form to the form the callback expects
- foreach ($match as &$matchItem) {
- $matchItem = $matchItem[0];
- }
-
- return $replacement($match);
- }
-
- /**
- * Strings are a pattern we need to match, in order to ignore potential
- * code-like content inside them, but we just want all of the string
- * content to remain untouched.
- *
- * This method will replace all string content with simple STRING#
- * placeholder text, so we've rid all strings from characters that may be
- * misinterpreted. Original string content will be saved in $this->extracted
- * and after doing all other minifying, we can restore the original content
- * via restoreStrings().
- *
- * @param string[optional] $chars
- * @param string[optional] $placeholderPrefix
- */
- protected function extractStrings($chars = '\'"', $placeholderPrefix = '')
- {
- // PHP only supports $this inside anonymous functions since 5.4
- $minifier = $this;
- $callback = function ($match) use ($minifier, $placeholderPrefix) {
- // check the second index here, because the first always contains a quote
- if ($match[2] === '') {
- /*
- * Empty strings need no placeholder; they can't be confused for
- * anything else anyway.
- * But we still needed to match them, for the extraction routine
- * to skip over this particular string.
- */
- return $match[0];
- }
-
- $count = count($minifier->extracted);
- $placeholder = $match[1] . $placeholderPrefix . $count . $match[1];
- $minifier->extracted[$placeholder] = $match[1] . $match[2] . $match[1];
-
- return $placeholder;
- };
-
- /*
- * The \\ messiness explained:
- * * Don't count ' or " as end-of-string if it's escaped (has backslash
- * in front of it)
- * * Unless... that backslash itself is escaped (another leading slash),
- * in which case it's no longer escaping the ' or "
- * * So there can be either no backslash, or an even number
- * * multiply all of that times 4, to account for the escaping that has
- * to be done to pass the backslash into the PHP string without it being
- * considered as escape-char (times 2) and to get it in the regex,
- * escaped (times 2)
- */
- $this->registerPattern('/([' . $chars . '])(.*?(?extracted.
- *
- * @param string $content
- *
- * @return string
- */
- protected function restoreExtractedData($content)
- {
- if (!$this->extracted) {
- // nothing was extracted, nothing to restore
- return $content;
- }
-
- $content = strtr($content, $this->extracted);
-
- $this->extracted = array();
-
- return $content;
- }
-
- /**
- * Check if the path is a regular file and can be read.
- *
- * @param string $path
- *
- * @return bool
- */
- protected function canImportFile($path)
- {
- $parsed = parse_url($path);
- if (
- // file is elsewhere
- isset($parsed['host'])
- // file responds to queries (may change, or need to bypass cache)
- || isset($parsed['query'])
- ) {
- return false;
- }
-
- try {
- return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
- }
- // catch openbasedir exceptions which are not caught by @ on is_file()
- catch (\Exception $e) {
- return false;
- }
- }
-
- /**
- * Attempts to open file specified by $path for writing.
- *
- * @param string $path The path to the file
- *
- * @return resource Specifier for the target file
- *
- * @throws IOException
- */
- protected function openFileForWriting($path)
- {
- if ($path === '' || ($handler = @fopen($path, 'w')) === false) {
- throw new IOException('The file "' . $path . '" could not be opened for writing. Check if PHP has enough permissions.');
- }
-
- return $handler;
- }
-
- /**
- * Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
- *
- * @param resource $handler The resource to write to
- * @param string $content The content to write
- * @param string $path The path to the file (for exception printing only)
- *
- * @throws IOException
- */
- protected function writeToFile($handler, $content, $path = '')
- {
- if (
- !is_resource($handler)
- || ($result = @fwrite($handler, $content)) === false
- || ($result < strlen($content))
- ) {
- throw new IOException('The file "' . $path . '" could not be written to. Check your disk space and file permissions.');
- }
- }
-
- protected static function str_replace_first($search, $replace, $subject)
- {
- $pos = strpos($subject, $search);
- if ($pos !== false) {
- return substr_replace($subject, $replace, $pos, strlen($search));
- }
-
- return $subject;
- }
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php b/includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php
deleted file mode 100644
index d1aedbd..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php
+++ /dev/null
@@ -1,204 +0,0 @@
-
- * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-class Converter implements ConverterInterface
-{
- /**
- * @var string
- */
- protected $from;
-
- /**
- * @var string
- */
- protected $to;
-
- /**
- * @param string $from The original base path (directory, not file!)
- * @param string $to The new base path (directory, not file!)
- * @param string $root Root directory (defaults to `getcwd`)
- */
- public function __construct($from, $to, $root = '')
- {
- $shared = $this->shared($from, $to);
- if ($shared === '') {
- // when both paths have nothing in common, one of them is probably
- // absolute while the other is relative
- $root = $root ?: getcwd();
- $from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from);
- $to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to);
-
- // or traveling the tree via `..`
- // attempt to resolve path, or assume it's fine if it doesn't exist
- $from = @realpath($from) ?: $from;
- $to = @realpath($to) ?: $to;
- }
-
- $from = $this->dirname($from);
- $to = $this->dirname($to);
-
- $from = $this->normalize($from);
- $to = $this->normalize($to);
-
- $this->from = $from;
- $this->to = $to;
- }
-
- /**
- * Normalize path.
- *
- * @param string $path
- *
- * @return string
- */
- protected function normalize($path)
- {
- // deal with different operating systems' directory structure
- $path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
-
- // remove leading current directory.
- if (substr($path, 0, 2) === './') {
- $path = substr($path, 2);
- }
-
- // remove references to current directory in the path.
- $path = str_replace('/./', '/', $path);
-
- /*
- * Example:
- * /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif
- * to
- * /home/forkcms/frontend/core/layout/images/img.gif
- */
- do {
- $path = preg_replace('/[^\/]+(? $chunk) {
- if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {
- $shared[] = $chunk;
- } else {
- break;
- }
- }
-
- return implode('/', $shared);
- }
-
- /**
- * Convert paths relative from 1 file to another.
- *
- * E.g.
- * ../images/img.gif relative to /home/forkcms/frontend/core/layout/css
- * should become:
- * ../../core/layout/images/img.gif relative to
- * /home/forkcms/frontend/cache/minified_css
- *
- * @param string $path The relative path that needs to be converted
- *
- * @return string The new relative path
- */
- public function convert($path)
- {
- // quit early if conversion makes no sense
- if ($this->from === $this->to) {
- return $path;
- }
-
- $path = $this->normalize($path);
- // if we're not dealing with a relative path, just return absolute
- if (strpos($path, '/') === 0) {
- return $path;
- }
-
- // normalize paths
- $path = $this->normalize($this->from.'/'.$path);
-
- // strip shared ancestor paths
- $shared = $this->shared($path, $this->to);
- $path = mb_substr($path, mb_strlen($shared));
- $to = mb_substr($this->to, mb_strlen($shared));
-
- // add .. for every directory that needs to be traversed to new path
- $to = str_repeat('../', count(array_filter(explode('/', $to))));
-
- return $to.ltrim($path, '/');
- }
-
- /**
- * Attempt to get the directory name from a path.
- *
- * @param string $path
- *
- * @return string
- */
- protected function dirname($path)
- {
- if (@is_file($path)) {
- return dirname($path);
- }
-
- if (@is_dir($path)) {
- return rtrim($path, '/');
- }
-
- // no known file/dir, start making assumptions
-
- // ends in / = dir
- if (mb_substr($path, -1) === '/') {
- return rtrim($path, '/');
- }
-
- // has a dot in the name, likely a file
- if (preg_match('/.*\..*$/', basename($path)) !== 0) {
- return dirname($path);
- }
-
- // you're on your own here!
- return $path;
- }
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php b/includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php
deleted file mode 100644
index 729ecbd..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-interface ConverterInterface
-{
- /**
- * Convert file paths.
- *
- * @param string $path The path to be converted
- *
- * @return string The new path
- */
- public function convert($path);
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php b/includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php
deleted file mode 100644
index f004bd0..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php
+++ /dev/null
@@ -1,23 +0,0 @@
-
- * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
- * @license MIT License
- */
-class NoConverter implements ConverterInterface
-{
- /**
- * {@inheritdoc}
- */
- public function convert($path)
- {
- return $path;
- }
-}
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt
deleted file mode 100644
index 5c8cba7..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-in
-public
-extends
-private
-protected
-implements
-instanceof
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt
deleted file mode 100644
index 5abf357..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-do
-in
-let
-new
-var
-case
-else
-enum
-void
-with
-class
-const
-yield
-delete
-export
-import
-public
-static
-typeof
-extends
-package
-private
-function
-protected
-implements
-instanceof
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt
deleted file mode 100644
index 2a3ad3c..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-do
-if
-in
-for
-let
-new
-try
-var
-case
-else
-enum
-eval
-null
-this
-true
-void
-with
-break
-catch
-class
-const
-false
-super
-throw
-while
-yield
-delete
-export
-import
-public
-return
-static
-switch
-typeof
-default
-extends
-finally
-package
-private
-continue
-debugger
-function
-arguments
-interface
-protected
-implements
-instanceof
-abstract
-boolean
-byte
-char
-double
-final
-float
-goto
-int
-long
-native
-short
-synchronized
-throws
-transient
-volatile
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt
deleted file mode 100644
index e66229a..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-+
--
-*
-/
-%
-=
-+=
--=
-*=
-/=
-%=
-<<=
->>=
->>>=
-&=
-^=
-|=
-&
-|
-^
-~
-<<
->>
->>>
-==
-===
-!=
-!==
->
-<
->=
-<=
-&&
-||
-!
-.
-[
-]
-?
-:
-,
-;
-(
-)
-{
-}
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt
deleted file mode 100644
index 71a9b70..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-+
--
-*
-/
-%
-=
-+=
--=
-*=
-/=
-%=
-<<=
->>=
->>>=
-&=
-^=
-|=
-&
-|
-^
-<<
->>
->>>
-==
-===
-!=
-!==
->
-<
->=
-<=
-&&
-||
-.
-[
-]
-?
-:
-,
-;
-(
-)
-}
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt
deleted file mode 100644
index ff50d87..0000000
--- a/includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-+
--
-*
-/
-%
-=
-+=
--=
-*=
-/=
-%=
-<<=
->>=
->>>=
-&=
-^=
-|=
-&
-|
-^
-~
-<<
->>
->>>
-==
-===
-!=
-!==
->
-<
->=
-<=
-&&
-||
-!
-.
-[
-?
-:
-,
-;
-(
-{
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md b/includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md
deleted file mode 100644
index de81fa2..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md
+++ /dev/null
@@ -1,18 +0,0 @@
-CHANGELOG
-=========
-
-4.4.0
------
-
- * Added support for `*:only-of-type`
-
-2.8.0
------
-
- * Added the `CssSelectorConverter` class as a non-static API for the component.
- * Deprecated the `CssSelector` static API of the component.
-
-2.1.0
------
-
- * none
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php
deleted file mode 100644
index 8336bfe..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php
+++ /dev/null
@@ -1,69 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
-
-/**
- * CssSelectorConverter is the main entry point of the component and can convert CSS
- * selectors to XPath expressions.
- *
- * @author Christophe Coevoet
- */
-class CssSelectorConverter
-{
- private $translator;
- private $cache;
-
- private static $xmlCache = [];
- private static $htmlCache = [];
-
- /**
- * @param bool $html Whether HTML support should be enabled. Disable it for XML documents
- */
- public function __construct(bool $html = true)
- {
- $this->translator = new Translator();
-
- if ($html) {
- $this->translator->registerExtension(new HtmlExtension($this->translator));
- $this->cache = &self::$htmlCache;
- } else {
- $this->cache = &self::$xmlCache;
- }
-
- $this->translator
- ->registerParserShortcut(new EmptyStringParser())
- ->registerParserShortcut(new ElementParser())
- ->registerParserShortcut(new ClassParser())
- ->registerParserShortcut(new HashParser())
- ;
- }
-
- /**
- * Translates a CSS expression to its XPath equivalent.
- *
- * Optionally, a prefix can be added to the resulting XPath
- * expression with the $prefix parameter.
- *
- * @return string
- */
- public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::')
- {
- return $this->cache[$prefix][$cssExpr] ?? $this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
deleted file mode 100644
index 311463d..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
-
-/**
- * Interface for exceptions.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- */
-interface ExceptionInterface extends \Throwable
-{
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
deleted file mode 100644
index 63e7ede..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
-
-/**
- * ParseException is thrown when a CSS selector syntax is not valid.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- */
-class ExpressionErrorException extends ParseException
-{
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php
deleted file mode 100644
index 0e23f8b..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
-
-/**
- * ParseException is thrown when a CSS selector syntax is not valid.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- */
-class InternalErrorException extends ParseException
-{
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php
deleted file mode 100644
index b3f0b1a..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
-
-/**
- * ParseException is thrown when a CSS selector syntax is not valid.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Fabien Potencier
- */
-class ParseException extends \Exception implements ExceptionInterface
-{
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
deleted file mode 100644
index 55d000d..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
+++ /dev/null
@@ -1,65 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-/**
- * ParseException is thrown when a CSS selector syntax is not valid.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- */
-class SyntaxErrorException extends ParseException
-{
- /**
- * @return self
- */
- public static function unexpectedToken(string $expectedValue, Token $foundToken)
- {
- return new self(sprintf('Expected %s, but %s found.', $expectedValue, $foundToken));
- }
-
- /**
- * @return self
- */
- public static function pseudoElementFound(string $pseudoElement, string $unexpectedLocation)
- {
- return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation));
- }
-
- /**
- * @return self
- */
- public static function unclosedString(int $position)
- {
- return new self(sprintf('Unclosed/invalid string at %s.', $position));
- }
-
- /**
- * @return self
- */
- public static function nestedNot()
- {
- return new self('Got nested ::not().');
- }
-
- /**
- * @return self
- */
- public static function stringAsFunctionArgument()
- {
- return new self('String not allowed as function argument.');
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE b/includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE
deleted file mode 100644
index 0138f8f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-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
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php
deleted file mode 100644
index c643366..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php
+++ /dev/null
@@ -1,39 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Abstract base node class.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-abstract class AbstractNode implements NodeInterface
-{
- /**
- * @var string
- */
- private $nodeName;
-
- public function getNodeName(): string
- {
- if (null === $this->nodeName) {
- $this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class);
- }
-
- return $this->nodeName;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php
deleted file mode 100644
index e624a46..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php
+++ /dev/null
@@ -1,82 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a "[| ]" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class AttributeNode extends AbstractNode
-{
- private $selector;
- private $namespace;
- private $attribute;
- private $operator;
- private $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 getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getNamespace(): ?string
- {
- return $this->namespace;
- }
-
- public function getAttribute(): string
- {
- return $this->attribute;
- }
-
- public function getOperator(): string
- {
- return $this->operator;
- }
-
- public function getValue(): ?string
- {
- return $this->value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
- }
-
- public function __toString(): string
- {
- $attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute;
-
- return 'exists' === $this->operator
- ? sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute)
- : sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php
deleted file mode 100644
index 1efb467..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php
+++ /dev/null
@@ -1,57 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a "." node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class ClassNode extends AbstractNode
-{
- private $selector;
- private $name;
-
- public function __construct(NodeInterface $selector, string $name)
- {
- $this->selector = $selector;
- $this->name = $name;
- }
-
- public function getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getName(): string
- {
- return $this->name;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
- }
-
- public function __toString(): string
- {
- return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
deleted file mode 100644
index 468b02a..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
+++ /dev/null
@@ -1,66 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a combined node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class CombinedSelectorNode extends AbstractNode
-{
- private $selector;
- private $combinator;
- private $subSelector;
-
- public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector)
- {
- $this->selector = $selector;
- $this->combinator = $combinator;
- $this->subSelector = $subSelector;
- }
-
- public function getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getCombinator(): string
- {
- return $this->combinator;
- }
-
- public function getSubSelector(): NodeInterface
- {
- return $this->subSelector;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
- }
-
- public function __toString(): string
- {
- $combinator = ' ' === $this->combinator ? '' : $this->combinator;
-
- return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php
deleted file mode 100644
index 72851c0..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php
+++ /dev/null
@@ -1,59 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a "|" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class ElementNode extends AbstractNode
-{
- private $namespace;
- private $element;
-
- public function __construct(?string $namespace = null, ?string $element = null)
- {
- $this->namespace = $namespace;
- $this->element = $element;
- }
-
- public function getNamespace(): ?string
- {
- return $this->namespace;
- }
-
- public function getElement(): ?string
- {
- return $this->element;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return new Specificity(0, 0, $this->element ? 1 : 0);
- }
-
- public function __toString(): string
- {
- $element = $this->element ?: '*';
-
- return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php
deleted file mode 100644
index 66626c8..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php
+++ /dev/null
@@ -1,76 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-/**
- * Represents a ":()" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class FunctionNode extends AbstractNode
-{
- private $selector;
- private $name;
- private $arguments;
-
- /**
- * @param Token[] $arguments
- */
- public function __construct(NodeInterface $selector, string $name, array $arguments = [])
- {
- $this->selector = $selector;
- $this->name = strtolower($name);
- $this->arguments = $arguments;
- }
-
- public function getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getName(): string
- {
- return $this->name;
- }
-
- /**
- * @return Token[]
- */
- public function getArguments(): array
- {
- return $this->arguments;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
- }
-
- public function __toString(): string
- {
- $arguments = implode(', ', array_map(function (Token $token) {
- return "'".$token->getValue()."'";
- }, $this->arguments));
-
- return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : '');
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php
deleted file mode 100644
index 366bc54..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php
+++ /dev/null
@@ -1,57 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a "#" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class HashNode extends AbstractNode
-{
- private $selector;
- private $id;
-
- public function __construct(NodeInterface $selector, string $id)
- {
- $this->selector = $selector;
- $this->id = $id;
- }
-
- public function getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getId(): string
- {
- return $this->id;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
- }
-
- public function __toString(): string
- {
- return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php
deleted file mode 100644
index abead95..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php
+++ /dev/null
@@ -1,57 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a ":not()" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class NegationNode extends AbstractNode
-{
- private $selector;
- private $subSelector;
-
- public function __construct(NodeInterface $selector, NodeInterface $subSelector)
- {
- $this->selector = $selector;
- $this->subSelector = $subSelector;
- }
-
- public function getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getSubSelector(): NodeInterface
- {
- return $this->subSelector;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
- }
-
- public function __toString(): string
- {
- return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php
deleted file mode 100644
index 41d22b5..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php
+++ /dev/null
@@ -1,31 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Interface for nodes.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-interface NodeInterface
-{
- public function getNodeName(): string;
-
- public function getSpecificity(): Specificity;
-
- public function __toString(): string;
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php
deleted file mode 100644
index 0f4c835..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php
+++ /dev/null
@@ -1,57 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a ":" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class PseudoNode extends AbstractNode
-{
- private $selector;
- private $identifier;
-
- public function __construct(NodeInterface $selector, string $identifier)
- {
- $this->selector = $selector;
- $this->identifier = strtolower($identifier);
- }
-
- public function getSelector(): NodeInterface
- {
- return $this->selector;
- }
-
- public function getIdentifier(): string
- {
- return $this->identifier;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
- }
-
- public function __toString(): string
- {
- return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php
deleted file mode 100644
index d0988d8..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php
+++ /dev/null
@@ -1,57 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a "(::|:)" node.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class SelectorNode extends AbstractNode
-{
- private $tree;
- private $pseudoElement;
-
- public function __construct(NodeInterface $tree, ?string $pseudoElement = null)
- {
- $this->tree = $tree;
- $this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
- }
-
- public function getTree(): NodeInterface
- {
- return $this->tree;
- }
-
- public function getPseudoElement(): ?string
- {
- return $this->pseudoElement;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getSpecificity(): Specificity
- {
- return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
- }
-
- public function __toString(): string
- {
- return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : '');
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php
deleted file mode 100644
index fdfdb67..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php
+++ /dev/null
@@ -1,73 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-
-/**
- * Represents a node specificity.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @see http://www.w3.org/TR/selectors/#specificity
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class Specificity
-{
- public const A_FACTOR = 100;
- public const B_FACTOR = 10;
- public const C_FACTOR = 1;
-
- private $a;
- private $b;
- private $c;
-
- public function __construct(int $a, int $b, int $c)
- {
- $this->a = $a;
- $this->b = $b;
- $this->c = $c;
- }
-
- public function plus(self $specificity): self
- {
- return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
- }
-
- public function getValue(): int
- {
- return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
- }
-
- /**
- * Returns -1 if the object specificity is lower than the argument,
- * 0 if they are equal, and 1 if the argument is lower.
- */
- public function compareTo(self $specificity): int
- {
- if ($this->a !== $specificity->a) {
- return $this->a > $specificity->a ? 1 : -1;
- }
-
- if ($this->b !== $specificity->b) {
- return $this->b > $specificity->b ? 1 : -1;
- }
-
- if ($this->c !== $specificity->c) {
- return $this->c > $specificity->c ? 1 : -1;
- }
-
- return 0;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
deleted file mode 100644
index 1164047..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
+++ /dev/null
@@ -1,48 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector comment handler.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class CommentHandler implements HandlerInterface
-{
- /**
- * {@inheritdoc}
- */
- public function handle(Reader $reader, TokenStream $stream): bool
- {
- if ('/*' !== $reader->getSubstring(2)) {
- return false;
- }
-
- $offset = $reader->getOffset('*/');
-
- if (false === $offset) {
- $reader->moveToEnd();
- } else {
- $reader->moveForward($offset + 2);
- }
-
- return true;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
deleted file mode 100644
index 8f59a56..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector handler interface.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-interface HandlerInterface
-{
- public function handle(Reader $reader, TokenStream $stream): bool;
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
deleted file mode 100644
index a739fc7..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
+++ /dev/null
@@ -1,58 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector comment handler.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class HashHandler implements HandlerInterface
-{
- private $patterns;
- private $escaping;
-
- public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
- {
- $this->patterns = $patterns;
- $this->escaping = $escaping;
- }
-
- /**
- * {@inheritdoc}
- */
- public function handle(Reader $reader, TokenStream $stream): bool
- {
- $match = $reader->findPattern($this->patterns->getHashPattern());
-
- if (!$match) {
- return false;
- }
-
- $value = $this->escaping->escapeUnicode($match[1]);
- $stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition()));
- $reader->moveForward(\strlen($match[0]));
-
- return true;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
deleted file mode 100644
index 56e4e23..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
+++ /dev/null
@@ -1,58 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector comment handler.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class IdentifierHandler implements HandlerInterface
-{
- private $patterns;
- private $escaping;
-
- public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
- {
- $this->patterns = $patterns;
- $this->escaping = $escaping;
- }
-
- /**
- * {@inheritdoc}
- */
- public function handle(Reader $reader, TokenStream $stream): bool
- {
- $match = $reader->findPattern($this->patterns->getIdentifierPattern());
-
- if (!$match) {
- return false;
- }
-
- $value = $this->escaping->escapeUnicode($match[0]);
- $stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition()));
- $reader->moveForward(\strlen($match[0]));
-
- return true;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
deleted file mode 100644
index 435f44c..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
+++ /dev/null
@@ -1,54 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector comment handler.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class NumberHandler implements HandlerInterface
-{
- private $patterns;
-
- public function __construct(TokenizerPatterns $patterns)
- {
- $this->patterns = $patterns;
- }
-
- /**
- * {@inheritdoc}
- */
- public function handle(Reader $reader, TokenStream $stream): bool
- {
- $match = $reader->findPattern($this->patterns->getNumberPattern());
-
- if (!$match) {
- return false;
- }
-
- $stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition()));
- $reader->moveForward(\strlen($match[0]));
-
- return true;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
deleted file mode 100644
index caf70c4..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
+++ /dev/null
@@ -1,77 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\InternalErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector comment handler.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class StringHandler implements HandlerInterface
-{
- private $patterns;
- private $escaping;
-
- public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
- {
- $this->patterns = $patterns;
- $this->escaping = $escaping;
- }
-
- /**
- * {@inheritdoc}
- */
- public function handle(Reader $reader, TokenStream $stream): bool
- {
- $quote = $reader->getSubstring(1);
-
- if (!\in_array($quote, ["'", '"'])) {
- return false;
- }
-
- $reader->moveForward(1);
- $match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote));
-
- if (!$match) {
- throw new InternalErrorException(sprintf('Should have found at least an empty match at %d.', $reader->getPosition()));
- }
-
- // check unclosed strings
- if (\strlen($match[0]) === $reader->getRemainingLength()) {
- throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
- }
-
- // check quotes pairs validity
- if ($quote !== $reader->getSubstring(1, \strlen($match[0]))) {
- throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
- }
-
- $string = $this->escaping->escapeUnicodeAndNewLine($match[0]);
- $stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition()));
- $reader->moveForward(\strlen($match[0]) + 1);
-
- return true;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
deleted file mode 100644
index ad93cca..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector whitespace handler.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class WhitespaceHandler implements HandlerInterface
-{
- /**
- * {@inheritdoc}
- */
- public function handle(Reader $reader, TokenStream $stream): bool
- {
- $match = $reader->findPattern('~^[ \t\r\n\f]+~');
-
- if (false === $match) {
- return false;
- }
-
- $stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition()));
- $reader->moveForward(\strlen($match[0]));
-
- return true;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php
deleted file mode 100644
index 09d44c5..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php
+++ /dev/null
@@ -1,353 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-use PoweredCache\Dependencies\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.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class Parser implements ParserInterface
-{
- private $tokenizer;
-
- public function __construct(?Tokenizer $tokenizer = null)
- {
- $this->tokenizer = $tokenizer ?? new Tokenizer();
- }
-
- /**
- * {@inheritdoc}
- */
- public function parse(string $source): array
- {
- $reader = new Reader($source);
- $stream = $this->tokenizer->tokenize($reader);
-
- return $this->parseSelectorList($stream);
- }
-
- /**
- * Parses the arguments for ":nth-child()" and friends.
- *
- * @param Token[] $tokens
- *
- * @throws SyntaxErrorException
- */
- public static function parseSeries(array $tokens): array
- {
- foreach ($tokens as $token) {
- if ($token->isString()) {
- throw SyntaxErrorException::stringAsFunctionArgument();
- }
- }
-
- $joined = trim(implode('', array_map(function (Token $token) {
- return $token->getValue();
- }, $tokens)));
-
- $int = function ($string) {
- if (!is_numeric($string)) {
- throw SyntaxErrorException::stringAsFunctionArgument();
- }
-
- return (int) $string;
- };
-
- switch (true) {
- case 'odd' === $joined:
- return [2, 1];
- case 'even' === $joined:
- return [2, 0];
- case 'n' === $joined:
- return [1, 0];
- case !str_contains($joined, 'n'):
- return [0, $int($joined)];
- }
-
- $split = explode('n', $joined);
- $first = $split[0] ?? null;
-
- return [
- $first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1,
- isset($split[1]) && $split[1] ? $int($split[1]) : 0,
- ];
- }
-
- private function parseSelectorList(TokenStream $stream): array
- {
- $stream->skipWhitespace();
- $selectors = [];
-
- while (true) {
- $selectors[] = $this->parserSelectorNode($stream);
-
- if ($stream->getPeek()->isDelimiter([','])) {
- $stream->getNext();
- $stream->skipWhitespace();
- } else {
- break;
- }
- }
-
- return $selectors;
- }
-
- private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
- {
- [$result, $pseudoElement] = $this->parseSimpleSelector($stream);
-
- while (true) {
- $stream->skipWhitespace();
- $peek = $stream->getPeek();
-
- if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
- break;
- }
-
- if (null !== $pseudoElement) {
- throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
- }
-
- if ($peek->isDelimiter(['+', '>', '~'])) {
- $combinator = $stream->getNext()->getValue();
- $stream->skipWhitespace();
- } else {
- $combinator = ' ';
- }
-
- [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
- $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
- }
-
- return new Node\SelectorNode($result, $pseudoElement);
- }
-
- /**
- * Parses next simple node (hash, class, pseudo, negation).
- *
- * @throws SyntaxErrorException
- */
- private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = 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([',', '+', '>', '~'])
- || ($insideNegation && $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);
-
- continue;
- }
-
- $stream->getNext();
- $stream->skipWhitespace();
-
- if ('not' === strtolower($identifier)) {
- if ($insideNegation) {
- throw SyntaxErrorException::nestedNot();
- }
-
- [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, 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);
- } 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 (empty($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];
- }
-
- private function parseElementNode(TokenStream $stream): Node\ElementNode
- {
- $peek = $stream->getPeek();
-
- if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
- if ($peek->isIdentifier()) {
- $namespace = $stream->getNext()->getValue();
- } else {
- $stream->getNext();
- $namespace = null;
- }
-
- if ($stream->getPeek()->isDelimiter(['|'])) {
- $stream->getNext();
- $element = $stream->getNextIdentifierOrStar();
- } else {
- $element = $namespace;
- $namespace = null;
- }
- } else {
- $element = $namespace = null;
- }
-
- return new Node\ElementNode($namespace, $element);
- }
-
- private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode
- {
- $stream->skipWhitespace();
- $attribute = $stream->getNextIdentifierOrStar();
-
- if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
- throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
- }
-
- if ($stream->getPeek()->isDelimiter(['|'])) {
- $stream->getNext();
-
- if ($stream->getPeek()->isDelimiter(['='])) {
- $namespace = null;
- $stream->getNext();
- $operator = '|=';
- } else {
- $namespace = $attribute;
- $attribute = $stream->getNextIdentifier();
- $operator = null;
- }
- } else {
- $namespace = $operator = null;
- }
-
- if (null === $operator) {
- $stream->skipWhitespace();
- $next = $stream->getNext();
-
- if ($next->isDelimiter([']'])) {
- return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
- } elseif ($next->isDelimiter(['='])) {
- $operator = '=';
- } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!'])
- && $stream->getPeek()->isDelimiter(['='])
- ) {
- $operator = $next->getValue().'=';
- $stream->getNext();
- } else {
- throw SyntaxErrorException::unexpectedToken('operator', $next);
- }
- }
-
- $stream->skipWhitespace();
- $value = $stream->getNext();
-
- if ($value->isNumber()) {
- // if the value is a number, it's casted into a string
- $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
- }
-
- if (!($value->isIdentifier() || $value->isString())) {
- throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
- }
-
- $stream->skipWhitespace();
- $next = $stream->getNext();
-
- if (!$next->isDelimiter([']'])) {
- throw SyntaxErrorException::unexpectedToken('"]"', $next);
- }
-
- return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php
deleted file mode 100644
index df808e2..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-
-/**
- * CSS selector parser interface.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-interface ParserInterface
-{
- /**
- * Parses given selector source into an array of tokens.
- *
- * @return SelectorNode[]
- */
- public function parse(string $source): array;
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php
deleted file mode 100644
index 2bef8ae..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php
+++ /dev/null
@@ -1,86 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
-
-/**
- * CSS selector reader.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class Reader
-{
- private $source;
- private $length;
- private $position = 0;
-
- public function __construct(string $source)
- {
- $this->source = $source;
- $this->length = \strlen($source);
- }
-
- public function isEOF(): bool
- {
- return $this->position >= $this->length;
- }
-
- public function getPosition(): int
- {
- return $this->position;
- }
-
- public function getRemainingLength(): int
- {
- return $this->length - $this->position;
- }
-
- public function getSubstring(int $length, int $offset = 0): string
- {
- return substr($this->source, $this->position + $offset, $length);
- }
-
- public function getOffset(string $string)
- {
- $position = strpos($this->source, $string, $this->position);
-
- return false === $position ? false : $position - $this->position;
- }
-
- /**
- * @return array|false
- */
- public function findPattern(string $pattern)
- {
- $source = substr($this->source, $this->position);
-
- if (preg_match($pattern, $source, $matches)) {
- return $matches;
- }
-
- return false;
- }
-
- public function moveForward(int $length)
- {
- $this->position += $length;
- }
-
- public function moveToEnd()
- {
- $this->position = $this->length;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
deleted file mode 100644
index a34a122..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
+++ /dev/null
@@ -1,51 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
-
-/**
- * CSS selector class parser shortcut.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class ClassParser implements ParserInterface
-{
- /**
- * {@inheritdoc}
- */
- public function parse(string $source): array
- {
- // Matches an optional namespace, optional element, and required class
- // $source = 'test|input.ab6bd_field';
- // $matches = array (size=4)
- // 0 => string 'test|input.ab6bd_field' (length=22)
- // 1 => string 'test' (length=4)
- // 2 => string 'input' (length=5)
- // 3 => string 'ab6bd_field' (length=11)
- if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) {
- return [
- new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
- ];
- }
-
- return [];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
deleted file mode 100644
index 2d07857..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
-
-/**
- * CSS selector element parser shortcut.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class ElementParser implements ParserInterface
-{
- /**
- * {@inheritdoc}
- */
- public function parse(string $source): array
- {
- // Matches an optional namespace, required element or `*`
- // $source = 'testns|testel';
- // $matches = array (size=3)
- // 0 => string 'testns|testel' (length=13)
- // 1 => string 'testns' (length=6)
- // 2 => string 'testel' (length=6)
- if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) {
- return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))];
- }
-
- return [];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
deleted file mode 100644
index 68f8a87..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
-
-/**
- * CSS selector class parser shortcut.
- *
- * This shortcut ensure compatibility with previous version.
- * - The parser fails to parse an empty string.
- * - In the previous version, an empty string matches each tags.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class EmptyStringParser implements ParserInterface
-{
- /**
- * {@inheritdoc}
- */
- public function parse(string $source): array
- {
- // Matches an empty string
- if ('' == $source) {
- return [new SelectorNode(new ElementNode(null, '*'))];
- }
-
- return [];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
deleted file mode 100644
index 6f08f5f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
+++ /dev/null
@@ -1,51 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\HashNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
-
-/**
- * CSS selector hash parser shortcut.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class HashParser implements ParserInterface
-{
- /**
- * {@inheritdoc}
- */
- public function parse(string $source): array
- {
- // Matches an optional namespace, optional element, and required id
- // $source = 'test|input#ab6bd_field';
- // $matches = array (size=4)
- // 0 => string 'test|input#ab6bd_field' (length=22)
- // 1 => string 'test' (length=4)
- // 2 => string 'input' (length=5)
- // 3 => string 'ab6bd_field' (length=11)
- if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) {
- return [
- new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
- ];
- }
-
- return [];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php
deleted file mode 100644
index ed43632..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php
+++ /dev/null
@@ -1,111 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
-
-/**
- * CSS selector token.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class Token
-{
- public const TYPE_FILE_END = 'eof';
- public const TYPE_DELIMITER = 'delimiter';
- public const TYPE_WHITESPACE = 'whitespace';
- public const TYPE_IDENTIFIER = 'identifier';
- public const TYPE_HASH = 'hash';
- public const TYPE_NUMBER = 'number';
- public const TYPE_STRING = 'string';
-
- private $type;
- private $value;
- private $position;
-
- public function __construct(?string $type, ?string $value, ?int $position)
- {
- $this->type = $type;
- $this->value = $value;
- $this->position = $position;
- }
-
- public function getType(): ?int
- {
- return $this->type;
- }
-
- public function getValue(): ?string
- {
- return $this->value;
- }
-
- public function getPosition(): ?int
- {
- return $this->position;
- }
-
- public function isFileEnd(): bool
- {
- return self::TYPE_FILE_END === $this->type;
- }
-
- public function isDelimiter(array $values = []): bool
- {
- if (self::TYPE_DELIMITER !== $this->type) {
- return false;
- }
-
- if (empty($values)) {
- return true;
- }
-
- return \in_array($this->value, $values);
- }
-
- public function isWhitespace(): bool
- {
- return self::TYPE_WHITESPACE === $this->type;
- }
-
- public function isIdentifier(): bool
- {
- return self::TYPE_IDENTIFIER === $this->type;
- }
-
- public function isHash(): bool
- {
- return self::TYPE_HASH === $this->type;
- }
-
- public function isNumber(): bool
- {
- return self::TYPE_NUMBER === $this->type;
- }
-
- public function isString(): bool
- {
- return self::TYPE_STRING === $this->type;
- }
-
- public function __toString(): string
- {
- if ($this->value) {
- return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position);
- }
-
- return sprintf('<%s at %s>', $this->type, $this->position);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php
deleted file mode 100644
index 56c5f55..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php
+++ /dev/null
@@ -1,167 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\InternalErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-
-/**
- * CSS selector token stream.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class TokenStream
-{
- /**
- * @var Token[]
- */
- private $tokens = [];
-
- /**
- * @var Token[]
- */
- private $used = [];
-
- /**
- * @var int
- */
- private $cursor = 0;
-
- /**
- * @var Token|null
- */
- private $peeked;
-
- /**
- * @var bool
- */
- private $peeking = false;
-
- /**
- * Pushes a token.
- *
- * @return $this
- */
- public function push(Token $token): self
- {
- $this->tokens[] = $token;
-
- return $this;
- }
-
- /**
- * Freezes stream.
- *
- * @return $this
- */
- public function freeze(): self
- {
- return $this;
- }
-
- /**
- * Returns next token.
- *
- * @throws InternalErrorException If there is no more token
- */
- public function getNext(): Token
- {
- if ($this->peeking) {
- $this->peeking = false;
- $this->used[] = $this->peeked;
-
- return $this->peeked;
- }
-
- if (!isset($this->tokens[$this->cursor])) {
- throw new InternalErrorException('Unexpected token stream end.');
- }
-
- return $this->tokens[$this->cursor++];
- }
-
- /**
- * Returns peeked token.
- */
- public function getPeek(): Token
- {
- if (!$this->peeking) {
- $this->peeked = $this->getNext();
- $this->peeking = true;
- }
-
- return $this->peeked;
- }
-
- /**
- * Returns used tokens.
- *
- * @return Token[]
- */
- public function getUsed(): array
- {
- return $this->used;
- }
-
- /**
- * Returns next identifier token.
- *
- * @throws SyntaxErrorException If next token is not an identifier
- */
- public function getNextIdentifier(): string
- {
- $next = $this->getNext();
-
- if (!$next->isIdentifier()) {
- throw SyntaxErrorException::unexpectedToken('identifier', $next);
- }
-
- return $next->getValue();
- }
-
- /**
- * Returns next identifier or null if star delimiter token is found.
- *
- * @throws SyntaxErrorException If next token is not an identifier or a star delimiter
- */
- public function getNextIdentifierOrStar(): ?string
- {
- $next = $this->getNext();
-
- if ($next->isIdentifier()) {
- return $next->getValue();
- }
-
- if ($next->isDelimiter(['*'])) {
- return null;
- }
-
- throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next);
- }
-
- /**
- * Skips next whitespace if any.
- */
- public function skipWhitespace()
- {
- $peek = $this->getPeek();
-
- if ($peek->isWhitespace()) {
- $this->getNext();
- }
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
deleted file mode 100644
index aa5cb8a..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
+++ /dev/null
@@ -1,73 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * CSS selector tokenizer.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class Tokenizer
-{
- /**
- * @var Handler\HandlerInterface[]
- */
- private $handlers;
-
- public function __construct()
- {
- $patterns = new TokenizerPatterns();
- $escaping = new TokenizerEscaping($patterns);
-
- $this->handlers = [
- new Handler\WhitespaceHandler(),
- new Handler\IdentifierHandler($patterns, $escaping),
- new Handler\HashHandler($patterns, $escaping),
- new Handler\StringHandler($patterns, $escaping),
- new Handler\NumberHandler($patterns),
- new Handler\CommentHandler(),
- ];
- }
-
- /**
- * Tokenize selector source code.
- */
- public function tokenize(Reader $reader): TokenStream
- {
- $stream = new TokenStream();
-
- while (!$reader->isEOF()) {
- foreach ($this->handlers as $handler) {
- if ($handler->handle($reader, $stream)) {
- continue 2;
- }
- }
-
- $stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition()));
- $reader->moveForward(1);
- }
-
- return $stream
- ->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition()))
- ->freeze();
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
deleted file mode 100644
index fa319c5..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
+++ /dev/null
@@ -1,65 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer;
-
-/**
- * CSS selector tokenizer escaping applier.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class TokenizerEscaping
-{
- private $patterns;
-
- public function __construct(TokenizerPatterns $patterns)
- {
- $this->patterns = $patterns;
- }
-
- public function escapeUnicode(string $value): string
- {
- $value = $this->replaceUnicodeSequences($value);
-
- return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
- }
-
- public function escapeUnicodeAndNewLine(string $value): string
- {
- $value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);
-
- return $this->escapeUnicode($value);
- }
-
- private function replaceUnicodeSequences(string $value): string
- {
- return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
- $c = hexdec($match[1]);
-
- if (0x80 > $c %= 0x200000) {
- return \chr($c);
- }
- if (0x800 > $c) {
- return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
- }
- if (0x10000 > $c) {
- return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
- }
-
- return '';
- }, $value);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
deleted file mode 100644
index e714a8e..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
+++ /dev/null
@@ -1,89 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer;
-
-/**
- * CSS selector tokenizer patterns builder.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class TokenizerPatterns
-{
- private $unicodeEscapePattern;
- private $simpleEscapePattern;
- private $newLineEscapePattern;
- private $escapePattern;
- private $stringEscapePattern;
- private $nonAsciiPattern;
- private $nmCharPattern;
- private $nmStartPattern;
- private $identifierPattern;
- private $hashPattern;
- private $numberPattern;
- private $quotedStringPattern;
-
- public function __construct()
- {
- $this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?';
- $this->simpleEscapePattern = '\\\\(.)';
- $this->newLineEscapePattern = '\\\\(?:\n|\r\n|\r|\f)';
- $this->escapePattern = $this->unicodeEscapePattern.'|\\\\[^\n\r\f0-9a-f]';
- $this->stringEscapePattern = $this->newLineEscapePattern.'|'.$this->escapePattern;
- $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->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
- $this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
- $this->quotedStringPattern = '([^\n\r\f\\\\%s]|'.$this->stringEscapePattern.')*';
- }
-
- public function getNewLineEscapePattern(): string
- {
- return '~'.$this->newLineEscapePattern.'~';
- }
-
- public function getSimpleEscapePattern(): string
- {
- return '~'.$this->simpleEscapePattern.'~';
- }
-
- public function getUnicodeEscapePattern(): string
- {
- return '~'.$this->unicodeEscapePattern.'~i';
- }
-
- public function getIdentifierPattern(): string
- {
- return '~^'.$this->identifierPattern.'~i';
- }
-
- public function getHashPattern(): string
- {
- return '~^'.$this->hashPattern.'~i';
- }
-
- public function getNumberPattern(): string
- {
- return '~^'.$this->numberPattern.'~';
- }
-
- public function getQuotedStringPattern(string $quote): string
- {
- return '~^'.sprintf($this->quotedStringPattern, $quote).'~i';
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/README.md b/includes/classes/Dependencies/Symfony/Component/CssSelector/README.md
deleted file mode 100644
index ede4a3a..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-CssSelector Component
-=====================
-
-The CssSelector component converts CSS selectors to XPath expressions.
-
-Resources
----------
-
- * [Documentation](https://symfony.com/doc/current/components/css_selector.html)
- * [Contributing](https://symfony.com/doc/current/contributing/index.html)
- * [Report issues](https://github.com/symfony/symfony/issues) and
- [send Pull Requests](https://github.com/symfony/symfony/pulls)
- in the [main Symfony repository](https://github.com/symfony/symfony)
-
-Credits
--------
-
-This component is a port of the Python cssselect library
-[v0.7.1](https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1),
-which is distributed under the BSD license.
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
deleted file mode 100644
index d42ce90..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
+++ /dev/null
@@ -1,83 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\CssSelectorConverter;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ParseException;
-
-class CssSelectorConverterTest extends TestCase
-{
- public function testCssToXPath()
- {
- $converter = new CssSelectorConverter();
-
- $this->assertEquals('descendant-or-self::*', $converter->toXPath(''));
- $this->assertEquals('descendant-or-self::h1', $converter->toXPath('h1'));
- $this->assertEquals("descendant-or-self::h1[@id = 'foo']", $converter->toXPath('h1#foo'));
- $this->assertEquals("descendant-or-self::h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", $converter->toXPath('h1.foo'));
- $this->assertEquals('descendant-or-self::foo:h1', $converter->toXPath('foo|h1'));
- $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
-
- // Test the cache layer
- $converter = new CssSelectorConverter();
- $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
- }
-
- public function testCssToXPathXml()
- {
- $converter = new CssSelectorConverter(false);
-
- $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
-
- $converter = new CssSelectorConverter(false);
- // Test the cache layer
- $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
- }
-
- public function testParseExceptions()
- {
- $this->expectException(ParseException::class);
- $this->expectExceptionMessage('Expected identifier, but found.');
- $converter = new CssSelectorConverter();
- $converter->toXPath('h1:');
- }
-
- /** @dataProvider getCssToXPathWithoutPrefixTestData */
- public function testCssToXPathWithoutPrefix($css, $xpath)
- {
- $converter = new CssSelectorConverter();
-
- $this->assertEquals($xpath, $converter->toXPath($css, ''), '->parse() parses an input string and returns a node');
- }
-
- public static function getCssToXPathWithoutPrefixTestData()
- {
- return [
- ['h1', 'h1'],
- ['foo|h1', 'foo:h1'],
- ['h1, h2, h3', 'h1 | h2 | h3'],
- ['h1:nth-child(3n+1)', "*/*[(name() = 'h1') and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"],
- ['h1 > p', 'h1/p'],
- ['h1#foo', "h1[@id = 'foo']"],
- ['h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ['h1[class*="foo bar"]', "h1[@class and contains(@class, 'foo bar')]"],
- ['h1[foo|class*="foo bar"]', "h1[@foo:class and contains(@foo:class, 'foo bar')]"],
- ['h1[class]', 'h1[@class]'],
- ['h1 .foo', "h1/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ['h1 #foo', "h1/descendant-or-self::*/*[@id = 'foo']"],
- ['h1 [class*=foo]', "h1/descendant-or-self::*/*[@class and contains(@class, 'foo')]"],
- ['div>.foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ['div > .foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
deleted file mode 100644
index 99460ae..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NodeInterface;
-
-abstract class AbstractNodeTestCase extends TestCase
-{
- /** @dataProvider getToStringConversionTestData */
- public function testToStringConversion(NodeInterface $node, $representation)
- {
- $this->assertEquals($representation, (string) $node);
- }
-
- /** @dataProvider getSpecificityValueTestData */
- public function testSpecificityValue(NodeInterface $node, $value)
- {
- $this->assertEquals($value, $node->getSpecificity()->getValue());
- }
-
- abstract public static function getToStringConversionTestData();
-
- abstract public static function getSpecificityValueTestData();
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
deleted file mode 100644
index 5115605..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\AttributeNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class AttributeNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 'Powered_Cache_Attribute[Element[*][attribute]]'],
- [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][attribute $= 'value']]"],
- [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][namespace|attribute $= 'value']]"],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 10],
- [new AttributeNode(new ElementNode(null, 'element'), null, 'attribute', 'exists', null), 11],
- [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), 10],
- [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
deleted file mode 100644
index ae43a62..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class ClassNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new ClassNode(new ElementNode(), 'class'), 'Class[Element[*].class]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new ClassNode(new ElementNode(), 'class'), 10],
- [new ClassNode(new ElementNode(null, 'element'), 'class'), 11],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
deleted file mode 100644
index d9b2a38..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
+++ /dev/null
@@ -1,35 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\CombinedSelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class CombinedSelectorNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 'CombinedSelector[Element[*] > Element[*]]'],
- [new CombinedSelectorNode(new ElementNode(), ' ', new ElementNode()), 'CombinedSelector[Element[*] Element[*]]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 0],
- [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode()), 1],
- [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode(null, 'element')), 2],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
deleted file mode 100644
index b3ef2b2..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
+++ /dev/null
@@ -1,35 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class ElementNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new ElementNode(), 'Element[*]'],
- [new ElementNode(null, 'element'), 'Element[element]'],
- [new ElementNode('namespace', 'element'), 'Element[namespace|element]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new ElementNode(), 0],
- [new ElementNode(null, 'element'), 1],
- [new ElementNode('namespace', 'element'), 1],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
deleted file mode 100644
index f99a66b..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-class FunctionNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new FunctionNode(new ElementNode(), 'function'), 'Function[Element[*]:function()]'],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_IDENTIFIER, 'value', 0),
- ]), "Function[Element[*]:function(['value'])]"],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_STRING, 'value1', 0),
- new Token(Token::TYPE_NUMBER, 'value2', 0),
- ]), "Function[Element[*]:function(['value1', 'value2'])]"],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new FunctionNode(new ElementNode(), 'function'), 10],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_IDENTIFIER, 'value', 0),
- ]), 10],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_STRING, 'value1', 0),
- new Token(Token::TYPE_NUMBER, 'value2', 0),
- ]), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
deleted file mode 100644
index d43aac1..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\HashNode;
-
-class HashNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new HashNode(new ElementNode(), 'id'), 'Hash[Element[*]#id]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new HashNode(new ElementNode(), 'id'), 100],
- [new HashNode(new ElementNode(null, 'id'), 'class'), 101],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
deleted file mode 100644
index 9aafe8f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NegationNode;
-
-class NegationNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 'Negation[Element[*]:not(Class[Element[*].class])]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
deleted file mode 100644
index cf13881..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\PseudoNode;
-
-class PseudoNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new PseudoNode(new ElementNode(), 'pseudo'), 'Pseudo[Element[*]:pseudo]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new PseudoNode(new ElementNode(), 'pseudo'), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
deleted file mode 100644
index 142b104..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-
-class SelectorNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new SelectorNode(new ElementNode()), 'Selector[Element[*]]'],
- [new SelectorNode(new ElementNode(), 'pseudo'), 'Selector[Element[*]::pseudo]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new SelectorNode(new ElementNode()), 0],
- [new SelectorNode(new ElementNode(), 'pseudo'), 1],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
deleted file mode 100644
index 790f8c1..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\Specificity;
-
-class SpecificityTest extends TestCase
-{
- /** @dataProvider getValueTestData */
- public function testValue(Specificity $specificity, $value)
- {
- $this->assertEquals($value, $specificity->getValue());
- }
-
- /** @dataProvider getValueTestData */
- public function testPlusValue(Specificity $specificity, $value)
- {
- $this->assertEquals($value + 123, $specificity->plus(new Specificity(1, 2, 3))->getValue());
- }
-
- public static function getValueTestData()
- {
- return [
- [new Specificity(0, 0, 0), 0],
- [new Specificity(0, 0, 2), 2],
- [new Specificity(0, 3, 0), 30],
- [new Specificity(4, 0, 0), 400],
- [new Specificity(4, 3, 2), 432],
- ];
- }
-
- /** @dataProvider getCompareTestData */
- public function testCompareTo(Specificity $a, Specificity $b, $result)
- {
- $this->assertEquals($result, $a->compareTo($b));
- }
-
- public static function getCompareTestData()
- {
- return [
- [new Specificity(0, 0, 0), new Specificity(0, 0, 0), 0],
- [new Specificity(0, 0, 1), new Specificity(0, 0, 1), 0],
- [new Specificity(0, 0, 2), new Specificity(0, 0, 1), 1],
- [new Specificity(0, 0, 2), new Specificity(0, 0, 3), -1],
- [new Specificity(0, 4, 0), new Specificity(0, 4, 0), 0],
- [new Specificity(0, 6, 0), new Specificity(0, 5, 11), 1],
- [new Specificity(0, 7, 0), new Specificity(0, 8, 0), -1],
- [new Specificity(9, 0, 0), new Specificity(9, 0, 0), 0],
- [new Specificity(11, 0, 0), new Specificity(10, 11, 0), 1],
- [new Specificity(12, 11, 0), new Specificity(13, 0, 0), -1],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
deleted file mode 100644
index b46f2f7..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
+++ /dev/null
@@ -1,70 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * @author Jean-François Simon
- */
-abstract class AbstractHandlerTestCase extends TestCase
-{
- /** @dataProvider getHandleValueTestData */
- public function testHandleValue($value, Token $expectedToken, $remainingContent)
- {
- $reader = new Reader($value);
- $stream = new TokenStream();
-
- $this->assertTrue($this->generateHandler()->handle($reader, $stream));
- $this->assertEquals($expectedToken, $stream->getNext());
- $this->assertRemainingContent($reader, $remainingContent);
- }
-
- /** @dataProvider getDontHandleValueTestData */
- public function testDontHandleValue($value)
- {
- $reader = new Reader($value);
- $stream = new TokenStream();
-
- $this->assertFalse($this->generateHandler()->handle($reader, $stream));
- $this->assertStreamEmpty($stream);
- $this->assertRemainingContent($reader, $value);
- }
-
- abstract public static function getHandleValueTestData();
-
- abstract public static function getDontHandleValueTestData();
-
- abstract protected function generateHandler();
-
- protected function assertStreamEmpty(TokenStream $stream)
- {
- $property = new \ReflectionProperty($stream, 'tokens');
- $property->setAccessible(true);
-
- $this->assertEquals([], $property->getValue($stream));
- }
-
- protected function assertRemainingContent(Reader $reader, $remainingContent)
- {
- if ('' === $remainingContent) {
- $this->assertEquals(0, $reader->getRemainingLength());
- $this->assertTrue($reader->isEOF());
- } else {
- $this->assertEquals(\strlen($remainingContent), $reader->getRemainingLength());
- $this->assertEquals(0, $reader->getOffset($remainingContent));
- }
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
deleted file mode 100644
index 459d8de..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\CommentHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-class CommentHandlerTest extends AbstractHandlerTestCase
-{
- /** @dataProvider getHandleValueTestData */
- public function testHandleValue($value, Token $unusedArgument, $remainingContent)
- {
- $reader = new Reader($value);
- $stream = new TokenStream();
-
- $this->assertTrue($this->generateHandler()->handle($reader, $stream));
- // comments are ignored (not pushed as token in stream)
- $this->assertStreamEmpty($stream);
- $this->assertRemainingContent($reader, $remainingContent);
- }
-
- public static function getHandleValueTestData()
- {
- return [
- // 2nd argument only exists for inherited method compatibility
- ['/* comment */', new Token(null, null, null), ''],
- ['/* comment */foo', new Token(null, null, null), 'foo'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['>'],
- ['+'],
- [' '],
- ];
- }
-
- protected function generateHandler()
- {
- return new CommentHandler();
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
deleted file mode 100644
index a96c861..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\HashHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class HashHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['#id', new Token(Token::TYPE_HASH, 'id', 0), ''],
- ['#123', new Token(Token::TYPE_HASH, '123', 0), ''],
-
- ['#id.class', new Token(Token::TYPE_HASH, 'id', 0), '.class'],
- ['#id element', new Token(Token::TYPE_HASH, 'id', 0), ' element'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['id'],
- ['123'],
- ['<'],
- ['<'],
- ['#'],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new HashHandler($patterns, new TokenizerEscaping($patterns));
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
deleted file mode 100644
index 1cb9ffe..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\IdentifierHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class IdentifierHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['foo', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ''],
- ['foo|bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '|bar'],
- ['foo.class', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '.class'],
- ['foo[attr]', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '[attr]'],
- ['foo bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ' bar'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['>'],
- ['+'],
- [' '],
- ['*|foo'],
- ['/* comment */'],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new IdentifierHandler($patterns, new TokenizerEscaping($patterns));
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
deleted file mode 100644
index e40b86f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\NumberHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class NumberHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['12', new Token(Token::TYPE_NUMBER, '12', 0), ''],
- ['12.34', new Token(Token::TYPE_NUMBER, '12.34', 0), ''],
- ['+12.34', new Token(Token::TYPE_NUMBER, '+12.34', 0), ''],
- ['-12.34', new Token(Token::TYPE_NUMBER, '-12.34', 0), ''],
-
- ['12 arg', new Token(Token::TYPE_NUMBER, '12', 0), ' arg'],
- ['12]', new Token(Token::TYPE_NUMBER, '12', 0), ']'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['hello'],
- ['>'],
- ['+'],
- [' '],
- ['/* comment */'],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new NumberHandler($patterns);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
deleted file mode 100644
index d00233c..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\StringHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class StringHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['"hello"', new Token(Token::TYPE_STRING, 'hello', 1), ''],
- ['"1"', new Token(Token::TYPE_STRING, '1', 1), ''],
- ['" "', new Token(Token::TYPE_STRING, ' ', 1), ''],
- ['""', new Token(Token::TYPE_STRING, '', 1), ''],
- ["'hello'", new Token(Token::TYPE_STRING, 'hello', 1), ''],
-
- ["'foo'bar", new Token(Token::TYPE_STRING, 'foo', 1), 'bar'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['hello'],
- ['>'],
- ['1'],
- [' '],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new StringHandler($patterns, new TokenizerEscaping($patterns));
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
deleted file mode 100644
index 1cd3e9d..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\WhitespaceHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-class WhitespaceHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- [' ', new Token(Token::TYPE_WHITESPACE, ' ', 0), ''],
- ["\n", new Token(Token::TYPE_WHITESPACE, "\n", 0), ''],
- ["\t", new Token(Token::TYPE_WHITESPACE, "\t", 0), ''],
-
- [' foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), 'foo'],
- [' .foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), '.foo'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['>'],
- ['1'],
- ['a'],
- ];
- }
-
- protected function generateHandler()
- {
- return new WhitespaceHandler();
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
deleted file mode 100644
index a9ef9d6..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
+++ /dev/null
@@ -1,263 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-class ParserTest extends TestCase
-{
- /** @dataProvider getParserTestData */
- public function testParser($source, $representation)
- {
- $parser = new Parser();
-
- $this->assertEquals($representation, array_map(function (SelectorNode $node) {
- return (string) $node->getTree();
- }, $parser->parse($source)));
- }
-
- /** @dataProvider getParserExceptionTestData */
- public function testParserException($source, $message)
- {
- $parser = new Parser();
-
- try {
- $parser->parse($source);
- $this->fail('Parser should throw a SyntaxErrorException.');
- } catch (SyntaxErrorException $e) {
- $this->assertEquals($message, $e->getMessage());
- }
- }
-
- /** @dataProvider getPseudoElementsTestData */
- public function testPseudoElements($source, $element, $pseudo)
- {
- $parser = new Parser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($element, (string) $selector->getTree());
- $this->assertEquals($pseudo, (string) $selector->getPseudoElement());
- }
-
- /** @dataProvider getSpecificityTestData */
- public function testSpecificity($source, $value)
- {
- $parser = new Parser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($value, $selector->getSpecificity()->getValue());
- }
-
- /** @dataProvider getParseSeriesTestData */
- public function testParseSeries($series, $a, $b)
- {
- $parser = new Parser();
- $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
- $this->assertCount(1, $selectors);
-
- /** @var FunctionNode $function */
- $function = $selectors[0]->getTree();
- $this->assertEquals([$a, $b], Parser::parseSeries($function->getArguments()));
- }
-
- /** @dataProvider getParseSeriesExceptionTestData */
- public function testParseSeriesException($series)
- {
- $parser = new Parser();
- $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
- $this->assertCount(1, $selectors);
-
- /** @var FunctionNode $function */
- $function = $selectors[0]->getTree();
- $this->expectException(SyntaxErrorException::class);
- Parser::parseSeries($function->getArguments());
- }
-
- public static function getParserTestData()
- {
- return [
- ['*', ['Element[*]']],
- ['*|*', ['Element[*]']],
- ['*|foo', ['Element[foo]']],
- ['foo|*', ['Element[foo|*]']],
- ['foo|bar', ['Element[foo|bar]']],
- ['#foo#bar', ['Hash[Hash[Element[*]#foo]#bar]']],
- ['div>.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['div> .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['div >.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['div > .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ["div \n> \t \t .foo", ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['div, td.foo, div.bar span', ['Element[div]', 'Class[Element[td].foo]', 'CombinedSelector[Class[Element[div].bar] Element[span]]']],
- ['div > p', ['CombinedSelector[Element[div] > Element[p]]']],
- ['td:first', ['Pseudo[Element[td]:first]']],
- ['td :first', ['CombinedSelector[Element[td] Pseudo[Element[*]:first]]']],
- ['a[name]', ['Powered_Cache_Attribute[Element[a][name]]']],
- ["a[ name\t]", ['Powered_Cache_Attribute[Element[a][name]]']],
- ['a [name]', ['CombinedSelector[Element[a] Powered_Cache_Attribute[Element[*][name]]]']],
- ['[name="foo"]', ["Powered_Cache_Attribute[Element[*][name = 'foo']]"]],
- ["[name='foo[1]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[1]']]"]],
- ["[name='foo[0][bar]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[0][bar]']]"]],
- ['a[rel="include"]', ["Attribute[Element[a][rel = 'include']]"]],
- ['a[rel = include]', ["Attribute[Element[a][rel = 'include']]"]],
- ["a[hreflang |= 'en']", ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
- ['a[hreflang|=en]', ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
- ['div:nth-child(10)', ["Function[Element[div]:nth-child(['10'])]"]],
- [':nth-child(2n+2)', ["Function[Element[*]:nth-child(['2', 'n', '+2'])]"]],
- ['div:nth-of-type(10)', ["Function[Element[div]:nth-of-type(['10'])]"]],
- ['div div:nth-of-type(10) .aclass', ["CombinedSelector[CombinedSelector[Element[div] Function[Element[div]:nth-of-type(['10'])]] Class[Element[*].aclass]]"]],
- ['label:only', ['Pseudo[Element[label]:only]']],
- ['a:lang(fr)', ["Function[Element[a]:lang(['fr'])]"]],
- ['div:contains("foo")', ["Function[Element[div]:contains(['foo'])]"]],
- ['div#foobar', ['Hash[Element[div]#foobar]']],
- ['div:not(div.foo)', ['Negation[Element[div]:not(Class[Element[div].foo])]']],
- ['td ~ th', ['CombinedSelector[Element[td] ~ Element[th]]']],
- ['.foo[data-bar][data-baz=0]', ["Powered_Cache_Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]"]],
- ['div#foo\.bar', ['Hash[Element[div]#foo.bar]']],
- ['div.w-1\/3', ['Class[Element[div].w-1/3]']],
- ['#test\:colon', ['Hash[Element[*]#test:colon]']],
- [".a\xc1b", ["Class[Element[*].a\xc1b]"]],
- // unicode escape: \22 == "
- ['*[aval="\'\22\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"\'\']]']],
- ['*[aval="\'\22 2\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"2\'\']]']],
- // unicode escape: \20 == (space)
- ['*[aval="\'\20 \'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
- ["*[aval=\"'\\20\r\n '\"]", ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
- ];
- }
-
- public static function getParserExceptionTestData()
- {
- return [
- ['attributes(href)/html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
- ['attributes(href)', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
- ['html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '/', 4))->getMessage()],
- [' ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 1))->getMessage()],
- ['div, ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 5))->getMessage()],
- [' , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 1))->getMessage()],
- ['p, , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 3))->getMessage()],
- ['div > ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 6))->getMessage()],
- [' > div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '>', 2))->getMessage()],
- ['foo|#bar', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_HASH, 'bar', 4))->getMessage()],
- ['#.foo', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '#', 0))->getMessage()],
- ['.#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
- [':#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
- ['[*]', SyntaxErrorException::unexpectedToken('"|"', new Token(Token::TYPE_DELIMITER, ']', 2))->getMessage()],
- ['[foo|]', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_DELIMITER, ']', 5))->getMessage()],
- ['[#]', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_DELIMITER, '#', 1))->getMessage()],
- ['[foo=#]', SyntaxErrorException::unexpectedToken('string or identifier', new Token(Token::TYPE_DELIMITER, '#', 5))->getMessage()],
- [':nth-child()', SyntaxErrorException::unexpectedToken('at least one argument', new Token(Token::TYPE_DELIMITER, ')', 11))->getMessage()],
- ['[href]a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_IDENTIFIER, 'a', 6))->getMessage()],
- ['[rel:stylesheet]', SyntaxErrorException::unexpectedToken('operator', new Token(Token::TYPE_DELIMITER, ':', 4))->getMessage()],
- ['[rel=stylesheet', SyntaxErrorException::unexpectedToken('"]"', new Token(Token::TYPE_FILE_END, '', 15))->getMessage()],
- [':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()],
- [':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
- ['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
- ];
- }
-
- public static function getPseudoElementsTestData()
- {
- return [
- ['foo', 'Element[foo]', ''],
- ['*', 'Element[*]', ''],
- [':empty', 'Pseudo[Element[*]:empty]', ''],
- [':BEfore', 'Element[*]', 'before'],
- [':aftER', 'Element[*]', 'after'],
- [':First-Line', 'Element[*]', 'first-line'],
- [':First-Letter', 'Element[*]', 'first-letter'],
- ['::befoRE', 'Element[*]', 'before'],
- ['::AFter', 'Element[*]', 'after'],
- ['::firsT-linE', 'Element[*]', 'first-line'],
- ['::firsT-letteR', 'Element[*]', 'first-letter'],
- ['::Selection', 'Element[*]', 'selection'],
- ['foo:after', 'Element[foo]', 'after'],
- ['foo::selection', 'Element[foo]', 'selection'],
- ['lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Powered_Cache_Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'],
- ['video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'],
- ];
- }
-
- public static function getSpecificityTestData()
- {
- return [
- ['*', 0],
- [' foo', 1],
- [':empty ', 10],
- [':before', 1],
- ['*:before', 1],
- [':nth-child(2)', 10],
- ['.bar', 10],
- ['[baz]', 10],
- ['[baz="4"]', 10],
- ['[baz^="4"]', 10],
- ['#lipsum', 100],
- [':not(*)', 0],
- [':not(foo)', 1],
- [':not(.foo)', 10],
- [':not([foo])', 10],
- [':not(:empty)', 10],
- [':not(#foo)', 100],
- ['foo:empty', 11],
- ['foo:before', 2],
- ['foo::before', 2],
- ['foo:empty::before', 12],
- ['#lorem + foo#ipsum:first-child > bar:first-line', 213],
- ];
- }
-
- public static function getParseSeriesTestData()
- {
- return [
- ['1n+3', 1, 3],
- ['1n +3', 1, 3],
- ['1n + 3', 1, 3],
- ['1n+ 3', 1, 3],
- ['1n-3', 1, -3],
- ['1n -3', 1, -3],
- ['1n - 3', 1, -3],
- ['1n- 3', 1, -3],
- ['n-5', 1, -5],
- ['odd', 2, 1],
- ['even', 2, 0],
- ['3n', 3, 0],
- ['n', 1, 0],
- ['+n', 1, 0],
- ['-n', -1, 0],
- ['5', 0, 5],
- ];
- }
-
- public static function getParseSeriesExceptionTestData()
- {
- return [
- ['foo'],
- ['n+'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
deleted file mode 100644
index b160113..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-
-class ReaderTest extends TestCase
-{
- public function testIsEOF()
- {
- $reader = new Reader('');
- $this->assertTrue($reader->isEOF());
-
- $reader = new Reader('hello');
- $this->assertFalse($reader->isEOF());
-
- $this->assignPosition($reader, 2);
- $this->assertFalse($reader->isEOF());
-
- $this->assignPosition($reader, 5);
- $this->assertTrue($reader->isEOF());
- }
-
- public function testGetRemainingLength()
- {
- $reader = new Reader('hello');
- $this->assertEquals(5, $reader->getRemainingLength());
-
- $this->assignPosition($reader, 2);
- $this->assertEquals(3, $reader->getRemainingLength());
-
- $this->assignPosition($reader, 5);
- $this->assertEquals(0, $reader->getRemainingLength());
- }
-
- public function testGetSubstring()
- {
- $reader = new Reader('hello');
- $this->assertEquals('he', $reader->getSubstring(2));
- $this->assertEquals('el', $reader->getSubstring(2, 1));
-
- $this->assignPosition($reader, 2);
- $this->assertEquals('ll', $reader->getSubstring(2));
- $this->assertEquals('lo', $reader->getSubstring(2, 1));
- }
-
- public function testGetOffset()
- {
- $reader = new Reader('hello');
- $this->assertEquals(2, $reader->getOffset('ll'));
- $this->assertFalse($reader->getOffset('w'));
-
- $this->assignPosition($reader, 2);
- $this->assertEquals(0, $reader->getOffset('ll'));
- $this->assertFalse($reader->getOffset('he'));
- }
-
- public function testFindPattern()
- {
- $reader = new Reader('hello');
-
- $this->assertFalse($reader->findPattern('/world/'));
- $this->assertEquals(['hello', 'h'], $reader->findPattern('/^([a-z]).*/'));
-
- $this->assignPosition($reader, 2);
- $this->assertFalse($reader->findPattern('/^h.*/'));
- $this->assertEquals(['llo'], $reader->findPattern('/^llo$/'));
- }
-
- public function testMoveForward()
- {
- $reader = new Reader('hello');
- $this->assertEquals(0, $reader->getPosition());
-
- $reader->moveForward(2);
- $this->assertEquals(2, $reader->getPosition());
- }
-
- public function testToEnd()
- {
- $reader = new Reader('hello');
- $reader->moveToEnd();
- $this->assertTrue($reader->isEOF());
- }
-
- private function assignPosition(Reader $reader, int $value)
- {
- $position = new \ReflectionProperty($reader, 'position');
- $position->setAccessible(true);
- $position->setValue($reader, $value);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
deleted file mode 100644
index 188d29f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
-
-/**
- * @author Jean-François Simon
- */
-class ClassParserTest extends TestCase
-{
- /** @dataProvider getParseTestData */
- public function testParse($source, $representation)
- {
- $parser = new ClassParser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($representation, (string) $selector->getTree());
- }
-
- public static function getParseTestData()
- {
- return [
- ['.testclass', 'Class[Element[*].testclass]'],
- ['testel.testclass', 'Class[Element[testel].testclass]'],
- ['testns|.testclass', 'Class[Element[testns|*].testclass]'],
- ['testns|*.testclass', 'Class[Element[testns|*].testclass]'],
- ['testns|testel.testclass', 'Class[Element[testns|testel].testclass]'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
deleted file mode 100644
index 58540ea..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
-
-/**
- * @author Jean-François Simon
- */
-class ElementParserTest extends TestCase
-{
- /** @dataProvider getParseTestData */
- public function testParse($source, $representation)
- {
- $parser = new ElementParser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($representation, (string) $selector->getTree());
- }
-
- public static function getParseTestData()
- {
- return [
- ['*', 'Element[*]'],
- ['testel', 'Element[testel]'],
- ['testns|*', 'Element[testns|*]'],
- ['testns|testel', 'Element[testns|testel]'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
deleted file mode 100644
index b6540ff..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
-
-/**
- * @author Jean-François Simon
- */
-class EmptyStringParserTest extends TestCase
-{
- public function testParse()
- {
- $parser = new EmptyStringParser();
- $selectors = $parser->parse('');
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals('Element[*]', (string) $selector->getTree());
-
- $selectors = $parser->parse('this will produce an empty array');
- $this->assertCount(0, $selectors);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
deleted file mode 100644
index 9a92ca4..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
-
-/**
- * @author Jean-François Simon
- */
-class HashParserTest extends TestCase
-{
- /** @dataProvider getParseTestData */
- public function testParse($source, $representation)
- {
- $parser = new HashParser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($representation, (string) $selector->getTree());
- }
-
- public static function getParseTestData()
- {
- return [
- ['#testid', 'Hash[Element[*]#testid]'],
- ['testel#testid', 'Hash[Element[testel]#testid]'],
- ['testns|#testid', 'Hash[Element[testns|*]#testid]'],
- ['testns|*#testid', 'Hash[Element[testns|*]#testid]'],
- ['testns|testel#testid', 'Hash[Element[testns|testel]#testid]'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
deleted file mode 100644
index ec7f7f5..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
+++ /dev/null
@@ -1,97 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-class TokenStreamTest extends TestCase
-{
- public function testGetNext()
- {
- $stream = new TokenStream();
- $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
-
- $this->assertSame($t1, $stream->getNext());
- $this->assertSame($t2, $stream->getNext());
- $this->assertSame($t3, $stream->getNext());
- }
-
- public function testGetPeek()
- {
- $stream = new TokenStream();
- $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
-
- $this->assertSame($t1, $stream->getPeek());
- $this->assertSame($t1, $stream->getNext());
- $this->assertSame($t2, $stream->getPeek());
- $this->assertSame($t2, $stream->getPeek());
- $this->assertSame($t2, $stream->getNext());
- }
-
- public function testGetNextIdentifier()
- {
- $stream = new TokenStream();
- $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
-
- $this->assertEquals('h1', $stream->getNextIdentifier());
- }
-
- public function testFailToGetNextIdentifier()
- {
- $this->expectException(SyntaxErrorException::class);
-
- $stream = new TokenStream();
- $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->getNextIdentifier();
- }
-
- public function testGetNextIdentifierOrStar()
- {
- $stream = new TokenStream();
-
- $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $this->assertEquals('h1', $stream->getNextIdentifierOrStar());
-
- $stream->push(new Token(Token::TYPE_DELIMITER, '*', 0));
- $this->assertNull($stream->getNextIdentifierOrStar());
- }
-
- public function testFailToGetNextIdentifierOrStar()
- {
- $this->expectException(SyntaxErrorException::class);
-
- $stream = new TokenStream();
- $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->getNextIdentifierOrStar();
- }
-
- public function testSkipWhitespace()
- {
- $stream = new TokenStream();
- $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $stream->push($t2 = new Token(Token::TYPE_WHITESPACE, ' ', 2));
- $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'h1', 3));
-
- $stream->skipWhitespace();
- $this->assertSame($t1, $stream->getNext());
-
- $stream->skipWhitespace();
- $this->assertSame($t3, $stream->getNext());
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
deleted file mode 100644
index 1147bf3..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
deleted file mode 100644
index 14f8dbe..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
- a
- b
- c
- d
- e
- f
-
-
-
-
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
deleted file mode 100644
index 15d1ad3..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
+++ /dev/null
@@ -1,308 +0,0 @@
-
-
-
-
-
-
-
-
-
As You Like It
-
- by William Shakespeare
-
-
-
ACT I, SCENE III. A room in the palace.
-
-
Enter CELIA and ROSALIND
-
-
CELIA
-
-
Why, cousin! why, Rosalind! Cupid have mercy! not a word?
-
-
ROSALIND
-
-
Not one to throw at a dog.
-
-
CELIA
-
-
No, thy words are too precious to be cast away upon
-
curs; throw some of them at me; come, lame me with reasons.
-
-
ROSALIND
-
CELIA
-
-
But is all this for your father?
-
-
-
Then there were two cousins laid up; when the one
-
should be lamed with reasons and the other mad
-
without any.
-
-
ROSALIND
-
-
No, some of it is for my child's father. O, how
-
full of briers is this working-day world!
-
-
CELIA
-
-
They are but burs, cousin, thrown upon thee in
-
holiday foolery: if we walk not in the trodden
-
paths our very petticoats will catch them.
-
-
ROSALIND
-
-
I could shake them off my coat: these burs are in my heart.
-
-
CELIA
-
-
ROSALIND
-
-
I would try, if I could cry 'hem' and have him.
-
-
CELIA
-
-
Come, come, wrestle with thy affections.
-
-
ROSALIND
-
-
O, they take the part of a better wrestler than myself!
-
-
CELIA
-
-
O, a good wish upon you! you will try in time, in
-
despite of a fall. But, turning these jests out of
-
service, let us talk in good earnest: is it
-
possible, on such a sudden, you should fall into so
-
strong a liking with old Sir Rowland's youngest son?
-
-
ROSALIND
-
-
The duke my father loved his father dearly.
-
-
CELIA
-
-
Doth it therefore ensue that you should love his son
-
dearly? By this kind of chase, I should hate him,
-
for my father hated his father dearly; yet I hate
-
not Orlando.
-
-
ROSALIND
-
-
No, faith, hate him not, for my sake.
-
-
CELIA
-
-
Why should I not? doth he not deserve well?
-
-
ROSALIND
-
-
Let me love him for that, and do you love him
-
because I do. Look, here comes the duke.
-
-
CELIA
-
-
With his eyes full of anger.
-
Enter DUKE FREDERICK, with Lords
-
-
DUKE FREDERICK
-
-
Mistress, dispatch you with your safest haste
-
And get you from our court.
-
-
ROSALIND
-
-
DUKE FREDERICK
-
-
You, cousin
-
Within these ten days if that thou be'st found
-
So near our public court as twenty miles,
-
Thou diest for it.
-
-
ROSALIND
-
-
I do beseech your grace,
-
Let me the knowledge of my fault bear with me:
-
If with myself I hold intelligence
-
Or have acquaintance with mine own desires,
-
If that I do not dream or be not frantic,--
-
As I do trust I am not--then, dear uncle,
-
Never so much as in a thought unborn
-
Did I offend your highness.
-
-
DUKE FREDERICK
-
-
Thus do all traitors:
-
If their purgation did consist in words,
-
They are as innocent as grace itself:
-
Let it suffice thee that I trust thee not.
-
-
ROSALIND
-
-
Yet your mistrust cannot make me a traitor:
-
Tell me whereon the likelihood depends.
-
-
DUKE FREDERICK
-
-
Thou art thy father's daughter; there's enough.
-
-
ROSALIND
-
-
So was I when your highness took his dukedom;
-
So was I when your highness banish'd him:
-
Treason is not inherited, my lord;
-
Or, if we did derive it from our friends,
-
What's that to me? my father was no traitor:
-
Then, good my liege, mistake me not so much
-
To think my poverty is treacherous.
-
-
CELIA
-
-
Dear sovereign, hear me speak.
-
-
DUKE FREDERICK
-
-
Ay, Celia; we stay'd her for your sake,
-
Else had she with her father ranged along.
-
-
CELIA
-
-
I did not then entreat to have her stay;
-
It was your pleasure and your own remorse:
-
I was too young that time to value her;
-
But now I know her: if she be a traitor,
-
Why so am I; we still have slept together,
-
Rose at an instant, learn'd, play'd, eat together,
-
And wheresoever we went, like Juno's swans,
-
Still we went coupled and inseparable.
-
-
DUKE FREDERICK
-
-
She is too subtle for thee; and her smoothness,
-
Her very silence and her patience
-
Speak to the people, and they pity her.
-
Thou art a fool: she robs thee of thy name;
-
And thou wilt show more bright and seem more virtuous
-
When she is gone. Then open not thy lips:
-
Firm and irrevocable is my doom
-
Which I have pass'd upon her; she is banish'd.
-
-
CELIA
-
-
Pronounce that sentence then on me, my liege:
-
I cannot live out of her company.
-
-
DUKE FREDERICK
-
-
You are a fool. You, niece, provide yourself:
-
If you outstay the time, upon mine honour,
-
And in the greatness of my word, you die.
-
Exeunt DUKE FREDERICK and Lords
-
-
CELIA
-
-
O my poor Rosalind, whither wilt thou go?
-
Wilt thou change fathers? I will give thee mine.
-
I charge thee, be not thou more grieved than I am.
-
-
ROSALIND
-
-
CELIA
-
-
Thou hast not, cousin;
-
Prithee be cheerful: know'st thou not, the duke
-
Hath banish'd me, his daughter?
-
-
ROSALIND
-
-
CELIA
-
-
No, hath not? Rosalind lacks then the love
-
Which teacheth thee that thou and I am one:
-
Shall we be sunder'd? shall we part, sweet girl?
-
No: let my father seek another heir.
-
Therefore devise with me how we may fly,
-
Whither to go and what to bear with us;
-
And do not seek to take your change upon you,
-
To bear your griefs yourself and leave me out;
-
For, by this heaven, now at our sorrows pale,
-
Say what thou canst, I'll go along with thee.
-
-
ROSALIND
-
-
Why, whither shall we go?
-
-
CELIA
-
-
To seek my uncle in the forest of Arden.
-
-
ROSALIND
-
-
Alas, what danger will it be to us,
-
Maids as we are, to travel forth so far!
-
Beauty provoketh thieves sooner than gold.
-
-
CELIA
-
-
I'll put myself in poor and mean attire
-
And with a kind of umber smirch my face;
-
The like do you: so shall we pass along
-
And never stir assailants.
-
-
ROSALIND
-
-
Were it not better,
-
Because that I am more than common tall,
-
That I did suit me all points like a man?
-
A gallant curtle-axe upon my thigh,
-
A boar-spear in my hand; and--in my heart
-
Lie there what hidden woman's fear there will--
-
We'll have a swashing and a martial outside,
-
As many other mannish cowards have
-
That do outface it with their semblances.
-
-
CELIA
-
-
What shall I call thee when thou art a man?
-
-
ROSALIND
-
-
I'll have no worse a name than Jove's own page;
-
And therefore look you call me Ganymede.
-
But what will you be call'd?
-
-
CELIA
-
-
Something that hath a reference to my state
-
No longer Celia, but Aliena.
-
-
ROSALIND
-
-
But, cousin, what if we assay'd to steal
-
The clownish fool out of your father's court?
-
Would he not be a comfort to our travel?
-
-
CELIA
-
-
He'll go along o'er the wide world with me;
-
Leave me alone to woo him. Let's away,
-
And get our jewels and our wealth together,
-
Devise the fittest time and safest way
-
To hide us from pursuit that will be made
-
After my flight. Now go we in content
-
To liberty and not to banishment.
-
Exeunt
-
-
-
-
-
-
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
deleted file mode 100644
index fad6105..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
+++ /dev/null
@@ -1,416 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\XPath;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-class TranslatorTest extends TestCase
-{
- /** @dataProvider getXpathLiteralTestData */
- public function testXpathLiteral($value, $literal)
- {
- $this->assertEquals($literal, Translator::getXpathLiteral($value));
- }
-
- /** @dataProvider getCssToXPathTestData */
- public function testCssToXPath($css, $xpath)
- {
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $this->assertEquals($xpath, $translator->cssToXPath($css, ''));
- }
-
- public function testCssToXPathPseudoElement()
- {
- $this->expectException(ExpressionErrorException::class);
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $translator->cssToXPath('e::first-line');
- }
-
- public function testGetExtensionNotExistsExtension()
- {
- $this->expectException(ExpressionErrorException::class);
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $translator->getExtension('fake');
- }
-
- public function testAddCombinationNotExistsExtension()
- {
- $this->expectException(ExpressionErrorException::class);
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $parser = new Parser();
- $xpath = $parser->parse('*')[0];
- $combinedXpath = $parser->parse('*')[0];
- $translator->addCombination('fake', $xpath, $combinedXpath);
- }
-
- public function testAddFunctionNotExistsFunction()
- {
- $this->expectException(ExpressionErrorException::class);
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $xpath = new XPathExpr();
- $function = new FunctionNode(new ElementNode(), 'fake');
- $translator->addFunction($xpath, $function);
- }
-
- public function testAddPseudoClassNotExistsClass()
- {
- $this->expectException(ExpressionErrorException::class);
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $xpath = new XPathExpr();
- $translator->addPseudoClass($xpath, 'fake');
- }
-
- public function testAddAttributeMatchingClassNotExistsClass()
- {
- $this->expectException(ExpressionErrorException::class);
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $xpath = new XPathExpr();
- $translator->addAttributeMatching($xpath, '', '', '');
- }
-
- /** @dataProvider getXmlLangTestData */
- public function testXmlLang($css, array $elementsId)
- {
- $translator = new Translator();
- $document = new \SimpleXMLElement(file_get_contents(__DIR__.'/Fixtures/lang.xml'));
- $elements = $document->xpath($translator->cssToXPath($css));
- $this->assertCount(\count($elementsId), $elements);
- foreach ($elements as $element) {
- $this->assertContains((string) $element->attributes()->id, $elementsId);
- }
- }
-
- /** @dataProvider getHtmlIdsTestData */
- public function testHtmlIds($css, array $elementsId)
- {
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $document = new \DOMDocument();
- $document->strictErrorChecking = false;
- $internalErrors = libxml_use_internal_errors(true);
- $document->loadHTMLFile(__DIR__.'/Fixtures/ids.html');
- $document = simplexml_import_dom($document);
- $elements = $document->xpath($translator->cssToXPath($css));
- $this->assertCount(\count($elementsId), $elements);
- foreach ($elements as $element) {
- if (null !== $element->attributes()->id) {
- $this->assertContains((string) $element->attributes()->id, $elementsId);
- }
- }
- libxml_clear_errors();
- libxml_use_internal_errors($internalErrors);
- }
-
- /** @dataProvider getHtmlShakespearTestData */
- public function testHtmlShakespear($css, $count)
- {
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $document = new \DOMDocument();
- $document->strictErrorChecking = false;
- $document->loadHTMLFile(__DIR__.'/Fixtures/shakespear.html');
- $document = simplexml_import_dom($document);
- $bodies = $document->xpath('//body');
- $elements = $bodies[0]->xpath($translator->cssToXPath($css));
- $this->assertCount($count, $elements);
- }
-
- public function testOnlyOfTypeFindsSingleChildrenOfGivenType()
- {
- $translator = new Translator();
- $translator->registerExtension(new HtmlExtension($translator));
- $document = new \DOMDocument();
- $document->loadHTML(<<<'HTML'
-
-
-
- A
-
-
- B
- C
-
-
-
-HTML
- );
-
- $xpath = new \DOMXPath($document);
- $nodeList = $xpath->query($translator->cssToXPath('span:only-of-type'));
-
- $this->assertSame(1, $nodeList->length);
- $this->assertSame('A', $nodeList->item(0)->textContent);
- }
-
- public static function getXpathLiteralTestData()
- {
- return [
- ['foo', "'foo'"],
- ["foo's bar", '"foo\'s bar"'],
- ["foo's \"middle\" bar", 'concat(\'foo\', "\'", \'s "middle" bar\')'],
- ["foo's 'middle' \"bar\"", 'concat(\'foo\', "\'", \'s \', "\'", \'middle\', "\'", \' "bar"\')'],
- ];
- }
-
- public static function getCssToXPathTestData()
- {
- return [
- ['*', '*'],
- ['e', 'e'],
- ['*|e', 'e'],
- ['e|f', 'e:f'],
- ['e[foo]', 'e[@foo]'],
- ['e[foo|bar]', 'e[@foo:bar]'],
- ['e[foo="bar"]', "e[@foo = 'bar']"],
- ['e[foo~="bar"]', "e[@foo and contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]"],
- ['e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"],
- ['e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"],
- ['e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"],
- ['e[foo!="bar"]', "e[not(@foo) or @foo != 'bar']"],
- ['e[foo!="bar"][foo!="baz"]', "e[(not(@foo) or @foo != 'bar') and (not(@foo) or @foo != 'baz')]"],
- ['e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"],
- ['e:nth-child(1)', "*/*[(name() = 'e') and (position() = 1)]"],
- ['e:nth-last-child(1)', "*/*[(name() = 'e') and (position() = last() - 0)]"],
- ['e:nth-last-child(2n+2)', "*/*[(name() = 'e') and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"],
- ['e:nth-of-type(1)', '*/e[position() = 1]'],
- ['e:nth-last-of-type(1)', '*/e[position() = last() - 0]'],
- ['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 ')]"],
- ['e:first-child', "*/*[(name() = 'e') and (position() = 1)]"],
- ['e:last-child', "*/*[(name() = 'e') and (position() = last())]"],
- ['e:first-of-type', '*/e[position() = 1]'],
- ['e:last-of-type', '*/e[position() = last()]'],
- ['e:only-child', "*/*[(name() = 'e') and (last() = 1)]"],
- ['e:only-of-type', 'e[count(preceding-sibling::e)=0 and count(following-sibling::e)=0]'],
- ['e:empty', 'e[not(*) and not(string-length())]'],
- ['e:EmPTY', 'e[not(*) and not(string-length())]'],
- ['e:root', 'e[not(parent::*)]'],
- ['e:hover', 'e[0]'],
- ['e:contains("foo")', "e[contains(string(.), 'foo')]"],
- ['e:ConTains(foo)', "e[contains(string(.), 'foo')]"],
- ['e.warning', "e[@class and contains(concat(' ', normalize-space(@class), ' '), ' warning ')]"],
- ['e#myid', "e[@id = 'myid']"],
- ['e:not(:nth-child(odd))', 'e[not(position() - 1 >= 0 and (position() - 1) mod 2 = 0)]'],
- ['e:nOT(*)', 'e[0]'],
- ['e f', 'e/descendant-or-self::*/f'],
- ['e > f', 'e/f'],
- ['e + f', "e/following-sibling::*[(name() = 'f') and (position() = 1)]"],
- ['e ~ f', 'e/following-sibling::f'],
- ['div#container p', "div[@id = 'container']/descendant-or-self::*/p"],
- ];
- }
-
- public static function getXmlLangTestData()
- {
- return [
- [':lang("EN")', ['first', 'second', 'third', 'fourth']],
- [':lang("en-us")', ['second', 'fourth']],
- [':lang(en-nz)', ['third']],
- [':lang(fr)', ['fifth']],
- [':lang(ru)', ['sixth']],
- [":lang('ZH')", ['eighth']],
- [':lang(de) :lang(zh)', ['eighth']],
- [':lang(en), :lang(zh)', ['first', 'second', 'third', 'fourth', 'eighth']],
- [':lang(es)', []],
- ];
- }
-
- public static function getHtmlIdsTestData()
- {
- return [
- ['div', ['outer-div', 'li-div', 'foobar-div']],
- ['DIV', ['outer-div', 'li-div', 'foobar-div']], // case-insensitive in HTML
- ['div div', ['li-div']],
- ['div, div div', ['outer-div', 'li-div', 'foobar-div']],
- ['a[name]', ['name-anchor']],
- ['a[NAme]', ['name-anchor']], // case-insensitive in HTML:
- ['a[rel]', ['tag-anchor', 'nofollow-anchor']],
- ['a[rel="tag"]', ['tag-anchor']],
- ['a[href*="localhost"]', ['tag-anchor']],
- ['a[href*=""]', []],
- ['a[href^="http"]', ['tag-anchor', 'nofollow-anchor']],
- ['a[href^="http:"]', ['tag-anchor']],
- ['a[href^=""]', []],
- ['a[href$="org"]', ['nofollow-anchor']],
- ['a[href$=""]', []],
- ['div[foobar~="bc"]', ['foobar-div']],
- ['div[foobar~="cde"]', ['foobar-div']],
- ['[foobar~="ab bc"]', ['foobar-div']],
- ['[foobar~=""]', []],
- ['[foobar~=" \t"]', []],
- ['div[foobar~="cd"]', []],
- ['*[lang|="En"]', ['second-li']],
- ['[lang|="En-us"]', ['second-li']],
- // Powered_Cache_Attribute values are case sensitive
- ['*[lang|="en"]', []],
- ['[lang|="en-US"]', []],
- ['*[lang|="e"]', []],
- // ... :lang() is not.
- [':lang("EN")', ['second-li', 'li-div']],
- ['*:lang(en-US)', ['second-li', 'li-div']],
- [':lang("e")', []],
- ['li:nth-child(3)', ['third-li']],
- ['li:nth-child(10)', []],
- ['li:nth-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
- ['li:nth-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
- ['li:nth-child(2n+0)', ['second-li', 'fourth-li', 'sixth-li']],
- ['li:nth-child(+2n+1)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
- ['li:nth-child(odd)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
- ['li:nth-child(2n+4)', ['fourth-li', 'sixth-li']],
- ['li:nth-child(3n+1)', ['first-li', 'fourth-li', 'seventh-li']],
- ['li:nth-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-child(n+3)', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-child(-n)', []],
- ['li:nth-child(-n-1)', []],
- ['li:nth-child(-n+1)', ['first-li']],
- ['li:nth-child(-n+3)', ['first-li', 'second-li', 'third-li']],
- ['li:nth-last-child(0)', []],
- ['li:nth-last-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
- ['li:nth-last-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
- ['li:nth-last-child(2n+2)', ['second-li', 'fourth-li', 'sixth-li']],
- ['li:nth-last-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-last-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-last-child(n-3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-last-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
- ['li:nth-last-child(n+3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li']],
- ['li:nth-last-child(-n)', []],
- ['li:nth-last-child(-n-1)', []],
- ['li:nth-last-child(-n+1)', ['seventh-li']],
- ['li:nth-last-child(-n+3)', ['fifth-li', 'sixth-li', 'seventh-li']],
- ['ol:first-of-type', ['first-ol']],
- ['ol:nth-child(4)', ['first-ol']],
- ['ol:nth-of-type(2)', ['second-ol']],
- ['ol:nth-last-of-type(1)', ['second-ol']],
- ['span:only-child', ['foobar-span', 'no-siblings-of-any-type']],
- ['li div:only-child', ['li-div']],
- ['div *:only-child', ['li-div', 'foobar-span']],
- ['p:only-of-type', ['paragraph']],
- [':only-of-type', ['html', 'li-div', 'foobar-span', 'no-siblings-of-any-type']],
- ['div#foobar-div :only-of-type', ['foobar-span']],
- ['a:empty', ['name-anchor']],
- ['a:EMpty', ['name-anchor']],
- ['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']],
- [':root', ['html']],
- ['html:root', ['html']],
- ['li:root', []],
- ['* :root', []],
- ['*:contains("link")', ['html', 'nil', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
- [':CONtains("link")', ['html', 'nil', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
- ['*:contains("LInk")', []], // case sensitive
- ['*:contains("e")', ['html', 'nil', 'outer-div', 'first-ol', 'first-li', 'paragraph', 'p-em']],
- ['*:contains("E")', []], // case-sensitive
- ['.a', ['first-ol']],
- ['.b', ['first-ol']],
- ['*.a', ['first-ol']],
- ['ol.a', ['first-ol']],
- ['.c', ['first-ol', 'third-li', 'fourth-li']],
- ['*.c', ['first-ol', 'third-li', 'fourth-li']],
- ['ol *.c', ['third-li', 'fourth-li']],
- ['ol li.c', ['third-li', 'fourth-li']],
- ['li ~ li.c', ['third-li', 'fourth-li']],
- ['ol > li.c', ['third-li', 'fourth-li']],
- ['#first-li', ['first-li']],
- ['li#first-li', ['first-li']],
- ['*#first-li', ['first-li']],
- ['li div', ['li-div']],
- ['li > div', ['li-div']],
- ['div div', ['li-div']],
- ['div > div', []],
- ['div>.c', ['first-ol']],
- ['div > .c', ['first-ol']],
- ['div + div', ['foobar-div']],
- ['a ~ a', ['tag-anchor', 'nofollow-anchor']],
- ['a[rel="tag"] ~ a', ['nofollow-anchor']],
- ['ol#first-ol li:last-child', ['seventh-li']],
- ['ol#first-ol *:last-child', ['li-div', 'seventh-li']],
- ['#outer-div:first-child', ['outer-div']],
- ['#outer-div :first-child', ['name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-fieldset-disabled', 'area-href']],
- ['a[href]', ['tag-anchor', 'nofollow-anchor']],
- [':not(*)', []],
- ['a:not([href])', ['name-anchor']],
- ['ol :Not(li[class])', ['first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li']],
- // HTML-specific
- [':link', ['link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']],
- [':visited', []],
- [':enabled', ['link-href', 'tag-anchor', 'nofollow-anchor', 'checkbox-unchecked', 'text-checked', 'checkbox-checked', 'area-href']],
- [':disabled', ['checkbox-disabled', 'checkbox-disabled-checked', 'fieldset', 'checkbox-fieldset-disabled']],
- [':checked', ['checkbox-checked', 'checkbox-disabled-checked']],
- ];
- }
-
- public static function getHtmlShakespearTestData()
- {
- return [
- ['*', 246],
- ['div:contains(CELIA)', 26],
- ['div:only-child', 22], // ?
- ['div:nth-child(even)', 106],
- ['div:nth-child(2n)', 106],
- ['div:nth-child(odd)', 137],
- ['div:nth-child(2n+1)', 137],
- ['div:nth-child(n)', 243],
- ['div:last-child', 53],
- ['div:first-child', 51],
- ['div > div', 242],
- ['div + div', 190],
- ['div ~ div', 190],
- ['body', 1],
- ['body div', 243],
- ['div', 243],
- ['div div', 242],
- ['div div div', 241],
- ['div, div, div', 243],
- ['div, a, span', 243],
- ['.dialog', 51],
- ['div.dialog', 51],
- ['div .dialog', 51],
- ['div.character, div.dialog', 99],
- ['div.direction.dialog', 0],
- ['div.dialog.direction', 0],
- ['div.dialog.scene', 1],
- ['div.scene.scene', 1],
- ['div.scene .scene', 0],
- ['div.direction .dialog ', 0],
- ['div .dialog .direction', 4],
- ['div.dialog .dialog .direction', 4],
- ['#speech5', 1],
- ['div#speech5', 1],
- ['div #speech5', 1],
- ['div.scene div.dialog', 49],
- ['div#scene1 div.dialog div', 142],
- ['#scene1 #speech1', 1],
- ['div[class]', 103],
- ['div[class=dialog]', 50],
- ['div[class^=dia]', 51],
- ['div[class$=log]', 50],
- ['div[class*=sce]', 1],
- ['div[class|=dialog]', 50], // ? Seems right
- ['div[class!=madeup]', 243], // ? Seems right
- ['div[class~=dialog]', 51], // ? Seems right
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
deleted file mode 100644
index 8f3dcbb..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
+++ /dev/null
@@ -1,65 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-/**
- * XPath expression translator abstract extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-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 [];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
deleted file mode 100644
index 5415136..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
+++ /dev/null
@@ -1,119 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-/**
- * XPath expression translator attribute extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-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'],
- ];
- }
-
- public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
- {
- return $xpath->addCondition($attribute);
- }
-
- public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
- {
- return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($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)',
- $attribute,
- Translator::getXpathLiteral(' '.$value.' ')
- ) : '0');
- }
-
- 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))',
- $attribute,
- Translator::getXpathLiteral($value),
- Translator::getXpathLiteral($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)',
- $attribute,
- Translator::getXpathLiteral($value)
- ) : '0');
- }
-
- 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',
- $attribute,
- \strlen($value) - 1,
- Translator::getXpathLiteral($value)
- ) : '0');
- }
-
- public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
- {
- return $xpath->addCondition($value ? sprintf(
- '%1$s and contains(%1$s, %2$s)',
- $attribute,
- Translator::getXpathLiteral($value)
- ) : '0');
- }
-
- 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',
- $attribute,
- Translator::getXpathLiteral($value)
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return 'attribute-matching';
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
deleted file mode 100644
index 9d6e043..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
+++ /dev/null
@@ -1,71 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-/**
- * XPath expression translator combination extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class CombinationExtension extends AbstractExtension
-{
- /**
- * {@inheritdoc}
- */
- public function getCombinationTranslators(): array
- {
- return [
- ' ' => [$this, 'translateDescendant'],
- '>' => [$this, 'translateChild'],
- '+' => [$this, 'translateDirectAdjacent'],
- '~' => [$this, 'translateIndirectAdjacent'],
- ];
- }
-
- public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
- {
- return $xpath->join('/descendant-or-self::*/', $combinedXpath);
- }
-
- public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
- {
- return $xpath->join('/', $combinedXpath);
- }
-
- public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
- {
- return $xpath
- ->join('/following-sibling::', $combinedXpath)
- ->addNameTest()
- ->addCondition('position() = 1');
- }
-
- public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
- {
- return $xpath->join('/following-sibling::', $combinedXpath);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return 'combination';
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
deleted file mode 100644
index 56fb4a1..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
+++ /dev/null
@@ -1,67 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-/**
- * XPath expression translator extension interface.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-interface ExtensionInterface
-{
- /**
- * Returns node translators.
- *
- * These callables will receive the node as first argument and the translator as second argument.
- *
- * @return callable[]
- */
- public function getNodeTranslators(): array;
-
- /**
- * Returns combination translators.
- *
- * @return callable[]
- */
- public function getCombinationTranslators(): array;
-
- /**
- * Returns function translators.
- *
- * @return callable[]
- */
- public function getFunctionTranslators(): array;
-
- /**
- * Returns pseudo-class translators.
- *
- * @return callable[]
- */
- public function getPseudoClassTranslators(): array;
-
- /**
- * Returns attribute operation translators.
- *
- * @return callable[]
- */
- public function getAttributeMatchingTranslators(): array;
-
- /**
- * Returns extension name.
- */
- public function getName(): string;
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
deleted file mode 100644
index 811105d..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
+++ /dev/null
@@ -1,171 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-/**
- * XPath expression translator function extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-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'],
- ];
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr
- {
- try {
- [$a, $b] = Parser::parseSeries($function->getArguments());
- } catch (SyntaxErrorException $e) {
- throw new ExpressionErrorException(sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e);
- }
-
- $xpath->addStarPrefix();
- if ($addNameTest) {
- $xpath->addNameTest();
- }
-
- if (0 === $a) {
- return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b));
- }
-
- if ($a < 0) {
- if ($b < 1) {
- return $xpath->addCondition('false()');
- }
-
- $sign = '<=';
- } else {
- $sign = '>=';
- }
-
- $expr = 'position()';
-
- if ($last) {
- $expr = 'last() - '.$expr;
- --$b;
- }
-
- if (0 !== $b) {
- $expr .= ' - '.$b;
- }
-
- $conditions = [sprintf('%s %s 0', $expr, $sign)];
-
- if (1 !== $a && -1 !== $a) {
- $conditions[] = sprintf('(%s) mod %d = 0', $expr, $a);
- }
-
- return $xpath->addCondition(implode(' and ', $conditions));
-
- // todo: handle an+b, odd, even
- // an+b means every-a, plus b, e.g., 2n+1 means odd
- // 0n+b means b
- // n+0 means a=1, i.e., all elements
- // an means every a elements, i.e., 2n means even
- // -n means -1n
- // -1n+6 means elements 6 and previous
- }
-
- public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- return $this->translateNthChild($xpath, $function, true);
- }
-
- public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- return $this->translateNthChild($xpath, $function, false, false);
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- if ('*' === $xpath->getElement()) {
- throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
- }
-
- return $this->translateNthChild($xpath, $function, true, false);
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- $arguments = $function->getArguments();
- foreach ($arguments as $token) {
- if (!($token->isString() || $token->isIdentifier())) {
- throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments));
- }
- }
-
- return $xpath->addCondition(sprintf(
- 'contains(string(.), %s)',
- Translator::getXpathLiteral($arguments[0]->getValue())
- ));
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- $arguments = $function->getArguments();
- foreach ($arguments as $token) {
- if (!($token->isString() || $token->isIdentifier())) {
- throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
- }
- }
-
- return $xpath->addCondition(sprintf(
- 'lang(%s)',
- Translator::getXpathLiteral($arguments[0]->getValue())
- ));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return 'function';
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
deleted file mode 100644
index 72b9a23..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
+++ /dev/null
@@ -1,187 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-/**
- * XPath expression translator HTML extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class HtmlExtension extends AbstractExtension
-{
- public function __construct(Translator $translator)
- {
- $translator
- ->getExtension('node')
- ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true)
- ->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'],
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFunctionTranslators(): array
- {
- return [
- 'lang' => [$this, 'translateLang'],
- ];
- }
-
- public function translateChecked(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition(
- '(@checked '
- ."and (name(.) = 'input' or name(.) = 'command')"
- ."and (@type = 'checkbox' or @type = 'radio'))"
- );
- }
-
- public function translateLink(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
- }
-
- public function translateDisabled(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition(
- '('
- .'@disabled and'
- .'('
- ."(name(.) = 'input' and @type != 'hidden')"
- ." or name(.) = 'button'"
- ." or name(.) = 'select'"
- ." or name(.) = 'textarea'"
- ." or name(.) = 'command'"
- ." or name(.) = 'fieldset'"
- ." or name(.) = 'optgroup'"
- ." or name(.) = 'option'"
- .')'
- .') or ('
- ."(name(.) = 'input' and @type != 'hidden')"
- ." or name(.) = 'button'"
- ." or name(.) = 'select'"
- ." or name(.) = 'textarea'"
- .')'
- .' and ancestor::fieldset[@disabled]'
- );
- // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any."
- }
-
- public function translateEnabled(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition(
- '('
- .'@href and ('
- ."name(.) = 'a'"
- ." or name(.) = 'link'"
- ." or name(.) = 'area'"
- .')'
- .') or ('
- .'('
- ."name(.) = 'command'"
- ." or name(.) = 'fieldset'"
- ." or name(.) = 'optgroup'"
- .')'
- .' and not(@disabled)'
- .') or ('
- .'('
- ."(name(.) = 'input' and @type != 'hidden')"
- ." or name(.) = 'button'"
- ." or name(.) = 'select'"
- ." or name(.) = 'textarea'"
- ." or name(.) = 'keygen'"
- .')'
- .' and not (@disabled or ancestor::fieldset[@disabled])'
- .') or ('
- ."name(.) = 'option' and not("
- .'@disabled or ancestor::optgroup[@disabled]'
- .')'
- .')'
- );
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- $arguments = $function->getArguments();
- foreach ($arguments as $token) {
- if (!($token->isString() || $token->isIdentifier())) {
- throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
- }
- }
-
- return $xpath->addCondition(sprintf(
- 'ancestor-or-self::*[@lang][1][starts-with(concat('
- ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')"
- .', %s)]',
- 'lang',
- Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-')
- ));
- }
-
- public function translateSelected(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition("(@selected and name(.) = 'option')");
- }
-
- public function translateInvalid(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition('0');
- }
-
- public function translateHover(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition('0');
- }
-
- public function translateVisited(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition('0');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return 'html';
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
deleted file mode 100644
index a64f7ee..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
+++ /dev/null
@@ -1,197 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-/**
- * XPath expression translator node extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class NodeExtension extends AbstractExtension
-{
- public const ELEMENT_NAME_IN_LOWER_CASE = 1;
- public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
- public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
-
- private $flags;
-
- public function __construct(int $flags = 0)
- {
- $this->flags = $flags;
- }
-
- /**
- * @return $this
- */
- public function setFlag(int $flag, bool $on): self
- {
- if ($on && !$this->hasFlag($flag)) {
- $this->flags += $flag;
- }
-
- if (!$on && $this->hasFlag($flag)) {
- $this->flags -= $flag;
- }
-
- return $this;
- }
-
- public function hasFlag(int $flag): bool
- {
- 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'],
- 'Powered_Cache_Attribute' => [$this, 'translateAttribute'],
- 'Class' => [$this, 'translateClass'],
- 'Hash' => [$this, 'translateHash'],
- 'Element' => [$this, 'translateElement'],
- ];
- }
-
- public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
- {
- return $translator->nodeToXPath($node->getTree());
- }
-
- public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
- {
- return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
- }
-
- public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
- {
- $xpath = $translator->nodeToXPath($node->getSelector());
- $subXpath = $translator->nodeToXPath($node->getSubSelector());
- $subXpath->addNameTest();
-
- if ($subXpath->getCondition()) {
- return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition()));
- }
-
- return $xpath->addCondition('0');
- }
-
- public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
- {
- $xpath = $translator->nodeToXPath($node->getSelector());
-
- return $translator->addFunction($xpath, $node);
- }
-
- public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
- {
- $xpath = $translator->nodeToXPath($node->getSelector());
-
- return $translator->addPseudoClass($xpath, $node->getIdentifier());
- }
-
- public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
- {
- $name = $node->getAttribute();
- $safe = $this->isSafeName($name);
-
- if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
- $name = strtolower($name);
- }
-
- if ($node->getNamespace()) {
- $name = sprintf('%s:%s', $node->getNamespace(), $name);
- $safe = $safe && $this->isSafeName($node->getNamespace());
- }
-
- $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
- $value = $node->getValue();
- $xpath = $translator->nodeToXPath($node->getSelector());
-
- if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
- $value = strtolower($value);
- }
-
- return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
- }
-
- public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
- {
- $xpath = $translator->nodeToXPath($node->getSelector());
-
- return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
- }
-
- public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
- {
- $xpath = $translator->nodeToXPath($node->getSelector());
-
- return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
- }
-
- public function translateElement(Node\ElementNode $node): XPathExpr
- {
- $element = $node->getElement();
-
- if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
- $element = strtolower($element);
- }
-
- if ($element) {
- $safe = $this->isSafeName($element);
- } else {
- $element = '*';
- $safe = true;
- }
-
- if ($node->getNamespace()) {
- $element = sprintf('%s:%s', $node->getNamespace(), $element);
- $safe = $safe && $this->isSafeName($node->getNamespace());
- }
-
- $xpath = new XPathExpr('', $element);
-
- if (!$safe) {
- $xpath->addNameTest();
- }
-
- return $xpath;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return 'node';
- }
-
- private function isSafeName(string $name): bool
- {
- return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
deleted file mode 100644
index b20a597..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
+++ /dev/null
@@ -1,122 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
-
-/**
- * XPath expression translator pseudo-class extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-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'],
- ];
- }
-
- public function translateRoot(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition('not(parent::*)');
- }
-
- public function translateFirstChild(XPathExpr $xpath): XPathExpr
- {
- return $xpath
- ->addStarPrefix()
- ->addNameTest()
- ->addCondition('position() = 1');
- }
-
- public function translateLastChild(XPathExpr $xpath): XPathExpr
- {
- return $xpath
- ->addStarPrefix()
- ->addNameTest()
- ->addCondition('position() = last()');
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateFirstOfType(XPathExpr $xpath): XPathExpr
- {
- if ('*' === $xpath->getElement()) {
- throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
- }
-
- return $xpath
- ->addStarPrefix()
- ->addCondition('position() = 1');
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function translateLastOfType(XPathExpr $xpath): XPathExpr
- {
- if ('*' === $xpath->getElement()) {
- throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
- }
-
- return $xpath
- ->addStarPrefix()
- ->addCondition('position() = last()');
- }
-
- public function translateOnlyChild(XPathExpr $xpath): XPathExpr
- {
- return $xpath
- ->addStarPrefix()
- ->addNameTest()
- ->addCondition('last() = 1');
- }
-
- public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
- {
- $element = $xpath->getElement();
-
- return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
- }
-
- public function translateEmpty(XPathExpr $xpath): XPathExpr
- {
- return $xpath->addCondition('not(*) and not(string-length())');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return 'pseudo-class';
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php
deleted file mode 100644
index 488b40c..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php
+++ /dev/null
@@ -1,230 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NodeInterface;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
-
-/**
- * XPath expression translator interface.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class Translator implements TranslatorInterface
-{
- private $mainParser;
-
- /**
- * @var ParserInterface[]
- */
- private $shortcutParsers = [];
-
- /**
- * @var Extension\ExtensionInterface[]
- */
- private $extensions = [];
-
- private $nodeTranslators = [];
- private $combinationTranslators = [];
- private $functionTranslators = [];
- private $pseudoClassTranslators = [];
- private $attributeMatchingTranslators = [];
-
- public function __construct(?ParserInterface $parser = null)
- {
- $this->mainParser = $parser ?? new Parser();
-
- $this
- ->registerExtension(new Extension\NodeExtension())
- ->registerExtension(new Extension\CombinationExtension())
- ->registerExtension(new Extension\FunctionExtension())
- ->registerExtension(new Extension\PseudoClassExtension())
- ->registerExtension(new Extension\AttributeMatchingExtension())
- ;
- }
-
- public static function getXpathLiteral(string $element): string
- {
- if (!str_contains($element, "'")) {
- return "'".$element."'";
- }
-
- if (!str_contains($element, '"')) {
- return '"'.$element.'"';
- }
-
- $string = $element;
- $parts = [];
- while (true) {
- if (false !== $pos = strpos($string, "'")) {
- $parts[] = sprintf("'%s'", substr($string, 0, $pos));
- $parts[] = "\"'\"";
- $string = substr($string, $pos + 1);
- } else {
- $parts[] = "'$string'";
- break;
- }
- }
-
- return sprintf('concat(%s)', implode(', ', $parts));
- }
-
- /**
- * {@inheritdoc}
- */
- public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
- {
- $selectors = $this->parseSelectors($cssExpr);
-
- /** @var SelectorNode $selector */
- foreach ($selectors as $index => $selector) {
- if (null !== $selector->getPseudoElement()) {
- throw new ExpressionErrorException('Pseudo-elements are not supported.');
- }
-
- $selectors[$index] = $this->selectorToXPath($selector, $prefix);
- }
-
- return implode(' | ', $selectors);
- }
-
- /**
- * {@inheritdoc}
- */
- public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
- {
- return ($prefix ?: '').$this->nodeToXPath($selector);
- }
-
- /**
- * @return $this
- */
- public function registerExtension(Extension\ExtensionInterface $extension): self
- {
- $this->extensions[$extension->getName()] = $extension;
-
- $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
- $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
- $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
- $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
- $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
-
- return $this;
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function getExtension(string $name): Extension\ExtensionInterface
- {
- if (!isset($this->extensions[$name])) {
- throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
- }
-
- return $this->extensions[$name];
- }
-
- /**
- * @return $this
- */
- public function registerParserShortcut(ParserInterface $shortcut): self
- {
- $this->shortcutParsers[] = $shortcut;
-
- return $this;
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function nodeToXPath(NodeInterface $node): XPathExpr
- {
- if (!isset($this->nodeTranslators[$node->getNodeName()])) {
- throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
- }
-
- return $this->nodeTranslators[$node->getNodeName()]($node, $this);
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
- {
- if (!isset($this->combinationTranslators[$combiner])) {
- throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
- }
-
- return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
- {
- if (!isset($this->functionTranslators[$function->getName()])) {
- throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
- }
-
- return $this->functionTranslators[$function->getName()]($xpath, $function);
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
- {
- if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
- throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
- }
-
- return $this->pseudoClassTranslators[$pseudoClass]($xpath);
- }
-
- /**
- * @throws ExpressionErrorException
- */
- public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr
- {
- if (!isset($this->attributeMatchingTranslators[$operator])) {
- throw new ExpressionErrorException(sprintf('Powered_Cache_Attribute matcher operator "%s" not supported.', $operator));
- }
-
- return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
- }
-
- /**
- * @return SelectorNode[]
- */
- private function parseSelectors(string $css): array
- {
- foreach ($this->shortcutParsers as $shortcut) {
- $tokens = $shortcut->parse($css);
-
- if (!empty($tokens)) {
- return $tokens;
- }
- }
-
- return $this->mainParser->parse($css);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
deleted file mode 100644
index 2aae319..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
+++ /dev/null
@@ -1,37 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-
-/**
- * XPath expression translator interface.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-interface TranslatorInterface
-{
- /**
- * Translates a CSS selector to an XPath expression.
- */
- public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string;
-
- /**
- * Translates a parsed selector node to an XPath expression.
- */
- public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string;
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php
deleted file mode 100644
index 8ab83fe..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php
+++ /dev/null
@@ -1,111 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath;
-
-/**
- * XPath expression translator interface.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon
- *
- * @internal
- */
-class XPathExpr
-{
- private $path;
- private $element;
- private $condition;
-
- public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false)
- {
- $this->path = $path;
- $this->element = $element;
- $this->condition = $condition;
-
- if ($starPrefix) {
- $this->addStarPrefix();
- }
- }
-
- public function getElement(): string
- {
- return $this->element;
- }
-
- /**
- * @return $this
- */
- public function addCondition(string $condition): self
- {
- $this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
-
- return $this;
- }
-
- public function getCondition(): string
- {
- return $this->condition;
- }
-
- /**
- * @return $this
- */
- public function addNameTest(): self
- {
- if ('*' !== $this->element) {
- $this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
- $this->element = '*';
- }
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function addStarPrefix(): self
- {
- $this->path .= '*/';
-
- return $this;
- }
-
- /**
- * Joins another XPathExpr with a combiner.
- *
- * @return $this
- */
- public function join(string $combiner, self $expr): self
- {
- $path = $this->__toString().$combiner;
-
- if ('*/' !== $expr->path) {
- $path .= $expr->path;
- }
-
- $this->path = $path;
- $this->element = $expr->element;
- $this->condition = $expr->condition;
-
- return $this;
- }
-
- public function __toString(): string
- {
- $path = $this->path.$this->element;
- $condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';
-
- return $path.$condition;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json b/includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json
deleted file mode 100644
index f0b7124..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "name": "symfony/css-selector",
- "type": "library",
- "description": "Converts CSS selectors to XPath expressions",
- "keywords": [],
- "homepage": "https://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Jean-François Simon",
- "email": "jeanfrancois.simon@sensiolabs.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=7.2.5",
- "symfony/polyfill-php80": "^1.16"
- },
- "autoload": {
- "psr-4": { "Symfony\\Component\\CssSelector\\": "" },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "minimum-stability": "dev"
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist b/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
deleted file mode 100644
index a8e537e..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
- ./Tests/
-
-
-
-
-
- ./
-
- ./Resources
- ./Tests
- ./vendor
-
-
-
-
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE b/includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE
deleted file mode 100644
index 0ed3a24..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2020-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
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php
deleted file mode 100644
index bec0308..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php
+++ /dev/null
@@ -1,115 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Polyfill\Php80;
-
-/**
- * @author Ion Bazan
- * @author Nico Oelgart
- * @author Nicolas Grekas
- *
- * @internal
- */
-final class Php80
-{
- public static function fdiv(float $dividend, float $divisor): float
- {
- return @($dividend / $divisor);
- }
-
- public static function get_debug_type($value): string
- {
- switch (true) {
- case null === $value: return 'null';
- case \is_bool($value): return 'bool';
- case \is_string($value): return 'string';
- case \is_array($value): return 'array';
- case \is_int($value): return 'int';
- case \is_float($value): return 'float';
- case \is_object($value): break;
- case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
- default:
- if (null === $type = @get_resource_type($value)) {
- return 'unknown';
- }
-
- if ('Unknown' === $type) {
- $type = 'closed';
- }
-
- return "resource ($type)";
- }
-
- $class = \get_class($value);
-
- if (false === strpos($class, '@')) {
- return $class;
- }
-
- return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
- }
-
- public static function get_resource_id($res): int
- {
- if (!\is_resource($res) && null === @get_resource_type($res)) {
- throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
- }
-
- return (int) $res;
- }
-
- public static function preg_last_error_msg(): string
- {
- switch (preg_last_error()) {
- case \PREG_INTERNAL_ERROR:
- return 'Internal error';
- case \PREG_BAD_UTF8_ERROR:
- return 'Malformed UTF-8 characters, possibly incorrectly encoded';
- case \PREG_BAD_UTF8_OFFSET_ERROR:
- return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
- case \PREG_BACKTRACK_LIMIT_ERROR:
- return 'Backtrack limit exhausted';
- case \PREG_RECURSION_LIMIT_ERROR:
- return 'Recursion limit exhausted';
- case \PREG_JIT_STACKLIMIT_ERROR:
- return 'JIT stack limit exhausted';
- case \PREG_NO_ERROR:
- return 'No error';
- default:
- return 'Unknown error';
- }
- }
-
- public static function str_contains(string $haystack, string $needle): bool
- {
- return '' === $needle || false !== strpos($haystack, $needle);
- }
-
- public static function str_starts_with(string $haystack, string $needle): bool
- {
- return 0 === strncmp($haystack, $needle, \strlen($needle));
- }
-
- public static function str_ends_with(string $haystack, string $needle): bool
- {
- if ('' === $needle || $needle === $haystack) {
- return true;
- }
-
- if ('' === $haystack) {
- return false;
- }
-
- $needleLength = \strlen($needle);
-
- return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php
deleted file mode 100644
index e5fa75a..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php
+++ /dev/null
@@ -1,106 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Polyfill\Php80;
-
-/**
- * @author Fedonyuk Anton
- *
- * @internal
- */
-class PhpToken implements \Stringable
-{
- /**
- * @var int
- */
- public $id;
-
- /**
- * @var string
- */
- public $text;
-
- /**
- * @var -1|positive-int
- */
- public $line;
-
- /**
- * @var int
- */
- public $pos;
-
- /**
- * @param -1|positive-int $line
- */
- public function __construct(int $id, string $text, int $line = -1, int $position = -1)
- {
- $this->id = $id;
- $this->text = $text;
- $this->line = $line;
- $this->pos = $position;
- }
-
- public function getTokenName(): ?string
- {
- if ('UNKNOWN' === $name = token_name($this->id)) {
- $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
- }
-
- return $name;
- }
-
- /**
- * @param int|string|array $kind
- */
- public function is($kind): bool
- {
- foreach ((array) $kind as $value) {
- if (\in_array($value, [$this->id, $this->text], true)) {
- return true;
- }
- }
-
- return false;
- }
-
- public function isIgnorable(): bool
- {
- return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
- }
-
- public function __toString(): string
- {
- return (string) $this->text;
- }
-
- /**
- * @return list
- */
- public static function tokenize(string $code, int $flags = 0): array
- {
- $line = 1;
- $position = 0;
- $tokens = token_get_all($code, $flags);
- foreach ($tokens as $index => $token) {
- if (\is_string($token)) {
- $id = \ord($token);
- $text = $token;
- } else {
- [$id, $text, $line] = $token;
- }
- $tokens[$index] = new static($id, $text, $line, $position);
- $position += \strlen($text);
- }
-
- return $tokens;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md b/includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md
deleted file mode 100644
index 3816c55..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-Symfony Polyfill / Php80
-========================
-
-This component provides features added to PHP 8.0 core:
-
-- [`Stringable`](https://php.net/stringable) interface
-- [`fdiv`](https://php.net/fdiv)
-- [`ValueError`](https://php.net/valueerror) class
-- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
-- `FILTER_VALIDATE_BOOL` constant
-- [`get_debug_type`](https://php.net/get_debug_type)
-- [`PhpToken`](https://php.net/phptoken) class
-- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
-- [`str_contains`](https://php.net/str_contains)
-- [`str_starts_with`](https://php.net/str_starts_with)
-- [`str_ends_with`](https://php.net/str_ends_with)
-- [`get_resource_id`](https://php.net/get_resource_id)
-
-More information can be found in the
-[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
-
-License
-=======
-
-This library is released under the [MIT license](LICENSE).
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php
deleted file mode 100644
index 2b95542..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php
+++ /dev/null
@@ -1,31 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-#[Attribute(Attribute::TARGET_CLASS)]
-final class Attribute
-{
- public const TARGET_CLASS = 1;
- public const TARGET_FUNCTION = 2;
- public const TARGET_METHOD = 4;
- public const TARGET_PROPERTY = 8;
- public const TARGET_CLASS_CONSTANT = 16;
- public const TARGET_PARAMETER = 32;
- public const TARGET_ALL = 63;
- public const IS_REPEATABLE = 64;
-
- /** @var int */
- public $flags;
-
- public function __construct(int $flags = self::TARGET_ALL)
- {
- $this->flags = $flags;
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php
deleted file mode 100644
index 903d87e..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
- class PhpToken extends PoweredCache\Dependencies\Symfony\Polyfill\Php80\PhpToken
- {
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php
deleted file mode 100644
index 7c62d75..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php
+++ /dev/null
@@ -1,20 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-if (\PHP_VERSION_ID < 80000) {
- interface Stringable
- {
- /**
- * @return string
- */
- public function __toString();
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php
deleted file mode 100644
index 01c6c6c..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-if (\PHP_VERSION_ID < 80000) {
- class UnhandledMatchError extends Error
- {
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php
deleted file mode 100644
index 783dbc2..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-if (\PHP_VERSION_ID < 80000) {
- class ValueError extends Error
- {
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php
deleted file mode 100644
index 3d6dc26..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php
+++ /dev/null
@@ -1,42 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-use PoweredCache\Dependencies\Symfony\Polyfill\Php80 as p;
-
-if (\PHP_VERSION_ID >= 80000) {
- return;
-}
-
-if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
- define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
-}
-
-if (!function_exists('fdiv')) {
- function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
-}
-if (!function_exists('preg_last_error_msg')) {
- function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
-}
-if (!function_exists('str_contains')) {
- function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
-}
-if (!function_exists('str_starts_with')) {
- function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
-}
-if (!function_exists('str_ends_with')) {
- function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
-}
-if (!function_exists('get_debug_type')) {
- function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
-}
-if (!function_exists('get_resource_id')) {
- function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
-}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json b/includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json
deleted file mode 100644
index a503b03..0000000
--- a/includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "symfony/polyfill-php80",
- "type": "library",
- "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
- "keywords": ["polyfill", "shim", "compatibility", "portable"],
- "homepage": "https://symfony.com",
- "license": "MIT",
- "authors": [
- {
- "name": "Ion Bazan",
- "email": "ion.bazan@gmail.com"
- },
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "require": {
- "php": ">=7.2"
- },
- "autoload": {
- "psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
- "files": [ "bootstrap.php" ],
- "classmap": [ "Resources/stubs" ]
- },
- "minimum-stability": "dev",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractDomParser.php b/includes/classes/Dependencies/voku/helper/AbstractDomParser.php
deleted file mode 100644
index 457594d..0000000
--- a/includes/classes/Dependencies/voku/helper/AbstractDomParser.php
+++ /dev/null
@@ -1,527 +0,0 @@
- ['[', ']', '{', '}'],
- 'tmp' => [
- '____SIMPLE_HTML_DOM__VOKU__SQUARE_BRACKET_LEFT____',
- '____SIMPLE_HTML_DOM__VOKU__SQUARE_BRACKET_RIGHT____',
- '____SIMPLE_HTML_DOM__VOKU__BRACKET_LEFT____',
- '____SIMPLE_HTML_DOM__VOKU__BRACKET_RIGHT____',
- ],
- ];
-
- /**
- * @var string[][]
- */
- protected static $domReplaceHelper = [
- 'orig' => ['&', '|', '+', '%', '@', ' [
- '____SIMPLE_HTML_DOM__VOKU__AMP____',
- '____SIMPLE_HTML_DOM__VOKU__PIPE____',
- '____SIMPLE_HTML_DOM__VOKU__PLUS____',
- '____SIMPLE_HTML_DOM__VOKU__PERCENT____',
- '____SIMPLE_HTML_DOM__VOKU__AT____',
- 'document = clone $this->document;
- }
-
- /**
- * @param string $name
- *
- * @return string|null
- */
- abstract public function __get($name);
-
- /**
- * @return string
- */
- abstract public function __toString();
-
- /**
- * does nothing (only for api-compatibility-reasons)
- *
- * @return bool
- *
- * @deprecated
- */
- public function clear(): bool
- {
- return true;
- }
-
- /**
- * Create DOMDocument from HTML.
- *
- * @param string $html
- * @param int|null $libXMLExtraOptions
- *
- * @return \DOMDocument
- */
- abstract protected function createDOMDocument(string $html, $libXMLExtraOptions = null): \DOMDocument;
-
- /**
- * @param string $content
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- protected function decodeHtmlEntity(string $content, bool $multiDecodeNewHtmlEntity): string
- {
- if ($multiDecodeNewHtmlEntity) {
- if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
- $content = UTF8::rawurldecode($content, true);
- } else {
- do {
- $content_compare = $content;
-
- $content = \rawurldecode(
- \html_entity_decode(
- $content,
- \ENT_QUOTES | \ENT_HTML5
- )
- );
- } while ($content_compare !== $content);
- }
- } else {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
- $content = UTF8::rawurldecode($content, false);
- } else {
- $content = \rawurldecode(
- \html_entity_decode(
- $content,
- \ENT_QUOTES | \ENT_HTML5
- )
- );
- }
- }
-
- return $content;
- }
-
- /**
- * Find list of nodes with a CSS selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return mixed
- */
- abstract public function find(string $selector, $idx = null);
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return mixed
- */
- abstract public function findMulti(string $selector);
-
- /**
- * Find nodes with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return mixed
- */
- abstract public function findMultiOrFalse(string $selector);
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return mixed
- */
- abstract public function findOne(string $selector);
-
- /**
- * Find one node with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return mixed
- */
- abstract public function findOneOrFalse(string $selector);
-
- /**
- * @return \DOMDocument
- */
- public function getDocument(): \DOMDocument
- {
- return $this->document;
- }
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- abstract public function html(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
- {
- // init
- $text = '';
-
- if ($this->document->documentElement) {
- foreach ($this->document->documentElement->childNodes as $node) {
- $text .= $this->document->saveHTML($node);
- }
- }
-
- return $this->fixHtmlOutput($text, $multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
- {
- // init
- $text = '';
-
- if ($this->document->documentElement) {
- foreach ($this->document->documentElement->childNodes as $node) {
- $text .= $this->document->saveXML($node);
- }
- }
-
- return $this->fixHtmlOutput($text, $multiDecodeNewHtmlEntity);
- }
-
- /**
- * Load HTML from string.
- *
- * @param string $html
- * @param int|null $libXMLExtraOptions
- *
- * @return DomParserInterface
- */
- abstract public function loadHtml(string $html, $libXMLExtraOptions = null): DomParserInterface;
-
- /**
- * Load HTML from file.
- *
- * @param string $filePath
- * @param int|null $libXMLExtraOptions
- *
- * @throws \RuntimeException
- *
- * @return DomParserInterface
- */
- abstract public function loadHtmlFile(string $filePath, $libXMLExtraOptions = null): DomParserInterface;
-
- /**
- * Save the html-dom as string.
- *
- * @param string $filepath
- *
- * @return string
- */
- public function save(string $filepath = ''): string
- {
- $string = $this->html();
- if ($filepath !== '') {
- \file_put_contents($filepath, $string, \LOCK_EX);
- }
-
- return $string;
- }
-
- /**
- * @param callable $functionName
- *
- * @phpstan-param callable(\PoweredCache\Dependencies\voku\helper\XmlDomParser|\PoweredCache\Dependencies\voku\helper\HtmlDomParser): void $functionName
- *
- * @return void
- */
- public function set_callback($functionName)
- {
- static::$callback = $functionName;
- }
-
- /**
- * Get dom node's plain text.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function text(bool $multiDecodeNewHtmlEntity = false): string
- {
- return $this->fixHtmlOutput($this->document->textContent, $multiDecodeNewHtmlEntity);
- }
-
- /**
- * Get the HTML as XML or plain XML if needed.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $htmlToXml
- * @param bool $removeXmlHeader
- * @param int $options
- *
- * @return string
- */
- public function xml(
- bool $multiDecodeNewHtmlEntity = false,
- bool $htmlToXml = true,
- bool $removeXmlHeader = true,
- int $options = \LIBXML_NOEMPTYTAG
- ): string {
- $xml = $this->document->saveXML(null, $options);
- if ($xml === false) {
- return '';
- }
-
- if ($removeXmlHeader) {
- $xml = \ltrim((string) \preg_replace('/<\?xml.*\?>/', '', $xml));
- }
-
- if ($htmlToXml) {
- $return = $this->fixHtmlOutput($xml, $multiDecodeNewHtmlEntity);
- } else {
- $xml = $this->decodeHtmlEntity($xml, $multiDecodeNewHtmlEntity);
-
- $return = self::putReplacedBackToPreserveHtmlEntities($xml);
- }
-
- return $return;
- }
-
- /**
- * Get the encoding to use.
- *
- * @return string
- */
- protected function getEncoding(): string
- {
- return $this->encoding;
- }
-
- /**
- * workaround for bug: https://bugs.php.net/bug.php?id=74628
- *
- * @param string $html
- *
- * @return void
- */
- protected function html5FallbackForScriptTags(string &$html)
- {
- // regEx for e.g.: [';
- },
- $html
- );
-
- if ($htmlTmp !== null) {
- $html = $htmlTmp;
- }
- }
-
- /**
- * @param string $html
- *
- * @return string
- */
- public static function putReplacedBackToPreserveHtmlEntities(string $html, bool $putBrokenReplacedBack = true): string
- {
- static $DOM_REPLACE__HELPER_CACHE = null;
-
- if ($DOM_REPLACE__HELPER_CACHE === null) {
- $DOM_REPLACE__HELPER_CACHE['tmp'] = \array_merge(
- self::$domLinkReplaceHelper['tmp'],
- self::$domReplaceHelper['tmp']
- );
- $DOM_REPLACE__HELPER_CACHE['orig'] = \array_merge(
- self::$domLinkReplaceHelper['orig'],
- self::$domReplaceHelper['orig']
- );
-
- $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__start'] = '<' . self::$domHtmlWrapperHelper . '>';
- $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__end'] = '' . self::$domHtmlWrapperHelper . '>';
-
- $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__start'] = '';
- $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__end'] = '';
-
- $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__start_broken'] = self::$domHtmlWrapperHelper . '>';
- $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__end_broken'] = '' . self::$domHtmlWrapperHelper;
-
- $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__start_broken'] = '';
- $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__end_broken'] = '';
-
- $DOM_REPLACE__HELPER_CACHE['tmp']['html_special_script__start'] = '<' . self::$domHtmlSpecialScriptHelper;
- $DOM_REPLACE__HELPER_CACHE['tmp']['html_special_script__end'] = '' . self::$domHtmlSpecialScriptHelper . '>';
-
- $DOM_REPLACE__HELPER_CACHE['orig']['html_special_script__start'] = ' 0
- ) {
- $html = \str_ireplace(self::$domBrokenReplaceHelper['tmp'], self::$domBrokenReplaceHelper['orig'], $html);
- }
-
- return \str_ireplace($DOM_REPLACE__HELPER_CACHE['tmp'], $DOM_REPLACE__HELPER_CACHE['orig'], $html);
- }
-
- /**
- * @param string $html
- *
- * @return string
- */
- public static function replaceToPreserveHtmlEntities(string $html): string
- {
- // init
- $linksNew = [];
- $linksOld = [];
-
- if (\strpos($html, 'http') !== false) {
- // regEx for e.g.: [https://www.domain.de/foo.php?foobar=1&email=lars%40moelleken.org&guid=test1233312&{{foo}}#foo]
- $regExUrl = '/(\[?\bhttps?:\/\/[^\s<>]+(?:\(\w+\)|[^[:punct:]\s]|\/|}|]))/i';
- \preg_match_all($regExUrl, $html, $linksOld);
-
- if (!empty($linksOld[1])) {
- $linksOld = $linksOld[1];
- foreach ((array) $linksOld as $linkKey => $linkOld) {
- $linksNew[$linkKey] = \str_replace(
- self::$domLinkReplaceHelper['orig'],
- self::$domLinkReplaceHelper['tmp'],
- $linkOld
- );
- }
- }
- }
-
- $linksNewCount = \count($linksNew);
- if ($linksNewCount > 0 && \count($linksOld) === $linksNewCount) {
- $search = \array_merge($linksOld, self::$domReplaceHelper['orig']);
- $replace = \array_merge($linksNew, self::$domReplaceHelper['tmp']);
- } else {
- $search = self::$domReplaceHelper['orig'];
- $replace = self::$domReplaceHelper['tmp'];
- }
-
- return \str_replace($search, $replace, $html);
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php
deleted file mode 100644
index fdca9af..0000000
--- a/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php
+++ /dev/null
@@ -1,255 +0,0 @@
- 'childNodes',
- 'first_child' => 'firstChild',
- 'last_child' => 'lastChild',
- 'next_sibling' => 'nextSibling',
- 'prev_sibling' => 'previousSibling',
- 'parent' => 'parentNode',
- 'outertext' => 'html',
- 'outerhtml' => 'html',
- 'innertext' => 'innerHtml',
- 'innerhtml' => 'innerHtml',
- 'innerhtmlkeep' => 'innerHtmlKeep',
- ];
-
- /**
- * @var string[]
- */
- protected static $stringDomNodes = [
- 'id',
- 'prefix',
- 'content'
- ];
-
- /**
- * @var \DOMElement|\DOMNode|null
- */
- protected $node;
-
- /**
- * @var SimpleHtmlAttributes|null
- */
- private $classListCache;
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleHtmlDomInterface|string|null
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /**
- * @param string $name
- *
- * @return SimpleHtmlAttributes|string|string[]|null
- */
- public function __get($name)
- {
- $nameOrig = $name;
- $name = \strtolower($name);
-
- switch ($name) {
- case 'outerhtml':
- case 'outertext':
- case 'html':
- return $this->html();
- case 'innerhtml':
- case 'innertext':
- return $this->innerHtml();
- case 'innerhtmlkeep':
- return $this->innerHtml(false, false);
- case 'text':
- case 'plaintext':
- return $this->text();
- case 'tag':
- return $this->node->nodeName ?? '';
- case 'attr':
- return $this->getAllAttributes();
- case 'classlist':
- if ($this->classListCache === null) {
- $this->classListCache = new SimpleHtmlAttributes($this->node ?? null, 'class');
- }
-
- return $this->classListCache;
- default:
- if ($this->node && \property_exists($this->node, $nameOrig)) {
- if (\is_string($this->node->{$nameOrig})) {
- return HtmlDomParser::putReplacedBackToPreserveHtmlEntities($this->node->{$nameOrig});
- }
-
- return $this->node->{$nameOrig};
- }
-
- return $this->getAttribute($name);
- }
- }
-
- /**
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function __invoke($selector, $idx = null)
- {
- return $this->find($selector, $idx);
- }
-
- /**
- * @param string $name
- *
- * @return bool
- */
- public function __isset($name)
- {
- $nameOrig = $name;
- $name = \strtolower($name);
-
- switch ($name) {
- case 'outertext':
- case 'outerhtml':
- case 'innertext':
- case 'innerhtml':
- case 'innerhtmlkeep':
- case 'plaintext':
- case 'text':
- case 'tag':
- return true;
- default:
- if ($this->node && \property_exists($this->node, $nameOrig)) {
- return isset($this->node->{$nameOrig});
- }
-
- return $this->hasAttribute($name);
- }
- }
-
- /**
- * @param string $name
- * @param mixed $value
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function __set($name, $value)
- {
- $nameOrig = $name;
- $name = \strtolower($name);
-
- switch ($name) {
- case 'outerhtml':
- case 'outertext':
- return $this->replaceNodeWithString($value);
- case 'innertext':
- case 'innerhtml':
- return $this->replaceChildWithString($value);
- case 'innerhtmlkeep':
- return $this->replaceChildWithString($value, false);
- case 'plaintext':
- return $this->replaceTextWithString($value);
- case 'classlist':
- $name = 'class';
- $nameOrig = 'class';
- // no break
- default:
- if ($this->node && \property_exists($this->node, $nameOrig)) {
- // INFO: Cannot assign null to property DOMNode::* of type string
- if (in_array($nameOrig, self::$stringDomNodes)) {
- $value = (string)$value;
- }
-
- if (!is_null($value)) {
- return $this->node->{$nameOrig} = $value;
- }
- }
-
- return $this->setAttribute($name, $value);
- }
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- return $this->html();
- }
-
- /**
- * @param string $name
- *
- * @return void
- */
- public function __unset($name)
- {
- /** @noinspection UnusedFunctionResultInspection */
- $this->removeAttribute($name);
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return mixed
- */
- abstract public function find(string $selector, $idx = null);
-
- /**
- * @return string[]|null
- */
- abstract public function getAllAttributes();
-
- abstract public function getAttribute(string $name): string;
-
- abstract public function hasAttribute(string $name): bool;
-
- abstract public function html(bool $multiDecodeNewHtmlEntity = false): string;
-
- abstract public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
-
- abstract public function removeAttribute(string $name): SimpleHtmlDomInterface;
-
- abstract protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface;
-
- abstract protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface;
-
- /**
- * @param string $string
- *
- * @return SimpleHtmlDomInterface
- */
- abstract protected function replaceTextWithString($string): SimpleHtmlDomInterface;
-
- /**
- * @param string $name
- * @param string|null $value
- * @param bool $strictEmptyValueCheck
- *
- * @return SimpleHtmlDomInterface
- */
- abstract public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface;
-
- abstract public function text(): string;
-}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php
deleted file mode 100644
index 0033ddf..0000000
--- a/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php
+++ /dev/null
@@ -1,80 +0,0 @@
-count();
- }
-
- if ($this->count() > 0) {
- $return = [];
-
- foreach ($this as $node) {
- if ($node instanceof SimpleHtmlDomInterface) {
- $return[] = $node->{$name};
- }
- }
-
- return $return;
- }
-
- if ($name === 'plaintext' || $name === 'outertext') {
- return [];
- }
-
- return null;
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleHtmlDomNodeInterface|SimpleHtmlDomNodeInterface[]|null
- */
- public function __invoke($selector, $idx = null)
- {
- return $this->find($selector, $idx);
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- // init
- $html = '';
-
- foreach ($this as $node) {
- $html .= $node->outertext;
- }
-
- return $html;
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleHtmlDomNodeInterface|SimpleHtmlDomNodeInterface[]|null
- */
- abstract public function find(string $selector, $idx = null);
-}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php
deleted file mode 100644
index dae961c..0000000
--- a/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php
+++ /dev/null
@@ -1,217 +0,0 @@
- 'childNodes',
- 'first_child' => 'firstChild',
- 'last_child' => 'lastChild',
- 'next_sibling' => 'nextSibling',
- 'prev_sibling' => 'previousSibling',
- 'parent' => 'parentNode',
- ];
-
- /**
- * @var \DOMElement|\DOMNode|null
- */
- protected $node;
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleXmlDomInterface|string|null
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /**
- * @param string $name
- *
- * @return array|string|null
- */
- public function __get($name)
- {
- $nameOrig = $name;
- $name = \strtolower($name);
-
- switch ($name) {
- case 'xml':
- return $this->xml();
- case 'plaintext':
- return $this->text();
- case 'tag':
- return $this->node->nodeName ?? '';
- case 'attr':
- return $this->getAllAttributes();
- default:
- if ($this->node && \property_exists($this->node, $nameOrig)) {
- return $this->node->{$nameOrig};
- }
-
- return $this->getAttribute($name);
- }
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function __invoke($selector, $idx = null)
- {
- return $this->find($selector, $idx);
- }
-
- /**
- * @param string $name
- *
- * @return bool
- */
- public function __isset($name)
- {
- $nameOrig = $name;
- $name = \strtolower($name);
-
- switch ($name) {
- case 'outertext':
- case 'outerhtml':
- case 'innertext':
- case 'innerhtml':
- case 'innerhtmlkeep':
- case 'plaintext':
- case 'text':
- case 'tag':
- return true;
- default:
- if ($this->node && \property_exists($this->node, $nameOrig)) {
- return isset($this->node->{$nameOrig});
- }
-
- return $this->hasAttribute($name);
- }
- }
-
- /**
- * @param string $name
- * @param mixed $value
- *
- * @return SimpleXmlDomInterface|null
- */
- public function __set($name, $value)
- {
- $nameOrig = $name;
- $name = \strtolower($name);
-
- switch ($name) {
- case 'outerhtml':
- case 'outertext':
- return $this->replaceNodeWithString($value);
- case 'innertext':
- case 'innerhtml':
- return $this->replaceChildWithString($value);
- case 'innerhtmlkeep':
- return $this->replaceChildWithString($value, false);
- case 'plaintext':
- return $this->replaceTextWithString($value);
- default:
- if ($this->node && \property_exists($this->node, $nameOrig)) {
- return $this->node->{$nameOrig} = $value;
- }
-
- return $this->setAttribute($name, $value);
- }
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- return $this->xml();
- }
-
- /**
- * @param string $name
- *
- * @return void
- */
- public function __unset($name)
- {
- /** @noinspection UnusedFunctionResultInspection */
- $this->removeAttribute($name);
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- abstract public function find(string $selector, $idx = null);
-
- /**
- * @return string[]|null
- */
- abstract public function getAllAttributes();
-
- /**
- * @param string $name
- *
- * @return string
- */
- abstract public function getAttribute(string $name): string;
-
- /**
- * @param string $name
- *
- * @return bool
- */
- abstract public function hasAttribute(string $name): bool;
-
- abstract public function innerXml(bool $multiDecodeNewHtmlEntity = false): string;
-
- abstract public function removeAttribute(string $name): SimpleXmlDomInterface;
-
- abstract protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleXmlDomInterface;
-
- abstract protected function replaceNodeWithString(string $string): SimpleXmlDomInterface;
-
- /**
- * @param string $string
- *
- * @return SimpleXmlDomInterface
- */
- abstract protected function replaceTextWithString($string): SimpleXmlDomInterface;
-
- /**
- * @param string $name
- * @param string|null $value
- * @param bool $strictEmptyValueCheck
- *
- * @return SimpleXmlDomInterface
- */
- abstract public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleXmlDomInterface;
-
- abstract public function text(): string;
-
- abstract public function xml(bool $multiDecodeNewHtmlEntity = false): string;
-}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php
deleted file mode 100644
index dd7be0a..0000000
--- a/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php
+++ /dev/null
@@ -1,80 +0,0 @@
-count();
- }
-
- if ($this->count() > 0) {
- $return = [];
-
- foreach ($this as $node) {
- if ($node instanceof SimpleXmlDomInterface) {
- $return[] = $node->{$name};
- }
- }
-
- return $return;
- }
-
- if ($name === 'plaintext' || $name === 'outertext') {
- return [];
- }
-
- return null;
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomNodeInterface|SimpleXmlDomNodeInterface[]|null
- */
- public function __invoke($selector, $idx = null)
- {
- return $this->find($selector, $idx);
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- // init
- $html = '';
-
- foreach ($this as $node) {
- $html .= $node->outertext;
- }
-
- return $html;
- }
-
- /**
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomNodeInterface|SimpleXmlDomNodeInterface[]|null
- */
- abstract public function find(string $selector, $idx = null);
-}
diff --git a/includes/classes/Dependencies/voku/helper/DomParserInterface.php b/includes/classes/Dependencies/voku/helper/DomParserInterface.php
deleted file mode 100644
index f6e3513..0000000
--- a/includes/classes/Dependencies/voku/helper/DomParserInterface.php
+++ /dev/null
@@ -1,201 +0,0 @@
-');
-
- $domElement = $dom->findOneOrFalse($htmlCssSelector);
- if ($domElement === false) {
- return $html;
- }
- $attributes = $domElement->getAllAttributes();
- if (!$attributes) {
- return $html;
- }
-
- $domElementNew = $domNew->findOneOrFalse('textarea');
- if ($domElementNew === false) {
- return $html;
- }
- $attributesNew = $domElementNew->getAllAttributes();
- if (!$attributesNew) {
- return $html;
- }
-
- foreach ($attributesNew as $attributeNameNew => $attributeValueNew) {
- $attributeNameNew = \strtolower($attributeNameNew);
-
- if (
- $attributeNameNew === 'class'
- ||
- $attributeNameNew === 'style'
- ||
- \strpos($attributeNameNew, 'on') === 0 // e.g. onClick, ...
- ) {
- if (isset($attributes[$attributeNameNew])) {
- $attributes[$attributeNameNew] .= ' ' . $attributeValueNew;
- } else {
- $attributes[$attributeNameNew] = $attributeValueNew;
- }
- } else {
- $attributes[$attributeNameNew] = $attributeValueNew;
- }
- }
-
- foreach ($attributes as $attributeName => $attributeValue) {
- $domElement->setAttribute($attributeName, $attributeValue, true);
- }
-
- return $domElement->html();
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/HtmlDomParser.php b/includes/classes/Dependencies/voku/helper/HtmlDomParser.php
deleted file mode 100644
index 8f87676..0000000
--- a/includes/classes/Dependencies/voku/helper/HtmlDomParser.php
+++ /dev/null
@@ -1,1228 +0,0 @@
-Get dom node's outer html (alias for "outerHtml").
- * @property-read string $outerHtml
- * Get dom node's outer html.
- * @property-read string $innerText
- * Get dom node's inner html (alias for "innerHtml").
- * @property-read string $innerHtml
- * Get dom node's inner html.
- * @property-read string $plaintext
- * Get dom node's plain text.
- *
- * @method string outerText()
- * Get dom node's outer html (alias for "outerHtml()").
- * @method string outerHtml()
- * Get dom node's outer html.
- * @method string innerText()
- * Get dom node's inner html (alias for "innerHtml()").
- * @method HtmlDomParser load(string $html)
- * Load HTML from string.
- * @method HtmlDomParser load_file(string $html)
- * Load HTML from file.
- * @method static HtmlDomParser file_get_html($filePath, $libXMLExtraOptions = null)
- * Load HTML from file.
- * @method static HtmlDomParser str_get_html($html, $libXMLExtraOptions = null)
- * Load HTML from string.
- */
-class HtmlDomParser extends AbstractDomParser
-{
- /**
- * @var callable|null
- *
- * @phpstan-var null|callable(string $cssSelectorString, string $xPathString, \DOMXPath, \PoweredCache\Dependencies\voku\helper\HtmlDomParser): string
- */
- private $callbackXPathBeforeQuery;
-
- /**
- * @var callable|null
- *
- * @phpstan-var null|callable(string $htmlString, \PoweredCache\Dependencies\voku\helper\HtmlDomParser): string
- */
- private $callbackBeforeCreateDom;
-
- /**
- * @var string[]
- */
- protected static $functionAliases = [
- 'outertext' => 'html',
- 'outerhtml' => 'html',
- 'innertext' => 'innerHtml',
- 'innerhtml' => 'innerHtml',
- 'load' => 'loadHtml',
- 'load_file' => 'loadHtmlFile',
- ];
-
- /**
- * @var string[]
- */
- protected $templateLogicSyntaxInSpecialScriptTags = [
- '+',
- '<%',
- '{%',
- '{{',
- ];
-
- /**
- * The properties specified for each special script tag is an array.
- *
- * ```php
- * protected $specialScriptTags = [
- * 'text/html',
- * 'text/template',
- * 'text/x-custom-template',
- * 'text/x-handlebars-template'
- * ]
- * ```
- *
- * @var string[]
- */
- protected $specialScriptTags = [
- 'text/html',
- 'text/template',
- 'text/x-custom-template',
- 'text/x-handlebars-template',
- ];
-
- /**
- * @var string[]
- */
- protected $selfClosingTags = [
- 'area',
- 'base',
- 'br',
- 'col',
- 'command',
- 'embed',
- 'hr',
- 'img',
- 'input',
- 'keygen',
- 'link',
- 'meta',
- 'param',
- 'source',
- 'track',
- 'wbr',
- ];
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithoutHtml = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithoutWrapper = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithCommentWrapper = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithoutHeadWrapper = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithoutPTagWrapper = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithoutHtmlWrapper = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithoutBodyWrapper = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithMultiRoot = false;
-
- /**
- * @var bool
- */
- protected $isDOMDocumentCreatedWithFakeEndScript = false;
-
- /**
- * @var bool
- */
- protected $keepBrokenHtml = false;
-
- /**
- * @param \DOMNode|SimpleHtmlDomInterface|string $element HTML code or SimpleHtmlDomInterface, \DOMNode
- */
- public function __construct($element = null)
- {
- $this->document = new \DOMDocument('1.0', $this->getEncoding());
-
- // DOMDocument settings
- $this->document->preserveWhiteSpace = true;
- $this->document->formatOutput = true;
-
- if ($element instanceof SimpleHtmlDomInterface) {
- $element = $element->getNode();
- }
-
- if ($element instanceof \DOMNode) {
- $domNode = $this->document->importNode($element, true);
-
- if ($domNode instanceof \DOMNode) {
- $this->document->appendChild($domNode);
- }
-
- return;
- }
-
- if ($element !== null) {
- $this->loadHtml($element);
- }
- }
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @return bool|mixed
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist: ' . $name);
- }
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- * @throws \RuntimeException
- *
- * @return static
- */
- public static function __callStatic($name, $arguments)
- {
- $arguments0 = $arguments[0] ?? '';
-
- $arguments1 = $arguments[1] ?? null;
-
- if ($name === 'str_get_html') {
- $parser = new static();
-
- return $parser->loadHtml($arguments0, $arguments1);
- }
-
- if ($name === 'file_get_html') {
- $parser = new static();
-
- return $parser->loadHtmlFile($arguments0, $arguments1);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /** @noinspection MagicMethodsValidityInspection */
-
- /**
- * @param string $name
- *
- * @return string|null
- */
- public function __get($name)
- {
- $name = \strtolower($name);
-
- switch ($name) {
- case 'outerhtml':
- case 'outertext':
- return $this->html();
- case 'innerhtml':
- case 'innertext':
- return $this->innerHtml();
- case 'innerhtmlkeep':
- return $this->innerHtml(false, false);
- case 'text':
- case 'plaintext':
- return $this->text();
- }
-
- return null;
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- return $this->html();
- }
-
- /**
- * does nothing (only for api-compatibility-reasons)
- *
- * @return bool
- *
- * @deprecated
- */
- public function clear(): bool
- {
- return true;
- }
-
- /**
- * Create DOMDocument from HTML.
- *
- * @param string $html
- * @param int|null $libXMLExtraOptions
- * @param bool $useDefaultLibXMLOptions
- *
- * @return \DOMDocument
- */
- protected function createDOMDocument(string $html, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): \DOMDocument
- {
- if ($this->callbackBeforeCreateDom) {
- $html = \call_user_func($this->callbackBeforeCreateDom, $html, $this);
- }
-
- // Remove content before because otherwise the DOMDocument can not handle the input.
- $isDOMDocumentCreatedWithDoctype = false;
- if (\stripos($html, ']*)?>/sui', $html, $matches_before_doctype)
- &&
- \trim($matches_before_doctype[1])
- ) {
- $html = \str_replace($matches_before_doctype[1], '', $html);
- }
- }
-
- if ($this->keepBrokenHtml) {
- $html = $this->keepBrokenHtml(\trim($html));
- }
-
- if (\strpos($html, '<') === false) {
- $this->isDOMDocumentCreatedWithoutHtml = true;
- } elseif (\strpos(\ltrim($html), '<') !== 0) {
- $this->isDOMDocumentCreatedWithoutWrapper = true;
- }
-
- if (\strpos(\ltrim($html), '';
- }
- }
-
- return $html;
- }
-
- /**
- * @param \DOMNode $node
- *
- * @return string
- */
- private function getDoctype(\DOMNode $node): string
- {
- // check the doc-type only if it wasn't generated by DomDocument itself
- if (!$this->withDocType) {
- return '';
- }
-
- foreach ($node->childNodes as $child) {
- if (
- $child instanceof \DOMDocumentType
- &&
- $child->name
- ) {
- if (!$child->publicId && $child->systemId) {
- $tmpTypeSystem = 'SYSTEM';
- $tmpTypePublic = '';
- } else {
- $tmpTypeSystem = '';
- $tmpTypePublic = 'PUBLIC';
- }
-
- return 'name
- . ($child->publicId ? ' ' . $tmpTypePublic . ' "' . $child->publicId . '"' : '')
- . ($child->systemId ? ' ' . $tmpTypeSystem . ' "' . $child->systemId . '"' : '')
- . '>';
- }
- }
-
- return '';
- }
-
- /**
- * @return array
- */
- public function getDomainsToRemoveHttpPrefixFromAttributes(): array
- {
- return $this->domainsToRemoveHttpPrefixFromAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoOptimizeAttributes(): bool
- {
- return $this->doOptimizeAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoOptimizeViaHtmlDomParser(): bool
- {
- return $this->doOptimizeViaHtmlDomParser;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveComments(): bool
- {
- return $this->doRemoveComments;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDefaultAttributes(): bool
- {
- return $this->doRemoveDefaultAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDeprecatedAnchorName(): bool
- {
- return $this->doRemoveDeprecatedAnchorName;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDeprecatedScriptCharsetAttribute(): bool
- {
- return $this->doRemoveDeprecatedScriptCharsetAttribute;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDeprecatedTypeFromScriptTag(): bool
- {
- return $this->doRemoveDeprecatedTypeFromScriptTag;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDeprecatedTypeFromStylesheetLink(): bool
- {
- return $this->doRemoveDeprecatedTypeFromStylesheetLink;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDeprecatedTypeFromStyleAndLinkTag(): bool
- {
- return $this->doRemoveDeprecatedTypeFromStyleAndLinkTag;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDefaultMediaTypeFromStyleAndLinkTag(): bool
- {
- return $this->doRemoveDefaultMediaTypeFromStyleAndLinkTag;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveDefaultTypeFromButton(): bool
- {
- return $this->doRemoveDefaultTypeFromButton;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveEmptyAttributes(): bool
- {
- return $this->doRemoveEmptyAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveHttpPrefixFromAttributes(): bool
- {
- return $this->doRemoveHttpPrefixFromAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveHttpsPrefixFromAttributes(): bool
- {
- return $this->doRemoveHttpsPrefixFromAttributes;
- }
-
- /**
- * @return bool
- */
- public function isdoKeepHttpAndHttpsPrefixOnExternalAttributes(): bool
- {
- return $this->doKeepHttpAndHttpsPrefixOnExternalAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoMakeSameDomainsLinksRelative(): bool
- {
- return $this->doMakeSameDomainsLinksRelative;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveOmittedHtmlTags(): bool
- {
- return $this->doRemoveOmittedHtmlTags;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveOmittedQuotes(): bool
- {
- return $this->doRemoveOmittedQuotes;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveSpacesBetweenTags(): bool
- {
- return $this->doRemoveSpacesBetweenTags;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveValueFromEmptyInput(): bool
- {
- return $this->doRemoveValueFromEmptyInput;
- }
-
- /**
- * @return bool
- */
- public function isDoRemoveWhitespaceAroundTags(): bool
- {
- return $this->doRemoveWhitespaceAroundTags;
- }
-
- /**
- * @return bool
- */
- public function isDoSortCssClassNames(): bool
- {
- return $this->doSortCssClassNames;
- }
-
- /**
- * @return bool
- */
- public function isDoSortHtmlAttributes(): bool
- {
- return $this->doSortHtmlAttributes;
- }
-
- /**
- * @return bool
- */
- public function isDoSumUpWhitespace(): bool
- {
- return $this->doSumUpWhitespace;
- }
-
- /**
- * @return bool
- */
- public function isHTML4(): bool
- {
- return $this->isHTML4;
- }
-
- /**
- * @return bool
- */
- public function isXHTML(): bool
- {
- return $this->isXHTML;
- }
-
- /**
- * @param string $html
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function minify($html, $multiDecodeNewHtmlEntity = false): string
- {
- $html = (string) $html;
- if (!isset($html[0])) {
- return '';
- }
-
- $html = \trim($html);
- if (!$html) {
- return '';
- }
-
- // reset
- $this->protectedChildNodes = [];
-
- // save old content
- $origHtml = $html;
- $origHtmlLength = \strlen($html);
-
- // -------------------------------------------------------------------------
- // Minify the HTML via "HtmlDomParser"
- // -------------------------------------------------------------------------
-
- if ($this->doOptimizeViaHtmlDomParser) {
- $html = $this->minifyHtmlDom($html, $multiDecodeNewHtmlEntity);
- }
-
- // -------------------------------------------------------------------------
- // Trim whitespace from html-string. [protected html is still protected]
- // -------------------------------------------------------------------------
-
- // Remove extra white-space(s) between HTML attribute(s)
- if (\strpos($html, ' ') !== false) {
- $htmlCleaned = \preg_replace_callback(
- '#<([^/\s<>!]+)(?:\s+([^<>]*?)\s*|\s*)(/?)>#',
- static function ($matches) {
- return '<' . $matches[1] . \preg_replace('#([^\s=]+)(=([\'"]?)(.*?)\3)?(\s+|$)#su', ' $1$2', $matches[2]) . $matches[3] . '>';
- },
- $html
- );
- if ($htmlCleaned !== null) {
- $html = (string)$htmlCleaned;
- } else {
- $htmlCleaned = (string) \preg_replace_callback(
- '#<([^/\s<>!]+)(?:\s+([^<>]*)\s*|\s*)(/?)>#',
- static function ($matches) {
- return '<' . $matches[1] . \preg_replace('#([^\s=]+)(=([\'"]?)(.*?)\3)?(\s+|$)#su', ' $1$2', $matches[2]) . $matches[3] . '>';
- },
- $html
- );
- $html = $htmlCleaned;
- }
- }
-
- if ($this->doRemoveSpacesBetweenTags) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\strpos($html, ' ') !== false) {
- // Remove spaces that are between > and <
- $html = (string) \preg_replace('#(>)\s(<)#', '>$2', $html);
- }
- }
-
- // -------------------------------------------------------------------------
- // Restore protected HTML-code.
- // -------------------------------------------------------------------------
-
- if (\strpos($html, $this->protectedChildNodesHelper) !== false) {
- $html = (string) \preg_replace_callback(
- '/<(?' . $this->protectedChildNodesHelper . ')(? [^>]*)?>(?.*?)<\/' . $this->protectedChildNodesHelper . '>/',
- [$this, 'restoreProtectedHtml'],
- $html
- );
- }
-
- // -------------------------------------------------------------------------
- // Restore protected HTML-entities.
- // -------------------------------------------------------------------------
-
- if ($this->doOptimizeViaHtmlDomParser) {
- $html = HtmlDomParser::putReplacedBackToPreserveHtmlEntities($html);
- }
-
- // ------------------------------------
- // Final clean-up
- // ------------------------------------
-
- $html = \str_replace(
- [
- 'html>' . "\n",
- "\n" . ' ' . "\n",
- "\n" . '' . "\n",
- "\n" . ' ' . "\n",
- "\n" . '',
- ' ',
- '',
- ' ',
- '';
- $replacement[] = '<' . $selfClosingTag . '>';
- $replace[] = '<' . $selfClosingTag . ' />';
- $replacement[] = '<' . $selfClosingTag . '>';
- $replace[] = '>' . $selfClosingTag . '>';
- $replacement[] = '>';
- }
- $html = \str_replace(
- $replace,
- $replacement,
- $html
- );
-
- // ------------------------------------
- // check if compression worked
- // ------------------------------------
-
- if ($origHtmlLength < \strlen($html)) {
- $html = $origHtml;
- }
-
- return $html;
- }
-
- /**
- * @param \DOMNode $node
- *
- * @return \DOMNode|null
- */
- protected function getNextSiblingOfTypeDOMElement(\DOMNode $node)
- {
- do {
- /** @var \DOMElement|\DOMText|null $nodeTmp - false-positive error from phpstan */
- $nodeTmp = $node->nextSibling;
-
- if ($nodeTmp instanceof \DOMText) {
- if (
- \trim($nodeTmp->textContent) !== ''
- &&
- \strpos($nodeTmp->textContent, '<') === false
- ) {
- $node = $nodeTmp;
- } else {
- $node = $nodeTmp->nextSibling;
- }
- } else {
- $node = $nodeTmp;
- }
- } while (!($node === null || $node instanceof \DOMElement || $node instanceof \DOMText));
-
- return $node;
- }
-
- /**
- * Check if the current string is an conditional comment.
- *
- * INFO: since IE >= 10 conditional comment are not working anymore
- *
- *
- * HTML
- *
- * @param string $comment
- *
- * @return bool
- */
- private function isConditionalComment($comment): bool
- {
- if (\strpos($comment, '[if ') !== false) {
- /** @noinspection RegExpRedundantEscape */
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\preg_match('/^\[if [^\]]+\]/', $comment)) {
- return true;
- }
- }
-
- if (\strpos($comment, '[endif]') !== false) {
- /** @noinspection RegExpRedundantEscape */
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\preg_match('/\[endif\]$/', $comment)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Check if the current string is an special comment.
- *
- * @param string $comment
- *
- * @return bool
- */
- private function isSpecialComment($comment): bool
- {
- foreach ($this->specialHtmlCommentsStaringWith as $search) {
- if (\strpos($comment, $search) === 0) {
- return true;
- }
- }
-
- foreach ($this->specialHtmlCommentsEndingWith as $search) {
- if (\substr($comment, -\strlen($search)) === $search) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @param string $html
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- private function minifyHtmlDom($html, $multiDecodeNewHtmlEntity): string
- {
- // init dom
- $dom = new HtmlDomParser();
- $dom->useKeepBrokenHtml($this->keepBrokenHtml);
-
- if ($this->templateLogicSyntaxInSpecialScriptTags !== null) {
- $dom->overwriteTemplateLogicSyntaxInSpecialScriptTags($this->templateLogicSyntaxInSpecialScriptTags);
- }
-
- if ($this->specialScriptTags !== null) {
- $dom->overwriteSpecialScriptTags($this->specialScriptTags);
- }
-
- $dom->getDocument()->preserveWhiteSpace = false; // remove redundant white space
- $dom->getDocument()->formatOutput = false; // do not formats output with indentation
-
- // Remove content before because otherwise the DOMDocument can not handle the input.
- if (\stripos($html, ']*)?>/sui', $html, $matches_before_doctype)
- &&
- \trim($matches_before_doctype[1])
- ) {
- $html = \str_replace($matches_before_doctype[1], '', $html);
- }
- }
-
- // load dom
- $dom->loadHtml($html);
-
- $this->withDocType = (\stripos($html, 'getDoctype($dom->getDocument());
-
- if ($doctypeStr) {
- $this->isHTML4 = \strpos($doctypeStr, 'html4') !== false;
- $this->isXHTML = \strpos($doctypeStr, 'xhtml1') !== false;
- }
-
- // -------------------------------------------------------------------------
- // Protect HTML tags first.
- // -------------------------------------------------------------------------
-
- $dom = $this->protectTagHelper($dom, 'nocompress');
-
- // -------------------------------------------------------------------------
- // Notify the Observer before the minification.
- // -------------------------------------------------------------------------
-
- foreach ($dom->findMulti('*') as $element) {
- $this->notifyObserversAboutDomElementBeforeMinification($element);
- }
-
- // -------------------------------------------------------------------------
- // Protect HTML tags and conditional comments.
- // -------------------------------------------------------------------------
-
- $dom = $this->protectTags($dom);
-
- // -------------------------------------------------------------------------
- // Remove default HTML comments. [protected html is still protected]
- // -------------------------------------------------------------------------
-
- if ($this->doRemoveComments) {
- $dom = $this->removeComments($dom);
- }
-
- // -------------------------------------------------------------------------
- // Sum-Up extra whitespace from the Dom. [protected html is still protected]
- // -------------------------------------------------------------------------
-
- if ($this->doSumUpWhitespace) {
- $dom = $this->sumUpWhitespace($dom);
- }
-
- foreach ($dom->findMulti('*') as $element) {
- // -------------------------------------------------------------------------
- // Remove whitespace around tags. [protected html is still protected]
- // -------------------------------------------------------------------------
-
- if ($this->doRemoveWhitespaceAroundTags) {
- $this->removeWhitespaceAroundTags($element);
- }
-
- // -------------------------------------------------------------------------
- // Notify the Observer after the minification.
- // -------------------------------------------------------------------------
-
- $this->notifyObserversAboutDomElementAfterMinification($element);
- }
-
- // -------------------------------------------------------------------------
- // Convert the Dom into a string.
- // -------------------------------------------------------------------------
-
- return $dom->fixHtmlOutput(
- $doctypeStr . $this->domNodeToString($dom->getDocument()),
- $multiDecodeNewHtmlEntity
- );
- }
-
- /**
- * @param SimpleHtmlDomInterface $domElement
- *
- * @return void
- */
- private function notifyObserversAboutDomElementAfterMinification(SimpleHtmlDomInterface $domElement)
- {
- foreach ($this->domLoopObservers as $observer) {
- $observer->domElementAfterMinification($domElement, $this);
- }
- }
-
- /**
- * @param SimpleHtmlDomInterface $domElement
- *
- * @return void
- */
- private function notifyObserversAboutDomElementBeforeMinification(SimpleHtmlDomInterface $domElement)
- {
- foreach ($this->domLoopObservers as $observer) {
- $observer->domElementBeforeMinification($domElement, $this);
- }
- }
-
- /**
- * @param HtmlDomParser $dom
- * @param string $selector
- *
- * @return HtmlDomParser
- */
- private function protectTagHelper(HtmlDomParser $dom, string $selector): HtmlDomParser
- {
- foreach ($dom->findMulti($selector) as $element) {
- if ($element->isRemoved()) {
- continue;
- }
-
- $parentNode = $element->parentNode();
- if ($parentNode->nodeValue !== null) {
- $this->protectedChildNodes[$this->protected_tags_counter] = $parentNode->innerHtml();
- $parentNode->nodeValue = '<' . $this->protectedChildNodesHelper . ' data-' . $this->protectedChildNodesHelper . '="' . $this->protected_tags_counter . '">' . $this->protectedChildNodesHelper . '>';
- }
-
- ++$this->protected_tags_counter;
- }
-
- return $dom;
- }
-
- /**
- * Prevent changes of inline "styles" and "scripts".
- *
- * @param HtmlDomParser $dom
- *
- * @return HtmlDomParser
- */
- private function protectTags(HtmlDomParser $dom): HtmlDomParser
- {
- $this->protectTagHelper($dom, 'code');
-
- foreach ($dom->findMulti('script, style') as $element) {
- if ($element->isRemoved()) {
- continue;
- }
-
- if ($element->tag === 'script' || $element->tag === 'style') {
- $attributes = $element->getAllAttributes();
- // skip external links
- if (isset($attributes['src'])) {
- continue;
- }
- }
-
- $this->protectedChildNodes[$this->protected_tags_counter] = $element->innerhtml;
- $element->getNode()->nodeValue = '<' . $this->protectedChildNodesHelper . ' data-' . $this->protectedChildNodesHelper . '="' . $this->protected_tags_counter . '">' . $this->protectedChildNodesHelper . '>';
-
- ++$this->protected_tags_counter;
- }
-
- foreach ($dom->findMulti('//comment()') as $element) {
- if ($element->isRemoved()) {
- continue;
- }
-
- $text = $element->text();
-
- if (
- !$this->isConditionalComment($text)
- &&
- !$this->isSpecialComment($text)
- ) {
- continue;
- }
-
- $this->protectedChildNodes[$this->protected_tags_counter] = '';
-
- /* @var $node \DOMComment */
- $node = $element->getNode();
- $child = new \DOMText('<' . $this->protectedChildNodesHelper . ' data-' . $this->protectedChildNodesHelper . '="' . $this->protected_tags_counter . '">' . $this->protectedChildNodesHelper . '>');
- $parentNode = $element->getNode()->parentNode;
- if ($parentNode !== null) {
- $parentNode->replaceChild($child, $node);
- }
-
- ++$this->protected_tags_counter;
- }
-
- return $dom;
- }
-
- /**
- * Remove comments in the dom.
- *
- * @param HtmlDomParser $dom
- *
- * @return HtmlDomParser
- */
- private function removeComments(HtmlDomParser $dom): HtmlDomParser
- {
- foreach ($dom->findMulti('//comment()') as $commentWrapper) {
- $comment = $commentWrapper->getNode();
- $val = $comment->nodeValue;
- if (\strpos($val, '[') === false) {
- $parentNode = $comment->parentNode;
- if ($parentNode !== null) {
- $parentNode->removeChild($comment);
- }
- }
- }
-
- $dom->getDocument()->normalizeDocument();
-
- return $dom;
- }
-
- /**
- * Trim tags in the dom.
- *
- * @param SimpleHtmlDomInterface $element
- *
- * @return void
- */
- private function removeWhitespaceAroundTags(SimpleHtmlDomInterface $element)
- {
- if (isset(self::$trimWhitespaceFromTags[$element->tag])) {
- $node = $element->getNode();
-
- /** @var \DOMNode[] $candidates */
- $candidates = [];
- if ($node->childNodes->length > 0) {
- $candidates[] = $node->firstChild;
- $candidates[] = $node->lastChild;
- $candidates[] = $node->previousSibling;
- $candidates[] = $node->nextSibling;
- }
-
- /** @var mixed $candidate - false-positive error from phpstan */
- foreach ($candidates as &$candidate) {
- if ($candidate === null) {
- continue;
- }
-
- if ($candidate->nodeType === \XML_TEXT_NODE) {
- $nodeValueTmp = \preg_replace(self::$regExSpace, ' ', $candidate->nodeValue);
- if ($nodeValueTmp !== null) {
- $candidate->nodeValue = $nodeValueTmp;
- }
- }
- }
- }
- }
-
- /**
- * Callback function for preg_replace_callback use.
- *
- * @param array $matches PREG matches
- *
- * @return string
- */
- private function restoreProtectedHtml($matches): string
- {
- \preg_match('/.*"(?\d*)"/', $matches['attributes'], $matchesInner);
-
- return $this->protectedChildNodes[$matchesInner['id']] ?? '';
- }
-
- /**
- * @param string[] $domainsToRemoveHttpPrefixFromAttributes
- *
- * @return $this
- */
- public function setDomainsToRemoveHttpPrefixFromAttributes($domainsToRemoveHttpPrefixFromAttributes): self
- {
- $this->domainsToRemoveHttpPrefixFromAttributes = $domainsToRemoveHttpPrefixFromAttributes;
-
- return $this;
- }
-
- /**
- * @param string[] $startingWith
- * @param string[] $endingWith
- *
- * @return $this
- */
- public function setSpecialHtmlComments(array $startingWith, array $endingWith = []): self
- {
- $this->specialHtmlCommentsStaringWith = $startingWith;
- $this->specialHtmlCommentsEndingWith = $endingWith;
-
- return $this;
- }
-
- /**
- * Sum-up extra whitespace from dom-nodes.
- *
- * @param HtmlDomParser $dom
- *
- * @return HtmlDomParser
- */
- private function sumUpWhitespace(HtmlDomParser $dom): HtmlDomParser
- {
- foreach ($dom->findMulti('//text()') as $text_node_wrapper) {
- /* @var $text_node \DOMNode */
- $text_node = $text_node_wrapper->getNode();
- $xp = $text_node->getNodePath();
- if ($xp === null) {
- continue;
- }
-
- $doSkip = false;
- foreach (self::$skipTagsForRemoveWhitespace as $pattern) {
- if (\strpos($xp, '/' . $pattern) !== false) {
- $doSkip = true;
-
- break;
- }
- }
- if ($doSkip) {
- continue;
- }
-
- $nodeValueTmp = \preg_replace(self::$regExSpace, ' ', $text_node->nodeValue);
- if ($nodeValueTmp !== null) {
- $text_node->nodeValue = $nodeValueTmp;
- }
- }
-
- $dom->getDocument()->normalizeDocument();
-
- return $dom;
- }
-
- /**
- * WARNING: maybe bad for performance ...
- *
- * @param bool $keepBrokenHtml
- *
- * @return HtmlMin
- */
- public function useKeepBrokenHtml(bool $keepBrokenHtml): self
- {
- $this->keepBrokenHtml = $keepBrokenHtml;
-
- return $this;
- }
-
- /**
- * @param string[] $templateLogicSyntaxInSpecialScriptTags
- *
- * @return HtmlMin
- */
- public function overwriteTemplateLogicSyntaxInSpecialScriptTags(array $templateLogicSyntaxInSpecialScriptTags): self
- {
- foreach ($templateLogicSyntaxInSpecialScriptTags as $tmp) {
- if (!\is_string($tmp)) {
- throw new \InvalidArgumentException('setTemplateLogicSyntaxInSpecialScriptTags only allows string[]');
- }
- }
-
- $this->templateLogicSyntaxInSpecialScriptTags = $templateLogicSyntaxInSpecialScriptTags;
-
- return $this;
- }
-
-
- /**
- * @param string[] $specialScriptTags
- *
- * @return HtmlDomParser
- */
- public function overwriteSpecialScriptTags(array $specialScriptTags): self
- {
- foreach ($specialScriptTags as $tag) {
- if (!\is_string($tag)) {
- throw new \InvalidArgumentException('SpecialScriptTags only allows string[]');
- }
- }
-
- $this->specialScriptTags = $specialScriptTags;
-
- return $this;
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php b/includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php
deleted file mode 100644
index ead6eea..0000000
--- a/includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php
+++ /dev/null
@@ -1,28 +0,0 @@
-
- */
- private static $executableScriptsMimeTypes = [
- 'text/javascript' => '',
- 'text/ecmascript' => '',
- 'text/jscript' => '',
- 'application/javascript' => '',
- 'application/x-javascript' => '',
- 'application/ecmascript' => '',
- ];
-
- /**
- * Receive dom elements before the minification.
- *
- * @param SimpleHtmlDomInterface $element
- * @param HtmlMinInterface $htmlMin
- *
- * @return void
- */
- public function domElementBeforeMinification(SimpleHtmlDomInterface $element, HtmlMinInterface $htmlMin)
- {
- }
-
- /**
- * Receive dom elements after the minification.
- *
- * @param SimpleHtmlDomInterface $element
- * @param HtmlMinInterface $htmlMin
- *
- * @return void
- */
- public function domElementAfterMinification(SimpleHtmlDomInterface $element, HtmlMinInterface $htmlMin)
- {
- $attributes = $element->getAllAttributes();
- if ($attributes === null) {
- return;
- }
-
- $tagName = $element->getNode()->nodeName;
- $attrs = [];
- foreach ((array) $attributes as $attrName => $attrValue) {
- // -------------------------------------------------------------------------
- // Remove local domains from attributes.
- // -------------------------------------------------------------------------
-
- if ($htmlMin->isDoMakeSameDomainsLinksRelative()) {
- $localDomains = $htmlMin->getLocalDomains();
- foreach ($localDomains as $localDomain) {
- /** @noinspection InArrayCanBeUsedInspection */
- if (
- (
- $attrName === 'href'
- ||
- $attrName === 'src'
- ||
- $attrName === 'srcset'
- ||
- $attrName === 'action'
- )
- &&
- !(isset($attributes['rel']) && $attributes['rel'] === 'external')
- &&
- !(isset($attributes['target']) && $attributes['target'] === '_blank')
- &&
- \stripos($attrValue, $localDomain) !== false
- ) {
- $localDomainEscaped = \preg_quote($localDomain, '/');
-
- $attrValue = (string) \preg_replace("/^(?:(?:https?:)?\/\/)?{$localDomainEscaped}(?!\w)(?:\/?)/i", '/', $attrValue);
- }
- }
- }
-
- // -------------------------------------------------------------------------
- // Remove optional "http:"-prefix from attributes.
- // -------------------------------------------------------------------------
-
- if ($htmlMin->isDoRemoveHttpPrefixFromAttributes()) {
- $attrValue = $this->removeUrlSchemeHelper(
- $attrValue,
- $attrName,
- 'http',
- $attributes,
- $tagName,
- $htmlMin
- );
- }
-
- if ($htmlMin->isDoRemoveHttpsPrefixFromAttributes()) {
- $attrValue = $this->removeUrlSchemeHelper(
- $attrValue,
- $attrName,
- 'https',
- $attributes,
- $tagName,
- $htmlMin
- );
- }
-
- // -------------------------------------------------------------------------
- // Remove some special attributes.
- // -------------------------------------------------------------------------
-
- if ($this->removeAttributeHelper(
- $element->tag,
- $attrName,
- $attrValue,
- $attributes,
- $htmlMin
- )) {
- $element->{$attrName} = null;
-
- continue;
- }
-
- // -------------------------------------------------------------------------
- // Sort css-class-Powered_Cache_names, for better gzip results.
- // -------------------------------------------------------------------------
-
- if ($htmlMin->isDoSortCssClassNames()) {
- $attrValue = $this->sortCssClassNames($attrName, $attrValue);
- }
-
- if ($htmlMin->isDoSortHtmlAttributes()) {
- $attrs[$attrName] = $attrValue;
- $element->{$attrName} = null;
- }
- }
-
- // -------------------------------------------------------------------------
- // Sort html-attributes, for better gzip results.
- // -------------------------------------------------------------------------
-
- if ($htmlMin->isDoSortHtmlAttributes()) {
- \ksort($attrs);
- foreach ($attrs as $attrName => $attrValue) {
- $attrValue = HtmlDomParser::replaceToPreserveHtmlEntities($attrValue);
- $element->setAttribute((string) $attrName, $attrValue, true);
- }
- }
- }
-
- /**
- * Check if the attribute can be removed.
- *
- * @param string $tag
- * @param string $attrName
- * @param string $attrValue
- * @param array $allAttr
- * @param HtmlMinInterface $htmlMin
- *
- * @return bool
- */
- private function removeAttributeHelper($tag, $attrName, $attrValue, $allAttr, HtmlMinInterface $htmlMin): bool
- {
- // remove defaults
- if ($htmlMin->isDoRemoveDefaultAttributes()) {
- if ($tag === 'script' && $attrName === 'language' && $attrValue === 'javascript') {
- return true;
- }
-
- if ($tag === 'form' && $attrName === 'method' && $attrValue === 'get') {
- return true;
- }
-
- if ($tag === 'form' && $attrName === 'autocomplete' && $attrValue === 'on') {
- return true;
- }
-
- if ($tag === 'form' && $attrName === 'enctype' && $attrValue === 'application/x-www-form-urlencoded') {
- return true;
- }
-
- if ($tag === 'input' && $attrName === 'type' && $attrValue === 'text') {
- return true;
- }
-
- if ($tag === 'textarea' && $attrName === 'wrap' && $attrValue === 'soft') {
- return true;
- }
-
- if ($tag === 'area' && $attrName === 'shape' && $attrValue === 'rect') {
- return true;
- }
-
- if ($tag === 'th' && $attrName === 'scope' && $attrValue === 'auto') {
- return true;
- }
-
- if ($tag === 'ol' && $attrName === 'type' && $attrValue === 'decimal') {
- return true;
- }
-
- if ($tag === 'ol' && $attrName === 'start' && $attrValue === '1') {
- return true;
- }
-
- if ($tag === 'track' && $attrName === 'kind' && $attrValue === 'subtitles') {
- return true;
- }
-
- if ($attrName === 'spellcheck' && $attrValue === 'default') {
- return true;
- }
-
- if ($attrName === 'draggable' && $attrValue === 'auto') {
- return true;
- }
- }
-
- // remove deprecated charset-attribute (the browser will use the charset from the HTTP-Header, anyway)
- if ($htmlMin->isDoRemoveDeprecatedScriptCharsetAttribute()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($tag === 'script' && $attrName === 'charset' && !isset($allAttr['src'])) {
- return true;
- }
- }
-
- // remove deprecated anchor-jump
- if ($htmlMin->isDoRemoveDeprecatedAnchorName()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($tag === 'a' && $attrName === 'name' && isset($allAttr['id']) && $allAttr['id'] === $attrValue) {
- return true;
- }
- }
-
- if ($htmlMin->isDoRemoveDefaultMediaTypeFromStyleAndLinkTag()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (($tag === 'link' || $tag === 'style') && $attrName === 'media' && $attrValue === 'all') {
- return true;
- }
- }
-
- // remove "type=text/css" for css "stylesheet"-links
- if ($htmlMin->isDoRemoveDeprecatedTypeFromStylesheetLink()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($tag === 'link' && $attrName === 'type' && $attrValue === 'text/css' && isset($allAttr['rel']) && $allAttr['rel'] === 'stylesheet' && $htmlMin->isXHTML() === false && $htmlMin->isHTML4() === false) {
- return true;
- }
- }
- // remove deprecated css-mime-types
- if ($htmlMin->isDoRemoveDeprecatedTypeFromStyleAndLinkTag()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (($tag === 'link' || $tag === 'style') && $attrName === 'type' && $attrValue === 'text/css' && $htmlMin->isXHTML() === false && $htmlMin->isHTML4() === false) {
- return true;
- }
- }
-
- // remove deprecated script-mime-types
- if ($htmlMin->isDoRemoveDeprecatedTypeFromScriptTag()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($tag === 'script' && $attrName === 'type' && isset(self::$executableScriptsMimeTypes[$attrValue]) && $htmlMin->isXHTML() === false && $htmlMin->isHTML4() === false) {
- return true;
- }
- }
-
- // remove 'type=submit' from
- if ($htmlMin->isDoRemoveDefaultTypeFromButton()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($tag === 'button' && $attrName === 'type' && $attrValue === 'submit') {
- return true;
- }
- }
-
- // remove 'value=""' from
- if ($htmlMin->isDoRemoveValueFromEmptyInput()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($tag === 'input' && $attrName === 'value' && $attrValue === '' && isset($allAttr['type']) && $allAttr['type'] === 'text') {
- return true;
- }
- }
-
- // remove some empty attributes
- if ($htmlMin->isDoRemoveEmptyAttributes()) {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\trim($attrValue) === '' && \preg_match('/^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$/', $attrName)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @param string $attrValue
- * @param string $attrName
- * @param string $scheme
- * @param string[] $attributes
- * @param string $tagName
- * @param HtmlMinInterface $htmlMin
- *
- * @return string
- *
- * @noinspection PhpTooManyParametersInspection
- */
- private function removeUrlSchemeHelper(
- string $attrValue,
- string $attrName,
- string $scheme,
- array $attributes,
- string $tagName,
- HtmlMinInterface $htmlMin
- ): string {
- /** @noinspection InArrayCanBeUsedInspection */
- if (
- !(isset($attributes['rel']) && $attributes['rel'] === 'external')
- &&
- !(isset($attributes['target']) && $attributes['target'] === '_blank')
- &&
- (
- (
- $attrName === 'href'
- &&
- (
- !$htmlMin->isdoKeepHttpAndHttpsPrefixOnExternalAttributes()
- ||
- $tagName === 'link'
- )
- )
- ||
- $attrName === 'src'
- ||
- $attrName === 'srcset'
- ||
- $attrName === 'action'
- )
- ) {
- $attrValue = \str_replace($scheme . '://', '//', $attrValue);
- }
-
- return $attrValue;
- }
-
- /**
- * @param string $attrName
- * @param string $attrValue
- *
- * @return string
- */
- private function sortCssClassNames($attrName, $attrValue): string
- {
- if ($attrName !== 'class' || !$attrValue) {
- return $attrValue;
- }
-
- $classes = \array_unique(
- \explode(' ', $attrValue)
- );
- \sort($classes);
-
- $attrValue = '';
- foreach ($classes as $class) {
- if (!$class) {
- continue;
- }
-
- $attrValue .= \trim($class) . ' ';
- }
-
- return \trim($attrValue);
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/HtmlMinInterface.php b/includes/classes/Dependencies/voku/helper/HtmlMinInterface.php
deleted file mode 100644
index 99c9c53..0000000
--- a/includes/classes/Dependencies/voku/helper/HtmlMinInterface.php
+++ /dev/null
@@ -1,154 +0,0 @@
-
- */
- protected static $compiled = [];
-
- /**
- * @param string $selector
- * @param bool $ignoreCssSelectorErrors
- *
- * Ignore css selector errors and use the $selector as it is on error,
- * so that you can also use xPath selectors.
- *
- * @param bool $isForHtml
- *
- * @return string
- */
- public static function toXPath(string $selector, bool $ignoreCssSelectorErrors = false, bool $isForHtml = true)
- {
- if (isset(self::$compiled[$selector])) {
- return self::$compiled[$selector];
- }
-
- // Select DOMText
- if ($selector === 'text') {
- return '//text()';
- }
-
- // Select DOMComment
- if ($selector === 'comment') {
- return '//comment()';
- }
-
- if (\strpos($selector, '//') === 0) {
- return $selector;
- }
-
- if (!\class_exists(CssSelectorConverter::class)) {
- throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector 2.8+ is not installed (you can use filterXPath instead).');
- }
-
- $converterKey = '-' . $isForHtml . '-' . $ignoreCssSelectorErrors . '-';
- static $converterArray = [];
- if (!isset($converterArray[$converterKey])) {
- $converterArray[$converterKey] = new CssSelectorConverter($isForHtml);
- }
- $converter = $converterArray[$converterKey];
- assert($converter instanceof CssSelectorConverter);
-
- if ($ignoreCssSelectorErrors) {
- try {
- $xPathQuery = $converter->toXPath($selector);
- } catch (\Exception $e) {
- $xPathQuery = $selector;
- }
- } else {
- $xPathQuery = $converter->toXPath($selector);
- }
-
- self::$compiled[$selector] = $xPathQuery;
-
- return $xPathQuery;
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php
deleted file mode 100644
index 4da7bc5..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php
+++ /dev/null
@@ -1,269 +0,0 @@
-
- */
- private $tokens = [];
-
- /**
- * @var string|null
- */
- private $previousValue;
-
- /**
- * Creates a list of space-separated tokens based on the attribute value of an element.
- *
- * @param \DOMElement|null $element
- * The DOM element.
- * @param string $attributeName
- * The name of the attribute.
- */
- public function __construct($element, string $attributeName)
- {
- $this->element = $element;
- $this->attributeName = $attributeName;
-
- $this->tokenize();
- }
-
- /** @noinspection MagicMethodsValidityInspection */
-
- /**
- * Returns the value for the property specified.
- *
- * @param string $name The name of the property
- *
- * @return int|string The value of the property specified
- */
- public function __get(string $name)
- {
- if ($name === 'length') {
- $this->tokenize();
-
- return \count($this->tokens);
- }
-
- if ($name === 'value') {
- return (string) $this;
- }
-
- throw new \InvalidArgumentException('Undefined property: $' . $name);
- }
-
- /**
- * @return string
- */
- public function __toString(): string
- {
- $this->tokenize();
-
- return \implode(' ', $this->tokens);
- }
-
- /**
- * {@inheritdoc}
- */
- public function add(string ...$tokens)
- {
- if (\count($tokens) === 0) {
- return null;
- }
-
- foreach ($tokens as $t) {
- if (\in_array($t, $this->tokens, true)) {
- continue;
- }
-
- $this->tokens[] = $t;
- }
-
- return $this->setAttributeValue();
- }
-
- /**
- * {@inheritdoc}
- */
- public function contains(string $token): bool
- {
- $this->tokenize();
-
- return \in_array($token, $this->tokens, true);
- }
-
- /**
- * {@inheritdoc}
- */
- public function entries(): \ArrayIterator
- {
- $this->tokenize();
-
- return new \ArrayIterator($this->tokens);
- }
-
- public function item(int $index)
- {
- $this->tokenize();
- if ($index >= \count($this->tokens)) {
- return null;
- }
-
- return $this->tokens[$index];
- }
-
- /**
- * {@inheritdoc}
- */
- public function remove(string ...$tokens)
- {
- if (\count($tokens) === 0) {
- return null;
- }
-
- if (\count($this->tokens) === 0) {
- return null;
- }
-
- foreach ($tokens as $t) {
- $i = \array_search($t, $this->tokens, true);
- if ($i === false) {
- continue;
- }
-
- \array_splice($this->tokens, $i, 1);
- }
-
- return $this->setAttributeValue();
- }
-
- /**
- * {@inheritdoc}
- */
- public function replace(string $old, string $new)
- {
- if ($old === $new) {
- return null;
- }
-
- $this->tokenize();
- $i = \array_search($old, $this->tokens, true);
- if ($i !== false) {
- $j = \array_search($new, $this->tokens, true);
- if ($j === false) {
- $this->tokens[$i] = $new;
- } else {
- \array_splice($this->tokens, $i, 1);
- }
-
- return $this->setAttributeValue();
- }
-
- return null;
- }
-
- /**
- * {@inheritdoc}
- */
- public function toggle(string $token, bool $force = null): bool
- {
- // init
- $this->tokenize();
- $isThereAfter = false;
-
- $i = \array_search($token, $this->tokens, true);
- if ($force === null) {
- if ($i === false) {
- $this->tokens[] = $token;
- $isThereAfter = true;
- } else {
- \array_splice($this->tokens, $i, 1);
- }
- } elseif ($force) {
- if ($i === false) {
- $this->tokens[] = $token;
- }
- $isThereAfter = true;
- } else {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if ($i !== false) {
- \array_splice($this->tokens, $i, 1);
- }
- }
-
- /** @noinspection UnusedFunctionResultInspection */
- $this->setAttributeValue();
-
- return $isThereAfter;
- }
-
- /**
- * @return \DOMAttr|false|null
- */
- private function setAttributeValue()
- {
- if ($this->element === null) {
- return false;
- }
-
- $value = \implode(' ', $this->tokens);
- if ($this->previousValue === $value) {
- return null;
- }
-
- $this->previousValue = $value;
-
- return $this->element->setAttribute($this->attributeName, $value);
- }
-
- /**
- * @return void
- */
- private function tokenize()
- {
- if ($this->element === null) {
- return;
- }
-
- $current = $this->element->getAttribute($this->attributeName);
- if ($this->previousValue === $current) {
- return;
- }
-
- $this->previousValue = $current;
- $tokens = \explode(' ', $current);
- $finals = [];
- foreach ($tokens as $token) {
- if ($token === '') {
- continue;
- }
-
- if (\in_array($token, $finals, true)) {
- continue;
- }
-
- $finals[] = $token;
- }
-
- $this->tokens = $finals;
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php
deleted file mode 100644
index d1f0261..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php
+++ /dev/null
@@ -1,82 +0,0 @@
-The tokens you want to add to the list.
- *
- * @return \DOMAttr|false|null
- */
- public function add(string ...$tokens);
-
- /**
- * Returns true if the list contains the given token, otherwise false.
- *
- * @param string $token the token you want to check for the existence of in the list
- *
- * @return bool true if the list contains the given token, otherwise false
- */
- public function contains(string $token): bool;
-
- /**
- * Returns an iterator allowing you to go through all tokens contained in the list.
- *
- * @return \ArrayIterator
- */
- public function entries(): \ArrayIterator;
-
- /**
- * Returns an item in the list by its index (returns null if the number is greater than or equal to the length of
- * the list).
- *
- * @param int $index the zero-based index of the item you want to return
- *
- * @return string|null
- */
- public function item(int $index);
-
- /**
- * Removes the specified tokens from the list. If the string does not exist in the list, no error is thrown.
- *
- * @param string ...$tokens
- * The token you want to remove from the list.>
- *
- * @return \DOMAttr|false|null
- */
- public function remove(string ...$tokens);
-
- /**
- * Replaces an existing token with a new token.
- *
- * @param string $old the token you want to replace
- * @param string $new the token you want to replace $old with
- *
- * @return \DOMAttr|false|null
- */
- public function replace(string $old, string $new);
-
- /**
- * Removes a given token from the list and returns false. If token doesn't exist it's added and the function
- * returns true.
- *
- * @param string $token the token you want to toggle
- * @param bool $force A Boolean that, if included, turns the toggle into a one way-only operation. If set to
- * false, the token will only be removed but not added again. If set to true, the token will
- * only be added but not removed again.
- *
- * @return bool false if the token is not in the list after the call, or true if the token is in the list after the
- * call
- */
- public function toggle(string $token, bool $force = null): bool;
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php
deleted file mode 100644
index 8059186..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php
+++ /dev/null
@@ -1,1011 +0,0 @@
-
- */
-class SimpleHtmlDom extends AbstractSimpleHtmlDom implements \IteratorAggregate, SimpleHtmlDomInterface
-{
- /**
- * @param \DOMElement|\DOMNode $node
- */
- public function __construct(\DOMNode $node)
- {
- $this->node = $node;
- }
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleHtmlDomInterface|string|null
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /**
- * Find list of nodes with a CSS selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function find(string $selector, $idx = null)
- {
- return $this->getHtmlDomParser()->find($selector, $idx);
- }
-
- public function getTag(): string
- {
- return $this->tag;
- }
-
- /**
- * Returns an array of attributes.
- *
- * @return string[]|null
- */
- public function getAllAttributes()
- {
- if (
- $this->node
- &&
- $this->node->hasAttributes()
- ) {
- $attributes = [];
- foreach ($this->node->attributes ?? [] as $attr) {
- $attributes[$attr->name] = HtmlDomParser::putReplacedBackToPreserveHtmlEntities($attr->value);
- }
-
- return $attributes;
- }
-
- return null;
- }
-
- /**
- * @return bool
- */
- public function hasAttributes(): bool
- {
- return $this->node && $this->node->hasAttributes();
- }
-
- /**
- * Return attribute value.
- *
- * @param string $name
- *
- * @return string
- */
- public function getAttribute(string $name): string
- {
- if ($this->node instanceof \DOMElement) {
- return HtmlDomParser::putReplacedBackToPreserveHtmlEntities(
- $this->node->getAttribute($name)
- );
- }
-
- return '';
- }
-
- /**
- * Determine if an attribute exists on the element.
- *
- * @param string $name
- *
- * @return bool
- */
- public function hasAttribute(string $name): bool
- {
- if (!$this->node instanceof \DOMElement) {
- return false;
- }
-
- return $this->node->hasAttribute($name);
- }
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function html(bool $multiDecodeNewHtmlEntity = false): string
- {
- return $this->getHtmlDomParser()->html($multiDecodeNewHtmlEntity);
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
- {
- return $this->getHtmlDomParser()->innerHtml($multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
- }
-
- /**
- * Remove attribute.
- *
- * @param string $name The name of the html-attribute.
- *
- * @return SimpleHtmlDomInterface
- */
- public function removeAttribute(string $name): SimpleHtmlDomInterface
- {
- if (\method_exists($this->node, 'removeAttribute')) {
- $this->node->removeAttribute($name);
- }
-
- return $this;
- }
-
- /**
- * Remove all attributes
- *
- * @return SimpleHtmlDomInterface
- */
- public function removeAttributes(): SimpleHtmlDomInterface
- {
- if ($this->hasAttributes()) {
- foreach (array_keys((array)$this->getAllAttributes()) as $attribute) {
- $this->removeAttribute($attribute);
- }
- }
- return $this;
- }
-
- /**
- * Replace child node.
- *
- * @param string $string
- * @param bool $putBrokenReplacedBack
- *
- * @return SimpleHtmlDomInterface
- */
- protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface
- {
- if (!empty($string)) {
- $newDocument = new HtmlDomParser($string);
-
- $tmpDomString = $this->normalizeStringForComparison($newDocument);
- $tmpStr = $this->normalizeStringForComparison($string);
-
- if ($tmpDomString !== $tmpStr) {
- throw new \RuntimeException(
- 'Not valid HTML fragment!' . "\n" .
- $tmpDomString . "\n" .
- $tmpStr
- );
- }
- }
-
- /** @var \DOMNode[] $remove_nodes */
- $remove_nodes = [];
- if ($this->node->childNodes->length > 0) {
- // INFO: We need to fetch the nodes first, before we can delete them, because of missing references in the dom,
- // if we delete the elements on the fly.
- foreach ($this->node->childNodes as $node) {
- $remove_nodes[] = $node;
- }
- }
- foreach ($remove_nodes as $remove_node) {
- $this->node->removeChild($remove_node);
- }
-
- if (!empty($newDocument)) {
- $newDocument = $this->cleanHtmlWrapper($newDocument);
- $ownerDocument = $this->node->ownerDocument;
- if (
- $ownerDocument
- &&
- $newDocument->getDocument()->documentElement
- ) {
- $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
- $this->node->appendChild($newNode);
- }
- }
-
- return $this;
- }
-
- /**
- * Replace this node.
- *
- * @param string $string
- *
- * @return SimpleHtmlDomInterface
- */
- protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface
- {
- if (empty($string)) {
- if ($this->node->parentNode) {
- $this->node->parentNode->removeChild($this->node);
- }
- $this->node = new \DOMText();
-
- return $this;
- }
-
- $newDocument = new HtmlDomParser($string);
-
- $tmpDomOuterTextString = $this->normalizeStringForComparison($newDocument);
- $tmpStr = $this->normalizeStringForComparison($string);
-
- if ($tmpDomOuterTextString !== $tmpStr) {
- throw new \RuntimeException(
- 'Not valid HTML fragment!' . "\n"
- . $tmpDomOuterTextString . "\n" .
- $tmpStr
- );
- }
-
- $newDocument = $this->cleanHtmlWrapper($newDocument, true);
- $ownerDocument = $this->node->ownerDocument;
- if (
- $ownerDocument === null
- ||
- $newDocument->getDocument()->documentElement === null
- ) {
- return $this;
- }
-
- $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
-
- $this->node->parentNode->replaceChild($newNode, $this->node);
- $this->node = $newNode;
-
- // Remove head element, preserving child nodes. (again)
- if (
- $this->node->parentNode instanceof \DOMElement
- &&
- $newDocument->getIsDOMDocumentCreatedWithoutHeadWrapper()
- ) {
- $html = $this->node->parentNode->getElementsByTagName('head')[0];
-
- if (
- $html !== null
- &&
- $this->node->parentNode->ownerDocument
- ) {
- $fragment = $this->node->parentNode->ownerDocument->createDocumentFragment();
- /** @var \DOMNode $html */
- while ($html->childNodes->length > 0) {
- $tmpNode = $html->childNodes->item(0);
- if ($tmpNode !== null) {
- /** @noinspection UnusedFunctionResultInspection */
- $fragment->appendChild($tmpNode);
- }
- }
- $html->parentNode->replaceChild($fragment, $html);
- }
- }
-
- return $this;
- }
-
- /**
- * Replace this node with text
- *
- * @param string $string
- *
- * @return SimpleHtmlDomInterface
- */
- protected function replaceTextWithString($string): SimpleHtmlDomInterface
- {
- if (empty($string)) {
- if ($this->node->parentNode) {
- $this->node->parentNode->removeChild($this->node);
- }
- $this->node = new \DOMText();
-
- return $this;
- }
-
- $ownerDocument = $this->node->ownerDocument;
- if ($ownerDocument) {
- $newElement = $ownerDocument->createTextNode($string);
- $newNode = $ownerDocument->importNode($newElement, true);
- $this->node->parentNode->replaceChild($newNode, $this->node);
- $this->node = $newNode;
- }
-
- return $this;
- }
-
- /**
- * Set attribute value.
- *
- * @param string $name The name of the html-attribute.
- * @param string|null $value Set to NULL or empty string, to remove the attribute.
- * @param bool $strictEmptyValueCheck
- * $value must be NULL, to remove the attribute,
- * so that you can set an empty string as attribute-value e.g. autofocus=""
- *
- *
- * @return SimpleHtmlDomInterface
- */
- public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface
- {
- if (
- ($strictEmptyValueCheck && $value === null)
- ||
- (!$strictEmptyValueCheck && empty($value))
- ) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->removeAttribute($name);
- } elseif (\method_exists($this->node, 'setAttribute')) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->node->setAttribute($name, HtmlDomParser::replaceToPreserveHtmlEntities((string) $value));
- }
-
- return $this;
- }
-
- /**
- * Get dom node's plain text.
- *
- * @return string
- */
- public function text(): string
- {
- return $this->getHtmlDomParser()->fixHtmlOutput($this->node->textContent);
- }
-
- /**
- * Change the name of a tag in a "DOMNode".
- *
- * @param \DOMNode $node
- * @param string $name
- *
- * @return \DOMElement|false
- * DOMElement a new instance of class DOMElement or false
- * if an error occurred.
- */
- protected function changeElementName(\DOMNode $node, string $name)
- {
- $ownerDocument = $node->ownerDocument;
- if (!$ownerDocument) {
- return false;
- }
-
- $newNode = $ownerDocument->createElement($name);
-
- foreach ($node->childNodes as $child) {
- $child = $ownerDocument->importNode($child, true);
- $newNode->appendChild($child);
- }
-
- foreach ($node->attributes ?? [] as $attrName => $attrNode) {
- /** @noinspection UnusedFunctionResultInspection */
- $newNode->setAttribute($attrName, $attrNode);
- }
-
- if ($newNode->ownerDocument) {
- /** @noinspection UnusedFunctionResultInspection */
- $newNode->ownerDocument->replaceChild($newNode, $node);
- }
-
- return $newNode;
- }
-
- /**
- * Returns children of node.
- *
- * @param int $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface|null
- */
- public function childNodes(int $idx = -1)
- {
- $nodeList = $this->getIterator();
-
- if ($idx === -1) {
- return $nodeList;
- }
-
- return $nodeList[$idx] ?? null;
- }
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleHtmlDomNodeInterface
- {
- return $this->getHtmlDomParser()->findMulti($selector);
- }
-
- /**
- * Find nodes with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector)
- {
- return $this->getHtmlDomParser()->findMultiOrFalse($selector);
- }
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface
- */
- public function findOne(string $selector): SimpleHtmlDomInterface
- {
- return $this->getHtmlDomParser()->findOne($selector);
- }
-
- /**
- * Find one node with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomInterface
- */
- public function findOneOrFalse(string $selector)
- {
- return $this->getHtmlDomParser()->findOneOrFalse($selector);
- }
-
- /**
- * Returns the first child of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function firstChild()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->firstChild;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function getElementByClass(string $class): SimpleHtmlDomNodeInterface
- {
- return $this->findMulti(".{$class}");
- }
-
- /**
- * Return element by #id.
- *
- * @param string $id
- *
- * @return SimpleHtmlDomInterface
- */
- public function getElementById(string $id): SimpleHtmlDomInterface
- {
- return $this->findOne("#{$id}");
- }
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleHtmlDomInterface
- */
- public function getElementByTagName(string $name): SimpleHtmlDomInterface
- {
- if ($this->node instanceof \DOMElement) {
- $node = $this->node->getElementsByTagName($name)->item(0);
- } else {
- $node = null;
- }
-
- if ($node === null) {
- return new SimpleHtmlDomBlank();
- }
-
- return new static($node);
- }
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null)
- {
- return $this->find("#{$id}", $idx);
- }
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null)
- {
- if ($this->node instanceof \DOMElement) {
- $nodesList = $this->node->getElementsByTagName($name);
- } else {
- $nodesList = [];
- }
-
- $elements = new SimpleHtmlDomNode();
-
- foreach ($nodesList as $node) {
- $elements[] = new static($node);
- }
-
- // return all elements
- if ($idx === null) {
- if (\count($elements) === 0) {
- return new SimpleHtmlDomNodeBlank();
- }
-
- return $elements;
- }
-
- // handle negative values
- if ($idx < 0) {
- $idx = \count($elements) + $idx;
- }
-
- // return one element
- return $elements[$idx] ?? new SimpleHtmlDomBlank();
- }
-
- /**
- * Create a new "HtmlDomParser"-object from the current context.
- *
- * @return HtmlDomParser
- */
- public function getHtmlDomParser(): HtmlDomParser
- {
- return new HtmlDomParser($this);
- }
-
- /**
- * @return \DOMNode
- */
- public function getNode(): \DOMNode
- {
- return $this->node;
- }
-
- /**
- * Nodes can get partially destroyed in which they're still an
- * actual DOM node (such as \DOMElement) but almost their entire
- * body is gone, including the `nodeType` attribute.
- *
- * @return bool true if node has been destroyed
- */
- public function isRemoved(): bool
- {
- return !isset($this->node->nodeType);
- }
-
- /**
- * Returns the last child of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function lastChild()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->lastChild;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function nextSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->nextSibling;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function nextNonWhitespaceSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->nextSibling;
-
- while ($node && !\trim($node->textContent)) {
- /** @var \DOMNode|null $node */
- $node = $node->nextSibling;
- }
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the parent of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function parentNode(): ?SimpleHtmlDomInterface
- {
- if ($node = $this->node->parentNode) {
- return new static($node);
- }
-
- return null;
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function previousSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->previousSibling;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function previousNonWhitespaceSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->previousSibling;
-
- while ($node && !\trim($node->textContent)) {
- /** @var \DOMNode|null $node */
- $node = $node->previousSibling;
- }
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * @param string|string[]|null $value
- * null === get the current input value
- * text === set a new input value
- *
- *
- * @return string|string[]|null
- */
- public function val($value = null)
- {
- if ($value === null) {
- if (
- $this->tag === 'input'
- &&
- (
- $this->getAttribute('type') === 'hidden'
- ||
- $this->getAttribute('type') === 'text'
- ||
- !$this->hasAttribute('type')
- )
- ) {
- return $this->getAttribute('value');
- }
-
- if (
- $this->hasAttribute('checked')
- &&
- \in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)
- ) {
- return $this->getAttribute('value');
- }
-
- if ($this->node->nodeName === 'select') {
- $valuesFromDom = [];
- $options = $this->getElementsByTagName('option');
- if ($options instanceof SimpleHtmlDomNode) {
- foreach ($options as $option) {
- if ($this->hasAttribute('checked')) {
- $valuesFromDom[] = (string) $option->getAttribute('value');
- }
- }
- }
-
- if (\count($valuesFromDom) === 0) {
- return null;
- }
-
- return $valuesFromDom;
- }
-
- if ($this->node->nodeName === 'textarea') {
- return $this->node->nodeValue;
- }
- } else {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)) {
- if ($value === $this->getAttribute('value')) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->setAttribute('checked', 'checked');
- } else {
- /** @noinspection UnusedFunctionResultInspection */
- $this->removeAttribute('checked');
- }
- } elseif ($this->node instanceof \DOMElement && $this->node->nodeName === 'select') {
- foreach ($this->node->getElementsByTagName('option') as $option) {
- /** @var \DOMElement $option */
- if ($value === $option->getAttribute('value')) {
- /** @noinspection UnusedFunctionResultInspection */
- $option->setAttribute('selected', 'selected');
- } else {
- $option->removeAttribute('selected');
- }
- }
- } elseif ($this->node->nodeName === 'input' && \is_string($value)) {
- // Set value for input elements
- /** @noinspection UnusedFunctionResultInspection */
- $this->setAttribute('value', $value);
- } elseif ($this->node->nodeName === 'textarea' && \is_string($value)) {
- $this->node->nodeValue = $value;
- }
- }
-
- return null;
- }
-
- /**
- * @param HtmlDomParser $newDocument
- * @param bool $removeExtraHeadTag
- *
- * @return HtmlDomParser
- */
- protected function cleanHtmlWrapper(
- HtmlDomParser $newDocument,
- $removeExtraHeadTag = false
- ): HtmlDomParser {
- if (
- $newDocument->getIsDOMDocumentCreatedWithoutHtml()
- ||
- $newDocument->getIsDOMDocumentCreatedWithoutHtmlWrapper()
- ) {
- // Remove doc-type node.
- if ($newDocument->getDocument()->doctype !== null) {
- $newDocument->getDocument()->doctype->parentNode->removeChild($newDocument->getDocument()->doctype);
- }
-
- // Replace html element, preserving child nodes -> but keep the html wrapper, otherwise we got other problems ...
- // so we replace it with "" and delete this at the ending.
- $item = $newDocument->getDocument()->getElementsByTagName('html')->item(0);
- if ($item !== null) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->changeElementName($item, 'simpleHtmlDomHtml');
- }
-
- if ($newDocument->getIsDOMDocumentCreatedWithoutPTagWrapper()) {
- // Remove -element, preserving child nodes.
- $pElement = $newDocument->getDocument()->getElementsByTagName('p')->item(0);
- if ($pElement instanceof \DOMElement) {
- $fragment = $newDocument->getDocument()->createDocumentFragment();
-
- while ($pElement->childNodes->length > 0) {
- $tmpNode = $pElement->childNodes->item(0);
- if ($tmpNode !== null) {
- /** @noinspection UnusedFunctionResultInspection */
- $fragment->appendChild($tmpNode);
- }
- }
-
- if ($pElement->parentNode !== null) {
- $pElement->parentNode->replaceChild($fragment, $pElement);
- }
- }
- }
-
- // Remove
-element, preserving child nodes.
- $body = $newDocument->getDocument()->getElementsByTagName('body')->item(0);
- if ($body instanceof \DOMElement) {
- $fragment = $newDocument->getDocument()->createDocumentFragment();
-
- while ($body->childNodes->length > 0) {
- $tmpNode = $body->childNodes->item(0);
- if ($tmpNode !== null) {
- /** @noinspection UnusedFunctionResultInspection */
- $fragment->appendChild($tmpNode);
- }
- }
-
- if ($body->parentNode !== null) {
- $body->parentNode->replaceChild($fragment, $body);
- }
- }
- }
-
- // Remove head element, preserving child nodes.
- if (
- $removeExtraHeadTag
- &&
- $this->node->parentNode instanceof \DOMElement
- &&
- $newDocument->getIsDOMDocumentCreatedWithoutHeadWrapper()
- ) {
- $html = $this->node->parentNode->getElementsByTagName('head')[0] ?? null;
-
- if (
- $html !== null
- &&
- $this->node->parentNode->ownerDocument
- ) {
- $fragment = $this->node->parentNode->ownerDocument->createDocumentFragment();
-
- /** @var \DOMNode $html */
- while ($html->childNodes->length > 0) {
- $tmpNode = $html->childNodes->item(0);
- if ($tmpNode !== null) {
- /** @noinspection UnusedFunctionResultInspection */
- $fragment->appendChild($tmpNode);
- }
- }
-
- $html->parentNode->replaceChild($fragment, $html);
- }
- }
-
- return $newDocument;
- }
-
- /**
- * Retrieve an external iterator.
- *
- * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
- *
- * @return SimpleHtmlDomNode
- *
- * An instance of an object implementing Iterator or
- * Traversable
- *
- */
- public function getIterator(): SimpleHtmlDomNodeInterface
- {
- $elements = new SimpleHtmlDomNode();
- if ($this->node->hasChildNodes()) {
- foreach ($this->node->childNodes as $node) {
- $elements[] = new static($node);
- }
- }
-
- return $elements;
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
- {
- return $this->getHtmlDomParser()->innerXml($multiDecodeNewHtmlEntity);
- }
-
- /**
- * Normalize the given input for comparison.
- *
- * @param HtmlDomParser|string $input
- *
- * @return string
- */
- private function normalizeStringForComparison($input): string
- {
- if ($input instanceof HtmlDomParser) {
- $string = $input->html(false, false);
-
- if ($input->getIsDOMDocumentCreatedWithoutHeadWrapper()) {
- /** @noinspection HtmlRequiredTitleElement */
- $string = \str_replace(['', ''], '', $string);
- }
- } else {
- $string = (string) $input;
- }
-
- return
- \urlencode(
- \urldecode(
- \trim(
- \str_replace(
- [
- ' ',
- "\n",
- "\r",
- '/>',
- ],
- [
- '',
- '',
- '',
- '>',
- ],
- \strtolower($string)
- )
- )
- )
- );
- }
-
- /**
- * Delete
- *
- * @return void
- */
- public function delete()
- {
- $this->outertext = '';
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php
deleted file mode 100644
index 4d313c1..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php
+++ /dev/null
@@ -1,472 +0,0 @@
-
- */
-class SimpleHtmlDomBlank extends AbstractSimpleHtmlDom implements \IteratorAggregate, SimpleHtmlDomInterface
-{
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleHtmlDomInterface|string|null
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /**
- * Find list of nodes with a CSS selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function find(string $selector, $idx = null)
- {
- return new SimpleHtmlDomNodeBlank();
- }
-
- public function getTag(): string
- {
- return '';
- }
-
- /**
- * Returns an array of attributes.
- *
- * @return null
- */
- public function getAllAttributes()
- {
- return null;
- }
-
- /**
- * @return bool
- */
- public function hasAttributes(): bool
- {
- return false;
- }
-
- /**
- * Return attribute value.
- *
- * @param string $name
- *
- * @return string
- */
- public function getAttribute(string $name): string
- {
- return '';
- }
-
- /**
- * Determine if an attribute exists on the element.
- *
- * @param string $name
- *
- * @return bool
- */
- public function hasAttribute(string $name): bool
- {
- return false;
- }
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function html(bool $multiDecodeNewHtmlEntity = false): string
- {
- return '';
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
- {
- return '';
- }
-
- /**
- * Remove attribute.
- *
- * @param string $name The name of the html-attribute.
- *
- * @return SimpleHtmlDomInterface
- */
- public function removeAttribute(string $name): SimpleHtmlDomInterface
- {
- return $this;
- }
-
- /**
- * Remove all attributes
- *
- * @return SimpleHtmlDomBlank
- */
- public function removeAttributes(): SimpleHtmlDomInterface
- {
- return $this;
- }
-
- /**
- * @param string $string
- * @param bool $putBrokenReplacedBack
- *
- * @return SimpleHtmlDomInterface
- */
- protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * @param string $string
- *
- * @return SimpleHtmlDomInterface
- */
- protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * @param string $string
- *
- * @return SimpleHtmlDomInterface
- */
- protected function replaceTextWithString($string): SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * Set attribute value.
- *
- * @param string $name The name of the html-attribute.
- * @param string|null $value Set to NULL or empty string, to remove the attribute.
- * @param bool $strictEmptyValueCheck
- * $value must be NULL, to remove the attribute,
- * so that you can set an empty string as attribute-value e.g. autofocus=""
- *
- *
- * @return SimpleHtmlDomInterface
- */
- public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface
- {
- return $this;
- }
-
- /**
- * Get dom node's plain text.
- *
- * @return string
- */
- public function text(): string
- {
- return '';
- }
-
- /**
- * Returns children of node.
- *
- * @param int $idx
- *
- * @return null
- */
- public function childNodes(int $idx = -1)
- {
- return null;
- }
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleHtmlDomNodeInterface
- {
- return new SimpleHtmlDomNodeBlank();
- }
-
- /**
- * Find nodes with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findMultiOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface
- */
- public function findOne(string $selector): SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * Find one node with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findOneOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * Returns the first child of node.
- *
- * @return null
- */
- public function firstChild()
- {
- return null;
- }
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function getElementByClass(string $class): SimpleHtmlDomNodeInterface
- {
- return new SimpleHtmlDomNodeBlank();
- }
-
- /**
- * Return element by #id.
- *
- * @param string $id
- *
- * @return SimpleHtmlDomInterface
- */
- public function getElementById(string $id): SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleHtmlDomInterface
- */
- public function getElementByTagName(string $name): SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null)
- {
- return new SimpleHtmlDomNodeBlank();
- }
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null)
- {
- return new SimpleHtmlDomNodeBlank();
- }
-
- /**
- * Create a new "HtmlDomParser"-object from the current context.
- *
- * @return HtmlDomParser
- */
- public function getHtmlDomParser(): HtmlDomParser
- {
- return new HtmlDomParser($this);
- }
-
- /**
- * @return \DOMNode
- */
- public function getNode(): \DOMNode
- {
- return new \DOMNode();
- }
-
- /**
- * Nodes can get partially destroyed in which they're still an
- * actual DOM node (such as \DOMElement) but almost their entire
- * body is gone, including the `nodeType` attribute.
- *
- * @return bool true if node has been destroyed
- */
- public function isRemoved(): bool
- {
- return true;
- }
-
- /**
- * Returns the last child of node.
- *
- * @return null
- */
- public function lastChild()
- {
- return null;
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return null
- */
- public function nextSibling()
- {
- return null;
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return null
- */
- public function nextNonWhitespaceSibling()
- {
- return null;
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return null
- */
- public function previousNonWhitespaceSibling()
- {
- return null;
- }
-
- /**
- * Returns the parent of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function parentNode(): ?SimpleHtmlDomInterface
- {
- return new static();
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return null
- */
- public function previousSibling()
- {
- return null;
- }
-
- /**
- * @param string|string[]|null $value
- * null === get the current input value
- * text === set a new input value
- *
- *
- * @return string|string[]|null
- */
- public function val($value = null)
- {
- return null;
- }
-
- /**
- * Retrieve an external iterator.
- *
- * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
- *
- * @return SimpleHtmlDomNodeInterface
- *
- * An instance of an object implementing Iterator or
- * Traversable
- *
- */
- public function getIterator(): SimpleHtmlDomNodeInterface
- {
- return new SimpleHtmlDomNodeBlank();
- }
-
- /**
- * Get dom node's inner xml.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
- {
- return '';
- }
-
- /**
- * Delete
- *
- * @return void
- */
- public function delete()
- {
- $this->outertext='';
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php
deleted file mode 100644
index 1a01bfb..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php
+++ /dev/null
@@ -1,391 +0,0 @@
-Get dom node's outer html (alias for "outerHtml").
- * @property string $outerhtml
- * Get dom node's outer html.
- * @property string $innertext
- * Get dom node's inner html (alias for "innerHtml").
- * @property string $innerhtml
- * Get dom node's inner html.
- * @property string $innerhtmlKeep
- * Get dom node's inner html + keep fix for broken html.
- * @property string $plaintext
- * Get dom node's plain text.
- * @property string $class
- * Get dom node's class attribute.
- * @property string $id
- * Get dom node's id attribute.
- * @property SimpleHtmlAttributes $classList
- * Get dom node attributes.
- * @property-read string $tag
- * Get dom node name.
- * @property-read string $attr
- * Get dom node attributes.
- * @property-read string $text
- * Get dom node name.
- * @property-read string $html
- * Get dom node's outer html.
- *
- * @method SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface|null children() children($idx = -1)
- * Returns children of node.
- * @method SimpleHtmlDomInterface|null first_child()
- * Returns the first child of node.
- * @method SimpleHtmlDomInterface|null last_child()
- * Returns the last child of node.
- * @method SimpleHtmlDomInterface|null next_sibling()
- * Returns the next sibling of node.
- * @method SimpleHtmlDomInterface|null prev_sibling()
- * Returns the previous sibling of node.
- * @method SimpleHtmlDomInterface|null parent()
- * Returns the parent of node.
- * @method string outerText()
- * Get dom node's outer html (alias for "outerHtml()").
- * @method string outerHtml()
- * Get dom node's outer html.
- * @method string innerText()
- * Get dom node's inner html (alias for "innerHtml()").
- *
- * @extends \IteratorAggregate
- */
-interface SimpleHtmlDomInterface extends \IteratorAggregate
-{
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleHtmlDomInterface|string|null
- */
- public function __call($name, $arguments);
-
- /**
- * @param string $name
- *
- * @return array|string|null
- */
- public function __get($name);
-
- /**
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function __invoke($selector, $idx = null);
-
- /**
- * @param string $name
- *
- * @return bool
- */
- public function __isset($name);
-
- /**
- * @return string
- */
- public function __toString();
-
- /**
- * Return the tag of node
- *
- * @return string
- */
- public function getTag():string;
-
- /**
- * Returns children of node.
- *
- * @param int $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface|null
- */
- public function childNodes(int $idx = -1);
-
- /**
- * Find list of nodes with a CSS selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function find(string $selector, $idx = null);
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleHtmlDomNodeInterface;
-
- /**
- * Find nodes with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector);
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface
- */
- public function findOne(string $selector): self;
-
- /**
- * Find one node with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomInterface
- */
- public function findOneOrFalse(string $selector);
-
- /**
- * Returns the first child of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function firstChild();
-
- /**
- * Returns an array of attributes.
- *
- * @return string[]|null
- */
- public function getAllAttributes();
-
- /**
- * Return attribute value.
- *
- * @param string $name
- *
- * @return string
- */
- public function getAttribute(string $name): string;
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function getElementByClass(string $class);
-
- /**
- * Return element by "#id".
- *
- * @param string $id
- *
- * @return SimpleHtmlDomInterface
- */
- public function getElementById(string $id): self;
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleHtmlDomInterface
- */
- public function getElementByTagName(string $name): self;
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null);
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null);
-
- /**
- * Create a new "HtmlDomParser"-object from the current context.
- *
- * @return HtmlDomParser
- */
- public function getHtmlDomParser(): HtmlDomParser;
-
- /**
- * Retrieve an external iterator.
- *
- * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
- *
- * @return SimpleHtmlDomNodeInterface
- *
- * An instance of an object implementing Iterator or
- * Traversable
- *
- */
- public function getIterator(): SimpleHtmlDomNodeInterface;
-
- /**
- * @return \DOMNode
- */
- public function getNode(): \DOMNode;
-
- /**
- * Determine if an attribute exists on the element.
- *
- * @param string $name
- *
- * @return bool
- */
- public function hasAttribute(string $name): bool;
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function html(bool $multiDecodeNewHtmlEntity = false): string;
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string;
-
- /**
- * Nodes can get partially destroyed in which they're still an
- * actual DOM node (such as \DOMElement) but almost their entire
- * body is gone, including the `nodeType` attribute.
- *
- * @return bool true if node has been destroyed
- */
- public function isRemoved(): bool;
-
- /**
- * Returns the last child of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function lastChild();
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function nextSibling();
-
- /**
- * Returns the next sibling of node, and it will ignore whitespace elements.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function nextNonWhitespaceSibling();
-
- /**
- * Returns the previous sibling of node, and it will ignore whitespace elements.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function previousNonWhitespaceSibling();
-
- /**
- * Returns the parent of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function parentNode(): ?self;
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleHtmlDomInterface|null
- */
- public function previousSibling();
-
- /**
- * Remove attribute.
- *
- * @param string $name The name of the html-attribute.
- *
- * @return SimpleHtmlDomInterface
- */
- public function removeAttribute(string $name): self;
-
- /**
- * Set attribute value.
- *
- * @param string $name The name of the html-attribute.
- * @param string|null $value Set to NULL or empty string, to remove the attribute.
- * @param bool $strictEmptyValueCheck
- * $value must be NULL, to remove the attribute,
- * so that you can set an empty string as attribute-value e.g. autofocus=""
- *
- *
- * @return SimpleHtmlDomInterface
- */
- public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): self;
-
- /**
- * Remove all attributes
- *
- * @return SimpleHtmlDomInterface
- */
- public function removeAttributes(): self;
-
- /**
- * Get dom node's plain text.
- *
- * @return string
- */
- public function text(): string;
-
- /**
- * @param string|string[]|null $value
- * null === get the current input value
- * text === set a new input value
- *
- *
- * @return string|string[]|null
- */
- public function val($value = null);
-
- /**
- * Delete
- *
- * @return mixed
- */
- public function delete();
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php
deleted file mode 100644
index 8b491ed..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php
+++ /dev/null
@@ -1,161 +0,0 @@
-|SimpleHtmlDomNodeInterface[]|null
- */
- public function find(string $selector, $idx = null)
- {
- // init
- $elements = new static();
-
- foreach ($this as $node) {
- \assert($node instanceof SimpleHtmlDomInterface);
- foreach ($node->find($selector) as $res) {
- $elements[] = $res;
- }
- }
-
- // return all elements
- if ($idx === null) {
- if (\count($elements) === 0) {
- return new SimpleHtmlDomNodeBlank();
- }
-
- return $elements;
- }
-
- // handle negative values
- if ($idx < 0) {
- $idx = \count($elements) + $idx;
- }
-
- // return one element
- return $elements[$idx] ?? null;
- }
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleHtmlDomNodeInterface
- {
- return $this->find($selector, null);
- }
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector)
- {
- $return = $this->find($selector, null);
-
- if ($return instanceof SimpleHtmlDomNodeBlank) {
- return false;
- }
-
- return $return;
- }
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function findOne(string $selector)
- {
- $return = $this->find($selector, 0);
-
- return $return ?? new SimpleHtmlDomNodeBlank();
- }
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomNodeInterface
- */
- public function findOneOrFalse(string $selector)
- {
- $return = $this->find($selector, 0);
-
- return $return ?? false;
- }
-
- /**
- * Get html of elements.
- *
- * @return string[]
- */
- public function innerHtml(): array
- {
- // init
- $html = [];
-
- foreach ($this as $node) {
- $html[] = $node->outertext;
- }
-
- return $html;
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function innertext()
- {
- return $this->innerHtml();
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function outertext()
- {
- return $this->innerHtml();
- }
-
- /**
- * Get plain text.
- *
- * @return string[]
- */
- public function text(): array
- {
- // init
- $text = [];
-
- foreach ($this as $node) {
- $text[] = $node->plaintext;
- }
-
- return $text;
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php
deleted file mode 100644
index ea31cfe..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php
+++ /dev/null
@@ -1,106 +0,0 @@
-
- */
- public function findMulti(string $selector): SimpleHtmlDomNodeInterface
- {
- return new self();
- }
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findMultiOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface
- */
- public function findOne(string $selector)
- {
- return new SimpleHtmlDomBlank();
- }
-
- /**
- * Find one node with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findOneOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * @return string[]
- */
- public function innerHtml(): array
- {
- return [];
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function innertext()
- {
- return [];
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function outertext()
- {
- return [];
- }
-
- /**
- * @return string[]
- */
- public function text(): array
- {
- return [];
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php
deleted file mode 100644
index e2990ea..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php
+++ /dev/null
@@ -1,117 +0,0 @@
-The list items count.
- * @property-read string[] $outertext
- * Get dom node's outer html.
- * @property-read string[] $plaintext
- * Get dom node's plain text.
- *
- * @extends \IteratorAggregate
- */
-interface SimpleHtmlDomNodeInterface extends \IteratorAggregate
-{
- /**
- * @param string $name
- *
- * @return array|null
- */
- public function __get($name);
-
- /**
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleHtmlDomNodeInterface|SimpleHtmlDomNodeInterface[]|null
- */
- public function __invoke($selector, $idx = null);
-
- /**
- * @return string
- */
- public function __toString();
-
- /**
- * Get the number of items in this dom node.
- *
- * @return int
- */
- public function count();
-
- /**
- * Find list of nodes with a CSS selector.
- *
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleHtmlDomNode|SimpleHtmlDomNode[]|null
- */
- public function find(string $selector, $idx = null);
-
- /**
- * Find nodes with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMulti(string $selector): self;
-
- /**
- * Find nodes with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector);
-
- /**
- * Find one node with a CSS selector.
- *
- * @param string $selector
- *
- * @return SimpleHtmlDomNodeInterface
- */
- public function findOne(string $selector);
-
- /**
- * Find one node with a CSS selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleHtmlDomNodeInterface
- */
- public function findOneOrFalse(string $selector);
-
- /**
- * Get html of elements.
- *
- * @return string[]
- */
- public function innerHtml(): array;
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function innertext();
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function outertext();
-
- /**
- * Get plain text.
- *
- * @return string[]
- */
- public function text(): array;
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDom.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDom.php
deleted file mode 100644
index a4cebb2..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleXmlDom.php
+++ /dev/null
@@ -1,843 +0,0 @@
-
- */
-class SimpleXmlDom extends AbstractSimpleXmlDom implements \IteratorAggregate, SimpleXmlDomInterface
-{
- /**
- * @param \DOMElement|\DOMNode $node
- */
- public function __construct(\DOMNode $node)
- {
- $this->node = $node;
- }
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleXmlDomInterface|string|null
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /**
- * Find list of nodes with a CSS or xPath selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function find(string $selector, $idx = null)
- {
- return $this->getXmlDomParser()->find($selector, $idx);
- }
-
- /**
- * Returns an array of attributes.
- *
- * @return string[]|null
- */
- public function getAllAttributes()
- {
- if (
- $this->node
- &&
- $this->node->hasAttributes()
- ) {
- $attributes = [];
- foreach ($this->node->attributes ?? [] as $attr) {
- $attributes[$attr->name] = XmlDomParser::putReplacedBackToPreserveHtmlEntities($attr->value);
- }
-
- return $attributes;
- }
-
- return null;
- }
-
- /**
- * @return bool
- */
- public function hasAttributes(): bool
- {
- return $this->node->hasAttributes();
- }
-
- /**
- * Return attribute value.
- *
- * @param string $name
- *
- * @return string
- */
- public function getAttribute(string $name): string
- {
- if ($this->node instanceof \DOMElement) {
- return XmlDomParser::putReplacedBackToPreserveHtmlEntities(
- $this->node->getAttribute($name)
- );
- }
-
- return '';
- }
-
- /**
- * Determine if an attribute exists on the element.
- *
- * @param string $name
- *
- * @return bool
- */
- public function hasAttribute(string $name): bool
- {
- if (!$this->node instanceof \DOMElement) {
- return false;
- }
-
- return $this->node->hasAttribute($name);
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
- {
- return $this->getXmlDomParser()->innerXml($multiDecodeNewHtmlEntity);
- }
-
- /**
- * Remove attribute.
- *
- * @param string $name The name of the html-attribute.
- *
- * @return SimpleXmlDomInterface
- */
- public function removeAttribute(string $name): SimpleXmlDomInterface
- {
- if (\method_exists($this->node, 'removeAttribute')) {
- $this->node->removeAttribute($name);
- }
-
- return $this;
- }
-
- /**
- * Replace child node.
- *
- * @param string $string
- * @param bool $putBrokenReplacedBack
- *
- * @return SimpleXmlDomInterface
- */
- protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleXmlDomInterface
- {
- if (!empty($string)) {
- $newDocument = new XmlDomParser($string);
-
- $tmpDomString = $this->normalizeStringForComparision($newDocument);
- $tmpStr = $this->normalizeStringForComparision($string);
-
- if ($tmpDomString !== $tmpStr) {
- throw new \RuntimeException(
- 'Not valid XML fragment!' . "\n" .
- $tmpDomString . "\n" .
- $tmpStr
- );
- }
- }
-
- /** @var \DOMNode[] $remove_nodes */
- $remove_nodes = [];
- if ($this->node->childNodes->length > 0) {
- // INFO: We need to fetch the nodes first, before we can delete them, because of missing references in the dom,
- // if we delete the elements on the fly.
- foreach ($this->node->childNodes as $node) {
- $remove_nodes[] = $node;
- }
- }
- foreach ($remove_nodes as $remove_node) {
- $this->node->removeChild($remove_node);
- }
-
- if (!empty($newDocument)) {
- $ownerDocument = $this->node->ownerDocument;
- if (
- $ownerDocument
- &&
- $newDocument->getDocument()->documentElement
- ) {
- $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
- /** @noinspection UnusedFunctionResultInspection */
- $this->node->appendChild($newNode);
- }
- }
-
- return $this;
- }
-
- /**
- * Replace this node.
- *
- * @param string $string
- *
- * @return SimpleXmlDomInterface
- */
- protected function replaceNodeWithString(string $string): SimpleXmlDomInterface
- {
- if (empty($string)) {
- if ($this->node->parentNode) {
- $this->node->parentNode->removeChild($this->node);
- }
-
- return $this;
- }
-
- $newDocument = new XmlDomParser($string);
-
- $tmpDomOuterTextString = $this->normalizeStringForComparision($newDocument);
- $tmpStr = $this->normalizeStringForComparision($string);
-
- if ($tmpDomOuterTextString !== $tmpStr) {
- throw new \RuntimeException(
- 'Not valid XML fragment!' . "\n"
- . $tmpDomOuterTextString . "\n" .
- $tmpStr
- );
- }
-
- $ownerDocument = $this->node->ownerDocument;
- if (
- $ownerDocument === null
- ||
- $newDocument->getDocument()->documentElement === null
- ) {
- return $this;
- }
-
- $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
-
- $this->node->parentNode->replaceChild($newNode, $this->node);
- $this->node = $newNode;
-
- return $this;
- }
-
- /**
- * Replace this node with text
- *
- * @param string $string
- *
- * @return SimpleXmlDomInterface
- */
- protected function replaceTextWithString($string): SimpleXmlDomInterface
- {
- if (empty($string)) {
- if ($this->node->parentNode) {
- $this->node->parentNode->removeChild($this->node);
- }
-
- return $this;
- }
-
- $ownerDocument = $this->node->ownerDocument;
- if ($ownerDocument) {
- $newElement = $ownerDocument->createTextNode($string);
- $newNode = $ownerDocument->importNode($newElement, true);
- $this->node->parentNode->replaceChild($newNode, $this->node);
- $this->node = $newNode;
- }
-
- return $this;
- }
-
- /**
- * Set attribute value.
- *
- * @param string $name The name of the html-attribute.
- * @param string|null $value Set to NULL or empty string, to remove the attribute.
- * @param bool $strictEmptyValueCheck
- * $value must be NULL, to remove the attribute,
- * so that you can set an empty string as attribute-value e.g. autofocus=""
- *
- *
- * @return SimpleXmlDomInterface
- */
- public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleXmlDomInterface
- {
- if (
- ($strictEmptyValueCheck && $value === null)
- ||
- (!$strictEmptyValueCheck && empty($value))
- ) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->removeAttribute($name);
- } elseif (\method_exists($this->node, 'setAttribute')) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->node->setAttribute($name, HtmlDomParser::replaceToPreserveHtmlEntities((string) $value));
- }
-
- return $this;
- }
-
- /**
- * Get dom node's plain text.
- *
- * @return string
- */
- public function text(): string
- {
- return $this->getXmlDomParser()->fixHtmlOutput($this->node->textContent);
- }
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function xml(bool $multiDecodeNewHtmlEntity = false): string
- {
- return $this->getXmlDomParser()->xml($multiDecodeNewHtmlEntity, false);
- }
-
- /**
- * Change the name of a tag in a "DOMNode".
- *
- * @param \DOMNode $node
- * @param string $name
- *
- * @return \DOMElement|false
- * DOMElement a new instance of class DOMElement or false
- * if an error occured.
- */
- protected function changeElementName(\DOMNode $node, string $name)
- {
- $ownerDocument = $node->ownerDocument;
- if (!$ownerDocument) {
- return false;
- }
-
- $newNode = $ownerDocument->createElement($name);
-
- foreach ($node->childNodes as $child) {
- $child = $ownerDocument->importNode($child, true);
- $newNode->appendChild($child);
- }
-
- foreach ($node->attributes ?? [] as $attrName => $attrNode) {
- /** @noinspection UnusedFunctionResultInspection */
- $newNode->setAttribute($attrName, $attrNode);
- }
-
- if ($newNode->ownerDocument) {
- /** @noinspection UnusedFunctionResultInspection */
- $newNode->ownerDocument->replaceChild($newNode, $node);
- }
-
- return $newNode;
- }
-
- /**
- * Returns children of node.
- *
- * @param int $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface|null
- */
- public function childNodes(int $idx = -1)
- {
- $nodeList = $this->getIterator();
-
- if ($idx === -1) {
- return $nodeList;
- }
-
- return $nodeList[$idx] ?? null;
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleXmlDomNodeInterface
- {
- return $this->getXmlDomParser()->findMulti($selector);
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector)
- {
- return $this->getXmlDomParser()->findMultiOrFalse($selector);
- }
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface
- */
- public function findOne(string $selector): SimpleXmlDomInterface
- {
- return $this->getXmlDomParser()->findOne($selector);
- }
-
- /**
- * Find one node with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface
- */
- public function findOneOrFalse(string $selector)
- {
- return $this->getXmlDomParser()->findOneOrFalse($selector);
- }
-
- /**
- * Returns the first child of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function firstChild()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->firstChild;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementByClass(string $class): SimpleXmlDomNodeInterface
- {
- return $this->findMulti(".{$class}");
- }
-
- /**
- * Return element by #id.
- *
- * @param string $id
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementById(string $id): SimpleXmlDomInterface
- {
- return $this->findOne("#{$id}");
- }
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementByTagName(string $name): SimpleXmlDomInterface
- {
- if ($this->node instanceof \DOMElement) {
- $node = $this->node->getElementsByTagName($name)->item(0);
- } else {
- $node = null;
- }
-
- if ($node === null) {
- return new SimpleXmlDomBlank();
- }
-
- return new static($node);
- }
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null)
- {
- return $this->find("#{$id}", $idx);
- }
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null)
- {
- if ($this->node instanceof \DOMElement) {
- $nodesList = $this->node->getElementsByTagName($name);
- } else {
- $nodesList = [];
- }
-
- $elements = new SimpleXmlDomNode();
-
- foreach ($nodesList as $node) {
- $elements[] = new static($node);
- }
-
- // return all elements
- if ($idx === null) {
- if (\count($elements) === 0) {
- return new SimpleXmlDomNodeBlank();
- }
-
- return $elements;
- }
-
- // handle negative values
- if ($idx < 0) {
- $idx = \count($elements) + $idx;
- }
-
- // return one element
- return $elements[$idx] ?? new SimpleXmlDomBlank();
- }
-
- /**
- * @return \DOMNode
- */
- public function getNode(): \DOMNode
- {
- return $this->node;
- }
-
- /**
- * Create a new "XmlDomParser"-object from the current context.
- *
- * @return XmlDomParser
- */
- public function getXmlDomParser(): XmlDomParser
- {
- return new XmlDomParser($this);
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
- {
- return $this->getXmlDomParser()->innerHtml($multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
- }
-
- /**
- * Nodes can get partially destroyed in which they're still an
- * actual DOM node (such as \DOMElement) but almost their entire
- * body is gone, including the `nodeType` attribute.
- *
- * @return bool true if node has been destroyed
- */
- public function isRemoved(): bool
- {
- return !isset($this->node->nodeType);
- }
-
- /**
- * Returns the last child of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function lastChild()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->lastChild;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function nextSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->nextSibling;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function nextNonWhitespaceSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->nextSibling;
-
- if ($node === null) {
- return null;
- }
-
- while ($node && !\trim($node->textContent)) {
- /** @var \DOMNode|null $node */
- $node = $node->nextSibling;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the parent of node.
- *
- * @return SimpleXmlDomInterface
- */
- public function parentNode(): SimpleXmlDomInterface
- {
- return new static($this->node->parentNode);
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function previousSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->previousSibling;
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function previousNonWhitespaceSibling()
- {
- /** @var \DOMNode|null $node */
- $node = $this->node->previousSibling;
-
- while ($node && !\trim($node->textContent)) {
- /** @var \DOMNode|null $node */
- $node = $node->previousSibling;
- }
-
- if ($node === null) {
- return null;
- }
-
- return new static($node);
- }
-
- /**
- * @param string|string[]|null $value
- * null === get the current input value
- * text === set a new input value
- *
- *
- * @return string|string[]|null
- */
- public function val($value = null)
- {
- if ($value === null) {
- if (
- $this->tag === 'input'
- &&
- (
- $this->getAttribute('type') === 'hidden'
- ||
- $this->getAttribute('type') === 'text'
- ||
- !$this->hasAttribute('type')
- )
- ) {
- return $this->getAttribute('value');
- }
-
- if (
- $this->hasAttribute('checked')
- &&
- \in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)
- ) {
- return $this->getAttribute('value');
- }
-
- if ($this->node->nodeName === 'select') {
- $valuesFromDom = [];
- $options = $this->getElementsByTagName('option');
- if ($options instanceof SimpleXmlDomNode) {
- foreach ($options as $option) {
- if ($this->hasAttribute('checked')) {
- $valuesFromDom[] = (string) $option->getAttribute('value');
- }
- }
- }
-
- if (\count($valuesFromDom) === 0) {
- return null;
- }
-
- return $valuesFromDom;
- }
-
- if ($this->node->nodeName === 'textarea') {
- return $this->node->nodeValue;
- }
- } else {
- /** @noinspection NestedPositiveIfStatementsInspection */
- if (\in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)) {
- if ($value === $this->getAttribute('value')) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->setAttribute('checked', 'checked');
- } else {
- /** @noinspection UnusedFunctionResultInspection */
- $this->removeAttribute('checked');
- }
- } elseif ($this->node instanceof \DOMElement && $this->node->nodeName === 'select') {
- foreach ($this->node->getElementsByTagName('option') as $option) {
- /** @var \DOMElement $option */
- if ($value === $option->getAttribute('value')) {
- /** @noinspection UnusedFunctionResultInspection */
- $option->setAttribute('selected', 'selected');
- } else {
- $option->removeAttribute('selected');
- }
- }
- } elseif ($this->node->nodeName === 'input' && \is_string($value)) {
- // Set value for input elements
- /** @noinspection UnusedFunctionResultInspection */
- $this->setAttribute('value', $value);
- } elseif ($this->node->nodeName === 'textarea' && \is_string($value)) {
- $this->node->nodeValue = $value;
- }
- }
-
- return null;
- }
-
- /**
- * Retrieve an external iterator.
- *
- * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
- *
- * @return SimpleXmlDomNode
- *
- * An instance of an object implementing Iterator or
- * Traversable
- *
- */
- public function getIterator(): SimpleXmlDomNodeInterface
- {
- $elements = new SimpleXmlDomNode();
- if ($this->node->hasChildNodes()) {
- foreach ($this->node->childNodes as $node) {
- $elements[] = new static($node);
- }
- }
-
- return $elements;
- }
-
- /**
- * Normalize the given input for comparision.
- *
- * @param string|XmlDomParser $input
- *
- * @return string
- */
- private function normalizeStringForComparision($input): string
- {
- if ($input instanceof XmlDomParser) {
- $string = $input->html(false, false);
- } else {
- $string = (string) $input;
- }
-
- return
- \urlencode(
- \urldecode(
- \trim(
- \str_replace(
- [
- ' ',
- "\n",
- "\r",
- '/>',
- ],
- [
- '',
- '',
- '',
- '>',
- ],
- \strtolower($string)
- )
- )
- )
- );
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php
deleted file mode 100644
index 142d6cc..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php
+++ /dev/null
@@ -1,447 +0,0 @@
-
- */
-class SimpleXmlDomBlank extends AbstractSimpleXmlDom implements \IteratorAggregate, SimpleXmlDomInterface
-{
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleXmlDomInterface|string|null
- */
- public function __call($name, $arguments)
- {
- $name = \strtolower($name);
-
- if (isset(self::$functionAliases[$name])) {
- return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /**
- * Find list of nodes with a CSS or xPath selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomNodeInterface
- */
- public function find(string $selector, $idx = null)
- {
- return new SimpleXmlDomNodeBlank();
- }
-
- /**
- * Returns an array of attributes.
- *
- * @return null
- */
- public function getAllAttributes()
- {
- return null;
- }
-
- /**
- * @return bool
- */
- public function hasAttributes(): bool
- {
- return false;
- }
-
- /**
- * Return attribute value.
- *
- * @param string $name
- *
- * @return string
- */
- public function getAttribute(string $name): string
- {
- return '';
- }
-
- /**
- * Determine if an attribute exists on the element.
- *
- * @param string $name
- *
- * @return bool
- */
- public function hasAttribute(string $name): bool
- {
- return false;
- }
-
- /**
- * Get dom node's inner xml.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
- {
- return '';
- }
-
- /**
- * Remove attribute.
- *
- * @param string $name The name of the html-attribute.
- *
- * @return SimpleXmlDomInterface
- */
- public function removeAttribute(string $name): SimpleXmlDomInterface
- {
- return $this;
- }
-
- /**
- * @param string $string
- * @param bool $putBrokenReplacedBack
- *
- * @return SimpleXmlDomInterface
- */
- protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * @param string $string
- *
- * @return SimpleXmlDomInterface
- */
- protected function replaceNodeWithString(string $string): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * @param string $string
- *
- * @return SimpleXmlDomInterface
- */
- protected function replaceTextWithString($string): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * Set attribute value.
- *
- * @param string $name The name of the html-attribute.
- * @param string|null $value Set to NULL or empty string, to remove the attribute.
- * @param bool $strictEmptyValueCheck
- * $value must be NULL, to remove the attribute,
- * so that you can set an empty string as attribute-value e.g. autofocus=""
- *
- *
- * @return SimpleXmlDomInterface
- */
- public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleXmlDomInterface
- {
- return $this;
- }
-
- /**
- * Get dom node's plain text.
- *
- * @return string
- */
- public function text(): string
- {
- return '';
- }
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function xml(bool $multiDecodeNewHtmlEntity = false): string
- {
- return '';
- }
-
- /**
- * Returns children of node.
- *
- * @param int $idx
- *
- * @return null
- */
- public function childNodes(int $idx = -1)
- {
- return null;
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleXmlDomNodeInterface
- {
- return new SimpleXmlDomNodeBlank();
- }
-
- /**
- * Find nodes with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findMultiOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface
- */
- public function findOne(string $selector): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * Find one node with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findOneOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * Returns the first child of node.
- *
- * @return null
- */
- public function firstChild()
- {
- return null;
- }
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleXmlDomNodeInterface
- */
- public function getElementByClass(string $class): SimpleXmlDomNodeInterface
- {
- return new SimpleXmlDomNodeBlank();
- }
-
- /**
- * Return element by #id.
- *
- * @param string $id
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementById(string $id): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementByTagName(string $name): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleXmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null)
- {
- return new SimpleXmlDomNodeBlank();
- }
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleXmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null)
- {
- return new SimpleXmlDomNodeBlank();
- }
-
- /**
- * @return \DOMNode
- */
- public function getNode(): \DOMNode
- {
- return new \DOMNode();
- }
-
- /**
- * Create a new "XmlDomParser"-object from the current context.
- *
- * @return XmlDomParser
- */
- public function getXmlDomParser(): XmlDomParser
- {
- return new XmlDomParser($this);
- }
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
- {
- return '';
- }
-
- /**
- * Nodes can get partially destroyed in which they're still an
- * actual DOM node (such as \DOMElement) but almost their entire
- * body is gone, including the `nodeType` attribute.
- *
- * @return bool true if node has been destroyed
- */
- public function isRemoved(): bool
- {
- return true;
- }
-
- /**
- * Returns the last child of node.
- *
- * @return null
- */
- public function lastChild()
- {
- return null;
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return null
- */
- public function nextSibling()
- {
- return null;
- }
-
- /**
- * Returns the next sibling of node.
- *
- * @return null
- */
- public function nextNonWhitespaceSibling()
- {
- return null;
- }
-
- /**
- * Returns the parent of node.
- *
- * @return SimpleXmlDomInterface
- */
- public function parentNode(): SimpleXmlDomInterface
- {
- return new static();
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return null
- */
- public function previousSibling()
- {
- return null;
- }
-
- /**
- * Returns the previous sibling of node.
- *
- * @return null
- */
- public function previousNonWhitespaceSibling()
- {
- return null;
- }
-
- /**
- * @param string|string[]|null $value
- * null === get the current input value
- * text === set a new input value
- *
- *
- * @return string|string[]|null
- */
- public function val($value = null)
- {
- return null;
- }
-
- /**
- * Retrieve an external iterator.
- *
- * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
- *
- * @return SimpleXmlDomNodeInterface
- *
- * An instance of an object implementing Iterator or
- * Traversable
- *
- */
- public function getIterator(): SimpleXmlDomNodeInterface
- {
- return new SimpleXmlDomNodeBlank();
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php
deleted file mode 100644
index e983ae6..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php
+++ /dev/null
@@ -1,367 +0,0 @@
-Get dom node's outer html (alias for "outerHtml").
- * @property string $outerhtml
- * Get dom node's outer html.
- * @property string $innertext
- * Get dom node's inner html (alias for "innerHtml").
- * @property string $innerhtml
- * Get dom node's inner html.
- * @property string $plaintext
- * Get dom node's plain text.
- * @property-read string $tag
- * Get dom node name.
- * @property-read string $attr
- * Get dom node attributes.
- * @property-read string $text
- * Get dom node name.
- * @property-read string $html
- * Get dom node's outer html.
- *
- * @method SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface|null children() children($idx = -1)
- * Returns children of node.
- * @method SimpleXmlDomInterface|null first_child()
- * Returns the first child of node.
- * @method SimpleXmlDomInterface|null last_child()
- * Returns the last child of node.
- * @method SimpleXmlDomInterface|null next_sibling()
- * Returns the next sibling of node.
- * @method SimpleXmlDomInterface|null prev_sibling()
- * Returns the previous sibling of node.
- * @method SimpleXmlDomInterface|null parent()
- * Returns the parent of node.
- * @method string outerText()
- * Get dom node's outer html (alias for "outerHtml()").
- * @method string outerHtml()
- * Get dom node's outer html.
- * @method string innerText()
- * Get dom node's inner html (alias for "innerHtml()").
- *
- * @extends \IteratorAggregate
- */
-interface SimpleXmlDomInterface extends \IteratorAggregate
-{
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- *
- * @return SimpleXmlDomInterface|string|null
- */
- public function __call($name, $arguments);
-
- /**
- * @param string $name
- *
- * @return array|string|null
- */
- public function __get($name);
-
- /**
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function __invoke($selector, $idx = null);
-
- /**
- * @param string $name
- *
- * @return bool
- */
- public function __isset($name);
-
- /**
- * @return string
- */
- public function __toString();
-
- /**
- * Returns children of node.
- *
- * @param int $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface|null
- */
- public function childNodes(int $idx = -1);
-
- /**
- * Find list of nodes with a CSS or xPath selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function find(string $selector, $idx = null);
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleXmlDomNodeInterface;
-
- /**
- * Find nodes with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector);
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface
- */
- public function findOne(string $selector): self;
-
- /**
- * Find one node with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface
- */
- public function findOneOrFalse(string $selector);
-
- /**
- * Returns the first child of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function firstChild();
-
- /**
- * Returns an array of attributes.
- *
- * @return string[]|null
- */
- public function getAllAttributes();
-
- /**
- * @return bool
- */
- public function hasAttributes(): bool;
-
- /**
- * Return attribute value.
- *
- * @param string $name
- *
- * @return string
- */
- public function getAttribute(string $name): string;
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementByClass(string $class);
-
- /**
- * Return element by "#id".
- *
- * @param string $id
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementById(string $id): self;
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementByTagName(string $name): self;
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null);
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null);
-
- /**
- * Retrieve an external iterator.
- *
- * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
- *
- * @return SimpleXmlDomNodeInterface
- *
- * An instance of an object implementing Iterator or
- * Traversable
- *
- */
- public function getIterator(): SimpleXmlDomNodeInterface;
-
- /**
- * @return \DOMNode
- */
- public function getNode(): \DOMNode;
-
- /**
- * Create a new "XmlDomParser"-object from the current context.
- *
- * @return XmlDomParser
- */
- public function getXmlDomParser(): XmlDomParser;
-
- /**
- * Determine if an attribute exists on the element.
- *
- * @param string $name
- *
- * @return bool
- */
- public function hasAttribute(string $name): bool;
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
-
- /**
- * Get dom node's inner html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function innerXml(bool $multiDecodeNewHtmlEntity = false): string;
-
- /**
- * Nodes can get partially destroyed in which they're still an
- * actual DOM node (such as \DOMElement) but almost their entire
- * body is gone, including the `nodeType` attribute.
- *
- * @return bool true if node has been destroyed
- */
- public function isRemoved(): bool;
-
- /**
- * Returns the last child of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function lastChild();
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function nextSibling();
-
- /**
- * Returns the next sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function nextNonWhitespaceSibling();
-
- /**
- * Returns the parent of node.
- *
- * @return SimpleXmlDomInterface
- */
- public function parentNode(): self;
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function previousSibling();
-
- /**
- * Returns the previous sibling of node.
- *
- * @return SimpleXmlDomInterface|null
- */
- public function previousNonWhitespaceSibling();
-
- /**
- * Remove attribute.
- *
- * @param string $name The name of the html-attribute.
- *
- * @return SimpleXmlDomInterface
- */
- public function removeAttribute(string $name): self;
-
- /**
- * Set attribute value.
- *
- * @param string $name The name of the html-attribute.
- * @param string|null $value Set to NULL or empty string, to remove the attribute.
- * @param bool $strictEmptyValueCheck
- * $value must be NULL, to remove the attribute,
- * so that you can set an empty string as attribute-value e.g. autofocus=""
- *
- *
- * @return SimpleXmlDomInterface
- */
- public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): self;
-
- /**
- * Get dom node's plain text.
- *
- * @return string
- */
- public function text(): string;
-
- /**
- * @param string|string[]|null $value
- * null === get the current input value
- * text === set a new input value
- *
- *
- * @return string|string[]|null
- */
- public function val($value = null);
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- *
- * @return string
- */
- public function xml(bool $multiDecodeNewHtmlEntity = false): string;
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php
deleted file mode 100644
index c41ff83..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php
+++ /dev/null
@@ -1,161 +0,0 @@
-|SimpleXmlDomNodeInterface[]|null
- */
- public function find(string $selector, $idx = null)
- {
- // init
- $elements = new static();
-
- foreach ($this as $node) {
- \assert($node instanceof SimpleXmlDomInterface);
- foreach ($node->find($selector) as $res) {
- $elements->append($res);
- }
- }
-
- // return all elements
- if ($idx === null) {
- if (\count($elements) === 0) {
- return new SimpleXmlDomNodeBlank();
- }
-
- return $elements;
- }
-
- // handle negative values
- if ($idx < 0) {
- $idx = \count($elements) + $idx;
- }
-
- // return one element
- return $elements[$idx] ?? null;
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleXmlDomNodeInterface
- {
- return $this->find($selector, null);
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector)
- {
- $return = $this->find($selector, null);
-
- if ($return instanceof SimpleXmlDomNodeBlank) {
- return false;
- }
-
- return $return;
- }
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomNodeInterface
- */
- public function findOne(string $selector)
- {
- $return = $this->find($selector, 0);
-
- return $return ?? new SimpleXmlDomNodeBlank();
- }
-
- /**
- * Find one node with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomNodeInterface
- */
- public function findOneOrFalse(string $selector)
- {
- $return = $this->find($selector, 0);
-
- return $return ?? false;
- }
-
- /**
- * Get html of elements.
- *
- * @return string[]
- */
- public function innerHtml(): array
- {
- // init
- $html = [];
-
- foreach ($this as $node) {
- $html[] = $node->outertext;
- }
-
- return $html;
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function innertext()
- {
- return $this->innerHtml();
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function outertext()
- {
- return $this->innerHtml();
- }
-
- /**
- * Get plain text.
- *
- * @return string[]
- */
- public function text(): array
- {
- // init
- $text = [];
-
- foreach ($this as $node) {
- $text[] = $node->plaintext;
- }
-
- return $text;
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php
deleted file mode 100644
index 2c079ce..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php
+++ /dev/null
@@ -1,104 +0,0 @@
-
- */
- public function findMulti(string $selector): SimpleXmlDomNodeInterface
- {
- return new self();
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return false
- */
- public function findMultiOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface
- */
- public function findOne(string $selector)
- {
- return new SimpleXmlDomBlank();
- }
-
- /**
- * @param string $selector
- *
- * @return false
- */
- public function findOneOrFalse(string $selector)
- {
- return false;
- }
-
- /**
- * @return string[]
- */
- public function innerHtml(): array
- {
- return [];
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function innertext()
- {
- return [];
- }
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function outertext()
- {
- return [];
- }
-
- /**
- * @return string[]
- */
- public function text(): array
- {
- return [];
- }
-}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php
deleted file mode 100644
index 67b601c..0000000
--- a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php
+++ /dev/null
@@ -1,117 +0,0 @@
-The list items count.
- * @property-read string[] $outertext
- * Get dom node's outer html.
- * @property-read string[] $plaintext
- * Get dom node's plain text.
- *
- * @extends \IteratorAggregate
- */
-interface SimpleXmlDomNodeInterface extends \IteratorAggregate
-{
- /**
- * @param string $name
- *
- * @return array|null
- */
- public function __get($name);
-
- /**
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleXmlDomNodeInterface|SimpleXmlDomNodeInterface[]|null
- */
- public function __invoke($selector, $idx = null);
-
- /**
- * @return string
- */
- public function __toString();
-
- /**
- * Get the number of items in this dom node.
- *
- * @return int
- */
- public function count();
-
- /**
- * Find list of nodes with a CSS or xPath selector.
- *
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleXmlDomNode|SimpleXmlDomNode[]|null
- */
- public function find(string $selector, $idx = null);
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMulti(string $selector): self;
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector);
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface
- */
- public function findOne(string $selector);
-
- /**
- * Find one node with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface
- */
- public function findOneOrFalse(string $selector);
-
- /**
- * Get html of elements.
- *
- * @return string[]
- */
- public function innerHtml(): array;
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function innertext();
-
- /**
- * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
- *
- * @return string[]
- */
- public function outertext();
-
- /**
- * Get plain text.
- *
- * @return string[]
- */
- public function text(): array;
-}
diff --git a/includes/classes/Dependencies/voku/helper/XmlDomParser.php b/includes/classes/Dependencies/voku/helper/XmlDomParser.php
deleted file mode 100644
index c53429e..0000000
--- a/includes/classes/Dependencies/voku/helper/XmlDomParser.php
+++ /dev/null
@@ -1,733 +0,0 @@
-Get dom node's plain text.
- *
- * @method static XmlDomParser file_get_xml($xml, $libXMLExtraOptions = null)
- * Load XML from file.
- * @method static XmlDomParser str_get_xml($xml, $libXMLExtraOptions = null)
- * Load XML from string.
- */
-class XmlDomParser extends AbstractDomParser
-{
- /**
- * @var callable|null
- *
- * @phpstan-var null|callable(string $cssSelectorString, string $xPathString, \DOMXPath, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string
- */
- private $callbackXPathBeforeQuery;
-
- /**
- * @var callable|null
- *
- * @phpstan-var null|callable(string $xmlString, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string
- */
- private $callbackBeforeCreateDom;
-
- /**
- * @var bool
- */
- private $autoRemoveXPathNamespaces = false;
-
- /**
- * @var bool
- */
- private $autoRegisterXPathNamespaces = false;
-
- /**
- * @var bool
- */
- private $reportXmlErrorsAsException = false;
-
- /**
- * @var string[]
- *
- * @phpstan-var array
- */
- private $xPathNamespaces = [];
-
- /**
- * @param \DOMNode|SimpleXmlDomInterface|string $element HTML code or SimpleXmlDomInterface, \DOMNode
- */
- public function __construct($element = null)
- {
- $this->document = new \DOMDocument('1.0', $this->getEncoding());
-
- // DOMDocument settings
- $this->document->preserveWhiteSpace = true;
- $this->document->formatOutput = true;
-
- if ($element instanceof SimpleXmlDomInterface) {
- $element = $element->getNode();
- }
-
- if ($element instanceof \DOMNode) {
- $domNode = $this->document->importNode($element, true);
-
- if ($domNode instanceof \DOMNode) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->document->appendChild($domNode);
- }
-
- return;
- }
-
- if ($element !== null) {
- $this->loadXml($element);
- }
- }
-
- /**
- * @param string $name
- * @param array $arguments
- *
- * @throws \BadMethodCallException
- * @throws \RuntimeException
- *
- * @return static
- */
- public static function __callStatic($name, $arguments)
- {
- $arguments0 = $arguments[0] ?? '';
-
- $arguments1 = $arguments[1] ?? null;
-
- if ($name === 'str_get_xml') {
- $parser = new static();
-
- return $parser->loadXml($arguments0, $arguments1);
- }
-
- if ($name === 'file_get_xml') {
- $parser = new static();
-
- return $parser->loadXmlFile($arguments0, $arguments1);
- }
-
- throw new \BadMethodCallException('Method does not exist');
- }
-
- /** @noinspection MagicMethodsValidityInspection */
-
- /**
- * @param string $name
- *
- * @return string|null
- */
- public function __get($name)
- {
- $name = \strtolower($name);
-
- if ($name === 'plaintext') {
- return $this->text();
- }
-
- return null;
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- return $this->xml(false, false, true, 0);
- }
-
- /**
- * Create DOMDocument from XML.
- *
- * @param string $xml
- * @param int|null $libXMLExtraOptions
- * @param bool $useDefaultLibXMLOptions
- *
- * @return \DOMDocument
- */
- protected function createDOMDocument(string $xml, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): \DOMDocument
- {
- if ($this->callbackBeforeCreateDom) {
- $xml = \call_user_func($this->callbackBeforeCreateDom, $xml, $this);
- }
-
- // set error level
- $internalErrors = \libxml_use_internal_errors(true);
- if (\PHP_VERSION_ID < 80000) {
- $disableEntityLoader = \libxml_disable_entity_loader(true);
- }
- \libxml_clear_errors();
-
- $optionsXml = 0;
- if ($useDefaultLibXMLOptions) {
- $optionsXml = \LIBXML_DTDLOAD | \LIBXML_DTDATTR | \LIBXML_NONET;
-
- if (\defined('LIBXML_BIGLINES')) {
- $optionsXml |= \LIBXML_BIGLINES;
- }
-
- if (\defined('LIBXML_COMPACT')) {
- $optionsXml |= \LIBXML_COMPACT;
- }
- }
-
- if ($libXMLExtraOptions !== null) {
- $optionsXml |= $libXMLExtraOptions;
- }
-
- $this->xPathNamespaces = []; // reset
- $matches = [];
- \preg_match_all('#xmlns:(?.*)=(["\'])(?.*)\\2#Ui', $xml, $matches);
- foreach ($matches['namespaceKey'] ?? [] as $index => $key) {
- if ($key) {
- $this->xPathNamespaces[\trim($key, ':')] = $matches['namespaceValue'][$index];
- }
- }
-
- if ($this->autoRemoveXPathNamespaces) {
- $xml = $this->removeXPathNamespaces($xml);
- }
-
- $xml = self::replaceToPreserveHtmlEntities($xml);
-
- $documentFound = false;
- $sxe = \simplexml_load_string($xml, \SimpleXMLElement::class, $optionsXml);
- $xmlErrors = \libxml_get_errors();
- if ($sxe !== false && \count($xmlErrors) === 0) {
- $domElementTmp = \dom_import_simplexml($sxe);
- if ($domElementTmp->ownerDocument instanceof \DOMDocument) {
- $documentFound = true;
- $this->document = $domElementTmp->ownerDocument;
- }
- }
-
- if ($documentFound === false) {
- // UTF-8 hack: http://php.net/manual/en/domdocument.loadhtml.php#95251
- $xmlHackUsed = false;
- /** @noinspection StringFragmentMisplacedInspection */
- if (\stripos('getEncoding() . '" ?>' . $xml;
- }
-
- $documentFound = $this->document->loadXML($xml, $optionsXml);
-
- // remove the "xml-encoding" hack
- if ($xmlHackUsed) {
- foreach ($this->document->childNodes as $child) {
- if ($child->nodeType === \XML_PI_NODE) {
- /** @noinspection UnusedFunctionResultInspection */
- $this->document->removeChild($child);
-
- break;
- }
- }
- }
- }
-
- if (
- $documentFound === false
- &&
- \count($xmlErrors) > 0
- ) {
- $errorStr = 'XML-Errors: ' . \print_r($xmlErrors, true) . ' in ' . \print_r($xml, true);
-
- if (!$this->reportXmlErrorsAsException) {
- \trigger_error($errorStr, \E_USER_WARNING);
- } else {
- throw new \InvalidArgumentException($errorStr);
- }
- }
-
- // set encoding
- $this->document->encoding = $this->getEncoding();
-
- // restore lib-xml settings
- \libxml_clear_errors();
- \libxml_use_internal_errors($internalErrors);
- if (\PHP_VERSION_ID < 80000 && isset($disableEntityLoader)) {
- \libxml_disable_entity_loader($disableEntityLoader);
- }
-
- return $this->document;
- }
-
- /**
- * Find list of nodes with a CSS or xPath selector.
- *
- * @param string $selector
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function find(string $selector, $idx = null)
- {
- $xPathQuery = SelectorConverter::toXPath($selector, true, false);
-
- $xPath = new \DOMXPath($this->document);
-
- if ($this->autoRegisterXPathNamespaces) {
- foreach ($this->xPathNamespaces as $key => $value) {
- $xPath->registerNamespace($key, $value);
- }
- }
-
- if ($this->callbackXPathBeforeQuery) {
- $xPathQuery = \call_user_func($this->callbackXPathBeforeQuery, $selector, $xPathQuery, $xPath, $this);
- }
-
- $nodesList = $xPath->query($xPathQuery);
-
- $elements = new SimpleXmlDomNode();
-
- if ($nodesList) {
- foreach ($nodesList as $node) {
- $elements[] = new SimpleXmlDom($node);
- }
- }
-
- // return all elements
- if ($idx === null) {
- if (\count($elements) === 0) {
- return new SimpleXmlDomNodeBlank();
- }
-
- return $elements;
- }
-
- // handle negative values
- if ($idx < 0) {
- $idx = \count($elements) + $idx;
- }
-
- // return one element
- return $elements[$idx] ?? new SimpleXmlDomBlank();
- }
-
- /**
- * Find nodes with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMulti(string $selector): SimpleXmlDomNodeInterface
- {
- return $this->find($selector, null);
- }
-
- /**
- * Find nodes with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function findMultiOrFalse(string $selector)
- {
- $return = $this->find($selector, null);
-
- if ($return instanceof SimpleXmlDomNodeBlank) {
- return false;
- }
-
- return $return;
- }
-
- /**
- * Find one node with a CSS or xPath selector.
- *
- * @param string $selector
- *
- * @return SimpleXmlDomInterface
- */
- public function findOne(string $selector): SimpleXmlDomInterface
- {
- return $this->find($selector, 0);
- }
-
- /**
- * Find one node with a CSS or xPath selector or false, if no element is found.
- *
- * @param string $selector
- *
- * @return false|SimpleXmlDomInterface
- */
- public function findOneOrFalse(string $selector)
- {
- $return = $this->find($selector, 0);
-
- if ($return instanceof SimpleXmlDomBlank) {
- return false;
- }
-
- return $return;
- }
-
- /**
- * @param string $content
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function fixHtmlOutput(
- string $content,
- bool $multiDecodeNewHtmlEntity = false,
- bool $putBrokenReplacedBack = true
- ): string {
- $content = $this->decodeHtmlEntity($content, $multiDecodeNewHtmlEntity);
-
- return self::putReplacedBackToPreserveHtmlEntities($content, $putBrokenReplacedBack);
- }
-
- /**
- * Return elements by ".class".
- *
- * @param string $class
- *
- * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementByClass(string $class): SimpleXmlDomNodeInterface
- {
- return $this->findMulti(".{$class}");
- }
-
- /**
- * Return element by #id.
- *
- * @param string $id
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementById(string $id): SimpleXmlDomInterface
- {
- return $this->findOne("#{$id}");
- }
-
- /**
- * Return element by tag name.
- *
- * @param string $name
- *
- * @return SimpleXmlDomInterface
- */
- public function getElementByTagName(string $name): SimpleXmlDomInterface
- {
- $node = $this->document->getElementsByTagName($name)->item(0);
-
- if ($node === null) {
- return new SimpleXmlDomBlank();
- }
-
- return new SimpleXmlDom($node);
- }
-
- /**
- * Returns elements by "#id".
- *
- * @param string $id
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementsById(string $id, $idx = null)
- {
- return $this->find("#{$id}", $idx);
- }
-
- /**
- * Returns elements by tag name.
- *
- * @param string $name
- * @param int|null $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function getElementsByTagName(string $name, $idx = null)
- {
- $nodesList = $this->document->getElementsByTagName($name);
-
- $elements = new SimpleXmlDomNode();
-
- foreach ($nodesList as $node) {
- $elements[] = new SimpleXmlDom($node);
- }
-
- // return all elements
- if ($idx === null) {
- if (\count($elements) === 0) {
- return new SimpleXmlDomNodeBlank();
- }
-
- return $elements;
- }
-
- // handle negative values
- if ($idx < 0) {
- $idx = \count($elements) + $idx;
- }
-
- // return one element
- return $elements[$idx] ?? new SimpleXmlDomNodeBlank();
- }
-
- /**
- * Get dom node's outer html.
- *
- * @param bool $multiDecodeNewHtmlEntity
- * @param bool $putBrokenReplacedBack
- *
- * @return string
- */
- public function html(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
- {
- if (static::$callback !== null) {
- \call_user_func(static::$callback, [$this]);
- }
-
- $content = $this->document->saveHTML();
-
- if ($content === false) {
- return '';
- }
-
- return $this->fixHtmlOutput($content, $multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
- }
-
- /**
- * Load HTML from string.
- *
- * @param string $html
- * @param int|null $libXMLExtraOptions
- *
- * @return $this
- */
- public function loadHtml(string $html, $libXMLExtraOptions = null): DomParserInterface
- {
- $this->document = $this->createDOMDocument($html, $libXMLExtraOptions);
-
- return $this;
- }
-
- /**
- * Load HTML from file.
- *
- * @param string $filePath
- * @param int|null $libXMLExtraOptions
- *
- * @throws \RuntimeException
- *
- * @return $this
- */
- public function loadHtmlFile(string $filePath, $libXMLExtraOptions = null): DomParserInterface
- {
- if (
- !\preg_match("/^https?:\/\//i", $filePath)
- &&
- !\file_exists($filePath)
- ) {
- throw new \RuntimeException("File {$filePath} not found");
- }
-
- try {
- if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
- $html = \PoweredCache\Dependencies\voku\helper\UTF8::file_get_contents($filePath);
- } else {
- $html = \file_get_contents($filePath);
- }
- } catch (\Exception $e) {
- throw new \RuntimeException("Could not load file {$filePath}");
- }
-
- if ($html === false) {
- throw new \RuntimeException("Could not load file {$filePath}");
- }
-
- return $this->loadHtml($html, $libXMLExtraOptions);
- }
-
- /**
- * @param string $selector
- * @param int $idx
- *
- * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
- */
- public function __invoke($selector, $idx = null)
- {
- return $this->find($selector, $idx);
- }
-
- /**
- * @param string $xml
- *
- * @return string
- */
- private function removeXPathNamespaces(string $xml): string
- {
- foreach ($this->xPathNamespaces as $key => $value) {
- $xml = \str_replace($key . ':', '', $xml);
- }
-
- return (string) \preg_replace('#xmlns:?.*=(["\'])(?:.*)\\1#Ui', '', $xml);
- }
-
- /**
- * Load XML from string.
- *
- * @param string $xml
- * @param int|null $libXMLExtraOptions
- * @param bool $useDefaultLibXMLOptions
- *
- * @return $this
- */
- public function loadXml(string $xml, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): self
- {
- $this->document = $this->createDOMDocument($xml, $libXMLExtraOptions, $useDefaultLibXMLOptions);
-
- return $this;
- }
-
- /**
- * Load XML from file.
- *
- * @param string $filePath
- * @param int|null $libXMLExtraOptions
- * @param bool $useDefaultLibXMLOptions
- *
- * @throws \RuntimeException
- *
- * @return $this
- */
- public function loadXmlFile(string $filePath, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): self
- {
- if (
- !\preg_match("/^https?:\/\//i", $filePath)
- &&
- !\file_exists($filePath)
- ) {
- throw new \RuntimeException("File {$filePath} not found");
- }
-
- try {
- if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
- $xml = \PoweredCache\Dependencies\voku\helper\UTF8::file_get_contents($filePath);
- } else {
- $xml = \file_get_contents($filePath);
- }
- } catch (\Exception $e) {
- throw new \RuntimeException("Could not load file {$filePath}");
- }
-
- if ($xml === false) {
- throw new \RuntimeException("Could not load file {$filePath}");
- }
-
- return $this->loadXml($xml, $libXMLExtraOptions, $useDefaultLibXMLOptions);
- }
-
- /**
- * @param callable $callback
- * @param \DOMNode|null $domNode
- *
- * @return void
- */
- public function replaceTextWithCallback($callback, \DOMNode $domNode = null)
- {
- if ($domNode === null) {
- $domNode = $this->document;
- }
-
- if ($domNode->hasChildNodes()) {
- $children = [];
-
- // since looping through a DOM being modified is a bad idea we prepare an array:
- foreach ($domNode->childNodes as $child) {
- $children[] = $child;
- }
-
- foreach ($children as $child) {
- if ($child->nodeType === \XML_TEXT_NODE) {
- /** @noinspection PhpSillyAssignmentInspection */
- /** @var \DOMText $child */
- $child = $child;
-
- $oldText = self::putReplacedBackToPreserveHtmlEntities($child->wholeText);
- $newText = $callback($oldText);
- if ($domNode->ownerDocument) {
- $newTextNode = $domNode->ownerDocument->createTextNode(self::replaceToPreserveHtmlEntities($newText));
- $domNode->replaceChild($newTextNode, $child);
- }
- } else {
- $this->replaceTextWithCallback($callback, $child);
- }
- }
- }
- }
-
- /**
- * @param bool $autoRemoveXPathNamespaces
- *
- * @return $this
- */
- public function autoRemoveXPathNamespaces(bool $autoRemoveXPathNamespaces = true): self
- {
- $this->autoRemoveXPathNamespaces = $autoRemoveXPathNamespaces;
-
- return $this;
- }
-
- /**
- * @param bool $autoRegisterXPathNamespaces
- *
- * @return $this
- */
- public function autoRegisterXPathNamespaces(bool $autoRegisterXPathNamespaces = true): self
- {
- $this->autoRegisterXPathNamespaces = $autoRegisterXPathNamespaces;
-
- return $this;
- }
-
- /**
- * @param callable $callbackXPathBeforeQuery
- *
- * @phpstan-param callable(string $cssSelectorString, string $xPathString, \DOMXPath, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string $callbackXPathBeforeQuery
- *
- * @return $this
- */
- public function setCallbackXPathBeforeQuery(callable $callbackXPathBeforeQuery): self
- {
- $this->callbackXPathBeforeQuery = $callbackXPathBeforeQuery;
-
- return $this;
- }
-
- /**
- * @param callable $callbackBeforeCreateDom
- *
- * @phpstan-param callable(string $xmlString, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string $callbackBeforeCreateDom
- *
- * @return $this
- */
- public function setCallbackBeforeCreateDom(callable $callbackBeforeCreateDom): self
- {
- $this->callbackBeforeCreateDom = $callbackBeforeCreateDom;
-
- return $this;
- }
-
- /**
- * @param bool $reportXmlErrorsAsException
- *
- * @return $this
- */
- public function reportXmlErrorsAsException(bool $reportXmlErrorsAsException = true): self
- {
- $this->reportXmlErrorsAsException = $reportXmlErrorsAsException;
-
- return $this;
- }
-}
From 620f0f0cd8c936fa60e8bc3c6b71288996f43905 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 08:59:58 +0000
Subject: [PATCH 8/9] Restore Dependencies directory and remove from gitignore
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.gitignore | 1 -
.../MatthiasMullie/Minify/CSS.php | 870 ++++++++
.../MatthiasMullie/Minify/Exception.php | 22 +
.../Minify/Exceptions/BasicException.php | 24 +
.../Minify/Exceptions/FileImportException.php | 22 +
.../Minify/Exceptions/IOException.php | 22 +
.../Dependencies/MatthiasMullie/Minify/JS.php | 618 +++++
.../MatthiasMullie/Minify/Minify.php | 560 +++++
.../PathConverter/Converter.php | 204 ++
.../PathConverter/ConverterInterface.php | 24 +
.../PathConverter/NoConverter.php | 23 +
.../MatthiasMullie/data/js/keywords_after.txt | 7 +
.../data/js/keywords_before.txt | 26 +
.../data/js/keywords_reserved.txt | 63 +
.../MatthiasMullie/data/js/operators.txt | 46 +
.../data/js/operators_after.txt | 43 +
.../data/js/operators_before.txt | 43 +
.../Component/CssSelector/CHANGELOG.md | 18 +
.../CssSelector/CssSelectorConverter.php | 69 +
.../Exception/ExceptionInterface.php | 24 +
.../Exception/ExpressionErrorException.php | 24 +
.../Exception/InternalErrorException.php | 24 +
.../CssSelector/Exception/ParseException.php | 24 +
.../Exception/SyntaxErrorException.php | 65 +
.../Symfony/Component/CssSelector/LICENSE | 19 +
.../CssSelector/Node/AbstractNode.php | 39 +
.../CssSelector/Node/AttributeNode.php | 82 +
.../Component/CssSelector/Node/ClassNode.php | 57 +
.../CssSelector/Node/CombinedSelectorNode.php | 66 +
.../CssSelector/Node/ElementNode.php | 59 +
.../CssSelector/Node/FunctionNode.php | 76 +
.../Component/CssSelector/Node/HashNode.php | 57 +
.../CssSelector/Node/NegationNode.php | 57 +
.../CssSelector/Node/NodeInterface.php | 31 +
.../Component/CssSelector/Node/PseudoNode.php | 57 +
.../CssSelector/Node/SelectorNode.php | 57 +
.../CssSelector/Node/Specificity.php | 73 +
.../Parser/Handler/CommentHandler.php | 48 +
.../Parser/Handler/HandlerInterface.php | 30 +
.../Parser/Handler/HashHandler.php | 58 +
.../Parser/Handler/IdentifierHandler.php | 58 +
.../Parser/Handler/NumberHandler.php | 54 +
.../Parser/Handler/StringHandler.php | 77 +
.../Parser/Handler/WhitespaceHandler.php | 46 +
.../Component/CssSelector/Parser/Parser.php | 353 +++
.../CssSelector/Parser/ParserInterface.php | 34 +
.../Component/CssSelector/Parser/Reader.php | 86 +
.../Parser/Shortcut/ClassParser.php | 51 +
.../Parser/Shortcut/ElementParser.php | 47 +
.../Parser/Shortcut/EmptyStringParser.php | 46 +
.../Parser/Shortcut/HashParser.php | 51 +
.../Component/CssSelector/Parser/Token.php | 111 +
.../CssSelector/Parser/TokenStream.php | 167 ++
.../Parser/Tokenizer/Tokenizer.php | 73 +
.../Parser/Tokenizer/TokenizerEscaping.php | 65 +
.../Parser/Tokenizer/TokenizerPatterns.php | 89 +
.../Symfony/Component/CssSelector/README.md | 20 +
.../Tests/CssSelectorConverterTest.php | 83 +
.../Tests/Node/AbstractNodeTestCase.php | 34 +
.../Tests/Node/AttributeNodeTest.php | 37 +
.../CssSelector/Tests/Node/ClassNodeTest.php | 33 +
.../Tests/Node/CombinedSelectorNodeTest.php | 35 +
.../Tests/Node/ElementNodeTest.php | 35 +
.../Tests/Node/FunctionNodeTest.php | 47 +
.../CssSelector/Tests/Node/HashNodeTest.php | 33 +
.../Tests/Node/NegationNodeTest.php | 33 +
.../CssSelector/Tests/Node/PseudoNodeTest.php | 32 +
.../Tests/Node/SelectorNodeTest.php | 34 +
.../Tests/Node/SpecificityTest.php | 63 +
.../Handler/AbstractHandlerTestCase.php | 70 +
.../Parser/Handler/CommentHandlerTest.php | 55 +
.../Tests/Parser/Handler/HashHandlerTest.php | 49 +
.../Parser/Handler/IdentifierHandlerTest.php | 49 +
.../Parser/Handler/NumberHandlerTest.php | 50 +
.../Parser/Handler/StringHandlerTest.php | 50 +
.../Parser/Handler/WhitespaceHandlerTest.php | 44 +
.../CssSelector/Tests/Parser/ParserTest.php | 263 +++
.../CssSelector/Tests/Parser/ReaderTest.php | 102 +
.../Tests/Parser/Shortcut/ClassParserTest.php | 45 +
.../Parser/Shortcut/ElementParserTest.php | 44 +
.../Parser/Shortcut/EmptyStringParserTest.php | 36 +
.../Tests/Parser/Shortcut/HashParserTest.php | 45 +
.../Tests/Parser/TokenStreamTest.php | 97 +
.../CssSelector/Tests/XPath/Fixtures/ids.html | 52 +
.../CssSelector/Tests/XPath/Fixtures/lang.xml | 11 +
.../Tests/XPath/Fixtures/shakespear.html | 308 +++
.../Tests/XPath/TranslatorTest.php | 416 ++++
.../XPath/Extension/AbstractExtension.php | 65 +
.../Extension/AttributeMatchingExtension.php | 119 +
.../XPath/Extension/CombinationExtension.php | 71 +
.../XPath/Extension/ExtensionInterface.php | 67 +
.../XPath/Extension/FunctionExtension.php | 171 ++
.../XPath/Extension/HtmlExtension.php | 187 ++
.../XPath/Extension/NodeExtension.php | 197 ++
.../XPath/Extension/PseudoClassExtension.php | 122 +
.../CssSelector/XPath/Translator.php | 230 ++
.../CssSelector/XPath/TranslatorInterface.php | 37 +
.../Component/CssSelector/XPath/XPathExpr.php | 111 +
.../Component/CssSelector/composer.json | 33 +
.../Component/CssSelector/phpunit.xml.dist | 31 +
.../Symfony/Polyfill/Php80/LICENSE | 19 +
.../Symfony/Polyfill/Php80/Php80.php | 115 +
.../Symfony/Polyfill/Php80/PhpToken.php | 106 +
.../Symfony/Polyfill/Php80/README.md | 25 +
.../Php80/Resources/stubs/Attribute.php | 31 +
.../Php80/Resources/stubs/PhpToken.php | 16 +
.../Php80/Resources/stubs/Stringable.php | 20 +
.../Resources/stubs/UnhandledMatchError.php | 16 +
.../Php80/Resources/stubs/ValueError.php | 16 +
.../Symfony/Polyfill/Php80/bootstrap.php | 42 +
.../Symfony/Polyfill/Php80/composer.json | 37 +
.../voku/helper/AbstractDomParser.php | 527 +++++
.../voku/helper/AbstractSimpleHtmlDom.php | 255 +++
.../voku/helper/AbstractSimpleHtmlDomNode.php | 80 +
.../voku/helper/AbstractSimpleXmlDom.php | 217 ++
.../voku/helper/AbstractSimpleXmlDomNode.php | 80 +
.../voku/helper/DomParserInterface.php | 201 ++
.../voku/helper/HtmlDomHelper.php | 72 +
.../voku/helper/HtmlDomParser.php | 1228 ++++++++++
.../Dependencies/voku/helper/HtmlMin.php | 1981 +++++++++++++++++
.../helper/HtmlMinDomObserverInterface.php | 28 +
.../HtmlMinDomObserverOptimizeAttributes.php | 381 ++++
.../voku/helper/HtmlMinInterface.php | 154 ++
.../voku/helper/SelectorConverter.php | 75 +
.../voku/helper/SimpleHtmlAttributes.php | 269 +++
.../helper/SimpleHtmlAttributesInterface.php | 82 +
.../voku/helper/SimpleHtmlDom.php | 1011 +++++++++
.../voku/helper/SimpleHtmlDomBlank.php | 472 ++++
.../voku/helper/SimpleHtmlDomInterface.php | 391 ++++
.../voku/helper/SimpleHtmlDomNode.php | 161 ++
.../voku/helper/SimpleHtmlDomNodeBlank.php | 106 +
.../helper/SimpleHtmlDomNodeInterface.php | 117 +
.../Dependencies/voku/helper/SimpleXmlDom.php | 843 +++++++
.../voku/helper/SimpleXmlDomBlank.php | 447 ++++
.../voku/helper/SimpleXmlDomInterface.php | 367 +++
.../voku/helper/SimpleXmlDomNode.php | 161 ++
.../voku/helper/SimpleXmlDomNodeBlank.php | 104 +
.../voku/helper/SimpleXmlDomNodeInterface.php | 117 +
.../Dependencies/voku/helper/XmlDomParser.php | 733 ++++++
139 files changed, 19988 insertions(+), 1 deletion(-)
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/JS.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/Minify/Minify.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php
create mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt
create mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt
create mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt
create mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt
create mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt
create mode 100644 includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/README.md
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json
create mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php
create mode 100644 includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json
create mode 100644 includes/classes/Dependencies/voku/helper/AbstractDomParser.php
create mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php
create mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php
create mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php
create mode 100644 includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php
create mode 100644 includes/classes/Dependencies/voku/helper/DomParserInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/HtmlDomHelper.php
create mode 100644 includes/classes/Dependencies/voku/helper/HtmlDomParser.php
create mode 100644 includes/classes/Dependencies/voku/helper/HtmlMin.php
create mode 100644 includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/HtmlMinDomObserverOptimizeAttributes.php
create mode 100644 includes/classes/Dependencies/voku/helper/HtmlMinInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/SelectorConverter.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDom.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php
create mode 100644 includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php
create mode 100644 includes/classes/Dependencies/voku/helper/XmlDomParser.php
diff --git a/.gitignore b/.gitignore
index 554862e..4c7d8f9 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@ node_modules
bower_components
release
vendor
-includes/classes/Dependencies
.idea
*.log
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php b/includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php
new file mode 100644
index 0000000..6b13213
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/Minify/CSS.php
@@ -0,0 +1,870 @@
+
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
+
+use PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions\FileImportException;
+use PoweredCache\Dependencies\MatthiasMullie\PathConverter\Converter;
+use PoweredCache\Dependencies\MatthiasMullie\PathConverter\ConverterInterface;
+
+/**
+ * CSS minifier.
+ *
+ * Please report bugs on https://github.com/matthiasmullie/minify/issues
+ *
+ * @author Matthias Mullie
+ * @author Tijs Verkoyen
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+class CSS extends Minify
+{
+ /**
+ * @var int maximum inport size in kB
+ */
+ protected $maxImportSize = 5;
+
+ /**
+ * @var string[] valid import extensions
+ */
+ protected $importExtensions = array(
+ 'gif' => 'data:image/gif',
+ 'png' => 'data:image/png',
+ 'jpe' => 'data:image/jpeg',
+ 'jpg' => 'data:image/jpeg',
+ 'jpeg' => 'data:image/jpeg',
+ 'svg' => 'data:image/svg+xml',
+ 'woff' => 'data:application/x-font-woff',
+ 'woff2' => 'data:application/x-font-woff2',
+ 'avif' => 'data:image/avif',
+ 'apng' => 'data:image/apng',
+ 'webp' => 'data:image/webp',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'xbm' => 'image/x-xbitmap',
+ );
+
+ /**
+ * Set the maximum size if files to be imported.
+ *
+ * Files larger than this size (in kB) will not be imported into the CSS.
+ * Importing files into the CSS as data-uri will save you some connections,
+ * but we should only import relatively small decorative images so that our
+ * CSS file doesn't get too bulky.
+ *
+ * @param int $size Size in kB
+ */
+ public function setMaxImportSize($size)
+ {
+ $this->maxImportSize = $size;
+ }
+
+ /**
+ * Set the type of extensions to be imported into the CSS (to save network
+ * connections).
+ * Keys of the array should be the file extensions & respective values
+ * should be the data type.
+ *
+ * @param string[] $extensions Array of file extensions
+ */
+ public function setImportExtensions(array $extensions)
+ {
+ $this->importExtensions = $extensions;
+ }
+
+ /**
+ * Move any import statements to the top.
+ *
+ * @param string $content Nearly finished CSS content
+ *
+ * @return string
+ */
+ protected function moveImportsToTop($content)
+ {
+ if (preg_match_all('/(;?)(@import (?url\()?(?P["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) {
+ // remove from content
+ foreach ($matches[0] as $import) {
+ $content = str_replace($import, '', $content);
+ }
+
+ // add to top
+ $content = implode(';', $matches[2]) . ';' . trim($content, ';');
+ }
+
+ return $content;
+ }
+
+ /**
+ * Combine CSS from import statements.
+ *
+ * \@import's will be loaded and their content merged into the original file,
+ * to save HTTP requests.
+ *
+ * @param string $source The file to combine imports for
+ * @param string $content The CSS content to combine imports for
+ * @param string[] $parents Parent paths, for circular reference checks
+ *
+ * @return string
+ *
+ * @throws FileImportException
+ */
+ protected function combineImports($source, $content, $parents)
+ {
+ $importRegexes = array(
+ // @import url(xxx)
+ '/
+ # import statement
+ @import
+
+ # whitespace
+ \s+
+
+ # open url()
+ url\(
+
+ # (optional) open path enclosure
+ (?P["\']?)
+
+ # fetch path
+ (?P.+?)
+
+ # (optional) close path enclosure
+ (?P=quotes)
+
+ # close url()
+ \)
+
+ # (optional) trailing whitespace
+ \s*
+
+ # (optional) media statement(s)
+ (?P[^;]*)
+
+ # (optional) trailing whitespace
+ \s*
+
+ # (optional) closing semi-colon
+ ;?
+
+ /ix',
+
+ // @import 'xxx'
+ '/
+
+ # import statement
+ @import
+
+ # whitespace
+ \s+
+
+ # open path enclosure
+ (?P["\'])
+
+ # fetch path
+ (?P.+?)
+
+ # close path enclosure
+ (?P=quotes)
+
+ # (optional) trailing whitespace
+ \s*
+
+ # (optional) media statement(s)
+ (?P[^;]*)
+
+ # (optional) trailing whitespace
+ \s*
+
+ # (optional) closing semi-colon
+ ;?
+
+ /ix',
+ );
+
+ // find all relative imports in css
+ $matches = array();
+ foreach ($importRegexes as $importRegex) {
+ if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
+ $matches = array_merge($matches, $regexMatches);
+ }
+ }
+
+ $search = array();
+ $replace = array();
+
+ // loop the matches
+ foreach ($matches as $match) {
+ // get the path for the file that will be imported
+ $importPath = dirname($source) . '/' . $match['path'];
+
+ // only replace the import with the content if we can grab the
+ // content of the file
+ if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
+ continue;
+ }
+
+ // check if current file was not imported previously in the same
+ // import chain.
+ if (in_array($importPath, $parents)) {
+ throw new FileImportException('Failed to import file "' . $importPath . '": circular reference detected.');
+ }
+
+ // grab referenced file & minify it (which may include importing
+ // yet other @import statements recursively)
+ $minifier = new self($importPath);
+ $minifier->setMaxImportSize($this->maxImportSize);
+ $minifier->setImportExtensions($this->importExtensions);
+ $importContent = $minifier->execute($source, $parents);
+
+ // check if this is only valid for certain media
+ if (!empty($match['media'])) {
+ $importContent = '@media ' . $match['media'] . '{' . $importContent . '}';
+ }
+
+ // add to replacement array
+ $search[] = $match[0];
+ $replace[] = $importContent;
+ }
+
+ // replace the import statements
+ return str_replace($search, $replace, $content);
+ }
+
+ /**
+ * Import files into the CSS, base64-ized.
+ *
+ * @url(image.jpg) images will be loaded and their content merged into the
+ * original file, to save HTTP requests.
+ *
+ * @param string $source The file to import files for
+ * @param string $content The CSS content to import files for
+ *
+ * @return string
+ */
+ protected function importFiles($source, $content)
+ {
+ $regex = '/url\((["\']?)(.+?)\\1\)/i';
+ if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
+ $search = array();
+ $replace = array();
+
+ // loop the matches
+ foreach ($matches as $match) {
+ $extension = substr(strrchr($match[2], '.'), 1);
+ if ($extension && !array_key_exists($extension, $this->importExtensions)) {
+ continue;
+ }
+
+ // get the path for the file that will be imported
+ $path = $match[2];
+ $path = dirname($source) . '/' . $path;
+
+ // only replace the import with the content if we're able to get
+ // the content of the file, and it's relatively small
+ if ($this->canImportFile($path) && $this->canImportBySize($path)) {
+ // grab content && base64-ize
+ $importContent = $this->load($path);
+ $importContent = base64_encode($importContent);
+
+ // build replacement
+ $search[] = $match[0];
+ $replace[] = 'url(' . $this->importExtensions[$extension] . ';base64,' . $importContent . ')';
+ }
+ }
+
+ // replace the import statements
+ $content = str_replace($search, $replace, $content);
+ }
+
+ return $content;
+ }
+
+ /**
+ * Minify the data.
+ * Perform CSS optimizations.
+ *
+ * @param string[optional] $path Path to write the data to
+ * @param string[] $parents Parent paths, for circular reference checks
+ *
+ * @return string The minified data
+ */
+ public function execute($path = null, $parents = array())
+ {
+ $content = '';
+
+ // loop CSS data (raw data and files)
+ foreach ($this->data as $source => $css) {
+ /*
+ * Let's first take out strings & comments, since we can't just
+ * remove whitespace anywhere. If whitespace occurs inside a string,
+ * we should leave it alone. E.g.:
+ * p { content: "a test" }
+ */
+ $this->extractStrings();
+ $this->stripComments();
+ $this->extractMath();
+ $this->extractCustomProperties();
+ $css = $this->replace($css);
+
+ $css = $this->stripWhitespace($css);
+ $css = $this->convertLegacyColors($css);
+ $css = $this->cleanupModernColors($css);
+ $css = $this->shortenHEXColors($css);
+ $css = $this->shortenZeroes($css);
+ $css = $this->shortenFontWeights($css);
+ $css = $this->stripEmptyTags($css);
+
+ // restore the string we've extracted earlier
+ $css = $this->restoreExtractedData($css);
+
+ $source = is_int($source) ? '' : $source;
+ $parents = $source ? array_merge($parents, array($source)) : $parents;
+ $css = $this->combineImports($source, $css, $parents);
+ $css = $this->importFiles($source, $css);
+
+ /*
+ * If we'll save to a new path, we'll have to fix the relative paths
+ * to be relative no longer to the source file, but to the new path.
+ * If we don't write to a file, fall back to same path so no
+ * conversion happens (because we still want it to go through most
+ * of the move code, which also addresses url() & @import syntax...)
+ */
+ $converter = $this->getPathConverter($source, $path ?: $source);
+ $css = $this->move($converter, $css);
+
+ // combine css
+ $content .= $css;
+ }
+
+ $content = $this->moveImportsToTop($content);
+
+ return $content;
+ }
+
+ /**
+ * Moving a css file should update all relative urls.
+ * Relative references (e.g. ../images/image.gif) in a certain css file,
+ * will have to be updated when a file is being saved at another location
+ * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
+ *
+ * @param ConverterInterface $converter Relative path converter
+ * @param string $content The CSS content to update relative urls for
+ *
+ * @return string
+ */
+ protected function move(ConverterInterface $converter, $content)
+ {
+ /*
+ * Relative path references will usually be enclosed by url(). @import
+ * is an exception, where url() is not necessary around the path (but is
+ * allowed).
+ * This *could* be 1 regular expression, where both regular expressions
+ * in this array are on different sides of a |. But we're using named
+ * patterns in both regexes, the same name on both regexes. This is only
+ * possible with a (?J) modifier, but that only works after a fairly
+ * recent PCRE version. That's why I'm doing 2 separate regular
+ * expressions & combining the matches after executing of both.
+ */
+ $relativeRegexes = array(
+ // url(xxx)
+ '/
+ # open url()
+ url\(
+
+ \s*
+
+ # open path enclosure
+ (?P["\'])?
+
+ # fetch path
+ (?P.+?)
+
+ # close path enclosure
+ (?(quotes)(?P=quotes))
+
+ \s*
+
+ # close url()
+ \)
+
+ /ix',
+
+ // @import "xxx"
+ '/
+ # import statement
+ @import
+
+ # whitespace
+ \s+
+
+ # we don\'t have to check for @import url(), because the
+ # condition above will already catch these
+
+ # open path enclosure
+ (?P["\'])
+
+ # fetch path
+ (?P.+?)
+
+ # close path enclosure
+ (?P=quotes)
+
+ /ix',
+ );
+
+ // find all relative urls in css
+ $matches = array();
+ foreach ($relativeRegexes as $relativeRegex) {
+ if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
+ $matches = array_merge($matches, $regexMatches);
+ }
+ }
+
+ $search = array();
+ $replace = array();
+
+ // loop all urls
+ foreach ($matches as $match) {
+ // determine if it's a url() or an @import match
+ $type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
+
+ $url = $match['path'];
+ if ($this->canImportByPath($url)) {
+ // attempting to interpret GET-params makes no sense, so let's discard them for awhile
+ $params = strrchr($url, '?');
+ $url = $params ? substr($url, 0, -strlen($params)) : $url;
+
+ // fix relative url
+ $url = $converter->convert($url);
+
+ // now that the path has been converted, re-apply GET-params
+ $url .= $params;
+ }
+
+ /*
+ * Urls with control characters above 0x7e should be quoted.
+ * According to Mozilla's parser, whitespace is only allowed at the
+ * end of unquoted urls.
+ * Urls with `)` (as could happen with data: uris) should also be
+ * quoted to avoid being confused for the url() closing parentheses.
+ * And urls with a # have also been reported to cause issues.
+ * Urls with quotes inside should also remain escaped.
+ *
+ * @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
+ * @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
+ * @see https://github.com/matthiasmullie/minify/issues/193
+ */
+ $url = trim($url);
+ if (preg_match('/[\s\)\'"#\x{7f}-\x{9f}]/u', $url)) {
+ $url = $match['quotes'] . $url . $match['quotes'];
+ }
+
+ // build replacement
+ $search[] = $match[0];
+ if ($type === 'url') {
+ $replace[] = 'url(' . $url . ')';
+ } elseif ($type === 'import') {
+ $replace[] = '@import "' . $url . '"';
+ }
+ }
+
+ // replace urls
+ return str_replace($search, $replace, $content);
+ }
+
+ /**
+ * Shorthand HEX color codes.
+ * #FF0000FF -> #f00 -> red
+ * #FF00FF00 -> transparent.
+ *
+ * @param string $content The CSS content to shorten the HEX color codes for
+ *
+ * @return string
+ */
+ protected function shortenHexColors($content)
+ {
+ // shorten repeating patterns within HEX ..
+ $content = preg_replace('/(?<=[: ])#([0-9a-f])\\1([0-9a-f])\\2([0-9a-f])\\3(?:([0-9a-f])\\4)?(?=[; }])/i', '#$1$2$3$4', $content);
+
+ // remove alpha channel if it's pointless ..
+ $content = preg_replace('/(?<=[: ])#([0-9a-f]{6})ff(?=[; }])/i', '#$1', $content);
+ $content = preg_replace('/(?<=[: ])#([0-9a-f]{3})f(?=[; }])/i', '#$1', $content);
+
+ // replace `transparent` with shortcut ..
+ $content = preg_replace('/(?<=[: ])#[0-9a-f]{6}00(?=[; }])/i', '#fff0', $content);
+
+ $colors = array(
+ // make these more readable
+ '#00f' => 'blue',
+ '#dc143c' => 'crimson',
+ '#0ff' => 'cyan',
+ '#8b0000' => 'darkred',
+ '#696969' => 'dimgray',
+ '#ff69b4' => 'hotpink',
+ '#0f0' => 'lime',
+ '#fdf5e6' => 'oldlace',
+ '#87ceeb' => 'skyblue',
+ '#d8bfd8' => 'thistle',
+ // we can shorten some even more by replacing them with their color name
+ '#f0ffff' => 'azure',
+ '#f5f5dc' => 'beige',
+ '#ffe4c4' => 'bisque',
+ '#a52a2a' => 'brown',
+ '#ff7f50' => 'coral',
+ '#ffd700' => 'gold',
+ '#808080' => 'gray',
+ '#008000' => 'green',
+ '#4b0082' => 'indigo',
+ '#fffff0' => 'ivory',
+ '#f0e68c' => 'khaki',
+ '#faf0e6' => 'linen',
+ '#800000' => 'maroon',
+ '#000080' => 'navy',
+ '#808000' => 'olive',
+ '#ffa500' => 'orange',
+ '#da70d6' => 'orchid',
+ '#cd853f' => 'peru',
+ '#ffc0cb' => 'pink',
+ '#dda0dd' => 'plum',
+ '#800080' => 'purple',
+ '#f00' => 'red',
+ '#fa8072' => 'salmon',
+ '#a0522d' => 'sienna',
+ '#c0c0c0' => 'silver',
+ '#fffafa' => 'snow',
+ '#d2b48c' => 'tan',
+ '#008080' => 'teal',
+ '#ff6347' => 'tomato',
+ '#ee82ee' => 'violet',
+ '#f5deb3' => 'wheat',
+ // or the other way around
+ 'black' => '#000',
+ 'fuchsia' => '#f0f',
+ 'magenta' => '#f0f',
+ 'white' => '#fff',
+ 'yellow' => '#ff0',
+ // and also `transparent`
+ 'transparent' => '#fff0',
+ );
+
+ return preg_replace_callback(
+ '/(?<=[: ])(' . implode('|', array_keys($colors)) . ')(?=[; }])/i',
+ function ($match) use ($colors) {
+ return $colors[strtolower($match[0])];
+ },
+ $content
+ );
+ }
+
+ /**
+ * Convert RGB|HSL color codes.
+ * rgb(255,0,0,.5) -> rgb(255 0 0 / .5).
+ * rgb(255,0,0) -> #f00.
+ *
+ * @param string $content The CSS content to shorten the RGB color codes for
+ *
+ * @return string
+ */
+ protected function convertLegacyColors($content)
+ {
+ /*
+ https://drafts.csswg.org/css-color/#color-syntax-legacy
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
+ */
+
+ // convert legacy color syntax
+ $content = preg_replace('/(rgb)a?\(\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0,1]?(?:\.[0-9]*)?)\s*\)/i', '$1($2 $3 $4 / $5)', $content);
+ $content = preg_replace('/(rgb)a?\(\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*\)/i', '$1($2 $3 $4)', $content);
+ $content = preg_replace('/(hsl)a?\(\s*([0-9]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9]{1,3}%)\s*,\s*([0-9]{1,3}%)\s*,\s*([0,1]?(?:\.[0-9]*)?)\s*\)/i', '$1($2 $3 $4 / $5)', $content);
+ $content = preg_replace('/(hsl)a?\(\s*([0-9]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9]{1,3}%)\s*,\s*([0-9]{1,3}%)\s*\)/i', '$1($2 $3 $4)', $content);
+
+ // convert `rgb` to `hex`
+ $dec = '([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])';
+ return preg_replace_callback(
+ "/rgb\($dec $dec $dec\)/i",
+ function ($match) {
+ return sprintf('#%02x%02x%02x', $match[1], $match[2], $match[3]);
+ },
+ $content
+ );
+ }
+
+ /**
+ * Cleanup RGB|HSL|HWB|LCH|LAB
+ * rgb(255 0 0 / 1) -> rgb(255 0 0).
+ * rgb(255 0 0 / 0) -> transparent.
+ *
+ * @param string $content The CSS content to cleanup HSL|HWB|LCH|LAB
+ *
+ * @return string
+ */
+ protected function cleanupModernColors($content)
+ {
+ /*
+ https://drafts.csswg.org/css-color/#color-syntax-modern
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab
+ */
+ $tag = '(rgb|hsl|hwb|(?:(?:ok)?(?:lch|lab)))';
+
+ // remove alpha channel if it's pointless ..
+ $content = preg_replace('/' . $tag . '\(\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+\/\s+1(?:(?:\.\d?)*|00%)?\s*\)/i', '$1($2 $3 $4)', $content);
+
+ // replace `transparent` with shortcut ..
+ $content = preg_replace('/' . $tag . '\(\s*[^\s]+\s+[^\s]+\s+[^\s]+\s+\/\s+0(?:[\.0%]*)?\s*\)/i', '#fff0', $content);
+
+ return $content;
+ }
+
+ /**
+ * Shorten CSS font weights.
+ *
+ * @param string $content The CSS content to shorten the font weights for
+ *
+ * @return string
+ */
+ protected function shortenFontWeights($content)
+ {
+ $weights = array(
+ 'normal' => 400,
+ 'bold' => 700,
+ );
+
+ $callback = function ($match) use ($weights) {
+ return $match[1] . $weights[$match[2]];
+ };
+
+ return preg_replace_callback('/(font-weight\s*:\s*)(' . implode('|', array_keys($weights)) . ')(?=[;}])/', $callback, $content);
+ }
+
+ /**
+ * Shorthand 0 values to plain 0, instead of e.g. -0em.
+ *
+ * @param string $content The CSS content to shorten the zero values for
+ *
+ * @return string
+ */
+ protected function shortenZeroes($content)
+ {
+ // we don't want to strip units in `calc()` expressions:
+ // `5px - 0px` is valid, but `5px - 0` is not
+ // `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but
+ // `10 * 0` is invalid
+ // we've extracted calcs earlier, so we don't need to worry about this
+
+ // reusable bits of code throughout these regexes:
+ // before & after are used to make sure we don't match lose unintended
+ // 0-like values (e.g. in #000, or in http://url/1.0)
+ // units can be stripped from 0 values, or used to recognize non 0
+ // values (where wa may be able to strip a .0 suffix)
+ $before = '(?<=[:(, ])';
+ $after = '(?=[ ,);}])';
+ $units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
+
+ // strip units after zeroes (0px -> 0)
+ // NOTE: it should be safe to remove all units for a 0 value, but in
+ // practice, Webkit (especially Safari) seems to stumble over at least
+ // 0%, potentially other units as well. Only stripping 'px' for now.
+ // @see https://github.com/matthiasmullie/minify/issues/60
+ $content = preg_replace('/' . $before . '(-?0*(\.0+)?)(?<=0)px' . $after . '/', '\\1', $content);
+
+ // strip 0-digits (.0 -> 0)
+ $content = preg_replace('/' . $before . '\.0+' . $units . '?' . $after . '/', '0\\1', $content);
+ // strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
+ $content = preg_replace('/' . $before . '(-?[0-9]+\.[0-9]+)0+' . $units . '?' . $after . '/', '\\1\\2', $content);
+ // strip trailing 0: 50.00 -> 50, 50.00px -> 50px
+ $content = preg_replace('/' . $before . '(-?[0-9]+)\.0+' . $units . '?' . $after . '/', '\\1\\2', $content);
+ // strip leading 0: 0.1 -> .1, 01.1 -> 1.1
+ $content = preg_replace('/' . $before . '(-?)0+([0-9]*\.[0-9]+)' . $units . '?' . $after . '/', '\\1\\2\\3', $content);
+
+ // strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
+ $content = preg_replace('/' . $before . '-?0+' . $units . '?' . $after . '/', '0\\1', $content);
+
+ // IE doesn't seem to understand a unitless flex-basis value (correct -
+ // it goes against the spec), so let's add it in again (make it `%`,
+ // which is only 1 char: 0%, 0px, 0 anything, it's all just the same)
+ // @see https://developer.mozilla.org/nl/docs/Web/CSS/flex
+ $content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content);
+ $content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
+
+ return $content;
+ }
+
+ /**
+ * Strip empty tags from source code.
+ *
+ * @param string $content
+ *
+ * @return string
+ */
+ protected function stripEmptyTags($content)
+ {
+ $content = preg_replace('/(?<=^)[^\{\};]+\{\s*\}/', '', $content);
+ $content = preg_replace('/(?<=(\}|;))[^\{\};]+\{\s*\}/', '', $content);
+
+ return $content;
+ }
+
+ /**
+ * Strip comments from source code.
+ */
+ protected function stripComments()
+ {
+ $this->stripMultilineComments();
+ }
+
+ /**
+ * Strip whitespace.
+ *
+ * @param string $content The CSS content to strip the whitespace for
+ *
+ * @return string
+ */
+ protected function stripWhitespace($content)
+ {
+ // remove leading & trailing whitespace
+ $content = preg_replace('/^\s*/m', '', $content);
+ $content = preg_replace('/\s*$/m', '', $content);
+
+ // replace newlines with a single space
+ $content = preg_replace('/\s+/', ' ', $content);
+
+ // remove whitespace around meta characters
+ // inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
+ $content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
+ $content = preg_replace('/([\[(:>\+])\s+/', '$1', $content);
+ $content = preg_replace('/\s+([\]\)>\+])/', '$1', $content);
+ $content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
+
+ // whitespace around + and - can only be stripped inside some pseudo-
+ // classes, like `:nth-child(3+2n)`
+ // not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
+ // selectors like `div.weird- p`
+ $pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
+ $content = preg_replace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
+
+ // remove semicolon/whitespace followed by closing bracket
+ $content = str_replace(';}', '}', $content);
+
+ return trim($content);
+ }
+
+ /**
+ * Replace all occurrences of functions that may contain math, where
+ * whitespace around operators needs to be preserved (e.g. calc, clamp).
+ */
+ protected function extractMath()
+ {
+ $functions = array('calc', 'clamp', 'min', 'max');
+ $pattern = '/\b(' . implode('|', $functions) . ')(\(.+?)(?=$|;|})/m';
+
+ // PHP only supports $this inside anonymous functions since 5.4
+ $minifier = $this;
+ $callback = function ($match) use ($minifier, $pattern, &$callback) {
+ $function = $match[1];
+ $length = strlen($match[2]);
+ $expr = '';
+ $opened = 0;
+
+ // the regular expression for extracting math has 1 significant problem:
+ // it can't determine the correct closing parenthesis...
+ // instead, it'll match a larger portion of code to where it's certain that
+ // the calc() musts have ended, and we'll figure out which is the correct
+ // closing parenthesis here, by counting how many have opened
+ for ($i = 0; $i < $length; ++$i) {
+ $char = $match[2][$i];
+ $expr .= $char;
+ if ($char === '(') {
+ ++$opened;
+ } elseif ($char === ')' && --$opened === 0) {
+ break;
+ }
+ }
+
+ // now that we've figured out where the calc() starts and ends, extract it
+ $count = count($minifier->extracted);
+ $placeholder = 'math(' . $count . ')';
+ $minifier->extracted[$placeholder] = $function . '(' . trim(substr($expr, 1, -1)) . ')';
+
+ // and since we've captured more code than required, we may have some leftover
+ // calc() in here too - go recursive on the remaining but of code to go figure
+ // that out and extract what is needed
+ $rest = $minifier->str_replace_first($function . $expr, '', $match[0]);
+ $rest = preg_replace_callback($pattern, $callback, $rest);
+
+ return $placeholder . $rest;
+ };
+
+ $this->registerPattern($pattern, $callback);
+ }
+
+ /**
+ * Replace custom properties, whose values may be used in scenarios where
+ * we wouldn't want them to be minified (e.g. inside calc).
+ */
+ protected function extractCustomProperties()
+ {
+ // PHP only supports $this inside anonymous functions since 5.4
+ $minifier = $this;
+ $this->registerPattern(
+ '/(?<=^|[;}{])\s*(--[^:;{}"\'\s]+)\s*:([^;{}]+)/m',
+ function ($match) use ($minifier) {
+ $placeholder = '--custom-' . count($minifier->extracted) . ':0';
+ $minifier->extracted[$placeholder] = $match[1] . ':' . trim($match[2]);
+
+ return $placeholder;
+ }
+ );
+ }
+
+ /**
+ * Check if file is small enough to be imported.
+ *
+ * @param string $path The path to the file
+ *
+ * @return bool
+ */
+ protected function canImportBySize($path)
+ {
+ return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
+ }
+
+ /**
+ * Check if file a file can be imported, going by the path.
+ *
+ * @param string $path
+ *
+ * @return bool
+ */
+ protected function canImportByPath($path)
+ {
+ return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
+ }
+
+ /**
+ * Return a converter to update relative paths to be relative to the new
+ * destination.
+ *
+ * @param string $source
+ * @param string $target
+ *
+ * @return ConverterInterface
+ */
+ protected function getPathConverter($source, $target)
+ {
+ return new Converter($source, $target);
+ }
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php
new file mode 100644
index 0000000..300e43c
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/Minify/Exception.php
@@ -0,0 +1,22 @@
+
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
+
+/**
+ * Base Exception Class.
+ *
+ * @deprecated Use Exceptions\BasicException instead
+ *
+ * @author Matthias Mullie
+ */
+abstract class Exception extends \Exception
+{
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php
new file mode 100644
index 0000000..6b095e7
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/BasicException.php
@@ -0,0 +1,24 @@
+
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions;
+
+use PoweredCache\Dependencies\MatthiasMullie\Minify\Exception;
+
+/**
+ * Basic Exception Class.
+ *
+ * @author Matthias Mullie
+ */
+abstract class BasicException extends Exception
+{
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php
new file mode 100644
index 0000000..312d6ec
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/FileImportException.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions;
+
+/**
+ * File Import Exception Class.
+ *
+ * @author Matthias Mullie
+ */
+class FileImportException extends BasicException
+{
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php
new file mode 100644
index 0000000..174d738
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/Minify/Exceptions/IOException.php
@@ -0,0 +1,22 @@
+
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions;
+
+/**
+ * IO Exception Class.
+ *
+ * @author Matthias Mullie
+ */
+class IOException extends BasicException
+{
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/Minify/JS.php b/includes/classes/Dependencies/MatthiasMullie/Minify/JS.php
new file mode 100644
index 0000000..f934969
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/Minify/JS.php
@@ -0,0 +1,618 @@
+
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
+
+/**
+ * JavaScript Minifier Class.
+ *
+ * Please report bugs on https://github.com/matthiasmullie/minify/issues
+ *
+ * @author Matthias Mullie
+ * @author Tijs Verkoyen
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+class JS extends Minify
+{
+ /**
+ * Var-matching regex based on http://stackoverflow.com/a/9337047/802993.
+ *
+ * Note that regular expressions using that bit must have the PCRE_UTF8
+ * pattern modifier (/u) set.
+ *
+ * @internal
+ *
+ * @var string
+ */
+ const REGEX_VARIABLE = '\b[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}0-9\x{0300}-\x{036f}\x{0483}-\x{0487}\x{0591}-\x{05bd}\x{05bf}\x{05c1}\x{05c2}\x{05c4}\x{05c5}\x{05c7}\x{0610}-\x{061a}\x{064b}-\x{0669}\x{0670}\x{06d6}-\x{06dc}\x{06df}-\x{06e4}\x{06e7}\x{06e8}\x{06ea}-\x{06ed}\x{06f0}-\x{06f9}\x{0711}\x{0730}-\x{074a}\x{07a6}-\x{07b0}\x{07c0}-\x{07c9}\x{07eb}-\x{07f3}\x{0816}-\x{0819}\x{081b}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082d}\x{0859}-\x{085b}\x{08e4}-\x{08fe}\x{0900}-\x{0903}\x{093a}-\x{093c}\x{093e}-\x{094f}\x{0951}-\x{0957}\x{0962}\x{0963}\x{0966}-\x{096f}\x{0981}-\x{0983}\x{09bc}\x{09be}-\x{09c4}\x{09c7}\x{09c8}\x{09cb}-\x{09cd}\x{09d7}\x{09e2}\x{09e3}\x{09e6}-\x{09ef}\x{0a01}-\x{0a03}\x{0a3c}\x{0a3e}-\x{0a42}\x{0a47}\x{0a48}\x{0a4b}-\x{0a4d}\x{0a51}\x{0a66}-\x{0a71}\x{0a75}\x{0a81}-\x{0a83}\x{0abc}\x{0abe}-\x{0ac5}\x{0ac7}-\x{0ac9}\x{0acb}-\x{0acd}\x{0ae2}\x{0ae3}\x{0ae6}-\x{0aef}\x{0b01}-\x{0b03}\x{0b3c}\x{0b3e}-\x{0b44}\x{0b47}\x{0b48}\x{0b4b}-\x{0b4d}\x{0b56}\x{0b57}\x{0b62}\x{0b63}\x{0b66}-\x{0b6f}\x{0b82}\x{0bbe}-\x{0bc2}\x{0bc6}-\x{0bc8}\x{0bca}-\x{0bcd}\x{0bd7}\x{0be6}-\x{0bef}\x{0c01}-\x{0c03}\x{0c3e}-\x{0c44}\x{0c46}-\x{0c48}\x{0c4a}-\x{0c4d}\x{0c55}\x{0c56}\x{0c62}\x{0c63}\x{0c66}-\x{0c6f}\x{0c82}\x{0c83}\x{0cbc}\x{0cbe}-\x{0cc4}\x{0cc6}-\x{0cc8}\x{0cca}-\x{0ccd}\x{0cd5}\x{0cd6}\x{0ce2}\x{0ce3}\x{0ce6}-\x{0cef}\x{0d02}\x{0d03}\x{0d3e}-\x{0d44}\x{0d46}-\x{0d48}\x{0d4a}-\x{0d4d}\x{0d57}\x{0d62}\x{0d63}\x{0d66}-\x{0d6f}\x{0d82}\x{0d83}\x{0dca}\x{0dcf}-\x{0dd4}\x{0dd6}\x{0dd8}-\x{0ddf}\x{0df2}\x{0df3}\x{0e31}\x{0e34}-\x{0e3a}\x{0e47}-\x{0e4e}\x{0e50}-\x{0e59}\x{0eb1}\x{0eb4}-\x{0eb9}\x{0ebb}\x{0ebc}\x{0ec8}-\x{0ecd}\x{0ed0}-\x{0ed9}\x{0f18}\x{0f19}\x{0f20}-\x{0f29}\x{0f35}\x{0f37}\x{0f39}\x{0f3e}\x{0f3f}\x{0f71}-\x{0f84}\x{0f86}\x{0f87}\x{0f8d}-\x{0f97}\x{0f99}-\x{0fbc}\x{0fc6}\x{102b}-\x{103e}\x{1040}-\x{1049}\x{1056}-\x{1059}\x{105e}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106d}\x{1071}-\x{1074}\x{1082}-\x{108d}\x{108f}-\x{109d}\x{135d}-\x{135f}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17d3}\x{17dd}\x{17e0}-\x{17e9}\x{180b}-\x{180d}\x{1810}-\x{1819}\x{18a9}\x{1920}-\x{192b}\x{1930}-\x{193b}\x{1946}-\x{194f}\x{19b0}-\x{19c0}\x{19c8}\x{19c9}\x{19d0}-\x{19d9}\x{1a17}-\x{1a1b}\x{1a55}-\x{1a5e}\x{1a60}-\x{1a7c}\x{1a7f}-\x{1a89}\x{1a90}-\x{1a99}\x{1b00}-\x{1b04}\x{1b34}-\x{1b44}\x{1b50}-\x{1b59}\x{1b6b}-\x{1b73}\x{1b80}-\x{1b82}\x{1ba1}-\x{1bad}\x{1bb0}-\x{1bb9}\x{1be6}-\x{1bf3}\x{1c24}-\x{1c37}\x{1c40}-\x{1c49}\x{1c50}-\x{1c59}\x{1cd0}-\x{1cd2}\x{1cd4}-\x{1ce8}\x{1ced}\x{1cf2}-\x{1cf4}\x{1dc0}-\x{1de6}\x{1dfc}-\x{1dff}\x{200c}\x{200d}\x{203f}\x{2040}\x{2054}\x{20d0}-\x{20dc}\x{20e1}\x{20e5}-\x{20f0}\x{2cef}-\x{2cf1}\x{2d7f}\x{2de0}-\x{2dff}\x{302a}-\x{302f}\x{3099}\x{309a}\x{a620}-\x{a629}\x{a66f}\x{a674}-\x{a67d}\x{a69f}\x{a6f0}\x{a6f1}\x{a802}\x{a806}\x{a80b}\x{a823}-\x{a827}\x{a880}\x{a881}\x{a8b4}-\x{a8c4}\x{a8d0}-\x{a8d9}\x{a8e0}-\x{a8f1}\x{a900}-\x{a909}\x{a926}-\x{a92d}\x{a947}-\x{a953}\x{a980}-\x{a983}\x{a9b3}-\x{a9c0}\x{a9d0}-\x{a9d9}\x{aa29}-\x{aa36}\x{aa43}\x{aa4c}\x{aa4d}\x{aa50}-\x{aa59}\x{aa7b}\x{aab0}\x{aab2}-\x{aab4}\x{aab7}\x{aab8}\x{aabe}\x{aabf}\x{aac1}\x{aaeb}-\x{aaef}\x{aaf5}\x{aaf6}\x{abe3}-\x{abea}\x{abec}\x{abed}\x{abf0}-\x{abf9}\x{fb1e}\x{fe00}-\x{fe0f}\x{fe20}-\x{fe26}\x{fe33}\x{fe34}\x{fe4d}-\x{fe4f}\x{ff10}-\x{ff19}\x{ff3f}]*\b';
+
+ /**
+ * Full list of JavaScript reserved words.
+ * Will be loaded from /data/js/keywords_reserved.txt.
+ *
+ * @see https://mathiasbynens.be/notes/reserved-keywords
+ *
+ * @var string[]
+ */
+ protected $keywordsReserved = array();
+
+ /**
+ * List of JavaScript reserved words that accept a
+ * after them. Some end of lines are not the end of a statement, like with
+ * these keywords.
+ *
+ * E.g.: we shouldn't insert a ; after this else
+ * else
+ * console.log('this is quite fine')
+ *
+ * Will be loaded from /data/js/keywords_before.txt
+ *
+ * @var string[]
+ */
+ protected $keywordsBefore = array();
+
+ /**
+ * List of JavaScript reserved words that accept a
+ * before them. Some end of lines are not the end of a statement, like when
+ * continued by one of these keywords on the newline.
+ *
+ * E.g.: we shouldn't insert a ; before this instanceof
+ * variable
+ * instanceof String
+ *
+ * Will be loaded from /data/js/keywords_after.txt
+ *
+ * @var string[]
+ */
+ protected $keywordsAfter = array();
+
+ /**
+ * List of all JavaScript operators.
+ *
+ * Will be loaded from /data/js/operators.txt
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
+ *
+ * @var string[]
+ */
+ protected $operators = array();
+
+ /**
+ * List of JavaScript operators that accept a after
+ * them. Some end of lines are not the end of a statement, like with these
+ * operators.
+ *
+ * Note: Most operators are fine, we've only removed ++ and --.
+ * ++ & -- have to be joined with the value they're in-/decrementing.
+ *
+ * Will be loaded from /data/js/operators_before.txt
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
+ *
+ * @var string[]
+ */
+ protected $operatorsBefore = array();
+
+ /**
+ * List of JavaScript operators that accept a before
+ * them. Some end of lines are not the end of a statement, like when
+ * continued by one of these operators on the newline.
+ *
+ * Note: Most operators are fine, we've only removed ), ], ++, --, ! and ~.
+ * There can't be a newline separating ! or ~ and whatever it is negating.
+ * ++ & -- have to be joined with the value they're in-/decrementing.
+ * ) & ] are "special" in that they have lots or usecases. () for example
+ * is used for function calls, for grouping, in if () and for (), ...
+ *
+ * Will be loaded from /data/js/operators_after.txt
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
+ *
+ * @var string[]
+ */
+ protected $operatorsAfter = array();
+
+ public function __construct()
+ {
+ call_user_func_array(array('\\PoweredCache\Dependencies\MatthiasMullie\Minify\\Minify', '__construct'), func_get_args());
+
+ $dataDir = __DIR__ . '/../data/js/';
+ $options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES;
+ $this->keywordsReserved = file($dataDir . 'keywords_reserved.txt', $options);
+ $this->keywordsBefore = file($dataDir . 'keywords_before.txt', $options);
+ $this->keywordsAfter = file($dataDir . 'keywords_after.txt', $options);
+ $this->operators = file($dataDir . 'operators.txt', $options);
+ $this->operatorsBefore = file($dataDir . 'operators_before.txt', $options);
+ $this->operatorsAfter = file($dataDir . 'operators_after.txt', $options);
+ }
+
+ /**
+ * Minify the data.
+ * Perform JS optimizations.
+ *
+ * @param string[optional] $path Path to write the data to
+ *
+ * @return string The minified data
+ */
+ public function execute($path = null)
+ {
+ $content = '';
+
+ /*
+ * Let's first take out strings, comments and regular expressions.
+ * All of these can contain JS code-like characters, and we should make
+ * sure any further magic ignores anything inside of these.
+ *
+ * Consider this example, where we should not strip any whitespace:
+ * var str = "a test";
+ *
+ * Comments will be removed altogether, strings and regular expressions
+ * will be replaced by placeholder text, which we'll restore later.
+ */
+ $this->extractStrings('\'"`');
+ $this->stripComments();
+ $this->extractRegex();
+
+ // loop files
+ foreach ($this->data as $source => $js) {
+ // take out strings, comments & regex (for which we've registered
+ // the regexes just a few lines earlier)
+ $js = $this->replace($js);
+
+ $js = $this->propertyNotation($js);
+ $js = $this->shortenBools($js);
+ $js = $this->stripWhitespace($js);
+
+ // combine js: separating the scripts by a ;
+ $content .= $js . ';';
+ }
+
+ // clean up leftover `;`s from the combination of multiple scripts
+ $content = ltrim($content, ';');
+ $content = (string) substr($content, 0, -1);
+
+ /*
+ * Earlier, we extracted strings & regular expressions and replaced them
+ * with placeholder text. This will restore them.
+ */
+ $content = $this->restoreExtractedData($content);
+
+ return $content;
+ }
+
+ /**
+ * Strip comments from source code.
+ */
+ protected function stripComments()
+ {
+ $this->stripMultilineComments();
+
+ // single-line comments
+ $this->registerPattern('/\/\/.*$/m', '');
+ }
+
+ /**
+ * JS can have /-delimited regular expressions, like: /ab+c/.match(string).
+ *
+ * The content inside the regex can contain characters that may be confused
+ * for JS code: e.g. it could contain whitespace it needs to match & we
+ * don't want to strip whitespace in there.
+ *
+ * The regex can be pretty simple: we don't have to care about comments,
+ * (which also use slashes) because stripComments() will have stripped those
+ * already.
+ *
+ * This method will replace all string content with simple REGEX#
+ * placeholder text, so we've rid all regular expressions from characters
+ * that may be misinterpreted. Original regex content will be saved in
+ * $this->extracted and after doing all other minifying, we can restore the
+ * original content via restoreRegex()
+ */
+ protected function extractRegex()
+ {
+ // PHP only supports $this inside anonymous functions since 5.4
+ $minifier = $this;
+ $callback = function ($match) use ($minifier) {
+ $count = count($minifier->extracted);
+ $placeholder = '"' . $count . '"';
+ $minifier->extracted[$placeholder] = $match[0];
+
+ return $placeholder;
+ };
+
+ // match all chars except `/` and `\`
+ // `\` is allowed though, along with whatever char follows (which is the
+ // one being escaped)
+ // this should allow all chars, except for an unescaped `/` (= the one
+ // closing the regex)
+ // then also ignore bare `/` inside `[]`, where they don't need to be
+ // escaped: anything inside `[]` can be ignored safely
+ $pattern = '\\/(?!\*)(?:[^\\[\\/\\\\\n\r]++|(?:\\\\.)++|(?:\\[(?:[^\\]\\\\\n\r]++|(?:\\\\.)++)++\\])++)++\\/[gimuy]*';
+
+ // a regular expression can only be followed by a few operators or some
+ // of the RegExp methods (a `\` followed by a variable or value is
+ // likely part of a division, not a regex)
+ $keywords = array('do', 'in', 'new', 'else', 'throw', 'yield', 'delete', 'return', 'typeof');
+ $before = '(^|[=:,;\+\-\*\?\/\}\(\{\[&\|!]|' . implode('|', $keywords) . ')\s*';
+ $propertiesAndMethods = array(
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2
+ 'constructor',
+ 'flags',
+ 'global',
+ 'ignoreCase',
+ 'multiline',
+ 'source',
+ 'sticky',
+ 'unicode',
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Methods_2
+ 'compile(',
+ 'exec(',
+ 'test(',
+ 'toSource(',
+ 'toString(',
+ );
+ $delimiters = array_fill(0, count($propertiesAndMethods), '/');
+ $propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters);
+ $after = '(?=\s*([\.,;:\)\}&\|+]|\/\/|$|\.(' . implode('|', $propertiesAndMethods) . ')))';
+ $this->registerPattern('/' . $before . '\K' . $pattern . $after . '/', $callback);
+
+ // regular expressions following a `)` are rather annoying to detect...
+ // quite often, `/` after `)` is a division operator & if it happens to
+ // be followed by another one (or a comment), it is likely to be
+ // confused for a regular expression
+ // however, it's perfectly possible for a regex to follow a `)`: after
+ // a single-line `if()`, `while()`, ... statement, for example
+ // since, when they occur like that, they're always the start of a
+ // statement, there's only a limited amount of ways they can be useful:
+ // by calling the regex methods directly
+ // if a regex following `)` is not followed by `.`,
+ // it's quite likely not a regex
+ $before = '\)\s*';
+ $after = '(?=\s*\.(' . implode('|', $propertiesAndMethods) . '))';
+ $this->registerPattern('/' . $before . '\K' . $pattern . $after . '/', $callback);
+
+ // 1 more edge case: a regex can be followed by a lot more operators or
+ // keywords if there's a newline (ASI) in between, where the operator
+ // actually starts a new statement
+ // (https://github.com/matthiasmullie/minify/issues/56)
+ $operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
+ $operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
+ $after = '(?=\s*\n\s*(' . implode('|', $operators) . '))';
+ $this->registerPattern('/' . $pattern . $after . '/', $callback);
+ }
+
+ /**
+ * Strip whitespace.
+ *
+ * We won't strip *all* whitespace, but as much as possible. The thing that
+ * we'll preserve are newlines we're unsure about.
+ * JavaScript doesn't require statements to be terminated with a semicolon.
+ * It will automatically fix missing semicolons with ASI (automatic semi-
+ * colon insertion) at the end of line causing errors (without semicolon.)
+ *
+ * Because it's sometimes hard to tell if a newline is part of a statement
+ * that should be terminated or not, we'll just leave some of them alone.
+ *
+ * @param string $content The content to strip the whitespace for
+ *
+ * @return string
+ */
+ protected function stripWhitespace($content)
+ {
+ // uniform line endings, make them all line feed
+ $content = str_replace(array("\r\n", "\r"), "\n", $content);
+
+ // collapse all non-line feed whitespace into a single space
+ $content = preg_replace('/[^\S\n]+/', ' ', $content);
+
+ // strip leading & trailing whitespace
+ $content = str_replace(array(" \n", "\n "), "\n", $content);
+
+ // collapse consecutive line feeds into just 1
+ $content = preg_replace('/\n+/', "\n", $content);
+
+ $operatorsBefore = $this->getOperatorsForRegex($this->operatorsBefore, '/');
+ $operatorsAfter = $this->getOperatorsForRegex($this->operatorsAfter, '/');
+ $operators = $this->getOperatorsForRegex($this->operators, '/');
+ $keywordsBefore = $this->getKeywordsForRegex($this->keywordsBefore, '/');
+ $keywordsAfter = $this->getKeywordsForRegex($this->keywordsAfter, '/');
+
+ // strip whitespace that ends in (or next line begin with) an operator
+ // that allows statements to be broken up over multiple lines
+ unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
+ $content = preg_replace(
+ array(
+ '/(' . implode('|', $operatorsBefore) . ')\s+/',
+ '/\s+(' . implode('|', $operatorsAfter) . ')/',
+ ),
+ '\\1',
+ $content
+ );
+
+ // make sure + and - can't be mistaken for, or joined into ++ and --
+ $content = preg_replace(
+ array(
+ '/(?%&|', $delimiter);
+ $operators['='] = '(?keywordsReserved;
+ $callback = function ($match) use ($minifier, $keywords) {
+ $property = trim($minifier->extracted[$match[1]], '\'"');
+
+ /*
+ * Check if the property is a reserved keyword. In this context (as
+ * property of an object literal/array) it shouldn't matter, but IE8
+ * freaks out with "Expected identifier".
+ */
+ if (in_array($property, $keywords)) {
+ return $match[0];
+ }
+
+ /*
+ * See if the property is in a variable-like format (e.g.
+ * array['key-here'] can't be replaced by array.key-here since '-'
+ * is not a valid character there.
+ */
+ if (!preg_match('/^' . $minifier::REGEX_VARIABLE . '$/u', $property)) {
+ return $match[0];
+ }
+
+ return '.' . $property;
+ };
+
+ /*
+ * Figure out if previous character is a variable name (of the array
+ * we want to use property notation on) - this is to make sure
+ * standalone ['value'] arrays aren't confused for keys-of-an-array.
+ * We can (and only have to) check the last character, because PHP's
+ * regex implementation doesn't allow unfixed-length look-behind
+ * assertions.
+ */
+ preg_match('/(\[[^\]]+\])[^\]]*$/', static::REGEX_VARIABLE, $previousChar);
+ $previousChar = $previousChar[1];
+
+ /*
+ * Make sure word preceding the ['value'] is not a keyword, e.g.
+ * return['x']. Because -again- PHP's regex implementation doesn't allow
+ * unfixed-length look-behind assertions, I'm just going to do a lot of
+ * separate look-behind assertions, one for each keyword.
+ */
+ $keywords = $this->getKeywordsForRegex($keywords);
+ $keywords = '(?
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+
+namespace PoweredCache\Dependencies\MatthiasMullie\Minify;
+
+use PoweredCache\Dependencies\MatthiasMullie\Minify\Exceptions\IOException;
+use Psr\Cache\CacheItemInterface;
+
+/**
+ * Abstract minifier class.
+ *
+ * Please report bugs on https://github.com/matthiasmullie/minify/issues
+ *
+ * @author Matthias Mullie
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+abstract class Minify
+{
+ /**
+ * The data to be minified.
+ *
+ * @var string[]
+ */
+ protected $data = array();
+
+ /**
+ * Array of patterns to match.
+ *
+ * @var string[]
+ */
+ protected $patterns = array();
+
+ /**
+ * This array will hold content of strings and regular expressions that have
+ * been extracted from the JS source code, so we can reliably match "code",
+ * without having to worry about potential "code-like" characters inside.
+ *
+ * @internal
+ *
+ * @var string[]
+ */
+ public $extracted = array();
+
+ /**
+ * Init the minify class - optionally, code may be passed along already.
+ */
+ public function __construct(/* $data = null, ... */)
+ {
+ // it's possible to add the source through the constructor as well ;)
+ if (func_num_args()) {
+ call_user_func_array(array($this, 'add'), func_get_args());
+ }
+ }
+
+ /**
+ * Add a file or straight-up code to be minified.
+ *
+ * @param string|string[] $data
+ *
+ * @return static
+ */
+ public function add($data /* $data = null, ... */)
+ {
+ // bogus "usage" of parameter $data: scrutinizer warns this variable is
+ // not used (we're using func_get_args instead to support overloading),
+ // but it still needs to be defined because it makes no sense to have
+ // this function without argument :)
+ $args = array($data) + func_get_args();
+
+ // this method can be overloaded
+ foreach ($args as $data) {
+ if (is_array($data)) {
+ call_user_func_array(array($this, 'add'), $data);
+ continue;
+ }
+
+ // redefine var
+ $data = (string) $data;
+
+ // load data
+ $value = $this->load($data);
+ $key = ($data != $value) ? $data : count($this->data);
+
+ // replace CR linefeeds etc.
+ // @see https://github.com/matthiasmullie/minify/pull/139
+ $value = str_replace(array("\r\n", "\r"), "\n", $value);
+
+ // store data
+ $this->data[$key] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a file to be minified.
+ *
+ * @param string|string[] $data
+ *
+ * @return static
+ *
+ * @throws IOException
+ */
+ public function addFile($data /* $data = null, ... */)
+ {
+ // bogus "usage" of parameter $data: scrutinizer warns this variable is
+ // not used (we're using func_get_args instead to support overloading),
+ // but it still needs to be defined because it makes no sense to have
+ // this function without argument :)
+ $args = array($data) + func_get_args();
+
+ // this method can be overloaded
+ foreach ($args as $path) {
+ if (is_array($path)) {
+ call_user_func_array(array($this, 'addFile'), $path);
+ continue;
+ }
+
+ // redefine var
+ $path = (string) $path;
+
+ // check if we can read the file
+ if (!$this->canImportFile($path)) {
+ throw new IOException('The file "' . $path . '" could not be opened for reading. Check if PHP has enough permissions.');
+ }
+
+ $this->add($path);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Minify the data & (optionally) saves it to a file.
+ *
+ * @param string[optional] $path Path to write the data to
+ *
+ * @return string The minified data
+ */
+ public function minify($path = null)
+ {
+ $content = $this->execute($path);
+
+ // save to path
+ if ($path !== null) {
+ $this->save($content, $path);
+ }
+
+ return $content;
+ }
+
+ /**
+ * Minify & gzip the data & (optionally) saves it to a file.
+ *
+ * @param string[optional] $path Path to write the data to
+ * @param int[optional] $level Compression level, from 0 to 9
+ *
+ * @return string The minified & gzipped data
+ */
+ public function gzip($path = null, $level = 9)
+ {
+ $content = $this->execute($path);
+ $content = gzencode($content, $level, FORCE_GZIP);
+
+ // save to path
+ if ($path !== null) {
+ $this->save($content, $path);
+ }
+
+ return $content;
+ }
+
+ /**
+ * Minify the data & write it to a CacheItemInterface object.
+ *
+ * @param CacheItemInterface $item Cache item to write the data to
+ *
+ * @return CacheItemInterface Cache item with the minifier data
+ */
+ public function cache(CacheItemInterface $item)
+ {
+ $content = $this->execute();
+ $item->set($content);
+
+ return $item;
+ }
+
+ /**
+ * Minify the data.
+ *
+ * @param string[optional] $path Path to write the data to
+ *
+ * @return string The minified data
+ */
+ abstract public function execute($path = null);
+
+ /**
+ * Load data.
+ *
+ * @param string $data Either a path to a file or the content itself
+ *
+ * @return string
+ */
+ protected function load($data)
+ {
+ // check if the data is a file
+ if ($this->canImportFile($data)) {
+ $data = file_get_contents($data);
+
+ // strip BOM, if any
+ if (substr($data, 0, 3) == "\xef\xbb\xbf") {
+ $data = substr($data, 3);
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Save to file.
+ *
+ * @param string $content The minified data
+ * @param string $path The path to save the minified data to
+ *
+ * @throws IOException
+ */
+ protected function save($content, $path)
+ {
+ $handler = $this->openFileForWriting($path);
+
+ $this->writeToFile($handler, $content);
+
+ @fclose($handler);
+ }
+
+ /**
+ * Register a pattern to execute against the source content.
+ *
+ * If $replacement is a string, it must be plain text. Placeholders like $1 or \2 don't work.
+ * If you need that functionality, use a callback instead.
+ *
+ * @param string $pattern PCRE pattern
+ * @param string|callable $replacement Replacement value for matched pattern
+ */
+ protected function registerPattern($pattern, $replacement = '')
+ {
+ // study the pattern, we'll execute it more than once
+ $pattern .= 'S';
+
+ $this->patterns[] = array($pattern, $replacement);
+ }
+
+ /**
+ * Both JS and CSS use the same form of multi-line comment, so putting the common code here.
+ */
+ protected function stripMultilineComments()
+ {
+ // First extract comments we want to keep, so they can be restored later
+ // PHP only supports $this inside anonymous functions since 5.4
+ $minifier = $this;
+ $callback = function ($match) use ($minifier) {
+ $count = count($minifier->extracted);
+ $placeholder = '/*' . $count . '*/';
+ $minifier->extracted[$placeholder] = $match[0];
+
+ return $placeholder;
+ };
+ $this->registerPattern('/
+ # optional newline
+ \n?
+
+ # start comment
+ \/\*
+
+ # comment content
+ (?:
+ # either starts with an !
+ !
+ |
+ # or, after some number of characters which do not end the comment
+ (?:(?!\*\/).)*?
+
+ # there is either a @license or @preserve tag
+ @(?:license|preserve)
+ )
+
+ # then match to the end of the comment
+ .*?\*\/\n?
+
+ /ixs', $callback);
+
+ // Then strip all other comments
+ $this->registerPattern('/\/\*.*?\*\//s', '');
+ }
+
+ /**
+ * We can't "just" run some regular expressions against JavaScript: it's a
+ * complex language. E.g. having an occurrence of // xyz would be a comment,
+ * unless it's used within a string. Of you could have something that looks
+ * like a 'string', but inside a comment.
+ * The only way to accurately replace these pieces is to traverse the JS one
+ * character at a time and try to find whatever starts first.
+ *
+ * @param string $content The content to replace patterns in
+ *
+ * @return string The (manipulated) content
+ */
+ protected function replace($content)
+ {
+ $contentLength = strlen($content);
+ $output = '';
+ $processedOffset = 0;
+ $positions = array_fill(0, count($this->patterns), -1);
+ $matches = array();
+
+ while ($processedOffset < $contentLength) {
+ // find first match for all patterns
+ foreach ($this->patterns as $i => $pattern) {
+ list($pattern, $replacement) = $pattern;
+
+ // we can safely ignore patterns for positions we've unset earlier,
+ // because we know these won't show up anymore
+ if (array_key_exists($i, $positions) == false) {
+ continue;
+ }
+
+ // no need to re-run matches that are still in the part of the
+ // content that hasn't been processed
+ if ($positions[$i] >= $processedOffset) {
+ continue;
+ }
+
+ $match = null;
+ if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset)) {
+ $matches[$i] = $match;
+
+ // we'll store the match position as well; that way, we
+ // don't have to redo all preg_matches after changing only
+ // the first (we'll still know where those others are)
+ $positions[$i] = $match[0][1];
+ } else {
+ // if the pattern couldn't be matched, there's no point in
+ // executing it again in later runs on this same content;
+ // ignore this one until we reach end of content
+ unset($matches[$i], $positions[$i]);
+ }
+ }
+
+ // no more matches to find: everything's been processed, break out
+ if (!$matches) {
+ // output the remaining content
+ $output .= substr($content, $processedOffset);
+ break;
+ }
+
+ // see which of the patterns actually found the first thing (we'll
+ // only want to execute that one, since we're unsure if what the
+ // other found was not inside what the first found)
+ $matchOffset = min($positions);
+ $firstPattern = array_search($matchOffset, $positions);
+ $match = $matches[$firstPattern];
+
+ // execute the pattern that matches earliest in the content string
+ list(, $replacement) = $this->patterns[$firstPattern];
+
+ // add the part of the input between $processedOffset and the first match;
+ // that content wasn't matched by anything
+ $output .= substr($content, $processedOffset, $matchOffset - $processedOffset);
+ // add the replacement for the match
+ $output .= $this->executeReplacement($replacement, $match);
+ // advance $processedOffset past the match
+ $processedOffset = $matchOffset + strlen($match[0][0]);
+ }
+
+ return $output;
+ }
+
+ /**
+ * If $replacement is a callback, execute it, passing in the match data.
+ * If it's a string, just pass it through.
+ *
+ * @param string|callable $replacement Replacement value
+ * @param array $match Match data, in PREG_OFFSET_CAPTURE form
+ *
+ * @return string
+ */
+ protected function executeReplacement($replacement, $match)
+ {
+ if (!is_callable($replacement)) {
+ return $replacement;
+ }
+ // convert $match from the PREG_OFFSET_CAPTURE form to the form the callback expects
+ foreach ($match as &$matchItem) {
+ $matchItem = $matchItem[0];
+ }
+
+ return $replacement($match);
+ }
+
+ /**
+ * Strings are a pattern we need to match, in order to ignore potential
+ * code-like content inside them, but we just want all of the string
+ * content to remain untouched.
+ *
+ * This method will replace all string content with simple STRING#
+ * placeholder text, so we've rid all strings from characters that may be
+ * misinterpreted. Original string content will be saved in $this->extracted
+ * and after doing all other minifying, we can restore the original content
+ * via restoreStrings().
+ *
+ * @param string[optional] $chars
+ * @param string[optional] $placeholderPrefix
+ */
+ protected function extractStrings($chars = '\'"', $placeholderPrefix = '')
+ {
+ // PHP only supports $this inside anonymous functions since 5.4
+ $minifier = $this;
+ $callback = function ($match) use ($minifier, $placeholderPrefix) {
+ // check the second index here, because the first always contains a quote
+ if ($match[2] === '') {
+ /*
+ * Empty strings need no placeholder; they can't be confused for
+ * anything else anyway.
+ * But we still needed to match them, for the extraction routine
+ * to skip over this particular string.
+ */
+ return $match[0];
+ }
+
+ $count = count($minifier->extracted);
+ $placeholder = $match[1] . $placeholderPrefix . $count . $match[1];
+ $minifier->extracted[$placeholder] = $match[1] . $match[2] . $match[1];
+
+ return $placeholder;
+ };
+
+ /*
+ * The \\ messiness explained:
+ * * Don't count ' or " as end-of-string if it's escaped (has backslash
+ * in front of it)
+ * * Unless... that backslash itself is escaped (another leading slash),
+ * in which case it's no longer escaping the ' or "
+ * * So there can be either no backslash, or an even number
+ * * multiply all of that times 4, to account for the escaping that has
+ * to be done to pass the backslash into the PHP string without it being
+ * considered as escape-char (times 2) and to get it in the regex,
+ * escaped (times 2)
+ */
+ $this->registerPattern('/([' . $chars . '])(.*?(?extracted.
+ *
+ * @param string $content
+ *
+ * @return string
+ */
+ protected function restoreExtractedData($content)
+ {
+ if (!$this->extracted) {
+ // nothing was extracted, nothing to restore
+ return $content;
+ }
+
+ $content = strtr($content, $this->extracted);
+
+ $this->extracted = array();
+
+ return $content;
+ }
+
+ /**
+ * Check if the path is a regular file and can be read.
+ *
+ * @param string $path
+ *
+ * @return bool
+ */
+ protected function canImportFile($path)
+ {
+ $parsed = parse_url($path);
+ if (
+ // file is elsewhere
+ isset($parsed['host'])
+ // file responds to queries (may change, or need to bypass cache)
+ || isset($parsed['query'])
+ ) {
+ return false;
+ }
+
+ try {
+ return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
+ }
+ // catch openbasedir exceptions which are not caught by @ on is_file()
+ catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Attempts to open file specified by $path for writing.
+ *
+ * @param string $path The path to the file
+ *
+ * @return resource Specifier for the target file
+ *
+ * @throws IOException
+ */
+ protected function openFileForWriting($path)
+ {
+ if ($path === '' || ($handler = @fopen($path, 'w')) === false) {
+ throw new IOException('The file "' . $path . '" could not be opened for writing. Check if PHP has enough permissions.');
+ }
+
+ return $handler;
+ }
+
+ /**
+ * Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
+ *
+ * @param resource $handler The resource to write to
+ * @param string $content The content to write
+ * @param string $path The path to the file (for exception printing only)
+ *
+ * @throws IOException
+ */
+ protected function writeToFile($handler, $content, $path = '')
+ {
+ if (
+ !is_resource($handler)
+ || ($result = @fwrite($handler, $content)) === false
+ || ($result < strlen($content))
+ ) {
+ throw new IOException('The file "' . $path . '" could not be written to. Check your disk space and file permissions.');
+ }
+ }
+
+ protected static function str_replace_first($search, $replace, $subject)
+ {
+ $pos = strpos($subject, $search);
+ if ($pos !== false) {
+ return substr_replace($subject, $replace, $pos, strlen($search));
+ }
+
+ return $subject;
+ }
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php b/includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php
new file mode 100644
index 0000000..d1aedbd
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/PathConverter/Converter.php
@@ -0,0 +1,204 @@
+
+ * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+class Converter implements ConverterInterface
+{
+ /**
+ * @var string
+ */
+ protected $from;
+
+ /**
+ * @var string
+ */
+ protected $to;
+
+ /**
+ * @param string $from The original base path (directory, not file!)
+ * @param string $to The new base path (directory, not file!)
+ * @param string $root Root directory (defaults to `getcwd`)
+ */
+ public function __construct($from, $to, $root = '')
+ {
+ $shared = $this->shared($from, $to);
+ if ($shared === '') {
+ // when both paths have nothing in common, one of them is probably
+ // absolute while the other is relative
+ $root = $root ?: getcwd();
+ $from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from);
+ $to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to);
+
+ // or traveling the tree via `..`
+ // attempt to resolve path, or assume it's fine if it doesn't exist
+ $from = @realpath($from) ?: $from;
+ $to = @realpath($to) ?: $to;
+ }
+
+ $from = $this->dirname($from);
+ $to = $this->dirname($to);
+
+ $from = $this->normalize($from);
+ $to = $this->normalize($to);
+
+ $this->from = $from;
+ $this->to = $to;
+ }
+
+ /**
+ * Normalize path.
+ *
+ * @param string $path
+ *
+ * @return string
+ */
+ protected function normalize($path)
+ {
+ // deal with different operating systems' directory structure
+ $path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
+
+ // remove leading current directory.
+ if (substr($path, 0, 2) === './') {
+ $path = substr($path, 2);
+ }
+
+ // remove references to current directory in the path.
+ $path = str_replace('/./', '/', $path);
+
+ /*
+ * Example:
+ * /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif
+ * to
+ * /home/forkcms/frontend/core/layout/images/img.gif
+ */
+ do {
+ $path = preg_replace('/[^\/]+(? $chunk) {
+ if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {
+ $shared[] = $chunk;
+ } else {
+ break;
+ }
+ }
+
+ return implode('/', $shared);
+ }
+
+ /**
+ * Convert paths relative from 1 file to another.
+ *
+ * E.g.
+ * ../images/img.gif relative to /home/forkcms/frontend/core/layout/css
+ * should become:
+ * ../../core/layout/images/img.gif relative to
+ * /home/forkcms/frontend/cache/minified_css
+ *
+ * @param string $path The relative path that needs to be converted
+ *
+ * @return string The new relative path
+ */
+ public function convert($path)
+ {
+ // quit early if conversion makes no sense
+ if ($this->from === $this->to) {
+ return $path;
+ }
+
+ $path = $this->normalize($path);
+ // if we're not dealing with a relative path, just return absolute
+ if (strpos($path, '/') === 0) {
+ return $path;
+ }
+
+ // normalize paths
+ $path = $this->normalize($this->from.'/'.$path);
+
+ // strip shared ancestor paths
+ $shared = $this->shared($path, $this->to);
+ $path = mb_substr($path, mb_strlen($shared));
+ $to = mb_substr($this->to, mb_strlen($shared));
+
+ // add .. for every directory that needs to be traversed to new path
+ $to = str_repeat('../', count(array_filter(explode('/', $to))));
+
+ return $to.ltrim($path, '/');
+ }
+
+ /**
+ * Attempt to get the directory name from a path.
+ *
+ * @param string $path
+ *
+ * @return string
+ */
+ protected function dirname($path)
+ {
+ if (@is_file($path)) {
+ return dirname($path);
+ }
+
+ if (@is_dir($path)) {
+ return rtrim($path, '/');
+ }
+
+ // no known file/dir, start making assumptions
+
+ // ends in / = dir
+ if (mb_substr($path, -1) === '/') {
+ return rtrim($path, '/');
+ }
+
+ // has a dot in the name, likely a file
+ if (preg_match('/.*\..*$/', basename($path)) !== 0) {
+ return dirname($path);
+ }
+
+ // you're on your own here!
+ return $path;
+ }
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php b/includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php
new file mode 100644
index 0000000..729ecbd
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/PathConverter/ConverterInterface.php
@@ -0,0 +1,24 @@
+
+ * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+interface ConverterInterface
+{
+ /**
+ * Convert file paths.
+ *
+ * @param string $path The path to be converted
+ *
+ * @return string The new path
+ */
+ public function convert($path);
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php b/includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php
new file mode 100644
index 0000000..f004bd0
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/PathConverter/NoConverter.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+class NoConverter implements ConverterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function convert($path)
+ {
+ return $path;
+ }
+}
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt
new file mode 100644
index 0000000..5c8cba7
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_after.txt
@@ -0,0 +1,7 @@
+in
+public
+extends
+private
+protected
+implements
+instanceof
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt
new file mode 100644
index 0000000..5abf357
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_before.txt
@@ -0,0 +1,26 @@
+do
+in
+let
+new
+var
+case
+else
+enum
+void
+with
+class
+const
+yield
+delete
+export
+import
+public
+static
+typeof
+extends
+package
+private
+function
+protected
+implements
+instanceof
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt
new file mode 100644
index 0000000..2a3ad3c
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/data/js/keywords_reserved.txt
@@ -0,0 +1,63 @@
+do
+if
+in
+for
+let
+new
+try
+var
+case
+else
+enum
+eval
+null
+this
+true
+void
+with
+break
+catch
+class
+const
+false
+super
+throw
+while
+yield
+delete
+export
+import
+public
+return
+static
+switch
+typeof
+default
+extends
+finally
+package
+private
+continue
+debugger
+function
+arguments
+interface
+protected
+implements
+instanceof
+abstract
+boolean
+byte
+char
+double
+final
+float
+goto
+int
+long
+native
+short
+synchronized
+throws
+transient
+volatile
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt
new file mode 100644
index 0000000..e66229a
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/data/js/operators.txt
@@ -0,0 +1,46 @@
++
+-
+*
+/
+%
+=
++=
+-=
+*=
+/=
+%=
+<<=
+>>=
+>>>=
+&=
+^=
+|=
+&
+|
+^
+~
+<<
+>>
+>>>
+==
+===
+!=
+!==
+>
+<
+>=
+<=
+&&
+||
+!
+.
+[
+]
+?
+:
+,
+;
+(
+)
+{
+}
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt
new file mode 100644
index 0000000..71a9b70
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/data/js/operators_after.txt
@@ -0,0 +1,43 @@
++
+-
+*
+/
+%
+=
++=
+-=
+*=
+/=
+%=
+<<=
+>>=
+>>>=
+&=
+^=
+|=
+&
+|
+^
+<<
+>>
+>>>
+==
+===
+!=
+!==
+>
+<
+>=
+<=
+&&
+||
+.
+[
+]
+?
+:
+,
+;
+(
+)
+}
\ No newline at end of file
diff --git a/includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt b/includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt
new file mode 100644
index 0000000..ff50d87
--- /dev/null
+++ b/includes/classes/Dependencies/MatthiasMullie/data/js/operators_before.txt
@@ -0,0 +1,43 @@
++
+-
+*
+/
+%
+=
++=
+-=
+*=
+/=
+%=
+<<=
+>>=
+>>>=
+&=
+^=
+|=
+&
+|
+^
+~
+<<
+>>
+>>>
+==
+===
+!=
+!==
+>
+<
+>=
+<=
+&&
+||
+!
+.
+[
+?
+:
+,
+;
+(
+{
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md b/includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md
new file mode 100644
index 0000000..de81fa2
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/CHANGELOG.md
@@ -0,0 +1,18 @@
+CHANGELOG
+=========
+
+4.4.0
+-----
+
+ * Added support for `*:only-of-type`
+
+2.8.0
+-----
+
+ * Added the `CssSelectorConverter` class as a non-static API for the component.
+ * Deprecated the `CssSelector` static API of the component.
+
+2.1.0
+-----
+
+ * none
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php
new file mode 100644
index 0000000..8336bfe
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/CssSelectorConverter.php
@@ -0,0 +1,69 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+
+/**
+ * CssSelectorConverter is the main entry point of the component and can convert CSS
+ * selectors to XPath expressions.
+ *
+ * @author Christophe Coevoet
+ */
+class CssSelectorConverter
+{
+ private $translator;
+ private $cache;
+
+ private static $xmlCache = [];
+ private static $htmlCache = [];
+
+ /**
+ * @param bool $html Whether HTML support should be enabled. Disable it for XML documents
+ */
+ public function __construct(bool $html = true)
+ {
+ $this->translator = new Translator();
+
+ if ($html) {
+ $this->translator->registerExtension(new HtmlExtension($this->translator));
+ $this->cache = &self::$htmlCache;
+ } else {
+ $this->cache = &self::$xmlCache;
+ }
+
+ $this->translator
+ ->registerParserShortcut(new EmptyStringParser())
+ ->registerParserShortcut(new ElementParser())
+ ->registerParserShortcut(new ClassParser())
+ ->registerParserShortcut(new HashParser())
+ ;
+ }
+
+ /**
+ * Translates a CSS expression to its XPath equivalent.
+ *
+ * Optionally, a prefix can be added to the resulting XPath
+ * expression with the $prefix parameter.
+ *
+ * @return string
+ */
+ public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::')
+ {
+ return $this->cache[$prefix][$cssExpr] ?? $this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..311463d
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
+
+/**
+ * Interface for exceptions.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ */
+interface ExceptionInterface extends \Throwable
+{
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
new file mode 100644
index 0000000..63e7ede
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ */
+class ExpressionErrorException extends ParseException
+{
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php
new file mode 100644
index 0000000..0e23f8b
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/InternalErrorException.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ */
+class InternalErrorException extends ParseException
+{
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php
new file mode 100644
index 0000000..b3f0b1a
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/ParseException.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Fabien Potencier
+ */
+class ParseException extends \Exception implements ExceptionInterface
+{
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
new file mode 100644
index 0000000..55d000d
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ */
+class SyntaxErrorException extends ParseException
+{
+ /**
+ * @return self
+ */
+ public static function unexpectedToken(string $expectedValue, Token $foundToken)
+ {
+ return new self(sprintf('Expected %s, but %s found.', $expectedValue, $foundToken));
+ }
+
+ /**
+ * @return self
+ */
+ public static function pseudoElementFound(string $pseudoElement, string $unexpectedLocation)
+ {
+ return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation));
+ }
+
+ /**
+ * @return self
+ */
+ public static function unclosedString(int $position)
+ {
+ return new self(sprintf('Unclosed/invalid string at %s.', $position));
+ }
+
+ /**
+ * @return self
+ */
+ public static function nestedNot()
+ {
+ return new self('Got nested ::not().');
+ }
+
+ /**
+ * @return self
+ */
+ public static function stringAsFunctionArgument()
+ {
+ return new self('String not allowed as function argument.');
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE b/includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE
new file mode 100644
index 0000000..0138f8f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/LICENSE
@@ -0,0 +1,19 @@
+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
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php
new file mode 100644
index 0000000..c643366
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AbstractNode.php
@@ -0,0 +1,39 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Abstract base node class.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+abstract class AbstractNode implements NodeInterface
+{
+ /**
+ * @var string
+ */
+ private $nodeName;
+
+ public function getNodeName(): string
+ {
+ if (null === $this->nodeName) {
+ $this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class);
+ }
+
+ return $this->nodeName;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php
new file mode 100644
index 0000000..e624a46
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/AttributeNode.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a "[| ]" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class AttributeNode extends AbstractNode
+{
+ private $selector;
+ private $namespace;
+ private $attribute;
+ private $operator;
+ private $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 getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getNamespace(): ?string
+ {
+ return $this->namespace;
+ }
+
+ public function getAttribute(): string
+ {
+ return $this->attribute;
+ }
+
+ public function getOperator(): string
+ {
+ return $this->operator;
+ }
+
+ public function getValue(): ?string
+ {
+ return $this->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+ }
+
+ public function __toString(): string
+ {
+ $attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute;
+
+ return 'exists' === $this->operator
+ ? sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute)
+ : sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php
new file mode 100644
index 0000000..1efb467
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ClassNode.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a "." node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class ClassNode extends AbstractNode
+{
+ private $selector;
+ private $name;
+
+ public function __construct(NodeInterface $selector, string $name)
+ {
+ $this->selector = $selector;
+ $this->name = $name;
+ }
+
+ public function getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+ }
+
+ public function __toString(): string
+ {
+ return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
new file mode 100644
index 0000000..468b02a
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a combined node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class CombinedSelectorNode extends AbstractNode
+{
+ private $selector;
+ private $combinator;
+ private $subSelector;
+
+ public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector)
+ {
+ $this->selector = $selector;
+ $this->combinator = $combinator;
+ $this->subSelector = $subSelector;
+ }
+
+ public function getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getCombinator(): string
+ {
+ return $this->combinator;
+ }
+
+ public function getSubSelector(): NodeInterface
+ {
+ return $this->subSelector;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
+ }
+
+ public function __toString(): string
+ {
+ $combinator = ' ' === $this->combinator ? '' : $this->combinator;
+
+ return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php
new file mode 100644
index 0000000..72851c0
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/ElementNode.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a "|" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class ElementNode extends AbstractNode
+{
+ private $namespace;
+ private $element;
+
+ public function __construct(?string $namespace = null, ?string $element = null)
+ {
+ $this->namespace = $namespace;
+ $this->element = $element;
+ }
+
+ public function getNamespace(): ?string
+ {
+ return $this->namespace;
+ }
+
+ public function getElement(): ?string
+ {
+ return $this->element;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return new Specificity(0, 0, $this->element ? 1 : 0);
+ }
+
+ public function __toString(): string
+ {
+ $element = $this->element ?: '*';
+
+ return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php
new file mode 100644
index 0000000..66626c8
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/FunctionNode.php
@@ -0,0 +1,76 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+/**
+ * Represents a ":()" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class FunctionNode extends AbstractNode
+{
+ private $selector;
+ private $name;
+ private $arguments;
+
+ /**
+ * @param Token[] $arguments
+ */
+ public function __construct(NodeInterface $selector, string $name, array $arguments = [])
+ {
+ $this->selector = $selector;
+ $this->name = strtolower($name);
+ $this->arguments = $arguments;
+ }
+
+ public function getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * @return Token[]
+ */
+ public function getArguments(): array
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+ }
+
+ public function __toString(): string
+ {
+ $arguments = implode(', ', array_map(function (Token $token) {
+ return "'".$token->getValue()."'";
+ }, $this->arguments));
+
+ return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : '');
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php
new file mode 100644
index 0000000..366bc54
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/HashNode.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a "#" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class HashNode extends AbstractNode
+{
+ private $selector;
+ private $id;
+
+ public function __construct(NodeInterface $selector, string $id)
+ {
+ $this->selector = $selector;
+ $this->id = $id;
+ }
+
+ public function getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
+ }
+
+ public function __toString(): string
+ {
+ return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php
new file mode 100644
index 0000000..abead95
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NegationNode.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a ":not()" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class NegationNode extends AbstractNode
+{
+ private $selector;
+ private $subSelector;
+
+ public function __construct(NodeInterface $selector, NodeInterface $subSelector)
+ {
+ $this->selector = $selector;
+ $this->subSelector = $subSelector;
+ }
+
+ public function getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getSubSelector(): NodeInterface
+ {
+ return $this->subSelector;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
+ }
+
+ public function __toString(): string
+ {
+ return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php
new file mode 100644
index 0000000..41d22b5
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/NodeInterface.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Interface for nodes.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+interface NodeInterface
+{
+ public function getNodeName(): string;
+
+ public function getSpecificity(): Specificity;
+
+ public function __toString(): string;
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php
new file mode 100644
index 0000000..0f4c835
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/PseudoNode.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a ":" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class PseudoNode extends AbstractNode
+{
+ private $selector;
+ private $identifier;
+
+ public function __construct(NodeInterface $selector, string $identifier)
+ {
+ $this->selector = $selector;
+ $this->identifier = strtolower($identifier);
+ }
+
+ public function getSelector(): NodeInterface
+ {
+ return $this->selector;
+ }
+
+ public function getIdentifier(): string
+ {
+ return $this->identifier;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+ }
+
+ public function __toString(): string
+ {
+ return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php
new file mode 100644
index 0000000..d0988d8
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/SelectorNode.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a "(::|:)" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class SelectorNode extends AbstractNode
+{
+ private $tree;
+ private $pseudoElement;
+
+ public function __construct(NodeInterface $tree, ?string $pseudoElement = null)
+ {
+ $this->tree = $tree;
+ $this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
+ }
+
+ public function getTree(): NodeInterface
+ {
+ return $this->tree;
+ }
+
+ public function getPseudoElement(): ?string
+ {
+ return $this->pseudoElement;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSpecificity(): Specificity
+ {
+ return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
+ }
+
+ public function __toString(): string
+ {
+ return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : '');
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php
new file mode 100644
index 0000000..fdfdb67
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Node/Specificity.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a node specificity.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @see http://www.w3.org/TR/selectors/#specificity
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class Specificity
+{
+ public const A_FACTOR = 100;
+ public const B_FACTOR = 10;
+ public const C_FACTOR = 1;
+
+ private $a;
+ private $b;
+ private $c;
+
+ public function __construct(int $a, int $b, int $c)
+ {
+ $this->a = $a;
+ $this->b = $b;
+ $this->c = $c;
+ }
+
+ public function plus(self $specificity): self
+ {
+ return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
+ }
+
+ public function getValue(): int
+ {
+ return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
+ }
+
+ /**
+ * Returns -1 if the object specificity is lower than the argument,
+ * 0 if they are equal, and 1 if the argument is lower.
+ */
+ public function compareTo(self $specificity): int
+ {
+ if ($this->a !== $specificity->a) {
+ return $this->a > $specificity->a ? 1 : -1;
+ }
+
+ if ($this->b !== $specificity->b) {
+ return $this->b > $specificity->b ? 1 : -1;
+ }
+
+ if ($this->c !== $specificity->c) {
+ return $this->c > $specificity->c ? 1 : -1;
+ }
+
+ return 0;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
new file mode 100644
index 0000000..1164047
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class CommentHandler implements HandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(Reader $reader, TokenStream $stream): bool
+ {
+ if ('/*' !== $reader->getSubstring(2)) {
+ return false;
+ }
+
+ $offset = $reader->getOffset('*/');
+
+ if (false === $offset) {
+ $reader->moveToEnd();
+ } else {
+ $reader->moveForward($offset + 2);
+ }
+
+ return true;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
new file mode 100644
index 0000000..8f59a56
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector handler interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+interface HandlerInterface
+{
+ public function handle(Reader $reader, TokenStream $stream): bool;
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
new file mode 100644
index 0000000..a739fc7
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class HashHandler implements HandlerInterface
+{
+ private $patterns;
+ private $escaping;
+
+ public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
+ {
+ $this->patterns = $patterns;
+ $this->escaping = $escaping;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(Reader $reader, TokenStream $stream): bool
+ {
+ $match = $reader->findPattern($this->patterns->getHashPattern());
+
+ if (!$match) {
+ return false;
+ }
+
+ $value = $this->escaping->escapeUnicode($match[1]);
+ $stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition()));
+ $reader->moveForward(\strlen($match[0]));
+
+ return true;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
new file mode 100644
index 0000000..56e4e23
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class IdentifierHandler implements HandlerInterface
+{
+ private $patterns;
+ private $escaping;
+
+ public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
+ {
+ $this->patterns = $patterns;
+ $this->escaping = $escaping;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(Reader $reader, TokenStream $stream): bool
+ {
+ $match = $reader->findPattern($this->patterns->getIdentifierPattern());
+
+ if (!$match) {
+ return false;
+ }
+
+ $value = $this->escaping->escapeUnicode($match[0]);
+ $stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition()));
+ $reader->moveForward(\strlen($match[0]));
+
+ return true;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
new file mode 100644
index 0000000..435f44c
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class NumberHandler implements HandlerInterface
+{
+ private $patterns;
+
+ public function __construct(TokenizerPatterns $patterns)
+ {
+ $this->patterns = $patterns;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(Reader $reader, TokenStream $stream): bool
+ {
+ $match = $reader->findPattern($this->patterns->getNumberPattern());
+
+ if (!$match) {
+ return false;
+ }
+
+ $stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition()));
+ $reader->moveForward(\strlen($match[0]));
+
+ return true;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
new file mode 100644
index 0000000..caf70c4
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\InternalErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class StringHandler implements HandlerInterface
+{
+ private $patterns;
+ private $escaping;
+
+ public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
+ {
+ $this->patterns = $patterns;
+ $this->escaping = $escaping;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(Reader $reader, TokenStream $stream): bool
+ {
+ $quote = $reader->getSubstring(1);
+
+ if (!\in_array($quote, ["'", '"'])) {
+ return false;
+ }
+
+ $reader->moveForward(1);
+ $match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote));
+
+ if (!$match) {
+ throw new InternalErrorException(sprintf('Should have found at least an empty match at %d.', $reader->getPosition()));
+ }
+
+ // check unclosed strings
+ if (\strlen($match[0]) === $reader->getRemainingLength()) {
+ throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
+ }
+
+ // check quotes pairs validity
+ if ($quote !== $reader->getSubstring(1, \strlen($match[0]))) {
+ throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
+ }
+
+ $string = $this->escaping->escapeUnicodeAndNewLine($match[0]);
+ $stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition()));
+ $reader->moveForward(\strlen($match[0]) + 1);
+
+ return true;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
new file mode 100644
index 0000000..ad93cca
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector whitespace handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class WhitespaceHandler implements HandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(Reader $reader, TokenStream $stream): bool
+ {
+ $match = $reader->findPattern('~^[ \t\r\n\f]+~');
+
+ if (false === $match) {
+ return false;
+ }
+
+ $stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition()));
+ $reader->moveForward(\strlen($match[0]));
+
+ return true;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php
new file mode 100644
index 0000000..09d44c5
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Parser.php
@@ -0,0 +1,353 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+use PoweredCache\Dependencies\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.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class Parser implements ParserInterface
+{
+ private $tokenizer;
+
+ public function __construct(?Tokenizer $tokenizer = null)
+ {
+ $this->tokenizer = $tokenizer ?? new Tokenizer();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parse(string $source): array
+ {
+ $reader = new Reader($source);
+ $stream = $this->tokenizer->tokenize($reader);
+
+ return $this->parseSelectorList($stream);
+ }
+
+ /**
+ * Parses the arguments for ":nth-child()" and friends.
+ *
+ * @param Token[] $tokens
+ *
+ * @throws SyntaxErrorException
+ */
+ public static function parseSeries(array $tokens): array
+ {
+ foreach ($tokens as $token) {
+ if ($token->isString()) {
+ throw SyntaxErrorException::stringAsFunctionArgument();
+ }
+ }
+
+ $joined = trim(implode('', array_map(function (Token $token) {
+ return $token->getValue();
+ }, $tokens)));
+
+ $int = function ($string) {
+ if (!is_numeric($string)) {
+ throw SyntaxErrorException::stringAsFunctionArgument();
+ }
+
+ return (int) $string;
+ };
+
+ switch (true) {
+ case 'odd' === $joined:
+ return [2, 1];
+ case 'even' === $joined:
+ return [2, 0];
+ case 'n' === $joined:
+ return [1, 0];
+ case !str_contains($joined, 'n'):
+ return [0, $int($joined)];
+ }
+
+ $split = explode('n', $joined);
+ $first = $split[0] ?? null;
+
+ return [
+ $first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1,
+ isset($split[1]) && $split[1] ? $int($split[1]) : 0,
+ ];
+ }
+
+ private function parseSelectorList(TokenStream $stream): array
+ {
+ $stream->skipWhitespace();
+ $selectors = [];
+
+ while (true) {
+ $selectors[] = $this->parserSelectorNode($stream);
+
+ if ($stream->getPeek()->isDelimiter([','])) {
+ $stream->getNext();
+ $stream->skipWhitespace();
+ } else {
+ break;
+ }
+ }
+
+ return $selectors;
+ }
+
+ private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
+ {
+ [$result, $pseudoElement] = $this->parseSimpleSelector($stream);
+
+ while (true) {
+ $stream->skipWhitespace();
+ $peek = $stream->getPeek();
+
+ if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
+ break;
+ }
+
+ if (null !== $pseudoElement) {
+ throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
+ }
+
+ if ($peek->isDelimiter(['+', '>', '~'])) {
+ $combinator = $stream->getNext()->getValue();
+ $stream->skipWhitespace();
+ } else {
+ $combinator = ' ';
+ }
+
+ [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
+ $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
+ }
+
+ return new Node\SelectorNode($result, $pseudoElement);
+ }
+
+ /**
+ * Parses next simple node (hash, class, pseudo, negation).
+ *
+ * @throws SyntaxErrorException
+ */
+ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = 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([',', '+', '>', '~'])
+ || ($insideNegation && $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);
+
+ continue;
+ }
+
+ $stream->getNext();
+ $stream->skipWhitespace();
+
+ if ('not' === strtolower($identifier)) {
+ if ($insideNegation) {
+ throw SyntaxErrorException::nestedNot();
+ }
+
+ [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, 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);
+ } 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 (empty($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];
+ }
+
+ private function parseElementNode(TokenStream $stream): Node\ElementNode
+ {
+ $peek = $stream->getPeek();
+
+ if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
+ if ($peek->isIdentifier()) {
+ $namespace = $stream->getNext()->getValue();
+ } else {
+ $stream->getNext();
+ $namespace = null;
+ }
+
+ if ($stream->getPeek()->isDelimiter(['|'])) {
+ $stream->getNext();
+ $element = $stream->getNextIdentifierOrStar();
+ } else {
+ $element = $namespace;
+ $namespace = null;
+ }
+ } else {
+ $element = $namespace = null;
+ }
+
+ return new Node\ElementNode($namespace, $element);
+ }
+
+ private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode
+ {
+ $stream->skipWhitespace();
+ $attribute = $stream->getNextIdentifierOrStar();
+
+ if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
+ throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
+ }
+
+ if ($stream->getPeek()->isDelimiter(['|'])) {
+ $stream->getNext();
+
+ if ($stream->getPeek()->isDelimiter(['='])) {
+ $namespace = null;
+ $stream->getNext();
+ $operator = '|=';
+ } else {
+ $namespace = $attribute;
+ $attribute = $stream->getNextIdentifier();
+ $operator = null;
+ }
+ } else {
+ $namespace = $operator = null;
+ }
+
+ if (null === $operator) {
+ $stream->skipWhitespace();
+ $next = $stream->getNext();
+
+ if ($next->isDelimiter([']'])) {
+ return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
+ } elseif ($next->isDelimiter(['='])) {
+ $operator = '=';
+ } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!'])
+ && $stream->getPeek()->isDelimiter(['='])
+ ) {
+ $operator = $next->getValue().'=';
+ $stream->getNext();
+ } else {
+ throw SyntaxErrorException::unexpectedToken('operator', $next);
+ }
+ }
+
+ $stream->skipWhitespace();
+ $value = $stream->getNext();
+
+ if ($value->isNumber()) {
+ // if the value is a number, it's casted into a string
+ $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
+ }
+
+ if (!($value->isIdentifier() || $value->isString())) {
+ throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
+ }
+
+ $stream->skipWhitespace();
+ $next = $stream->getNext();
+
+ if (!$next->isDelimiter([']'])) {
+ throw SyntaxErrorException::unexpectedToken('"]"', $next);
+ }
+
+ return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php
new file mode 100644
index 0000000..df808e2
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/ParserInterface.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+
+/**
+ * CSS selector parser interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+interface ParserInterface
+{
+ /**
+ * Parses given selector source into an array of tokens.
+ *
+ * @return SelectorNode[]
+ */
+ public function parse(string $source): array;
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php
new file mode 100644
index 0000000..2bef8ae
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Reader.php
@@ -0,0 +1,86 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
+
+/**
+ * CSS selector reader.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class Reader
+{
+ private $source;
+ private $length;
+ private $position = 0;
+
+ public function __construct(string $source)
+ {
+ $this->source = $source;
+ $this->length = \strlen($source);
+ }
+
+ public function isEOF(): bool
+ {
+ return $this->position >= $this->length;
+ }
+
+ public function getPosition(): int
+ {
+ return $this->position;
+ }
+
+ public function getRemainingLength(): int
+ {
+ return $this->length - $this->position;
+ }
+
+ public function getSubstring(int $length, int $offset = 0): string
+ {
+ return substr($this->source, $this->position + $offset, $length);
+ }
+
+ public function getOffset(string $string)
+ {
+ $position = strpos($this->source, $string, $this->position);
+
+ return false === $position ? false : $position - $this->position;
+ }
+
+ /**
+ * @return array|false
+ */
+ public function findPattern(string $pattern)
+ {
+ $source = substr($this->source, $this->position);
+
+ if (preg_match($pattern, $source, $matches)) {
+ return $matches;
+ }
+
+ return false;
+ }
+
+ public function moveForward(int $length)
+ {
+ $this->position += $length;
+ }
+
+ public function moveToEnd()
+ {
+ $this->position = $this->length;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
new file mode 100644
index 0000000..a34a122
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector class parser shortcut.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class ClassParser implements ParserInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parse(string $source): array
+ {
+ // Matches an optional namespace, optional element, and required class
+ // $source = 'test|input.ab6bd_field';
+ // $matches = array (size=4)
+ // 0 => string 'test|input.ab6bd_field' (length=22)
+ // 1 => string 'test' (length=4)
+ // 2 => string 'input' (length=5)
+ // 3 => string 'ab6bd_field' (length=11)
+ if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) {
+ return [
+ new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
+ ];
+ }
+
+ return [];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
new file mode 100644
index 0000000..2d07857
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector element parser shortcut.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class ElementParser implements ParserInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parse(string $source): array
+ {
+ // Matches an optional namespace, required element or `*`
+ // $source = 'testns|testel';
+ // $matches = array (size=3)
+ // 0 => string 'testns|testel' (length=13)
+ // 1 => string 'testns' (length=6)
+ // 2 => string 'testel' (length=6)
+ if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) {
+ return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))];
+ }
+
+ return [];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
new file mode 100644
index 0000000..68f8a87
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector class parser shortcut.
+ *
+ * This shortcut ensure compatibility with previous version.
+ * - The parser fails to parse an empty string.
+ * - In the previous version, an empty string matches each tags.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class EmptyStringParser implements ParserInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parse(string $source): array
+ {
+ // Matches an empty string
+ if ('' == $source) {
+ return [new SelectorNode(new ElementNode(null, '*'))];
+ }
+
+ return [];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
new file mode 100644
index 0000000..6f08f5f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\HashNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector hash parser shortcut.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class HashParser implements ParserInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parse(string $source): array
+ {
+ // Matches an optional namespace, optional element, and required id
+ // $source = 'test|input#ab6bd_field';
+ // $matches = array (size=4)
+ // 0 => string 'test|input#ab6bd_field' (length=22)
+ // 1 => string 'test' (length=4)
+ // 2 => string 'input' (length=5)
+ // 3 => string 'ab6bd_field' (length=11)
+ if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) {
+ return [
+ new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
+ ];
+ }
+
+ return [];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php
new file mode 100644
index 0000000..ed43632
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Token.php
@@ -0,0 +1,111 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
+
+/**
+ * CSS selector token.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class Token
+{
+ public const TYPE_FILE_END = 'eof';
+ public const TYPE_DELIMITER = 'delimiter';
+ public const TYPE_WHITESPACE = 'whitespace';
+ public const TYPE_IDENTIFIER = 'identifier';
+ public const TYPE_HASH = 'hash';
+ public const TYPE_NUMBER = 'number';
+ public const TYPE_STRING = 'string';
+
+ private $type;
+ private $value;
+ private $position;
+
+ public function __construct(?string $type, ?string $value, ?int $position)
+ {
+ $this->type = $type;
+ $this->value = $value;
+ $this->position = $position;
+ }
+
+ public function getType(): ?int
+ {
+ return $this->type;
+ }
+
+ public function getValue(): ?string
+ {
+ return $this->value;
+ }
+
+ public function getPosition(): ?int
+ {
+ return $this->position;
+ }
+
+ public function isFileEnd(): bool
+ {
+ return self::TYPE_FILE_END === $this->type;
+ }
+
+ public function isDelimiter(array $values = []): bool
+ {
+ if (self::TYPE_DELIMITER !== $this->type) {
+ return false;
+ }
+
+ if (empty($values)) {
+ return true;
+ }
+
+ return \in_array($this->value, $values);
+ }
+
+ public function isWhitespace(): bool
+ {
+ return self::TYPE_WHITESPACE === $this->type;
+ }
+
+ public function isIdentifier(): bool
+ {
+ return self::TYPE_IDENTIFIER === $this->type;
+ }
+
+ public function isHash(): bool
+ {
+ return self::TYPE_HASH === $this->type;
+ }
+
+ public function isNumber(): bool
+ {
+ return self::TYPE_NUMBER === $this->type;
+ }
+
+ public function isString(): bool
+ {
+ return self::TYPE_STRING === $this->type;
+ }
+
+ public function __toString(): string
+ {
+ if ($this->value) {
+ return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position);
+ }
+
+ return sprintf('<%s at %s>', $this->type, $this->position);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php
new file mode 100644
index 0000000..56c5f55
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/TokenStream.php
@@ -0,0 +1,167 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\InternalErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+
+/**
+ * CSS selector token stream.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class TokenStream
+{
+ /**
+ * @var Token[]
+ */
+ private $tokens = [];
+
+ /**
+ * @var Token[]
+ */
+ private $used = [];
+
+ /**
+ * @var int
+ */
+ private $cursor = 0;
+
+ /**
+ * @var Token|null
+ */
+ private $peeked;
+
+ /**
+ * @var bool
+ */
+ private $peeking = false;
+
+ /**
+ * Pushes a token.
+ *
+ * @return $this
+ */
+ public function push(Token $token): self
+ {
+ $this->tokens[] = $token;
+
+ return $this;
+ }
+
+ /**
+ * Freezes stream.
+ *
+ * @return $this
+ */
+ public function freeze(): self
+ {
+ return $this;
+ }
+
+ /**
+ * Returns next token.
+ *
+ * @throws InternalErrorException If there is no more token
+ */
+ public function getNext(): Token
+ {
+ if ($this->peeking) {
+ $this->peeking = false;
+ $this->used[] = $this->peeked;
+
+ return $this->peeked;
+ }
+
+ if (!isset($this->tokens[$this->cursor])) {
+ throw new InternalErrorException('Unexpected token stream end.');
+ }
+
+ return $this->tokens[$this->cursor++];
+ }
+
+ /**
+ * Returns peeked token.
+ */
+ public function getPeek(): Token
+ {
+ if (!$this->peeking) {
+ $this->peeked = $this->getNext();
+ $this->peeking = true;
+ }
+
+ return $this->peeked;
+ }
+
+ /**
+ * Returns used tokens.
+ *
+ * @return Token[]
+ */
+ public function getUsed(): array
+ {
+ return $this->used;
+ }
+
+ /**
+ * Returns next identifier token.
+ *
+ * @throws SyntaxErrorException If next token is not an identifier
+ */
+ public function getNextIdentifier(): string
+ {
+ $next = $this->getNext();
+
+ if (!$next->isIdentifier()) {
+ throw SyntaxErrorException::unexpectedToken('identifier', $next);
+ }
+
+ return $next->getValue();
+ }
+
+ /**
+ * Returns next identifier or null if star delimiter token is found.
+ *
+ * @throws SyntaxErrorException If next token is not an identifier or a star delimiter
+ */
+ public function getNextIdentifierOrStar(): ?string
+ {
+ $next = $this->getNext();
+
+ if ($next->isIdentifier()) {
+ return $next->getValue();
+ }
+
+ if ($next->isDelimiter(['*'])) {
+ return null;
+ }
+
+ throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next);
+ }
+
+ /**
+ * Skips next whitespace if any.
+ */
+ public function skipWhitespace()
+ {
+ $peek = $this->getPeek();
+
+ if ($peek->isWhitespace()) {
+ $this->getNext();
+ }
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
new file mode 100644
index 0000000..aa5cb8a
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector tokenizer.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class Tokenizer
+{
+ /**
+ * @var Handler\HandlerInterface[]
+ */
+ private $handlers;
+
+ public function __construct()
+ {
+ $patterns = new TokenizerPatterns();
+ $escaping = new TokenizerEscaping($patterns);
+
+ $this->handlers = [
+ new Handler\WhitespaceHandler(),
+ new Handler\IdentifierHandler($patterns, $escaping),
+ new Handler\HashHandler($patterns, $escaping),
+ new Handler\StringHandler($patterns, $escaping),
+ new Handler\NumberHandler($patterns),
+ new Handler\CommentHandler(),
+ ];
+ }
+
+ /**
+ * Tokenize selector source code.
+ */
+ public function tokenize(Reader $reader): TokenStream
+ {
+ $stream = new TokenStream();
+
+ while (!$reader->isEOF()) {
+ foreach ($this->handlers as $handler) {
+ if ($handler->handle($reader, $stream)) {
+ continue 2;
+ }
+ }
+
+ $stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition()));
+ $reader->moveForward(1);
+ }
+
+ return $stream
+ ->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition()))
+ ->freeze();
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
new file mode 100644
index 0000000..fa319c5
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer;
+
+/**
+ * CSS selector tokenizer escaping applier.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class TokenizerEscaping
+{
+ private $patterns;
+
+ public function __construct(TokenizerPatterns $patterns)
+ {
+ $this->patterns = $patterns;
+ }
+
+ public function escapeUnicode(string $value): string
+ {
+ $value = $this->replaceUnicodeSequences($value);
+
+ return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
+ }
+
+ public function escapeUnicodeAndNewLine(string $value): string
+ {
+ $value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);
+
+ return $this->escapeUnicode($value);
+ }
+
+ private function replaceUnicodeSequences(string $value): string
+ {
+ return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
+ $c = hexdec($match[1]);
+
+ if (0x80 > $c %= 0x200000) {
+ return \chr($c);
+ }
+ if (0x800 > $c) {
+ return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
+ }
+ if (0x10000 > $c) {
+ return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
+ }
+
+ return '';
+ }, $value);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
new file mode 100644
index 0000000..e714a8e
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
@@ -0,0 +1,89 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer;
+
+/**
+ * CSS selector tokenizer patterns builder.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class TokenizerPatterns
+{
+ private $unicodeEscapePattern;
+ private $simpleEscapePattern;
+ private $newLineEscapePattern;
+ private $escapePattern;
+ private $stringEscapePattern;
+ private $nonAsciiPattern;
+ private $nmCharPattern;
+ private $nmStartPattern;
+ private $identifierPattern;
+ private $hashPattern;
+ private $numberPattern;
+ private $quotedStringPattern;
+
+ public function __construct()
+ {
+ $this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?';
+ $this->simpleEscapePattern = '\\\\(.)';
+ $this->newLineEscapePattern = '\\\\(?:\n|\r\n|\r|\f)';
+ $this->escapePattern = $this->unicodeEscapePattern.'|\\\\[^\n\r\f0-9a-f]';
+ $this->stringEscapePattern = $this->newLineEscapePattern.'|'.$this->escapePattern;
+ $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->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
+ $this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
+ $this->quotedStringPattern = '([^\n\r\f\\\\%s]|'.$this->stringEscapePattern.')*';
+ }
+
+ public function getNewLineEscapePattern(): string
+ {
+ return '~'.$this->newLineEscapePattern.'~';
+ }
+
+ public function getSimpleEscapePattern(): string
+ {
+ return '~'.$this->simpleEscapePattern.'~';
+ }
+
+ public function getUnicodeEscapePattern(): string
+ {
+ return '~'.$this->unicodeEscapePattern.'~i';
+ }
+
+ public function getIdentifierPattern(): string
+ {
+ return '~^'.$this->identifierPattern.'~i';
+ }
+
+ public function getHashPattern(): string
+ {
+ return '~^'.$this->hashPattern.'~i';
+ }
+
+ public function getNumberPattern(): string
+ {
+ return '~^'.$this->numberPattern.'~';
+ }
+
+ public function getQuotedStringPattern(string $quote): string
+ {
+ return '~^'.sprintf($this->quotedStringPattern, $quote).'~i';
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/README.md b/includes/classes/Dependencies/Symfony/Component/CssSelector/README.md
new file mode 100644
index 0000000..ede4a3a
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/README.md
@@ -0,0 +1,20 @@
+CssSelector Component
+=====================
+
+The CssSelector component converts CSS selectors to XPath expressions.
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/css_selector.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
+
+Credits
+-------
+
+This component is a port of the Python cssselect library
+[v0.7.1](https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1),
+which is distributed under the BSD license.
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
new file mode 100644
index 0000000..d42ce90
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\CssSelectorConverter;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ParseException;
+
+class CssSelectorConverterTest extends TestCase
+{
+ public function testCssToXPath()
+ {
+ $converter = new CssSelectorConverter();
+
+ $this->assertEquals('descendant-or-self::*', $converter->toXPath(''));
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('h1'));
+ $this->assertEquals("descendant-or-self::h1[@id = 'foo']", $converter->toXPath('h1#foo'));
+ $this->assertEquals("descendant-or-self::h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", $converter->toXPath('h1.foo'));
+ $this->assertEquals('descendant-or-self::foo:h1', $converter->toXPath('foo|h1'));
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
+
+ // Test the cache layer
+ $converter = new CssSelectorConverter();
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
+ }
+
+ public function testCssToXPathXml()
+ {
+ $converter = new CssSelectorConverter(false);
+
+ $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
+
+ $converter = new CssSelectorConverter(false);
+ // Test the cache layer
+ $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
+ }
+
+ public function testParseExceptions()
+ {
+ $this->expectException(ParseException::class);
+ $this->expectExceptionMessage('Expected identifier, but found.');
+ $converter = new CssSelectorConverter();
+ $converter->toXPath('h1:');
+ }
+
+ /** @dataProvider getCssToXPathWithoutPrefixTestData */
+ public function testCssToXPathWithoutPrefix($css, $xpath)
+ {
+ $converter = new CssSelectorConverter();
+
+ $this->assertEquals($xpath, $converter->toXPath($css, ''), '->parse() parses an input string and returns a node');
+ }
+
+ public static function getCssToXPathWithoutPrefixTestData()
+ {
+ return [
+ ['h1', 'h1'],
+ ['foo|h1', 'foo:h1'],
+ ['h1, h2, h3', 'h1 | h2 | h3'],
+ ['h1:nth-child(3n+1)', "*/*[(name() = 'h1') and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"],
+ ['h1 > p', 'h1/p'],
+ ['h1#foo', "h1[@id = 'foo']"],
+ ['h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['h1[class*="foo bar"]', "h1[@class and contains(@class, 'foo bar')]"],
+ ['h1[foo|class*="foo bar"]', "h1[@foo:class and contains(@foo:class, 'foo bar')]"],
+ ['h1[class]', 'h1[@class]'],
+ ['h1 .foo', "h1/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['h1 #foo', "h1/descendant-or-self::*/*[@id = 'foo']"],
+ ['h1 [class*=foo]', "h1/descendant-or-self::*/*[@class and contains(@class, 'foo')]"],
+ ['div>.foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['div > .foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
new file mode 100644
index 0000000..99460ae
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NodeInterface;
+
+abstract class AbstractNodeTestCase extends TestCase
+{
+ /** @dataProvider getToStringConversionTestData */
+ public function testToStringConversion(NodeInterface $node, $representation)
+ {
+ $this->assertEquals($representation, (string) $node);
+ }
+
+ /** @dataProvider getSpecificityValueTestData */
+ public function testSpecificityValue(NodeInterface $node, $value)
+ {
+ $this->assertEquals($value, $node->getSpecificity()->getValue());
+ }
+
+ abstract public static function getToStringConversionTestData();
+
+ abstract public static function getSpecificityValueTestData();
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
new file mode 100644
index 0000000..5115605
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\AttributeNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class AttributeNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 'Powered_Cache_Attribute[Element[*][attribute]]'],
+ [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][attribute $= 'value']]"],
+ [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][namespace|attribute $= 'value']]"],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 10],
+ [new AttributeNode(new ElementNode(null, 'element'), null, 'attribute', 'exists', null), 11],
+ [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), 10],
+ [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
new file mode 100644
index 0000000..ae43a62
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class ClassNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new ClassNode(new ElementNode(), 'class'), 'Class[Element[*].class]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new ClassNode(new ElementNode(), 'class'), 10],
+ [new ClassNode(new ElementNode(null, 'element'), 'class'), 11],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
new file mode 100644
index 0000000..d9b2a38
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\CombinedSelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class CombinedSelectorNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 'CombinedSelector[Element[*] > Element[*]]'],
+ [new CombinedSelectorNode(new ElementNode(), ' ', new ElementNode()), 'CombinedSelector[Element[*] Element[*]]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 0],
+ [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode()), 1],
+ [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode(null, 'element')), 2],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
new file mode 100644
index 0000000..b3ef2b2
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+
+class ElementNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new ElementNode(), 'Element[*]'],
+ [new ElementNode(null, 'element'), 'Element[element]'],
+ [new ElementNode('namespace', 'element'), 'Element[namespace|element]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new ElementNode(), 0],
+ [new ElementNode(null, 'element'), 1],
+ [new ElementNode('namespace', 'element'), 1],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
new file mode 100644
index 0000000..f99a66b
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+class FunctionNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new FunctionNode(new ElementNode(), 'function'), 'Function[Element[*]:function()]'],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+ ]), "Function[Element[*]:function(['value'])]"],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_STRING, 'value1', 0),
+ new Token(Token::TYPE_NUMBER, 'value2', 0),
+ ]), "Function[Element[*]:function(['value1', 'value2'])]"],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new FunctionNode(new ElementNode(), 'function'), 10],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+ ]), 10],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_STRING, 'value1', 0),
+ new Token(Token::TYPE_NUMBER, 'value2', 0),
+ ]), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
new file mode 100644
index 0000000..d43aac1
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\HashNode;
+
+class HashNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new HashNode(new ElementNode(), 'id'), 'Hash[Element[*]#id]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new HashNode(new ElementNode(), 'id'), 100],
+ [new HashNode(new ElementNode(null, 'id'), 'class'), 101],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
new file mode 100644
index 0000000..9aafe8f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NegationNode;
+
+class NegationNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 'Negation[Element[*]:not(Class[Element[*].class])]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
new file mode 100644
index 0000000..cf13881
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\PseudoNode;
+
+class PseudoNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new PseudoNode(new ElementNode(), 'pseudo'), 'Pseudo[Element[*]:pseudo]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new PseudoNode(new ElementNode(), 'pseudo'), 10],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
new file mode 100644
index 0000000..142b104
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+
+class SelectorNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new SelectorNode(new ElementNode()), 'Selector[Element[*]]'],
+ [new SelectorNode(new ElementNode(), 'pseudo'), 'Selector[Element[*]::pseudo]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new SelectorNode(new ElementNode()), 0],
+ [new SelectorNode(new ElementNode(), 'pseudo'), 1],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
new file mode 100644
index 0000000..790f8c1
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\Specificity;
+
+class SpecificityTest extends TestCase
+{
+ /** @dataProvider getValueTestData */
+ public function testValue(Specificity $specificity, $value)
+ {
+ $this->assertEquals($value, $specificity->getValue());
+ }
+
+ /** @dataProvider getValueTestData */
+ public function testPlusValue(Specificity $specificity, $value)
+ {
+ $this->assertEquals($value + 123, $specificity->plus(new Specificity(1, 2, 3))->getValue());
+ }
+
+ public static function getValueTestData()
+ {
+ return [
+ [new Specificity(0, 0, 0), 0],
+ [new Specificity(0, 0, 2), 2],
+ [new Specificity(0, 3, 0), 30],
+ [new Specificity(4, 0, 0), 400],
+ [new Specificity(4, 3, 2), 432],
+ ];
+ }
+
+ /** @dataProvider getCompareTestData */
+ public function testCompareTo(Specificity $a, Specificity $b, $result)
+ {
+ $this->assertEquals($result, $a->compareTo($b));
+ }
+
+ public static function getCompareTestData()
+ {
+ return [
+ [new Specificity(0, 0, 0), new Specificity(0, 0, 0), 0],
+ [new Specificity(0, 0, 1), new Specificity(0, 0, 1), 0],
+ [new Specificity(0, 0, 2), new Specificity(0, 0, 1), 1],
+ [new Specificity(0, 0, 2), new Specificity(0, 0, 3), -1],
+ [new Specificity(0, 4, 0), new Specificity(0, 4, 0), 0],
+ [new Specificity(0, 6, 0), new Specificity(0, 5, 11), 1],
+ [new Specificity(0, 7, 0), new Specificity(0, 8, 0), -1],
+ [new Specificity(9, 0, 0), new Specificity(9, 0, 0), 0],
+ [new Specificity(11, 0, 0), new Specificity(10, 11, 0), 1],
+ [new Specificity(12, 11, 0), new Specificity(13, 0, 0), -1],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
new file mode 100644
index 0000000..b46f2f7
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * @author Jean-François Simon
+ */
+abstract class AbstractHandlerTestCase extends TestCase
+{
+ /** @dataProvider getHandleValueTestData */
+ public function testHandleValue($value, Token $expectedToken, $remainingContent)
+ {
+ $reader = new Reader($value);
+ $stream = new TokenStream();
+
+ $this->assertTrue($this->generateHandler()->handle($reader, $stream));
+ $this->assertEquals($expectedToken, $stream->getNext());
+ $this->assertRemainingContent($reader, $remainingContent);
+ }
+
+ /** @dataProvider getDontHandleValueTestData */
+ public function testDontHandleValue($value)
+ {
+ $reader = new Reader($value);
+ $stream = new TokenStream();
+
+ $this->assertFalse($this->generateHandler()->handle($reader, $stream));
+ $this->assertStreamEmpty($stream);
+ $this->assertRemainingContent($reader, $value);
+ }
+
+ abstract public static function getHandleValueTestData();
+
+ abstract public static function getDontHandleValueTestData();
+
+ abstract protected function generateHandler();
+
+ protected function assertStreamEmpty(TokenStream $stream)
+ {
+ $property = new \ReflectionProperty($stream, 'tokens');
+ $property->setAccessible(true);
+
+ $this->assertEquals([], $property->getValue($stream));
+ }
+
+ protected function assertRemainingContent(Reader $reader, $remainingContent)
+ {
+ if ('' === $remainingContent) {
+ $this->assertEquals(0, $reader->getRemainingLength());
+ $this->assertTrue($reader->isEOF());
+ } else {
+ $this->assertEquals(\strlen($remainingContent), $reader->getRemainingLength());
+ $this->assertEquals(0, $reader->getOffset($remainingContent));
+ }
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
new file mode 100644
index 0000000..459d8de
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\CommentHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+class CommentHandlerTest extends AbstractHandlerTestCase
+{
+ /** @dataProvider getHandleValueTestData */
+ public function testHandleValue($value, Token $unusedArgument, $remainingContent)
+ {
+ $reader = new Reader($value);
+ $stream = new TokenStream();
+
+ $this->assertTrue($this->generateHandler()->handle($reader, $stream));
+ // comments are ignored (not pushed as token in stream)
+ $this->assertStreamEmpty($stream);
+ $this->assertRemainingContent($reader, $remainingContent);
+ }
+
+ public static function getHandleValueTestData()
+ {
+ return [
+ // 2nd argument only exists for inherited method compatibility
+ ['/* comment */', new Token(null, null, null), ''],
+ ['/* comment */foo', new Token(null, null, null), 'foo'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['+'],
+ [' '],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ return new CommentHandler();
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
new file mode 100644
index 0000000..a96c861
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\HashHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class HashHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['#id', new Token(Token::TYPE_HASH, 'id', 0), ''],
+ ['#123', new Token(Token::TYPE_HASH, '123', 0), ''],
+
+ ['#id.class', new Token(Token::TYPE_HASH, 'id', 0), '.class'],
+ ['#id element', new Token(Token::TYPE_HASH, 'id', 0), ' element'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['id'],
+ ['123'],
+ ['<'],
+ ['<'],
+ ['#'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new HashHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
new file mode 100644
index 0000000..1cb9ffe
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\IdentifierHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class IdentifierHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['foo', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ''],
+ ['foo|bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '|bar'],
+ ['foo.class', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '.class'],
+ ['foo[attr]', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '[attr]'],
+ ['foo bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ' bar'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['+'],
+ [' '],
+ ['*|foo'],
+ ['/* comment */'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new IdentifierHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
new file mode 100644
index 0000000..e40b86f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\NumberHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class NumberHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['12', new Token(Token::TYPE_NUMBER, '12', 0), ''],
+ ['12.34', new Token(Token::TYPE_NUMBER, '12.34', 0), ''],
+ ['+12.34', new Token(Token::TYPE_NUMBER, '+12.34', 0), ''],
+ ['-12.34', new Token(Token::TYPE_NUMBER, '-12.34', 0), ''],
+
+ ['12 arg', new Token(Token::TYPE_NUMBER, '12', 0), ' arg'],
+ ['12]', new Token(Token::TYPE_NUMBER, '12', 0), ']'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['hello'],
+ ['>'],
+ ['+'],
+ [' '],
+ ['/* comment */'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new NumberHandler($patterns);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
new file mode 100644
index 0000000..d00233c
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\StringHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class StringHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ ['"hello"', new Token(Token::TYPE_STRING, 'hello', 1), ''],
+ ['"1"', new Token(Token::TYPE_STRING, '1', 1), ''],
+ ['" "', new Token(Token::TYPE_STRING, ' ', 1), ''],
+ ['""', new Token(Token::TYPE_STRING, '', 1), ''],
+ ["'hello'", new Token(Token::TYPE_STRING, 'hello', 1), ''],
+
+ ["'foo'bar", new Token(Token::TYPE_STRING, 'foo', 1), 'bar'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['hello'],
+ ['>'],
+ ['1'],
+ [' '],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new StringHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
new file mode 100644
index 0000000..1cd3e9d
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\WhitespaceHandler;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+class WhitespaceHandlerTest extends AbstractHandlerTestCase
+{
+ public static function getHandleValueTestData()
+ {
+ return [
+ [' ', new Token(Token::TYPE_WHITESPACE, ' ', 0), ''],
+ ["\n", new Token(Token::TYPE_WHITESPACE, "\n", 0), ''],
+ ["\t", new Token(Token::TYPE_WHITESPACE, "\t", 0), ''],
+
+ [' foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), 'foo'],
+ [' .foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), '.foo'],
+ ];
+ }
+
+ public static function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['1'],
+ ['a'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ return new WhitespaceHandler();
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
new file mode 100644
index 0000000..a9ef9d6
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
@@ -0,0 +1,263 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+
+class ParserTest extends TestCase
+{
+ /** @dataProvider getParserTestData */
+ public function testParser($source, $representation)
+ {
+ $parser = new Parser();
+
+ $this->assertEquals($representation, array_map(function (SelectorNode $node) {
+ return (string) $node->getTree();
+ }, $parser->parse($source)));
+ }
+
+ /** @dataProvider getParserExceptionTestData */
+ public function testParserException($source, $message)
+ {
+ $parser = new Parser();
+
+ try {
+ $parser->parse($source);
+ $this->fail('Parser should throw a SyntaxErrorException.');
+ } catch (SyntaxErrorException $e) {
+ $this->assertEquals($message, $e->getMessage());
+ }
+ }
+
+ /** @dataProvider getPseudoElementsTestData */
+ public function testPseudoElements($source, $element, $pseudo)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($element, (string) $selector->getTree());
+ $this->assertEquals($pseudo, (string) $selector->getPseudoElement());
+ }
+
+ /** @dataProvider getSpecificityTestData */
+ public function testSpecificity($source, $value)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($value, $selector->getSpecificity()->getValue());
+ }
+
+ /** @dataProvider getParseSeriesTestData */
+ public function testParseSeries($series, $a, $b)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
+ $this->assertCount(1, $selectors);
+
+ /** @var FunctionNode $function */
+ $function = $selectors[0]->getTree();
+ $this->assertEquals([$a, $b], Parser::parseSeries($function->getArguments()));
+ }
+
+ /** @dataProvider getParseSeriesExceptionTestData */
+ public function testParseSeriesException($series)
+ {
+ $parser = new Parser();
+ $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
+ $this->assertCount(1, $selectors);
+
+ /** @var FunctionNode $function */
+ $function = $selectors[0]->getTree();
+ $this->expectException(SyntaxErrorException::class);
+ Parser::parseSeries($function->getArguments());
+ }
+
+ public static function getParserTestData()
+ {
+ return [
+ ['*', ['Element[*]']],
+ ['*|*', ['Element[*]']],
+ ['*|foo', ['Element[foo]']],
+ ['foo|*', ['Element[foo|*]']],
+ ['foo|bar', ['Element[foo|bar]']],
+ ['#foo#bar', ['Hash[Hash[Element[*]#foo]#bar]']],
+ ['div>.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div> .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div >.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div > .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ["div \n> \t \t .foo", ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['div, td.foo, div.bar span', ['Element[div]', 'Class[Element[td].foo]', 'CombinedSelector[Class[Element[div].bar] Element[span]]']],
+ ['div > p', ['CombinedSelector[Element[div] > Element[p]]']],
+ ['td:first', ['Pseudo[Element[td]:first]']],
+ ['td :first', ['CombinedSelector[Element[td] Pseudo[Element[*]:first]]']],
+ ['a[name]', ['Powered_Cache_Attribute[Element[a][name]]']],
+ ["a[ name\t]", ['Powered_Cache_Attribute[Element[a][name]]']],
+ ['a [name]', ['CombinedSelector[Element[a] Powered_Cache_Attribute[Element[*][name]]]']],
+ ['[name="foo"]', ["Powered_Cache_Attribute[Element[*][name = 'foo']]"]],
+ ["[name='foo[1]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[1]']]"]],
+ ["[name='foo[0][bar]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[0][bar]']]"]],
+ ['a[rel="include"]', ["Attribute[Element[a][rel = 'include']]"]],
+ ['a[rel = include]', ["Attribute[Element[a][rel = 'include']]"]],
+ ["a[hreflang |= 'en']", ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
+ ['a[hreflang|=en]', ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
+ ['div:nth-child(10)', ["Function[Element[div]:nth-child(['10'])]"]],
+ [':nth-child(2n+2)', ["Function[Element[*]:nth-child(['2', 'n', '+2'])]"]],
+ ['div:nth-of-type(10)', ["Function[Element[div]:nth-of-type(['10'])]"]],
+ ['div div:nth-of-type(10) .aclass', ["CombinedSelector[CombinedSelector[Element[div] Function[Element[div]:nth-of-type(['10'])]] Class[Element[*].aclass]]"]],
+ ['label:only', ['Pseudo[Element[label]:only]']],
+ ['a:lang(fr)', ["Function[Element[a]:lang(['fr'])]"]],
+ ['div:contains("foo")', ["Function[Element[div]:contains(['foo'])]"]],
+ ['div#foobar', ['Hash[Element[div]#foobar]']],
+ ['div:not(div.foo)', ['Negation[Element[div]:not(Class[Element[div].foo])]']],
+ ['td ~ th', ['CombinedSelector[Element[td] ~ Element[th]]']],
+ ['.foo[data-bar][data-baz=0]', ["Powered_Cache_Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]"]],
+ ['div#foo\.bar', ['Hash[Element[div]#foo.bar]']],
+ ['div.w-1\/3', ['Class[Element[div].w-1/3]']],
+ ['#test\:colon', ['Hash[Element[*]#test:colon]']],
+ [".a\xc1b", ["Class[Element[*].a\xc1b]"]],
+ // unicode escape: \22 == "
+ ['*[aval="\'\22\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"\'\']]']],
+ ['*[aval="\'\22 2\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"2\'\']]']],
+ // unicode escape: \20 == (space)
+ ['*[aval="\'\20 \'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
+ ["*[aval=\"'\\20\r\n '\"]", ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
+ ];
+ }
+
+ public static function getParserExceptionTestData()
+ {
+ return [
+ ['attributes(href)/html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
+ ['attributes(href)', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
+ ['html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '/', 4))->getMessage()],
+ [' ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 1))->getMessage()],
+ ['div, ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 5))->getMessage()],
+ [' , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 1))->getMessage()],
+ ['p, , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 3))->getMessage()],
+ ['div > ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 6))->getMessage()],
+ [' > div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '>', 2))->getMessage()],
+ ['foo|#bar', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_HASH, 'bar', 4))->getMessage()],
+ ['#.foo', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '#', 0))->getMessage()],
+ ['.#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
+ [':#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
+ ['[*]', SyntaxErrorException::unexpectedToken('"|"', new Token(Token::TYPE_DELIMITER, ']', 2))->getMessage()],
+ ['[foo|]', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_DELIMITER, ']', 5))->getMessage()],
+ ['[#]', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_DELIMITER, '#', 1))->getMessage()],
+ ['[foo=#]', SyntaxErrorException::unexpectedToken('string or identifier', new Token(Token::TYPE_DELIMITER, '#', 5))->getMessage()],
+ [':nth-child()', SyntaxErrorException::unexpectedToken('at least one argument', new Token(Token::TYPE_DELIMITER, ')', 11))->getMessage()],
+ ['[href]a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_IDENTIFIER, 'a', 6))->getMessage()],
+ ['[rel:stylesheet]', SyntaxErrorException::unexpectedToken('operator', new Token(Token::TYPE_DELIMITER, ':', 4))->getMessage()],
+ ['[rel=stylesheet', SyntaxErrorException::unexpectedToken('"]"', new Token(Token::TYPE_FILE_END, '', 15))->getMessage()],
+ [':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()],
+ [':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
+ ['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
+ ];
+ }
+
+ public static function getPseudoElementsTestData()
+ {
+ return [
+ ['foo', 'Element[foo]', ''],
+ ['*', 'Element[*]', ''],
+ [':empty', 'Pseudo[Element[*]:empty]', ''],
+ [':BEfore', 'Element[*]', 'before'],
+ [':aftER', 'Element[*]', 'after'],
+ [':First-Line', 'Element[*]', 'first-line'],
+ [':First-Letter', 'Element[*]', 'first-letter'],
+ ['::befoRE', 'Element[*]', 'before'],
+ ['::AFter', 'Element[*]', 'after'],
+ ['::firsT-linE', 'Element[*]', 'first-line'],
+ ['::firsT-letteR', 'Element[*]', 'first-letter'],
+ ['::Selection', 'Element[*]', 'selection'],
+ ['foo:after', 'Element[foo]', 'after'],
+ ['foo::selection', 'Element[foo]', 'selection'],
+ ['lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Powered_Cache_Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'],
+ ['video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'],
+ ];
+ }
+
+ public static function getSpecificityTestData()
+ {
+ return [
+ ['*', 0],
+ [' foo', 1],
+ [':empty ', 10],
+ [':before', 1],
+ ['*:before', 1],
+ [':nth-child(2)', 10],
+ ['.bar', 10],
+ ['[baz]', 10],
+ ['[baz="4"]', 10],
+ ['[baz^="4"]', 10],
+ ['#lipsum', 100],
+ [':not(*)', 0],
+ [':not(foo)', 1],
+ [':not(.foo)', 10],
+ [':not([foo])', 10],
+ [':not(:empty)', 10],
+ [':not(#foo)', 100],
+ ['foo:empty', 11],
+ ['foo:before', 2],
+ ['foo::before', 2],
+ ['foo:empty::before', 12],
+ ['#lorem + foo#ipsum:first-child > bar:first-line', 213],
+ ];
+ }
+
+ public static function getParseSeriesTestData()
+ {
+ return [
+ ['1n+3', 1, 3],
+ ['1n +3', 1, 3],
+ ['1n + 3', 1, 3],
+ ['1n+ 3', 1, 3],
+ ['1n-3', 1, -3],
+ ['1n -3', 1, -3],
+ ['1n - 3', 1, -3],
+ ['1n- 3', 1, -3],
+ ['n-5', 1, -5],
+ ['odd', 2, 1],
+ ['even', 2, 0],
+ ['3n', 3, 0],
+ ['n', 1, 0],
+ ['+n', 1, 0],
+ ['-n', -1, 0],
+ ['5', 0, 5],
+ ];
+ }
+
+ public static function getParseSeriesExceptionTestData()
+ {
+ return [
+ ['foo'],
+ ['n+'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
new file mode 100644
index 0000000..b160113
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
@@ -0,0 +1,102 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
+
+class ReaderTest extends TestCase
+{
+ public function testIsEOF()
+ {
+ $reader = new Reader('');
+ $this->assertTrue($reader->isEOF());
+
+ $reader = new Reader('hello');
+ $this->assertFalse($reader->isEOF());
+
+ $this->assignPosition($reader, 2);
+ $this->assertFalse($reader->isEOF());
+
+ $this->assignPosition($reader, 5);
+ $this->assertTrue($reader->isEOF());
+ }
+
+ public function testGetRemainingLength()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals(5, $reader->getRemainingLength());
+
+ $this->assignPosition($reader, 2);
+ $this->assertEquals(3, $reader->getRemainingLength());
+
+ $this->assignPosition($reader, 5);
+ $this->assertEquals(0, $reader->getRemainingLength());
+ }
+
+ public function testGetSubstring()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals('he', $reader->getSubstring(2));
+ $this->assertEquals('el', $reader->getSubstring(2, 1));
+
+ $this->assignPosition($reader, 2);
+ $this->assertEquals('ll', $reader->getSubstring(2));
+ $this->assertEquals('lo', $reader->getSubstring(2, 1));
+ }
+
+ public function testGetOffset()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals(2, $reader->getOffset('ll'));
+ $this->assertFalse($reader->getOffset('w'));
+
+ $this->assignPosition($reader, 2);
+ $this->assertEquals(0, $reader->getOffset('ll'));
+ $this->assertFalse($reader->getOffset('he'));
+ }
+
+ public function testFindPattern()
+ {
+ $reader = new Reader('hello');
+
+ $this->assertFalse($reader->findPattern('/world/'));
+ $this->assertEquals(['hello', 'h'], $reader->findPattern('/^([a-z]).*/'));
+
+ $this->assignPosition($reader, 2);
+ $this->assertFalse($reader->findPattern('/^h.*/'));
+ $this->assertEquals(['llo'], $reader->findPattern('/^llo$/'));
+ }
+
+ public function testMoveForward()
+ {
+ $reader = new Reader('hello');
+ $this->assertEquals(0, $reader->getPosition());
+
+ $reader->moveForward(2);
+ $this->assertEquals(2, $reader->getPosition());
+ }
+
+ public function testToEnd()
+ {
+ $reader = new Reader('hello');
+ $reader->moveToEnd();
+ $this->assertTrue($reader->isEOF());
+ }
+
+ private function assignPosition(Reader $reader, int $value)
+ {
+ $position = new \ReflectionProperty($reader, 'position');
+ $position->setAccessible(true);
+ $position->setValue($reader, $value);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
new file mode 100644
index 0000000..188d29f
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class ClassParserTest extends TestCase
+{
+ /** @dataProvider getParseTestData */
+ public function testParse($source, $representation)
+ {
+ $parser = new ClassParser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($representation, (string) $selector->getTree());
+ }
+
+ public static function getParseTestData()
+ {
+ return [
+ ['.testclass', 'Class[Element[*].testclass]'],
+ ['testel.testclass', 'Class[Element[testel].testclass]'],
+ ['testns|.testclass', 'Class[Element[testns|*].testclass]'],
+ ['testns|*.testclass', 'Class[Element[testns|*].testclass]'],
+ ['testns|testel.testclass', 'Class[Element[testns|testel].testclass]'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
new file mode 100644
index 0000000..58540ea
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class ElementParserTest extends TestCase
+{
+ /** @dataProvider getParseTestData */
+ public function testParse($source, $representation)
+ {
+ $parser = new ElementParser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($representation, (string) $selector->getTree());
+ }
+
+ public static function getParseTestData()
+ {
+ return [
+ ['*', 'Element[*]'],
+ ['testel', 'Element[testel]'],
+ ['testns|*', 'Element[testns|*]'],
+ ['testns|testel', 'Element[testns|testel]'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
new file mode 100644
index 0000000..b6540ff
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class EmptyStringParserTest extends TestCase
+{
+ public function testParse()
+ {
+ $parser = new EmptyStringParser();
+ $selectors = $parser->parse('');
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals('Element[*]', (string) $selector->getTree());
+
+ $selectors = $parser->parse('this will produce an empty array');
+ $this->assertCount(0, $selectors);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
new file mode 100644
index 0000000..9a92ca4
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
+
+/**
+ * @author Jean-François Simon
+ */
+class HashParserTest extends TestCase
+{
+ /** @dataProvider getParseTestData */
+ public function testParse($source, $representation)
+ {
+ $parser = new HashParser();
+ $selectors = $parser->parse($source);
+ $this->assertCount(1, $selectors);
+
+ /** @var SelectorNode $selector */
+ $selector = $selectors[0];
+ $this->assertEquals($representation, (string) $selector->getTree());
+ }
+
+ public static function getParseTestData()
+ {
+ return [
+ ['#testid', 'Hash[Element[*]#testid]'],
+ ['testel#testid', 'Hash[Element[testel]#testid]'],
+ ['testns|#testid', 'Hash[Element[testns|*]#testid]'],
+ ['testns|*#testid', 'Hash[Element[testns|*]#testid]'],
+ ['testns|testel#testid', 'Hash[Element[testns|testel]#testid]'],
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
new file mode 100644
index 0000000..ec7f7f5
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
+
+class TokenStreamTest extends TestCase
+{
+ public function testGetNext()
+ {
+ $stream = new TokenStream();
+ $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
+
+ $this->assertSame($t1, $stream->getNext());
+ $this->assertSame($t2, $stream->getNext());
+ $this->assertSame($t3, $stream->getNext());
+ }
+
+ public function testGetPeek()
+ {
+ $stream = new TokenStream();
+ $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
+
+ $this->assertSame($t1, $stream->getPeek());
+ $this->assertSame($t1, $stream->getNext());
+ $this->assertSame($t2, $stream->getPeek());
+ $this->assertSame($t2, $stream->getPeek());
+ $this->assertSame($t2, $stream->getNext());
+ }
+
+ public function testGetNextIdentifier()
+ {
+ $stream = new TokenStream();
+ $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+
+ $this->assertEquals('h1', $stream->getNextIdentifier());
+ }
+
+ public function testFailToGetNextIdentifier()
+ {
+ $this->expectException(SyntaxErrorException::class);
+
+ $stream = new TokenStream();
+ $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->getNextIdentifier();
+ }
+
+ public function testGetNextIdentifierOrStar()
+ {
+ $stream = new TokenStream();
+
+ $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $this->assertEquals('h1', $stream->getNextIdentifierOrStar());
+
+ $stream->push(new Token(Token::TYPE_DELIMITER, '*', 0));
+ $this->assertNull($stream->getNextIdentifierOrStar());
+ }
+
+ public function testFailToGetNextIdentifierOrStar()
+ {
+ $this->expectException(SyntaxErrorException::class);
+
+ $stream = new TokenStream();
+ $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
+ $stream->getNextIdentifierOrStar();
+ }
+
+ public function testSkipWhitespace()
+ {
+ $stream = new TokenStream();
+ $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+ $stream->push($t2 = new Token(Token::TYPE_WHITESPACE, ' ', 2));
+ $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'h1', 3));
+
+ $stream->skipWhitespace();
+ $this->assertSame($t1, $stream->getNext());
+
+ $stream->skipWhitespace();
+ $this->assertSame($t3, $stream->getNext());
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
new file mode 100644
index 0000000..1147bf3
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
new file mode 100644
index 0000000..14f8dbe
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
@@ -0,0 +1,11 @@
+
+ a
+ b
+ c
+ d
+ e
+ f
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
new file mode 100644
index 0000000..15d1ad3
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
As You Like It
+
+ by William Shakespeare
+
+
+
ACT I, SCENE III. A room in the palace.
+
+
Enter CELIA and ROSALIND
+
+
CELIA
+
+
Why, cousin! why, Rosalind! Cupid have mercy! not a word?
+
+
ROSALIND
+
+
Not one to throw at a dog.
+
+
CELIA
+
+
No, thy words are too precious to be cast away upon
+
curs; throw some of them at me; come, lame me with reasons.
+
+
ROSALIND
+
CELIA
+
+
But is all this for your father?
+
+
+
Then there were two cousins laid up; when the one
+
should be lamed with reasons and the other mad
+
without any.
+
+
ROSALIND
+
+
No, some of it is for my child's father. O, how
+
full of briers is this working-day world!
+
+
CELIA
+
+
They are but burs, cousin, thrown upon thee in
+
holiday foolery: if we walk not in the trodden
+
paths our very petticoats will catch them.
+
+
ROSALIND
+
+
I could shake them off my coat: these burs are in my heart.
+
+
CELIA
+
+
ROSALIND
+
+
I would try, if I could cry 'hem' and have him.
+
+
CELIA
+
+
Come, come, wrestle with thy affections.
+
+
ROSALIND
+
+
O, they take the part of a better wrestler than myself!
+
+
CELIA
+
+
O, a good wish upon you! you will try in time, in
+
despite of a fall. But, turning these jests out of
+
service, let us talk in good earnest: is it
+
possible, on such a sudden, you should fall into so
+
strong a liking with old Sir Rowland's youngest son?
+
+
ROSALIND
+
+
The duke my father loved his father dearly.
+
+
CELIA
+
+
Doth it therefore ensue that you should love his son
+
dearly? By this kind of chase, I should hate him,
+
for my father hated his father dearly; yet I hate
+
not Orlando.
+
+
ROSALIND
+
+
No, faith, hate him not, for my sake.
+
+
CELIA
+
+
Why should I not? doth he not deserve well?
+
+
ROSALIND
+
+
Let me love him for that, and do you love him
+
because I do. Look, here comes the duke.
+
+
CELIA
+
+
With his eyes full of anger.
+
Enter DUKE FREDERICK, with Lords
+
+
DUKE FREDERICK
+
+
Mistress, dispatch you with your safest haste
+
And get you from our court.
+
+
ROSALIND
+
+
DUKE FREDERICK
+
+
You, cousin
+
Within these ten days if that thou be'st found
+
So near our public court as twenty miles,
+
Thou diest for it.
+
+
ROSALIND
+
+
I do beseech your grace,
+
Let me the knowledge of my fault bear with me:
+
If with myself I hold intelligence
+
Or have acquaintance with mine own desires,
+
If that I do not dream or be not frantic,--
+
As I do trust I am not--then, dear uncle,
+
Never so much as in a thought unborn
+
Did I offend your highness.
+
+
DUKE FREDERICK
+
+
Thus do all traitors:
+
If their purgation did consist in words,
+
They are as innocent as grace itself:
+
Let it suffice thee that I trust thee not.
+
+
ROSALIND
+
+
Yet your mistrust cannot make me a traitor:
+
Tell me whereon the likelihood depends.
+
+
DUKE FREDERICK
+
+
Thou art thy father's daughter; there's enough.
+
+
ROSALIND
+
+
So was I when your highness took his dukedom;
+
So was I when your highness banish'd him:
+
Treason is not inherited, my lord;
+
Or, if we did derive it from our friends,
+
What's that to me? my father was no traitor:
+
Then, good my liege, mistake me not so much
+
To think my poverty is treacherous.
+
+
CELIA
+
+
Dear sovereign, hear me speak.
+
+
DUKE FREDERICK
+
+
Ay, Celia; we stay'd her for your sake,
+
Else had she with her father ranged along.
+
+
CELIA
+
+
I did not then entreat to have her stay;
+
It was your pleasure and your own remorse:
+
I was too young that time to value her;
+
But now I know her: if she be a traitor,
+
Why so am I; we still have slept together,
+
Rose at an instant, learn'd, play'd, eat together,
+
And wheresoever we went, like Juno's swans,
+
Still we went coupled and inseparable.
+
+
DUKE FREDERICK
+
+
She is too subtle for thee; and her smoothness,
+
Her very silence and her patience
+
Speak to the people, and they pity her.
+
Thou art a fool: she robs thee of thy name;
+
And thou wilt show more bright and seem more virtuous
+
When she is gone. Then open not thy lips:
+
Firm and irrevocable is my doom
+
Which I have pass'd upon her; she is banish'd.
+
+
CELIA
+
+
Pronounce that sentence then on me, my liege:
+
I cannot live out of her company.
+
+
DUKE FREDERICK
+
+
You are a fool. You, niece, provide yourself:
+
If you outstay the time, upon mine honour,
+
And in the greatness of my word, you die.
+
Exeunt DUKE FREDERICK and Lords
+
+
CELIA
+
+
O my poor Rosalind, whither wilt thou go?
+
Wilt thou change fathers? I will give thee mine.
+
I charge thee, be not thou more grieved than I am.
+
+
ROSALIND
+
+
CELIA
+
+
Thou hast not, cousin;
+
Prithee be cheerful: know'st thou not, the duke
+
Hath banish'd me, his daughter?
+
+
ROSALIND
+
+
CELIA
+
+
No, hath not? Rosalind lacks then the love
+
Which teacheth thee that thou and I am one:
+
Shall we be sunder'd? shall we part, sweet girl?
+
No: let my father seek another heir.
+
Therefore devise with me how we may fly,
+
Whither to go and what to bear with us;
+
And do not seek to take your change upon you,
+
To bear your griefs yourself and leave me out;
+
For, by this heaven, now at our sorrows pale,
+
Say what thou canst, I'll go along with thee.
+
+
ROSALIND
+
+
Why, whither shall we go?
+
+
CELIA
+
+
To seek my uncle in the forest of Arden.
+
+
ROSALIND
+
+
Alas, what danger will it be to us,
+
Maids as we are, to travel forth so far!
+
Beauty provoketh thieves sooner than gold.
+
+
CELIA
+
+
I'll put myself in poor and mean attire
+
And with a kind of umber smirch my face;
+
The like do you: so shall we pass along
+
And never stir assailants.
+
+
ROSALIND
+
+
Were it not better,
+
Because that I am more than common tall,
+
That I did suit me all points like a man?
+
A gallant curtle-axe upon my thigh,
+
A boar-spear in my hand; and--in my heart
+
Lie there what hidden woman's fear there will--
+
We'll have a swashing and a martial outside,
+
As many other mannish cowards have
+
That do outface it with their semblances.
+
+
CELIA
+
+
What shall I call thee when thou art a man?
+
+
ROSALIND
+
+
I'll have no worse a name than Jove's own page;
+
And therefore look you call me Ganymede.
+
But what will you be call'd?
+
+
CELIA
+
+
Something that hath a reference to my state
+
No longer Celia, but Aliena.
+
+
ROSALIND
+
+
But, cousin, what if we assay'd to steal
+
The clownish fool out of your father's court?
+
Would he not be a comfort to our travel?
+
+
CELIA
+
+
He'll go along o'er the wide world with me;
+
Leave me alone to woo him. Let's away,
+
And get our jewels and our wealth together,
+
Devise the fittest time and safest way
+
To hide us from pursuit that will be made
+
After my flight. Now go we in content
+
To liberty and not to banishment.
+
Exeunt
+
+
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
new file mode 100644
index 0000000..fad6105
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
@@ -0,0 +1,416 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\XPath;
+
+use PHPUnit\Framework\TestCase;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+class TranslatorTest extends TestCase
+{
+ /** @dataProvider getXpathLiteralTestData */
+ public function testXpathLiteral($value, $literal)
+ {
+ $this->assertEquals($literal, Translator::getXpathLiteral($value));
+ }
+
+ /** @dataProvider getCssToXPathTestData */
+ public function testCssToXPath($css, $xpath)
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $this->assertEquals($xpath, $translator->cssToXPath($css, ''));
+ }
+
+ public function testCssToXPathPseudoElement()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $translator->cssToXPath('e::first-line');
+ }
+
+ public function testGetExtensionNotExistsExtension()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $translator->getExtension('fake');
+ }
+
+ public function testAddCombinationNotExistsExtension()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $parser = new Parser();
+ $xpath = $parser->parse('*')[0];
+ $combinedXpath = $parser->parse('*')[0];
+ $translator->addCombination('fake', $xpath, $combinedXpath);
+ }
+
+ public function testAddFunctionNotExistsFunction()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $function = new FunctionNode(new ElementNode(), 'fake');
+ $translator->addFunction($xpath, $function);
+ }
+
+ public function testAddPseudoClassNotExistsClass()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $translator->addPseudoClass($xpath, 'fake');
+ }
+
+ public function testAddAttributeMatchingClassNotExistsClass()
+ {
+ $this->expectException(ExpressionErrorException::class);
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $translator->addAttributeMatching($xpath, '', '', '');
+ }
+
+ /** @dataProvider getXmlLangTestData */
+ public function testXmlLang($css, array $elementsId)
+ {
+ $translator = new Translator();
+ $document = new \SimpleXMLElement(file_get_contents(__DIR__.'/Fixtures/lang.xml'));
+ $elements = $document->xpath($translator->cssToXPath($css));
+ $this->assertCount(\count($elementsId), $elements);
+ foreach ($elements as $element) {
+ $this->assertContains((string) $element->attributes()->id, $elementsId);
+ }
+ }
+
+ /** @dataProvider getHtmlIdsTestData */
+ public function testHtmlIds($css, array $elementsId)
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $document = new \DOMDocument();
+ $document->strictErrorChecking = false;
+ $internalErrors = libxml_use_internal_errors(true);
+ $document->loadHTMLFile(__DIR__.'/Fixtures/ids.html');
+ $document = simplexml_import_dom($document);
+ $elements = $document->xpath($translator->cssToXPath($css));
+ $this->assertCount(\count($elementsId), $elements);
+ foreach ($elements as $element) {
+ if (null !== $element->attributes()->id) {
+ $this->assertContains((string) $element->attributes()->id, $elementsId);
+ }
+ }
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+ }
+
+ /** @dataProvider getHtmlShakespearTestData */
+ public function testHtmlShakespear($css, $count)
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $document = new \DOMDocument();
+ $document->strictErrorChecking = false;
+ $document->loadHTMLFile(__DIR__.'/Fixtures/shakespear.html');
+ $document = simplexml_import_dom($document);
+ $bodies = $document->xpath('//body');
+ $elements = $bodies[0]->xpath($translator->cssToXPath($css));
+ $this->assertCount($count, $elements);
+ }
+
+ public function testOnlyOfTypeFindsSingleChildrenOfGivenType()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $document = new \DOMDocument();
+ $document->loadHTML(<<<'HTML'
+
+
+
+ A
+
+
+ B
+ C
+
+
+
+HTML
+ );
+
+ $xpath = new \DOMXPath($document);
+ $nodeList = $xpath->query($translator->cssToXPath('span:only-of-type'));
+
+ $this->assertSame(1, $nodeList->length);
+ $this->assertSame('A', $nodeList->item(0)->textContent);
+ }
+
+ public static function getXpathLiteralTestData()
+ {
+ return [
+ ['foo', "'foo'"],
+ ["foo's bar", '"foo\'s bar"'],
+ ["foo's \"middle\" bar", 'concat(\'foo\', "\'", \'s "middle" bar\')'],
+ ["foo's 'middle' \"bar\"", 'concat(\'foo\', "\'", \'s \', "\'", \'middle\', "\'", \' "bar"\')'],
+ ];
+ }
+
+ public static function getCssToXPathTestData()
+ {
+ return [
+ ['*', '*'],
+ ['e', 'e'],
+ ['*|e', 'e'],
+ ['e|f', 'e:f'],
+ ['e[foo]', 'e[@foo]'],
+ ['e[foo|bar]', 'e[@foo:bar]'],
+ ['e[foo="bar"]', "e[@foo = 'bar']"],
+ ['e[foo~="bar"]', "e[@foo and contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]"],
+ ['e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"],
+ ['e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"],
+ ['e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"],
+ ['e[foo!="bar"]', "e[not(@foo) or @foo != 'bar']"],
+ ['e[foo!="bar"][foo!="baz"]', "e[(not(@foo) or @foo != 'bar') and (not(@foo) or @foo != 'baz')]"],
+ ['e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"],
+ ['e:nth-child(1)', "*/*[(name() = 'e') and (position() = 1)]"],
+ ['e:nth-last-child(1)', "*/*[(name() = 'e') and (position() = last() - 0)]"],
+ ['e:nth-last-child(2n+2)', "*/*[(name() = 'e') and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"],
+ ['e:nth-of-type(1)', '*/e[position() = 1]'],
+ ['e:nth-last-of-type(1)', '*/e[position() = last() - 0]'],
+ ['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 ')]"],
+ ['e:first-child', "*/*[(name() = 'e') and (position() = 1)]"],
+ ['e:last-child', "*/*[(name() = 'e') and (position() = last())]"],
+ ['e:first-of-type', '*/e[position() = 1]'],
+ ['e:last-of-type', '*/e[position() = last()]'],
+ ['e:only-child', "*/*[(name() = 'e') and (last() = 1)]"],
+ ['e:only-of-type', 'e[count(preceding-sibling::e)=0 and count(following-sibling::e)=0]'],
+ ['e:empty', 'e[not(*) and not(string-length())]'],
+ ['e:EmPTY', 'e[not(*) and not(string-length())]'],
+ ['e:root', 'e[not(parent::*)]'],
+ ['e:hover', 'e[0]'],
+ ['e:contains("foo")', "e[contains(string(.), 'foo')]"],
+ ['e:ConTains(foo)', "e[contains(string(.), 'foo')]"],
+ ['e.warning', "e[@class and contains(concat(' ', normalize-space(@class), ' '), ' warning ')]"],
+ ['e#myid', "e[@id = 'myid']"],
+ ['e:not(:nth-child(odd))', 'e[not(position() - 1 >= 0 and (position() - 1) mod 2 = 0)]'],
+ ['e:nOT(*)', 'e[0]'],
+ ['e f', 'e/descendant-or-self::*/f'],
+ ['e > f', 'e/f'],
+ ['e + f', "e/following-sibling::*[(name() = 'f') and (position() = 1)]"],
+ ['e ~ f', 'e/following-sibling::f'],
+ ['div#container p', "div[@id = 'container']/descendant-or-self::*/p"],
+ ];
+ }
+
+ public static function getXmlLangTestData()
+ {
+ return [
+ [':lang("EN")', ['first', 'second', 'third', 'fourth']],
+ [':lang("en-us")', ['second', 'fourth']],
+ [':lang(en-nz)', ['third']],
+ [':lang(fr)', ['fifth']],
+ [':lang(ru)', ['sixth']],
+ [":lang('ZH')", ['eighth']],
+ [':lang(de) :lang(zh)', ['eighth']],
+ [':lang(en), :lang(zh)', ['first', 'second', 'third', 'fourth', 'eighth']],
+ [':lang(es)', []],
+ ];
+ }
+
+ public static function getHtmlIdsTestData()
+ {
+ return [
+ ['div', ['outer-div', 'li-div', 'foobar-div']],
+ ['DIV', ['outer-div', 'li-div', 'foobar-div']], // case-insensitive in HTML
+ ['div div', ['li-div']],
+ ['div, div div', ['outer-div', 'li-div', 'foobar-div']],
+ ['a[name]', ['name-anchor']],
+ ['a[NAme]', ['name-anchor']], // case-insensitive in HTML:
+ ['a[rel]', ['tag-anchor', 'nofollow-anchor']],
+ ['a[rel="tag"]', ['tag-anchor']],
+ ['a[href*="localhost"]', ['tag-anchor']],
+ ['a[href*=""]', []],
+ ['a[href^="http"]', ['tag-anchor', 'nofollow-anchor']],
+ ['a[href^="http:"]', ['tag-anchor']],
+ ['a[href^=""]', []],
+ ['a[href$="org"]', ['nofollow-anchor']],
+ ['a[href$=""]', []],
+ ['div[foobar~="bc"]', ['foobar-div']],
+ ['div[foobar~="cde"]', ['foobar-div']],
+ ['[foobar~="ab bc"]', ['foobar-div']],
+ ['[foobar~=""]', []],
+ ['[foobar~=" \t"]', []],
+ ['div[foobar~="cd"]', []],
+ ['*[lang|="En"]', ['second-li']],
+ ['[lang|="En-us"]', ['second-li']],
+ // Powered_Cache_Attribute values are case sensitive
+ ['*[lang|="en"]', []],
+ ['[lang|="en-US"]', []],
+ ['*[lang|="e"]', []],
+ // ... :lang() is not.
+ [':lang("EN")', ['second-li', 'li-div']],
+ ['*:lang(en-US)', ['second-li', 'li-div']],
+ [':lang("e")', []],
+ ['li:nth-child(3)', ['third-li']],
+ ['li:nth-child(10)', []],
+ ['li:nth-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(2n+0)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(+2n+1)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
+ ['li:nth-child(odd)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
+ ['li:nth-child(2n+4)', ['fourth-li', 'sixth-li']],
+ ['li:nth-child(3n+1)', ['first-li', 'fourth-li', 'seventh-li']],
+ ['li:nth-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n+3)', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(-n)', []],
+ ['li:nth-child(-n-1)', []],
+ ['li:nth-child(-n+1)', ['first-li']],
+ ['li:nth-child(-n+3)', ['first-li', 'second-li', 'third-li']],
+ ['li:nth-last-child(0)', []],
+ ['li:nth-last-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(2n+2)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n-3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n+3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li']],
+ ['li:nth-last-child(-n)', []],
+ ['li:nth-last-child(-n-1)', []],
+ ['li:nth-last-child(-n+1)', ['seventh-li']],
+ ['li:nth-last-child(-n+3)', ['fifth-li', 'sixth-li', 'seventh-li']],
+ ['ol:first-of-type', ['first-ol']],
+ ['ol:nth-child(4)', ['first-ol']],
+ ['ol:nth-of-type(2)', ['second-ol']],
+ ['ol:nth-last-of-type(1)', ['second-ol']],
+ ['span:only-child', ['foobar-span', 'no-siblings-of-any-type']],
+ ['li div:only-child', ['li-div']],
+ ['div *:only-child', ['li-div', 'foobar-span']],
+ ['p:only-of-type', ['paragraph']],
+ [':only-of-type', ['html', 'li-div', 'foobar-span', 'no-siblings-of-any-type']],
+ ['div#foobar-div :only-of-type', ['foobar-span']],
+ ['a:empty', ['name-anchor']],
+ ['a:EMpty', ['name-anchor']],
+ ['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']],
+ [':root', ['html']],
+ ['html:root', ['html']],
+ ['li:root', []],
+ ['* :root', []],
+ ['*:contains("link")', ['html', 'nil', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
+ [':CONtains("link")', ['html', 'nil', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
+ ['*:contains("LInk")', []], // case sensitive
+ ['*:contains("e")', ['html', 'nil', 'outer-div', 'first-ol', 'first-li', 'paragraph', 'p-em']],
+ ['*:contains("E")', []], // case-sensitive
+ ['.a', ['first-ol']],
+ ['.b', ['first-ol']],
+ ['*.a', ['first-ol']],
+ ['ol.a', ['first-ol']],
+ ['.c', ['first-ol', 'third-li', 'fourth-li']],
+ ['*.c', ['first-ol', 'third-li', 'fourth-li']],
+ ['ol *.c', ['third-li', 'fourth-li']],
+ ['ol li.c', ['third-li', 'fourth-li']],
+ ['li ~ li.c', ['third-li', 'fourth-li']],
+ ['ol > li.c', ['third-li', 'fourth-li']],
+ ['#first-li', ['first-li']],
+ ['li#first-li', ['first-li']],
+ ['*#first-li', ['first-li']],
+ ['li div', ['li-div']],
+ ['li > div', ['li-div']],
+ ['div div', ['li-div']],
+ ['div > div', []],
+ ['div>.c', ['first-ol']],
+ ['div > .c', ['first-ol']],
+ ['div + div', ['foobar-div']],
+ ['a ~ a', ['tag-anchor', 'nofollow-anchor']],
+ ['a[rel="tag"] ~ a', ['nofollow-anchor']],
+ ['ol#first-ol li:last-child', ['seventh-li']],
+ ['ol#first-ol *:last-child', ['li-div', 'seventh-li']],
+ ['#outer-div:first-child', ['outer-div']],
+ ['#outer-div :first-child', ['name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-fieldset-disabled', 'area-href']],
+ ['a[href]', ['tag-anchor', 'nofollow-anchor']],
+ [':not(*)', []],
+ ['a:not([href])', ['name-anchor']],
+ ['ol :Not(li[class])', ['first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li']],
+ // HTML-specific
+ [':link', ['link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']],
+ [':visited', []],
+ [':enabled', ['link-href', 'tag-anchor', 'nofollow-anchor', 'checkbox-unchecked', 'text-checked', 'checkbox-checked', 'area-href']],
+ [':disabled', ['checkbox-disabled', 'checkbox-disabled-checked', 'fieldset', 'checkbox-fieldset-disabled']],
+ [':checked', ['checkbox-checked', 'checkbox-disabled-checked']],
+ ];
+ }
+
+ public static function getHtmlShakespearTestData()
+ {
+ return [
+ ['*', 246],
+ ['div:contains(CELIA)', 26],
+ ['div:only-child', 22], // ?
+ ['div:nth-child(even)', 106],
+ ['div:nth-child(2n)', 106],
+ ['div:nth-child(odd)', 137],
+ ['div:nth-child(2n+1)', 137],
+ ['div:nth-child(n)', 243],
+ ['div:last-child', 53],
+ ['div:first-child', 51],
+ ['div > div', 242],
+ ['div + div', 190],
+ ['div ~ div', 190],
+ ['body', 1],
+ ['body div', 243],
+ ['div', 243],
+ ['div div', 242],
+ ['div div div', 241],
+ ['div, div, div', 243],
+ ['div, a, span', 243],
+ ['.dialog', 51],
+ ['div.dialog', 51],
+ ['div .dialog', 51],
+ ['div.character, div.dialog', 99],
+ ['div.direction.dialog', 0],
+ ['div.dialog.direction', 0],
+ ['div.dialog.scene', 1],
+ ['div.scene.scene', 1],
+ ['div.scene .scene', 0],
+ ['div.direction .dialog ', 0],
+ ['div .dialog .direction', 4],
+ ['div.dialog .dialog .direction', 4],
+ ['#speech5', 1],
+ ['div#speech5', 1],
+ ['div #speech5', 1],
+ ['div.scene div.dialog', 49],
+ ['div#scene1 div.dialog div', 142],
+ ['#scene1 #speech1', 1],
+ ['div[class]', 103],
+ ['div[class=dialog]', 50],
+ ['div[class^=dia]', 51],
+ ['div[class$=log]', 50],
+ ['div[class*=sce]', 1],
+ ['div[class|=dialog]', 50], // ? Seems right
+ ['div[class!=madeup]', 243], // ? Seems right
+ ['div[class~=dialog]', 51], // ? Seems right
+ ];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
new file mode 100644
index 0000000..8f3dcbb
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+/**
+ * XPath expression translator abstract extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+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 [];
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
new file mode 100644
index 0000000..5415136
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
@@ -0,0 +1,119 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator attribute extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+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'],
+ ];
+ }
+
+ public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
+ {
+ return $xpath->addCondition($attribute);
+ }
+
+ public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
+ {
+ return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($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)',
+ $attribute,
+ Translator::getXpathLiteral(' '.$value.' ')
+ ) : '0');
+ }
+
+ 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))',
+ $attribute,
+ Translator::getXpathLiteral($value),
+ Translator::getXpathLiteral($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)',
+ $attribute,
+ Translator::getXpathLiteral($value)
+ ) : '0');
+ }
+
+ 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',
+ $attribute,
+ \strlen($value) - 1,
+ Translator::getXpathLiteral($value)
+ ) : '0');
+ }
+
+ public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr
+ {
+ return $xpath->addCondition($value ? sprintf(
+ '%1$s and contains(%1$s, %2$s)',
+ $attribute,
+ Translator::getXpathLiteral($value)
+ ) : '0');
+ }
+
+ 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',
+ $attribute,
+ Translator::getXpathLiteral($value)
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName(): string
+ {
+ return 'attribute-matching';
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
new file mode 100644
index 0000000..9d6e043
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
@@ -0,0 +1,71 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator combination extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class CombinationExtension extends AbstractExtension
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getCombinationTranslators(): array
+ {
+ return [
+ ' ' => [$this, 'translateDescendant'],
+ '>' => [$this, 'translateChild'],
+ '+' => [$this, 'translateDirectAdjacent'],
+ '~' => [$this, 'translateIndirectAdjacent'],
+ ];
+ }
+
+ public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
+ {
+ return $xpath->join('/descendant-or-self::*/', $combinedXpath);
+ }
+
+ public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
+ {
+ return $xpath->join('/', $combinedXpath);
+ }
+
+ public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
+ {
+ return $xpath
+ ->join('/following-sibling::', $combinedXpath)
+ ->addNameTest()
+ ->addCondition('position() = 1');
+ }
+
+ public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr
+ {
+ return $xpath->join('/following-sibling::', $combinedXpath);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName(): string
+ {
+ return 'combination';
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
new file mode 100644
index 0000000..56fb4a1
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+/**
+ * XPath expression translator extension interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+interface ExtensionInterface
+{
+ /**
+ * Returns node translators.
+ *
+ * These callables will receive the node as first argument and the translator as second argument.
+ *
+ * @return callable[]
+ */
+ public function getNodeTranslators(): array;
+
+ /**
+ * Returns combination translators.
+ *
+ * @return callable[]
+ */
+ public function getCombinationTranslators(): array;
+
+ /**
+ * Returns function translators.
+ *
+ * @return callable[]
+ */
+ public function getFunctionTranslators(): array;
+
+ /**
+ * Returns pseudo-class translators.
+ *
+ * @return callable[]
+ */
+ public function getPseudoClassTranslators(): array;
+
+ /**
+ * Returns attribute operation translators.
+ *
+ * @return callable[]
+ */
+ public function getAttributeMatchingTranslators(): array;
+
+ /**
+ * Returns extension name.
+ */
+ public function getName(): string;
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
new file mode 100644
index 0000000..811105d
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
@@ -0,0 +1,171 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator function extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+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'],
+ ];
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr
+ {
+ try {
+ [$a, $b] = Parser::parseSeries($function->getArguments());
+ } catch (SyntaxErrorException $e) {
+ throw new ExpressionErrorException(sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e);
+ }
+
+ $xpath->addStarPrefix();
+ if ($addNameTest) {
+ $xpath->addNameTest();
+ }
+
+ if (0 === $a) {
+ return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b));
+ }
+
+ if ($a < 0) {
+ if ($b < 1) {
+ return $xpath->addCondition('false()');
+ }
+
+ $sign = '<=';
+ } else {
+ $sign = '>=';
+ }
+
+ $expr = 'position()';
+
+ if ($last) {
+ $expr = 'last() - '.$expr;
+ --$b;
+ }
+
+ if (0 !== $b) {
+ $expr .= ' - '.$b;
+ }
+
+ $conditions = [sprintf('%s %s 0', $expr, $sign)];
+
+ if (1 !== $a && -1 !== $a) {
+ $conditions[] = sprintf('(%s) mod %d = 0', $expr, $a);
+ }
+
+ return $xpath->addCondition(implode(' and ', $conditions));
+
+ // todo: handle an+b, odd, even
+ // an+b means every-a, plus b, e.g., 2n+1 means odd
+ // 0n+b means b
+ // n+0 means a=1, i.e., all elements
+ // an means every a elements, i.e., 2n means even
+ // -n means -1n
+ // -1n+6 means elements 6 and previous
+ }
+
+ public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ return $this->translateNthChild($xpath, $function, true);
+ }
+
+ public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ return $this->translateNthChild($xpath, $function, false, false);
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ if ('*' === $xpath->getElement()) {
+ throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
+ }
+
+ return $this->translateNthChild($xpath, $function, true, false);
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ $arguments = $function->getArguments();
+ foreach ($arguments as $token) {
+ if (!($token->isString() || $token->isIdentifier())) {
+ throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments));
+ }
+ }
+
+ return $xpath->addCondition(sprintf(
+ 'contains(string(.), %s)',
+ Translator::getXpathLiteral($arguments[0]->getValue())
+ ));
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ $arguments = $function->getArguments();
+ foreach ($arguments as $token) {
+ if (!($token->isString() || $token->isIdentifier())) {
+ throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
+ }
+ }
+
+ return $xpath->addCondition(sprintf(
+ 'lang(%s)',
+ Translator::getXpathLiteral($arguments[0]->getValue())
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName(): string
+ {
+ return 'function';
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
new file mode 100644
index 0000000..72b9a23
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
@@ -0,0 +1,187 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator HTML extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class HtmlExtension extends AbstractExtension
+{
+ public function __construct(Translator $translator)
+ {
+ $translator
+ ->getExtension('node')
+ ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true)
+ ->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'],
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFunctionTranslators(): array
+ {
+ return [
+ 'lang' => [$this, 'translateLang'],
+ ];
+ }
+
+ public function translateChecked(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition(
+ '(@checked '
+ ."and (name(.) = 'input' or name(.) = 'command')"
+ ."and (@type = 'checkbox' or @type = 'radio'))"
+ );
+ }
+
+ public function translateLink(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
+ }
+
+ public function translateDisabled(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition(
+ '('
+ .'@disabled and'
+ .'('
+ ."(name(.) = 'input' and @type != 'hidden')"
+ ." or name(.) = 'button'"
+ ." or name(.) = 'select'"
+ ." or name(.) = 'textarea'"
+ ." or name(.) = 'command'"
+ ." or name(.) = 'fieldset'"
+ ." or name(.) = 'optgroup'"
+ ." or name(.) = 'option'"
+ .')'
+ .') or ('
+ ."(name(.) = 'input' and @type != 'hidden')"
+ ." or name(.) = 'button'"
+ ." or name(.) = 'select'"
+ ." or name(.) = 'textarea'"
+ .')'
+ .' and ancestor::fieldset[@disabled]'
+ );
+ // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any."
+ }
+
+ public function translateEnabled(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition(
+ '('
+ .'@href and ('
+ ."name(.) = 'a'"
+ ." or name(.) = 'link'"
+ ." or name(.) = 'area'"
+ .')'
+ .') or ('
+ .'('
+ ."name(.) = 'command'"
+ ." or name(.) = 'fieldset'"
+ ." or name(.) = 'optgroup'"
+ .')'
+ .' and not(@disabled)'
+ .') or ('
+ .'('
+ ."(name(.) = 'input' and @type != 'hidden')"
+ ." or name(.) = 'button'"
+ ." or name(.) = 'select'"
+ ." or name(.) = 'textarea'"
+ ." or name(.) = 'keygen'"
+ .')'
+ .' and not (@disabled or ancestor::fieldset[@disabled])'
+ .') or ('
+ ."name(.) = 'option' and not("
+ .'@disabled or ancestor::optgroup[@disabled]'
+ .')'
+ .')'
+ );
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ $arguments = $function->getArguments();
+ foreach ($arguments as $token) {
+ if (!($token->isString() || $token->isIdentifier())) {
+ throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments));
+ }
+ }
+
+ return $xpath->addCondition(sprintf(
+ 'ancestor-or-self::*[@lang][1][starts-with(concat('
+ ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')"
+ .', %s)]',
+ 'lang',
+ Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-')
+ ));
+ }
+
+ public function translateSelected(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition("(@selected and name(.) = 'option')");
+ }
+
+ public function translateInvalid(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition('0');
+ }
+
+ public function translateHover(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition('0');
+ }
+
+ public function translateVisited(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition('0');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName(): string
+ {
+ return 'html';
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
new file mode 100644
index 0000000..a64f7ee
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
@@ -0,0 +1,197 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Translator;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator node extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class NodeExtension extends AbstractExtension
+{
+ public const ELEMENT_NAME_IN_LOWER_CASE = 1;
+ public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
+ public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
+
+ private $flags;
+
+ public function __construct(int $flags = 0)
+ {
+ $this->flags = $flags;
+ }
+
+ /**
+ * @return $this
+ */
+ public function setFlag(int $flag, bool $on): self
+ {
+ if ($on && !$this->hasFlag($flag)) {
+ $this->flags += $flag;
+ }
+
+ if (!$on && $this->hasFlag($flag)) {
+ $this->flags -= $flag;
+ }
+
+ return $this;
+ }
+
+ public function hasFlag(int $flag): bool
+ {
+ 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'],
+ 'Powered_Cache_Attribute' => [$this, 'translateAttribute'],
+ 'Class' => [$this, 'translateClass'],
+ 'Hash' => [$this, 'translateHash'],
+ 'Element' => [$this, 'translateElement'],
+ ];
+ }
+
+ public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
+ {
+ return $translator->nodeToXPath($node->getTree());
+ }
+
+ public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
+ {
+ return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
+ }
+
+ public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+ $subXpath = $translator->nodeToXPath($node->getSubSelector());
+ $subXpath->addNameTest();
+
+ if ($subXpath->getCondition()) {
+ return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition()));
+ }
+
+ return $xpath->addCondition('0');
+ }
+
+ public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addFunction($xpath, $node);
+ }
+
+ public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addPseudoClass($xpath, $node->getIdentifier());
+ }
+
+ public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
+ {
+ $name = $node->getAttribute();
+ $safe = $this->isSafeName($name);
+
+ if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
+ $name = strtolower($name);
+ }
+
+ if ($node->getNamespace()) {
+ $name = sprintf('%s:%s', $node->getNamespace(), $name);
+ $safe = $safe && $this->isSafeName($node->getNamespace());
+ }
+
+ $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
+ $value = $node->getValue();
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
+ $value = strtolower($value);
+ }
+
+ return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
+ }
+
+ public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
+ }
+
+ public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
+ }
+
+ public function translateElement(Node\ElementNode $node): XPathExpr
+ {
+ $element = $node->getElement();
+
+ if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
+ $element = strtolower($element);
+ }
+
+ if ($element) {
+ $safe = $this->isSafeName($element);
+ } else {
+ $element = '*';
+ $safe = true;
+ }
+
+ if ($node->getNamespace()) {
+ $element = sprintf('%s:%s', $node->getNamespace(), $element);
+ $safe = $safe && $this->isSafeName($node->getNamespace());
+ }
+
+ $xpath = new XPathExpr('', $element);
+
+ if (!$safe) {
+ $xpath->addNameTest();
+ }
+
+ return $xpath;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName(): string
+ {
+ return 'node';
+ }
+
+ private function isSafeName(string $name): bool
+ {
+ return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
new file mode 100644
index 0000000..b20a597
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
@@ -0,0 +1,122 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\Extension;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator pseudo-class extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+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'],
+ ];
+ }
+
+ public function translateRoot(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition('not(parent::*)');
+ }
+
+ public function translateFirstChild(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath
+ ->addStarPrefix()
+ ->addNameTest()
+ ->addCondition('position() = 1');
+ }
+
+ public function translateLastChild(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath
+ ->addStarPrefix()
+ ->addNameTest()
+ ->addCondition('position() = last()');
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateFirstOfType(XPathExpr $xpath): XPathExpr
+ {
+ if ('*' === $xpath->getElement()) {
+ throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
+ }
+
+ return $xpath
+ ->addStarPrefix()
+ ->addCondition('position() = 1');
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function translateLastOfType(XPathExpr $xpath): XPathExpr
+ {
+ if ('*' === $xpath->getElement()) {
+ throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
+ }
+
+ return $xpath
+ ->addStarPrefix()
+ ->addCondition('position() = last()');
+ }
+
+ public function translateOnlyChild(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath
+ ->addStarPrefix()
+ ->addNameTest()
+ ->addCondition('last() = 1');
+ }
+
+ public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
+ {
+ $element = $xpath->getElement();
+
+ return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
+ }
+
+ public function translateEmpty(XPathExpr $xpath): XPathExpr
+ {
+ return $xpath->addCondition('not(*) and not(string-length())');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName(): string
+ {
+ return 'pseudo-class';
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php
new file mode 100644
index 0000000..488b40c
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/Translator.php
@@ -0,0 +1,230 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NodeInterface;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class Translator implements TranslatorInterface
+{
+ private $mainParser;
+
+ /**
+ * @var ParserInterface[]
+ */
+ private $shortcutParsers = [];
+
+ /**
+ * @var Extension\ExtensionInterface[]
+ */
+ private $extensions = [];
+
+ private $nodeTranslators = [];
+ private $combinationTranslators = [];
+ private $functionTranslators = [];
+ private $pseudoClassTranslators = [];
+ private $attributeMatchingTranslators = [];
+
+ public function __construct(?ParserInterface $parser = null)
+ {
+ $this->mainParser = $parser ?? new Parser();
+
+ $this
+ ->registerExtension(new Extension\NodeExtension())
+ ->registerExtension(new Extension\CombinationExtension())
+ ->registerExtension(new Extension\FunctionExtension())
+ ->registerExtension(new Extension\PseudoClassExtension())
+ ->registerExtension(new Extension\AttributeMatchingExtension())
+ ;
+ }
+
+ public static function getXpathLiteral(string $element): string
+ {
+ if (!str_contains($element, "'")) {
+ return "'".$element."'";
+ }
+
+ if (!str_contains($element, '"')) {
+ return '"'.$element.'"';
+ }
+
+ $string = $element;
+ $parts = [];
+ while (true) {
+ if (false !== $pos = strpos($string, "'")) {
+ $parts[] = sprintf("'%s'", substr($string, 0, $pos));
+ $parts[] = "\"'\"";
+ $string = substr($string, $pos + 1);
+ } else {
+ $parts[] = "'$string'";
+ break;
+ }
+ }
+
+ return sprintf('concat(%s)', implode(', ', $parts));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
+ {
+ $selectors = $this->parseSelectors($cssExpr);
+
+ /** @var SelectorNode $selector */
+ foreach ($selectors as $index => $selector) {
+ if (null !== $selector->getPseudoElement()) {
+ throw new ExpressionErrorException('Pseudo-elements are not supported.');
+ }
+
+ $selectors[$index] = $this->selectorToXPath($selector, $prefix);
+ }
+
+ return implode(' | ', $selectors);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
+ {
+ return ($prefix ?: '').$this->nodeToXPath($selector);
+ }
+
+ /**
+ * @return $this
+ */
+ public function registerExtension(Extension\ExtensionInterface $extension): self
+ {
+ $this->extensions[$extension->getName()] = $extension;
+
+ $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
+ $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
+ $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
+ $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
+ $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
+
+ return $this;
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function getExtension(string $name): Extension\ExtensionInterface
+ {
+ if (!isset($this->extensions[$name])) {
+ throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
+ }
+
+ return $this->extensions[$name];
+ }
+
+ /**
+ * @return $this
+ */
+ public function registerParserShortcut(ParserInterface $shortcut): self
+ {
+ $this->shortcutParsers[] = $shortcut;
+
+ return $this;
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function nodeToXPath(NodeInterface $node): XPathExpr
+ {
+ if (!isset($this->nodeTranslators[$node->getNodeName()])) {
+ throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
+ }
+
+ return $this->nodeTranslators[$node->getNodeName()]($node, $this);
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
+ {
+ if (!isset($this->combinationTranslators[$combiner])) {
+ throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
+ }
+
+ return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
+ {
+ if (!isset($this->functionTranslators[$function->getName()])) {
+ throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
+ }
+
+ return $this->functionTranslators[$function->getName()]($xpath, $function);
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
+ {
+ if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
+ throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
+ }
+
+ return $this->pseudoClassTranslators[$pseudoClass]($xpath);
+ }
+
+ /**
+ * @throws ExpressionErrorException
+ */
+ public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr
+ {
+ if (!isset($this->attributeMatchingTranslators[$operator])) {
+ throw new ExpressionErrorException(sprintf('Powered_Cache_Attribute matcher operator "%s" not supported.', $operator));
+ }
+
+ return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
+ }
+
+ /**
+ * @return SelectorNode[]
+ */
+ private function parseSelectors(string $css): array
+ {
+ foreach ($this->shortcutParsers as $shortcut) {
+ $tokens = $shortcut->parse($css);
+
+ if (!empty($tokens)) {
+ return $tokens;
+ }
+ }
+
+ return $this->mainParser->parse($css);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
new file mode 100644
index 0000000..2aae319
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath;
+
+use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+interface TranslatorInterface
+{
+ /**
+ * Translates a CSS selector to an XPath expression.
+ */
+ public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string;
+
+ /**
+ * Translates a parsed selector node to an XPath expression.
+ */
+ public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string;
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php
new file mode 100644
index 0000000..8ab83fe
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/XPath/XPathExpr.php
@@ -0,0 +1,111 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\XPath;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon
+ *
+ * @internal
+ */
+class XPathExpr
+{
+ private $path;
+ private $element;
+ private $condition;
+
+ public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false)
+ {
+ $this->path = $path;
+ $this->element = $element;
+ $this->condition = $condition;
+
+ if ($starPrefix) {
+ $this->addStarPrefix();
+ }
+ }
+
+ public function getElement(): string
+ {
+ return $this->element;
+ }
+
+ /**
+ * @return $this
+ */
+ public function addCondition(string $condition): self
+ {
+ $this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
+
+ return $this;
+ }
+
+ public function getCondition(): string
+ {
+ return $this->condition;
+ }
+
+ /**
+ * @return $this
+ */
+ public function addNameTest(): self
+ {
+ if ('*' !== $this->element) {
+ $this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
+ $this->element = '*';
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function addStarPrefix(): self
+ {
+ $this->path .= '*/';
+
+ return $this;
+ }
+
+ /**
+ * Joins another XPathExpr with a combiner.
+ *
+ * @return $this
+ */
+ public function join(string $combiner, self $expr): self
+ {
+ $path = $this->__toString().$combiner;
+
+ if ('*/' !== $expr->path) {
+ $path .= $expr->path;
+ }
+
+ $this->path = $path;
+ $this->element = $expr->element;
+ $this->condition = $expr->condition;
+
+ return $this;
+ }
+
+ public function __toString(): string
+ {
+ $path = $this->path.$this->element;
+ $condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';
+
+ return $path.$condition;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json b/includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json
new file mode 100644
index 0000000..f0b7124
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/composer.json
@@ -0,0 +1,33 @@
+{
+ "name": "symfony/css-selector",
+ "type": "library",
+ "description": "Converts CSS selectors to XPath expressions",
+ "keywords": [],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Jean-François Simon",
+ "email": "jeanfrancois.simon@sensiolabs.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-php80": "^1.16"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\CssSelector\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist b/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
new file mode 100644
index 0000000..a8e537e
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Resources
+ ./Tests
+ ./vendor
+
+
+
+
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE b/includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE
new file mode 100644
index 0000000..0ed3a24
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2020-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
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php
new file mode 100644
index 0000000..bec0308
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Php80.php
@@ -0,0 +1,115 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Polyfill\Php80;
+
+/**
+ * @author Ion Bazan
+ * @author Nico Oelgart
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+final class Php80
+{
+ public static function fdiv(float $dividend, float $divisor): float
+ {
+ return @($dividend / $divisor);
+ }
+
+ public static function get_debug_type($value): string
+ {
+ switch (true) {
+ case null === $value: return 'null';
+ case \is_bool($value): return 'bool';
+ case \is_string($value): return 'string';
+ case \is_array($value): return 'array';
+ case \is_int($value): return 'int';
+ case \is_float($value): return 'float';
+ case \is_object($value): break;
+ case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';
+ default:
+ if (null === $type = @get_resource_type($value)) {
+ return 'unknown';
+ }
+
+ if ('Unknown' === $type) {
+ $type = 'closed';
+ }
+
+ return "resource ($type)";
+ }
+
+ $class = \get_class($value);
+
+ if (false === strpos($class, '@')) {
+ return $class;
+ }
+
+ return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';
+ }
+
+ public static function get_resource_id($res): int
+ {
+ if (!\is_resource($res) && null === @get_resource_type($res)) {
+ throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));
+ }
+
+ return (int) $res;
+ }
+
+ public static function preg_last_error_msg(): string
+ {
+ switch (preg_last_error()) {
+ case \PREG_INTERNAL_ERROR:
+ return 'Internal error';
+ case \PREG_BAD_UTF8_ERROR:
+ return 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ case \PREG_BAD_UTF8_OFFSET_ERROR:
+ return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
+ case \PREG_BACKTRACK_LIMIT_ERROR:
+ return 'Backtrack limit exhausted';
+ case \PREG_RECURSION_LIMIT_ERROR:
+ return 'Recursion limit exhausted';
+ case \PREG_JIT_STACKLIMIT_ERROR:
+ return 'JIT stack limit exhausted';
+ case \PREG_NO_ERROR:
+ return 'No error';
+ default:
+ return 'Unknown error';
+ }
+ }
+
+ public static function str_contains(string $haystack, string $needle): bool
+ {
+ return '' === $needle || false !== strpos($haystack, $needle);
+ }
+
+ public static function str_starts_with(string $haystack, string $needle): bool
+ {
+ return 0 === strncmp($haystack, $needle, \strlen($needle));
+ }
+
+ public static function str_ends_with(string $haystack, string $needle): bool
+ {
+ if ('' === $needle || $needle === $haystack) {
+ return true;
+ }
+
+ if ('' === $haystack) {
+ return false;
+ }
+
+ $needleLength = \strlen($needle);
+
+ return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php
new file mode 100644
index 0000000..e5fa75a
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/PhpToken.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace PoweredCache\Dependencies\Symfony\Polyfill\Php80;
+
+/**
+ * @author Fedonyuk Anton
+ *
+ * @internal
+ */
+class PhpToken implements \Stringable
+{
+ /**
+ * @var int
+ */
+ public $id;
+
+ /**
+ * @var string
+ */
+ public $text;
+
+ /**
+ * @var -1|positive-int
+ */
+ public $line;
+
+ /**
+ * @var int
+ */
+ public $pos;
+
+ /**
+ * @param -1|positive-int $line
+ */
+ public function __construct(int $id, string $text, int $line = -1, int $position = -1)
+ {
+ $this->id = $id;
+ $this->text = $text;
+ $this->line = $line;
+ $this->pos = $position;
+ }
+
+ public function getTokenName(): ?string
+ {
+ if ('UNKNOWN' === $name = token_name($this->id)) {
+ $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
+ }
+
+ return $name;
+ }
+
+ /**
+ * @param int|string|array $kind
+ */
+ public function is($kind): bool
+ {
+ foreach ((array) $kind as $value) {
+ if (\in_array($value, [$this->id, $this->text], true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function isIgnorable(): bool
+ {
+ return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true);
+ }
+
+ public function __toString(): string
+ {
+ return (string) $this->text;
+ }
+
+ /**
+ * @return list
+ */
+ public static function tokenize(string $code, int $flags = 0): array
+ {
+ $line = 1;
+ $position = 0;
+ $tokens = token_get_all($code, $flags);
+ foreach ($tokens as $index => $token) {
+ if (\is_string($token)) {
+ $id = \ord($token);
+ $text = $token;
+ } else {
+ [$id, $text, $line] = $token;
+ }
+ $tokens[$index] = new static($id, $text, $line, $position);
+ $position += \strlen($text);
+ }
+
+ return $tokens;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md b/includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md
new file mode 100644
index 0000000..3816c55
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/README.md
@@ -0,0 +1,25 @@
+Symfony Polyfill / Php80
+========================
+
+This component provides features added to PHP 8.0 core:
+
+- [`Stringable`](https://php.net/stringable) interface
+- [`fdiv`](https://php.net/fdiv)
+- [`ValueError`](https://php.net/valueerror) class
+- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class
+- `FILTER_VALIDATE_BOOL` constant
+- [`get_debug_type`](https://php.net/get_debug_type)
+- [`PhpToken`](https://php.net/phptoken) class
+- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)
+- [`str_contains`](https://php.net/str_contains)
+- [`str_starts_with`](https://php.net/str_starts_with)
+- [`str_ends_with`](https://php.net/str_ends_with)
+- [`get_resource_id`](https://php.net/get_resource_id)
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php
new file mode 100644
index 0000000..2b95542
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Attribute.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#[Attribute(Attribute::TARGET_CLASS)]
+final class Attribute
+{
+ public const TARGET_CLASS = 1;
+ public const TARGET_FUNCTION = 2;
+ public const TARGET_METHOD = 4;
+ public const TARGET_PROPERTY = 8;
+ public const TARGET_CLASS_CONSTANT = 16;
+ public const TARGET_PARAMETER = 32;
+ public const TARGET_ALL = 63;
+ public const IS_REPEATABLE = 64;
+
+ /** @var int */
+ public $flags;
+
+ public function __construct(int $flags = self::TARGET_ALL)
+ {
+ $this->flags = $flags;
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php
new file mode 100644
index 0000000..903d87e
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/PhpToken.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
+ class PhpToken extends PoweredCache\Dependencies\Symfony\Polyfill\Php80\PhpToken
+ {
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php
new file mode 100644
index 0000000..7c62d75
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/Stringable.php
@@ -0,0 +1,20 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+ interface Stringable
+ {
+ /**
+ * @return string
+ */
+ public function __toString();
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php
new file mode 100644
index 0000000..01c6c6c
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/UnhandledMatchError.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+ class UnhandledMatchError extends Error
+ {
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php
new file mode 100644
index 0000000..783dbc2
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/Resources/stubs/ValueError.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80000) {
+ class ValueError extends Error
+ {
+ }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php b/includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php
new file mode 100644
index 0000000..3d6dc26
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/bootstrap.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use PoweredCache\Dependencies\Symfony\Polyfill\Php80 as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+ return;
+}
+
+if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
+ define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
+}
+
+if (!function_exists('fdiv')) {
+ function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
+}
+if (!function_exists('preg_last_error_msg')) {
+ function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
+}
+if (!function_exists('str_contains')) {
+ function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('str_starts_with')) {
+ function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('str_ends_with')) {
+ function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }
+}
+if (!function_exists('get_debug_type')) {
+ function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
+}
+if (!function_exists('get_resource_id')) {
+ function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); }
+}
diff --git a/includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json b/includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json
new file mode 100644
index 0000000..a503b03
--- /dev/null
+++ b/includes/classes/Dependencies/Symfony/Polyfill/Php80/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "symfony/polyfill-php80",
+ "type": "library",
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.2"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Php80\\": "" },
+ "files": [ "bootstrap.php" ],
+ "classmap": [ "Resources/stubs" ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractDomParser.php b/includes/classes/Dependencies/voku/helper/AbstractDomParser.php
new file mode 100644
index 0000000..457594d
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/AbstractDomParser.php
@@ -0,0 +1,527 @@
+ ['[', ']', '{', '}'],
+ 'tmp' => [
+ '____SIMPLE_HTML_DOM__VOKU__SQUARE_BRACKET_LEFT____',
+ '____SIMPLE_HTML_DOM__VOKU__SQUARE_BRACKET_RIGHT____',
+ '____SIMPLE_HTML_DOM__VOKU__BRACKET_LEFT____',
+ '____SIMPLE_HTML_DOM__VOKU__BRACKET_RIGHT____',
+ ],
+ ];
+
+ /**
+ * @var string[][]
+ */
+ protected static $domReplaceHelper = [
+ 'orig' => ['&', '|', '+', '%', '@', ' [
+ '____SIMPLE_HTML_DOM__VOKU__AMP____',
+ '____SIMPLE_HTML_DOM__VOKU__PIPE____',
+ '____SIMPLE_HTML_DOM__VOKU__PLUS____',
+ '____SIMPLE_HTML_DOM__VOKU__PERCENT____',
+ '____SIMPLE_HTML_DOM__VOKU__AT____',
+ 'document = clone $this->document;
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return string|null
+ */
+ abstract public function __get($name);
+
+ /**
+ * @return string
+ */
+ abstract public function __toString();
+
+ /**
+ * does nothing (only for api-compatibility-reasons)
+ *
+ * @return bool
+ *
+ * @deprecated
+ */
+ public function clear(): bool
+ {
+ return true;
+ }
+
+ /**
+ * Create DOMDocument from HTML.
+ *
+ * @param string $html
+ * @param int|null $libXMLExtraOptions
+ *
+ * @return \DOMDocument
+ */
+ abstract protected function createDOMDocument(string $html, $libXMLExtraOptions = null): \DOMDocument;
+
+ /**
+ * @param string $content
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ protected function decodeHtmlEntity(string $content, bool $multiDecodeNewHtmlEntity): string
+ {
+ if ($multiDecodeNewHtmlEntity) {
+ if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
+ $content = UTF8::rawurldecode($content, true);
+ } else {
+ do {
+ $content_compare = $content;
+
+ $content = \rawurldecode(
+ \html_entity_decode(
+ $content,
+ \ENT_QUOTES | \ENT_HTML5
+ )
+ );
+ } while ($content_compare !== $content);
+ }
+ } else {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
+ $content = UTF8::rawurldecode($content, false);
+ } else {
+ $content = \rawurldecode(
+ \html_entity_decode(
+ $content,
+ \ENT_QUOTES | \ENT_HTML5
+ )
+ );
+ }
+ }
+
+ return $content;
+ }
+
+ /**
+ * Find list of nodes with a CSS selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return mixed
+ */
+ abstract public function find(string $selector, $idx = null);
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return mixed
+ */
+ abstract public function findMulti(string $selector);
+
+ /**
+ * Find nodes with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return mixed
+ */
+ abstract public function findMultiOrFalse(string $selector);
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return mixed
+ */
+ abstract public function findOne(string $selector);
+
+ /**
+ * Find one node with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return mixed
+ */
+ abstract public function findOneOrFalse(string $selector);
+
+ /**
+ * @return \DOMDocument
+ */
+ public function getDocument(): \DOMDocument
+ {
+ return $this->document;
+ }
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ abstract public function html(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
+ {
+ // init
+ $text = '';
+
+ if ($this->document->documentElement) {
+ foreach ($this->document->documentElement->childNodes as $node) {
+ $text .= $this->document->saveHTML($node);
+ }
+ }
+
+ return $this->fixHtmlOutput($text, $multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ // init
+ $text = '';
+
+ if ($this->document->documentElement) {
+ foreach ($this->document->documentElement->childNodes as $node) {
+ $text .= $this->document->saveXML($node);
+ }
+ }
+
+ return $this->fixHtmlOutput($text, $multiDecodeNewHtmlEntity);
+ }
+
+ /**
+ * Load HTML from string.
+ *
+ * @param string $html
+ * @param int|null $libXMLExtraOptions
+ *
+ * @return DomParserInterface
+ */
+ abstract public function loadHtml(string $html, $libXMLExtraOptions = null): DomParserInterface;
+
+ /**
+ * Load HTML from file.
+ *
+ * @param string $filePath
+ * @param int|null $libXMLExtraOptions
+ *
+ * @throws \RuntimeException
+ *
+ * @return DomParserInterface
+ */
+ abstract public function loadHtmlFile(string $filePath, $libXMLExtraOptions = null): DomParserInterface;
+
+ /**
+ * Save the html-dom as string.
+ *
+ * @param string $filepath
+ *
+ * @return string
+ */
+ public function save(string $filepath = ''): string
+ {
+ $string = $this->html();
+ if ($filepath !== '') {
+ \file_put_contents($filepath, $string, \LOCK_EX);
+ }
+
+ return $string;
+ }
+
+ /**
+ * @param callable $functionName
+ *
+ * @phpstan-param callable(\PoweredCache\Dependencies\voku\helper\XmlDomParser|\PoweredCache\Dependencies\voku\helper\HtmlDomParser): void $functionName
+ *
+ * @return void
+ */
+ public function set_callback($functionName)
+ {
+ static::$callback = $functionName;
+ }
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function text(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return $this->fixHtmlOutput($this->document->textContent, $multiDecodeNewHtmlEntity);
+ }
+
+ /**
+ * Get the HTML as XML or plain XML if needed.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $htmlToXml
+ * @param bool $removeXmlHeader
+ * @param int $options
+ *
+ * @return string
+ */
+ public function xml(
+ bool $multiDecodeNewHtmlEntity = false,
+ bool $htmlToXml = true,
+ bool $removeXmlHeader = true,
+ int $options = \LIBXML_NOEMPTYTAG
+ ): string {
+ $xml = $this->document->saveXML(null, $options);
+ if ($xml === false) {
+ return '';
+ }
+
+ if ($removeXmlHeader) {
+ $xml = \ltrim((string) \preg_replace('/<\?xml.*\?>/', '', $xml));
+ }
+
+ if ($htmlToXml) {
+ $return = $this->fixHtmlOutput($xml, $multiDecodeNewHtmlEntity);
+ } else {
+ $xml = $this->decodeHtmlEntity($xml, $multiDecodeNewHtmlEntity);
+
+ $return = self::putReplacedBackToPreserveHtmlEntities($xml);
+ }
+
+ return $return;
+ }
+
+ /**
+ * Get the encoding to use.
+ *
+ * @return string
+ */
+ protected function getEncoding(): string
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * workaround for bug: https://bugs.php.net/bug.php?id=74628
+ *
+ * @param string $html
+ *
+ * @return void
+ */
+ protected function html5FallbackForScriptTags(string &$html)
+ {
+ // regEx for e.g.: [';
+ },
+ $html
+ );
+
+ if ($htmlTmp !== null) {
+ $html = $htmlTmp;
+ }
+ }
+
+ /**
+ * @param string $html
+ *
+ * @return string
+ */
+ public static function putReplacedBackToPreserveHtmlEntities(string $html, bool $putBrokenReplacedBack = true): string
+ {
+ static $DOM_REPLACE__HELPER_CACHE = null;
+
+ if ($DOM_REPLACE__HELPER_CACHE === null) {
+ $DOM_REPLACE__HELPER_CACHE['tmp'] = \array_merge(
+ self::$domLinkReplaceHelper['tmp'],
+ self::$domReplaceHelper['tmp']
+ );
+ $DOM_REPLACE__HELPER_CACHE['orig'] = \array_merge(
+ self::$domLinkReplaceHelper['orig'],
+ self::$domReplaceHelper['orig']
+ );
+
+ $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__start'] = '<' . self::$domHtmlWrapperHelper . '>';
+ $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__end'] = '' . self::$domHtmlWrapperHelper . '>';
+
+ $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__start'] = '';
+ $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__end'] = '';
+
+ $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__start_broken'] = self::$domHtmlWrapperHelper . '>';
+ $DOM_REPLACE__HELPER_CACHE['tmp']['html_wrapper__end_broken'] = '' . self::$domHtmlWrapperHelper;
+
+ $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__start_broken'] = '';
+ $DOM_REPLACE__HELPER_CACHE['orig']['html_wrapper__end_broken'] = '';
+
+ $DOM_REPLACE__HELPER_CACHE['tmp']['html_special_script__start'] = '<' . self::$domHtmlSpecialScriptHelper;
+ $DOM_REPLACE__HELPER_CACHE['tmp']['html_special_script__end'] = '' . self::$domHtmlSpecialScriptHelper . '>';
+
+ $DOM_REPLACE__HELPER_CACHE['orig']['html_special_script__start'] = ' 0
+ ) {
+ $html = \str_ireplace(self::$domBrokenReplaceHelper['tmp'], self::$domBrokenReplaceHelper['orig'], $html);
+ }
+
+ return \str_ireplace($DOM_REPLACE__HELPER_CACHE['tmp'], $DOM_REPLACE__HELPER_CACHE['orig'], $html);
+ }
+
+ /**
+ * @param string $html
+ *
+ * @return string
+ */
+ public static function replaceToPreserveHtmlEntities(string $html): string
+ {
+ // init
+ $linksNew = [];
+ $linksOld = [];
+
+ if (\strpos($html, 'http') !== false) {
+ // regEx for e.g.: [https://www.domain.de/foo.php?foobar=1&email=lars%40moelleken.org&guid=test1233312&{{foo}}#foo]
+ $regExUrl = '/(\[?\bhttps?:\/\/[^\s<>]+(?:\(\w+\)|[^[:punct:]\s]|\/|}|]))/i';
+ \preg_match_all($regExUrl, $html, $linksOld);
+
+ if (!empty($linksOld[1])) {
+ $linksOld = $linksOld[1];
+ foreach ((array) $linksOld as $linkKey => $linkOld) {
+ $linksNew[$linkKey] = \str_replace(
+ self::$domLinkReplaceHelper['orig'],
+ self::$domLinkReplaceHelper['tmp'],
+ $linkOld
+ );
+ }
+ }
+ }
+
+ $linksNewCount = \count($linksNew);
+ if ($linksNewCount > 0 && \count($linksOld) === $linksNewCount) {
+ $search = \array_merge($linksOld, self::$domReplaceHelper['orig']);
+ $replace = \array_merge($linksNew, self::$domReplaceHelper['tmp']);
+ } else {
+ $search = self::$domReplaceHelper['orig'];
+ $replace = self::$domReplaceHelper['tmp'];
+ }
+
+ return \str_replace($search, $replace, $html);
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php
new file mode 100644
index 0000000..fdca9af
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDom.php
@@ -0,0 +1,255 @@
+ 'childNodes',
+ 'first_child' => 'firstChild',
+ 'last_child' => 'lastChild',
+ 'next_sibling' => 'nextSibling',
+ 'prev_sibling' => 'previousSibling',
+ 'parent' => 'parentNode',
+ 'outertext' => 'html',
+ 'outerhtml' => 'html',
+ 'innertext' => 'innerHtml',
+ 'innerhtml' => 'innerHtml',
+ 'innerhtmlkeep' => 'innerHtmlKeep',
+ ];
+
+ /**
+ * @var string[]
+ */
+ protected static $stringDomNodes = [
+ 'id',
+ 'prefix',
+ 'content'
+ ];
+
+ /**
+ * @var \DOMElement|\DOMNode|null
+ */
+ protected $node;
+
+ /**
+ * @var SimpleHtmlAttributes|null
+ */
+ private $classListCache;
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleHtmlDomInterface|string|null
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return SimpleHtmlAttributes|string|string[]|null
+ */
+ public function __get($name)
+ {
+ $nameOrig = $name;
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'outerhtml':
+ case 'outertext':
+ case 'html':
+ return $this->html();
+ case 'innerhtml':
+ case 'innertext':
+ return $this->innerHtml();
+ case 'innerhtmlkeep':
+ return $this->innerHtml(false, false);
+ case 'text':
+ case 'plaintext':
+ return $this->text();
+ case 'tag':
+ return $this->node->nodeName ?? '';
+ case 'attr':
+ return $this->getAllAttributes();
+ case 'classlist':
+ if ($this->classListCache === null) {
+ $this->classListCache = new SimpleHtmlAttributes($this->node ?? null, 'class');
+ }
+
+ return $this->classListCache;
+ default:
+ if ($this->node && \property_exists($this->node, $nameOrig)) {
+ if (\is_string($this->node->{$nameOrig})) {
+ return HtmlDomParser::putReplacedBackToPreserveHtmlEntities($this->node->{$nameOrig});
+ }
+
+ return $this->node->{$nameOrig};
+ }
+
+ return $this->getAttribute($name);
+ }
+ }
+
+ /**
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function __invoke($selector, $idx = null)
+ {
+ return $this->find($selector, $idx);
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ $nameOrig = $name;
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'outertext':
+ case 'outerhtml':
+ case 'innertext':
+ case 'innerhtml':
+ case 'innerhtmlkeep':
+ case 'plaintext':
+ case 'text':
+ case 'tag':
+ return true;
+ default:
+ if ($this->node && \property_exists($this->node, $nameOrig)) {
+ return isset($this->node->{$nameOrig});
+ }
+
+ return $this->hasAttribute($name);
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function __set($name, $value)
+ {
+ $nameOrig = $name;
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'outerhtml':
+ case 'outertext':
+ return $this->replaceNodeWithString($value);
+ case 'innertext':
+ case 'innerhtml':
+ return $this->replaceChildWithString($value);
+ case 'innerhtmlkeep':
+ return $this->replaceChildWithString($value, false);
+ case 'plaintext':
+ return $this->replaceTextWithString($value);
+ case 'classlist':
+ $name = 'class';
+ $nameOrig = 'class';
+ // no break
+ default:
+ if ($this->node && \property_exists($this->node, $nameOrig)) {
+ // INFO: Cannot assign null to property DOMNode::* of type string
+ if (in_array($nameOrig, self::$stringDomNodes)) {
+ $value = (string)$value;
+ }
+
+ if (!is_null($value)) {
+ return $this->node->{$nameOrig} = $value;
+ }
+ }
+
+ return $this->setAttribute($name, $value);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->html();
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return void
+ */
+ public function __unset($name)
+ {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->removeAttribute($name);
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return mixed
+ */
+ abstract public function find(string $selector, $idx = null);
+
+ /**
+ * @return string[]|null
+ */
+ abstract public function getAllAttributes();
+
+ abstract public function getAttribute(string $name): string;
+
+ abstract public function hasAttribute(string $name): bool;
+
+ abstract public function html(bool $multiDecodeNewHtmlEntity = false): string;
+
+ abstract public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
+
+ abstract public function removeAttribute(string $name): SimpleHtmlDomInterface;
+
+ abstract protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface;
+
+ abstract protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface;
+
+ /**
+ * @param string $string
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ abstract protected function replaceTextWithString($string): SimpleHtmlDomInterface;
+
+ /**
+ * @param string $name
+ * @param string|null $value
+ * @param bool $strictEmptyValueCheck
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ abstract public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface;
+
+ abstract public function text(): string;
+}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php
new file mode 100644
index 0000000..0033ddf
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/AbstractSimpleHtmlDomNode.php
@@ -0,0 +1,80 @@
+count();
+ }
+
+ if ($this->count() > 0) {
+ $return = [];
+
+ foreach ($this as $node) {
+ if ($node instanceof SimpleHtmlDomInterface) {
+ $return[] = $node->{$name};
+ }
+ }
+
+ return $return;
+ }
+
+ if ($name === 'plaintext' || $name === 'outertext') {
+ return [];
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomNodeInterface|SimpleHtmlDomNodeInterface[]|null
+ */
+ public function __invoke($selector, $idx = null)
+ {
+ return $this->find($selector, $idx);
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ // init
+ $html = '';
+
+ foreach ($this as $node) {
+ $html .= $node->outertext;
+ }
+
+ return $html;
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomNodeInterface|SimpleHtmlDomNodeInterface[]|null
+ */
+ abstract public function find(string $selector, $idx = null);
+}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php
new file mode 100644
index 0000000..dae961c
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDom.php
@@ -0,0 +1,217 @@
+ 'childNodes',
+ 'first_child' => 'firstChild',
+ 'last_child' => 'lastChild',
+ 'next_sibling' => 'nextSibling',
+ 'prev_sibling' => 'previousSibling',
+ 'parent' => 'parentNode',
+ ];
+
+ /**
+ * @var \DOMElement|\DOMNode|null
+ */
+ protected $node;
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleXmlDomInterface|string|null
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return array|string|null
+ */
+ public function __get($name)
+ {
+ $nameOrig = $name;
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'xml':
+ return $this->xml();
+ case 'plaintext':
+ return $this->text();
+ case 'tag':
+ return $this->node->nodeName ?? '';
+ case 'attr':
+ return $this->getAllAttributes();
+ default:
+ if ($this->node && \property_exists($this->node, $nameOrig)) {
+ return $this->node->{$nameOrig};
+ }
+
+ return $this->getAttribute($name);
+ }
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function __invoke($selector, $idx = null)
+ {
+ return $this->find($selector, $idx);
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ $nameOrig = $name;
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'outertext':
+ case 'outerhtml':
+ case 'innertext':
+ case 'innerhtml':
+ case 'innerhtmlkeep':
+ case 'plaintext':
+ case 'text':
+ case 'tag':
+ return true;
+ default:
+ if ($this->node && \property_exists($this->node, $nameOrig)) {
+ return isset($this->node->{$nameOrig});
+ }
+
+ return $this->hasAttribute($name);
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function __set($name, $value)
+ {
+ $nameOrig = $name;
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'outerhtml':
+ case 'outertext':
+ return $this->replaceNodeWithString($value);
+ case 'innertext':
+ case 'innerhtml':
+ return $this->replaceChildWithString($value);
+ case 'innerhtmlkeep':
+ return $this->replaceChildWithString($value, false);
+ case 'plaintext':
+ return $this->replaceTextWithString($value);
+ default:
+ if ($this->node && \property_exists($this->node, $nameOrig)) {
+ return $this->node->{$nameOrig} = $value;
+ }
+
+ return $this->setAttribute($name, $value);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->xml();
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return void
+ */
+ public function __unset($name)
+ {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->removeAttribute($name);
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ abstract public function find(string $selector, $idx = null);
+
+ /**
+ * @return string[]|null
+ */
+ abstract public function getAllAttributes();
+
+ /**
+ * @param string $name
+ *
+ * @return string
+ */
+ abstract public function getAttribute(string $name): string;
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ abstract public function hasAttribute(string $name): bool;
+
+ abstract public function innerXml(bool $multiDecodeNewHtmlEntity = false): string;
+
+ abstract public function removeAttribute(string $name): SimpleXmlDomInterface;
+
+ abstract protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleXmlDomInterface;
+
+ abstract protected function replaceNodeWithString(string $string): SimpleXmlDomInterface;
+
+ /**
+ * @param string $string
+ *
+ * @return SimpleXmlDomInterface
+ */
+ abstract protected function replaceTextWithString($string): SimpleXmlDomInterface;
+
+ /**
+ * @param string $name
+ * @param string|null $value
+ * @param bool $strictEmptyValueCheck
+ *
+ * @return SimpleXmlDomInterface
+ */
+ abstract public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleXmlDomInterface;
+
+ abstract public function text(): string;
+
+ abstract public function xml(bool $multiDecodeNewHtmlEntity = false): string;
+}
diff --git a/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php b/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php
new file mode 100644
index 0000000..dd7be0a
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/AbstractSimpleXmlDomNode.php
@@ -0,0 +1,80 @@
+count();
+ }
+
+ if ($this->count() > 0) {
+ $return = [];
+
+ foreach ($this as $node) {
+ if ($node instanceof SimpleXmlDomInterface) {
+ $return[] = $node->{$name};
+ }
+ }
+
+ return $return;
+ }
+
+ if ($name === 'plaintext' || $name === 'outertext') {
+ return [];
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomNodeInterface|SimpleXmlDomNodeInterface[]|null
+ */
+ public function __invoke($selector, $idx = null)
+ {
+ return $this->find($selector, $idx);
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ // init
+ $html = '';
+
+ foreach ($this as $node) {
+ $html .= $node->outertext;
+ }
+
+ return $html;
+ }
+
+ /**
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomNodeInterface|SimpleXmlDomNodeInterface[]|null
+ */
+ abstract public function find(string $selector, $idx = null);
+}
diff --git a/includes/classes/Dependencies/voku/helper/DomParserInterface.php b/includes/classes/Dependencies/voku/helper/DomParserInterface.php
new file mode 100644
index 0000000..f6e3513
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/DomParserInterface.php
@@ -0,0 +1,201 @@
+');
+
+ $domElement = $dom->findOneOrFalse($htmlCssSelector);
+ if ($domElement === false) {
+ return $html;
+ }
+ $attributes = $domElement->getAllAttributes();
+ if (!$attributes) {
+ return $html;
+ }
+
+ $domElementNew = $domNew->findOneOrFalse('textarea');
+ if ($domElementNew === false) {
+ return $html;
+ }
+ $attributesNew = $domElementNew->getAllAttributes();
+ if (!$attributesNew) {
+ return $html;
+ }
+
+ foreach ($attributesNew as $attributeNameNew => $attributeValueNew) {
+ $attributeNameNew = \strtolower($attributeNameNew);
+
+ if (
+ $attributeNameNew === 'class'
+ ||
+ $attributeNameNew === 'style'
+ ||
+ \strpos($attributeNameNew, 'on') === 0 // e.g. onClick, ...
+ ) {
+ if (isset($attributes[$attributeNameNew])) {
+ $attributes[$attributeNameNew] .= ' ' . $attributeValueNew;
+ } else {
+ $attributes[$attributeNameNew] = $attributeValueNew;
+ }
+ } else {
+ $attributes[$attributeNameNew] = $attributeValueNew;
+ }
+ }
+
+ foreach ($attributes as $attributeName => $attributeValue) {
+ $domElement->setAttribute($attributeName, $attributeValue, true);
+ }
+
+ return $domElement->html();
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/HtmlDomParser.php b/includes/classes/Dependencies/voku/helper/HtmlDomParser.php
new file mode 100644
index 0000000..8f87676
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/HtmlDomParser.php
@@ -0,0 +1,1228 @@
+Get dom node's outer html (alias for "outerHtml").
+ * @property-read string $outerHtml
+ * Get dom node's outer html.
+ * @property-read string $innerText
+ * Get dom node's inner html (alias for "innerHtml").
+ * @property-read string $innerHtml
+ * Get dom node's inner html.
+ * @property-read string $plaintext
+ * Get dom node's plain text.
+ *
+ * @method string outerText()
+ * Get dom node's outer html (alias for "outerHtml()").
+ * @method string outerHtml()
+ * Get dom node's outer html.
+ * @method string innerText()
+ * Get dom node's inner html (alias for "innerHtml()").
+ * @method HtmlDomParser load(string $html)
+ * Load HTML from string.
+ * @method HtmlDomParser load_file(string $html)
+ * Load HTML from file.
+ * @method static HtmlDomParser file_get_html($filePath, $libXMLExtraOptions = null)
+ * Load HTML from file.
+ * @method static HtmlDomParser str_get_html($html, $libXMLExtraOptions = null)
+ * Load HTML from string.
+ */
+class HtmlDomParser extends AbstractDomParser
+{
+ /**
+ * @var callable|null
+ *
+ * @phpstan-var null|callable(string $cssSelectorString, string $xPathString, \DOMXPath, \PoweredCache\Dependencies\voku\helper\HtmlDomParser): string
+ */
+ private $callbackXPathBeforeQuery;
+
+ /**
+ * @var callable|null
+ *
+ * @phpstan-var null|callable(string $htmlString, \PoweredCache\Dependencies\voku\helper\HtmlDomParser): string
+ */
+ private $callbackBeforeCreateDom;
+
+ /**
+ * @var string[]
+ */
+ protected static $functionAliases = [
+ 'outertext' => 'html',
+ 'outerhtml' => 'html',
+ 'innertext' => 'innerHtml',
+ 'innerhtml' => 'innerHtml',
+ 'load' => 'loadHtml',
+ 'load_file' => 'loadHtmlFile',
+ ];
+
+ /**
+ * @var string[]
+ */
+ protected $templateLogicSyntaxInSpecialScriptTags = [
+ '+',
+ '<%',
+ '{%',
+ '{{',
+ ];
+
+ /**
+ * The properties specified for each special script tag is an array.
+ *
+ * ```php
+ * protected $specialScriptTags = [
+ * 'text/html',
+ * 'text/template',
+ * 'text/x-custom-template',
+ * 'text/x-handlebars-template'
+ * ]
+ * ```
+ *
+ * @var string[]
+ */
+ protected $specialScriptTags = [
+ 'text/html',
+ 'text/template',
+ 'text/x-custom-template',
+ 'text/x-handlebars-template',
+ ];
+
+ /**
+ * @var string[]
+ */
+ protected $selfClosingTags = [
+ 'area',
+ 'base',
+ 'br',
+ 'col',
+ 'command',
+ 'embed',
+ 'hr',
+ 'img',
+ 'input',
+ 'keygen',
+ 'link',
+ 'meta',
+ 'param',
+ 'source',
+ 'track',
+ 'wbr',
+ ];
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithoutHtml = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithoutWrapper = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithCommentWrapper = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithoutHeadWrapper = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithoutPTagWrapper = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithoutHtmlWrapper = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithoutBodyWrapper = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithMultiRoot = false;
+
+ /**
+ * @var bool
+ */
+ protected $isDOMDocumentCreatedWithFakeEndScript = false;
+
+ /**
+ * @var bool
+ */
+ protected $keepBrokenHtml = false;
+
+ /**
+ * @param \DOMNode|SimpleHtmlDomInterface|string $element HTML code or SimpleHtmlDomInterface, \DOMNode
+ */
+ public function __construct($element = null)
+ {
+ $this->document = new \DOMDocument('1.0', $this->getEncoding());
+
+ // DOMDocument settings
+ $this->document->preserveWhiteSpace = true;
+ $this->document->formatOutput = true;
+
+ if ($element instanceof SimpleHtmlDomInterface) {
+ $element = $element->getNode();
+ }
+
+ if ($element instanceof \DOMNode) {
+ $domNode = $this->document->importNode($element, true);
+
+ if ($domNode instanceof \DOMNode) {
+ $this->document->appendChild($domNode);
+ }
+
+ return;
+ }
+
+ if ($element !== null) {
+ $this->loadHtml($element);
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @return bool|mixed
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist: ' . $name);
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ * @throws \RuntimeException
+ *
+ * @return static
+ */
+ public static function __callStatic($name, $arguments)
+ {
+ $arguments0 = $arguments[0] ?? '';
+
+ $arguments1 = $arguments[1] ?? null;
+
+ if ($name === 'str_get_html') {
+ $parser = new static();
+
+ return $parser->loadHtml($arguments0, $arguments1);
+ }
+
+ if ($name === 'file_get_html') {
+ $parser = new static();
+
+ return $parser->loadHtmlFile($arguments0, $arguments1);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+
+ /**
+ * @param string $name
+ *
+ * @return string|null
+ */
+ public function __get($name)
+ {
+ $name = \strtolower($name);
+
+ switch ($name) {
+ case 'outerhtml':
+ case 'outertext':
+ return $this->html();
+ case 'innerhtml':
+ case 'innertext':
+ return $this->innerHtml();
+ case 'innerhtmlkeep':
+ return $this->innerHtml(false, false);
+ case 'text':
+ case 'plaintext':
+ return $this->text();
+ }
+
+ return null;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->html();
+ }
+
+ /**
+ * does nothing (only for api-compatibility-reasons)
+ *
+ * @return bool
+ *
+ * @deprecated
+ */
+ public function clear(): bool
+ {
+ return true;
+ }
+
+ /**
+ * Create DOMDocument from HTML.
+ *
+ * @param string $html
+ * @param int|null $libXMLExtraOptions
+ * @param bool $useDefaultLibXMLOptions
+ *
+ * @return \DOMDocument
+ */
+ protected function createDOMDocument(string $html, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): \DOMDocument
+ {
+ if ($this->callbackBeforeCreateDom) {
+ $html = \call_user_func($this->callbackBeforeCreateDom, $html, $this);
+ }
+
+ // Remove content before because otherwise the DOMDocument can not handle the input.
+ $isDOMDocumentCreatedWithDoctype = false;
+ if (\stripos($html, ']*)?>/sui', $html, $matches_before_doctype)
+ &&
+ \trim($matches_before_doctype[1])
+ ) {
+ $html = \str_replace($matches_before_doctype[1], '', $html);
+ }
+ }
+
+ if ($this->keepBrokenHtml) {
+ $html = $this->keepBrokenHtml(\trim($html));
+ }
+
+ if (\strpos($html, '<') === false) {
+ $this->isDOMDocumentCreatedWithoutHtml = true;
+ } elseif (\strpos(\ltrim($html), '<') !== 0) {
+ $this->isDOMDocumentCreatedWithoutWrapper = true;
+ }
+
+ if (\strpos(\ltrim($html), '';
+ }
+ }
+
+ return $html;
+ }
+
+ /**
+ * @param \DOMNode $node
+ *
+ * @return string
+ */
+ private function getDoctype(\DOMNode $node): string
+ {
+ // check the doc-type only if it wasn't generated by DomDocument itself
+ if (!$this->withDocType) {
+ return '';
+ }
+
+ foreach ($node->childNodes as $child) {
+ if (
+ $child instanceof \DOMDocumentType
+ &&
+ $child->name
+ ) {
+ if (!$child->publicId && $child->systemId) {
+ $tmpTypeSystem = 'SYSTEM';
+ $tmpTypePublic = '';
+ } else {
+ $tmpTypeSystem = '';
+ $tmpTypePublic = 'PUBLIC';
+ }
+
+ return 'name
+ . ($child->publicId ? ' ' . $tmpTypePublic . ' "' . $child->publicId . '"' : '')
+ . ($child->systemId ? ' ' . $tmpTypeSystem . ' "' . $child->systemId . '"' : '')
+ . '>';
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @return array
+ */
+ public function getDomainsToRemoveHttpPrefixFromAttributes(): array
+ {
+ return $this->domainsToRemoveHttpPrefixFromAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoOptimizeAttributes(): bool
+ {
+ return $this->doOptimizeAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoOptimizeViaHtmlDomParser(): bool
+ {
+ return $this->doOptimizeViaHtmlDomParser;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveComments(): bool
+ {
+ return $this->doRemoveComments;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDefaultAttributes(): bool
+ {
+ return $this->doRemoveDefaultAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDeprecatedAnchorName(): bool
+ {
+ return $this->doRemoveDeprecatedAnchorName;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDeprecatedScriptCharsetAttribute(): bool
+ {
+ return $this->doRemoveDeprecatedScriptCharsetAttribute;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDeprecatedTypeFromScriptTag(): bool
+ {
+ return $this->doRemoveDeprecatedTypeFromScriptTag;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDeprecatedTypeFromStylesheetLink(): bool
+ {
+ return $this->doRemoveDeprecatedTypeFromStylesheetLink;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDeprecatedTypeFromStyleAndLinkTag(): bool
+ {
+ return $this->doRemoveDeprecatedTypeFromStyleAndLinkTag;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDefaultMediaTypeFromStyleAndLinkTag(): bool
+ {
+ return $this->doRemoveDefaultMediaTypeFromStyleAndLinkTag;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveDefaultTypeFromButton(): bool
+ {
+ return $this->doRemoveDefaultTypeFromButton;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveEmptyAttributes(): bool
+ {
+ return $this->doRemoveEmptyAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveHttpPrefixFromAttributes(): bool
+ {
+ return $this->doRemoveHttpPrefixFromAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveHttpsPrefixFromAttributes(): bool
+ {
+ return $this->doRemoveHttpsPrefixFromAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isdoKeepHttpAndHttpsPrefixOnExternalAttributes(): bool
+ {
+ return $this->doKeepHttpAndHttpsPrefixOnExternalAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoMakeSameDomainsLinksRelative(): bool
+ {
+ return $this->doMakeSameDomainsLinksRelative;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveOmittedHtmlTags(): bool
+ {
+ return $this->doRemoveOmittedHtmlTags;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveOmittedQuotes(): bool
+ {
+ return $this->doRemoveOmittedQuotes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveSpacesBetweenTags(): bool
+ {
+ return $this->doRemoveSpacesBetweenTags;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveValueFromEmptyInput(): bool
+ {
+ return $this->doRemoveValueFromEmptyInput;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoRemoveWhitespaceAroundTags(): bool
+ {
+ return $this->doRemoveWhitespaceAroundTags;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoSortCssClassNames(): bool
+ {
+ return $this->doSortCssClassNames;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoSortHtmlAttributes(): bool
+ {
+ return $this->doSortHtmlAttributes;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDoSumUpWhitespace(): bool
+ {
+ return $this->doSumUpWhitespace;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isHTML4(): bool
+ {
+ return $this->isHTML4;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isXHTML(): bool
+ {
+ return $this->isXHTML;
+ }
+
+ /**
+ * @param string $html
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function minify($html, $multiDecodeNewHtmlEntity = false): string
+ {
+ $html = (string) $html;
+ if (!isset($html[0])) {
+ return '';
+ }
+
+ $html = \trim($html);
+ if (!$html) {
+ return '';
+ }
+
+ // reset
+ $this->protectedChildNodes = [];
+
+ // save old content
+ $origHtml = $html;
+ $origHtmlLength = \strlen($html);
+
+ // -------------------------------------------------------------------------
+ // Minify the HTML via "HtmlDomParser"
+ // -------------------------------------------------------------------------
+
+ if ($this->doOptimizeViaHtmlDomParser) {
+ $html = $this->minifyHtmlDom($html, $multiDecodeNewHtmlEntity);
+ }
+
+ // -------------------------------------------------------------------------
+ // Trim whitespace from html-string. [protected html is still protected]
+ // -------------------------------------------------------------------------
+
+ // Remove extra white-space(s) between HTML attribute(s)
+ if (\strpos($html, ' ') !== false) {
+ $htmlCleaned = \preg_replace_callback(
+ '#<([^/\s<>!]+)(?:\s+([^<>]*?)\s*|\s*)(/?)>#',
+ static function ($matches) {
+ return '<' . $matches[1] . \preg_replace('#([^\s=]+)(=([\'"]?)(.*?)\3)?(\s+|$)#su', ' $1$2', $matches[2]) . $matches[3] . '>';
+ },
+ $html
+ );
+ if ($htmlCleaned !== null) {
+ $html = (string)$htmlCleaned;
+ } else {
+ $htmlCleaned = (string) \preg_replace_callback(
+ '#<([^/\s<>!]+)(?:\s+([^<>]*)\s*|\s*)(/?)>#',
+ static function ($matches) {
+ return '<' . $matches[1] . \preg_replace('#([^\s=]+)(=([\'"]?)(.*?)\3)?(\s+|$)#su', ' $1$2', $matches[2]) . $matches[3] . '>';
+ },
+ $html
+ );
+ $html = $htmlCleaned;
+ }
+ }
+
+ if ($this->doRemoveSpacesBetweenTags) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\strpos($html, ' ') !== false) {
+ // Remove spaces that are between > and <
+ $html = (string) \preg_replace('#(>)\s(<)#', '>$2', $html);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Restore protected HTML-code.
+ // -------------------------------------------------------------------------
+
+ if (\strpos($html, $this->protectedChildNodesHelper) !== false) {
+ $html = (string) \preg_replace_callback(
+ '/<(?' . $this->protectedChildNodesHelper . ')(? [^>]*)?>(?.*?)<\/' . $this->protectedChildNodesHelper . '>/',
+ [$this, 'restoreProtectedHtml'],
+ $html
+ );
+ }
+
+ // -------------------------------------------------------------------------
+ // Restore protected HTML-entities.
+ // -------------------------------------------------------------------------
+
+ if ($this->doOptimizeViaHtmlDomParser) {
+ $html = HtmlDomParser::putReplacedBackToPreserveHtmlEntities($html);
+ }
+
+ // ------------------------------------
+ // Final clean-up
+ // ------------------------------------
+
+ $html = \str_replace(
+ [
+ 'html>' . "\n",
+ "\n" . ' ' . "\n",
+ "\n" . '' . "\n",
+ "\n" . ' ' . "\n",
+ "\n" . '',
+ ' ',
+ '',
+ ' ',
+ '';
+ $replacement[] = '<' . $selfClosingTag . '>';
+ $replace[] = '<' . $selfClosingTag . ' />';
+ $replacement[] = '<' . $selfClosingTag . '>';
+ $replace[] = '>' . $selfClosingTag . '>';
+ $replacement[] = '>';
+ }
+ $html = \str_replace(
+ $replace,
+ $replacement,
+ $html
+ );
+
+ // ------------------------------------
+ // check if compression worked
+ // ------------------------------------
+
+ if ($origHtmlLength < \strlen($html)) {
+ $html = $origHtml;
+ }
+
+ return $html;
+ }
+
+ /**
+ * @param \DOMNode $node
+ *
+ * @return \DOMNode|null
+ */
+ protected function getNextSiblingOfTypeDOMElement(\DOMNode $node)
+ {
+ do {
+ /** @var \DOMElement|\DOMText|null $nodeTmp - false-positive error from phpstan */
+ $nodeTmp = $node->nextSibling;
+
+ if ($nodeTmp instanceof \DOMText) {
+ if (
+ \trim($nodeTmp->textContent) !== ''
+ &&
+ \strpos($nodeTmp->textContent, '<') === false
+ ) {
+ $node = $nodeTmp;
+ } else {
+ $node = $nodeTmp->nextSibling;
+ }
+ } else {
+ $node = $nodeTmp;
+ }
+ } while (!($node === null || $node instanceof \DOMElement || $node instanceof \DOMText));
+
+ return $node;
+ }
+
+ /**
+ * Check if the current string is an conditional comment.
+ *
+ * INFO: since IE >= 10 conditional comment are not working anymore
+ *
+ *
+ * HTML
+ *
+ * @param string $comment
+ *
+ * @return bool
+ */
+ private function isConditionalComment($comment): bool
+ {
+ if (\strpos($comment, '[if ') !== false) {
+ /** @noinspection RegExpRedundantEscape */
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\preg_match('/^\[if [^\]]+\]/', $comment)) {
+ return true;
+ }
+ }
+
+ if (\strpos($comment, '[endif]') !== false) {
+ /** @noinspection RegExpRedundantEscape */
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\preg_match('/\[endif\]$/', $comment)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if the current string is an special comment.
+ *
+ * @param string $comment
+ *
+ * @return bool
+ */
+ private function isSpecialComment($comment): bool
+ {
+ foreach ($this->specialHtmlCommentsStaringWith as $search) {
+ if (\strpos($comment, $search) === 0) {
+ return true;
+ }
+ }
+
+ foreach ($this->specialHtmlCommentsEndingWith as $search) {
+ if (\substr($comment, -\strlen($search)) === $search) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $html
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ private function minifyHtmlDom($html, $multiDecodeNewHtmlEntity): string
+ {
+ // init dom
+ $dom = new HtmlDomParser();
+ $dom->useKeepBrokenHtml($this->keepBrokenHtml);
+
+ if ($this->templateLogicSyntaxInSpecialScriptTags !== null) {
+ $dom->overwriteTemplateLogicSyntaxInSpecialScriptTags($this->templateLogicSyntaxInSpecialScriptTags);
+ }
+
+ if ($this->specialScriptTags !== null) {
+ $dom->overwriteSpecialScriptTags($this->specialScriptTags);
+ }
+
+ $dom->getDocument()->preserveWhiteSpace = false; // remove redundant white space
+ $dom->getDocument()->formatOutput = false; // do not formats output with indentation
+
+ // Remove content before because otherwise the DOMDocument can not handle the input.
+ if (\stripos($html, ']*)?>/sui', $html, $matches_before_doctype)
+ &&
+ \trim($matches_before_doctype[1])
+ ) {
+ $html = \str_replace($matches_before_doctype[1], '', $html);
+ }
+ }
+
+ // load dom
+ $dom->loadHtml($html);
+
+ $this->withDocType = (\stripos($html, 'getDoctype($dom->getDocument());
+
+ if ($doctypeStr) {
+ $this->isHTML4 = \strpos($doctypeStr, 'html4') !== false;
+ $this->isXHTML = \strpos($doctypeStr, 'xhtml1') !== false;
+ }
+
+ // -------------------------------------------------------------------------
+ // Protect HTML tags first.
+ // -------------------------------------------------------------------------
+
+ $dom = $this->protectTagHelper($dom, 'nocompress');
+
+ // -------------------------------------------------------------------------
+ // Notify the Observer before the minification.
+ // -------------------------------------------------------------------------
+
+ foreach ($dom->findMulti('*') as $element) {
+ $this->notifyObserversAboutDomElementBeforeMinification($element);
+ }
+
+ // -------------------------------------------------------------------------
+ // Protect HTML tags and conditional comments.
+ // -------------------------------------------------------------------------
+
+ $dom = $this->protectTags($dom);
+
+ // -------------------------------------------------------------------------
+ // Remove default HTML comments. [protected html is still protected]
+ // -------------------------------------------------------------------------
+
+ if ($this->doRemoveComments) {
+ $dom = $this->removeComments($dom);
+ }
+
+ // -------------------------------------------------------------------------
+ // Sum-Up extra whitespace from the Dom. [protected html is still protected]
+ // -------------------------------------------------------------------------
+
+ if ($this->doSumUpWhitespace) {
+ $dom = $this->sumUpWhitespace($dom);
+ }
+
+ foreach ($dom->findMulti('*') as $element) {
+ // -------------------------------------------------------------------------
+ // Remove whitespace around tags. [protected html is still protected]
+ // -------------------------------------------------------------------------
+
+ if ($this->doRemoveWhitespaceAroundTags) {
+ $this->removeWhitespaceAroundTags($element);
+ }
+
+ // -------------------------------------------------------------------------
+ // Notify the Observer after the minification.
+ // -------------------------------------------------------------------------
+
+ $this->notifyObserversAboutDomElementAfterMinification($element);
+ }
+
+ // -------------------------------------------------------------------------
+ // Convert the Dom into a string.
+ // -------------------------------------------------------------------------
+
+ return $dom->fixHtmlOutput(
+ $doctypeStr . $this->domNodeToString($dom->getDocument()),
+ $multiDecodeNewHtmlEntity
+ );
+ }
+
+ /**
+ * @param SimpleHtmlDomInterface $domElement
+ *
+ * @return void
+ */
+ private function notifyObserversAboutDomElementAfterMinification(SimpleHtmlDomInterface $domElement)
+ {
+ foreach ($this->domLoopObservers as $observer) {
+ $observer->domElementAfterMinification($domElement, $this);
+ }
+ }
+
+ /**
+ * @param SimpleHtmlDomInterface $domElement
+ *
+ * @return void
+ */
+ private function notifyObserversAboutDomElementBeforeMinification(SimpleHtmlDomInterface $domElement)
+ {
+ foreach ($this->domLoopObservers as $observer) {
+ $observer->domElementBeforeMinification($domElement, $this);
+ }
+ }
+
+ /**
+ * @param HtmlDomParser $dom
+ * @param string $selector
+ *
+ * @return HtmlDomParser
+ */
+ private function protectTagHelper(HtmlDomParser $dom, string $selector): HtmlDomParser
+ {
+ foreach ($dom->findMulti($selector) as $element) {
+ if ($element->isRemoved()) {
+ continue;
+ }
+
+ $parentNode = $element->parentNode();
+ if ($parentNode->nodeValue !== null) {
+ $this->protectedChildNodes[$this->protected_tags_counter] = $parentNode->innerHtml();
+ $parentNode->nodeValue = '<' . $this->protectedChildNodesHelper . ' data-' . $this->protectedChildNodesHelper . '="' . $this->protected_tags_counter . '">' . $this->protectedChildNodesHelper . '>';
+ }
+
+ ++$this->protected_tags_counter;
+ }
+
+ return $dom;
+ }
+
+ /**
+ * Prevent changes of inline "styles" and "scripts".
+ *
+ * @param HtmlDomParser $dom
+ *
+ * @return HtmlDomParser
+ */
+ private function protectTags(HtmlDomParser $dom): HtmlDomParser
+ {
+ $this->protectTagHelper($dom, 'code');
+
+ foreach ($dom->findMulti('script, style') as $element) {
+ if ($element->isRemoved()) {
+ continue;
+ }
+
+ if ($element->tag === 'script' || $element->tag === 'style') {
+ $attributes = $element->getAllAttributes();
+ // skip external links
+ if (isset($attributes['src'])) {
+ continue;
+ }
+ }
+
+ $this->protectedChildNodes[$this->protected_tags_counter] = $element->innerhtml;
+ $element->getNode()->nodeValue = '<' . $this->protectedChildNodesHelper . ' data-' . $this->protectedChildNodesHelper . '="' . $this->protected_tags_counter . '">' . $this->protectedChildNodesHelper . '>';
+
+ ++$this->protected_tags_counter;
+ }
+
+ foreach ($dom->findMulti('//comment()') as $element) {
+ if ($element->isRemoved()) {
+ continue;
+ }
+
+ $text = $element->text();
+
+ if (
+ !$this->isConditionalComment($text)
+ &&
+ !$this->isSpecialComment($text)
+ ) {
+ continue;
+ }
+
+ $this->protectedChildNodes[$this->protected_tags_counter] = '';
+
+ /* @var $node \DOMComment */
+ $node = $element->getNode();
+ $child = new \DOMText('<' . $this->protectedChildNodesHelper . ' data-' . $this->protectedChildNodesHelper . '="' . $this->protected_tags_counter . '">' . $this->protectedChildNodesHelper . '>');
+ $parentNode = $element->getNode()->parentNode;
+ if ($parentNode !== null) {
+ $parentNode->replaceChild($child, $node);
+ }
+
+ ++$this->protected_tags_counter;
+ }
+
+ return $dom;
+ }
+
+ /**
+ * Remove comments in the dom.
+ *
+ * @param HtmlDomParser $dom
+ *
+ * @return HtmlDomParser
+ */
+ private function removeComments(HtmlDomParser $dom): HtmlDomParser
+ {
+ foreach ($dom->findMulti('//comment()') as $commentWrapper) {
+ $comment = $commentWrapper->getNode();
+ $val = $comment->nodeValue;
+ if (\strpos($val, '[') === false) {
+ $parentNode = $comment->parentNode;
+ if ($parentNode !== null) {
+ $parentNode->removeChild($comment);
+ }
+ }
+ }
+
+ $dom->getDocument()->normalizeDocument();
+
+ return $dom;
+ }
+
+ /**
+ * Trim tags in the dom.
+ *
+ * @param SimpleHtmlDomInterface $element
+ *
+ * @return void
+ */
+ private function removeWhitespaceAroundTags(SimpleHtmlDomInterface $element)
+ {
+ if (isset(self::$trimWhitespaceFromTags[$element->tag])) {
+ $node = $element->getNode();
+
+ /** @var \DOMNode[] $candidates */
+ $candidates = [];
+ if ($node->childNodes->length > 0) {
+ $candidates[] = $node->firstChild;
+ $candidates[] = $node->lastChild;
+ $candidates[] = $node->previousSibling;
+ $candidates[] = $node->nextSibling;
+ }
+
+ /** @var mixed $candidate - false-positive error from phpstan */
+ foreach ($candidates as &$candidate) {
+ if ($candidate === null) {
+ continue;
+ }
+
+ if ($candidate->nodeType === \XML_TEXT_NODE) {
+ $nodeValueTmp = \preg_replace(self::$regExSpace, ' ', $candidate->nodeValue);
+ if ($nodeValueTmp !== null) {
+ $candidate->nodeValue = $nodeValueTmp;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback function for preg_replace_callback use.
+ *
+ * @param array $matches PREG matches
+ *
+ * @return string
+ */
+ private function restoreProtectedHtml($matches): string
+ {
+ \preg_match('/.*"(?\d*)"/', $matches['attributes'], $matchesInner);
+
+ return $this->protectedChildNodes[$matchesInner['id']] ?? '';
+ }
+
+ /**
+ * @param string[] $domainsToRemoveHttpPrefixFromAttributes
+ *
+ * @return $this
+ */
+ public function setDomainsToRemoveHttpPrefixFromAttributes($domainsToRemoveHttpPrefixFromAttributes): self
+ {
+ $this->domainsToRemoveHttpPrefixFromAttributes = $domainsToRemoveHttpPrefixFromAttributes;
+
+ return $this;
+ }
+
+ /**
+ * @param string[] $startingWith
+ * @param string[] $endingWith
+ *
+ * @return $this
+ */
+ public function setSpecialHtmlComments(array $startingWith, array $endingWith = []): self
+ {
+ $this->specialHtmlCommentsStaringWith = $startingWith;
+ $this->specialHtmlCommentsEndingWith = $endingWith;
+
+ return $this;
+ }
+
+ /**
+ * Sum-up extra whitespace from dom-nodes.
+ *
+ * @param HtmlDomParser $dom
+ *
+ * @return HtmlDomParser
+ */
+ private function sumUpWhitespace(HtmlDomParser $dom): HtmlDomParser
+ {
+ foreach ($dom->findMulti('//text()') as $text_node_wrapper) {
+ /* @var $text_node \DOMNode */
+ $text_node = $text_node_wrapper->getNode();
+ $xp = $text_node->getNodePath();
+ if ($xp === null) {
+ continue;
+ }
+
+ $doSkip = false;
+ foreach (self::$skipTagsForRemoveWhitespace as $pattern) {
+ if (\strpos($xp, '/' . $pattern) !== false) {
+ $doSkip = true;
+
+ break;
+ }
+ }
+ if ($doSkip) {
+ continue;
+ }
+
+ $nodeValueTmp = \preg_replace(self::$regExSpace, ' ', $text_node->nodeValue);
+ if ($nodeValueTmp !== null) {
+ $text_node->nodeValue = $nodeValueTmp;
+ }
+ }
+
+ $dom->getDocument()->normalizeDocument();
+
+ return $dom;
+ }
+
+ /**
+ * WARNING: maybe bad for performance ...
+ *
+ * @param bool $keepBrokenHtml
+ *
+ * @return HtmlMin
+ */
+ public function useKeepBrokenHtml(bool $keepBrokenHtml): self
+ {
+ $this->keepBrokenHtml = $keepBrokenHtml;
+
+ return $this;
+ }
+
+ /**
+ * @param string[] $templateLogicSyntaxInSpecialScriptTags
+ *
+ * @return HtmlMin
+ */
+ public function overwriteTemplateLogicSyntaxInSpecialScriptTags(array $templateLogicSyntaxInSpecialScriptTags): self
+ {
+ foreach ($templateLogicSyntaxInSpecialScriptTags as $tmp) {
+ if (!\is_string($tmp)) {
+ throw new \InvalidArgumentException('setTemplateLogicSyntaxInSpecialScriptTags only allows string[]');
+ }
+ }
+
+ $this->templateLogicSyntaxInSpecialScriptTags = $templateLogicSyntaxInSpecialScriptTags;
+
+ return $this;
+ }
+
+
+ /**
+ * @param string[] $specialScriptTags
+ *
+ * @return HtmlDomParser
+ */
+ public function overwriteSpecialScriptTags(array $specialScriptTags): self
+ {
+ foreach ($specialScriptTags as $tag) {
+ if (!\is_string($tag)) {
+ throw new \InvalidArgumentException('SpecialScriptTags only allows string[]');
+ }
+ }
+
+ $this->specialScriptTags = $specialScriptTags;
+
+ return $this;
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php b/includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php
new file mode 100644
index 0000000..ead6eea
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/HtmlMinDomObserverInterface.php
@@ -0,0 +1,28 @@
+
+ */
+ private static $executableScriptsMimeTypes = [
+ 'text/javascript' => '',
+ 'text/ecmascript' => '',
+ 'text/jscript' => '',
+ 'application/javascript' => '',
+ 'application/x-javascript' => '',
+ 'application/ecmascript' => '',
+ ];
+
+ /**
+ * Receive dom elements before the minification.
+ *
+ * @param SimpleHtmlDomInterface $element
+ * @param HtmlMinInterface $htmlMin
+ *
+ * @return void
+ */
+ public function domElementBeforeMinification(SimpleHtmlDomInterface $element, HtmlMinInterface $htmlMin)
+ {
+ }
+
+ /**
+ * Receive dom elements after the minification.
+ *
+ * @param SimpleHtmlDomInterface $element
+ * @param HtmlMinInterface $htmlMin
+ *
+ * @return void
+ */
+ public function domElementAfterMinification(SimpleHtmlDomInterface $element, HtmlMinInterface $htmlMin)
+ {
+ $attributes = $element->getAllAttributes();
+ if ($attributes === null) {
+ return;
+ }
+
+ $tagName = $element->getNode()->nodeName;
+ $attrs = [];
+ foreach ((array) $attributes as $attrName => $attrValue) {
+ // -------------------------------------------------------------------------
+ // Remove local domains from attributes.
+ // -------------------------------------------------------------------------
+
+ if ($htmlMin->isDoMakeSameDomainsLinksRelative()) {
+ $localDomains = $htmlMin->getLocalDomains();
+ foreach ($localDomains as $localDomain) {
+ /** @noinspection InArrayCanBeUsedInspection */
+ if (
+ (
+ $attrName === 'href'
+ ||
+ $attrName === 'src'
+ ||
+ $attrName === 'srcset'
+ ||
+ $attrName === 'action'
+ )
+ &&
+ !(isset($attributes['rel']) && $attributes['rel'] === 'external')
+ &&
+ !(isset($attributes['target']) && $attributes['target'] === '_blank')
+ &&
+ \stripos($attrValue, $localDomain) !== false
+ ) {
+ $localDomainEscaped = \preg_quote($localDomain, '/');
+
+ $attrValue = (string) \preg_replace("/^(?:(?:https?:)?\/\/)?{$localDomainEscaped}(?!\w)(?:\/?)/i", '/', $attrValue);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Remove optional "http:"-prefix from attributes.
+ // -------------------------------------------------------------------------
+
+ if ($htmlMin->isDoRemoveHttpPrefixFromAttributes()) {
+ $attrValue = $this->removeUrlSchemeHelper(
+ $attrValue,
+ $attrName,
+ 'http',
+ $attributes,
+ $tagName,
+ $htmlMin
+ );
+ }
+
+ if ($htmlMin->isDoRemoveHttpsPrefixFromAttributes()) {
+ $attrValue = $this->removeUrlSchemeHelper(
+ $attrValue,
+ $attrName,
+ 'https',
+ $attributes,
+ $tagName,
+ $htmlMin
+ );
+ }
+
+ // -------------------------------------------------------------------------
+ // Remove some special attributes.
+ // -------------------------------------------------------------------------
+
+ if ($this->removeAttributeHelper(
+ $element->tag,
+ $attrName,
+ $attrValue,
+ $attributes,
+ $htmlMin
+ )) {
+ $element->{$attrName} = null;
+
+ continue;
+ }
+
+ // -------------------------------------------------------------------------
+ // Sort css-class-Powered_Cache_names, for better gzip results.
+ // -------------------------------------------------------------------------
+
+ if ($htmlMin->isDoSortCssClassNames()) {
+ $attrValue = $this->sortCssClassNames($attrName, $attrValue);
+ }
+
+ if ($htmlMin->isDoSortHtmlAttributes()) {
+ $attrs[$attrName] = $attrValue;
+ $element->{$attrName} = null;
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Sort html-attributes, for better gzip results.
+ // -------------------------------------------------------------------------
+
+ if ($htmlMin->isDoSortHtmlAttributes()) {
+ \ksort($attrs);
+ foreach ($attrs as $attrName => $attrValue) {
+ $attrValue = HtmlDomParser::replaceToPreserveHtmlEntities($attrValue);
+ $element->setAttribute((string) $attrName, $attrValue, true);
+ }
+ }
+ }
+
+ /**
+ * Check if the attribute can be removed.
+ *
+ * @param string $tag
+ * @param string $attrName
+ * @param string $attrValue
+ * @param array $allAttr
+ * @param HtmlMinInterface $htmlMin
+ *
+ * @return bool
+ */
+ private function removeAttributeHelper($tag, $attrName, $attrValue, $allAttr, HtmlMinInterface $htmlMin): bool
+ {
+ // remove defaults
+ if ($htmlMin->isDoRemoveDefaultAttributes()) {
+ if ($tag === 'script' && $attrName === 'language' && $attrValue === 'javascript') {
+ return true;
+ }
+
+ if ($tag === 'form' && $attrName === 'method' && $attrValue === 'get') {
+ return true;
+ }
+
+ if ($tag === 'form' && $attrName === 'autocomplete' && $attrValue === 'on') {
+ return true;
+ }
+
+ if ($tag === 'form' && $attrName === 'enctype' && $attrValue === 'application/x-www-form-urlencoded') {
+ return true;
+ }
+
+ if ($tag === 'input' && $attrName === 'type' && $attrValue === 'text') {
+ return true;
+ }
+
+ if ($tag === 'textarea' && $attrName === 'wrap' && $attrValue === 'soft') {
+ return true;
+ }
+
+ if ($tag === 'area' && $attrName === 'shape' && $attrValue === 'rect') {
+ return true;
+ }
+
+ if ($tag === 'th' && $attrName === 'scope' && $attrValue === 'auto') {
+ return true;
+ }
+
+ if ($tag === 'ol' && $attrName === 'type' && $attrValue === 'decimal') {
+ return true;
+ }
+
+ if ($tag === 'ol' && $attrName === 'start' && $attrValue === '1') {
+ return true;
+ }
+
+ if ($tag === 'track' && $attrName === 'kind' && $attrValue === 'subtitles') {
+ return true;
+ }
+
+ if ($attrName === 'spellcheck' && $attrValue === 'default') {
+ return true;
+ }
+
+ if ($attrName === 'draggable' && $attrValue === 'auto') {
+ return true;
+ }
+ }
+
+ // remove deprecated charset-attribute (the browser will use the charset from the HTTP-Header, anyway)
+ if ($htmlMin->isDoRemoveDeprecatedScriptCharsetAttribute()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($tag === 'script' && $attrName === 'charset' && !isset($allAttr['src'])) {
+ return true;
+ }
+ }
+
+ // remove deprecated anchor-jump
+ if ($htmlMin->isDoRemoveDeprecatedAnchorName()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($tag === 'a' && $attrName === 'name' && isset($allAttr['id']) && $allAttr['id'] === $attrValue) {
+ return true;
+ }
+ }
+
+ if ($htmlMin->isDoRemoveDefaultMediaTypeFromStyleAndLinkTag()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (($tag === 'link' || $tag === 'style') && $attrName === 'media' && $attrValue === 'all') {
+ return true;
+ }
+ }
+
+ // remove "type=text/css" for css "stylesheet"-links
+ if ($htmlMin->isDoRemoveDeprecatedTypeFromStylesheetLink()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($tag === 'link' && $attrName === 'type' && $attrValue === 'text/css' && isset($allAttr['rel']) && $allAttr['rel'] === 'stylesheet' && $htmlMin->isXHTML() === false && $htmlMin->isHTML4() === false) {
+ return true;
+ }
+ }
+ // remove deprecated css-mime-types
+ if ($htmlMin->isDoRemoveDeprecatedTypeFromStyleAndLinkTag()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (($tag === 'link' || $tag === 'style') && $attrName === 'type' && $attrValue === 'text/css' && $htmlMin->isXHTML() === false && $htmlMin->isHTML4() === false) {
+ return true;
+ }
+ }
+
+ // remove deprecated script-mime-types
+ if ($htmlMin->isDoRemoveDeprecatedTypeFromScriptTag()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($tag === 'script' && $attrName === 'type' && isset(self::$executableScriptsMimeTypes[$attrValue]) && $htmlMin->isXHTML() === false && $htmlMin->isHTML4() === false) {
+ return true;
+ }
+ }
+
+ // remove 'type=submit' from
+ if ($htmlMin->isDoRemoveDefaultTypeFromButton()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($tag === 'button' && $attrName === 'type' && $attrValue === 'submit') {
+ return true;
+ }
+ }
+
+ // remove 'value=""' from
+ if ($htmlMin->isDoRemoveValueFromEmptyInput()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($tag === 'input' && $attrName === 'value' && $attrValue === '' && isset($allAttr['type']) && $allAttr['type'] === 'text') {
+ return true;
+ }
+ }
+
+ // remove some empty attributes
+ if ($htmlMin->isDoRemoveEmptyAttributes()) {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\trim($attrValue) === '' && \preg_match('/^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$/', $attrName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $attrValue
+ * @param string $attrName
+ * @param string $scheme
+ * @param string[] $attributes
+ * @param string $tagName
+ * @param HtmlMinInterface $htmlMin
+ *
+ * @return string
+ *
+ * @noinspection PhpTooManyParametersInspection
+ */
+ private function removeUrlSchemeHelper(
+ string $attrValue,
+ string $attrName,
+ string $scheme,
+ array $attributes,
+ string $tagName,
+ HtmlMinInterface $htmlMin
+ ): string {
+ /** @noinspection InArrayCanBeUsedInspection */
+ if (
+ !(isset($attributes['rel']) && $attributes['rel'] === 'external')
+ &&
+ !(isset($attributes['target']) && $attributes['target'] === '_blank')
+ &&
+ (
+ (
+ $attrName === 'href'
+ &&
+ (
+ !$htmlMin->isdoKeepHttpAndHttpsPrefixOnExternalAttributes()
+ ||
+ $tagName === 'link'
+ )
+ )
+ ||
+ $attrName === 'src'
+ ||
+ $attrName === 'srcset'
+ ||
+ $attrName === 'action'
+ )
+ ) {
+ $attrValue = \str_replace($scheme . '://', '//', $attrValue);
+ }
+
+ return $attrValue;
+ }
+
+ /**
+ * @param string $attrName
+ * @param string $attrValue
+ *
+ * @return string
+ */
+ private function sortCssClassNames($attrName, $attrValue): string
+ {
+ if ($attrName !== 'class' || !$attrValue) {
+ return $attrValue;
+ }
+
+ $classes = \array_unique(
+ \explode(' ', $attrValue)
+ );
+ \sort($classes);
+
+ $attrValue = '';
+ foreach ($classes as $class) {
+ if (!$class) {
+ continue;
+ }
+
+ $attrValue .= \trim($class) . ' ';
+ }
+
+ return \trim($attrValue);
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/HtmlMinInterface.php b/includes/classes/Dependencies/voku/helper/HtmlMinInterface.php
new file mode 100644
index 0000000..99c9c53
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/HtmlMinInterface.php
@@ -0,0 +1,154 @@
+
+ */
+ protected static $compiled = [];
+
+ /**
+ * @param string $selector
+ * @param bool $ignoreCssSelectorErrors
+ *
+ * Ignore css selector errors and use the $selector as it is on error,
+ * so that you can also use xPath selectors.
+ *
+ * @param bool $isForHtml
+ *
+ * @return string
+ */
+ public static function toXPath(string $selector, bool $ignoreCssSelectorErrors = false, bool $isForHtml = true)
+ {
+ if (isset(self::$compiled[$selector])) {
+ return self::$compiled[$selector];
+ }
+
+ // Select DOMText
+ if ($selector === 'text') {
+ return '//text()';
+ }
+
+ // Select DOMComment
+ if ($selector === 'comment') {
+ return '//comment()';
+ }
+
+ if (\strpos($selector, '//') === 0) {
+ return $selector;
+ }
+
+ if (!\class_exists(CssSelectorConverter::class)) {
+ throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector 2.8+ is not installed (you can use filterXPath instead).');
+ }
+
+ $converterKey = '-' . $isForHtml . '-' . $ignoreCssSelectorErrors . '-';
+ static $converterArray = [];
+ if (!isset($converterArray[$converterKey])) {
+ $converterArray[$converterKey] = new CssSelectorConverter($isForHtml);
+ }
+ $converter = $converterArray[$converterKey];
+ assert($converter instanceof CssSelectorConverter);
+
+ if ($ignoreCssSelectorErrors) {
+ try {
+ $xPathQuery = $converter->toXPath($selector);
+ } catch (\Exception $e) {
+ $xPathQuery = $selector;
+ }
+ } else {
+ $xPathQuery = $converter->toXPath($selector);
+ }
+
+ self::$compiled[$selector] = $xPathQuery;
+
+ return $xPathQuery;
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php
new file mode 100644
index 0000000..4da7bc5
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributes.php
@@ -0,0 +1,269 @@
+
+ */
+ private $tokens = [];
+
+ /**
+ * @var string|null
+ */
+ private $previousValue;
+
+ /**
+ * Creates a list of space-separated tokens based on the attribute value of an element.
+ *
+ * @param \DOMElement|null $element
+ * The DOM element.
+ * @param string $attributeName
+ * The name of the attribute.
+ */
+ public function __construct($element, string $attributeName)
+ {
+ $this->element = $element;
+ $this->attributeName = $attributeName;
+
+ $this->tokenize();
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+
+ /**
+ * Returns the value for the property specified.
+ *
+ * @param string $name The name of the property
+ *
+ * @return int|string The value of the property specified
+ */
+ public function __get(string $name)
+ {
+ if ($name === 'length') {
+ $this->tokenize();
+
+ return \count($this->tokens);
+ }
+
+ if ($name === 'value') {
+ return (string) $this;
+ }
+
+ throw new \InvalidArgumentException('Undefined property: $' . $name);
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString(): string
+ {
+ $this->tokenize();
+
+ return \implode(' ', $this->tokens);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(string ...$tokens)
+ {
+ if (\count($tokens) === 0) {
+ return null;
+ }
+
+ foreach ($tokens as $t) {
+ if (\in_array($t, $this->tokens, true)) {
+ continue;
+ }
+
+ $this->tokens[] = $t;
+ }
+
+ return $this->setAttributeValue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function contains(string $token): bool
+ {
+ $this->tokenize();
+
+ return \in_array($token, $this->tokens, true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function entries(): \ArrayIterator
+ {
+ $this->tokenize();
+
+ return new \ArrayIterator($this->tokens);
+ }
+
+ public function item(int $index)
+ {
+ $this->tokenize();
+ if ($index >= \count($this->tokens)) {
+ return null;
+ }
+
+ return $this->tokens[$index];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove(string ...$tokens)
+ {
+ if (\count($tokens) === 0) {
+ return null;
+ }
+
+ if (\count($this->tokens) === 0) {
+ return null;
+ }
+
+ foreach ($tokens as $t) {
+ $i = \array_search($t, $this->tokens, true);
+ if ($i === false) {
+ continue;
+ }
+
+ \array_splice($this->tokens, $i, 1);
+ }
+
+ return $this->setAttributeValue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function replace(string $old, string $new)
+ {
+ if ($old === $new) {
+ return null;
+ }
+
+ $this->tokenize();
+ $i = \array_search($old, $this->tokens, true);
+ if ($i !== false) {
+ $j = \array_search($new, $this->tokens, true);
+ if ($j === false) {
+ $this->tokens[$i] = $new;
+ } else {
+ \array_splice($this->tokens, $i, 1);
+ }
+
+ return $this->setAttributeValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toggle(string $token, bool $force = null): bool
+ {
+ // init
+ $this->tokenize();
+ $isThereAfter = false;
+
+ $i = \array_search($token, $this->tokens, true);
+ if ($force === null) {
+ if ($i === false) {
+ $this->tokens[] = $token;
+ $isThereAfter = true;
+ } else {
+ \array_splice($this->tokens, $i, 1);
+ }
+ } elseif ($force) {
+ if ($i === false) {
+ $this->tokens[] = $token;
+ }
+ $isThereAfter = true;
+ } else {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if ($i !== false) {
+ \array_splice($this->tokens, $i, 1);
+ }
+ }
+
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->setAttributeValue();
+
+ return $isThereAfter;
+ }
+
+ /**
+ * @return \DOMAttr|false|null
+ */
+ private function setAttributeValue()
+ {
+ if ($this->element === null) {
+ return false;
+ }
+
+ $value = \implode(' ', $this->tokens);
+ if ($this->previousValue === $value) {
+ return null;
+ }
+
+ $this->previousValue = $value;
+
+ return $this->element->setAttribute($this->attributeName, $value);
+ }
+
+ /**
+ * @return void
+ */
+ private function tokenize()
+ {
+ if ($this->element === null) {
+ return;
+ }
+
+ $current = $this->element->getAttribute($this->attributeName);
+ if ($this->previousValue === $current) {
+ return;
+ }
+
+ $this->previousValue = $current;
+ $tokens = \explode(' ', $current);
+ $finals = [];
+ foreach ($tokens as $token) {
+ if ($token === '') {
+ continue;
+ }
+
+ if (\in_array($token, $finals, true)) {
+ continue;
+ }
+
+ $finals[] = $token;
+ }
+
+ $this->tokens = $finals;
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php
new file mode 100644
index 0000000..d1f0261
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlAttributesInterface.php
@@ -0,0 +1,82 @@
+The tokens you want to add to the list.
+ *
+ * @return \DOMAttr|false|null
+ */
+ public function add(string ...$tokens);
+
+ /**
+ * Returns true if the list contains the given token, otherwise false.
+ *
+ * @param string $token the token you want to check for the existence of in the list
+ *
+ * @return bool true if the list contains the given token, otherwise false
+ */
+ public function contains(string $token): bool;
+
+ /**
+ * Returns an iterator allowing you to go through all tokens contained in the list.
+ *
+ * @return \ArrayIterator
+ */
+ public function entries(): \ArrayIterator;
+
+ /**
+ * Returns an item in the list by its index (returns null if the number is greater than or equal to the length of
+ * the list).
+ *
+ * @param int $index the zero-based index of the item you want to return
+ *
+ * @return string|null
+ */
+ public function item(int $index);
+
+ /**
+ * Removes the specified tokens from the list. If the string does not exist in the list, no error is thrown.
+ *
+ * @param string ...$tokens
+ * The token you want to remove from the list.>
+ *
+ * @return \DOMAttr|false|null
+ */
+ public function remove(string ...$tokens);
+
+ /**
+ * Replaces an existing token with a new token.
+ *
+ * @param string $old the token you want to replace
+ * @param string $new the token you want to replace $old with
+ *
+ * @return \DOMAttr|false|null
+ */
+ public function replace(string $old, string $new);
+
+ /**
+ * Removes a given token from the list and returns false. If token doesn't exist it's added and the function
+ * returns true.
+ *
+ * @param string $token the token you want to toggle
+ * @param bool $force A Boolean that, if included, turns the toggle into a one way-only operation. If set to
+ * false, the token will only be removed but not added again. If set to true, the token will
+ * only be added but not removed again.
+ *
+ * @return bool false if the token is not in the list after the call, or true if the token is in the list after the
+ * call
+ */
+ public function toggle(string $token, bool $force = null): bool;
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php
new file mode 100644
index 0000000..8059186
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlDom.php
@@ -0,0 +1,1011 @@
+
+ */
+class SimpleHtmlDom extends AbstractSimpleHtmlDom implements \IteratorAggregate, SimpleHtmlDomInterface
+{
+ /**
+ * @param \DOMElement|\DOMNode $node
+ */
+ public function __construct(\DOMNode $node)
+ {
+ $this->node = $node;
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleHtmlDomInterface|string|null
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /**
+ * Find list of nodes with a CSS selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null)
+ {
+ return $this->getHtmlDomParser()->find($selector, $idx);
+ }
+
+ public function getTag(): string
+ {
+ return $this->tag;
+ }
+
+ /**
+ * Returns an array of attributes.
+ *
+ * @return string[]|null
+ */
+ public function getAllAttributes()
+ {
+ if (
+ $this->node
+ &&
+ $this->node->hasAttributes()
+ ) {
+ $attributes = [];
+ foreach ($this->node->attributes ?? [] as $attr) {
+ $attributes[$attr->name] = HtmlDomParser::putReplacedBackToPreserveHtmlEntities($attr->value);
+ }
+
+ return $attributes;
+ }
+
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasAttributes(): bool
+ {
+ return $this->node && $this->node->hasAttributes();
+ }
+
+ /**
+ * Return attribute value.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function getAttribute(string $name): string
+ {
+ if ($this->node instanceof \DOMElement) {
+ return HtmlDomParser::putReplacedBackToPreserveHtmlEntities(
+ $this->node->getAttribute($name)
+ );
+ }
+
+ return '';
+ }
+
+ /**
+ * Determine if an attribute exists on the element.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasAttribute(string $name): bool
+ {
+ if (!$this->node instanceof \DOMElement) {
+ return false;
+ }
+
+ return $this->node->hasAttribute($name);
+ }
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function html(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return $this->getHtmlDomParser()->html($multiDecodeNewHtmlEntity);
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
+ {
+ return $this->getHtmlDomParser()->innerHtml($multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
+ }
+
+ /**
+ * Remove attribute.
+ *
+ * @param string $name The name of the html-attribute.
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function removeAttribute(string $name): SimpleHtmlDomInterface
+ {
+ if (\method_exists($this->node, 'removeAttribute')) {
+ $this->node->removeAttribute($name);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Remove all attributes
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function removeAttributes(): SimpleHtmlDomInterface
+ {
+ if ($this->hasAttributes()) {
+ foreach (array_keys((array)$this->getAllAttributes()) as $attribute) {
+ $this->removeAttribute($attribute);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Replace child node.
+ *
+ * @param string $string
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface
+ {
+ if (!empty($string)) {
+ $newDocument = new HtmlDomParser($string);
+
+ $tmpDomString = $this->normalizeStringForComparison($newDocument);
+ $tmpStr = $this->normalizeStringForComparison($string);
+
+ if ($tmpDomString !== $tmpStr) {
+ throw new \RuntimeException(
+ 'Not valid HTML fragment!' . "\n" .
+ $tmpDomString . "\n" .
+ $tmpStr
+ );
+ }
+ }
+
+ /** @var \DOMNode[] $remove_nodes */
+ $remove_nodes = [];
+ if ($this->node->childNodes->length > 0) {
+ // INFO: We need to fetch the nodes first, before we can delete them, because of missing references in the dom,
+ // if we delete the elements on the fly.
+ foreach ($this->node->childNodes as $node) {
+ $remove_nodes[] = $node;
+ }
+ }
+ foreach ($remove_nodes as $remove_node) {
+ $this->node->removeChild($remove_node);
+ }
+
+ if (!empty($newDocument)) {
+ $newDocument = $this->cleanHtmlWrapper($newDocument);
+ $ownerDocument = $this->node->ownerDocument;
+ if (
+ $ownerDocument
+ &&
+ $newDocument->getDocument()->documentElement
+ ) {
+ $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
+ $this->node->appendChild($newNode);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Replace this node.
+ *
+ * @param string $string
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface
+ {
+ if (empty($string)) {
+ if ($this->node->parentNode) {
+ $this->node->parentNode->removeChild($this->node);
+ }
+ $this->node = new \DOMText();
+
+ return $this;
+ }
+
+ $newDocument = new HtmlDomParser($string);
+
+ $tmpDomOuterTextString = $this->normalizeStringForComparison($newDocument);
+ $tmpStr = $this->normalizeStringForComparison($string);
+
+ if ($tmpDomOuterTextString !== $tmpStr) {
+ throw new \RuntimeException(
+ 'Not valid HTML fragment!' . "\n"
+ . $tmpDomOuterTextString . "\n" .
+ $tmpStr
+ );
+ }
+
+ $newDocument = $this->cleanHtmlWrapper($newDocument, true);
+ $ownerDocument = $this->node->ownerDocument;
+ if (
+ $ownerDocument === null
+ ||
+ $newDocument->getDocument()->documentElement === null
+ ) {
+ return $this;
+ }
+
+ $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
+
+ $this->node->parentNode->replaceChild($newNode, $this->node);
+ $this->node = $newNode;
+
+ // Remove head element, preserving child nodes. (again)
+ if (
+ $this->node->parentNode instanceof \DOMElement
+ &&
+ $newDocument->getIsDOMDocumentCreatedWithoutHeadWrapper()
+ ) {
+ $html = $this->node->parentNode->getElementsByTagName('head')[0];
+
+ if (
+ $html !== null
+ &&
+ $this->node->parentNode->ownerDocument
+ ) {
+ $fragment = $this->node->parentNode->ownerDocument->createDocumentFragment();
+ /** @var \DOMNode $html */
+ while ($html->childNodes->length > 0) {
+ $tmpNode = $html->childNodes->item(0);
+ if ($tmpNode !== null) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $fragment->appendChild($tmpNode);
+ }
+ }
+ $html->parentNode->replaceChild($fragment, $html);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Replace this node with text
+ *
+ * @param string $string
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ protected function replaceTextWithString($string): SimpleHtmlDomInterface
+ {
+ if (empty($string)) {
+ if ($this->node->parentNode) {
+ $this->node->parentNode->removeChild($this->node);
+ }
+ $this->node = new \DOMText();
+
+ return $this;
+ }
+
+ $ownerDocument = $this->node->ownerDocument;
+ if ($ownerDocument) {
+ $newElement = $ownerDocument->createTextNode($string);
+ $newNode = $ownerDocument->importNode($newElement, true);
+ $this->node->parentNode->replaceChild($newNode, $this->node);
+ $this->node = $newNode;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set attribute value.
+ *
+ * @param string $name The name of the html-attribute.
+ * @param string|null $value Set to NULL or empty string, to remove the attribute.
+ * @param bool $strictEmptyValueCheck
+ * $value must be NULL, to remove the attribute,
+ * so that you can set an empty string as attribute-value e.g. autofocus=""
+ *
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface
+ {
+ if (
+ ($strictEmptyValueCheck && $value === null)
+ ||
+ (!$strictEmptyValueCheck && empty($value))
+ ) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->removeAttribute($name);
+ } elseif (\method_exists($this->node, 'setAttribute')) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->node->setAttribute($name, HtmlDomParser::replaceToPreserveHtmlEntities((string) $value));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @return string
+ */
+ public function text(): string
+ {
+ return $this->getHtmlDomParser()->fixHtmlOutput($this->node->textContent);
+ }
+
+ /**
+ * Change the name of a tag in a "DOMNode".
+ *
+ * @param \DOMNode $node
+ * @param string $name
+ *
+ * @return \DOMElement|false
+ * DOMElement a new instance of class DOMElement or false
+ * if an error occurred.
+ */
+ protected function changeElementName(\DOMNode $node, string $name)
+ {
+ $ownerDocument = $node->ownerDocument;
+ if (!$ownerDocument) {
+ return false;
+ }
+
+ $newNode = $ownerDocument->createElement($name);
+
+ foreach ($node->childNodes as $child) {
+ $child = $ownerDocument->importNode($child, true);
+ $newNode->appendChild($child);
+ }
+
+ foreach ($node->attributes ?? [] as $attrName => $attrNode) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $newNode->setAttribute($attrName, $attrNode);
+ }
+
+ if ($newNode->ownerDocument) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $newNode->ownerDocument->replaceChild($newNode, $node);
+ }
+
+ return $newNode;
+ }
+
+ /**
+ * Returns children of node.
+ *
+ * @param int $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface|null
+ */
+ public function childNodes(int $idx = -1)
+ {
+ $nodeList = $this->getIterator();
+
+ if ($idx === -1) {
+ return $nodeList;
+ }
+
+ return $nodeList[$idx] ?? null;
+ }
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleHtmlDomNodeInterface
+ {
+ return $this->getHtmlDomParser()->findMulti($selector);
+ }
+
+ /**
+ * Find nodes with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ return $this->getHtmlDomParser()->findMultiOrFalse($selector);
+ }
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function findOne(string $selector): SimpleHtmlDomInterface
+ {
+ return $this->getHtmlDomParser()->findOne($selector);
+ }
+
+ /**
+ * Find one node with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomInterface
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ return $this->getHtmlDomParser()->findOneOrFalse($selector);
+ }
+
+ /**
+ * Returns the first child of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function firstChild()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->firstChild;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function getElementByClass(string $class): SimpleHtmlDomNodeInterface
+ {
+ return $this->findMulti(".{$class}");
+ }
+
+ /**
+ * Return element by #id.
+ *
+ * @param string $id
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function getElementById(string $id): SimpleHtmlDomInterface
+ {
+ return $this->findOne("#{$id}");
+ }
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function getElementByTagName(string $name): SimpleHtmlDomInterface
+ {
+ if ($this->node instanceof \DOMElement) {
+ $node = $this->node->getElementsByTagName($name)->item(0);
+ } else {
+ $node = null;
+ }
+
+ if ($node === null) {
+ return new SimpleHtmlDomBlank();
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null)
+ {
+ return $this->find("#{$id}", $idx);
+ }
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null)
+ {
+ if ($this->node instanceof \DOMElement) {
+ $nodesList = $this->node->getElementsByTagName($name);
+ } else {
+ $nodesList = [];
+ }
+
+ $elements = new SimpleHtmlDomNode();
+
+ foreach ($nodesList as $node) {
+ $elements[] = new static($node);
+ }
+
+ // return all elements
+ if ($idx === null) {
+ if (\count($elements) === 0) {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ return $elements;
+ }
+
+ // handle negative values
+ if ($idx < 0) {
+ $idx = \count($elements) + $idx;
+ }
+
+ // return one element
+ return $elements[$idx] ?? new SimpleHtmlDomBlank();
+ }
+
+ /**
+ * Create a new "HtmlDomParser"-object from the current context.
+ *
+ * @return HtmlDomParser
+ */
+ public function getHtmlDomParser(): HtmlDomParser
+ {
+ return new HtmlDomParser($this);
+ }
+
+ /**
+ * @return \DOMNode
+ */
+ public function getNode(): \DOMNode
+ {
+ return $this->node;
+ }
+
+ /**
+ * Nodes can get partially destroyed in which they're still an
+ * actual DOM node (such as \DOMElement) but almost their entire
+ * body is gone, including the `nodeType` attribute.
+ *
+ * @return bool true if node has been destroyed
+ */
+ public function isRemoved(): bool
+ {
+ return !isset($this->node->nodeType);
+ }
+
+ /**
+ * Returns the last child of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function lastChild()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->lastChild;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function nextSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->nextSibling;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function nextNonWhitespaceSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->nextSibling;
+
+ while ($node && !\trim($node->textContent)) {
+ /** @var \DOMNode|null $node */
+ $node = $node->nextSibling;
+ }
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the parent of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function parentNode(): ?SimpleHtmlDomInterface
+ {
+ if ($node = $this->node->parentNode) {
+ return new static($node);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function previousSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->previousSibling;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function previousNonWhitespaceSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->previousSibling;
+
+ while ($node && !\trim($node->textContent)) {
+ /** @var \DOMNode|null $node */
+ $node = $node->previousSibling;
+ }
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * @param string|string[]|null $value
+ * null === get the current input value
+ * text === set a new input value
+ *
+ *
+ * @return string|string[]|null
+ */
+ public function val($value = null)
+ {
+ if ($value === null) {
+ if (
+ $this->tag === 'input'
+ &&
+ (
+ $this->getAttribute('type') === 'hidden'
+ ||
+ $this->getAttribute('type') === 'text'
+ ||
+ !$this->hasAttribute('type')
+ )
+ ) {
+ return $this->getAttribute('value');
+ }
+
+ if (
+ $this->hasAttribute('checked')
+ &&
+ \in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)
+ ) {
+ return $this->getAttribute('value');
+ }
+
+ if ($this->node->nodeName === 'select') {
+ $valuesFromDom = [];
+ $options = $this->getElementsByTagName('option');
+ if ($options instanceof SimpleHtmlDomNode) {
+ foreach ($options as $option) {
+ if ($this->hasAttribute('checked')) {
+ $valuesFromDom[] = (string) $option->getAttribute('value');
+ }
+ }
+ }
+
+ if (\count($valuesFromDom) === 0) {
+ return null;
+ }
+
+ return $valuesFromDom;
+ }
+
+ if ($this->node->nodeName === 'textarea') {
+ return $this->node->nodeValue;
+ }
+ } else {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)) {
+ if ($value === $this->getAttribute('value')) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->setAttribute('checked', 'checked');
+ } else {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->removeAttribute('checked');
+ }
+ } elseif ($this->node instanceof \DOMElement && $this->node->nodeName === 'select') {
+ foreach ($this->node->getElementsByTagName('option') as $option) {
+ /** @var \DOMElement $option */
+ if ($value === $option->getAttribute('value')) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $option->setAttribute('selected', 'selected');
+ } else {
+ $option->removeAttribute('selected');
+ }
+ }
+ } elseif ($this->node->nodeName === 'input' && \is_string($value)) {
+ // Set value for input elements
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->setAttribute('value', $value);
+ } elseif ($this->node->nodeName === 'textarea' && \is_string($value)) {
+ $this->node->nodeValue = $value;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param HtmlDomParser $newDocument
+ * @param bool $removeExtraHeadTag
+ *
+ * @return HtmlDomParser
+ */
+ protected function cleanHtmlWrapper(
+ HtmlDomParser $newDocument,
+ $removeExtraHeadTag = false
+ ): HtmlDomParser {
+ if (
+ $newDocument->getIsDOMDocumentCreatedWithoutHtml()
+ ||
+ $newDocument->getIsDOMDocumentCreatedWithoutHtmlWrapper()
+ ) {
+ // Remove doc-type node.
+ if ($newDocument->getDocument()->doctype !== null) {
+ $newDocument->getDocument()->doctype->parentNode->removeChild($newDocument->getDocument()->doctype);
+ }
+
+ // Replace html element, preserving child nodes -> but keep the html wrapper, otherwise we got other problems ...
+ // so we replace it with "" and delete this at the ending.
+ $item = $newDocument->getDocument()->getElementsByTagName('html')->item(0);
+ if ($item !== null) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->changeElementName($item, 'simpleHtmlDomHtml');
+ }
+
+ if ($newDocument->getIsDOMDocumentCreatedWithoutPTagWrapper()) {
+ // Remove -element, preserving child nodes.
+ $pElement = $newDocument->getDocument()->getElementsByTagName('p')->item(0);
+ if ($pElement instanceof \DOMElement) {
+ $fragment = $newDocument->getDocument()->createDocumentFragment();
+
+ while ($pElement->childNodes->length > 0) {
+ $tmpNode = $pElement->childNodes->item(0);
+ if ($tmpNode !== null) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $fragment->appendChild($tmpNode);
+ }
+ }
+
+ if ($pElement->parentNode !== null) {
+ $pElement->parentNode->replaceChild($fragment, $pElement);
+ }
+ }
+ }
+
+ // Remove
-element, preserving child nodes.
+ $body = $newDocument->getDocument()->getElementsByTagName('body')->item(0);
+ if ($body instanceof \DOMElement) {
+ $fragment = $newDocument->getDocument()->createDocumentFragment();
+
+ while ($body->childNodes->length > 0) {
+ $tmpNode = $body->childNodes->item(0);
+ if ($tmpNode !== null) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $fragment->appendChild($tmpNode);
+ }
+ }
+
+ if ($body->parentNode !== null) {
+ $body->parentNode->replaceChild($fragment, $body);
+ }
+ }
+ }
+
+ // Remove head element, preserving child nodes.
+ if (
+ $removeExtraHeadTag
+ &&
+ $this->node->parentNode instanceof \DOMElement
+ &&
+ $newDocument->getIsDOMDocumentCreatedWithoutHeadWrapper()
+ ) {
+ $html = $this->node->parentNode->getElementsByTagName('head')[0] ?? null;
+
+ if (
+ $html !== null
+ &&
+ $this->node->parentNode->ownerDocument
+ ) {
+ $fragment = $this->node->parentNode->ownerDocument->createDocumentFragment();
+
+ /** @var \DOMNode $html */
+ while ($html->childNodes->length > 0) {
+ $tmpNode = $html->childNodes->item(0);
+ if ($tmpNode !== null) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $fragment->appendChild($tmpNode);
+ }
+ }
+
+ $html->parentNode->replaceChild($fragment, $html);
+ }
+ }
+
+ return $newDocument;
+ }
+
+ /**
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return SimpleHtmlDomNode
+ *
+ * An instance of an object implementing Iterator or
+ * Traversable
+ *
+ */
+ public function getIterator(): SimpleHtmlDomNodeInterface
+ {
+ $elements = new SimpleHtmlDomNode();
+ if ($this->node->hasChildNodes()) {
+ foreach ($this->node->childNodes as $node) {
+ $elements[] = new static($node);
+ }
+ }
+
+ return $elements;
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return $this->getHtmlDomParser()->innerXml($multiDecodeNewHtmlEntity);
+ }
+
+ /**
+ * Normalize the given input for comparison.
+ *
+ * @param HtmlDomParser|string $input
+ *
+ * @return string
+ */
+ private function normalizeStringForComparison($input): string
+ {
+ if ($input instanceof HtmlDomParser) {
+ $string = $input->html(false, false);
+
+ if ($input->getIsDOMDocumentCreatedWithoutHeadWrapper()) {
+ /** @noinspection HtmlRequiredTitleElement */
+ $string = \str_replace(['', ''], '', $string);
+ }
+ } else {
+ $string = (string) $input;
+ }
+
+ return
+ \urlencode(
+ \urldecode(
+ \trim(
+ \str_replace(
+ [
+ ' ',
+ "\n",
+ "\r",
+ '/>',
+ ],
+ [
+ '',
+ '',
+ '',
+ '>',
+ ],
+ \strtolower($string)
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * Delete
+ *
+ * @return void
+ */
+ public function delete()
+ {
+ $this->outertext = '';
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php
new file mode 100644
index 0000000..4d313c1
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomBlank.php
@@ -0,0 +1,472 @@
+
+ */
+class SimpleHtmlDomBlank extends AbstractSimpleHtmlDom implements \IteratorAggregate, SimpleHtmlDomInterface
+{
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleHtmlDomInterface|string|null
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /**
+ * Find list of nodes with a CSS selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null)
+ {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ public function getTag(): string
+ {
+ return '';
+ }
+
+ /**
+ * Returns an array of attributes.
+ *
+ * @return null
+ */
+ public function getAllAttributes()
+ {
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasAttributes(): bool
+ {
+ return false;
+ }
+
+ /**
+ * Return attribute value.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function getAttribute(string $name): string
+ {
+ return '';
+ }
+
+ /**
+ * Determine if an attribute exists on the element.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasAttribute(string $name): bool
+ {
+ return false;
+ }
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function html(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return '';
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
+ {
+ return '';
+ }
+
+ /**
+ * Remove attribute.
+ *
+ * @param string $name The name of the html-attribute.
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function removeAttribute(string $name): SimpleHtmlDomInterface
+ {
+ return $this;
+ }
+
+ /**
+ * Remove all attributes
+ *
+ * @return SimpleHtmlDomBlank
+ */
+ public function removeAttributes(): SimpleHtmlDomInterface
+ {
+ return $this;
+ }
+
+ /**
+ * @param string $string
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ protected function replaceTextWithString($string): SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Set attribute value.
+ *
+ * @param string $name The name of the html-attribute.
+ * @param string|null $value Set to NULL or empty string, to remove the attribute.
+ * @param bool $strictEmptyValueCheck
+ * $value must be NULL, to remove the attribute,
+ * so that you can set an empty string as attribute-value e.g. autofocus=""
+ *
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface
+ {
+ return $this;
+ }
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @return string
+ */
+ public function text(): string
+ {
+ return '';
+ }
+
+ /**
+ * Returns children of node.
+ *
+ * @param int $idx
+ *
+ * @return null
+ */
+ public function childNodes(int $idx = -1)
+ {
+ return null;
+ }
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleHtmlDomNodeInterface
+ {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ /**
+ * Find nodes with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function findOne(string $selector): SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Find one node with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * Returns the first child of node.
+ *
+ * @return null
+ */
+ public function firstChild()
+ {
+ return null;
+ }
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function getElementByClass(string $class): SimpleHtmlDomNodeInterface
+ {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ /**
+ * Return element by #id.
+ *
+ * @param string $id
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function getElementById(string $id): SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function getElementByTagName(string $name): SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null)
+ {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null)
+ {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ /**
+ * Create a new "HtmlDomParser"-object from the current context.
+ *
+ * @return HtmlDomParser
+ */
+ public function getHtmlDomParser(): HtmlDomParser
+ {
+ return new HtmlDomParser($this);
+ }
+
+ /**
+ * @return \DOMNode
+ */
+ public function getNode(): \DOMNode
+ {
+ return new \DOMNode();
+ }
+
+ /**
+ * Nodes can get partially destroyed in which they're still an
+ * actual DOM node (such as \DOMElement) but almost their entire
+ * body is gone, including the `nodeType` attribute.
+ *
+ * @return bool true if node has been destroyed
+ */
+ public function isRemoved(): bool
+ {
+ return true;
+ }
+
+ /**
+ * Returns the last child of node.
+ *
+ * @return null
+ */
+ public function lastChild()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return null
+ */
+ public function nextSibling()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return null
+ */
+ public function nextNonWhitespaceSibling()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return null
+ */
+ public function previousNonWhitespaceSibling()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the parent of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function parentNode(): ?SimpleHtmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return null
+ */
+ public function previousSibling()
+ {
+ return null;
+ }
+
+ /**
+ * @param string|string[]|null $value
+ * null === get the current input value
+ * text === set a new input value
+ *
+ *
+ * @return string|string[]|null
+ */
+ public function val($value = null)
+ {
+ return null;
+ }
+
+ /**
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return SimpleHtmlDomNodeInterface
+ *
+ * An instance of an object implementing Iterator or
+ * Traversable
+ *
+ */
+ public function getIterator(): SimpleHtmlDomNodeInterface
+ {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ /**
+ * Get dom node's inner xml.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return '';
+ }
+
+ /**
+ * Delete
+ *
+ * @return void
+ */
+ public function delete()
+ {
+ $this->outertext='';
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php
new file mode 100644
index 0000000..1a01bfb
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomInterface.php
@@ -0,0 +1,391 @@
+Get dom node's outer html (alias for "outerHtml").
+ * @property string $outerhtml
+ * Get dom node's outer html.
+ * @property string $innertext
+ * Get dom node's inner html (alias for "innerHtml").
+ * @property string $innerhtml
+ * Get dom node's inner html.
+ * @property string $innerhtmlKeep
+ * Get dom node's inner html + keep fix for broken html.
+ * @property string $plaintext
+ * Get dom node's plain text.
+ * @property string $class
+ * Get dom node's class attribute.
+ * @property string $id
+ * Get dom node's id attribute.
+ * @property SimpleHtmlAttributes $classList
+ * Get dom node attributes.
+ * @property-read string $tag
+ * Get dom node name.
+ * @property-read string $attr
+ * Get dom node attributes.
+ * @property-read string $text
+ * Get dom node name.
+ * @property-read string $html
+ * Get dom node's outer html.
+ *
+ * @method SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface|null children() children($idx = -1)
+ * Returns children of node.
+ * @method SimpleHtmlDomInterface|null first_child()
+ * Returns the first child of node.
+ * @method SimpleHtmlDomInterface|null last_child()
+ * Returns the last child of node.
+ * @method SimpleHtmlDomInterface|null next_sibling()
+ * Returns the next sibling of node.
+ * @method SimpleHtmlDomInterface|null prev_sibling()
+ * Returns the previous sibling of node.
+ * @method SimpleHtmlDomInterface|null parent()
+ * Returns the parent of node.
+ * @method string outerText()
+ * Get dom node's outer html (alias for "outerHtml()").
+ * @method string outerHtml()
+ * Get dom node's outer html.
+ * @method string innerText()
+ * Get dom node's inner html (alias for "innerHtml()").
+ *
+ * @extends \IteratorAggregate
+ */
+interface SimpleHtmlDomInterface extends \IteratorAggregate
+{
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleHtmlDomInterface|string|null
+ */
+ public function __call($name, $arguments);
+
+ /**
+ * @param string $name
+ *
+ * @return array|string|null
+ */
+ public function __get($name);
+
+ /**
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function __invoke($selector, $idx = null);
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function __isset($name);
+
+ /**
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Return the tag of node
+ *
+ * @return string
+ */
+ public function getTag():string;
+
+ /**
+ * Returns children of node.
+ *
+ * @param int $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface|null
+ */
+ public function childNodes(int $idx = -1);
+
+ /**
+ * Find list of nodes with a CSS selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null);
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleHtmlDomNodeInterface;
+
+ /**
+ * Find nodes with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector);
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function findOne(string $selector): self;
+
+ /**
+ * Find one node with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomInterface
+ */
+ public function findOneOrFalse(string $selector);
+
+ /**
+ * Returns the first child of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function firstChild();
+
+ /**
+ * Returns an array of attributes.
+ *
+ * @return string[]|null
+ */
+ public function getAllAttributes();
+
+ /**
+ * Return attribute value.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function getAttribute(string $name): string;
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function getElementByClass(string $class);
+
+ /**
+ * Return element by "#id".
+ *
+ * @param string $id
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function getElementById(string $id): self;
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function getElementByTagName(string $name): self;
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null);
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null);
+
+ /**
+ * Create a new "HtmlDomParser"-object from the current context.
+ *
+ * @return HtmlDomParser
+ */
+ public function getHtmlDomParser(): HtmlDomParser;
+
+ /**
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return SimpleHtmlDomNodeInterface
+ *
+ * An instance of an object implementing Iterator or
+ * Traversable
+ *
+ */
+ public function getIterator(): SimpleHtmlDomNodeInterface;
+
+ /**
+ * @return \DOMNode
+ */
+ public function getNode(): \DOMNode;
+
+ /**
+ * Determine if an attribute exists on the element.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasAttribute(string $name): bool;
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function html(bool $multiDecodeNewHtmlEntity = false): string;
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string;
+
+ /**
+ * Nodes can get partially destroyed in which they're still an
+ * actual DOM node (such as \DOMElement) but almost their entire
+ * body is gone, including the `nodeType` attribute.
+ *
+ * @return bool true if node has been destroyed
+ */
+ public function isRemoved(): bool;
+
+ /**
+ * Returns the last child of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function lastChild();
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function nextSibling();
+
+ /**
+ * Returns the next sibling of node, and it will ignore whitespace elements.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function nextNonWhitespaceSibling();
+
+ /**
+ * Returns the previous sibling of node, and it will ignore whitespace elements.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function previousNonWhitespaceSibling();
+
+ /**
+ * Returns the parent of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function parentNode(): ?self;
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleHtmlDomInterface|null
+ */
+ public function previousSibling();
+
+ /**
+ * Remove attribute.
+ *
+ * @param string $name The name of the html-attribute.
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function removeAttribute(string $name): self;
+
+ /**
+ * Set attribute value.
+ *
+ * @param string $name The name of the html-attribute.
+ * @param string|null $value Set to NULL or empty string, to remove the attribute.
+ * @param bool $strictEmptyValueCheck
+ * $value must be NULL, to remove the attribute,
+ * so that you can set an empty string as attribute-value e.g. autofocus=""
+ *
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): self;
+
+ /**
+ * Remove all attributes
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function removeAttributes(): self;
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @return string
+ */
+ public function text(): string;
+
+ /**
+ * @param string|string[]|null $value
+ * null === get the current input value
+ * text === set a new input value
+ *
+ *
+ * @return string|string[]|null
+ */
+ public function val($value = null);
+
+ /**
+ * Delete
+ *
+ * @return mixed
+ */
+ public function delete();
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php
new file mode 100644
index 0000000..8b491ed
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNode.php
@@ -0,0 +1,161 @@
+|SimpleHtmlDomNodeInterface[]|null
+ */
+ public function find(string $selector, $idx = null)
+ {
+ // init
+ $elements = new static();
+
+ foreach ($this as $node) {
+ \assert($node instanceof SimpleHtmlDomInterface);
+ foreach ($node->find($selector) as $res) {
+ $elements[] = $res;
+ }
+ }
+
+ // return all elements
+ if ($idx === null) {
+ if (\count($elements) === 0) {
+ return new SimpleHtmlDomNodeBlank();
+ }
+
+ return $elements;
+ }
+
+ // handle negative values
+ if ($idx < 0) {
+ $idx = \count($elements) + $idx;
+ }
+
+ // return one element
+ return $elements[$idx] ?? null;
+ }
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleHtmlDomNodeInterface
+ {
+ return $this->find($selector, null);
+ }
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ $return = $this->find($selector, null);
+
+ if ($return instanceof SimpleHtmlDomNodeBlank) {
+ return false;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function findOne(string $selector)
+ {
+ $return = $this->find($selector, 0);
+
+ return $return ?? new SimpleHtmlDomNodeBlank();
+ }
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomNodeInterface
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ $return = $this->find($selector, 0);
+
+ return $return ?? false;
+ }
+
+ /**
+ * Get html of elements.
+ *
+ * @return string[]
+ */
+ public function innerHtml(): array
+ {
+ // init
+ $html = [];
+
+ foreach ($this as $node) {
+ $html[] = $node->outertext;
+ }
+
+ return $html;
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function innertext()
+ {
+ return $this->innerHtml();
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function outertext()
+ {
+ return $this->innerHtml();
+ }
+
+ /**
+ * Get plain text.
+ *
+ * @return string[]
+ */
+ public function text(): array
+ {
+ // init
+ $text = [];
+
+ foreach ($this as $node) {
+ $text[] = $node->plaintext;
+ }
+
+ return $text;
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php
new file mode 100644
index 0000000..ea31cfe
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeBlank.php
@@ -0,0 +1,106 @@
+
+ */
+ public function findMulti(string $selector): SimpleHtmlDomNodeInterface
+ {
+ return new self();
+ }
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface
+ */
+ public function findOne(string $selector)
+ {
+ return new SimpleHtmlDomBlank();
+ }
+
+ /**
+ * Find one node with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function innerHtml(): array
+ {
+ return [];
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function innertext()
+ {
+ return [];
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function outertext()
+ {
+ return [];
+ }
+
+ /**
+ * @return string[]
+ */
+ public function text(): array
+ {
+ return [];
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php
new file mode 100644
index 0000000..e2990ea
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleHtmlDomNodeInterface.php
@@ -0,0 +1,117 @@
+The list items count.
+ * @property-read string[] $outertext
+ * Get dom node's outer html.
+ * @property-read string[] $plaintext
+ * Get dom node's plain text.
+ *
+ * @extends \IteratorAggregate
+ */
+interface SimpleHtmlDomNodeInterface extends \IteratorAggregate
+{
+ /**
+ * @param string $name
+ *
+ * @return array|null
+ */
+ public function __get($name);
+
+ /**
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleHtmlDomNodeInterface|SimpleHtmlDomNodeInterface[]|null
+ */
+ public function __invoke($selector, $idx = null);
+
+ /**
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Get the number of items in this dom node.
+ *
+ * @return int
+ */
+ public function count();
+
+ /**
+ * Find list of nodes with a CSS selector.
+ *
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleHtmlDomNode|SimpleHtmlDomNode[]|null
+ */
+ public function find(string $selector, $idx = null);
+
+ /**
+ * Find nodes with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMulti(string $selector): self;
+
+ /**
+ * Find nodes with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector);
+
+ /**
+ * Find one node with a CSS selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleHtmlDomNodeInterface
+ */
+ public function findOne(string $selector);
+
+ /**
+ * Find one node with a CSS selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleHtmlDomNodeInterface
+ */
+ public function findOneOrFalse(string $selector);
+
+ /**
+ * Get html of elements.
+ *
+ * @return string[]
+ */
+ public function innerHtml(): array;
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function innertext();
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function outertext();
+
+ /**
+ * Get plain text.
+ *
+ * @return string[]
+ */
+ public function text(): array;
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDom.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDom.php
new file mode 100644
index 0000000..a4cebb2
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleXmlDom.php
@@ -0,0 +1,843 @@
+
+ */
+class SimpleXmlDom extends AbstractSimpleXmlDom implements \IteratorAggregate, SimpleXmlDomInterface
+{
+ /**
+ * @param \DOMElement|\DOMNode $node
+ */
+ public function __construct(\DOMNode $node)
+ {
+ $this->node = $node;
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleXmlDomInterface|string|null
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /**
+ * Find list of nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null)
+ {
+ return $this->getXmlDomParser()->find($selector, $idx);
+ }
+
+ /**
+ * Returns an array of attributes.
+ *
+ * @return string[]|null
+ */
+ public function getAllAttributes()
+ {
+ if (
+ $this->node
+ &&
+ $this->node->hasAttributes()
+ ) {
+ $attributes = [];
+ foreach ($this->node->attributes ?? [] as $attr) {
+ $attributes[$attr->name] = XmlDomParser::putReplacedBackToPreserveHtmlEntities($attr->value);
+ }
+
+ return $attributes;
+ }
+
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasAttributes(): bool
+ {
+ return $this->node->hasAttributes();
+ }
+
+ /**
+ * Return attribute value.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function getAttribute(string $name): string
+ {
+ if ($this->node instanceof \DOMElement) {
+ return XmlDomParser::putReplacedBackToPreserveHtmlEntities(
+ $this->node->getAttribute($name)
+ );
+ }
+
+ return '';
+ }
+
+ /**
+ * Determine if an attribute exists on the element.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasAttribute(string $name): bool
+ {
+ if (!$this->node instanceof \DOMElement) {
+ return false;
+ }
+
+ return $this->node->hasAttribute($name);
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return $this->getXmlDomParser()->innerXml($multiDecodeNewHtmlEntity);
+ }
+
+ /**
+ * Remove attribute.
+ *
+ * @param string $name The name of the html-attribute.
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function removeAttribute(string $name): SimpleXmlDomInterface
+ {
+ if (\method_exists($this->node, 'removeAttribute')) {
+ $this->node->removeAttribute($name);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Replace child node.
+ *
+ * @param string $string
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return SimpleXmlDomInterface
+ */
+ protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleXmlDomInterface
+ {
+ if (!empty($string)) {
+ $newDocument = new XmlDomParser($string);
+
+ $tmpDomString = $this->normalizeStringForComparision($newDocument);
+ $tmpStr = $this->normalizeStringForComparision($string);
+
+ if ($tmpDomString !== $tmpStr) {
+ throw new \RuntimeException(
+ 'Not valid XML fragment!' . "\n" .
+ $tmpDomString . "\n" .
+ $tmpStr
+ );
+ }
+ }
+
+ /** @var \DOMNode[] $remove_nodes */
+ $remove_nodes = [];
+ if ($this->node->childNodes->length > 0) {
+ // INFO: We need to fetch the nodes first, before we can delete them, because of missing references in the dom,
+ // if we delete the elements on the fly.
+ foreach ($this->node->childNodes as $node) {
+ $remove_nodes[] = $node;
+ }
+ }
+ foreach ($remove_nodes as $remove_node) {
+ $this->node->removeChild($remove_node);
+ }
+
+ if (!empty($newDocument)) {
+ $ownerDocument = $this->node->ownerDocument;
+ if (
+ $ownerDocument
+ &&
+ $newDocument->getDocument()->documentElement
+ ) {
+ $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->node->appendChild($newNode);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Replace this node.
+ *
+ * @param string $string
+ *
+ * @return SimpleXmlDomInterface
+ */
+ protected function replaceNodeWithString(string $string): SimpleXmlDomInterface
+ {
+ if (empty($string)) {
+ if ($this->node->parentNode) {
+ $this->node->parentNode->removeChild($this->node);
+ }
+
+ return $this;
+ }
+
+ $newDocument = new XmlDomParser($string);
+
+ $tmpDomOuterTextString = $this->normalizeStringForComparision($newDocument);
+ $tmpStr = $this->normalizeStringForComparision($string);
+
+ if ($tmpDomOuterTextString !== $tmpStr) {
+ throw new \RuntimeException(
+ 'Not valid XML fragment!' . "\n"
+ . $tmpDomOuterTextString . "\n" .
+ $tmpStr
+ );
+ }
+
+ $ownerDocument = $this->node->ownerDocument;
+ if (
+ $ownerDocument === null
+ ||
+ $newDocument->getDocument()->documentElement === null
+ ) {
+ return $this;
+ }
+
+ $newNode = $ownerDocument->importNode($newDocument->getDocument()->documentElement, true);
+
+ $this->node->parentNode->replaceChild($newNode, $this->node);
+ $this->node = $newNode;
+
+ return $this;
+ }
+
+ /**
+ * Replace this node with text
+ *
+ * @param string $string
+ *
+ * @return SimpleXmlDomInterface
+ */
+ protected function replaceTextWithString($string): SimpleXmlDomInterface
+ {
+ if (empty($string)) {
+ if ($this->node->parentNode) {
+ $this->node->parentNode->removeChild($this->node);
+ }
+
+ return $this;
+ }
+
+ $ownerDocument = $this->node->ownerDocument;
+ if ($ownerDocument) {
+ $newElement = $ownerDocument->createTextNode($string);
+ $newNode = $ownerDocument->importNode($newElement, true);
+ $this->node->parentNode->replaceChild($newNode, $this->node);
+ $this->node = $newNode;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set attribute value.
+ *
+ * @param string $name The name of the html-attribute.
+ * @param string|null $value Set to NULL or empty string, to remove the attribute.
+ * @param bool $strictEmptyValueCheck
+ * $value must be NULL, to remove the attribute,
+ * so that you can set an empty string as attribute-value e.g. autofocus=""
+ *
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleXmlDomInterface
+ {
+ if (
+ ($strictEmptyValueCheck && $value === null)
+ ||
+ (!$strictEmptyValueCheck && empty($value))
+ ) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->removeAttribute($name);
+ } elseif (\method_exists($this->node, 'setAttribute')) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->node->setAttribute($name, HtmlDomParser::replaceToPreserveHtmlEntities((string) $value));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @return string
+ */
+ public function text(): string
+ {
+ return $this->getXmlDomParser()->fixHtmlOutput($this->node->textContent);
+ }
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function xml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return $this->getXmlDomParser()->xml($multiDecodeNewHtmlEntity, false);
+ }
+
+ /**
+ * Change the name of a tag in a "DOMNode".
+ *
+ * @param \DOMNode $node
+ * @param string $name
+ *
+ * @return \DOMElement|false
+ * DOMElement a new instance of class DOMElement or false
+ * if an error occured.
+ */
+ protected function changeElementName(\DOMNode $node, string $name)
+ {
+ $ownerDocument = $node->ownerDocument;
+ if (!$ownerDocument) {
+ return false;
+ }
+
+ $newNode = $ownerDocument->createElement($name);
+
+ foreach ($node->childNodes as $child) {
+ $child = $ownerDocument->importNode($child, true);
+ $newNode->appendChild($child);
+ }
+
+ foreach ($node->attributes ?? [] as $attrName => $attrNode) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $newNode->setAttribute($attrName, $attrNode);
+ }
+
+ if ($newNode->ownerDocument) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $newNode->ownerDocument->replaceChild($newNode, $node);
+ }
+
+ return $newNode;
+ }
+
+ /**
+ * Returns children of node.
+ *
+ * @param int $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface|null
+ */
+ public function childNodes(int $idx = -1)
+ {
+ $nodeList = $this->getIterator();
+
+ if ($idx === -1) {
+ return $nodeList;
+ }
+
+ return $nodeList[$idx] ?? null;
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleXmlDomNodeInterface
+ {
+ return $this->getXmlDomParser()->findMulti($selector);
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ return $this->getXmlDomParser()->findMultiOrFalse($selector);
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function findOne(string $selector): SimpleXmlDomInterface
+ {
+ return $this->getXmlDomParser()->findOne($selector);
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ return $this->getXmlDomParser()->findOneOrFalse($selector);
+ }
+
+ /**
+ * Returns the first child of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function firstChild()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->firstChild;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementByClass(string $class): SimpleXmlDomNodeInterface
+ {
+ return $this->findMulti(".{$class}");
+ }
+
+ /**
+ * Return element by #id.
+ *
+ * @param string $id
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementById(string $id): SimpleXmlDomInterface
+ {
+ return $this->findOne("#{$id}");
+ }
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementByTagName(string $name): SimpleXmlDomInterface
+ {
+ if ($this->node instanceof \DOMElement) {
+ $node = $this->node->getElementsByTagName($name)->item(0);
+ } else {
+ $node = null;
+ }
+
+ if ($node === null) {
+ return new SimpleXmlDomBlank();
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null)
+ {
+ return $this->find("#{$id}", $idx);
+ }
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null)
+ {
+ if ($this->node instanceof \DOMElement) {
+ $nodesList = $this->node->getElementsByTagName($name);
+ } else {
+ $nodesList = [];
+ }
+
+ $elements = new SimpleXmlDomNode();
+
+ foreach ($nodesList as $node) {
+ $elements[] = new static($node);
+ }
+
+ // return all elements
+ if ($idx === null) {
+ if (\count($elements) === 0) {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ return $elements;
+ }
+
+ // handle negative values
+ if ($idx < 0) {
+ $idx = \count($elements) + $idx;
+ }
+
+ // return one element
+ return $elements[$idx] ?? new SimpleXmlDomBlank();
+ }
+
+ /**
+ * @return \DOMNode
+ */
+ public function getNode(): \DOMNode
+ {
+ return $this->node;
+ }
+
+ /**
+ * Create a new "XmlDomParser"-object from the current context.
+ *
+ * @return XmlDomParser
+ */
+ public function getXmlDomParser(): XmlDomParser
+ {
+ return new XmlDomParser($this);
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
+ {
+ return $this->getXmlDomParser()->innerHtml($multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
+ }
+
+ /**
+ * Nodes can get partially destroyed in which they're still an
+ * actual DOM node (such as \DOMElement) but almost their entire
+ * body is gone, including the `nodeType` attribute.
+ *
+ * @return bool true if node has been destroyed
+ */
+ public function isRemoved(): bool
+ {
+ return !isset($this->node->nodeType);
+ }
+
+ /**
+ * Returns the last child of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function lastChild()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->lastChild;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function nextSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->nextSibling;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function nextNonWhitespaceSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->nextSibling;
+
+ if ($node === null) {
+ return null;
+ }
+
+ while ($node && !\trim($node->textContent)) {
+ /** @var \DOMNode|null $node */
+ $node = $node->nextSibling;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the parent of node.
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function parentNode(): SimpleXmlDomInterface
+ {
+ return new static($this->node->parentNode);
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function previousSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->previousSibling;
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function previousNonWhitespaceSibling()
+ {
+ /** @var \DOMNode|null $node */
+ $node = $this->node->previousSibling;
+
+ while ($node && !\trim($node->textContent)) {
+ /** @var \DOMNode|null $node */
+ $node = $node->previousSibling;
+ }
+
+ if ($node === null) {
+ return null;
+ }
+
+ return new static($node);
+ }
+
+ /**
+ * @param string|string[]|null $value
+ * null === get the current input value
+ * text === set a new input value
+ *
+ *
+ * @return string|string[]|null
+ */
+ public function val($value = null)
+ {
+ if ($value === null) {
+ if (
+ $this->tag === 'input'
+ &&
+ (
+ $this->getAttribute('type') === 'hidden'
+ ||
+ $this->getAttribute('type') === 'text'
+ ||
+ !$this->hasAttribute('type')
+ )
+ ) {
+ return $this->getAttribute('value');
+ }
+
+ if (
+ $this->hasAttribute('checked')
+ &&
+ \in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)
+ ) {
+ return $this->getAttribute('value');
+ }
+
+ if ($this->node->nodeName === 'select') {
+ $valuesFromDom = [];
+ $options = $this->getElementsByTagName('option');
+ if ($options instanceof SimpleXmlDomNode) {
+ foreach ($options as $option) {
+ if ($this->hasAttribute('checked')) {
+ $valuesFromDom[] = (string) $option->getAttribute('value');
+ }
+ }
+ }
+
+ if (\count($valuesFromDom) === 0) {
+ return null;
+ }
+
+ return $valuesFromDom;
+ }
+
+ if ($this->node->nodeName === 'textarea') {
+ return $this->node->nodeValue;
+ }
+ } else {
+ /** @noinspection NestedPositiveIfStatementsInspection */
+ if (\in_array($this->getAttribute('type'), ['checkbox', 'radio'], true)) {
+ if ($value === $this->getAttribute('value')) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->setAttribute('checked', 'checked');
+ } else {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->removeAttribute('checked');
+ }
+ } elseif ($this->node instanceof \DOMElement && $this->node->nodeName === 'select') {
+ foreach ($this->node->getElementsByTagName('option') as $option) {
+ /** @var \DOMElement $option */
+ if ($value === $option->getAttribute('value')) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $option->setAttribute('selected', 'selected');
+ } else {
+ $option->removeAttribute('selected');
+ }
+ }
+ } elseif ($this->node->nodeName === 'input' && \is_string($value)) {
+ // Set value for input elements
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->setAttribute('value', $value);
+ } elseif ($this->node->nodeName === 'textarea' && \is_string($value)) {
+ $this->node->nodeValue = $value;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return SimpleXmlDomNode
+ *
+ * An instance of an object implementing Iterator or
+ * Traversable
+ *
+ */
+ public function getIterator(): SimpleXmlDomNodeInterface
+ {
+ $elements = new SimpleXmlDomNode();
+ if ($this->node->hasChildNodes()) {
+ foreach ($this->node->childNodes as $node) {
+ $elements[] = new static($node);
+ }
+ }
+
+ return $elements;
+ }
+
+ /**
+ * Normalize the given input for comparision.
+ *
+ * @param string|XmlDomParser $input
+ *
+ * @return string
+ */
+ private function normalizeStringForComparision($input): string
+ {
+ if ($input instanceof XmlDomParser) {
+ $string = $input->html(false, false);
+ } else {
+ $string = (string) $input;
+ }
+
+ return
+ \urlencode(
+ \urldecode(
+ \trim(
+ \str_replace(
+ [
+ ' ',
+ "\n",
+ "\r",
+ '/>',
+ ],
+ [
+ '',
+ '',
+ '',
+ '>',
+ ],
+ \strtolower($string)
+ )
+ )
+ )
+ );
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php
new file mode 100644
index 0000000..142d6cc
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleXmlDomBlank.php
@@ -0,0 +1,447 @@
+
+ */
+class SimpleXmlDomBlank extends AbstractSimpleXmlDom implements \IteratorAggregate, SimpleXmlDomInterface
+{
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleXmlDomInterface|string|null
+ */
+ public function __call($name, $arguments)
+ {
+ $name = \strtolower($name);
+
+ if (isset(self::$functionAliases[$name])) {
+ return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /**
+ * Find list of nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null)
+ {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * Returns an array of attributes.
+ *
+ * @return null
+ */
+ public function getAllAttributes()
+ {
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasAttributes(): bool
+ {
+ return false;
+ }
+
+ /**
+ * Return attribute value.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function getAttribute(string $name): string
+ {
+ return '';
+ }
+
+ /**
+ * Determine if an attribute exists on the element.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasAttribute(string $name): bool
+ {
+ return false;
+ }
+
+ /**
+ * Get dom node's inner xml.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return '';
+ }
+
+ /**
+ * Remove attribute.
+ *
+ * @param string $name The name of the html-attribute.
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function removeAttribute(string $name): SimpleXmlDomInterface
+ {
+ return $this;
+ }
+
+ /**
+ * @param string $string
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return SimpleXmlDomInterface
+ */
+ protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return SimpleXmlDomInterface
+ */
+ protected function replaceNodeWithString(string $string): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return SimpleXmlDomInterface
+ */
+ protected function replaceTextWithString($string): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Set attribute value.
+ *
+ * @param string $name The name of the html-attribute.
+ * @param string|null $value Set to NULL or empty string, to remove the attribute.
+ * @param bool $strictEmptyValueCheck
+ * $value must be NULL, to remove the attribute,
+ * so that you can set an empty string as attribute-value e.g. autofocus=""
+ *
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleXmlDomInterface
+ {
+ return $this;
+ }
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @return string
+ */
+ public function text(): string
+ {
+ return '';
+ }
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function xml(bool $multiDecodeNewHtmlEntity = false): string
+ {
+ return '';
+ }
+
+ /**
+ * Returns children of node.
+ *
+ * @param int $idx
+ *
+ * @return null
+ */
+ public function childNodes(int $idx = -1)
+ {
+ return null;
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleXmlDomNodeInterface
+ {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function findOne(string $selector): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * Returns the first child of node.
+ *
+ * @return null
+ */
+ public function firstChild()
+ {
+ return null;
+ }
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleXmlDomNodeInterface
+ */
+ public function getElementByClass(string $class): SimpleXmlDomNodeInterface
+ {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * Return element by #id.
+ *
+ * @param string $id
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementById(string $id): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementByTagName(string $name): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null)
+ {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null)
+ {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * @return \DOMNode
+ */
+ public function getNode(): \DOMNode
+ {
+ return new \DOMNode();
+ }
+
+ /**
+ * Create a new "XmlDomParser"-object from the current context.
+ *
+ * @return XmlDomParser
+ */
+ public function getXmlDomParser(): XmlDomParser
+ {
+ return new XmlDomParser($this);
+ }
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
+ {
+ return '';
+ }
+
+ /**
+ * Nodes can get partially destroyed in which they're still an
+ * actual DOM node (such as \DOMElement) but almost their entire
+ * body is gone, including the `nodeType` attribute.
+ *
+ * @return bool true if node has been destroyed
+ */
+ public function isRemoved(): bool
+ {
+ return true;
+ }
+
+ /**
+ * Returns the last child of node.
+ *
+ * @return null
+ */
+ public function lastChild()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return null
+ */
+ public function nextSibling()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return null
+ */
+ public function nextNonWhitespaceSibling()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the parent of node.
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function parentNode(): SimpleXmlDomInterface
+ {
+ return new static();
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return null
+ */
+ public function previousSibling()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return null
+ */
+ public function previousNonWhitespaceSibling()
+ {
+ return null;
+ }
+
+ /**
+ * @param string|string[]|null $value
+ * null === get the current input value
+ * text === set a new input value
+ *
+ *
+ * @return string|string[]|null
+ */
+ public function val($value = null)
+ {
+ return null;
+ }
+
+ /**
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return SimpleXmlDomNodeInterface
+ *
+ * An instance of an object implementing Iterator or
+ * Traversable
+ *
+ */
+ public function getIterator(): SimpleXmlDomNodeInterface
+ {
+ return new SimpleXmlDomNodeBlank();
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php
new file mode 100644
index 0000000..e983ae6
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleXmlDomInterface.php
@@ -0,0 +1,367 @@
+Get dom node's outer html (alias for "outerHtml").
+ * @property string $outerhtml
+ * Get dom node's outer html.
+ * @property string $innertext
+ * Get dom node's inner html (alias for "innerHtml").
+ * @property string $innerhtml
+ * Get dom node's inner html.
+ * @property string $plaintext
+ * Get dom node's plain text.
+ * @property-read string $tag
+ * Get dom node name.
+ * @property-read string $attr
+ * Get dom node attributes.
+ * @property-read string $text
+ * Get dom node name.
+ * @property-read string $html
+ * Get dom node's outer html.
+ *
+ * @method SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface|null children() children($idx = -1)
+ * Returns children of node.
+ * @method SimpleXmlDomInterface|null first_child()
+ * Returns the first child of node.
+ * @method SimpleXmlDomInterface|null last_child()
+ * Returns the last child of node.
+ * @method SimpleXmlDomInterface|null next_sibling()
+ * Returns the next sibling of node.
+ * @method SimpleXmlDomInterface|null prev_sibling()
+ * Returns the previous sibling of node.
+ * @method SimpleXmlDomInterface|null parent()
+ * Returns the parent of node.
+ * @method string outerText()
+ * Get dom node's outer html (alias for "outerHtml()").
+ * @method string outerHtml()
+ * Get dom node's outer html.
+ * @method string innerText()
+ * Get dom node's inner html (alias for "innerHtml()").
+ *
+ * @extends \IteratorAggregate
+ */
+interface SimpleXmlDomInterface extends \IteratorAggregate
+{
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ *
+ * @return SimpleXmlDomInterface|string|null
+ */
+ public function __call($name, $arguments);
+
+ /**
+ * @param string $name
+ *
+ * @return array|string|null
+ */
+ public function __get($name);
+
+ /**
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function __invoke($selector, $idx = null);
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function __isset($name);
+
+ /**
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Returns children of node.
+ *
+ * @param int $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface|null
+ */
+ public function childNodes(int $idx = -1);
+
+ /**
+ * Find list of nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null);
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleXmlDomNodeInterface;
+
+ /**
+ * Find nodes with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector);
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function findOne(string $selector): self;
+
+ /**
+ * Find one node with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface
+ */
+ public function findOneOrFalse(string $selector);
+
+ /**
+ * Returns the first child of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function firstChild();
+
+ /**
+ * Returns an array of attributes.
+ *
+ * @return string[]|null
+ */
+ public function getAllAttributes();
+
+ /**
+ * @return bool
+ */
+ public function hasAttributes(): bool;
+
+ /**
+ * Return attribute value.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function getAttribute(string $name): string;
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementByClass(string $class);
+
+ /**
+ * Return element by "#id".
+ *
+ * @param string $id
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementById(string $id): self;
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementByTagName(string $name): self;
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null);
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null);
+
+ /**
+ * Retrieve an external iterator.
+ *
+ * @see http://php.net/manual/en/iteratoraggregate.getiterator.php
+ *
+ * @return SimpleXmlDomNodeInterface
+ *
+ * An instance of an object implementing Iterator or
+ * Traversable
+ *
+ */
+ public function getIterator(): SimpleXmlDomNodeInterface;
+
+ /**
+ * @return \DOMNode
+ */
+ public function getNode(): \DOMNode;
+
+ /**
+ * Create a new "XmlDomParser"-object from the current context.
+ *
+ * @return XmlDomParser
+ */
+ public function getXmlDomParser(): XmlDomParser;
+
+ /**
+ * Determine if an attribute exists on the element.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function hasAttribute(string $name): bool;
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
+
+ /**
+ * Get dom node's inner html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function innerXml(bool $multiDecodeNewHtmlEntity = false): string;
+
+ /**
+ * Nodes can get partially destroyed in which they're still an
+ * actual DOM node (such as \DOMElement) but almost their entire
+ * body is gone, including the `nodeType` attribute.
+ *
+ * @return bool true if node has been destroyed
+ */
+ public function isRemoved(): bool;
+
+ /**
+ * Returns the last child of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function lastChild();
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function nextSibling();
+
+ /**
+ * Returns the next sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function nextNonWhitespaceSibling();
+
+ /**
+ * Returns the parent of node.
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function parentNode(): self;
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function previousSibling();
+
+ /**
+ * Returns the previous sibling of node.
+ *
+ * @return SimpleXmlDomInterface|null
+ */
+ public function previousNonWhitespaceSibling();
+
+ /**
+ * Remove attribute.
+ *
+ * @param string $name The name of the html-attribute.
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function removeAttribute(string $name): self;
+
+ /**
+ * Set attribute value.
+ *
+ * @param string $name The name of the html-attribute.
+ * @param string|null $value Set to NULL or empty string, to remove the attribute.
+ * @param bool $strictEmptyValueCheck
+ * $value must be NULL, to remove the attribute,
+ * so that you can set an empty string as attribute-value e.g. autofocus=""
+ *
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): self;
+
+ /**
+ * Get dom node's plain text.
+ *
+ * @return string
+ */
+ public function text(): string;
+
+ /**
+ * @param string|string[]|null $value
+ * null === get the current input value
+ * text === set a new input value
+ *
+ *
+ * @return string|string[]|null
+ */
+ public function val($value = null);
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ *
+ * @return string
+ */
+ public function xml(bool $multiDecodeNewHtmlEntity = false): string;
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php
new file mode 100644
index 0000000..c41ff83
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNode.php
@@ -0,0 +1,161 @@
+|SimpleXmlDomNodeInterface[]|null
+ */
+ public function find(string $selector, $idx = null)
+ {
+ // init
+ $elements = new static();
+
+ foreach ($this as $node) {
+ \assert($node instanceof SimpleXmlDomInterface);
+ foreach ($node->find($selector) as $res) {
+ $elements->append($res);
+ }
+ }
+
+ // return all elements
+ if ($idx === null) {
+ if (\count($elements) === 0) {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ return $elements;
+ }
+
+ // handle negative values
+ if ($idx < 0) {
+ $idx = \count($elements) + $idx;
+ }
+
+ // return one element
+ return $elements[$idx] ?? null;
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleXmlDomNodeInterface
+ {
+ return $this->find($selector, null);
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ $return = $this->find($selector, null);
+
+ if ($return instanceof SimpleXmlDomNodeBlank) {
+ return false;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomNodeInterface
+ */
+ public function findOne(string $selector)
+ {
+ $return = $this->find($selector, 0);
+
+ return $return ?? new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomNodeInterface
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ $return = $this->find($selector, 0);
+
+ return $return ?? false;
+ }
+
+ /**
+ * Get html of elements.
+ *
+ * @return string[]
+ */
+ public function innerHtml(): array
+ {
+ // init
+ $html = [];
+
+ foreach ($this as $node) {
+ $html[] = $node->outertext;
+ }
+
+ return $html;
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function innertext()
+ {
+ return $this->innerHtml();
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function outertext()
+ {
+ return $this->innerHtml();
+ }
+
+ /**
+ * Get plain text.
+ *
+ * @return string[]
+ */
+ public function text(): array
+ {
+ // init
+ $text = [];
+
+ foreach ($this as $node) {
+ $text[] = $node->plaintext;
+ }
+
+ return $text;
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php
new file mode 100644
index 0000000..2c079ce
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeBlank.php
@@ -0,0 +1,104 @@
+
+ */
+ public function findMulti(string $selector): SimpleXmlDomNodeInterface
+ {
+ return new self();
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function findOne(string $selector)
+ {
+ return new SimpleXmlDomBlank();
+ }
+
+ /**
+ * @param string $selector
+ *
+ * @return false
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ return false;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function innerHtml(): array
+ {
+ return [];
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function innertext()
+ {
+ return [];
+ }
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function outertext()
+ {
+ return [];
+ }
+
+ /**
+ * @return string[]
+ */
+ public function text(): array
+ {
+ return [];
+ }
+}
diff --git a/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php
new file mode 100644
index 0000000..67b601c
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/SimpleXmlDomNodeInterface.php
@@ -0,0 +1,117 @@
+The list items count.
+ * @property-read string[] $outertext
+ * Get dom node's outer html.
+ * @property-read string[] $plaintext
+ * Get dom node's plain text.
+ *
+ * @extends \IteratorAggregate
+ */
+interface SimpleXmlDomNodeInterface extends \IteratorAggregate
+{
+ /**
+ * @param string $name
+ *
+ * @return array|null
+ */
+ public function __get($name);
+
+ /**
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleXmlDomNodeInterface|SimpleXmlDomNodeInterface[]|null
+ */
+ public function __invoke($selector, $idx = null);
+
+ /**
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Get the number of items in this dom node.
+ *
+ * @return int
+ */
+ public function count();
+
+ /**
+ * Find list of nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleXmlDomNode|SimpleXmlDomNode[]|null
+ */
+ public function find(string $selector, $idx = null);
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMulti(string $selector): self;
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector);
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function findOne(string $selector);
+
+ /**
+ * Find one node with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface
+ */
+ public function findOneOrFalse(string $selector);
+
+ /**
+ * Get html of elements.
+ *
+ * @return string[]
+ */
+ public function innerHtml(): array;
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function innertext();
+
+ /**
+ * alias for "$this->innerHtml()" (added for compatibly-reasons with v1.x)
+ *
+ * @return string[]
+ */
+ public function outertext();
+
+ /**
+ * Get plain text.
+ *
+ * @return string[]
+ */
+ public function text(): array;
+}
diff --git a/includes/classes/Dependencies/voku/helper/XmlDomParser.php b/includes/classes/Dependencies/voku/helper/XmlDomParser.php
new file mode 100644
index 0000000..c53429e
--- /dev/null
+++ b/includes/classes/Dependencies/voku/helper/XmlDomParser.php
@@ -0,0 +1,733 @@
+Get dom node's plain text.
+ *
+ * @method static XmlDomParser file_get_xml($xml, $libXMLExtraOptions = null)
+ * Load XML from file.
+ * @method static XmlDomParser str_get_xml($xml, $libXMLExtraOptions = null)
+ * Load XML from string.
+ */
+class XmlDomParser extends AbstractDomParser
+{
+ /**
+ * @var callable|null
+ *
+ * @phpstan-var null|callable(string $cssSelectorString, string $xPathString, \DOMXPath, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string
+ */
+ private $callbackXPathBeforeQuery;
+
+ /**
+ * @var callable|null
+ *
+ * @phpstan-var null|callable(string $xmlString, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string
+ */
+ private $callbackBeforeCreateDom;
+
+ /**
+ * @var bool
+ */
+ private $autoRemoveXPathNamespaces = false;
+
+ /**
+ * @var bool
+ */
+ private $autoRegisterXPathNamespaces = false;
+
+ /**
+ * @var bool
+ */
+ private $reportXmlErrorsAsException = false;
+
+ /**
+ * @var string[]
+ *
+ * @phpstan-var array
+ */
+ private $xPathNamespaces = [];
+
+ /**
+ * @param \DOMNode|SimpleXmlDomInterface|string $element HTML code or SimpleXmlDomInterface, \DOMNode
+ */
+ public function __construct($element = null)
+ {
+ $this->document = new \DOMDocument('1.0', $this->getEncoding());
+
+ // DOMDocument settings
+ $this->document->preserveWhiteSpace = true;
+ $this->document->formatOutput = true;
+
+ if ($element instanceof SimpleXmlDomInterface) {
+ $element = $element->getNode();
+ }
+
+ if ($element instanceof \DOMNode) {
+ $domNode = $this->document->importNode($element, true);
+
+ if ($domNode instanceof \DOMNode) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->document->appendChild($domNode);
+ }
+
+ return;
+ }
+
+ if ($element !== null) {
+ $this->loadXml($element);
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws \BadMethodCallException
+ * @throws \RuntimeException
+ *
+ * @return static
+ */
+ public static function __callStatic($name, $arguments)
+ {
+ $arguments0 = $arguments[0] ?? '';
+
+ $arguments1 = $arguments[1] ?? null;
+
+ if ($name === 'str_get_xml') {
+ $parser = new static();
+
+ return $parser->loadXml($arguments0, $arguments1);
+ }
+
+ if ($name === 'file_get_xml') {
+ $parser = new static();
+
+ return $parser->loadXmlFile($arguments0, $arguments1);
+ }
+
+ throw new \BadMethodCallException('Method does not exist');
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+
+ /**
+ * @param string $name
+ *
+ * @return string|null
+ */
+ public function __get($name)
+ {
+ $name = \strtolower($name);
+
+ if ($name === 'plaintext') {
+ return $this->text();
+ }
+
+ return null;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->xml(false, false, true, 0);
+ }
+
+ /**
+ * Create DOMDocument from XML.
+ *
+ * @param string $xml
+ * @param int|null $libXMLExtraOptions
+ * @param bool $useDefaultLibXMLOptions
+ *
+ * @return \DOMDocument
+ */
+ protected function createDOMDocument(string $xml, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): \DOMDocument
+ {
+ if ($this->callbackBeforeCreateDom) {
+ $xml = \call_user_func($this->callbackBeforeCreateDom, $xml, $this);
+ }
+
+ // set error level
+ $internalErrors = \libxml_use_internal_errors(true);
+ if (\PHP_VERSION_ID < 80000) {
+ $disableEntityLoader = \libxml_disable_entity_loader(true);
+ }
+ \libxml_clear_errors();
+
+ $optionsXml = 0;
+ if ($useDefaultLibXMLOptions) {
+ $optionsXml = \LIBXML_DTDLOAD | \LIBXML_DTDATTR | \LIBXML_NONET;
+
+ if (\defined('LIBXML_BIGLINES')) {
+ $optionsXml |= \LIBXML_BIGLINES;
+ }
+
+ if (\defined('LIBXML_COMPACT')) {
+ $optionsXml |= \LIBXML_COMPACT;
+ }
+ }
+
+ if ($libXMLExtraOptions !== null) {
+ $optionsXml |= $libXMLExtraOptions;
+ }
+
+ $this->xPathNamespaces = []; // reset
+ $matches = [];
+ \preg_match_all('#xmlns:(?.*)=(["\'])(?.*)\\2#Ui', $xml, $matches);
+ foreach ($matches['namespaceKey'] ?? [] as $index => $key) {
+ if ($key) {
+ $this->xPathNamespaces[\trim($key, ':')] = $matches['namespaceValue'][$index];
+ }
+ }
+
+ if ($this->autoRemoveXPathNamespaces) {
+ $xml = $this->removeXPathNamespaces($xml);
+ }
+
+ $xml = self::replaceToPreserveHtmlEntities($xml);
+
+ $documentFound = false;
+ $sxe = \simplexml_load_string($xml, \SimpleXMLElement::class, $optionsXml);
+ $xmlErrors = \libxml_get_errors();
+ if ($sxe !== false && \count($xmlErrors) === 0) {
+ $domElementTmp = \dom_import_simplexml($sxe);
+ if ($domElementTmp->ownerDocument instanceof \DOMDocument) {
+ $documentFound = true;
+ $this->document = $domElementTmp->ownerDocument;
+ }
+ }
+
+ if ($documentFound === false) {
+ // UTF-8 hack: http://php.net/manual/en/domdocument.loadhtml.php#95251
+ $xmlHackUsed = false;
+ /** @noinspection StringFragmentMisplacedInspection */
+ if (\stripos('getEncoding() . '" ?>' . $xml;
+ }
+
+ $documentFound = $this->document->loadXML($xml, $optionsXml);
+
+ // remove the "xml-encoding" hack
+ if ($xmlHackUsed) {
+ foreach ($this->document->childNodes as $child) {
+ if ($child->nodeType === \XML_PI_NODE) {
+ /** @noinspection UnusedFunctionResultInspection */
+ $this->document->removeChild($child);
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (
+ $documentFound === false
+ &&
+ \count($xmlErrors) > 0
+ ) {
+ $errorStr = 'XML-Errors: ' . \print_r($xmlErrors, true) . ' in ' . \print_r($xml, true);
+
+ if (!$this->reportXmlErrorsAsException) {
+ \trigger_error($errorStr, \E_USER_WARNING);
+ } else {
+ throw new \InvalidArgumentException($errorStr);
+ }
+ }
+
+ // set encoding
+ $this->document->encoding = $this->getEncoding();
+
+ // restore lib-xml settings
+ \libxml_clear_errors();
+ \libxml_use_internal_errors($internalErrors);
+ if (\PHP_VERSION_ID < 80000 && isset($disableEntityLoader)) {
+ \libxml_disable_entity_loader($disableEntityLoader);
+ }
+
+ return $this->document;
+ }
+
+ /**
+ * Find list of nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function find(string $selector, $idx = null)
+ {
+ $xPathQuery = SelectorConverter::toXPath($selector, true, false);
+
+ $xPath = new \DOMXPath($this->document);
+
+ if ($this->autoRegisterXPathNamespaces) {
+ foreach ($this->xPathNamespaces as $key => $value) {
+ $xPath->registerNamespace($key, $value);
+ }
+ }
+
+ if ($this->callbackXPathBeforeQuery) {
+ $xPathQuery = \call_user_func($this->callbackXPathBeforeQuery, $selector, $xPathQuery, $xPath, $this);
+ }
+
+ $nodesList = $xPath->query($xPathQuery);
+
+ $elements = new SimpleXmlDomNode();
+
+ if ($nodesList) {
+ foreach ($nodesList as $node) {
+ $elements[] = new SimpleXmlDom($node);
+ }
+ }
+
+ // return all elements
+ if ($idx === null) {
+ if (\count($elements) === 0) {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ return $elements;
+ }
+
+ // handle negative values
+ if ($idx < 0) {
+ $idx = \count($elements) + $idx;
+ }
+
+ // return one element
+ return $elements[$idx] ?? new SimpleXmlDomBlank();
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMulti(string $selector): SimpleXmlDomNodeInterface
+ {
+ return $this->find($selector, null);
+ }
+
+ /**
+ * Find nodes with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function findMultiOrFalse(string $selector)
+ {
+ $return = $this->find($selector, null);
+
+ if ($return instanceof SimpleXmlDomNodeBlank) {
+ return false;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector.
+ *
+ * @param string $selector
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function findOne(string $selector): SimpleXmlDomInterface
+ {
+ return $this->find($selector, 0);
+ }
+
+ /**
+ * Find one node with a CSS or xPath selector or false, if no element is found.
+ *
+ * @param string $selector
+ *
+ * @return false|SimpleXmlDomInterface
+ */
+ public function findOneOrFalse(string $selector)
+ {
+ $return = $this->find($selector, 0);
+
+ if ($return instanceof SimpleXmlDomBlank) {
+ return false;
+ }
+
+ return $return;
+ }
+
+ /**
+ * @param string $content
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function fixHtmlOutput(
+ string $content,
+ bool $multiDecodeNewHtmlEntity = false,
+ bool $putBrokenReplacedBack = true
+ ): string {
+ $content = $this->decodeHtmlEntity($content, $multiDecodeNewHtmlEntity);
+
+ return self::putReplacedBackToPreserveHtmlEntities($content, $putBrokenReplacedBack);
+ }
+
+ /**
+ * Return elements by ".class".
+ *
+ * @param string $class
+ *
+ * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementByClass(string $class): SimpleXmlDomNodeInterface
+ {
+ return $this->findMulti(".{$class}");
+ }
+
+ /**
+ * Return element by #id.
+ *
+ * @param string $id
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementById(string $id): SimpleXmlDomInterface
+ {
+ return $this->findOne("#{$id}");
+ }
+
+ /**
+ * Return element by tag name.
+ *
+ * @param string $name
+ *
+ * @return SimpleXmlDomInterface
+ */
+ public function getElementByTagName(string $name): SimpleXmlDomInterface
+ {
+ $node = $this->document->getElementsByTagName($name)->item(0);
+
+ if ($node === null) {
+ return new SimpleXmlDomBlank();
+ }
+
+ return new SimpleXmlDom($node);
+ }
+
+ /**
+ * Returns elements by "#id".
+ *
+ * @param string $id
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementsById(string $id, $idx = null)
+ {
+ return $this->find("#{$id}", $idx);
+ }
+
+ /**
+ * Returns elements by tag name.
+ *
+ * @param string $name
+ * @param int|null $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function getElementsByTagName(string $name, $idx = null)
+ {
+ $nodesList = $this->document->getElementsByTagName($name);
+
+ $elements = new SimpleXmlDomNode();
+
+ foreach ($nodesList as $node) {
+ $elements[] = new SimpleXmlDom($node);
+ }
+
+ // return all elements
+ if ($idx === null) {
+ if (\count($elements) === 0) {
+ return new SimpleXmlDomNodeBlank();
+ }
+
+ return $elements;
+ }
+
+ // handle negative values
+ if ($idx < 0) {
+ $idx = \count($elements) + $idx;
+ }
+
+ // return one element
+ return $elements[$idx] ?? new SimpleXmlDomNodeBlank();
+ }
+
+ /**
+ * Get dom node's outer html.
+ *
+ * @param bool $multiDecodeNewHtmlEntity
+ * @param bool $putBrokenReplacedBack
+ *
+ * @return string
+ */
+ public function html(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
+ {
+ if (static::$callback !== null) {
+ \call_user_func(static::$callback, [$this]);
+ }
+
+ $content = $this->document->saveHTML();
+
+ if ($content === false) {
+ return '';
+ }
+
+ return $this->fixHtmlOutput($content, $multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
+ }
+
+ /**
+ * Load HTML from string.
+ *
+ * @param string $html
+ * @param int|null $libXMLExtraOptions
+ *
+ * @return $this
+ */
+ public function loadHtml(string $html, $libXMLExtraOptions = null): DomParserInterface
+ {
+ $this->document = $this->createDOMDocument($html, $libXMLExtraOptions);
+
+ return $this;
+ }
+
+ /**
+ * Load HTML from file.
+ *
+ * @param string $filePath
+ * @param int|null $libXMLExtraOptions
+ *
+ * @throws \RuntimeException
+ *
+ * @return $this
+ */
+ public function loadHtmlFile(string $filePath, $libXMLExtraOptions = null): DomParserInterface
+ {
+ if (
+ !\preg_match("/^https?:\/\//i", $filePath)
+ &&
+ !\file_exists($filePath)
+ ) {
+ throw new \RuntimeException("File {$filePath} not found");
+ }
+
+ try {
+ if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
+ $html = \PoweredCache\Dependencies\voku\helper\UTF8::file_get_contents($filePath);
+ } else {
+ $html = \file_get_contents($filePath);
+ }
+ } catch (\Exception $e) {
+ throw new \RuntimeException("Could not load file {$filePath}");
+ }
+
+ if ($html === false) {
+ throw new \RuntimeException("Could not load file {$filePath}");
+ }
+
+ return $this->loadHtml($html, $libXMLExtraOptions);
+ }
+
+ /**
+ * @param string $selector
+ * @param int $idx
+ *
+ * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface
+ */
+ public function __invoke($selector, $idx = null)
+ {
+ return $this->find($selector, $idx);
+ }
+
+ /**
+ * @param string $xml
+ *
+ * @return string
+ */
+ private function removeXPathNamespaces(string $xml): string
+ {
+ foreach ($this->xPathNamespaces as $key => $value) {
+ $xml = \str_replace($key . ':', '', $xml);
+ }
+
+ return (string) \preg_replace('#xmlns:?.*=(["\'])(?:.*)\\1#Ui', '', $xml);
+ }
+
+ /**
+ * Load XML from string.
+ *
+ * @param string $xml
+ * @param int|null $libXMLExtraOptions
+ * @param bool $useDefaultLibXMLOptions
+ *
+ * @return $this
+ */
+ public function loadXml(string $xml, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): self
+ {
+ $this->document = $this->createDOMDocument($xml, $libXMLExtraOptions, $useDefaultLibXMLOptions);
+
+ return $this;
+ }
+
+ /**
+ * Load XML from file.
+ *
+ * @param string $filePath
+ * @param int|null $libXMLExtraOptions
+ * @param bool $useDefaultLibXMLOptions
+ *
+ * @throws \RuntimeException
+ *
+ * @return $this
+ */
+ public function loadXmlFile(string $filePath, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): self
+ {
+ if (
+ !\preg_match("/^https?:\/\//i", $filePath)
+ &&
+ !\file_exists($filePath)
+ ) {
+ throw new \RuntimeException("File {$filePath} not found");
+ }
+
+ try {
+ if (\class_exists('\PoweredCache\Dependencies\voku\helper\UTF8')) {
+ $xml = \PoweredCache\Dependencies\voku\helper\UTF8::file_get_contents($filePath);
+ } else {
+ $xml = \file_get_contents($filePath);
+ }
+ } catch (\Exception $e) {
+ throw new \RuntimeException("Could not load file {$filePath}");
+ }
+
+ if ($xml === false) {
+ throw new \RuntimeException("Could not load file {$filePath}");
+ }
+
+ return $this->loadXml($xml, $libXMLExtraOptions, $useDefaultLibXMLOptions);
+ }
+
+ /**
+ * @param callable $callback
+ * @param \DOMNode|null $domNode
+ *
+ * @return void
+ */
+ public function replaceTextWithCallback($callback, \DOMNode $domNode = null)
+ {
+ if ($domNode === null) {
+ $domNode = $this->document;
+ }
+
+ if ($domNode->hasChildNodes()) {
+ $children = [];
+
+ // since looping through a DOM being modified is a bad idea we prepare an array:
+ foreach ($domNode->childNodes as $child) {
+ $children[] = $child;
+ }
+
+ foreach ($children as $child) {
+ if ($child->nodeType === \XML_TEXT_NODE) {
+ /** @noinspection PhpSillyAssignmentInspection */
+ /** @var \DOMText $child */
+ $child = $child;
+
+ $oldText = self::putReplacedBackToPreserveHtmlEntities($child->wholeText);
+ $newText = $callback($oldText);
+ if ($domNode->ownerDocument) {
+ $newTextNode = $domNode->ownerDocument->createTextNode(self::replaceToPreserveHtmlEntities($newText));
+ $domNode->replaceChild($newTextNode, $child);
+ }
+ } else {
+ $this->replaceTextWithCallback($callback, $child);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param bool $autoRemoveXPathNamespaces
+ *
+ * @return $this
+ */
+ public function autoRemoveXPathNamespaces(bool $autoRemoveXPathNamespaces = true): self
+ {
+ $this->autoRemoveXPathNamespaces = $autoRemoveXPathNamespaces;
+
+ return $this;
+ }
+
+ /**
+ * @param bool $autoRegisterXPathNamespaces
+ *
+ * @return $this
+ */
+ public function autoRegisterXPathNamespaces(bool $autoRegisterXPathNamespaces = true): self
+ {
+ $this->autoRegisterXPathNamespaces = $autoRegisterXPathNamespaces;
+
+ return $this;
+ }
+
+ /**
+ * @param callable $callbackXPathBeforeQuery
+ *
+ * @phpstan-param callable(string $cssSelectorString, string $xPathString, \DOMXPath, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string $callbackXPathBeforeQuery
+ *
+ * @return $this
+ */
+ public function setCallbackXPathBeforeQuery(callable $callbackXPathBeforeQuery): self
+ {
+ $this->callbackXPathBeforeQuery = $callbackXPathBeforeQuery;
+
+ return $this;
+ }
+
+ /**
+ * @param callable $callbackBeforeCreateDom
+ *
+ * @phpstan-param callable(string $xmlString, \PoweredCache\Dependencies\voku\helper\XmlDomParser): string $callbackBeforeCreateDom
+ *
+ * @return $this
+ */
+ public function setCallbackBeforeCreateDom(callable $callbackBeforeCreateDom): self
+ {
+ $this->callbackBeforeCreateDom = $callbackBeforeCreateDom;
+
+ return $this;
+ }
+
+ /**
+ * @param bool $reportXmlErrorsAsException
+ *
+ * @return $this
+ */
+ public function reportXmlErrorsAsException(bool $reportXmlErrorsAsException = true): self
+ {
+ $this->reportXmlErrorsAsException = $reportXmlErrorsAsException;
+
+ return $this;
+ }
+}
From 658c6c2cfb9e9acf3e6456c158bbbd419861bd1a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 12 Nov 2025 09:01:19 +0000
Subject: [PATCH 9/9] Remove test files that were accidentally added to
Dependencies
Co-authored-by: mustafauysal <1421387+mustafauysal@users.noreply.github.com>
---
.../Tests/CssSelectorConverterTest.php | 83 ----
.../Tests/Node/AbstractNodeTestCase.php | 34 --
.../Tests/Node/AttributeNodeTest.php | 37 --
.../CssSelector/Tests/Node/ClassNodeTest.php | 33 --
.../Tests/Node/CombinedSelectorNodeTest.php | 35 --
.../Tests/Node/ElementNodeTest.php | 35 --
.../Tests/Node/FunctionNodeTest.php | 47 --
.../CssSelector/Tests/Node/HashNodeTest.php | 33 --
.../Tests/Node/NegationNodeTest.php | 33 --
.../CssSelector/Tests/Node/PseudoNodeTest.php | 32 --
.../Tests/Node/SelectorNodeTest.php | 34 --
.../Tests/Node/SpecificityTest.php | 63 ---
.../Handler/AbstractHandlerTestCase.php | 70 ---
.../Parser/Handler/CommentHandlerTest.php | 55 ---
.../Tests/Parser/Handler/HashHandlerTest.php | 49 ---
.../Parser/Handler/IdentifierHandlerTest.php | 49 ---
.../Parser/Handler/NumberHandlerTest.php | 50 ---
.../Parser/Handler/StringHandlerTest.php | 50 ---
.../Parser/Handler/WhitespaceHandlerTest.php | 44 --
.../CssSelector/Tests/Parser/ParserTest.php | 263 -----------
.../CssSelector/Tests/Parser/ReaderTest.php | 102 -----
.../Tests/Parser/Shortcut/ClassParserTest.php | 45 --
.../Parser/Shortcut/ElementParserTest.php | 44 --
.../Parser/Shortcut/EmptyStringParserTest.php | 36 --
.../Tests/Parser/Shortcut/HashParserTest.php | 45 --
.../Tests/Parser/TokenStreamTest.php | 97 ----
.../CssSelector/Tests/XPath/Fixtures/ids.html | 52 ---
.../CssSelector/Tests/XPath/Fixtures/lang.xml | 11 -
.../Tests/XPath/Fixtures/shakespear.html | 308 -------------
.../Tests/XPath/TranslatorTest.php | 416 ------------------
.../Component/CssSelector/phpunit.xml.dist | 31 --
31 files changed, 2316 deletions(-)
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
delete mode 100644 includes/classes/Dependencies/Symfony/Component/CssSelector/phpunit.xml.dist
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
deleted file mode 100644
index d42ce90..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/CssSelectorConverterTest.php
+++ /dev/null
@@ -1,83 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\CssSelectorConverter;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\ParseException;
-
-class CssSelectorConverterTest extends TestCase
-{
- public function testCssToXPath()
- {
- $converter = new CssSelectorConverter();
-
- $this->assertEquals('descendant-or-self::*', $converter->toXPath(''));
- $this->assertEquals('descendant-or-self::h1', $converter->toXPath('h1'));
- $this->assertEquals("descendant-or-self::h1[@id = 'foo']", $converter->toXPath('h1#foo'));
- $this->assertEquals("descendant-or-self::h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", $converter->toXPath('h1.foo'));
- $this->assertEquals('descendant-or-self::foo:h1', $converter->toXPath('foo|h1'));
- $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
-
- // Test the cache layer
- $converter = new CssSelectorConverter();
- $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
- }
-
- public function testCssToXPathXml()
- {
- $converter = new CssSelectorConverter(false);
-
- $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
-
- $converter = new CssSelectorConverter(false);
- // Test the cache layer
- $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
- }
-
- public function testParseExceptions()
- {
- $this->expectException(ParseException::class);
- $this->expectExceptionMessage('Expected identifier, but found.');
- $converter = new CssSelectorConverter();
- $converter->toXPath('h1:');
- }
-
- /** @dataProvider getCssToXPathWithoutPrefixTestData */
- public function testCssToXPathWithoutPrefix($css, $xpath)
- {
- $converter = new CssSelectorConverter();
-
- $this->assertEquals($xpath, $converter->toXPath($css, ''), '->parse() parses an input string and returns a node');
- }
-
- public static function getCssToXPathWithoutPrefixTestData()
- {
- return [
- ['h1', 'h1'],
- ['foo|h1', 'foo:h1'],
- ['h1, h2, h3', 'h1 | h2 | h3'],
- ['h1:nth-child(3n+1)', "*/*[(name() = 'h1') and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"],
- ['h1 > p', 'h1/p'],
- ['h1#foo', "h1[@id = 'foo']"],
- ['h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ['h1[class*="foo bar"]', "h1[@class and contains(@class, 'foo bar')]"],
- ['h1[foo|class*="foo bar"]', "h1[@foo:class and contains(@foo:class, 'foo bar')]"],
- ['h1[class]', 'h1[@class]'],
- ['h1 .foo', "h1/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ['h1 #foo', "h1/descendant-or-self::*/*[@id = 'foo']"],
- ['h1 [class*=foo]', "h1/descendant-or-self::*/*[@class and contains(@class, 'foo')]"],
- ['div>.foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ['div > .foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
deleted file mode 100644
index 99460ae..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTestCase.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NodeInterface;
-
-abstract class AbstractNodeTestCase extends TestCase
-{
- /** @dataProvider getToStringConversionTestData */
- public function testToStringConversion(NodeInterface $node, $representation)
- {
- $this->assertEquals($representation, (string) $node);
- }
-
- /** @dataProvider getSpecificityValueTestData */
- public function testSpecificityValue(NodeInterface $node, $value)
- {
- $this->assertEquals($value, $node->getSpecificity()->getValue());
- }
-
- abstract public static function getToStringConversionTestData();
-
- abstract public static function getSpecificityValueTestData();
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
deleted file mode 100644
index 5115605..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\AttributeNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class AttributeNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 'Powered_Cache_Attribute[Element[*][attribute]]'],
- [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][attribute $= 'value']]"],
- [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), "Powered_Cache_Attribute[Element[*][namespace|attribute $= 'value']]"],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 10],
- [new AttributeNode(new ElementNode(null, 'element'), null, 'attribute', 'exists', null), 11],
- [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), 10],
- [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
deleted file mode 100644
index ae43a62..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class ClassNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new ClassNode(new ElementNode(), 'class'), 'Class[Element[*].class]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new ClassNode(new ElementNode(), 'class'), 10],
- [new ClassNode(new ElementNode(null, 'element'), 'class'), 11],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
deleted file mode 100644
index d9b2a38..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
+++ /dev/null
@@ -1,35 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\CombinedSelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class CombinedSelectorNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 'CombinedSelector[Element[*] > Element[*]]'],
- [new CombinedSelectorNode(new ElementNode(), ' ', new ElementNode()), 'CombinedSelector[Element[*] Element[*]]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 0],
- [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode()), 1],
- [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode(null, 'element')), 2],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
deleted file mode 100644
index b3ef2b2..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
+++ /dev/null
@@ -1,35 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-
-class ElementNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new ElementNode(), 'Element[*]'],
- [new ElementNode(null, 'element'), 'Element[element]'],
- [new ElementNode('namespace', 'element'), 'Element[namespace|element]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new ElementNode(), 0],
- [new ElementNode(null, 'element'), 1],
- [new ElementNode('namespace', 'element'), 1],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
deleted file mode 100644
index f99a66b..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-class FunctionNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new FunctionNode(new ElementNode(), 'function'), 'Function[Element[*]:function()]'],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_IDENTIFIER, 'value', 0),
- ]), "Function[Element[*]:function(['value'])]"],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_STRING, 'value1', 0),
- new Token(Token::TYPE_NUMBER, 'value2', 0),
- ]), "Function[Element[*]:function(['value1', 'value2'])]"],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new FunctionNode(new ElementNode(), 'function'), 10],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_IDENTIFIER, 'value', 0),
- ]), 10],
- [new FunctionNode(new ElementNode(), 'function', [
- new Token(Token::TYPE_STRING, 'value1', 0),
- new Token(Token::TYPE_NUMBER, 'value2', 0),
- ]), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
deleted file mode 100644
index d43aac1..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\HashNode;
-
-class HashNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new HashNode(new ElementNode(), 'id'), 'Hash[Element[*]#id]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new HashNode(new ElementNode(), 'id'), 100],
- [new HashNode(new ElementNode(null, 'id'), 'class'), 101],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
deleted file mode 100644
index 9aafe8f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ClassNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\NegationNode;
-
-class NegationNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 'Negation[Element[*]:not(Class[Element[*].class])]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
deleted file mode 100644
index cf13881..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\PseudoNode;
-
-class PseudoNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new PseudoNode(new ElementNode(), 'pseudo'), 'Pseudo[Element[*]:pseudo]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new PseudoNode(new ElementNode(), 'pseudo'), 10],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
deleted file mode 100644
index 142b104..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\ElementNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-
-class SelectorNodeTest extends AbstractNodeTestCase
-{
- public static function getToStringConversionTestData()
- {
- return [
- [new SelectorNode(new ElementNode()), 'Selector[Element[*]]'],
- [new SelectorNode(new ElementNode(), 'pseudo'), 'Selector[Element[*]::pseudo]'],
- ];
- }
-
- public static function getSpecificityValueTestData()
- {
- return [
- [new SelectorNode(new ElementNode()), 0],
- [new SelectorNode(new ElementNode(), 'pseudo'), 1],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
deleted file mode 100644
index 790f8c1..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Node;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\Specificity;
-
-class SpecificityTest extends TestCase
-{
- /** @dataProvider getValueTestData */
- public function testValue(Specificity $specificity, $value)
- {
- $this->assertEquals($value, $specificity->getValue());
- }
-
- /** @dataProvider getValueTestData */
- public function testPlusValue(Specificity $specificity, $value)
- {
- $this->assertEquals($value + 123, $specificity->plus(new Specificity(1, 2, 3))->getValue());
- }
-
- public static function getValueTestData()
- {
- return [
- [new Specificity(0, 0, 0), 0],
- [new Specificity(0, 0, 2), 2],
- [new Specificity(0, 3, 0), 30],
- [new Specificity(4, 0, 0), 400],
- [new Specificity(4, 3, 2), 432],
- ];
- }
-
- /** @dataProvider getCompareTestData */
- public function testCompareTo(Specificity $a, Specificity $b, $result)
- {
- $this->assertEquals($result, $a->compareTo($b));
- }
-
- public static function getCompareTestData()
- {
- return [
- [new Specificity(0, 0, 0), new Specificity(0, 0, 0), 0],
- [new Specificity(0, 0, 1), new Specificity(0, 0, 1), 0],
- [new Specificity(0, 0, 2), new Specificity(0, 0, 1), 1],
- [new Specificity(0, 0, 2), new Specificity(0, 0, 3), -1],
- [new Specificity(0, 4, 0), new Specificity(0, 4, 0), 0],
- [new Specificity(0, 6, 0), new Specificity(0, 5, 11), 1],
- [new Specificity(0, 7, 0), new Specificity(0, 8, 0), -1],
- [new Specificity(9, 0, 0), new Specificity(9, 0, 0), 0],
- [new Specificity(11, 0, 0), new Specificity(10, 11, 0), 1],
- [new Specificity(12, 11, 0), new Specificity(13, 0, 0), -1],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
deleted file mode 100644
index b46f2f7..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTestCase.php
+++ /dev/null
@@ -1,70 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-/**
- * @author Jean-François Simon
- */
-abstract class AbstractHandlerTestCase extends TestCase
-{
- /** @dataProvider getHandleValueTestData */
- public function testHandleValue($value, Token $expectedToken, $remainingContent)
- {
- $reader = new Reader($value);
- $stream = new TokenStream();
-
- $this->assertTrue($this->generateHandler()->handle($reader, $stream));
- $this->assertEquals($expectedToken, $stream->getNext());
- $this->assertRemainingContent($reader, $remainingContent);
- }
-
- /** @dataProvider getDontHandleValueTestData */
- public function testDontHandleValue($value)
- {
- $reader = new Reader($value);
- $stream = new TokenStream();
-
- $this->assertFalse($this->generateHandler()->handle($reader, $stream));
- $this->assertStreamEmpty($stream);
- $this->assertRemainingContent($reader, $value);
- }
-
- abstract public static function getHandleValueTestData();
-
- abstract public static function getDontHandleValueTestData();
-
- abstract protected function generateHandler();
-
- protected function assertStreamEmpty(TokenStream $stream)
- {
- $property = new \ReflectionProperty($stream, 'tokens');
- $property->setAccessible(true);
-
- $this->assertEquals([], $property->getValue($stream));
- }
-
- protected function assertRemainingContent(Reader $reader, $remainingContent)
- {
- if ('' === $remainingContent) {
- $this->assertEquals(0, $reader->getRemainingLength());
- $this->assertTrue($reader->isEOF());
- } else {
- $this->assertEquals(\strlen($remainingContent), $reader->getRemainingLength());
- $this->assertEquals(0, $reader->getOffset($remainingContent));
- }
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
deleted file mode 100644
index 459d8de..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\CommentHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-class CommentHandlerTest extends AbstractHandlerTestCase
-{
- /** @dataProvider getHandleValueTestData */
- public function testHandleValue($value, Token $unusedArgument, $remainingContent)
- {
- $reader = new Reader($value);
- $stream = new TokenStream();
-
- $this->assertTrue($this->generateHandler()->handle($reader, $stream));
- // comments are ignored (not pushed as token in stream)
- $this->assertStreamEmpty($stream);
- $this->assertRemainingContent($reader, $remainingContent);
- }
-
- public static function getHandleValueTestData()
- {
- return [
- // 2nd argument only exists for inherited method compatibility
- ['/* comment */', new Token(null, null, null), ''],
- ['/* comment */foo', new Token(null, null, null), 'foo'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['>'],
- ['+'],
- [' '],
- ];
- }
-
- protected function generateHandler()
- {
- return new CommentHandler();
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
deleted file mode 100644
index a96c861..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\HashHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class HashHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['#id', new Token(Token::TYPE_HASH, 'id', 0), ''],
- ['#123', new Token(Token::TYPE_HASH, '123', 0), ''],
-
- ['#id.class', new Token(Token::TYPE_HASH, 'id', 0), '.class'],
- ['#id element', new Token(Token::TYPE_HASH, 'id', 0), ' element'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['id'],
- ['123'],
- ['<'],
- ['<'],
- ['#'],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new HashHandler($patterns, new TokenizerEscaping($patterns));
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
deleted file mode 100644
index 1cb9ffe..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\IdentifierHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class IdentifierHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['foo', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ''],
- ['foo|bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '|bar'],
- ['foo.class', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '.class'],
- ['foo[attr]', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '[attr]'],
- ['foo bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ' bar'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['>'],
- ['+'],
- [' '],
- ['*|foo'],
- ['/* comment */'],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new IdentifierHandler($patterns, new TokenizerEscaping($patterns));
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
deleted file mode 100644
index e40b86f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\NumberHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class NumberHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['12', new Token(Token::TYPE_NUMBER, '12', 0), ''],
- ['12.34', new Token(Token::TYPE_NUMBER, '12.34', 0), ''],
- ['+12.34', new Token(Token::TYPE_NUMBER, '+12.34', 0), ''],
- ['-12.34', new Token(Token::TYPE_NUMBER, '-12.34', 0), ''],
-
- ['12 arg', new Token(Token::TYPE_NUMBER, '12', 0), ' arg'],
- ['12]', new Token(Token::TYPE_NUMBER, '12', 0), ']'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['hello'],
- ['>'],
- ['+'],
- [' '],
- ['/* comment */'],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new NumberHandler($patterns);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
deleted file mode 100644
index d00233c..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\StringHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
-
-class StringHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- ['"hello"', new Token(Token::TYPE_STRING, 'hello', 1), ''],
- ['"1"', new Token(Token::TYPE_STRING, '1', 1), ''],
- ['" "', new Token(Token::TYPE_STRING, ' ', 1), ''],
- ['""', new Token(Token::TYPE_STRING, '', 1), ''],
- ["'hello'", new Token(Token::TYPE_STRING, 'hello', 1), ''],
-
- ["'foo'bar", new Token(Token::TYPE_STRING, 'foo', 1), 'bar'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['hello'],
- ['>'],
- ['1'],
- [' '],
- ];
- }
-
- protected function generateHandler()
- {
- $patterns = new TokenizerPatterns();
-
- return new StringHandler($patterns, new TokenizerEscaping($patterns));
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
deleted file mode 100644
index 1cd3e9d..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Handler;
-
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Handler\WhitespaceHandler;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-class WhitespaceHandlerTest extends AbstractHandlerTestCase
-{
- public static function getHandleValueTestData()
- {
- return [
- [' ', new Token(Token::TYPE_WHITESPACE, ' ', 0), ''],
- ["\n", new Token(Token::TYPE_WHITESPACE, "\n", 0), ''],
- ["\t", new Token(Token::TYPE_WHITESPACE, "\t", 0), ''],
-
- [' foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), 'foo'],
- [' .foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), '.foo'],
- ];
- }
-
- public static function getDontHandleValueTestData()
- {
- return [
- ['>'],
- ['1'],
- ['a'],
- ];
- }
-
- protected function generateHandler()
- {
- return new WhitespaceHandler();
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
deleted file mode 100644
index a9ef9d6..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
+++ /dev/null
@@ -1,263 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\FunctionNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Parser;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-
-class ParserTest extends TestCase
-{
- /** @dataProvider getParserTestData */
- public function testParser($source, $representation)
- {
- $parser = new Parser();
-
- $this->assertEquals($representation, array_map(function (SelectorNode $node) {
- return (string) $node->getTree();
- }, $parser->parse($source)));
- }
-
- /** @dataProvider getParserExceptionTestData */
- public function testParserException($source, $message)
- {
- $parser = new Parser();
-
- try {
- $parser->parse($source);
- $this->fail('Parser should throw a SyntaxErrorException.');
- } catch (SyntaxErrorException $e) {
- $this->assertEquals($message, $e->getMessage());
- }
- }
-
- /** @dataProvider getPseudoElementsTestData */
- public function testPseudoElements($source, $element, $pseudo)
- {
- $parser = new Parser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($element, (string) $selector->getTree());
- $this->assertEquals($pseudo, (string) $selector->getPseudoElement());
- }
-
- /** @dataProvider getSpecificityTestData */
- public function testSpecificity($source, $value)
- {
- $parser = new Parser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($value, $selector->getSpecificity()->getValue());
- }
-
- /** @dataProvider getParseSeriesTestData */
- public function testParseSeries($series, $a, $b)
- {
- $parser = new Parser();
- $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
- $this->assertCount(1, $selectors);
-
- /** @var FunctionNode $function */
- $function = $selectors[0]->getTree();
- $this->assertEquals([$a, $b], Parser::parseSeries($function->getArguments()));
- }
-
- /** @dataProvider getParseSeriesExceptionTestData */
- public function testParseSeriesException($series)
- {
- $parser = new Parser();
- $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
- $this->assertCount(1, $selectors);
-
- /** @var FunctionNode $function */
- $function = $selectors[0]->getTree();
- $this->expectException(SyntaxErrorException::class);
- Parser::parseSeries($function->getArguments());
- }
-
- public static function getParserTestData()
- {
- return [
- ['*', ['Element[*]']],
- ['*|*', ['Element[*]']],
- ['*|foo', ['Element[foo]']],
- ['foo|*', ['Element[foo|*]']],
- ['foo|bar', ['Element[foo|bar]']],
- ['#foo#bar', ['Hash[Hash[Element[*]#foo]#bar]']],
- ['div>.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['div> .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['div >.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['div > .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ["div \n> \t \t .foo", ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
- ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
- ['div, td.foo, div.bar span', ['Element[div]', 'Class[Element[td].foo]', 'CombinedSelector[Class[Element[div].bar] Element[span]]']],
- ['div > p', ['CombinedSelector[Element[div] > Element[p]]']],
- ['td:first', ['Pseudo[Element[td]:first]']],
- ['td :first', ['CombinedSelector[Element[td] Pseudo[Element[*]:first]]']],
- ['a[name]', ['Powered_Cache_Attribute[Element[a][name]]']],
- ["a[ name\t]", ['Powered_Cache_Attribute[Element[a][name]]']],
- ['a [name]', ['CombinedSelector[Element[a] Powered_Cache_Attribute[Element[*][name]]]']],
- ['[name="foo"]', ["Powered_Cache_Attribute[Element[*][name = 'foo']]"]],
- ["[name='foo[1]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[1]']]"]],
- ["[name='foo[0][bar]']", ["Powered_Cache_Attribute[Element[*][name = 'foo[0][bar]']]"]],
- ['a[rel="include"]', ["Attribute[Element[a][rel = 'include']]"]],
- ['a[rel = include]', ["Attribute[Element[a][rel = 'include']]"]],
- ["a[hreflang |= 'en']", ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
- ['a[hreflang|=en]', ["Powered_Cache_Attribute[Element[a][hreflang |= 'en']]"]],
- ['div:nth-child(10)', ["Function[Element[div]:nth-child(['10'])]"]],
- [':nth-child(2n+2)', ["Function[Element[*]:nth-child(['2', 'n', '+2'])]"]],
- ['div:nth-of-type(10)', ["Function[Element[div]:nth-of-type(['10'])]"]],
- ['div div:nth-of-type(10) .aclass', ["CombinedSelector[CombinedSelector[Element[div] Function[Element[div]:nth-of-type(['10'])]] Class[Element[*].aclass]]"]],
- ['label:only', ['Pseudo[Element[label]:only]']],
- ['a:lang(fr)', ["Function[Element[a]:lang(['fr'])]"]],
- ['div:contains("foo")', ["Function[Element[div]:contains(['foo'])]"]],
- ['div#foobar', ['Hash[Element[div]#foobar]']],
- ['div:not(div.foo)', ['Negation[Element[div]:not(Class[Element[div].foo])]']],
- ['td ~ th', ['CombinedSelector[Element[td] ~ Element[th]]']],
- ['.foo[data-bar][data-baz=0]', ["Powered_Cache_Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]"]],
- ['div#foo\.bar', ['Hash[Element[div]#foo.bar]']],
- ['div.w-1\/3', ['Class[Element[div].w-1/3]']],
- ['#test\:colon', ['Hash[Element[*]#test:colon]']],
- [".a\xc1b", ["Class[Element[*].a\xc1b]"]],
- // unicode escape: \22 == "
- ['*[aval="\'\22\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"\'\']]']],
- ['*[aval="\'\22 2\'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\'"2\'\']]']],
- // unicode escape: \20 == (space)
- ['*[aval="\'\20 \'"]', ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
- ["*[aval=\"'\\20\r\n '\"]", ['Powered_Cache_Attribute[Element[*][aval = \'\' \'\']]']],
- ];
- }
-
- public static function getParserExceptionTestData()
- {
- return [
- ['attributes(href)/html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
- ['attributes(href)', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
- ['html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '/', 4))->getMessage()],
- [' ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 1))->getMessage()],
- ['div, ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 5))->getMessage()],
- [' , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 1))->getMessage()],
- ['p, , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 3))->getMessage()],
- ['div > ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 6))->getMessage()],
- [' > div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '>', 2))->getMessage()],
- ['foo|#bar', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_HASH, 'bar', 4))->getMessage()],
- ['#.foo', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '#', 0))->getMessage()],
- ['.#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
- [':#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
- ['[*]', SyntaxErrorException::unexpectedToken('"|"', new Token(Token::TYPE_DELIMITER, ']', 2))->getMessage()],
- ['[foo|]', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_DELIMITER, ']', 5))->getMessage()],
- ['[#]', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_DELIMITER, '#', 1))->getMessage()],
- ['[foo=#]', SyntaxErrorException::unexpectedToken('string or identifier', new Token(Token::TYPE_DELIMITER, '#', 5))->getMessage()],
- [':nth-child()', SyntaxErrorException::unexpectedToken('at least one argument', new Token(Token::TYPE_DELIMITER, ')', 11))->getMessage()],
- ['[href]a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_IDENTIFIER, 'a', 6))->getMessage()],
- ['[rel:stylesheet]', SyntaxErrorException::unexpectedToken('operator', new Token(Token::TYPE_DELIMITER, ':', 4))->getMessage()],
- ['[rel=stylesheet', SyntaxErrorException::unexpectedToken('"]"', new Token(Token::TYPE_FILE_END, '', 15))->getMessage()],
- [':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()],
- [':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
- ['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
- ];
- }
-
- public static function getPseudoElementsTestData()
- {
- return [
- ['foo', 'Element[foo]', ''],
- ['*', 'Element[*]', ''],
- [':empty', 'Pseudo[Element[*]:empty]', ''],
- [':BEfore', 'Element[*]', 'before'],
- [':aftER', 'Element[*]', 'after'],
- [':First-Line', 'Element[*]', 'first-line'],
- [':First-Letter', 'Element[*]', 'first-letter'],
- ['::befoRE', 'Element[*]', 'before'],
- ['::AFter', 'Element[*]', 'after'],
- ['::firsT-linE', 'Element[*]', 'first-line'],
- ['::firsT-letteR', 'Element[*]', 'first-letter'],
- ['::Selection', 'Element[*]', 'selection'],
- ['foo:after', 'Element[foo]', 'after'],
- ['foo::selection', 'Element[foo]', 'selection'],
- ['lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Powered_Cache_Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'],
- ['video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'],
- ];
- }
-
- public static function getSpecificityTestData()
- {
- return [
- ['*', 0],
- [' foo', 1],
- [':empty ', 10],
- [':before', 1],
- ['*:before', 1],
- [':nth-child(2)', 10],
- ['.bar', 10],
- ['[baz]', 10],
- ['[baz="4"]', 10],
- ['[baz^="4"]', 10],
- ['#lipsum', 100],
- [':not(*)', 0],
- [':not(foo)', 1],
- [':not(.foo)', 10],
- [':not([foo])', 10],
- [':not(:empty)', 10],
- [':not(#foo)', 100],
- ['foo:empty', 11],
- ['foo:before', 2],
- ['foo::before', 2],
- ['foo:empty::before', 12],
- ['#lorem + foo#ipsum:first-child > bar:first-line', 213],
- ];
- }
-
- public static function getParseSeriesTestData()
- {
- return [
- ['1n+3', 1, 3],
- ['1n +3', 1, 3],
- ['1n + 3', 1, 3],
- ['1n+ 3', 1, 3],
- ['1n-3', 1, -3],
- ['1n -3', 1, -3],
- ['1n - 3', 1, -3],
- ['1n- 3', 1, -3],
- ['n-5', 1, -5],
- ['odd', 2, 1],
- ['even', 2, 0],
- ['3n', 3, 0],
- ['n', 1, 0],
- ['+n', 1, 0],
- ['-n', -1, 0],
- ['5', 0, 5],
- ];
- }
-
- public static function getParseSeriesExceptionTestData()
- {
- return [
- ['foo'],
- ['n+'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
deleted file mode 100644
index b160113..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Reader;
-
-class ReaderTest extends TestCase
-{
- public function testIsEOF()
- {
- $reader = new Reader('');
- $this->assertTrue($reader->isEOF());
-
- $reader = new Reader('hello');
- $this->assertFalse($reader->isEOF());
-
- $this->assignPosition($reader, 2);
- $this->assertFalse($reader->isEOF());
-
- $this->assignPosition($reader, 5);
- $this->assertTrue($reader->isEOF());
- }
-
- public function testGetRemainingLength()
- {
- $reader = new Reader('hello');
- $this->assertEquals(5, $reader->getRemainingLength());
-
- $this->assignPosition($reader, 2);
- $this->assertEquals(3, $reader->getRemainingLength());
-
- $this->assignPosition($reader, 5);
- $this->assertEquals(0, $reader->getRemainingLength());
- }
-
- public function testGetSubstring()
- {
- $reader = new Reader('hello');
- $this->assertEquals('he', $reader->getSubstring(2));
- $this->assertEquals('el', $reader->getSubstring(2, 1));
-
- $this->assignPosition($reader, 2);
- $this->assertEquals('ll', $reader->getSubstring(2));
- $this->assertEquals('lo', $reader->getSubstring(2, 1));
- }
-
- public function testGetOffset()
- {
- $reader = new Reader('hello');
- $this->assertEquals(2, $reader->getOffset('ll'));
- $this->assertFalse($reader->getOffset('w'));
-
- $this->assignPosition($reader, 2);
- $this->assertEquals(0, $reader->getOffset('ll'));
- $this->assertFalse($reader->getOffset('he'));
- }
-
- public function testFindPattern()
- {
- $reader = new Reader('hello');
-
- $this->assertFalse($reader->findPattern('/world/'));
- $this->assertEquals(['hello', 'h'], $reader->findPattern('/^([a-z]).*/'));
-
- $this->assignPosition($reader, 2);
- $this->assertFalse($reader->findPattern('/^h.*/'));
- $this->assertEquals(['llo'], $reader->findPattern('/^llo$/'));
- }
-
- public function testMoveForward()
- {
- $reader = new Reader('hello');
- $this->assertEquals(0, $reader->getPosition());
-
- $reader->moveForward(2);
- $this->assertEquals(2, $reader->getPosition());
- }
-
- public function testToEnd()
- {
- $reader = new Reader('hello');
- $reader->moveToEnd();
- $this->assertTrue($reader->isEOF());
- }
-
- private function assignPosition(Reader $reader, int $value)
- {
- $position = new \ReflectionProperty($reader, 'position');
- $position->setAccessible(true);
- $position->setValue($reader, $value);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
deleted file mode 100644
index 188d29f..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
-
-/**
- * @author Jean-François Simon
- */
-class ClassParserTest extends TestCase
-{
- /** @dataProvider getParseTestData */
- public function testParse($source, $representation)
- {
- $parser = new ClassParser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($representation, (string) $selector->getTree());
- }
-
- public static function getParseTestData()
- {
- return [
- ['.testclass', 'Class[Element[*].testclass]'],
- ['testel.testclass', 'Class[Element[testel].testclass]'],
- ['testns|.testclass', 'Class[Element[testns|*].testclass]'],
- ['testns|*.testclass', 'Class[Element[testns|*].testclass]'],
- ['testns|testel.testclass', 'Class[Element[testns|testel].testclass]'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
deleted file mode 100644
index 58540ea..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
-
-/**
- * @author Jean-François Simon
- */
-class ElementParserTest extends TestCase
-{
- /** @dataProvider getParseTestData */
- public function testParse($source, $representation)
- {
- $parser = new ElementParser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($representation, (string) $selector->getTree());
- }
-
- public static function getParseTestData()
- {
- return [
- ['*', 'Element[*]'],
- ['testel', 'Element[testel]'],
- ['testns|*', 'Element[testns|*]'],
- ['testns|testel', 'Element[testns|testel]'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
deleted file mode 100644
index b6540ff..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
-
-/**
- * @author Jean-François Simon
- */
-class EmptyStringParserTest extends TestCase
-{
- public function testParse()
- {
- $parser = new EmptyStringParser();
- $selectors = $parser->parse('');
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals('Element[*]', (string) $selector->getTree());
-
- $selectors = $parser->parse('this will produce an empty array');
- $this->assertCount(0, $selectors);
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
deleted file mode 100644
index 9a92ca4..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser\Shortcut;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Node\SelectorNode;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
-
-/**
- * @author Jean-François Simon
- */
-class HashParserTest extends TestCase
-{
- /** @dataProvider getParseTestData */
- public function testParse($source, $representation)
- {
- $parser = new HashParser();
- $selectors = $parser->parse($source);
- $this->assertCount(1, $selectors);
-
- /** @var SelectorNode $selector */
- $selector = $selectors[0];
- $this->assertEquals($representation, (string) $selector->getTree());
- }
-
- public static function getParseTestData()
- {
- return [
- ['#testid', 'Hash[Element[*]#testid]'],
- ['testel#testid', 'Hash[Element[testel]#testid]'],
- ['testns|#testid', 'Hash[Element[testns|*]#testid]'],
- ['testns|*#testid', 'Hash[Element[testns|*]#testid]'],
- ['testns|testel#testid', 'Hash[Element[testns|testel]#testid]'],
- ];
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
deleted file mode 100644
index ec7f7f5..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
+++ /dev/null
@@ -1,97 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace PoweredCache\Dependencies\Symfony\Component\CssSelector\Tests\Parser;
-
-use PHPUnit\Framework\TestCase;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\Token;
-use PoweredCache\Dependencies\Symfony\Component\CssSelector\Parser\TokenStream;
-
-class TokenStreamTest extends TestCase
-{
- public function testGetNext()
- {
- $stream = new TokenStream();
- $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
-
- $this->assertSame($t1, $stream->getNext());
- $this->assertSame($t2, $stream->getNext());
- $this->assertSame($t3, $stream->getNext());
- }
-
- public function testGetPeek()
- {
- $stream = new TokenStream();
- $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
-
- $this->assertSame($t1, $stream->getPeek());
- $this->assertSame($t1, $stream->getNext());
- $this->assertSame($t2, $stream->getPeek());
- $this->assertSame($t2, $stream->getPeek());
- $this->assertSame($t2, $stream->getNext());
- }
-
- public function testGetNextIdentifier()
- {
- $stream = new TokenStream();
- $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
-
- $this->assertEquals('h1', $stream->getNextIdentifier());
- }
-
- public function testFailToGetNextIdentifier()
- {
- $this->expectException(SyntaxErrorException::class);
-
- $stream = new TokenStream();
- $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->getNextIdentifier();
- }
-
- public function testGetNextIdentifierOrStar()
- {
- $stream = new TokenStream();
-
- $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $this->assertEquals('h1', $stream->getNextIdentifierOrStar());
-
- $stream->push(new Token(Token::TYPE_DELIMITER, '*', 0));
- $this->assertNull($stream->getNextIdentifierOrStar());
- }
-
- public function testFailToGetNextIdentifierOrStar()
- {
- $this->expectException(SyntaxErrorException::class);
-
- $stream = new TokenStream();
- $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
- $stream->getNextIdentifierOrStar();
- }
-
- public function testSkipWhitespace()
- {
- $stream = new TokenStream();
- $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
- $stream->push($t2 = new Token(Token::TYPE_WHITESPACE, ' ', 2));
- $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'h1', 3));
-
- $stream->skipWhitespace();
- $this->assertSame($t1, $stream->getNext());
-
- $stream->skipWhitespace();
- $this->assertSame($t3, $stream->getNext());
- }
-}
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
deleted file mode 100644
index 1147bf3..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml b/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
deleted file mode 100644
index 14f8dbe..0000000
--- a/includes/classes/Dependencies/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
- a
- b
- c
- d
- e
- f
-
-