diff options
Diffstat (limited to 'vendor/league')
39 files changed, 961 insertions, 643 deletions
diff --git a/vendor/league/html-to-markdown/.github/FUNDING.yml b/vendor/league/html-to-markdown/.github/FUNDING.yml index 11ea19c6c..5f2ca1499 100644 --- a/vendor/league/html-to-markdown/.github/FUNDING.yml +++ b/vendor/league/html-to-markdown/.github/FUNDING.yml @@ -1,3 +1,3 @@ github: colinodell -patreon: colinodell +tidelift: "packagist/league/html-to-markdown" custom: ["https://www.colinodell.com/sponsor", "https://www.paypal.me/colinpodell/10.00"] diff --git a/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/1_Conversion_error.yaml b/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/1_Conversion_error.yaml new file mode 100644 index 000000000..7f267b208 --- /dev/null +++ b/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/1_Conversion_error.yaml @@ -0,0 +1,25 @@ +name: "📃 Bug Report (Incorrect Markdown)" +description: I'm not getting the Markdown I expect +body: + - type: input + id: affected-versions + attributes: + label: Version(s) affected + placeholder: x.y.z + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the problem. + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce + description: | + Provide the HTML input and any other information that would help us reproduce the problem. + validations: + required: true diff --git a/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/2_Bug_report.yaml b/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/2_Bug_report.yaml new file mode 100644 index 000000000..2045fb79a --- /dev/null +++ b/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/2_Bug_report.yaml @@ -0,0 +1,43 @@ +name: "🐛 Bug Report (Other)" +description: Report all other errors and problems +body: + - type: input + id: affected-versions + attributes: + label: Version(s) affected + placeholder: x.y.z + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the problem. + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce + description: | + HTML and/or any other information needed to reproduce the problem. + validations: + required: true + - type: textarea + id: possible-solution + attributes: + label: Possible solution + description: | + Optional: only if you have suggestions on a fix/reason for the bug + - type: textarea + id: additional-context + attributes: + label: Additional context + description: | + Optional: any other context about the problem: log messages, screenshots, etc. + - type: textarea + id: feedback + attributes: + label: Did this project help you today? Did it make you happy in any way? + description: | + Optional: Sometimes we get tired of reading bug reports and working on complex features, so if you have anything positive to share about how this library might have helped you we'd love to hear it! diff --git a/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/3_Feature_request.yaml b/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/3_Feature_request.yaml new file mode 100644 index 000000000..2d91a58d0 --- /dev/null +++ b/vendor/league/html-to-markdown/.github/ISSUE_TEMPLATE/3_Feature_request.yaml @@ -0,0 +1,27 @@ +name: "🚀 Feature Request" +description: RFC and ideas for new features and improvements +labels: + - enhancement +body: + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the problem. + validations: + required: true + - type: textarea + id: example + attributes: + label: Example + description: | + A simple example of the new feature in action (include PHP code, sample HTML/Markdown, etc.) + If the new feature changes an existing feature, include a simple before/after comparison. + validations: + required: true + - type: textarea + id: feedback + attributes: + label: Did this project help you today? Did it make you happy in any way? + description: | + Optional: Sometimes we get tired of reading bug reports and working on complex features, so if you have anything positive to share about how this library might have helped you we'd love to hear it! diff --git a/vendor/league/html-to-markdown/.github/SECURITY.md b/vendor/league/html-to-markdown/.github/SECURITY.md new file mode 100644 index 000000000..5741abb4a --- /dev/null +++ b/vendor/league/html-to-markdown/.github/SECURITY.md @@ -0,0 +1,13 @@ +# SECURITY POLICY + +## Supported Versions + +When a new **minor** version (`5.x`) is released, the previous one will continue to receive security and bug fixes for *at least* 3 months. + +When a new **major** version is released (`4.0`, `5.0`, etc), the previous one will receive bug fixes for *at least* 3 months and security updates for 6 months after that new release comes out. + +(This policy may change in the future and exceptions may be made on a case-by-case basis.) + +## Reporting a Vulnerability + +If you discover a security vulnerability within this package, please use the [Tidelift security contact form](https://tidelift.com/security) or email Colin O'Dell at <colinodell@gmail.com>. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. diff --git a/vendor/league/html-to-markdown/.github/workflows/tests.yml b/vendor/league/html-to-markdown/.github/workflows/tests.yml new file mode 100644 index 000000000..6abb2de3f --- /dev/null +++ b/vendor/league/html-to-markdown/.github/workflows/tests.yml @@ -0,0 +1,104 @@ +name: Tests + +on: + push: ~ + pull_request: ~ + +jobs: + phpcs: + name: PHPCS + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: shivammathur/setup-php@v2 + with: + php-version: 7.2 + extensions: curl, mbstring + coverage: none + tools: composer:v2, cs2pr + + - run: composer update --no-progress + + - run: vendor/bin/phpcs -q --report=checkstyle | cs2pr + + phpunit: + name: PHPUnit on ${{ matrix.php }} ${{ matrix.composer-flags }} + runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.2', '7.3', '7.4'] + coverage: [true] + composer-flags: [''] + include: + - php: '8.0' + coverage: false + composer-flags: '--ignore-platform-req=php' + - php: '7.2' + coverage: false + composer-flags: '--prefer-lowest' + + steps: + - uses: actions/checkout@v2 + + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: curl, mbstring + coverage: pcov + tools: composer:v2 + + - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: "Use PHPUnit 9.3+ on PHP 8" + run: composer require --no-update --dev phpunit/phpunit:^9.3 + if: "matrix.php == '8.0'" + + - run: composer update --no-progress ${{ matrix.composer-flags }} + + - run: vendor/bin/phpunit --no-coverage + if: ${{ !matrix.coverage }} + + - run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover + if: ${{ matrix.coverage }} + + - run: php vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover + if: ${{ matrix.coverage }} + continue-on-error: true + + phpstan: + name: PHPStan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: shivammathur/setup-php@v2 + with: + php-version: 7.2 + extensions: curl, mbstring + coverage: none + tools: composer:v2 + + - run: composer update --no-progress + + - run: vendor/bin/phpstan analyse --no-progress + + psalm: + name: Psalm + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: shivammathur/setup-php@v2 + with: + php-version: 7.2 + extensions: curl, mbstring + coverage: none + tools: composer:v2 + + - run: composer update --no-progress + + - run: vendor/bin/psalm --no-progress --output-format=github diff --git a/vendor/league/html-to-markdown/CHANGELOG.md b/vendor/league/html-to-markdown/CHANGELOG.md index c19cd9f69..60e8e6f24 100644 --- a/vendor/league/html-to-markdown/CHANGELOG.md +++ b/vendor/league/html-to-markdown/CHANGELOG.md @@ -4,6 +4,53 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip ## [Unreleased][unreleased] +## [5.1.0] - 2022-03-02 + +### Changed + + - Changed horizontal rule style (#218, #219) + +### Fixed + + - Fixed `Element::getValue()` not handling possible nulls + +## [5.0.2] - 2021-11-06 + +### Fixed + + - Fixed missplaced comment nodes appearing at the start of the HTML input (#212) + +## [5.0.1] - 2021-09-17 + +### Fixed + + - Fixed lists not using the correct amount of indentation (#211) + +## [5.0.0] - 2021-03-28 + +### Added + + - Added support for tables (#203) + - This feature is disable by default - see README for how to enable it + - Added new `strip_placeholder_links` option to strip `<a>` tags without `href` attributes (#196) + - Added new methods to `ElementInterface`: + - `hasParent()` + - `getNextSibling()` + - `getPreviousSibling()` + - `getListItemLevel()` + - Added several parameter and return types across all classes + - Added new `PreConverterInterface` to allow converters to perform any necessary pre-parsing + +### Changed + + - Supported PHP versions increased to PHP 7.2 - 8.0 + - `HtmlConverter::convert()` may now throw a `\RuntimeException` when unexpected `DOMDocument`-related errors occur + +### Fixed + + - Fixed complex nested lists containing heading and paragraphs (#198) + - Fixed consecutive emphasis producing incorrect markdown (#202) + ## [4.10.0] - 2020-06-30 ### Added @@ -268,7 +315,11 @@ not ideally set, so this releases fixes that. Moving forwards this should reduce ### Added - Initial release -[unreleased]: https://github.com/thephpleague/html-to-markdown/compare/4.10.0...master +[unreleased]: https://github.com/thephpleague/html-to-markdown/compare/5.1.0...master +[5.1.0]: https://github.com/thephpleague/html-to-markdown/compare/5.0.2...5.1.0 +[5.0.2]: https://github.com/thephpleague/html-to-markdown/compare/5.0.1...5.0.2 +[5.0.1]: https://github.com/thephpleague/html-to-markdown/compare/5.0.0...5.0.1 +[5.0.0]: https://github.com/thephpleague/html-to-markdown/compare/4.10.0...5.0.0 [4.10.0]: https://github.com/thephpleague/html-to-markdown/compare/4.9.1...4.10.0 [4.9.1]: https://github.com/thephpleague/html-to-markdown/compare/4.9.0...4.9.1 [4.9.0]: https://github.com/thephpleague/html-to-markdown/compare/4.8.3...4.9.0 diff --git a/vendor/league/html-to-markdown/LICENSE b/vendor/league/html-to-markdown/LICENSE index 6c04a59dd..a192f156f 100644 --- a/vendor/league/html-to-markdown/LICENSE +++ b/vendor/league/html-to-markdown/LICENSE @@ -1,8 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Colin O'Dell - -Originally created by Nick Cernis +Copyright (c) 2015 Colin O'Dell; Originally created by Nick Cernis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/vendor/league/html-to-markdown/README.md b/vendor/league/html-to-markdown/README.md index c1ac805ab..fcc256328 100644 --- a/vendor/league/html-to-markdown/README.md +++ b/vendor/league/html-to-markdown/README.md @@ -1,11 +1,9 @@ HTML To Markdown for PHP ======================== -[![Join the chat at https://gitter.im/thephpleague/html-to-markdown](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/thephpleague/html-to-markdown?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - [![Latest Version](https://img.shields.io/packagist/v/league/html-to-markdown.svg?style=flat-square)](https://packagist.org/packages/league/html-to-markdown) [![Software License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) -[![Build Status](https://img.shields.io/travis/thephpleague/html-to-markdown/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/html-to-markdown) +[![Build Status](https://img.shields.io/github/workflow/status/thephpleague/html-to-markdown/Tests/master.svg?style=flat-square)](https://github.com/thephpleague/html-to-markdown/actions?query=workflow%3ATests+branch%3Amaster) [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/html-to-markdown.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/html-to-markdown/code-structure) [![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/html-to-markdown.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/html-to-markdown) [![Total Downloads](https://img.shields.io/packagist/dt/league/html-to-markdown.svg?style=flat-square)](https://packagist.org/packages/league/html-to-markdown) @@ -13,7 +11,7 @@ HTML To Markdown for PHP Library which converts HTML to [Markdown](http://daringfireball.net/projects/markdown/) for your sanity and convenience. -**Requires**: PHP 5.3+ or PHP 7.0+ +**Requires**: PHP 7.2+ **Lead Developer**: [@colinodell](http://twitter.com/colinodell) @@ -113,6 +111,15 @@ $html = '<span>Turnips!</span><!-- Monkeys! --><!-- Eggs! -->'; $markdown = $converter->convert($html); // $markdown now contains "Turnips!<!-- Eggs! -->" ``` +By default, placeholder links are preserved. To strip the placeholder links, use the `strip_placeholder_links` option, like this: + +```php +$converter = new HtmlConverter(array('strip_placeholder_links' => true)); + +$html = '<a>Github</a>'; +$markdown = $converter->convert($html); // $markdown now contains "Github" +``` + ### Style options By default bold tags are converted using the asterisk syntax, and italic tags are converted using the underlined syntax. Change these by using the `bold_style` and `italic_style` options. @@ -174,17 +181,24 @@ $html = '<h3>Header</h3> $markdown = $converter->convert($html); // $markdown now contains "### Header" and "<img src="" />" ``` -### Limitations +### Table support -- Markdown Extra, MultiMarkdown and other variants aren't supported – just Markdown. +Support for Markdown tables is not enabled by default because it is not part of the original Markdown syntax. To use tables add the converter explicitly: -### Known issues +```php +use League\HTMLToMarkdown\HtmlConverter; +use League\HTMLToMarkdown\Converter\TableConverter; + +$converter = new HtmlConverter(); +$converter->getEnvironment()->addConverter(new TableConverter()); + +$html = "<table><tr><th>A</th></tr><tr><td>a</td></tr></table>"; +$markdown = $converter->convert($html); +``` -- Nested lists and lists containing multiple paragraphs aren't converted correctly. -- Lists inside blockquotes aren't converted correctly. -- Any reported [open issues here](https://github.com/thephpleague/html-to-markdown/issues?state=open). +### Limitations -[Report your issue or request a feature here.](https://github.com/thephpleague/html-to-markdown/issues/new) Issues with patches or failing tests are especially welcome. +- Markdown Extra, MultiMarkdown and other variants aren't supported – just Markdown. ### Style notes diff --git a/vendor/league/html-to-markdown/composer.json b/vendor/league/html-to-markdown/composer.json index 7990bcace..22ca054f3 100644 --- a/vendor/league/html-to-markdown/composer.json +++ b/vendor/league/html-to-markdown/composer.json @@ -30,19 +30,27 @@ } }, "require": { - "php": ">=5.3.3", + "php": "^7.2.5 || ^8.0", "ext-dom": "*", "ext-xml": "*" }, "require-dev": { - "mikehaertl/php-shellcommand": "~1.1.0", - "phpunit/phpunit": "^4.8|^5.7", - "scrutinizer/ocular": "~1.1" + "mikehaertl/php-shellcommand": "^1.1.0", + "phpstan/phpstan": "^0.12.99", + "phpunit/phpunit": "^8.5 || ^9.2", + "scrutinizer/ocular": "^1.6", + "unleashedtech/php-coding-standard": "^2.7", + "vimeo/psalm": "^4.22" }, "bin": ["bin/html-to-markdown"], "extra": { "branch-alias": { - "dev-master": "4.10-dev" + "dev-master": "5.2-dev" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true } } } diff --git a/vendor/league/html-to-markdown/phpcs.xml.dist b/vendor/league/html-to-markdown/phpcs.xml.dist new file mode 100644 index 000000000..59f148473 --- /dev/null +++ b/vendor/league/html-to-markdown/phpcs.xml.dist @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<ruleset> + <arg name="basepath" value="."/> + <arg name="extensions" value="php"/> + <arg name="parallel" value="80"/> + <arg name="cache" value=".phpcs-cache"/> + <arg name="colors"/> + + <!-- Ignore warnings, show progress of the run and show sniff names --> + <arg value="nps"/> + + <!-- Directories to be checked --> + <file>src</file> + <file>tests</file> + + <!-- Include full Unleashed Coding Standard --> + <rule ref="Unleashed"/> + + <rule ref="SlevomatCodingStandard.Commenting.ForbiddenAnnotations.AnnotationForbidden"> + <exclude-pattern>src/HtmlConverter*\.php</exclude-pattern> + </rule> + + <rule ref="SlevomatCodingStandard.Commenting.DocCommentSpacing.IncorrectOrderOfAnnotationsGroup"> + <exclude-pattern>src/HtmlConverter*\.php</exclude-pattern> + </rule> + +</ruleset> diff --git a/vendor/league/html-to-markdown/phpstan.neon.dist b/vendor/league/html-to-markdown/phpstan.neon.dist new file mode 100644 index 000000000..a1c637a78 --- /dev/null +++ b/vendor/league/html-to-markdown/phpstan.neon.dist @@ -0,0 +1,4 @@ +parameters: + level: max + paths: + - src diff --git a/vendor/league/html-to-markdown/psalm.xml b/vendor/league/html-to-markdown/psalm.xml new file mode 100644 index 000000000..30258a709 --- /dev/null +++ b/vendor/league/html-to-markdown/psalm.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<psalm + errorLevel="3" + resolveFromConfigFile="true" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="https://getpsalm.org/schema/config" + xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" +> + <projectFiles> + <directory name="src" /> + <ignoreFiles> + <directory name="vendor" /> + </ignoreFiles> + </projectFiles> +</psalm> diff --git a/vendor/league/html-to-markdown/src/Configuration.php b/vendor/league/html-to-markdown/src/Configuration.php index 5bc8d5503..7e1d71e68 100644 --- a/vendor/league/html-to-markdown/src/Configuration.php +++ b/vendor/league/html-to-markdown/src/Configuration.php @@ -1,15 +1,18 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; class Configuration { + /** @var array<string, mixed> */ protected $config; /** - * @param array $config + * @param array<string, mixed> $config */ - public function __construct(array $config = array()) + public function __construct(array $config = []) { $this->config = $config; @@ -17,59 +20,60 @@ class Configuration } /** - * @param array $config + * @param array<string, mixed> $config */ - public function merge(array $config = array()) + public function merge(array $config = []): void { $this->checkForDeprecatedOptions($config); - $this->config = array_replace_recursive($this->config, $config); + $this->config = \array_replace_recursive($this->config, $config); } /** - * @param array $config + * @param array<string, mixed> $config */ - public function replace(array $config = array()) + public function replace(array $config = []): void { $this->checkForDeprecatedOptions($config); $this->config = $config; } /** - * @param string $key - * @param mixed $value + * @param mixed $value */ - public function setOption($key, $value) + public function setOption(string $key, $value): void { - $this->checkForDeprecatedOptions(array($key => $value)); + $this->checkForDeprecatedOptions([$key => $value]); $this->config[$key] = $value; } /** - * @param string|null $key - * @param mixed|null $default + * @param mixed|null $default * * @return mixed|null */ - public function getOption($key = null, $default = null) + public function getOption(?string $key = null, $default = null) { if ($key === null) { return $this->config; } - if (!isset($this->config[$key])) { + if (! isset($this->config[$key])) { return $default; } return $this->config[$key]; } - private function checkForDeprecatedOptions(array $config) + /** + * @param array<string, mixed> $config + */ + private function checkForDeprecatedOptions(array $config): void { foreach ($config as $key => $value) { if ($key === 'bold_style' && $value !== '**') { - @trigger_error('Customizing the bold_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED); + @\trigger_error('Customizing the bold_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED); } elseif ($key === 'italic_style' && $value !== '*') { - @trigger_error('Customizing the italic_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED); + @\trigger_error('Customizing the italic_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED); } } } diff --git a/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php b/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php index 8aca530be..50c004c4a 100644 --- a/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php +++ b/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php @@ -1,11 +1,10 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; interface ConfigurationAwareInterface { - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config); + public function setConfig(Configuration $config): void; } diff --git a/vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php b/vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php index eb2d09d17..65034db12 100644 --- a/vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php @@ -1,32 +1,30 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class BlockquoteConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { // Contents should have already been converted to Markdown by this point, // so we just need to add '>' symbols to each line. $markdown = ''; - $quote_content = trim($element->getValue()); + $quoteContent = \trim($element->getValue()); - $lines = preg_split('/\r\n|\r|\n/', $quote_content); + $lines = \preg_split('/\r\n|\r|\n/', $quoteContent); + \assert(\is_array($lines)); - $total_lines = count($lines); + $totalLines = \count($lines); foreach ($lines as $i => $line) { $markdown .= '> ' . $line . "\n"; - if ($i + 1 === $total_lines) { + if ($i + 1 === $totalLines) { $markdown .= "\n"; } } @@ -37,8 +35,8 @@ class BlockquoteConverter implements ConverterInterface /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('blockquote'); + return ['blockquote']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/CodeConverter.php b/vendor/league/html-to-markdown/src/Converter/CodeConverter.php index 39e6a7bc4..40eb7f85a 100644 --- a/vendor/league/html-to-markdown/src/Converter/CodeConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/CodeConverter.php @@ -1,17 +1,14 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class CodeConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { $language = ''; @@ -20,23 +17,24 @@ class CodeConverter implements ConverterInterface if ($classes) { // Since tags can have more than one class, we need to find the one that starts with 'language-' - $classes = explode(' ', $classes); + $classes = \explode(' ', $classes); foreach ($classes as $class) { - if (strpos($class, 'language-') !== false) { + if (\strpos($class, 'language-') !== false) { // Found one, save it as the selected language and stop looping over the classes. - $language = str_replace('language-', '', $class); + $language = \str_replace('language-', '', $class); break; } } } $markdown = ''; - $code = html_entity_decode($element->getChildrenAsString()); + $code = \html_entity_decode($element->getChildrenAsString()); // In order to remove the code tags we need to search for them and, in the case of the opening tag // use a regular expression to find the tag and the other attributes it might have - $code = preg_replace('/<code\b[^>]*>/', '', $code); - $code = str_replace('</code>', '', $code); + $code = \preg_replace('/<code\b[^>]*>/', '', $code); + \assert($code !== null); + $code = \str_replace('</code>', '', $code); // Checking if it's a code block or span if ($this->shouldBeBlock($element, $code)) { @@ -44,7 +42,7 @@ class CodeConverter implements ConverterInterface $markdown .= '```' . $language . "\n" . $code . "\n" . '```'; } else { // One line of code, wrapping it on one backtick, removing new lines - $markdown .= '`' . preg_replace('/\r\n|\r|\n/', '', $code) . '`'; + $markdown .= '`' . \preg_replace('/\r\n|\r|\n/', '', $code) . '`'; } return $markdown; @@ -53,27 +51,18 @@ class CodeConverter implements ConverterInterface /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('code'); + return ['code']; } - /** - * @param ElementInterface $element - * @param string $code - * - * @return bool - */ - private function shouldBeBlock(ElementInterface $element, $code) + private function shouldBeBlock(ElementInterface $element, string $code): bool { - if ($element->getParent()->getTagName() == 'pre') { - return true; - } - - if (preg_match('/[^\s]` `/', $code)) { + $parent = $element->getParent(); + if ($parent !== null && $parent->getTagName() === 'pre') { return true; } - return false; + return \preg_match('/[^\s]` `/', $code) === 1; } } diff --git a/vendor/league/html-to-markdown/src/Converter/CommentConverter.php b/vendor/league/html-to-markdown/src/Converter/CommentConverter.php index 959381d1b..c69dea551 100644 --- a/vendor/league/html-to-markdown/src/Converter/CommentConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/CommentConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,55 +10,44 @@ use League\HTMLToMarkdown\ElementInterface; class CommentConverter implements ConverterInterface, ConfigurationAwareInterface { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { if ($this->shouldPreserve($element)) { return '<!--' . $element->getValue() . '-->'; } + return ''; } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('#comment'); + return ['#comment']; } - /** - * @param ElementInterface $element - * - * @return bool - */ - private function shouldPreserve(ElementInterface $element) + private function shouldPreserve(ElementInterface $element): bool { $preserve = $this->config->getOption('preserve_comments'); if ($preserve === true) { return true; } - if (is_array($preserve)) { - $value = trim($element->getValue()); - return in_array($value, $preserve); + + if (\is_array($preserve)) { + $value = \trim($element->getValue()); + + return \in_array($value, $preserve, true); } + return false; } } diff --git a/vendor/league/html-to-markdown/src/Converter/ConverterInterface.php b/vendor/league/html-to-markdown/src/Converter/ConverterInterface.php index 8530559a0..f10498578 100644 --- a/vendor/league/html-to-markdown/src/Converter/ConverterInterface.php +++ b/vendor/league/html-to-markdown/src/Converter/ConverterInterface.php @@ -1,20 +1,17 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; interface ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element); + public function convert(ElementInterface $element): string; /** * @return string[] */ - public function getSupportedTags(); + public function getSupportedTags(): array; } diff --git a/vendor/league/html-to-markdown/src/Converter/DefaultConverter.php b/vendor/league/html-to-markdown/src/Converter/DefaultConverter.php index 8de0af210..e71dd10cc 100644 --- a/vendor/league/html-to-markdown/src/Converter/DefaultConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/DefaultConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,27 +10,17 @@ use League\HTMLToMarkdown\ElementInterface; class DefaultConverter implements ConverterInterface, ConfigurationAwareInterface { - const DEFAULT_CONVERTER = '_default'; + public const DEFAULT_CONVERTER = '_default'; - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { // If strip_tags is false (the default), preserve tags that don't have Markdown equivalents, // such as <span> nodes on their own. C14N() canonicalizes the node to a string. @@ -37,8 +29,9 @@ class DefaultConverter implements ConverterInterface, ConfigurationAwareInterfac return $element->getValue(); } - $markdown = html_entity_decode($element->getChildrenAsString()); + $markdown = \html_entity_decode($element->getChildrenAsString()); + // Tables are only handled here if TableConverter is not used if ($element->getTagName() === 'table') { $markdown .= "\n\n"; } @@ -49,8 +42,8 @@ class DefaultConverter implements ConverterInterface, ConfigurationAwareInterfac /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array(self::DEFAULT_CONVERTER); + return [self::DEFAULT_CONVERTER]; } } diff --git a/vendor/league/html-to-markdown/src/Converter/DivConverter.php b/vendor/league/html-to-markdown/src/Converter/DivConverter.php index 656a0ba4d..6453a2a27 100644 --- a/vendor/league/html-to-markdown/src/Converter/DivConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/DivConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,38 +10,28 @@ use League\HTMLToMarkdown\ElementInterface; class DivConverter implements ConverterInterface, ConfigurationAwareInterface { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { if ($this->config->getOption('strip_tags', false)) { return $element->getValue() . "\n\n"; } - return html_entity_decode($element->getChildrenAsString()); + return \html_entity_decode($element->getChildrenAsString()); } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('div'); + return ['div']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php b/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php index 8fd4dd6e2..a122f4052 100644 --- a/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,50 +10,63 @@ use League\HTMLToMarkdown\ElementInterface; class EmphasisConverter implements ConverterInterface, ConfigurationAwareInterface { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + protected function getNormTag(?ElementInterface $element): string + { + if ($element !== null && ! $element->isText()) { + $tag = $element->getTagName(); + if ($tag === 'i' || $tag === 'em') { + return 'em'; + } + + if ($tag === 'b' || $tag === 'strong') { + return 'strong'; + } + } + + return ''; + } + + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { - $tag = $element->getTagName(); + $tag = $this->getNormTag($element); $value = $element->getValue(); - if (!trim($value)) { + if (! \trim($value)) { return $value; } - if ($tag === 'i' || $tag === 'em') { + if ($tag === 'em') { $style = $this->config->getOption('italic_style'); } else { $style = $this->config->getOption('bold_style'); } - $prefix = ltrim($value) !== $value ? ' ' : ''; - $suffix = rtrim($value) !== $value ? ' ' : ''; + $prefix = \ltrim($value) !== $value ? ' ' : ''; + $suffix = \rtrim($value) !== $value ? ' ' : ''; + + /* If this node is immediately preceded or followed by one of the same type don't emit + * the start or end $style, respectively. This prevents <em>foo</em><em>bar</em> from + * being converted to *foo**bar* which is incorrect. We want *foobar* instead. + */ + $preStyle = $this->getNormTag($element->getPreviousSibling()) === $tag ? '' : $style; + $postStyle = $this->getNormTag($element->getNextSibling()) === $tag ? '' : $style; - return $prefix . $style . trim($value) . $style . $suffix; + return $prefix . $preStyle . \trim($value) . $postStyle . $suffix; } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('em', 'i', 'strong', 'b'); + return ['em', 'i', 'strong', 'b']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php b/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php index 1be10bd63..45e89682e 100644 --- a/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,35 +10,25 @@ use League\HTMLToMarkdown\ElementInterface; class HardBreakConverter implements ConverterInterface, ConfigurationAwareInterface { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { $return = $this->config->getOption('hard_break') ? "\n" : " \n"; $next = $element->getNext(); if ($next) { - $next_value = $next->getValue(); - if ($next_value) { - if (in_array(substr($next_value, 0, 2), array('- ', '* ', '+ '))) { + $nextValue = $next->getValue(); + if ($nextValue) { + if (\in_array(\substr($nextValue, 0, 2), ['- ', '* ', '+ '], true)) { $parent = $element->getParent(); - if ($parent && $parent->getTagName() == 'li') { + if ($parent && $parent->getTagName() === 'li') { $return .= '\\'; } } @@ -49,8 +41,8 @@ class HardBreakConverter implements ConverterInterface, ConfigurationAwareInterf /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('br'); + return ['br']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php b/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php index 353833263..e99dfa0f4 100644 --- a/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,37 +10,27 @@ use League\HTMLToMarkdown\ElementInterface; class HeaderConverter implements ConverterInterface, ConfigurationAwareInterface { - const STYLE_ATX = 'atx'; - const STYLE_SETEXT = 'setext'; + public const STYLE_ATX = 'atx'; + public const STYLE_SETEXT = 'setext'; - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { - $level = (int) substr($element->getTagName(), 1, 1); + $level = (int) \substr($element->getTagName(), 1, 1); $style = $this->config->getOption('header_style', self::STYLE_SETEXT); - if (strlen($element->getValue()) === 0) { + if (\strlen($element->getValue()) === 0) { return "\n"; } - if (($level === 1 || $level === 2) && !$element->isDescendantOf('blockquote') && $style === self::STYLE_SETEXT) { + if (($level === 1 || $level === 2) && ! $element->isDescendantOf('blockquote') && $style === self::STYLE_SETEXT) { return $this->createSetextHeader($level, $element->getValue()); } @@ -48,34 +40,22 @@ class HeaderConverter implements ConverterInterface, ConfigurationAwareInterface /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + return ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; } - /** - * @param int $level - * @param string $content - * - * @return string - */ - private function createSetextHeader($level, $content) + private function createSetextHeader(int $level, string $content): string { - $length = function_exists('mb_strlen') ? mb_strlen($content, 'utf-8') : strlen($content); - $underline = ($level === 1) ? '=' : '-'; + $length = \function_exists('mb_strlen') ? \mb_strlen($content, 'utf-8') : \strlen($content); + $underline = $level === 1 ? '=' : '-'; - return $content . "\n" . str_repeat($underline, $length) . "\n\n"; + return $content . "\n" . \str_repeat($underline, $length) . "\n\n"; } - /** - * @param int $level - * @param string $content - * - * @return string - */ - private function createAtxHeader($level, $content) + private function createAtxHeader(int $level, string $content): string { - $prefix = str_repeat('#', $level) . ' '; + $prefix = \str_repeat('#', $level) . ' '; return $prefix . $content . "\n\n"; } diff --git a/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php b/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php index 8f54f9397..a2b1ac14a 100644 --- a/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php @@ -1,26 +1,23 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class HorizontalRuleConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { - return "- - - - - -\n\n"; + return "---\n\n"; } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('hr'); + return ['hr']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/ImageConverter.php b/vendor/league/html-to-markdown/src/Converter/ImageConverter.php index 657c769c2..5cd8aec67 100644 --- a/vendor/league/html-to-markdown/src/Converter/ImageConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/ImageConverter.php @@ -1,20 +1,17 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class ImageConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { - $src = $element->getAttribute('src'); - $alt = $element->getAttribute('alt'); + $src = $element->getAttribute('src'); + $alt = $element->getAttribute('alt'); $title = $element->getAttribute('title'); if ($title !== '') { @@ -28,8 +25,8 @@ class ImageConverter implements ConverterInterface /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('img'); + return ['img']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/LinkConverter.php b/vendor/league/html-to-markdown/src/Converter/LinkConverter.php index ed52619d2..25a3540fe 100644 --- a/vendor/league/html-to-markdown/src/Converter/LinkConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/LinkConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,28 +10,19 @@ use League\HTMLToMarkdown\ElementInterface; class LinkConverter implements ConverterInterface, ConfigurationAwareInterface { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) { + public function setConfig(Configuration $config): void + { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { - $href = $element->getAttribute('href'); + $href = $element->getAttribute('href'); $title = $element->getAttribute('title'); - $text = trim($element->getValue(), "\t\n\r\0\x0B"); + $text = \trim($element->getValue(), "\t\n\r\0\x0B"); if ($title !== '') { $markdown = '[' . $text . '](' . $href . ' "' . $title . '")'; @@ -38,14 +31,19 @@ class LinkConverter implements ConverterInterface, ConfigurationAwareInterface } elseif ($href === 'mailto:' . $text && $this->isValidEmail($text)) { $markdown = '<' . $text . '>'; } else { - if (stristr($href, ' ')) { - $href = '<'.$href.'>'; + if (\stristr($href, ' ')) { + $href = '<' . $href . '>'; } + $markdown = '[' . $text . '](' . $href . ')'; } - if (!$href) { - $markdown = html_entity_decode($element->getChildrenAsString()); + if (! $href) { + if ($this->shouldStrip()) { + $markdown = $text; + } else { + $markdown = \html_entity_decode($element->getChildrenAsString()); + } } return $markdown; @@ -54,30 +52,26 @@ class LinkConverter implements ConverterInterface, ConfigurationAwareInterface /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('a'); + return ['a']; } - /** - * @param string $href - * - * @return bool - */ - private function isValidAutolink($href) + private function isValidAutolink(string $href): bool { $useAutolinks = $this->config->getOption('use_autolinks'); - return $useAutolinks && (preg_match('/^[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*/i', $href) === 1); + + return $useAutolinks && (\preg_match('/^[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*/i', $href) === 1); } - /** - * @param string $email - * - * @return bool - */ - private function isValidEmail($email) + private function isValidEmail(string $email): bool { // Email validation is messy business, but this should cover most cases - return filter_var($email, FILTER_VALIDATE_EMAIL); + return \filter_var($email, FILTER_VALIDATE_EMAIL) !== false; + } + + private function shouldStrip(): bool + { + return $this->config->getOption('strip_placeholder_links') ?? false; } } diff --git a/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php b/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php index 07a4c85a9..ce7b94654 100644 --- a/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php @@ -1,17 +1,14 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class ListBlockConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { return $element->getValue() . "\n"; } @@ -19,8 +16,8 @@ class ListBlockConverter implements ConverterInterface /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('ol', 'ul'); + return ['ol', 'ul']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php b/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php index c56ab89cd..1521aad53 100644 --- a/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\Configuration; @@ -8,39 +10,26 @@ use League\HTMLToMarkdown\ElementInterface; class ListItemConverter implements ConverterInterface, ConfigurationAwareInterface { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; - /** - * @var string - */ + /** @var string|null */ protected $listItemStyle; - /** - * @param Configuration $config - */ - public function setConfig(Configuration $config) + public function setConfig(Configuration $config): void { $this->config = $config; } - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { // If parent is an ol, use numbers, otherwise, use dashes - $list_type = $element->getParent()->getTagName(); + $listType = ($parent = $element->getParent()) ? $parent->getTagName() : 'ul'; // Add spaces to start for nested list items - $level = $element->getListItemLevel($element); + $level = $element->getListItemLevel(); - $prefixForParagraph = str_repeat(' ', $level + 1); - $value = trim(implode("\n" . $prefixForParagraph, explode("\n", trim($element->getValue())))); + $value = \trim(\implode("\n" . ' ', \explode("\n", \trim($element->getValue())))); // If list item is the first in a nested list, add a newline before it $prefix = ''; @@ -48,21 +37,21 @@ class ListItemConverter implements ConverterInterface, ConfigurationAwareInterfa $prefix = "\n"; } - if ($list_type === 'ul') { - $list_item_style = $this->config->getOption('list_item_style', '-'); - $list_item_style_alternate = $this->config->getOption('list_item_style_alternate'); - if (!isset($this->listItemStyle)) { - $this->listItemStyle = $list_item_style_alternate ? $list_item_style_alternate : $list_item_style; + if ($listType === 'ul') { + $listItemStyle = $this->config->getOption('list_item_style', '-'); + $listItemStyleAlternate = $this->config->getOption('list_item_style_alternate'); + if (! isset($this->listItemStyle)) { + $this->listItemStyle = $listItemStyleAlternate ?: $listItemStyle; } - if ($list_item_style_alternate && $level == 0 && $element->getSiblingPosition() === 1) { - $this->listItemStyle = $this->listItemStyle == $list_item_style ? $list_item_style_alternate : $list_item_style; + if ($listItemStyleAlternate && $level === 0 && $element->getSiblingPosition() === 1) { + $this->listItemStyle = $this->listItemStyle === $listItemStyle ? $listItemStyleAlternate : $listItemStyle; } return $prefix . $this->listItemStyle . ' ' . $value . "\n"; } - if ($list_type === 'ol' && $start = $element->getParent()->getAttribute('start')) { + if ($listType === 'ol' && ($parent = $element->getParent()) && ($start = \intval($parent->getAttribute('start')))) { $number = $start + $element->getSiblingPosition() - 1; } else { $number = $element->getSiblingPosition(); @@ -74,8 +63,8 @@ class ListItemConverter implements ConverterInterface, ConfigurationAwareInterfa /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('li'); + return ['li']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php b/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php index 7207b81a6..65b37a4db 100644 --- a/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php @@ -1,23 +1,22 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class ParagraphConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { $value = $element->getValue(); $markdown = ''; - $lines = preg_split('/\r\n|\r|\n/', $value); + $lines = \preg_split('/\r\n|\r|\n/', $value); + \assert($lines !== false); + foreach ($lines as $line) { /* * Some special characters need to be escaped based on the position that they appear @@ -27,23 +26,18 @@ class ParagraphConverter implements ConverterInterface $markdown .= "\n"; } - return trim($markdown) !== '' ? rtrim($markdown) . "\n\n" : ''; + return \trim($markdown) !== '' ? \rtrim($markdown) . "\n\n" : ''; } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('p'); + return ['p']; } - /** - * @param string $line - * - * @return string - */ - private function escapeSpecialCharacters($line) + private function escapeSpecialCharacters(string $line): string { $line = $this->escapeFirstCharacters($line); $line = $this->escapeOtherCharacters($line); @@ -52,72 +46,61 @@ class ParagraphConverter implements ConverterInterface return $line; } - /** - * @param string $line - * - * @return string - */ - private function escapeFirstCharacters($line) + private function escapeFirstCharacters(string $line): string { - $escapable = array( + $escapable = [ '>', '- ', '+ ', '--', '~~~', '---', - '- - -' - ); + '- - -', + ]; foreach ($escapable as $i) { - if (strpos(ltrim($line), $i) === 0) { + if (\strpos(\ltrim($line), $i) === 0) { // Found a character that must be escaped, adding a backslash before - return '\\' . ltrim($line); + return '\\' . \ltrim($line); } } return $line; } - /** - * @param string $line - * - * @return string - */ - private function escapeOtherCharacters($line) + private function escapeOtherCharacters(string $line): string { - $escapable = array( - '<!--' - ); + $escapable = [ + '<!--', + ]; foreach ($escapable as $i) { - if (strpos($line, $i) !== false) { - // Found an escapable character, escaping it - $line = substr_replace($line, '\\', strpos($line, $i), 0); + if (($pos = \strpos($line, $i)) === false) { + continue; } + + // Found an escapable character, escaping it + $line = \substr_replace($line, '\\', $pos, 0); } return $line; } - /** - * @param string $line - * - * @return string - */ - private function escapeOtherCharactersRegex($line) + private function escapeOtherCharactersRegex(string $line): string { - $regExs = array( + $regExs = [ // Match numbers ending on ')' or '.' that are at the beginning of the line. // They will be escaped if immediately followed by a space or newline. - '/^[0-9]+(?=(\)|\.)( |$))/' - ); + '/^[0-9]+(?=(\)|\.)( |$))/', + ]; foreach ($regExs as $i) { - if (preg_match($i, $line, $match)) { - // Matched an escapable character, adding a backslash on the string before the offending character - $line = substr_replace($line, '\\', strlen($match[0]), 0); + if (! \preg_match($i, $line, $match)) { + continue; } + + // Matched an escapable character, adding a backslash on the string before the offending character + $line = \substr_replace($line, '\\', \strlen($match[0]), 0); } return $line; diff --git a/vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php b/vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php index 321c898b1..7d8ccc132 100644 --- a/vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php @@ -1,20 +1,17 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class PreformattedConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { - $pre_content = html_entity_decode($element->getChildrenAsString()); - $pre_content = str_replace(array('<pre>', '</pre>'), '', $pre_content); + $preContent = \html_entity_decode($element->getChildrenAsString()); + $preContent = \str_replace(['<pre>', '</pre>'], '', $preContent); /* * Checking for the code tag. @@ -23,36 +20,37 @@ class PreformattedConverter implements ConverterInterface * there's no more information to convert. */ - $firstBacktick = strpos(trim($pre_content), '`'); - $lastBacktick = strrpos(trim($pre_content), '`'); - if ($firstBacktick === 0 && $lastBacktick === strlen(trim($pre_content)) - 1) { - return $pre_content . "\n\n"; + $firstBacktick = \strpos(\trim($preContent), '`'); + $lastBacktick = \strrpos(\trim($preContent), '`'); + if ($firstBacktick === 0 && $lastBacktick === \strlen(\trim($preContent)) - 1) { + return $preContent . "\n\n"; } // If the execution reaches this point it means it's just a pre tag, with no code tag nested // Empty lines are a special case - if ($pre_content === '') { + if ($preContent === '') { return "```\n```\n\n"; } // Normalizing new lines - $pre_content = preg_replace('/\r\n|\r|\n/', "\n", $pre_content); + $preContent = \preg_replace('/\r\n|\r|\n/', "\n", $preContent); + \assert(\is_string($preContent)); // Ensure there's a newline at the end - if (strrpos($pre_content, "\n") !== strlen($pre_content) - strlen("\n")) { - $pre_content .= "\n"; + if (\strrpos($preContent, "\n") !== \strlen($preContent) - \strlen("\n")) { + $preContent .= "\n"; } // Use three backticks - return "```\n" . $pre_content . "```\n\n"; + return "```\n" . $preContent . "```\n\n"; } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('pre'); + return ['pre']; } } diff --git a/vendor/league/html-to-markdown/src/Converter/TableConverter.php b/vendor/league/html-to-markdown/src/Converter/TableConverter.php new file mode 100644 index 000000000..2e63e9a5b --- /dev/null +++ b/vendor/league/html-to-markdown/src/Converter/TableConverter.php @@ -0,0 +1,113 @@ +<?php + +declare(strict_types=1); + +namespace League\HTMLToMarkdown\Converter; + +use League\HTMLToMarkdown\Configuration; +use League\HTMLToMarkdown\ConfigurationAwareInterface; +use League\HTMLToMarkdown\ElementInterface; +use League\HTMLToMarkdown\PreConverterInterface; + +class TableConverter implements ConverterInterface, PreConverterInterface, ConfigurationAwareInterface +{ + /** @var Configuration */ + protected $config; + + public function setConfig(Configuration $config): void + { + $this->config = $config; + } + + /** @var array<string, string> */ + private static $alignments = [ + 'left' => ':--', + 'right' => '--:', + 'center' => ':-:', + ]; + + /** @var array<int, string>|null */ + private $columnAlignments = []; + + /** @var string|null */ + private $caption = null; + + public function preConvert(ElementInterface $element): void + { + $tag = $element->getTagName(); + // Only table cells and caption are allowed to contain content. + // Remove all text between other table elements. + if ($tag === 'th' || $tag === 'td' || $tag === 'caption') { + return; + } + + foreach ($element->getChildren() as $child) { + if ($child->isText()) { + $child->setFinalMarkdown(''); + } + } + } + + public function convert(ElementInterface $element): string + { + $value = $element->getValue(); + + switch ($element->getTagName()) { + case 'table': + $this->columnAlignments = []; + if ($this->caption) { + $side = $this->config->getOption('table_caption_side'); + if ($side === 'top') { + $value = $this->caption . "\n" . $value; + } elseif ($side === 'bottom') { + $value .= $this->caption; + } + + $this->caption = null; + } + + return $value . "\n"; + case 'caption': + $this->caption = \trim($value); + + return ''; + case 'tr': + $value .= "|\n"; + if ($this->columnAlignments !== null) { + $value .= '|' . \implode('|', $this->columnAlignments) . "|\n"; + + $this->columnAlignments = null; + } + + return $value; + case 'th': + case 'td': + if ($this->columnAlignments !== null) { + $align = $element->getAttribute('align'); + + $this->columnAlignments[] = self::$alignments[$align] ?? '---'; + } + + $value = \str_replace("\n", ' ', $value); + $value = \str_replace('|', $this->config->getOption('table_pipe_escape') ?? '\|', $value); + + return '| ' . \trim($value) . ' '; + case 'thead': + case 'tbody': + case 'tfoot': + case 'colgroup': + case 'col': + return $value; + default: + return ''; + } + } + + /** + * @return string[] + */ + public function getSupportedTags(): array + { + return ['table', 'tr', 'th', 'td', 'thead', 'tbody', 'tfoot', 'colgroup', 'col', 'caption']; + } +} diff --git a/vendor/league/html-to-markdown/src/Converter/TextConverter.php b/vendor/league/html-to-markdown/src/Converter/TextConverter.php index 6236a1e9d..465dd4883 100644 --- a/vendor/league/html-to-markdown/src/Converter/TextConverter.php +++ b/vendor/league/html-to-markdown/src/Converter/TextConverter.php @@ -1,48 +1,48 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown\Converter; use League\HTMLToMarkdown\ElementInterface; class TextConverter implements ConverterInterface { - /** - * @param ElementInterface $element - * - * @return string - */ - public function convert(ElementInterface $element) + public function convert(ElementInterface $element): string { $markdown = $element->getValue(); // Remove leftover \n at the beginning of the line - $markdown = ltrim($markdown, "\n"); + $markdown = \ltrim($markdown, "\n"); // Replace sequences of invisible characters with spaces - $markdown = preg_replace('~\s+~u', ' ', $markdown); + $markdown = \preg_replace('~\s+~u', ' ', $markdown); + \assert(\is_string($markdown)); // Escape the following characters: '*', '_', '[', ']' and '\' - if ($element->getParent() && $element->getParent()->getTagName() !== 'div') { - $markdown = preg_replace('~([*_\\[\\]\\\\])~u', '\\\\$1', $markdown); + if (($parent = $element->getParent()) && $parent->getTagName() !== 'div') { + $markdown = \preg_replace('~([*_\\[\\]\\\\])~u', '\\\\$1', $markdown); + \assert(\is_string($markdown)); } - $markdown = preg_replace('~^#~u', '\\\\#', $markdown); + $markdown = \preg_replace('~^#~u', '\\\\#', $markdown); + \assert(\is_string($markdown)); if ($markdown === ' ') { $next = $element->getNext(); - if (!$next || $next->isBlock()) { + if (! $next || $next->isBlock()) { $markdown = ''; } } - return htmlspecialchars($markdown, ENT_NOQUOTES, 'UTF-8'); + return \htmlspecialchars($markdown, ENT_NOQUOTES, 'UTF-8'); } /** * @return string[] */ - public function getSupportedTags() + public function getSupportedTags(): array { - return array('#text'); + return ['#text']; } } diff --git a/vendor/league/html-to-markdown/src/Element.php b/vendor/league/html-to-markdown/src/Element.php index 80ae7a911..0515b5995 100644 --- a/vendor/league/html-to-markdown/src/Element.php +++ b/vendor/league/html-to-markdown/src/Element.php @@ -1,28 +1,28 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; class Element implements ElementInterface { - /** - * @var \DOMNode - */ + /** @var \DOMNode */ protected $node; - /** - * @var ElementInterface|null - */ + /** @var ElementInterface|null */ private $nextCached; + /** @var \DOMNode|null */ + private $previousSiblingCached; + public function __construct(\DOMNode $node) { $this->node = $node; + + $this->previousSiblingCached = $this->node->previousSibling; } - /** - * @return bool - */ - public function isBlock() + public function isBlock(): bool { switch ($this->getTagName()) { case 'blockquote': @@ -46,50 +46,47 @@ class Element implements ElementInterface } } - /** - * @return bool - */ - public function isText() + public function isText(): bool { return $this->getTagName() === '#text'; } - /** - * @return bool - */ - public function isWhitespace() + public function isWhitespace(): bool { - return $this->getTagName() === '#text' && trim($this->getValue()) === ''; + return $this->getTagName() === '#text' && \trim($this->getValue()) === ''; } - /** - * @return string - */ - public function getTagName() + public function getTagName(): string { return $this->node->nodeName; } - /** - * @return string - */ - public function getValue() + public function getValue(): string { - return $this->node->nodeValue; + return $this->node->nodeValue ?? ''; } - /** - * @return ElementInterface|null - */ - public function getParent() + public function hasParent(): bool { - return new static($this->node->parentNode) ?: null; + return $this->node->parentNode !== null; } - /** - * @return bool - */ - public function hasChildren() + public function getParent(): ?ElementInterface + { + return $this->node->parentNode ? new self($this->node->parentNode) : null; + } + + public function getNextSibling(): ?ElementInterface + { + return $this->node->nextSibling !== null ? new self($this->node->nextSibling) : null; + } + + public function getPreviousSibling(): ?ElementInterface + { + return $this->previousSiblingCached !== null ? new self($this->previousSiblingCached) : null; + } + + public function hasChildren(): bool { return $this->node->hasChildNodes(); } @@ -97,39 +94,29 @@ class Element implements ElementInterface /** * @return ElementInterface[] */ - public function getChildren() + public function getChildren(): array { - $ret = array(); - /** @var \DOMNode $node */ + $ret = []; foreach ($this->node->childNodes as $node) { - $ret[] = new static($node); + $ret[] = new self($node); } return $ret; } - /** - * @return ElementInterface|null - */ - public function getNext() + public function getNext(): ?ElementInterface { if ($this->nextCached === null) { $nextNode = $this->getNextNode($this->node); if ($nextNode !== null) { - $this->nextCached = new static($nextNode); + $this->nextCached = new self($nextNode); } } return $this->nextCached; } - /** - * @param \DomNode $node - * @param bool $checkChildren - * - * @return \DomNode|null - */ - private function getNextNode($node, $checkChildren = true) + private function getNextNode(\DomNode $node, bool $checkChildren = true): ?\DomNode { if ($checkChildren && $node->firstChild) { return $node->firstChild; @@ -142,25 +129,25 @@ class Element implements ElementInterface if ($node->parentNode) { return $this->getNextNode($node->parentNode, false); } + + return null; } /** * @param string[]|string $tagNames - * - * @return bool */ - public function isDescendantOf($tagNames) + public function isDescendantOf($tagNames): bool { - if (!is_array($tagNames)) { - $tagNames = array($tagNames); + if (! \is_array($tagNames)) { + $tagNames = [$tagNames]; } for ($p = $this->node->parentNode; $p !== false; $p = $p->parentNode) { - if (is_null($p)) { + if ($p === null) { return false; } - if (in_array($p->nodeName, $tagNames)) { + if (\in_array($p->nodeName, $tagNames, true)) { return true; } } @@ -168,39 +155,43 @@ class Element implements ElementInterface return false; } - /** - * @param string $markdown - */ - public function setFinalMarkdown($markdown) + public function setFinalMarkdown(string $markdown): void { - $markdown_node = $this->node->ownerDocument->createTextNode($markdown); - $this->node->parentNode->replaceChild($markdown_node, $this->node); + if ($this->node->ownerDocument === null) { + throw new \RuntimeException('Unowned node'); + } + + if ($this->node->parentNode === null) { + throw new \RuntimeException('Cannot setFinalMarkdown() on a node without a parent'); + } + + $markdownNode = $this->node->ownerDocument->createTextNode($markdown); + $this->node->parentNode->replaceChild($markdownNode, $this->node); } - /** - * @return string - */ - public function getChildrenAsString() + public function getChildrenAsString(): string { return $this->node->C14N(); } - /** - * @return int - */ - public function getSiblingPosition() + public function getSiblingPosition(): int { $position = 0; + $parent = $this->getParent(); + if ($parent === null) { + return $position; + } + // Loop through all nodes and find the given $node - foreach ($this->getParent()->getChildren() as $current_node) { - if (!$current_node->isWhitespace()) { + foreach ($parent->getChildren() as $currentNode) { + if (! $currentNode->isWhitespace()) { $position++; } // TODO: Need a less-buggy way of comparing these // Perhaps we can somehow ensure that we always have the exact same object and use === instead? - if ($this->equals($current_node)) { + if ($this->equals($currentNode)) { break; } } @@ -208,30 +199,23 @@ class Element implements ElementInterface return $position; } - /** - * @return int - */ - public function getListItemLevel() + public function getListItemLevel(): int { - $level = 0; + $level = 0; $parent = $this->getParent(); - while ($parent !== null && $parent->node->parentNode) { + while ($parent !== null && $parent->hasParent()) { if ($parent->getTagName() === 'li') { $level++; } + $parent = $parent->getParent(); } return $level; } - /** - * @param string $name - * - * @return string - */ - public function getAttribute($name) + public function getAttribute(string $name): string { if ($this->node instanceof \DOMElement) { return $this->node->getAttribute($name); @@ -240,17 +224,12 @@ class Element implements ElementInterface return ''; } - /** - * @param ElementInterface $element - * - * @return bool - */ - public function equals(ElementInterface $element) + public function equals(ElementInterface $element): bool { if ($element instanceof self) { return $element->node === $this->node; } - return $element === $this; + return false; } } diff --git a/vendor/league/html-to-markdown/src/ElementInterface.php b/vendor/league/html-to-markdown/src/ElementInterface.php index 138ddf286..d8477cfae 100644 --- a/vendor/league/html-to-markdown/src/ElementInterface.php +++ b/vendor/league/html-to-markdown/src/ElementInterface.php @@ -1,80 +1,50 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; interface ElementInterface { - /** - * @return bool - */ - public function isBlock(); + public function isBlock(): bool; - /** - * @return bool - */ - public function isText(); + public function isText(): bool; - /** - * @return bool - */ - public function isWhitespace(); + public function isWhitespace(): bool; - /** - * @return string - */ - public function getTagName(); + public function getTagName(): string; - /** - * @return string - */ - public function getValue(); + public function getValue(): string; - /** - * @return ElementInterface|null - */ - public function getParent(); + public function hasParent(): bool; + + public function getParent(): ?ElementInterface; + + public function getNextSibling(): ?ElementInterface; + + public function getPreviousSibling(): ?ElementInterface; /** * @param string|string[] $tagNames - * - * @return bool */ - public function isDescendantOf($tagNames); + public function isDescendantOf($tagNames): bool; - /** - * @return bool - */ - public function hasChildren(); + public function hasChildren(): bool; /** * @return ElementInterface[] */ - public function getChildren(); + public function getChildren(): array; - /** - * @return ElementInterface|null - */ - public function getNext(); + public function getNext(): ?ElementInterface; - /** - * @return int - */ - public function getSiblingPosition(); + public function getSiblingPosition(): int; - /** - * @return string - */ - public function getChildrenAsString(); + public function getChildrenAsString(): string; - /** - * @param string $markdown - */ - public function setFinalMarkdown($markdown); + public function setFinalMarkdown(string $markdown): void; - /** - * @param string $name - * - * @return string - */ - public function getAttribute($name); + public function getListItemLevel(): int; + + public function getAttribute(string $name): string; } diff --git a/vendor/league/html-to-markdown/src/Environment.php b/vendor/league/html-to-markdown/src/Environment.php index 560cfe613..7ea19d410 100644 --- a/vendor/league/html-to-markdown/src/Environment.php +++ b/vendor/league/html-to-markdown/src/Environment.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; use League\HTMLToMarkdown\Converter\BlockquoteConverter; @@ -22,34 +24,27 @@ use League\HTMLToMarkdown\Converter\TextConverter; final class Environment { - /** - * @var Configuration - */ + /** @var Configuration */ protected $config; + /** @var ConverterInterface[] */ + protected $converters = []; + /** - * @var ConverterInterface[] + * @param array<string, mixed> $config */ - protected $converters = array(); - - public function __construct(array $config = array()) + public function __construct(array $config = []) { $this->config = new Configuration($config); $this->addConverter(new DefaultConverter()); } - /** - * @return Configuration - */ - public function getConfig() + public function getConfig(): Configuration { return $this->config; } - /** - * @param ConverterInterface $converter - */ - public function addConverter(ConverterInterface $converter) + public function addConverter(ConverterInterface $converter): void { if ($converter instanceof ConfigurationAwareInterface) { $converter->setConfig($this->config); @@ -60,12 +55,7 @@ final class Environment } } - /** - * @param string $tag - * - * @return ConverterInterface - */ - public function getConverterByTag($tag) + public function getConverterByTag(string $tag): ConverterInterface { if (isset($this->converters[$tag])) { return $this->converters[$tag]; @@ -75,11 +65,9 @@ final class Environment } /** - * @param array $config - * - * @return Environment + * @param array<string, mixed> $config */ - public static function createDefaultEnvironment(array $config = array()) + public static function createDefaultEnvironment(array $config = []): Environment { $environment = new static($config); diff --git a/vendor/league/html-to-markdown/src/HtmlConverter.php b/vendor/league/html-to-markdown/src/HtmlConverter.php index 6f98e97b4..7162b256d 100644 --- a/vendor/league/html-to-markdown/src/HtmlConverter.php +++ b/vendor/league/html-to-markdown/src/HtmlConverter.php @@ -1,10 +1,10 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; /** - * Class HtmlConverter - * * A helper class to convert HTML to Markdown. * * @author Colin O'Dell <colinodell@gmail.com> @@ -16,25 +16,24 @@ namespace League\HTMLToMarkdown; */ class HtmlConverter implements HtmlConverterInterface { - /** - * @var Environment - */ + /** @var Environment */ protected $environment; /** * Constructor * - * @param Environment|array $options Environment object or configuration options + * @param Environment|array<string, mixed> $options Environment object or configuration options */ - public function __construct($options = array()) + public function __construct($options = []) { if ($options instanceof Environment) { $this->environment = $options; - } elseif (is_array($options)) { - $defaults = array( + } elseif (\is_array($options)) { + $defaults = [ 'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2 'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML 'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output. + 'strip_placeholder_links' => false, // Set to true to remove <a> that doesn't have href. 'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style 'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style 'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script' @@ -42,7 +41,9 @@ class HtmlConverter implements HtmlConverterInterface 'list_item_style' => '-', // Set the default character for each <li> in a <ul>. Can be '-', '*', or '+' 'preserve_comments' => false, // Set to true to preserve comments, or set to an array of strings to preserve specific comments 'use_autolinks' => true, // Set to true to use simple link syntax if possible. Will always use []() if set to false - ); + 'table_pipe_escape' => '\|', // Replacement string for pipe characters inside markdown table cells + 'table_caption_side' => 'top', // Set to 'top' or 'bottom' to show <caption> content before or after table, null to suppress + ]; $this->environment = Environment::createDefaultEnvironment($defaults); @@ -50,18 +51,12 @@ class HtmlConverter implements HtmlConverterInterface } } - /** - * @return Environment - */ - public function getEnvironment() + public function getEnvironment(): Environment { return $this->environment; } - /** - * @return Configuration - */ - public function getConfig() + public function getConfig(): Configuration { return $this->environment->getConfig(); } @@ -71,11 +66,9 @@ class HtmlConverter implements HtmlConverterInterface * * @see HtmlConverter::convert * - * @param string $html - * * @return string The Markdown version of the html */ - public function __invoke($html) + public function __invoke(string $html): string { return $this->convert($html); } @@ -85,22 +78,20 @@ class HtmlConverter implements HtmlConverterInterface * * Loads HTML and passes to getMarkdown() * - * @param string $html - * - * @throws \InvalidArgumentException - * * @return string The Markdown version of the html + * + * @throws \InvalidArgumentException|\RuntimeException */ - public function convert($html) + public function convert(string $html): string { - if (trim($html) === '') { + if (\trim($html) === '') { return ''; } $document = $this->createDOMDocument($html); // Work on the entire DOM tree (including head and body) - if (!($root = $document->getElementsByTagName('html')->item(0))) { + if (! ($root = $document->getElementsByTagName('html')->item(0))) { throw new \InvalidArgumentException('Invalid HTML was provided'); } @@ -110,52 +101,87 @@ class HtmlConverter implements HtmlConverterInterface // Store the now-modified DOMDocument as a string $markdown = $document->saveHTML(); + if ($markdown === false) { + throw new \RuntimeException('Unknown error occurred during HTML to Markdown conversion'); + } + return $this->sanitize($markdown); } - /** - * @param string $html - * - * @return \DOMDocument - */ - private function createDOMDocument($html) + private function createDOMDocument(string $html): \DOMDocument { $document = new \DOMDocument(); if ($this->getConfig()->getOption('suppress_errors')) { // Suppress conversion errors (from http://bit.ly/pCCRSX) - libxml_use_internal_errors(true); + \libxml_use_internal_errors(true); } // Hack to load utf-8 HTML (from http://bit.ly/pVDyCt) $document->loadHTML('<?xml encoding="UTF-8">' . $html); $document->encoding = 'UTF-8'; + $this->replaceMisplacedComments($document); + if ($this->getConfig()->getOption('suppress_errors')) { - libxml_clear_errors(); + \libxml_clear_errors(); } return $document; } /** + * Finds any comment nodes outside <html> element and moves them into <body>. + * + * @see https://github.com/thephpleague/html-to-markdown/issues/212 + * @see https://3v4l.org/7bC33 + */ + private function replaceMisplacedComments(\DOMDocument $document): void + { + // Find ny comment nodes at the root of the document. + $misplacedComments = (new \DOMXPath($document))->query('/comment()'); + if ($misplacedComments === false) { + return; + } + + $body = $document->getElementsByTagName('body')->item(0); + if ($body === null) { + return; + } + + // Loop over comment nodes in reverse so we put them inside <body> in + // their original order. + for ($index = $misplacedComments->length - 1; $index >= 0; $index--) { + if ($body->firstChild === null) { + $body->insertBefore($misplacedComments[$index]); + } else { + $body->insertBefore($misplacedComments[$index], $body->firstChild); + } + } + } + + /** * Convert Children * * Recursive function to drill into the DOM and convert each node into Markdown from the inside out. * * Finds children of each node and convert those to #text nodes containing their Markdown equivalent, * starting with the innermost element and working up to the outermost element. - * - * @param ElementInterface $element */ - private function convertChildren(ElementInterface $element) + private function convertChildren(ElementInterface $element): void { // Don't convert HTML code inside <code> and <pre> blocks to Markdown - that should stay as HTML // except if the current node is a code tag, which needs to be converted by the CodeConverter. - if ($element->isDescendantOf(array('pre', 'code')) && $element->getTagName() !== 'code') { + if ($element->isDescendantOf(['pre', 'code']) && $element->getTagName() !== 'code') { return; } + // Give converter a chance to inspect/modify the DOM before children are converted + $converter = $this->environment->getConverterByTag($element->getTagName()); + if ($converter instanceof PreConverterInterface) { + $converter->preConvert($element); + } + // If the node has children, convert those to Markdown first if ($element->hasChildren()) { foreach ($element->getChildren() as $child) { @@ -179,18 +205,16 @@ class HtmlConverter implements HtmlConverterInterface * * Example: An <h3> node with text content of 'Title' becomes a text node with content of '### Title' * - * @param ElementInterface $element - * * @return string The converted HTML as Markdown */ - protected function convertToMarkdown(ElementInterface $element) + protected function convertToMarkdown(ElementInterface $element): string { $tag = $element->getTagName(); // Strip nodes named in remove_nodes - $tags_to_remove = explode(' ', $this->getConfig()->getOption('remove_nodes')); - if (in_array($tag, $tags_to_remove)) { - return false; + $tagsToRemove = \explode(' ', $this->getConfig()->getOption('remove_nodes') ?? ''); + if (\in_array($tag, $tagsToRemove, true)) { + return ''; } $converter = $this->environment->getConverterByTag($tag); @@ -198,38 +222,34 @@ class HtmlConverter implements HtmlConverterInterface return $converter->convert($element); } - /** - * @param string $markdown - * - * @return string - */ - protected function sanitize($markdown) + protected function sanitize(string $markdown): string { - $markdown = html_entity_decode($markdown, ENT_QUOTES, 'UTF-8'); - $markdown = preg_replace('/<!DOCTYPE [^>]+>/', '', $markdown); // Strip doctype declaration - $markdown = trim($markdown); // Remove blank spaces at the beggining of the html + $markdown = \html_entity_decode($markdown, ENT_QUOTES, 'UTF-8'); + $markdown = \preg_replace('/<!DOCTYPE [^>]+>/', '', $markdown); // Strip doctype declaration + \assert($markdown !== null); + $markdown = \trim($markdown); // Remove blank spaces at the beggining of the html /* * Removing unwanted tags. Tags should be added to the array in the order they are expected. * XML, html and body opening tags should be in that order. Same case with closing tags */ - $unwanted = array('<?xml encoding="UTF-8">', '<html>', '</html>', '<body>', '</body>', '<head>', '</head>', '
'); + $unwanted = ['<?xml encoding="UTF-8">', '<html>', '</html>', '<body>', '</body>', '<head>', '</head>', '
']; foreach ($unwanted as $tag) { - if (strpos($tag, '/') === false) { + if (\strpos($tag, '/') === false) { // Opening tags - if (strpos($markdown, $tag) === 0) { - $markdown = substr($markdown, strlen($tag)); + if (\strpos($markdown, $tag) === 0) { + $markdown = \substr($markdown, \strlen($tag)); } } else { // Closing tags - if (strpos($markdown, $tag) === strlen($markdown) - strlen($tag)) { - $markdown = substr($markdown, 0, -strlen($tag)); + if (\strpos($markdown, $tag) === \strlen($markdown) - \strlen($tag)) { + $markdown = \substr($markdown, 0, -\strlen($tag)); } } } - return trim($markdown, "\n\r\0\x0B"); + return \trim($markdown, "\n\r\0\x0B"); } /** @@ -239,6 +259,10 @@ class HtmlConverter implements HtmlConverterInterface * An example being: * * HtmlConverter::setOptions(['strip_tags' => true])->convert('<h1>test</h1>'); + * + * @param array<string, mixed> $options + * + * @return $this */ public function setOptions(array $options) { diff --git a/vendor/league/html-to-markdown/src/HtmlConverterInterface.php b/vendor/league/html-to-markdown/src/HtmlConverterInterface.php index 7d43cf87e..5c7e9eb65 100644 --- a/vendor/league/html-to-markdown/src/HtmlConverterInterface.php +++ b/vendor/league/html-to-markdown/src/HtmlConverterInterface.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace League\HTMLToMarkdown; /** @@ -16,11 +18,9 @@ interface HtmlConverterInterface /** * Convert the given $html to Markdown * - * @param string $html + * @return string The Markdown version of the html * * @throws \InvalidArgumentException - * - * @return string The Markdown version of the html */ - public function convert($html); + public function convert(string $html): string; } diff --git a/vendor/league/html-to-markdown/src/PreConverterInterface.php b/vendor/league/html-to-markdown/src/PreConverterInterface.php new file mode 100644 index 000000000..f835086ef --- /dev/null +++ b/vendor/league/html-to-markdown/src/PreConverterInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace League\HTMLToMarkdown; + +interface PreConverterInterface +{ + public function preConvert(ElementInterface $element): void; +} |