diff --git a/.gitignore b/.gitignore index c8153b5..8d978e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /composer.lock /vendor/ +.phpunit.result.cache diff --git a/composer.json b/composer.json index 16ba2e4..25cb07a 100644 --- a/composer.json +++ b/composer.json @@ -22,13 +22,16 @@ "ext-mbstring": "*" }, "require-dev": { - "pestphp/pest": "^0.3.0", + "pestphp/pest": "^1.21", "s9e/regexp-builder": "^1.4", "spatie/emoji": "^2.3.0", - "spatie/pest-plugin-snapshots": "^1.0" + "spatie/pest-plugin-snapshots": "^1.0", + "wa72/htmlpagedom": "^2.0 || ^3.0" }, "suggest": { - "spatie/emoji": "*" + "ext-dom": "*", + "spatie/emoji": "*", + "wa72/htmlpagedom": "*" }, "minimum-stability": "dev", "prefer-stable": true, @@ -38,7 +41,10 @@ } }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } }, "scripts": { "generate": "php ./generate.php", diff --git a/src/Exceptions/NoTextChildrenException.php b/src/Exceptions/NoTextChildrenException.php new file mode 100644 index 0000000..f1d2bef --- /dev/null +++ b/src/Exceptions/NoTextChildrenException.php @@ -0,0 +1,9 @@ +'; + + private const FRAGMENT_TEMPLATE = <<<'HTML' + + + + + + +%s + + +HTML; + + public function __construct() + { + if (! class_exists(HtmlPageCrawler::class)) { + throw new RuntimeException( + sprintf('Cannot use %s method unless `wa72/htmlpagedom` is installed.', __METHOD__) + ); + } + } + + public function parse(string $html): string + { + // Parse the HTML page or fragment... + $parsedHtmlRoot = HtmlPageCrawler::create($html); + + if ($parsedHtmlRoot->isHtmlDocument()) { + // We will only transform the body... + $parsedHtml = $parsedHtmlRoot->filter('body'); + } else { + return $this->parseFragment($html); + } + + try { + $this->findAndTwmojifyTextNodes($parsedHtml); + } catch (NoTextChildrenException $e) { + return $html; + } + + // Find the page head and check if meta header should be added + $htmlHead = $parsedHtmlRoot->filter('head'); + $addHeader = false; + if ($htmlHead->getNode(0)->hasChildNodes()) { + $contentTypeMeta = $htmlHead->children('meta[http-equiv="content-type"][content]'); + $metaNode = $contentTypeMeta->getNode(0); + if ( + $metaNode === null || + iterator_to_array($metaNode->attributes)['content']->textContent !== 'text/html; charset=utf-8' + ) { + $this->addUtf8MetaTag($htmlHead); + $contentTypeMeta->remove(); + } + } else { + $this->addUtf8MetaTag($htmlHead); + } + + return $parsedHtmlRoot->saveHTML(); + } + + public function parseFragment(string $html): string + { + $wrappedFragment = sprintf(static::FRAGMENT_TEMPLATE, $html); + + $parsedHtmlRoot = HtmlPageCrawler::create($wrappedFragment); + $parsedHtml = $parsedHtmlRoot->filter('body'); + + try { + $this->findAndTwmojifyTextNodes($parsedHtml); + } catch (NoTextChildrenException $e) { + return $html; + } + + return trim($parsedHtmlRoot->filter('body')->getInnerHtml()); + } + + /** + * @throws NoTextChildrenException + */ + private function findAndTwmojifyTextNodes(HtmlPageCrawler $htmlContent): HtmlPageCrawler + { + // Use xpath to filter only the "TextNodes" within every "Element" + $textNodes = $htmlContent->filterXPath('.//*[normalize-space(text())]'); + + // If the filtered DOM fragment doesn't have TextNode children, return the input HTML. + if ($textNodes->count() === 0) { + throw new NoTextChildrenException(); + } + + $textNodes->each(function (HtmlPageCrawler $node) { + $twemojiContent = (new EmojiText($node->getInnerHtml())) + ->base($this->base) + ->type($this->type) + ->toHtml(); + $node->makeEmpty()->setInnerHtml($twemojiContent); + + return $node; + }); + + return $textNodes; + } + + private function addUtf8MetaTag($htmlHead): void + { + $doc = new DOMDocument(); + $setUtf8Meta = $doc->createDocumentFragment(); + $setUtf8Meta->appendXML(static::UTF8_META); + $htmlHead->append($setUtf8Meta); + } +} diff --git a/src/Twemoji.php b/src/Twemoji.php index 5233c49..bcc36b7 100644 --- a/src/Twemoji.php +++ b/src/Twemoji.php @@ -25,7 +25,7 @@ public function __construct(array $codepoints) public static function emoji(string $emoji): self { - $chars = preg_split('//u', $emoji, null, PREG_SPLIT_NO_EMPTY); + $chars = preg_split('//u', $emoji, -1, PREG_SPLIT_NO_EMPTY); $codepoints = array_map( fn (string $code): string => dechex(mb_ord($code)), @@ -58,6 +58,7 @@ public function url(): string ); } + #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->url(); diff --git a/src/emoji_bytes.regexp b/src/emoji_bytes.regexp index 74314f5..cdc3c75 100644 --- a/src/emoji_bytes.regexp +++ b/src/emoji_bytes.regexp @@ -1 +1 @@ -(?:[#*0-9]\xE2\x83\xA3|\xC2[\xA9\xAE]|\xE2(?:\x80\xBC|\x81\x89|\x84[\xA2\xB9]|\x86[\x94-\x99\xA9\xAA]|\x8C[\x9A\x9B\xA8]|\x8F[\x8F\xA9-\xB3\xB8-\xBA]|\x93\x82|\x96[\xAA\xAB\xB6]|\x97[\x80\xBB-\xBE]|\x98(?:[\x80-\x84\x8E\x91\x94\x95\x98\xA0\xA2\xA3\xA6\xAA\xAE\xAF\xB8-\xBA]|\x9D(?:\xF0\x9F\x8F[\xBB-\xBF])?)|\x99[\x80\x82\x88-\x93\x9F\xA0\xA3\xA5\xA6\xA8\xBB\xBE\xBF]|\x9A[\x92-\x97\x99\x9B\x9C\xA0\xA1\xA7\xAA\xAB\xB0\xB1\xBD\xBE]|\x9B(?:[\x84\x85\x88\x8E\x8F\x91\x93\x94\xA9\xAA\xB0-\xB5\xB7\xB8\xBA\xBD]|\xB9(?:\xEF\xB8\x8F\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F|\xF0\x9F\x8F[\xBB-\xBF](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)?)|\x9C(?:[\x8A-\x8D](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x82\x85\x88\x89\x8F\x92\x94\x96\x9D\xA1\xA8\xB3\xB4])|\x9D(?:[\x84\x87\x8C\x8E\x93-\x95\x97\xA3]|\xA4(?:\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x94\xA5|\xA9\xB9))?)|\x9E[\x95-\x97\xA1\xB0\xBF]|\xA4[\xB4\xB5]|\xAC[\x85-\x87\x9B\x9C]|\xAD[\x90\x95])|\xE3(?:\x80[\xB0\xBD]|\x8A[\x97\x99])|\xF0\x9F(?:\x80\x84|\x83\x8F|\x85[\xB0\xB1\xBE\xBF]|\x86[\x8E\x91-\x9A]|\x87(?:\xA6\xF0\x9F\x87[\xA8-\xAC\xAE\xB1\xB2\xB4\xB6-\xBA\xBC\xBD\xBF]|\xA7\xF0\x9F\x87[\xA6\xA7\xA9-\xAF\xB1-\xB4\xB6-\xB9\xBB\xBC\xBE\xBF]|\xA8\xF0\x9F\x87[\xA6\xA8\xA9\xAB-\xAE\xB0-\xB5\xB7\xBA-\xBF]|\xA9\xF0\x9F\x87[\xAA\xAC\xAF\xB0\xB2\xB4\xBF]|\xAA\xF0\x9F\x87[\xA6\xA8\xAA\xAC\xAD\xB7-\xBA]|\xAB\xF0\x9F\x87[\xAE-\xB0\xB2\xB4\xB7]|\xAC\xF0\x9F\x87[\xA6\xA7\xA9-\xAE\xB1-\xB3\xB5-\xBA\xBC\xBE]|\xAD\xF0\x9F\x87[\xB0\xB2\xB3\xB7\xB9\xBA]|\xAE\xF0\x9F\x87[\xA8-\xAA\xB1-\xB4\xB6-\xB9]|\xAF\xF0\x9F\x87[\xAA\xB2\xB4\xB5]|\xB0\xF0\x9F\x87[\xAA\xAC-\xAE\xB2\xB3\xB5\xB7\xBC\xBE\xBF]|\xB1\xF0\x9F\x87[\xA6-\xA8\xAE\xB0\xB7-\xBB\xBE]|\xB2\xF0\x9F\x87[\xA6\xA8-\xAD\xB0-\xBF]|\xB3\xF0\x9F\x87[\xA6\xA8\xAA-\xAC\xAE\xB1\xB4\xB5\xB7\xBA\xBF]|\xB4\xF0\x9F\x87\xB2|\xB5\xF0\x9F\x87[\xA6\xAA-\xAD\xB0-\xB3\xB7-\xB9\xBC\xBE]|\xB6\xF0\x9F\x87\xA6|\xB7\xF0\x9F\x87[\xAA\xB4\xB8\xBA\xBC]|\xB8\xF0\x9F\x87[\xA6-\xAA\xAC-\xB4\xB7-\xB9\xBB\xBD-\xBF]|\xB9\xF0\x9F\x87[\xA6\xA8\xA9\xAB-\xAD\xAF-\xB4\xB7\xB9\xBB\xBC\xBF]|\xBA\xF0\x9F\x87[\xA6\xAC\xB2\xB3\xB8\xBE\xBF]|\xBB\xF0\x9F\x87[\xA6\xA8\xAA\xAC\xAE\xB3\xBA]|\xBC\xF0\x9F\x87[\xAB\xB8]|\xBD\xF0\x9F\x87\xB0|\xBE\xF0\x9F\x87[\xAA\xB9]|\xBF\xF0\x9F\x87[\xA6\xB2\xBC])|\x88[\x81\x82\x9A\xAF\xB2-\xBA]|\x89[\x90\x91]|\x8C[\x80-\xA1\xA4-\xBF]|\x8D[\x80-\xBF]|\x8E(?:[\x80-\x84\x86-\x93\x96\x97\x99-\x9B\x9E-\xBF]|\x85(?:\xF0\x9F\x8F[\xBB-\xBF])?)|\x8F(?:[\x82\x87](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x83\x84\x8A](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x8B\x8C](?:\xEF\xB8\x8F\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F|\xF0\x9F\x8F[\xBB-\xBF](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)?|[\x80\x81\x85\x86\x88\x89\x8D-\xB0\xB5\xB7-\xBF]|\xB3(?:\xEF\xB8\x8F\xE2\x80\x8D(?:\xE2\x9A\xA7\xEF\xB8\x8F|\xF0\x9F\x8C\x88))?|\xB4(?:\xE2\x80\x8D\xE2\x98\xA0\xEF\xB8\x8F|\xF3\xA0\x81\xA7\xF3\xA0\x81\xA2\xF3\xA0\x81(?:\xA5\xF3\xA0\x81\xAE\xF3\xA0\x81\xA7|\xB3\xF3\xA0\x81\xA3\xF3\xA0\x81\xB4|\xB7\xF3\xA0\x81\xAC\xF3\xA0\x81\xB3)\xF3\xA0\x81\xBF)?)|\x90(?:[\x80-\x87\x89-\x94\x96-\xBA\xBC-\xBF]|\x88(?:\xE2\x80\x8D\xE2\xAC\x9B)?|\x95(?:\xE2\x80\x8D\xF0\x9F\xA6\xBA)?|\xBB(?:\xE2\x80\x8D\xE2\x9D\x84\xEF\xB8\x8F)?)|\x91(?:[\x82\x83\x86-\x90\xA6\xA7\xAB-\xAD\xB2\xB4-\xB6\xB8\xBC](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\xAE\xB0\xB1\xB3\xB7](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80\x84\x85\x91-\xA5\xAA\xB9-\xBB\xBD-\xBF]|\x81(?:\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F\x97\xA8\xEF\xB8\x8F)?|\xA8(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8)|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x91(?:[\xA8\xA9]\xE2\x80\x8D\xF0\x9F\x91(?:\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?)|\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?)|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA6[\xAF-\xB3\xBC\xBD]))|\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBC-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBC(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB\xBD-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBD(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB\xBC\xBE\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBE(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB-\xBD\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBF(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB-\xBE]|\xA6[\xAF-\xB3\xBC\xBD])))?))?|\xA9(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x91(?:\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?|\xA9\xE2\x80\x8D\xF0\x9F\x91(?:\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?))|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA6[\xAF-\xB3\xBC\xBD]))|\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBC-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBC(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB\xBD-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBD(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB\xBC\xBE\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBE(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBD\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBF(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBE]|\xA6[\xAF-\xB3\xBC\xBD])))?))?|\xAF(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)|\x92(?:[\x81\x82\x86\x87](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x83\x85\x8F\x91\xAA](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x80\x84\x88-\x8E\x90\x92-\xA9\xAB-\xBF])|\x93[\x80-\xBD\xBF]|\x94[\x80-\xBD]|\x95(?:[\xB4\xBA](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x89-\x8E\x90-\xA7\xAF\xB0\xB3\xB6-\xB9]|\xB5(?:\xEF\xB8\x8F\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F|\xF0\x9F\x8F[\xBB-\xBF](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)?)|\x96(?:[\x90\x95\x96](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x87\x8A-\x8D\xA4\xA5\xA8\xB1\xB2\xBC])|\x97[\x82-\x84\x91-\x93\x9C-\x9E\xA1\xA3\xA8\xAF\xB3\xBA-\xBF]|\x98(?:[\x80-\xAD\xAF-\xB4\xB7-\xBF]|\xAE(?:\xE2\x80\x8D\xF0\x9F\x92\xA8)?|\xB5(?:\xE2\x80\x8D\xF0\x9F\x92\xAB)?|\xB6(?:\xE2\x80\x8D\xF0\x9F\x8C\xAB\xEF\xB8\x8F)?)|\x99(?:[\x85-\x87\x8B\x8D\x8E](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x8C\x8F](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x80-\x84\x88-\x8A])|\x9A(?:[\xA3\xB4-\xB6](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80-\xA2\xA4-\xB3\xB7-\xBF])|\x9B(?:[\x80\x8C](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x81-\x85\x8B\x8D-\x92\x95-\x97\xA0-\xA5\xA9\xAB\xAC\xB0\xB3-\xBC])|\x9F[\xA0-\xAB]|\xA4(?:[\x8C\x8F\x98-\x9C\x9E\x9F\xB0-\xB4\xB6](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\xA6\xB5\xB7-\xB9\xBD\xBE](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x8D\x8E\x90-\x97\x9D\xA0-\xA5\xA7-\xAF\xBA\xBF]|\xBC(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)|\xA5(?:[\x80-\x85\x87-\xB6\xB8\xBA-\xBF]|\xB7(?:\xF0\x9F\x8F[\xBB-\xBF])?)|\xA6(?:[\xB5\xB6\xBB](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\xB8\xB9](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80-\xB4\xB7\xBA\xBC-\xBF])|\xA7(?:[\x8D-\x8F\x94\x96-\x9D](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x92\x93\x95](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x9E\x9F](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80-\x8B\x90\xA0-\xBF]|\x91(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]|\x9C\x88)\xEF\xB8\x8F|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91|\xA6[\xAF-\xB3\xBC\xBD]))|\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBC-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBC(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB\xBD-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBD(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB\xBC\xBE\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBE(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB-\xBD\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBF(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB-\xBE])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?))?)|\xA9[\xB0-\xB4\xB8-\xBA]|\xAA[\x80-\x86\x90-\xA8\xB0-\xB6]|\xAB[\x80-\x82\x90-\x96])) \ No newline at end of file +(?:[#*0-9]\xE2\x83\xA3|\xC2[\xA9\xAE]|\xE2(?:\x80\xBC|\x81\x89|\x84[\xA2\xB9]|\x86[\x94-\x99\xA9\xAA]|\x8C[\x9A\x9B\xA8]|\x8F[\x8F\xA9-\xB3\xB8-\xBA]|\x93\x82|\x96[\xAA\xAB\xB6]|\x97[\x80\xBB-\xBE]|\x98(?:[\x80-\x84\x8E\x91\x94\x95\x98\xA0\xA2\xA3\xA6\xAA\xAE\xAF\xB8-\xBA]|\x9D(?:\xF0\x9F\x8F[\xBB-\xBF])?)|\x99[\x80\x82\x88-\x93\x9F\xA0\xA3\xA5\xA6\xA8\xBB\xBE\xBF]|\x9A[\x92-\x97\x99\x9B\x9C\xA0\xA1\xA7\xAA\xAB\xB0\xB1\xBD\xBE]|\x9B(?:[\x84\x85\x88\x8E\x8F\x91\x93\x94\xA9\xAA\xB0-\xB5\xB7\xB8\xBA\xBD]|\xB9(?:\xEF\xB8\x8F\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F|\xF0\x9F\x8F[\xBB-\xBF](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)?)|\x9C(?:[\x8A-\x8D](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x82\x85\x88\x89\x8F\x92\x94\x96\x9D\xA1\xA8\xB3\xB4])|\x9D(?:[\x84\x87\x8C\x8E\x93-\x95\x97\xA3]|\xA4(?:\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x94\xA5|\xA9\xB9))?)|\x9E[\x95-\x97\xA1\xB0\xBF]|\xA4[\xB4\xB5]|\xAC[\x85-\x87\x9B\x9C]|\xAD[\x90\x95])|\xE3(?:\x80[\xB0\xBD]|\x8A[\x97\x99])|\xF0\x9F(?:\x80\x84|\x83\x8F|\x85[\xB0\xB1\xBE\xBF]|\x86[\x8E\x91-\x9A]|\x87(?:\xA6\xF0\x9F\x87[\xA8-\xAC\xAE\xB1\xB2\xB4\xB6-\xBA\xBC\xBD\xBF]|\xA7\xF0\x9F\x87[\xA6\xA7\xA9-\xAF\xB1-\xB4\xB6-\xB9\xBB\xBC\xBE\xBF]|\xA8\xF0\x9F\x87[\xA6\xA8\xA9\xAB-\xAE\xB0-\xB5\xB7\xBA-\xBF]|\xA9\xF0\x9F\x87[\xAA\xAC\xAF\xB0\xB2\xB4\xBF]|\xAA\xF0\x9F\x87[\xA6\xA8\xAA\xAC\xAD\xB7-\xBA]|\xAB\xF0\x9F\x87[\xAE-\xB0\xB2\xB4\xB7]|\xAC\xF0\x9F\x87[\xA6\xA7\xA9-\xAE\xB1-\xB3\xB5-\xBA\xBC\xBE]|\xAD\xF0\x9F\x87[\xB0\xB2\xB3\xB7\xB9\xBA]|\xAE\xF0\x9F\x87[\xA8-\xAA\xB1-\xB4\xB6-\xB9]|\xAF\xF0\x9F\x87[\xAA\xB2\xB4\xB5]|\xB0\xF0\x9F\x87[\xAA\xAC-\xAE\xB2\xB3\xB5\xB7\xBC\xBE\xBF]|\xB1\xF0\x9F\x87[\xA6-\xA8\xAE\xB0\xB7-\xBB\xBE]|\xB2\xF0\x9F\x87[\xA6\xA8-\xAD\xB0-\xBF]|\xB3\xF0\x9F\x87[\xA6\xA8\xAA-\xAC\xAE\xB1\xB4\xB5\xB7\xBA\xBF]|\xB4\xF0\x9F\x87\xB2|\xB5\xF0\x9F\x87[\xA6\xAA-\xAD\xB0-\xB3\xB7-\xB9\xBC\xBE]|\xB6\xF0\x9F\x87\xA6|\xB7\xF0\x9F\x87[\xAA\xB4\xB8\xBA\xBC]|\xB8\xF0\x9F\x87[\xA6-\xAA\xAC-\xB4\xB7-\xB9\xBB\xBD-\xBF]|\xB9\xF0\x9F\x87[\xA6\xA8\xA9\xAB-\xAD\xAF-\xB4\xB7\xB9\xBB\xBC\xBF]|\xBA\xF0\x9F\x87[\xA6\xAC\xB2\xB3\xB8\xBE\xBF]|\xBB\xF0\x9F\x87[\xA6\xA8\xAA\xAC\xAE\xB3\xBA]|\xBC\xF0\x9F\x87[\xAB\xB8]|\xBD\xF0\x9F\x87\xB0|\xBE\xF0\x9F\x87[\xAA\xB9]|\xBF\xF0\x9F\x87[\xA6\xB2\xBC])|\x88[\x81\x82\x9A\xAF\xB2-\xBA]|\x89[\x90\x91]|\x8C[\x80-\xA1\xA4-\xBF]|\x8D[\x80-\xBF]|\x8E(?:[\x80-\x84\x86-\x93\x96\x97\x99-\x9B\x9E-\xBF]|\x85(?:\xF0\x9F\x8F[\xBB-\xBF])?)|\x8F(?:[\x82\x87](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x83\x84\x8A](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x8B\x8C](?:\xEF\xB8\x8F\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F|\xF0\x9F\x8F[\xBB-\xBF](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)?|[\x80\x81\x85\x86\x88\x89\x8D-\xB0\xB5\xB7-\xBF]|\xB3(?:\xEF\xB8\x8F\xE2\x80\x8D(?:\xE2\x9A\xA7\xEF\xB8\x8F|\xF0\x9F\x8C\x88))?|\xB4(?:\xE2\x80\x8D\xE2\x98\xA0\xEF\xB8\x8F|\xF3\xA0\x81\xA7\xF3\xA0\x81\xA2\xF3\xA0\x81(?:\xA5\xF3\xA0\x81\xAE\xF3\xA0\x81\xA7|\xB3\xF3\xA0\x81\xA3\xF3\xA0\x81\xB4|\xB7\xF3\xA0\x81\xAC\xF3\xA0\x81\xB3)\xF3\xA0\x81\xBF)?)|\x90(?:[\x88\xA6](?:\xE2\x80\x8D\xE2\xAC\x9B)?|[\x80-\x87\x89-\x94\x96-\xA5\xA7-\xBA\xBC-\xBF]|\x95(?:\xE2\x80\x8D\xF0\x9F\xA6\xBA)?|\xBB(?:\xE2\x80\x8D\xE2\x9D\x84\xEF\xB8\x8F)?)|\x91(?:[\x82\x83\x86-\x90\xA6\xA7\xAB-\xAD\xB2\xB4-\xB6\xB8\xBC](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\xAE\xB0\xB1\xB3\xB7](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80\x84\x85\x91-\xA5\xAA\xB9-\xBB\xBD-\xBF]|\x81(?:\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F\x97\xA8\xEF\xB8\x8F)?|\xA8(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8)|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x91(?:[\xA8\xA9]\xE2\x80\x8D\xF0\x9F\x91(?:\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?)|\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?)|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA6[\xAF-\xB3\xBC\xBD]))|\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBC-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBC(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB\xBD-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBD(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB\xBC\xBE\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBE(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB-\xBD\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBF(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91\xA8\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91\xA8\xF0\x9F\x8F[\xBB-\xBE]|\xA6[\xAF-\xB3\xBC\xBD])))?))?|\xA9(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x91(?:\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?|\xA9\xE2\x80\x8D\xF0\x9F\x91(?:\xA6(?:\xE2\x80\x8D\xF0\x9F\x91\xA6)?|\xA7(?:\xE2\x80\x8D\xF0\x9F\x91[\xA6\xA7])?))|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA6[\xAF-\xB3\xBC\xBD]))|\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBC-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBC(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB\xBD-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBD(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB\xBC\xBE\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBE(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBD\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBF(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\x91[\xA8\xA9]\xF0\x9F\x8F[\xBB-\xBE]|\xA6[\xAF-\xB3\xBC\xBD])))?))?|\xAF(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)|\x92(?:[\x81\x82\x86\x87](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x83\x85\x8F\x91\xAA](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x80\x84\x88-\x8E\x90\x92-\xA9\xAB-\xBF])|\x93[\x80-\xBD\xBF]|\x94[\x80-\xBD]|\x95(?:[\xB4\xBA](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x89-\x8E\x90-\xA7\xAF\xB0\xB3\xB6-\xB9]|\xB5(?:\xEF\xB8\x8F\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F|\xF0\x9F\x8F[\xBB-\xBF](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)?)|\x96(?:[\x90\x95\x96](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x87\x8A-\x8D\xA4\xA5\xA8\xB1\xB2\xBC])|\x97[\x82-\x84\x91-\x93\x9C-\x9E\xA1\xA3\xA8\xAF\xB3\xBA-\xBF]|\x98(?:[\x80-\xAD\xAF-\xB4\xB7-\xBF]|\xAE(?:\xE2\x80\x8D\xF0\x9F\x92\xA8)?|\xB5(?:\xE2\x80\x8D\xF0\x9F\x92\xAB)?|\xB6(?:\xE2\x80\x8D\xF0\x9F\x8C\xAB\xEF\xB8\x8F)?)|\x99(?:[\x85-\x87\x8B\x8D\x8E](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x8C\x8F](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x80-\x84\x88-\x8A])|\x9A(?:[\xA3\xB4-\xB6](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80-\xA2\xA4-\xB3\xB7-\xBF])|\x9B(?:[\x80\x8C](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x81-\x85\x8B\x8D-\x92\x95-\x97\x9C-\xA5\xA9\xAB\xAC\xB0\xB3-\xBC])|\x9F[\xA0-\xAB\xB0]|\xA4(?:[\x8C\x8F\x98-\x9F\xB0-\xB4\xB6](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\xA6\xB5\xB7-\xB9\xBD\xBE](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x8D\x8E\x90-\x97\xA0-\xA5\xA7-\xAF\xBA\xBF]|\xBC(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?)|\xA5(?:[\x80-\x85\x87-\xB6\xB8-\xBF]|\xB7(?:\xF0\x9F\x8F[\xBB-\xBF])?)|\xA6(?:[\xB5\xB6\xBB](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\xB8\xB9](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80-\xB4\xB7\xBA\xBC-\xBF])|\xA7(?:[\x8D-\x8F\x94\x96-\x9D](?:\xF0\x9F\x8F[\xBB-\xBF])?(?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x92\x93\x95](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x9E\x9F](?:\xE2\x80\x8D\xE2\x99[\x80\x82]\xEF\xB8\x8F)?|[\x80-\x8C\x90\xA0-\xBF]|\x91(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]|\x9C\x88)\xEF\xB8\x8F|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91|\xA6[\xAF-\xB3\xBC\xBD]))|\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBC-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBC(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB\xBD-\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBD(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB\xBC\xBE\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBE(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB-\xBD\xBF])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?|\xBF(?:\xE2\x80\x8D(?:\xE2(?:\x9A[\x95\x96]\xEF\xB8\x8F|\x9C\x88\xEF\xB8\x8F|\x9D\xA4\xEF\xB8\x8F\xE2\x80\x8D\xF0\x9F(?:\x92\x8B\xE2\x80\x8D\xF0\x9F)?\xA7\x91\xF0\x9F\x8F[\xBB-\xBE])|\xF0\x9F(?:\x8C\xBE|\x8D[\xB3\xBC]|\x8E[\x84\x93\xA4\xA8]|\x8F[\xAB\xAD]|\x92[\xBB\xBC]|\x94[\xA7\xAC]|\x9A[\x80\x92]|\xA4\x9D\xE2\x80\x8D\xF0\x9F\xA7\x91\xF0\x9F\x8F[\xBB-\xBF]|\xA6[\xAF-\xB3\xBC\xBD])))?))?)|\xA9[\xB0-\xBC]|\xAA[\x80-\x88\x90-\xBD\xBF]|\xAB(?:[\x83-\x85\xB0\xB2-\xB8](?:\xF0\x9F\x8F[\xBB-\xBF])?|[\x80-\x82\x8E-\x9B\xA0-\xA8]|\xB1(?:\xF0\x9F\x8F(?:\xBB(?:\xE2\x80\x8D\xF0\x9F\xAB\xB2\xF0\x9F\x8F[\xBC-\xBF])?|\xBC(?:\xE2\x80\x8D\xF0\x9F\xAB\xB2\xF0\x9F\x8F[\xBB\xBD-\xBF])?|\xBD(?:\xE2\x80\x8D\xF0\x9F\xAB\xB2\xF0\x9F\x8F[\xBB\xBC\xBE\xBF])?|\xBE(?:\xE2\x80\x8D\xF0\x9F\xAB\xB2\xF0\x9F\x8F[\xBB-\xBD\xBF])?|\xBF(?:\xE2\x80\x8D\xF0\x9F\xAB\xB2\xF0\x9F\x8F[\xBB-\xBE])?))?))) \ No newline at end of file diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..04e78b8 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,10 @@ +png(); + + return $htmlReplacer->parse($html); +} diff --git a/tests/Unit/HtmlReplacerFragmentTest.php b/tests/Unit/HtmlReplacerFragmentTest.php new file mode 100644 index 0000000..68cc430 --- /dev/null +++ b/tests/Unit/HtmlReplacerFragmentTest.php @@ -0,0 +1,78 @@ +๐Ÿš€

')); +}); + +it('will not convert an emoji within HTML attributes', function () { + assertMatchesTextSnapshot(htmlReplacerPngParser('๐ŸŽ‰')); +}); + +it('will not convert an emoji within SCRIPT tags', function () { + assertMatchesTextSnapshot(htmlReplacerPngParser("")); +}); + +it('can convert many Emoji in an HTML comment section', function () { + $commentsHtml = <<<'HTML' +
+
+

Time for a ElePHPant RAVE!

+

๐Ÿ˜๐Ÿ˜๐Ÿ˜๐Ÿ˜

+

๐Ÿ˜๐Ÿ˜๐Ÿ˜

+

๐Ÿ˜๐Ÿ˜๐Ÿ˜๐Ÿ˜๐Ÿ˜

+

๐Ÿ˜๐Ÿ˜

+
+
+
+
+

Time for a cRUSTation RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€

+
+
+
+
+

but what if the crabs and elephants rave together?!

+
+
+
+
+HTML; + assertMatchesTextSnapshot(htmlReplacerPngParser($commentsHtml)); +}); + +it('can convert many Emoji in an HTML article', function () { + $commentsHtml = <<<'HTML' +
+

Lorem ๐Ÿ˜‚๐Ÿ˜‚ ipsum ๐Ÿ•ต๏ธโ€โ™‚๏ธdolor sitโœ๏ธ amet, consectetur adipiscing๐Ÿ˜‡๐Ÿ˜‡๐Ÿค™ elit, sed do eiusmod๐Ÿฅฐ tempor ๐Ÿ˜ค๐Ÿ˜ค๐Ÿณ๏ธโ€๐ŸŒˆincididunt ut ๐Ÿ‘labore ๐Ÿ‘et๐Ÿ‘ dolore ๐Ÿ‘magna๐Ÿ‘ aliqua.

+

Ut enim ad minim ๐ŸตโœŠ๐Ÿฟveniam,โค๏ธ๐Ÿ˜ค๐Ÿ˜ซ๐Ÿ˜ฉ๐Ÿ’ฆ๐Ÿ’ฆ quis nostrud ๐Ÿ‘ฟ๐Ÿคฎexercitation ullamco ๐Ÿง ๐Ÿ‘ฎ๐Ÿฟโ€โ™€๏ธ๐Ÿ…ฑ๏ธlaboris nisi ut aliquipโ—๏ธ ex ea commodo consequat.

+

๐Ÿ’ฏDuis aute๐Ÿ’ฆ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚ irure dolor ๐Ÿ‘ณ๐Ÿปโ€โ™‚๏ธ๐Ÿ—ฟin reprehenderit ๐Ÿค–๐Ÿ‘ป๐Ÿ‘Žin voluptate velit esse cillum dolore ๐Ÿ™๐Ÿ™eu fugiat๐Ÿค” nulla pariatur.

+

๐Ÿ™…โ€โ™€๏ธ๐Ÿ™…โ€โ™€๏ธExcepteur sint occaecat๐Ÿคทโ€โ™€๏ธ๐Ÿคฆโ€โ™€๏ธ cupidatat๐Ÿ’… non๐Ÿ’ƒ proident,๐Ÿ‘จโ€๐Ÿ‘ง sunt๐Ÿค— in culpa๐Ÿ˜ฅ๐Ÿ˜ฐ๐Ÿ˜จ qui officia๐Ÿคฉ๐Ÿคฉ deserunt mollit ๐Ÿงanim id est laborum.๐Ÿค”๐Ÿค”

+
+HTML; + assertMatchesTextSnapshot(htmlReplacerPngParser($commentsHtml)); +}); + +it('can handle text with an outer P tag', function () { + $textContent = '

This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding <p> tags enabled. ๐ŸŽ‰

'; + assertMatchesTextSnapshot(htmlReplacerPngParser($textContent)); +}); + +it('can handle text with an outer P tag and CODE tag', function () { + $textContent = '

This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding <p> tags enabled. ๐ŸŽ‰

'; + assertMatchesTextSnapshot(htmlReplacerPngParser($textContent)); +}); + +it('can handle text without outer P tag and escaped HTML', function () { + $textContent = 'This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding <p> tags disabled. ๐ŸŽ‰'; + assertMatchesTextSnapshot(htmlReplacerPngParser($textContent)); +}); + +it('can handle text without outer P tag but inner HTML', function () { + $textContent = 'This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding

tags disabled. ๐ŸŽ‰'; + assertMatchesTextSnapshot(htmlReplacerPngParser($textContent)); +})->skip('Fails: Mutates the code content to close the p tag'); diff --git a/tests/Unit/HtmlReplacerPageTest.php b/tests/Unit/HtmlReplacerPageTest.php new file mode 100644 index 0000000..6d7b909 --- /dev/null +++ b/tests/Unit/HtmlReplacerPageTest.php @@ -0,0 +1,125 @@ + + + + + +HTML; + assertMatchesTextSnapshot(htmlReplacerPngParser($pageHtml)); +}); + +it('will replace a single Emoji on an page', function () { + $pageHtml = <<<'HTML' + + + + Hey ๐Ÿš€ + +HTML; + assertMatchesTextSnapshot(htmlReplacerPngParser($pageHtml)); +}); + +it('will not replace a single Emoji in the Title', function () { + $pageHtml = <<<'HTML' + + + + + + + HTML 5๐Ÿš€ Boilerplate + + + + +HTML; + $results = htmlReplacerPngParser($pageHtml); + expect($results)->toContain('5๐Ÿš€')->not()->toContain('&#'); + assertMatchesTextSnapshot($results); +}); + +it('will replace the Emoji on page, but not in head - OLD Charset Method', function () { + $pageHtml = <<<'HTML' + + + + + + + HTML 5๐Ÿš€ Boilerplate + + + +

Do a quick kickflip! ๐Ÿ›น

+

This is HTML text that should be replaced, but the emoji in the head should not.

+

Time for a CRAB RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿ™๐Ÿ˜

+ + +HTML; + $results = htmlReplacerPngParser($pageHtml); + expect($results)->toContain('5๐Ÿš€')->not()->toContain('5&#'); + assertMatchesTextSnapshot($results); +}); + +it('will replace the Emoji on page, but not in head - NEW Charset Method', function () { + $pageHtml = <<<'HTML' + + + + + + + HTML 5๐Ÿš€ Boilerplate + + + +

Do a quick kickflip! ๐Ÿ›น

+

This is HTML text that should be replaced, but the emoji in the head should not.

+

Time for a CRAB RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿ™๐Ÿ˜

+ + +HTML; + $results = htmlReplacerPngParser($pageHtml); + expect($results)->toContain('5๐Ÿš€')->not()->toContain('5&#'); + assertMatchesTextSnapshot($results); +}); + +it('will correct invalid content-type meta tag', function () { + $pageHtml = <<<'HTML' + + + + + + + HTML 5๐Ÿš€ Boilerplate + + + +

Do a quick kickflip! ๐Ÿ›น

+

This is HTML text that should be replaced, but the emoji in the head should not.

+

Time for a CRAB RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿ™๐Ÿ˜

+ + +HTML; + $results = htmlReplacerPngParser($pageHtml); + expect($results)->toContain('5๐Ÿš€')->not()->toContain('5&#'); + assertMatchesTextSnapshot($results); +}); diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_a_single_emoji_paragraph__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_a_single_emoji_paragraph__1.txt new file mode 100644 index 0000000..2835d2b --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_a_single_emoji_paragraph__1.txt @@ -0,0 +1 @@ +

