From: Tim Düsterhus Date: Thu, 19 Nov 2020 13:30:40 +0000 (+0100) Subject: Update pelago/emogrifier to 4.0 X-Git-Tag: 5.4.0_Alpha_1~593^2~1 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=de2fdfd8e7deea2746b088b76aee0fe6704d0764;p=GitHub%2FWoltLab%2FWCF.git Update pelago/emogrifier to 4.0 --- diff --git a/wcfsetup/install/files/lib/system/api/composer.json b/wcfsetup/install/files/lib/system/api/composer.json index 53caffb147..24d419216d 100644 --- a/wcfsetup/install/files/lib/system/api/composer.json +++ b/wcfsetup/install/files/lib/system/api/composer.json @@ -10,7 +10,7 @@ "require": { "ezyang/htmlpurifier": "4.13.*", "erusev/parsedown": "1.7.*", - "pelago/emogrifier": "2.1.*", + "pelago/emogrifier": "4.0.*", "chrisjean/php-ico": "1.0.*", "true/punycode": "~2.0", "pear/net_idna2": "^0.2.0", diff --git a/wcfsetup/install/files/lib/system/api/composer.lock b/wcfsetup/install/files/lib/system/api/composer.lock index da84909330..0f0ab507e9 100644 --- a/wcfsetup/install/files/lib/system/api/composer.lock +++ b/wcfsetup/install/files/lib/system/api/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "11c5b4995ff3a595d75c77350b9556ec", + "content-hash": "88f8ac80c8e871d978df5d19cf119c8e", "packages": [ { "name": "chrisjean/php-ico", @@ -537,39 +537,41 @@ }, { "name": "pelago/emogrifier", - "version": "v2.1.1", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/emogrifier.git", - "reference": "8ee7fb5ad772915451ed3415c1992bd3697d4983" + "reference": "f6fd679303c6e6861b5ff29af221f684729d8fd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/8ee7fb5ad772915451ed3415c1992bd3697d4983", - "reference": "8ee7fb5ad772915451ed3415c1992bd3697d4983", + "url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/f6fd679303c6e6861b5ff29af221f684729d8fd9", + "reference": "f6fd679303c6e6861b5ff29af221f684729d8fd9", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "php": "^5.5.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0", - "symfony/css-selector": "^3.4.0 || ^4.0.0" + "php": "~7.0 || ~7.1 || ~7.2 || ~7.3 || ~7.4", + "symfony/css-selector": "^3.4.32 || ^4.3.5 || ^5.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2.0", - "phpmd/phpmd": "^2.6.0", - "phpunit/phpunit": "^4.8.0", - "squizlabs/php_codesniffer": "^3.3.2" + "grogy/php-parallel-lint": "^1.1.0", + "phpunit/phpunit": "^6.5.14", + "psalm/plugin-phpunit": "^0.5.8", + "slevomat/coding-standard": "^4.0.0", + "squizlabs/php_codesniffer": "^3.5.1", + "vimeo/psalm": "^3.2.12" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "5.0.x-dev" } }, "autoload": { "psr-4": { - "Pelago\\": "src/" + "Pelago\\Emogrifier\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -577,16 +579,6 @@ "MIT" ], "authors": [ - { - "name": "John Reeve", - "email": "jreeve@pelagodesign.com" - }, - { - "name": "Cameron Brooks" - }, - { - "name": "Jaime Prado" - }, { "name": "Oliver Klee", "email": "github@oliverklee.de" @@ -595,9 +587,19 @@ "name": "Zoli Szabó", "email": "zoli.szabo+github@gmail.com" }, + { + "name": "John Reeve", + "email": "jreeve@pelagodesign.com" + }, { "name": "Jake Hotson", "email": "jake@qzdesign.co.uk" + }, + { + "name": "Cameron Brooks" + }, + { + "name": "Jaime Prado" } ], "description": "Converts CSS styles into inline style attributes in your HTML code", @@ -607,7 +609,11 @@ "email", "pre-processing" ], - "time": "2018-12-10T10:36:30+00:00" + "support": { + "issues": "https://github.com/MyIntervals/emogrifier/issues", + "source": "https://github.com/MyIntervals/emogrifier" + }, + "time": "2020-06-12T12:55:03+00:00" }, { "name": "psr/http-client", diff --git a/wcfsetup/install/files/lib/system/api/composer/InstalledVersions.php b/wcfsetup/install/files/lib/system/api/composer/InstalledVersions.php index 64f6adb556..03e40ce82b 100644 --- a/wcfsetup/install/files/lib/system/api/composer/InstalledVersions.php +++ b/wcfsetup/install/files/lib/system/api/composer/InstalledVersions.php @@ -116,12 +116,12 @@ private static $installed = array ( ), 'pelago/emogrifier' => array ( - 'pretty_version' => 'v2.1.1', - 'version' => '2.1.1.0', + 'pretty_version' => 'v4.0.0', + 'version' => '4.0.0.0', 'aliases' => array ( ), - 'reference' => '8ee7fb5ad772915451ed3415c1992bd3697d4983', + 'reference' => 'f6fd679303c6e6861b5ff29af221f684729d8fd9', ), 'psr/http-client' => array ( diff --git a/wcfsetup/install/files/lib/system/api/composer/autoload_psr4.php b/wcfsetup/install/files/lib/system/api/composer/autoload_psr4.php index b810a52444..824dc84ca6 100644 --- a/wcfsetup/install/files/lib/system/api/composer/autoload_psr4.php +++ b/wcfsetup/install/files/lib/system/api/composer/autoload_psr4.php @@ -12,7 +12,7 @@ return array( 'ScssPhp\\ScssPhp\\' => array($vendorDir . '/scssphp/scssphp/src'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), - 'Pelago\\' => array($vendorDir . '/pelago/emogrifier/src'), + 'Pelago\\Emogrifier\\' => array($vendorDir . '/pelago/emogrifier/src'), 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), diff --git a/wcfsetup/install/files/lib/system/api/composer/autoload_static.php b/wcfsetup/install/files/lib/system/api/composer/autoload_static.php index 8abb57a3ca..d81f4fb95d 100644 --- a/wcfsetup/install/files/lib/system/api/composer/autoload_static.php +++ b/wcfsetup/install/files/lib/system/api/composer/autoload_static.php @@ -30,7 +30,7 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d array ( 'Psr\\Http\\Message\\' => 17, 'Psr\\Http\\Client\\' => 16, - 'Pelago\\' => 7, + 'Pelago\\Emogrifier\\' => 18, 'ParagonIE\\ConstantTime\\' => 23, ), 'G' => @@ -66,7 +66,7 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d array ( 0 => __DIR__ . '/..' . '/psr/http-client/src', ), - 'Pelago\\' => + 'Pelago\\Emogrifier\\' => array ( 0 => __DIR__ . '/..' . '/pelago/emogrifier/src', ), diff --git a/wcfsetup/install/files/lib/system/api/composer/installed.json b/wcfsetup/install/files/lib/system/api/composer/installed.json index 30446fb034..954c8fe154 100644 --- a/wcfsetup/install/files/lib/system/api/composer/installed.json +++ b/wcfsetup/install/files/lib/system/api/composer/installed.json @@ -558,42 +558,44 @@ }, { "name": "pelago/emogrifier", - "version": "v2.1.1", - "version_normalized": "2.1.1.0", + "version": "v4.0.0", + "version_normalized": "4.0.0.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/emogrifier.git", - "reference": "8ee7fb5ad772915451ed3415c1992bd3697d4983" + "reference": "f6fd679303c6e6861b5ff29af221f684729d8fd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/8ee7fb5ad772915451ed3415c1992bd3697d4983", - "reference": "8ee7fb5ad772915451ed3415c1992bd3697d4983", + "url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/f6fd679303c6e6861b5ff29af221f684729d8fd9", + "reference": "f6fd679303c6e6861b5ff29af221f684729d8fd9", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "php": "^5.5.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0", - "symfony/css-selector": "^3.4.0 || ^4.0.0" + "php": "~7.0 || ~7.1 || ~7.2 || ~7.3 || ~7.4", + "symfony/css-selector": "^3.4.32 || ^4.3.5 || ^5.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2.0", - "phpmd/phpmd": "^2.6.0", - "phpunit/phpunit": "^4.8.0", - "squizlabs/php_codesniffer": "^3.3.2" - }, - "time": "2018-12-10T10:36:30+00:00", + "grogy/php-parallel-lint": "^1.1.0", + "phpunit/phpunit": "^6.5.14", + "psalm/plugin-phpunit": "^0.5.8", + "slevomat/coding-standard": "^4.0.0", + "squizlabs/php_codesniffer": "^3.5.1", + "vimeo/psalm": "^3.2.12" + }, + "time": "2020-06-12T12:55:03+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "5.0.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { - "Pelago\\": "src/" + "Pelago\\Emogrifier\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -601,16 +603,6 @@ "MIT" ], "authors": [ - { - "name": "John Reeve", - "email": "jreeve@pelagodesign.com" - }, - { - "name": "Cameron Brooks" - }, - { - "name": "Jaime Prado" - }, { "name": "Oliver Klee", "email": "github@oliverklee.de" @@ -619,9 +611,19 @@ "name": "Zoli Szabó", "email": "zoli.szabo+github@gmail.com" }, + { + "name": "John Reeve", + "email": "jreeve@pelagodesign.com" + }, { "name": "Jake Hotson", "email": "jake@qzdesign.co.uk" + }, + { + "name": "Cameron Brooks" + }, + { + "name": "Jaime Prado" } ], "description": "Converts CSS styles into inline style attributes in your HTML code", @@ -631,6 +633,10 @@ "email", "pre-processing" ], + "support": { + "issues": "https://github.com/MyIntervals/emogrifier/issues", + "source": "https://github.com/MyIntervals/emogrifier" + }, "install-path": "../pelago/emogrifier" }, { @@ -1050,5 +1056,6 @@ "install-path": "../true/punycode" } ], - "dev": true + "dev": true, + "dev-package-names": [] } diff --git a/wcfsetup/install/files/lib/system/api/composer/installed.php b/wcfsetup/install/files/lib/system/api/composer/installed.php index 55dcfcf5be..b2473602fa 100644 --- a/wcfsetup/install/files/lib/system/api/composer/installed.php +++ b/wcfsetup/install/files/lib/system/api/composer/installed.php @@ -103,12 +103,12 @@ ), 'pelago/emogrifier' => array ( - 'pretty_version' => 'v2.1.1', - 'version' => '2.1.1.0', + 'pretty_version' => 'v4.0.0', + 'version' => '4.0.0.0', 'aliases' => array ( ), - 'reference' => '8ee7fb5ad772915451ed3415c1992bd3697d4983', + 'reference' => 'f6fd679303c6e6861b5ff29af221f684729d8fd9', ), 'psr/http-client' => array ( diff --git a/wcfsetup/install/files/lib/system/api/composer/platform_check.php b/wcfsetup/install/files/lib/system/api/composer/platform_check.php index 1e56f6ecbc..a8b98d5ceb 100644 --- a/wcfsetup/install/files/lib/system/api/composer/platform_check.php +++ b/wcfsetup/install/files/lib/system/api/composer/platform_check.php @@ -5,22 +5,22 @@ $issues = array(); if (!(PHP_VERSION_ID >= 70205)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.'; -} - -$missingExtensions = array(); -extension_loaded('ctype') || $missingExtensions[] = 'ctype'; -extension_loaded('dom') || $missingExtensions[] = 'dom'; -extension_loaded('gd') || $missingExtensions[] = 'gd'; -extension_loaded('json') || $missingExtensions[] = 'json'; -extension_loaded('libxml') || $missingExtensions[] = 'libxml'; -extension_loaded('mbstring') || $missingExtensions[] = 'mbstring'; - -if ($missingExtensions) { - $issues[] = 'Your Composer dependencies require the following PHP extensions to be installed: ' . implode(', ', $missingExtensions); + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.'; } if ($issues) { - echo 'Composer detected issues in your platform:' . "\n\n" . implode("\n", $issues); - exit(104); + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); } diff --git a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.github/CONTRIBUTING.md b/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.github/CONTRIBUTING.md deleted file mode 100644 index 6287d6549c..0000000000 --- a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.github/CONTRIBUTING.md +++ /dev/null @@ -1,129 +0,0 @@ -# Contributing to Emogrifier - -Those that wish to contribute bug fixes, new features, refactorings and -clean-up to Emogrifier are more than welcome. - -When you contribute, please take the following things into account: - - -## Contributor Code of Conduct - -Please note that this project is released with a -[Contributor Code of Conduct](../CODE_OF_CONDUCT.md). By participating in this -project, you agree to abide by its terms. - - -## General workflow - -This is the workflow for contributing changes to Emogrifier: - -1. [Fork the Emogrifier Git repository](https://guides.github.com/activities/forking/). -2. Clone your forked repository and - [install the development dependencies](#install-the-development-dependencies). -3. Add a local remote "upstream" so you will be able to - [synchronize your fork with the original Emogrifier repository](https://help.github.com/articles/syncing-a-fork/). -4. Create a local branch for your changes. -5. [Add unit tests for your changes](#unit-test-your-changes). - These tests should fail without your changes. -6. Add your changes. Your added unit tests now should pass, and no other tests - should be broken. Check that your changes follow the same - [coding style](#coding-style) as the rest of the project. -7. Add a changelog entry. -8. [Commit](#git-commits) and push your changes. -9. [Create a pull request](https://help.github.com/articles/about-pull-requests/) - for your changes. Check that the Travis build is green. (If it is not, fix the - problems listed by Travis.) -10. [Request a review](https://help.github.com/articles/about-pull-request-reviews/) - from @oliverklee. -11. Together with him, polish your changes until they are ready to be merged. - - -## About code reviews - -After you have submitted a pull request, the Emogrifier team will review your -changes. This will probably result in quite a few comments on ways to improve -your pull request. The Emogrifier project receives contributions from -developers around the world, so we need the code to be the most consistent, -readable, and maintainable that it can be. - -Please do not feel frustrated by this - instead please view this both as our -contribution to your pull request as well as a way to learn more about -improving code quality. - -If you would like to know whether an idea would fit in the general strategy of -the Emogrifier project or would like to get feedback on the best architecture -for your ideas, we propose you open a ticket first and discuss your ideas there -first before investing a lot of time in writing code. - - -## Install the development dependencies - -To install the development dependencies (PHPUnit and PHP_CodeSniffer), please -run the following commands: - -```shell -composer install -composer require --dev slevomat/coding-standard:^4.0 -``` - -Note that the development dependencies (in particular, for PHP_CodeSniffer) -require PHP 7.0 or later. The second command installs the PHP_CodeSniffer -dependencies and should be omitted if specifically testing against an earlier -version of PHP, however you will not be able to run the static code analysis. - - -## Unit-test your changes - -Please cover all changes with unit tests and make sure that your code does not -break any existing tests. We will only merge pull requests that include full -code coverage of the fixed bugs and the new features. - -To run the existing PHPUnit tests, run this command: - -```shell -composer ci:tests:unit -``` - - -## Coding Style - -Please use the same coding style (PSR-2) as the rest of the code. Indentation -is four spaces. - -We will only merge pull requests that follow the project's coding style. - -Please check your code with the provided static code analysis tools: - -```shell -composer ci:static -``` - -Please make your code clean, well-readable and easy to understand. - -If you add new methods or fields, please add proper PHPDoc for the new -methods/fields. Please use grammatically correct, complete sentences in the -code documentation. - -You can autoformat your code using the following command: - -```shell -composer php:fix -``` - - -## Git commits - -Commit message should have a <= 50 character summary, optionally followed by a -blank line and a more in depth description of 79 characters per line. - -Please use grammatically correct, complete sentences in the commit messages. - -Also, please prefix the subject line of the commit message with either -[FEATURE], [TASK], [BUGFIX] OR [CLEANUP]. This makes it faster to see what -a commit is about. - - -## Creating pull requests (PRs) - -When you create a pull request, please -[make your PR editable](https://github.com/blog/2247-improving-collaboration-with-forks). diff --git a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.gitignore b/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.gitignore deleted file mode 100644 index 8bfbb851e4..0000000000 --- a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -######################### -# global ignore file -######################## -# ignoring temporary files (left by e.g. vim) -# ignoring by common IDE's used directories/files -# dont ignore .rej and .orig as we want to see/clean files after conflict resolution -# -# for local exclude patterns please edit .git/info/exclude -# -*~ -*.bak -*.idea -*.project -*.swp -.buildpath -.cache -.project -.session -.settings -.TemporaryItems -.webprj -nbproject -/.php_cs.cache -/vendor/ -composer.lock diff --git a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.travis.yml b/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.travis.yml deleted file mode 100644 index f3a6c22ea5..0000000000 --- a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/.travis.yml +++ /dev/null @@ -1,65 +0,0 @@ -sudo: false - -language: php - -php: -- 5.5 -- 5.6 -- 7.0 -- 7.1 -- 7.2 -- 7.3 - -cache: - directories: - - vendor - - $HOME/.composer/cache - -env: - matrix: - - DEPENDENCIES_PREFERENCE="--prefer-lowest" - - DEPENDENCIES_PREFERENCE="" - -before_install: -- phpenv config-rm xdebug.ini || echo "xdebug not available" - -install: -- > - export IGNORE_PLATFORM_REQS="$(composer php:version |grep -q '^7.3' && printf -- --ignore-platform-reqs)"; - echo; - echo "Updating the dependencies"; - composer update $IGNORE_PLATFORM_REQS --with-dependencies $DEPENDENCIES_PREFERENCE; - composer show; - -script: -- > - echo; - echo "Validating the composer.json"; - composer validate --no-check-all --no-check-lock --strict; - -- > - echo; - echo "Linting all PHP files"; - composer ci:php:lint; - -- > - echo; - echo "Running the unit tests"; - composer ci:tests:unit; - -- > - echo; - echo "Running PHPMD"; - composer ci:php:md; - -- > - echo; - function version_gte() { test "$(printf '%s\n' "$@" | sort -n -t. -r | head -n 1)" = "$1"; }; - if version_gte $(composer php:version) 7; then - echo "Installing slevomat/coding-standard only for PHP 7.x"; - composer require $IGNORE_PLATFORM_REQS --dev slevomat/coding-standard:^4.0 $DEPENDENCIES_PREFERENCE; - echo "Running PHP_CodeSniffer"; - composer ci:php:sniff; - else - echo "Skipped PHP_CodeSniffer due to insufficient PHP version: $(composer php:version)"; - fi; diff --git a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/CHANGELOG.md b/wcfsetup/install/files/lib/system/api/pelago/emogrifier/CHANGELOG.md index a3866a4bbd..37e336020b 100644 --- a/wcfsetup/install/files/lib/system/api/pelago/emogrifier/CHANGELOG.md +++ b/wcfsetup/install/files/lib/system/api/pelago/emogrifier/CHANGELOG.md @@ -10,11 +10,278 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Changed ### Deprecated +- Support for PHP 7.1 will be removed in Emogrifier 6.0. ### Removed ### Fixed +## 4.0.0 + +### Added +- Extract and inject `@font-face` rules into head + ([#870](https://github.com/MyIntervals/emogrifier/pull/870)) +- Test tag omission in conformant supplied HTML + ([#868](https://github.com/MyIntervals/emogrifier/pull/868)) +- Check for missing return type hint annotations in the code sniffs + ([#860](https://github.com/MyIntervals/emogrifier/pull/860)) +- Support `:only-of-type` (with a type) + ([#849](https://github.com/MyIntervals/emogrifier/issues/849), + [#856](https://github.com/MyIntervals/emogrifier/pull/856)) +- Configuration setting methods now all return `$this` to allow chaining + ([#824](https://github.com/MyIntervals/emogrifier/pull/824), + [#854](https://github.com/MyIntervals/emogrifier/pull/854)) +- Disable php-cs-fixer Yoda conditions + ([#791](https://github.com/MyIntervals/emogrifier/issues/791), + [#794](https://github.com/MyIntervals/emogrifier/pull/794)) +- Check the code with psalm + ([#537](https://github.com/MyIntervals/emogrifier/issues/537), + [#779](https://github.com/MyIntervals/emogrifier/pull/779)) +- Composer script to run tests with `--stop-on-failure` + ([#782](https://github.com/MyIntervals/emogrifier/pull/782)) +- Test universal selector with combinators + ([#776](https://github.com/MyIntervals/emogrifier/pull/776)) + +### Changed +- Normalize DOCTYPE declaration according to polyglot markup recommendation + ([#866](https://github.com/MyIntervals/emogrifier/pull/866)) +- Upgrade to V2 of the PHP setup GitHub action + ([#861](https://github.com/MyIntervals/emogrifier/pull/861)) +- Move the development tools to Phive + ([#850](https://github.com/MyIntervals/emogrifier/pull/850), + [#851](https://github.com/MyIntervals/emogrifier/pull/851)) +- Switch the parallel linting to a maintained fork + ([#842](https://github.com/MyIntervals/emogrifier/pull/842)) +- Move continuous integration from Travis CI to GitHub actions + ([#832](https://github.com/MyIntervals/emogrifier/pull/832), + [#834](https://github.com/MyIntervals/emogrifier/pull/834), + [#838](https://github.com/MyIntervals/emogrifier/pull/838), + [#839](https://github.com/MyIntervals/emogrifier/pull/839), + [#840](https://github.com/MyIntervals/emogrifier/pull/840), + [#841](https://github.com/MyIntervals/emogrifier/pull/841), + [#843](https://github.com/MyIntervals/emogrifier/pull/843), + [#846](https://github.com/MyIntervals/emogrifier/pull/846), + [#849](https://github.com/MyIntervals/emogrifier/pull/849)) +- Clean up the folder structure and autoloading configuration + ([#529](https://github.com/MyIntervals/emogrifier/issues/529), + [#785](https://github.com/MyIntervals/emogrifier/pull/785)) +- Use `self` as the return type for `fromHtml` + ([#784](https://github.com/MyIntervals/emogrifier/pull/784)) +- Make use of PHP 7.0 language features + ([#777](https://github.com/MyIntervals/emogrifier/pull/777)) + +### Deprecated +- Support for PHP 7.0 will be removed in Emogrifier 5.0. + +### Removed +- Drop support for Symfony versions that have reached their end of life + ([#847](https://github.com/MyIntervals/emogrifier/pull/847)) +- Drop the `Emogrifier` class + ([#774](https://github.com/MyIntervals/emogrifier/pull/774)) +- Drop support for PHP 5.6 + ([#773](https://github.com/MyIntervals/emogrifier/pull/773)) + +### Fixed +- Allow `:last-of-type` etc. without type, without causing exception + ([#875](https://github.com/MyIntervals/emogrifier/pull/875)) +- Make sure to use the Composer-installed development tools + ([#862](https://github.com/MyIntervals/emogrifier/pull/862), + [#865](https://github.com/MyIntervals/emogrifier/pull/865)) +- Add missing `` element when there's a `
` element + ([#844](https://github.com/MyIntervals/emogrifier/pull/844), + [#853](https://github.com/MyIntervals/emogrifier/pull/853)) +- Fix mapping width/height when decimal is used + ([#845](https://github.com/MyIntervals/emogrifier/pull/845)) +- Actually use the specified PHP version on GitHub actions + ([#836](https://github.com/MyIntervals/emogrifier/pull/836)) +- Support `ci:php:lint` on Windows + ([#740](https://github.com/MyIntervals/emogrifier/issues/740), + [#780](https://github.com/MyIntervals/emogrifier/pull/780)) + +## 3.1.0 + +### Added +- Add support for PHP 7.4 + ([#821](https://github.com/MyIntervals/emogrifier/pull/821), + [#829](https://github.com/MyIntervals/emogrifier/pull/829)) + +### Changed +- Upgrade to Symfony 5.0 + ([#820](https://github.com/MyIntervals/emogrifier/pull/820)) + +## 3.0.0 + +### Added +- Test and document excluding entire subtree with `addExcludedSelector()` + ([#347](https://github.com/MyIntervals/emogrifier/issues/347), + [#768](https://github.com/MyIntervals/emogrifier/pull/768)) +- Test that rules with `:optional` or `:required` are copied to the `

target

' - ); - - $result = $subject->emogrify(); - - static::assertContains('

target

', $result); - } - - /** - * @test - */ - public function emogrifyRemovesStyleNodes() - { - $subject = $this->buildDebugSubject(''); - - $result = $subject->emogrify(); - - static::assertNotContains('' - ); - $subject->setDebug(true); - - $subject->emogrify(); - } - - /** - * @test - */ - public function emogrifyNotInDebugModeIgnoresInvalidCssSelectors() - { - $html = ' ' . - '

'; - $subject = new CssInliner($html); - $subject->setDebug(false); - - $html = $subject->emogrify(); - - static::assertContains('color: red', $html); - static::assertContains('background-color: blue', $html); - } - - /** - * @test - */ - public function emogrifyByDefaultIgnoresInvalidCssSelectors() - { - $html = ' ' . - '

'; - $subject = new CssInliner($html); - - $html = $subject->emogrify(); - static::assertContains('color: red', $html); - static::assertContains('background-color: blue', $html); - } - - /** - * Data provider for things that should be left out when applying the CSS. - * - * @return string[][] - */ - public function unneededCssThingsDataProvider() - { - return [ - 'CSS comments with one asterisk' => ['p {color: #000;/* black */}', 'black'], - 'CSS comments with two asterisks' => ['p {color: #000;/** black */}', 'black'], - '@import directive' => ['@import "foo.css";', '@import'], - 'two @import directives, minified' => ['@import "foo.css";@import "bar.css";', '@import'], - '@charset directive' => ['@charset "UTF-8";', '@charset'], - 'style in "aural" media type rule' => ['@media aural {p {color: #000;}}', '#000'], - 'style in "braille" media type rule' => ['@media braille {p {color: #000;}}', '#000'], - 'style in "embossed" media type rule' => ['@media embossed {p {color: #000;}}', '#000'], - 'style in "handheld" media type rule' => ['@media handheld {p {color: #000;}}', '#000'], - 'style in "projection" media type rule' => ['@media projection {p {color: #000;}}', '#000'], - 'style in "speech" media type rule' => ['@media speech {p {color: #000;}}', '#000'], - 'style in "tty" media type rule' => ['@media tty {p {color: #000;}}', '#000'], - 'style in "tv" media type rule' => ['@media tv {p {color: #000;}}', '#000'], - 'style in "tv" media type rule with extra spaces' => [ - ' @media tv { p { color : #000 ; } } ', - '#000', - ], - 'style in "tv" media type rule with linefeeds' => [ - "\n@media\ntv\n{\np\n{\ncolor\n:\n#000\n;\n}\n}\n", - '#000', - ], - 'style in "tv" media type rule with Windows line endings' => [ - "\r\n@media\r\ntv\r\n{\r\np\r\n{\r\ncolor\r\n:\r\n#000\r\n;\r\n}\r\n}\r\n", - '#000', - ], - 'style in "only tv" media type rule' => ['@media only tv {p {color: #000;}}', '#000'], - 'style in "only tv" media type rule with extra spaces' => [ - ' @media only tv { p { color : #000 ; } } ', - '#000', - ], - 'style in "only tv" media type rule with linefeeds' => [ - "\n@media\nonly\ntv\n{\np\n{\ncolor\n:\n#000\n;\n}\n}\n", - '#000', - ], - 'style in "only tv" media type rule with Windows line endings' => [ - "\r\n@media\r\nonly\r\ntv\r\n{\r\np\r\n{\r\ncolor\r\n:\r\n#000\r\n;\r\n}\r\n}\r\n", - '#000', - ], - ]; - } - - /** - * @test - * - * @param string $unneededCss - * @param string $markerNotExpectedInHtml - * - * @dataProvider unneededCssThingsDataProvider - */ - public function emogrifyFiltersUnneededCssThings($unneededCss, $markerNotExpectedInHtml) - { - $subject = $this->buildDebugSubject('

foo

'); - $subject->setCss($unneededCss); - - $result = $subject->emogrify(); - - static::assertNotContains($markerNotExpectedInHtml, $result); - } - - /** - * @test - * - * @param string $unneededCss - * - * @dataProvider unneededCssThingsDataProvider - */ - public function emogrifyMatchesRuleAfterUnneededCssThing($unneededCss) - { - $subject = $this->buildDebugSubject(''); - $subject->setCss($unneededCss . ' body { color: green; }'); - - $result = $subject->emogrify(); - - static::assertContains('', $result); - } - - /** - * Data provider for media rules. - * - * @return string[][] - */ - public function mediaRulesDataProvider() - { - return [ - 'style in "only all" media type rule' => ['@media only all {p {color: #000;}}'], - 'style in "only screen" media type rule' => ['@media only screen {p {color: #000;}}'], - 'style in "only screen" media type rule with extra spaces' - => [' @media only screen { p { color : #000; } } '], - 'style in "only screen" media type rule with linefeeds' - => ["\n@media\nonly\nscreen\n{\np\n{\ncolor\n:\n#000;\n}\n}\n"], - 'style in "only screen" media type rule with Windows line endings' - => ["\r\n@media\r\nonly\r\nscreen\r\n{\r\np\r\n{\r\ncolor\r\n:\r\n#000;\r\n}\r\n}\r\n"], - 'style in media type rule' => ['@media {p {color: #000;}}'], - 'style in media type rule with extra spaces' => [' @media { p { color : #000; } } '], - 'style in media type rule with linefeeds' => ["\n@media\n{\np\n{\ncolor\n:\n#000;\n}\n}\n"], - 'style in media type rule with Windows line endings' - => ["\r\n@media\r\n{\r\np\r\n{\r\ncolor\r\n:\r\n#000;\r\n}\r\n}\r\n"], - 'style in "screen" media type rule' => ['@media screen {p {color: #000;}}'], - 'style in "screen" media type rule with extra spaces' - => [' @media screen { p { color : #000; } } '], - 'style in "screen" media type rule with linefeeds' - => ["\n@media\nscreen\n{\np\n{\ncolor\n:\n#000;\n}\n}\n"], - 'style in "screen" media type rule with Windows line endings' - => ["\r\n@media\r\nscreen\r\n{\r\np\r\n{\r\ncolor\r\n:\r\n#000;\r\n}\r\n}\r\n"], - 'style in "print" media type rule' => ['@media print {p {color: #000;}}'], - 'style in "all" media type rule' => ['@media all {p {color: #000;}}'], - ]; - } - - /** - * @test - * - * @param string $css - * - * @dataProvider mediaRulesDataProvider - */ - public function emogrifyKeepsMediaRules($css) - { - $subject = $this->buildDebugSubject('

foo

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - static::assertContainsCss($css, $result); - } - - /** - * @return string[][] - */ - public function orderedRulesAndSurroundingCssDataProvider() - { - $possibleSurroundingCss = [ - 'nothing' => '', - 'space' => ' ', - 'linefeed' => "\n", - 'Windows line ending' => "\r\n", - 'comment' => '/* hello */', - 'other non-matching CSS' => 'h6 { color: #f00; }', - 'other matching CSS' => 'p { color: #f00; }', - 'disallowed media rule' => '@media tv { p { color: #f00; } }', - 'allowed but non-matching media rule' => '@media screen { h6 { color: #f00; } }', - 'non-matching CSS with pseudo-component' => 'h6:hover { color: #f00; }', - ]; - $possibleCssBefore = $possibleSurroundingCss + [ - '@import' => '@import "foo.css";', - '@charset' => '@charset "UTF-8";', - ]; - - $datasetsSurroundingCss = []; - foreach ($possibleCssBefore as $descriptionBefore => $cssBefore) { - foreach ($possibleSurroundingCss as $descriptionBetween => $cssBetween) { - foreach ($possibleSurroundingCss as $descriptionAfter => $cssAfter) { - // every combination would be a ridiculous c.1000 datasets - choose a select few - // test all possible CSS before once - if (($cssBetween === '' && $cssAfter === '') - // test all possible CSS between once - || ($cssBefore === '' && $cssAfter === '') - // test all possible CSS after once - || ($cssBefore === '' && $cssBetween === '') - // test with each possible CSS in all three positions - || ($cssBefore === $cssBetween && $cssBetween === $cssAfter) - ) { - $description = ' with ' . $descriptionBefore . ' before, ' - . $descriptionBetween . ' between, ' - . $descriptionAfter . ' after'; - $datasetsSurroundingCss[$description] = [$cssBefore, $cssBetween, $cssAfter]; - } - } - } - } - - $datasets = []; - foreach ($datasetsSurroundingCss as $description => $datasetSurroundingCss) { - $datasets += [ - 'two media rules' . $description => \array_merge( - ['@media all { p { color: #333; } }', '@media print { p { color: #000; } }'], - $datasetSurroundingCss - ), - 'two rules involving pseudo-components' . $description => \array_merge( - ['a:hover { color: blue; }', 'a:active { color: green; }'], - $datasetSurroundingCss - ), - 'media rule followed by rule involving pseudo-components' . $description => \array_merge( - ['@media screen { p { color: #000; } }', 'a:hover { color: green; }'], - $datasetSurroundingCss - ), - 'rule involving pseudo-components followed by media rule' . $description => \array_merge( - ['a:hover { color: green; }', '@media screen { p { color: #000; } }'], - $datasetSurroundingCss - ), - ]; - } - return $datasets; - } - - /** - * @test - * - * @param string $rule1 - * @param string $rule2 - * @param string $cssBefore CSS to insert before the first rule - * @param string $cssBetween CSS to insert between the rules - * @param string $cssAfter CSS to insert after the second rule - * - * @dataProvider orderedRulesAndSurroundingCssDataProvider - */ - public function emogrifyKeepsRulesCopiedToStyleElementInSpecifiedOrder( - $rule1, - $rule2, - $cssBefore, - $cssBetween, - $cssAfter - ) { - $subject = $this->buildDebugSubject('

foo

'); - $subject->setCss($cssBefore . $rule1 . $cssBetween . $rule2 . $cssAfter); - - $result = $subject->emogrify(); - - static::assertContainsCss($rule1 . $rule2, $result); - } - - /** - * @test - */ - public function removeAllowedMediaTypeRemovesStylesForTheGivenMediaType() - { - $css = '@media screen { html { some-property: value; } }'; - $subject = $this->buildDebugSubject(''); - $subject->setCss($css); - $subject->removeAllowedMediaType('screen'); - - $result = $subject->emogrify(); - - static::assertNotContains('@media', $result); - } - - /** - * @test - */ - public function addAllowedMediaTypeKeepsStylesForTheGivenMediaType() - { - $css = '@media braille { html { some-property: value; } }'; - $subject = $this->buildDebugSubject(''); - $subject->setCss($css); - $subject->addAllowedMediaType('braille'); - - $result = $subject->emogrify(); - - static::assertContainsCss($css, $result); - } - - /** - * @test - */ - public function emogrifyKeepsExistingHeadElementContent() - { - $subject = $this->buildDebugSubject(''); - $subject->setCss('@media all { html { some-property: value; } }'); - - $result = $subject->emogrify(); - - static::assertContains('', $result); - } - - /** - * @test - */ - public function emogrifyKeepsExistingStyleElementWithMedia() - { - $html = $this->html5DocumentType . ''; - $subject = $this->buildDebugSubject($html); - $subject->setCss('@media all { html { some-property: value; } }'); - - $result = $subject->emogrify(); - - static::assertContains(''; - $html = '' . $style . ''; - $subject = $this->buildDebugSubject($html); - - $result = $subject->emogrify(); - - static::assertRegExp('/.*/s', $result); - } - - /** - * @test - */ - public function emogrifyKeepsExistingStyleElementWithMediaOutOfBody() - { - $style = ''; - $html = '' . $style . ''; - $subject = $this->buildDebugSubject($html); - - $result = $subject->emogrify(); - - static::assertNotRegExp('/.*', $result); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider validMediaPreserveDataProvider - */ - public function emogrifyWithValidMinifiedMediaQueryContainsInnerCss($css) - { - // Minify CSS by removing unnecessary whitespace. - $css = \preg_replace('/\\s*{\\s*/', '{', $css); - $css = \preg_replace('/;?\\s*}\\s*/', '}', $css); - $css = \preg_replace('/@media{/', '@media {', $css); - - $subject = $this->buildDebugSubject('

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - static::assertContains('', $result); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider validMediaPreserveDataProvider - */ - public function emogrifyForHtmlWithValidMediaQueryContainsInnerCss($css) - { - $subject = $this->buildDebugSubject('

'); - - $result = $subject->emogrify(); - - static::assertContainsCss('', $result); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider validMediaPreserveDataProvider - */ - public function emogrifyWithValidMediaQueryNotContainsInlineCss($css) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - static::assertNotContains('style=', $result); - } - - /** - * Invalid media query which need to be strip - * - * @return string[][] - */ - public function invalidMediaPreserveDataProvider() - { - return [ - 'style in "braille" type rule' => ['@media braille { h1 { color:red; } }'], - 'style in "embossed" type rule' => ['@media embossed { h1 { color:red; } }'], - 'style in "handheld" type rule' => ['@media handheld { h1 { color:red; } }'], - 'style in "projection" type rule' => ['@media projection { h1 { color:red; } }'], - 'style in "speech" type rule' => ['@media speech { h1 { color:red; } }'], - 'style in "tty" type rule' => ['@media tty { h1 { color:red; } }'], - 'style in "tv" type rule' => ['@media tv { h1 { color:red; } }'], - ]; - } - - /** - * @test - * - * @param string $css - * - * @dataProvider invalidMediaPreserveDataProvider - */ - public function emogrifyWithInvalidMediaQueryNotContainsInnerCss($css) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - static::assertNotContainsCss($css, $result); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider invalidMediaPreserveDataProvider - */ - public function emogrifyWithInvalidMediaQueryNotContainsInlineCss($css) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - static::assertNotContains('style=', $result); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider invalidMediaPreserveDataProvider - */ - public function emogrifyFromHtmlWithInvalidMediaQueryNotContainsInnerCss($css) - { - $subject = $this->buildDebugSubject('

'); - - $result = $subject->emogrify(); - - static::assertNotContainsCss($css, $result); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider invalidMediaPreserveDataProvider - */ - public function emogrifyFromHtmlWithInvalidMediaQueryNotContainsInlineCss($css) - { - $subject = $this->buildDebugSubject('

'); - - $result = $subject->emogrify(); - - static::assertNotContains('style=', $result); - } - - /** - * @test - */ - public function emogrifyIgnoresEmptyMediaQuery() - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss('@media screen {} @media tv { h1 { color: red; } }'); - - $result = $subject->emogrify(); - - static::assertNotContains('style=', $result); - static::assertNotContains('@media screen', $result); - } - - /** - * @test - */ - public function emogrifyIgnoresMediaQueryWithWhitespaceOnly() - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss('@media screen { } @media tv { h1 { color: red; } }'); - - $result = $subject->emogrify(); - - static::assertNotContains('style=', $result); - static::assertNotContains('@media screen', $result); - } - - /** - * @return string[][] - */ - public function mediaTypeDataProvider() - { - return [ - 'disallowed type' => ['tv'], - 'allowed type' => ['screen'], - ]; - } - - /** - * @test - * - * @param string $emptyRuleMediaType - * - * @dataProvider mediaTypeDataProvider - */ - public function emogrifyKeepsMediaRuleAfterEmptyMediaRule($emptyRuleMediaType) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss('@media ' . $emptyRuleMediaType . ' {} @media all { h1 { color: red; } }'); - - $result = $subject->emogrify(); - - static::assertContainsCss('@media all { h1 { color: red; } }', $result); - } - - /** - * @test - * - * @param string $emptyRuleMediaType - * - * @dataProvider mediaTypeDataProvider - */ - public function emogrifyNotKeepsUnneededMediaRuleAfterEmptyMediaRule($emptyRuleMediaType) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss('@media ' . $emptyRuleMediaType . ' {} @media speech { h1 { color: red; } }'); - - $result = $subject->emogrify(); - - static::assertNotContains('@media', $result); - } - - /** - * @param string[] $precedingSelectorComponents Array of selectors to which each type of pseudo-component is - * appended to create a selector for a CSS rule. - * Keys are human-readable descriptions. - * - * @return string[][] - */ - private function getCssRuleDatasetsWithSelectorPseudoComponents(array $precedingSelectorComponents) - { - $rulesComponents = [ - 'pseudo-element' => [ - 'selectorPseudoComponent' => '::after', - 'declarationsBlock' => 'content: "bar";', - ], - 'CSS2 pseudo-element' => [ - 'selectorPseudoComponent' => ':after', - 'declarationsBlock' => 'content: "bar";', - ], - 'hyphenated pseudo-element' => [ - 'selectorPseudoComponent' => '::first-letter', - 'declarationsBlock' => 'color: green;', - ], - 'pseudo-class' => [ - 'selectorPseudoComponent' => ':hover', - 'declarationsBlock' => 'color: green;', - ], - 'hyphenated pseudo-class' => [ - 'selectorPseudoComponent' => ':read-only', - 'declarationsBlock' => 'color: green;', - ], - 'pseudo-class with parameter' => [ - 'selectorPseudoComponent' => ':lang(en)', - 'declarationsBlock' => 'color: green;', - ], - ]; - - $datasets = []; - foreach ($precedingSelectorComponents as $precedingComponentDescription => $precedingSelectorComponent) { - foreach ($rulesComponents as $pseudoComponentDescription => $ruleComponents) { - $datasets[$precedingComponentDescription . ' ' . $pseudoComponentDescription] = [ - $precedingSelectorComponent . $ruleComponents['selectorPseudoComponent'] - . ' { ' . $ruleComponents['declarationsBlock'] . ' }', - ]; - } - } - return $datasets; - } - - /** - * @return string[][] - */ - public function matchingSelectorWithPseudoComponentCssRuleDataProvider() - { - $datasetsWithSelectorPseudoComponents = $this->getCssRuleDatasetsWithSelectorPseudoComponents( - [ - 'lone' => '', - 'type &' => 'a', - 'class &' => '.a', - 'ID &' => '#a', - 'attribute &' => 'a[href="a"]', - 'static pseudo-class &' => 'a:first-child', - 'ancestor &' => 'p ', - 'ancestor & type &' => 'p a', - ] - ); - $datasetsWithCombinedPseudoSelectors = [ - 'pseudo-class & descendant' => ['p:hover a { color: green; }'], - 'pseudo-class & pseudo-element' => ['a:hover::after { content: "bar"; }'], - 'pseudo-element & pseudo-class' => ['a::after:hover { content: "bar"; }'], - 'two pseudo-classes' => ['a:focus:hover { color: green; }'], - ]; - - return \array_merge($datasetsWithSelectorPseudoComponents, $datasetsWithCombinedPseudoSelectors); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider matchingSelectorWithPseudoComponentCssRuleDataProvider - */ - public function emogrifyKeepsRuleWithPseudoComponentInMatchingSelector($css) - { - $subject = $this->buildDebugSubject('

foo

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - self::assertContainsCss($css, $result); - } - - /** - * @return string[][] - */ - public function nonMatchingSelectorWithPseudoComponentCssRuleDataProvider() - { - $datasetsWithSelectorPseudoComponents = $this->getCssRuleDatasetsWithSelectorPseudoComponents( - [ - 'type &' => 'b', - 'class &' => '.b', - 'ID &' => '#b', - 'attribute &' => 'a[href="b"]', - 'static pseudo-class &' => 'a:not(.a)', - 'ancestor &' => 'ul ', - 'ancestor & type &' => 'p b', - ] - ); - $datasetsWithCombinedPseudoSelectors = [ - 'pseudo-class & descendant' => ['ul:hover a { color: green; }'], - 'pseudo-class & pseudo-element' => ['b:hover::after { content: "bar"; }'], - 'pseudo-element & pseudo-class' => ['b::after:hover { content: "bar"; }'], - 'two pseudo-classes' => ['input:focus:hover { color: green; }'], - ]; - - return \array_merge($datasetsWithSelectorPseudoComponents, $datasetsWithCombinedPseudoSelectors); - } - - /** - * @test - * - * @param string $css - * - * @dataProvider nonMatchingSelectorWithPseudoComponentCssRuleDataProvider - */ - public function emogrifyNotKeepsRuleWithPseudoComponentInNonMatchingSelector($css) - { - $subject = $this->buildDebugSubject('

foo

'); - $subject->setCss($css); - - $result = $subject->emogrify(); - - self::assertNotContainsCss($css, $result); - } - - /** - * @test - */ - public function emogrifyKeepsRuleInMediaQueryWithPseudoComponentInMatchingSelector() - { - $subject = $this->buildDebugSubject('foo'); - $css = '@media screen { a:hover { color: green; } }'; - $subject->setCss($css); - - $result = $subject->emogrify(); - - self::assertContainsCss($css, $result); - } - - /** - * @test - */ - public function emogrifyNotKeepsRuleInMediaQueryWithPseudoComponentInNonMatchingSelector() - { - $subject = $this->buildDebugSubject('foo'); - $css = '@media screen { b:hover { color: green; } }'; - $subject->setCss($css); - - $result = $subject->emogrify(); - - self::assertNotContainsCss($css, $result); - } - - /** - * @test - */ - public function emogrifyKeepsRuleWithPseudoComponentInMultipleMatchingSelectorsFromSingleRule() - { - $subject = $this->buildDebugSubject('

foo

bar'); - $css = 'p:hover, a:hover { color: green; }'; - $subject->setCss($css); - - $result = $subject->emogrify(); - - static::assertContainsCss($css, $result); - } - - /** - * @test - */ - public function emogrifyKeepsOnlyMatchingSelectorsWithPseudoComponentFromSingleRule() - { - $subject = $this->buildDebugSubject('foo'); - $subject->setCss('p:hover, a:hover { color: green; }'); - - $result = $subject->emogrify(); - - static::assertContainsCss('', $result); - } - - /** - * @test - */ - public function emogrifyAppliesCssToMatchingElementsAndKeepsRuleWithPseudoComponentFromSingleRule() - { - $subject = $this->buildDebugSubject('

foo

bar'); - $subject->setCss('p, a:hover { color: green; }'); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - static::assertContainsCss('', $result); - } - - /** - * @return string[][] - */ - public function mediaTypesDataProvider() - { - return [ - 'disallowed type after disallowed type' => ['tv', 'speech'], - 'allowed type after disallowed type' => ['tv', 'all'], - 'disallowed type after allowed type' => ['screen', 'tv'], - 'allowed type after allowed type' => ['screen', 'all'], - ]; - } - - /** - * @test - * - * @param string $emptyRuleMediaType - * @param string $mediaType - * - * @dataProvider mediaTypesDataProvider - */ - public function emogrifyAppliesCssBetweenEmptyMediaRuleAndMediaRule($emptyRuleMediaType, $mediaType) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss( - '@media ' . $emptyRuleMediaType . ' {} h1 { color: green; } @media ' . $mediaType - . ' { h1 { color: red; } }' - ); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - } - - /** - * @test - * - * @param string $emptyRuleMediaType - * @param string $mediaType - * - * @dataProvider mediaTypesDataProvider - */ - public function emogrifyAppliesCssBetweenEmptyMediaRuleAndMediaRuleWithCssAfter($emptyRuleMediaType, $mediaType) - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss( - '@media ' . $emptyRuleMediaType . ' {} h1 { color: green; } @media ' . $mediaType - . ' { h1 { color: red; } } h1 { font-size: 24px; }' - ); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - } - - /** - * @test - */ - public function emogrifyAppliesCssFromStyleNodes() - { - $styleAttributeValue = 'color: #ccc;'; - $subject = $this->buildDebugSubject( - '' - ); - - $result = $subject->emogrify(); - - static::assertContains('', $result); - } - - /** - * @test - */ - public function emogrifyWhenDisabledNotAppliesCssFromStyleBlocks() - { - $styleAttributeValue = 'color: #ccc;'; - $subject = $this->buildDebugSubject( - '' - ); - $subject->disableStyleBlocksParsing(); - - $result = $subject->emogrify(); - - static::assertNotContains('style=', $result); - } - - /** - * @test - */ - public function emogrifyWhenStyleBlocksParsingDisabledKeepInlineStyles() - { - $styleAttributeValue = 'text-align: center;'; - $subject = $this->buildDebugSubject( - '' . - '

paragraph

' - ); - $subject->disableStyleBlocksParsing(); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - } - - /** - * @test - */ - public function emogrifyWhenDisabledNotAppliesCssFromInlineStyles() - { - $subject = $this->buildDebugSubject(''); - $subject->disableInlineStyleAttributesParsing(); - - $result = $subject->emogrify(); - - static::assertNotContains('buildDebugSubject( - '' . - '

paragraph

' - ); - $subject->disableInlineStyleAttributesParsing(); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - } - - /** - * Emogrify was handling case differently for passed-in CSS vs. CSS parsed from style blocks. - * - * @test - */ - public function emogrifyAppliesCssWithMixedCaseAttributesInStyleBlock() - { - $subject = $this->buildDebugSubject( - '' . - '

some content

' - ); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - } - - /** - * Style block CSS overrides values. - * - * @test - */ - public function emogrifyMergesCssWithMixedCaseAttribute() - { - $subject = $this->buildDebugSubject( - '' . - '

some content

' - ); - $subject->setCss('p { margin: 0; padding-TOP: 0; PADDING-bottom: 1PX;}'); - - $result = $subject->emogrify(); - - static::assertContains( - '

', - $result - ); - } - - /** - * @test - */ - public function emogrifyMergesCssWithMixedUnits() - { - $subject = $this->buildDebugSubject( - '' . - '

some content

' - ); - $subject->setCss('p { margin: 1px; padding-bottom:0;}'); - - $result = $subject->emogrify(); - - static::assertContains('

', $result); - } - - /** - * @test - */ - public function emogrifyByDefaultRemovesElementsWithDisplayNoneFromExternalCss() - { - $subject = $this->buildDebugSubject('

'); - $subject->setCss('div.foo { display: none; }'); - - $result = $subject->emogrify(); - - static::assertNotContains('
', $result); - } - - /** - * @test - */ - public function emogrifyByDefaultRemovesElementsWithDisplayNoneInStyleAttribute() - { - $subject = $this->buildDebugSubject( - '' . - '' - ); - - $result = $subject->emogrify(); - - static::assertNotContains('buildDebugSubject('
'); - $subject->setCss('div.foo { display: none; }'); - - $subject->disableInvisibleNodeRemoval(); - $result = $subject->emogrify(); - - static::assertContains('