๐Ÿš€

\ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_many_Emoji_in_an_HTML_article__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_many_Emoji_in_an_HTML_article__1.txt new file mode 100644 index 0000000..d97fef8 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_many_Emoji_in_an_HTML_article__1.txt @@ -0,0 +1,6 @@ +
+

Lorem ๐Ÿ˜‚๐Ÿ˜‚ ipsum ๐Ÿ•ต๏ธโ€โ™‚๏ธdolor sitโœ๏ธ amet, consectetur adipiscing๐Ÿ˜‡๐Ÿ˜‡๐Ÿค™ elit, sed do eiusmod๐Ÿฅฐ tempor ๐Ÿ˜ค๐Ÿ˜ค๐Ÿณ๏ธโ€๐ŸŒˆincididunt ut ๐Ÿ‘labore ๐Ÿ‘et๐Ÿ‘ dolore ๐Ÿ‘magna๐Ÿ‘ aliqua.

+

Ut enim ad minim ๐ŸตโœŠ๐Ÿฟveniam,โค๏ธ๐Ÿ˜ค๐Ÿ˜ซ๐Ÿ˜ฉ๐Ÿ’ฆ๐Ÿ’ฆ quis nostrud ๐Ÿ‘ฟ๐Ÿคฎexercitation ullamco ๐Ÿง ๐Ÿ‘ฎ๐Ÿฟโ€โ™€๏ธ๐Ÿ…ฑ๏ธlaboris nisi ut aliquipโ—๏ธ ex ea commodo consequat.

+

๐Ÿ’ฏDuis aute๐Ÿ’ฆ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚ irure dolor ๐Ÿ‘ณ๐Ÿปโ€โ™‚๏ธ๐Ÿ—ฟin reprehenderit ๐Ÿค–๐Ÿ‘ป๐Ÿ‘Žin voluptate velit esse cillum dolore ๐Ÿ™๐Ÿ™eu fugiat๐Ÿค” nulla pariatur.

+

๐Ÿ™…โ€โ™€๏ธ๐Ÿ™…โ€โ™€๏ธExcepteur sint occaecat๐Ÿคทโ€โ™€๏ธ๐Ÿคฆโ€โ™€๏ธ cupidatat๐Ÿ’… non๐Ÿ’ƒ proident,๐Ÿ‘จโ€๐Ÿ‘ง sunt๐Ÿค— in culpa๐Ÿ˜ฅ๐Ÿ˜ฐ๐Ÿ˜จ qui officia๐Ÿคฉ๐Ÿคฉ deserunt mollit ๐Ÿงanim id est laborum.๐Ÿค”๐Ÿค”

+
\ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_many_Emoji_in_an_HTML_comment_section__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_many_Emoji_in_an_HTML_comment_section__1.txt new file mode 100644 index 0000000..1082cc5 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_convert_many_Emoji_in_an_HTML_comment_section__1.txt @@ -0,0 +1,25 @@ +
+
+

Time for a ElePHPant RAVE!

+

๐Ÿ˜๐Ÿ˜๐Ÿ˜๐Ÿ˜

+

๐Ÿ˜๐Ÿ˜๐Ÿ˜

+

๐Ÿ˜๐Ÿ˜๐Ÿ˜๐Ÿ˜๐Ÿ˜

+

๐Ÿ˜๐Ÿ˜

+
+
+
+
+

Time for a cRUSTation RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€

+
+
+
+
+

but what if the crabs and elephants rave together?!

+
+
+
+
\ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_with_an_outer_P_tag__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_with_an_outer_P_tag__1.txt new file mode 100644 index 0000000..adc8ef7 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_with_an_outer_P_tag__1.txt @@ -0,0 +1 @@ +

This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding <p> tags enabled. ๐ŸŽ‰

\ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_with_an_outer_P_tag_and_CODE_tag__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_with_an_outer_P_tag_and_CODE_tag__1.txt new file mode 100644 index 0000000..842f3db --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_with_an_outer_P_tag_and_CODE_tag__1.txt @@ -0,0 +1 @@ +

This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding <p> tags enabled. ๐ŸŽ‰

\ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_without_outer_P_tag_and_escaped_HTML__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_without_outer_P_tag_and_escaped_HTML__1.txt new file mode 100644 index 0000000..4aa185e --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_without_outer_P_tag_and_escaped_HTML__1.txt @@ -0,0 +1 @@ +This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding <p> tags disabled. ๐ŸŽ‰ \ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_without_outer_P_tag_but_inner_HTML__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_without_outer_P_tag_but_inner_HTML__1.txt new file mode 100644 index 0000000..ed20e5d --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_can_handle_text_without_outer_P_tag_but_inner_HTML__1.txt @@ -0,0 +1 @@ +This is some fancy-๐Ÿ’ƒ Markdown/WYSIWYG text with surrounding

tags disabled. ๐ŸŽ‰ diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_will_not_convert_an_emoji_within_HTML_attributes__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_will_not_convert_an_emoji_within_HTML_attributes__1.txt new file mode 100644 index 0000000..483ef65 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_will_not_convert_an_emoji_within_HTML_attributes__1.txt @@ -0,0 +1 @@ +๐ŸŽ‰ \ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerFragmentTest__it_will_not_convert_an_emoji_within_SCRIPT_tags__1.txt b/tests/__snapshots__/HtmlReplacerFragmentTest__it_will_not_convert_an_emoji_within_SCRIPT_tags__1.txt new file mode 100644 index 0000000..a9a2d93 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerFragmentTest__it_will_not_convert_an_emoji_within_SCRIPT_tags__1.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerPageTest__it_will_correct_invalid_content-type_meta_tag__1.txt b/tests/__snapshots__/HtmlReplacerPageTest__it_will_correct_invalid_content-type_meta_tag__1.txt new file mode 100644 index 0000000..a7b7416 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerPageTest__it_will_correct_invalid_content-type_meta_tag__1.txt @@ -0,0 +1,18 @@ + + + + + + HTML 5๐Ÿš€ Boilerplate + + + +

Do a quick kickflip! ๐Ÿ›น

+

This is HTML text that should be replaced, but the emoji in the head should not.

+

Time for a CRAB RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿ™๐Ÿ˜

+ + diff --git a/tests/__snapshots__/HtmlReplacerPageTest__it_will_not_mangle_an_Empty_HTML_page__1.txt b/tests/__snapshots__/HtmlReplacerPageTest__it_will_not_mangle_an_Empty_HTML_page__1.txt new file mode 100644 index 0000000..55a5d94 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerPageTest__it_will_not_mangle_an_Empty_HTML_page__1.txt @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerPageTest__it_will_not_replace_a_single_Emoji_in_the_Title__1.txt b/tests/__snapshots__/HtmlReplacerPageTest__it_will_not_replace_a_single_Emoji_in_the_Title__1.txt new file mode 100644 index 0000000..e33d55e --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerPageTest__it_will_not_replace_a_single_Emoji_in_the_Title__1.txt @@ -0,0 +1,11 @@ + + + + + + + HTML 5๐Ÿš€ Boilerplate + + + + \ No newline at end of file diff --git a/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_a_single_Emoji_on_an_page__1.txt b/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_a_single_Emoji_on_an_page__1.txt new file mode 100644 index 0000000..4d54a55 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_a_single_Emoji_on_an_page__1.txt @@ -0,0 +1,4 @@ + + + Hey ๐Ÿš€ + diff --git a/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_the_Emoji_on_page,_but_not_in_head_-_NEW_Charset_Method__1.txt b/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_the_Emoji_on_page,_but_not_in_head_-_NEW_Charset_Method__1.txt new file mode 100644 index 0000000..f85e8f5 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_the_Emoji_on_page,_but_not_in_head_-_NEW_Charset_Method__1.txt @@ -0,0 +1,18 @@ + + + + + + HTML 5๐Ÿš€ Boilerplate + + + +

Do a quick kickflip! ๐Ÿ›น

+

This is HTML text that should be replaced, but the emoji in the head should not.

+

Time for a CRAB RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿ™๐Ÿ˜

+ + diff --git a/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_the_Emoji_on_page,_but_not_in_head_-_OLD_Charset_Method__1.txt b/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_the_Emoji_on_page,_but_not_in_head_-_OLD_Charset_Method__1.txt new file mode 100644 index 0000000..72c74f6 --- /dev/null +++ b/tests/__snapshots__/HtmlReplacerPageTest__it_will_replace_the_Emoji_on_page,_but_not_in_head_-_OLD_Charset_Method__1.txt @@ -0,0 +1,18 @@ + + + + + + HTML 5๐Ÿš€ Boilerplate + + + +

Do a quick kickflip! ๐Ÿ›น

+

This is HTML text that should be replaced, but the emoji in the head should not.

+

Time for a CRAB RAVE!

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€๐Ÿฆ€

+

๐Ÿ™๐Ÿ˜

+ +