Add support for tempest/markdown in markdown-extra

This commit is contained in:
Romain Monteil
2026-08-12 13:01:10 +02:00
parent 6fafa104c4
commit aa17f59877
8 changed files with 68 additions and 16 deletions
+5
View File
@@ -151,6 +151,11 @@ jobs:
working-directory: extra/${{ matrix.extension }}
run: "composer require --no-update 'symfony/translation-contracts:^1.1|^2.0'"
- name: "Prevent installing tempest/markdown, which requires PHP 8.5"
if: "matrix.extension == 'markdown-extra' && matrix.php-version != '8.5'"
working-directory: extra/${{ matrix.extension }}
run: composer remove --dev --no-update tempest/markdown
- name: "Composer install ${{ matrix.extension }}"
working-directory: extra/${{ matrix.extension }}
run: composer install
+1
View File
@@ -3,4 +3,5 @@
/composer.lock
/phpunit.xml
/vendor
.php-cs-fixer.cache
.phpunit.result.cache
+1
View File
@@ -1,5 +1,6 @@
# 3.29.0 (2026-XX-XX)
* Add `TempestMarkdown` to use `tempest/markdown` as the `markdown_to_html` converter
* Fix imported macros not resolving their own template-level macro imports
* Add the `Twig\Sandbox\SandboxInterface` interface and `Twig\Sandbox\Sandbox` class to render untrusted templates through a dedicated, always-sandboxed environment crafted for it
* Add the `Twig\Extension\SandboxBridgeExtension` to render sandboxed templates from trusted templates with an explicit output escaping strategy
+13 -4
View File
@@ -84,10 +84,11 @@ Using a Custom Converter
The ``markdown_to_html`` filter delegates the conversion to a class implementing
``Twig\Extra\Markdown\MarkdownInterface``. Several implementations are provided:
``LeagueMarkdown`` (``league/commonmark``), ``MichelfMarkdown``
(``michelf/php-markdown``), and ``ErusevMarkdown`` (``erusev/parsedown``). Each
accepts a pre-configured converter in its constructor, so you can tune the
underlying library or switch to another implementation (for instance
``ParsedownExtra``, which extends ``Parsedown``)::
(``michelf/php-markdown``), ``ErusevMarkdown`` (``erusev/parsedown``), and
``TempestMarkdown`` (``tempest/markdown``). Each accepts a pre-configured
converter in its constructor, so you can tune the underlying library or switch
to another implementation (for instance ``ParsedownExtra``, which extends
``Parsedown``)::
use Twig\Extra\Markdown\ErusevMarkdown;
@@ -96,6 +97,14 @@ underlying library or switch to another implementation (for instance
$markdown = new ErusevMarkdown($parsedown);
.. note::
``tempest/markdown`` requires PHP 8.5 or later. It also differs from the
other libraries on two points worth knowing about: Setext headings
(``Title`` underlined with ``===``) are not supported, so use ATX headings
(``# Title``) instead, and any YAML front matter is parsed out of the
rendered HTML rather than being rendered.
When using ``twig/extra-bundle``, register your converter as the
``twig.markdown.default`` service to make it the one used by the filter:
+3
View File
@@ -13,6 +13,7 @@ namespace Twig\Extra\Markdown;
use League\CommonMark\CommonMarkConverter;
use Michelf\MarkdownExtra;
use Tempest\Markdown\Markdown;
class DefaultMarkdown implements MarkdownInterface
{
@@ -26,6 +27,8 @@ class DefaultMarkdown implements MarkdownInterface
$this->converter = new MichelfMarkdown();
} elseif (class_exists(\Parsedown::class)) {
$this->converter = new ErusevMarkdown();
} elseif (class_exists(Markdown::class)) {
$this->converter = new TempestMarkdown();
} else {
throw new \LogicException('You cannot use the "markdown_to_html" filter as no Markdown library is available; try running "composer require league/commonmark".');
}
+29
View File
@@ -0,0 +1,29 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extra\Markdown;
use Tempest\Markdown\Markdown;
class TempestMarkdown implements MarkdownInterface
{
private $converter;
public function __construct(?Markdown $converter = null)
{
$this->converter = $converter ?: new Markdown();
}
public function convert(string $body): string
{
return $this->converter->parse($body)->html;
}
}
+14 -11
View File
@@ -20,6 +20,7 @@ use Twig\Extra\Markdown\MarkdownExtension;
use Twig\Extra\Markdown\MarkdownInterface;
use Twig\Extra\Markdown\MarkdownRuntime;
use Twig\Extra\Markdown\MichelfMarkdown;
use Twig\Extra\Markdown\TempestMarkdown;
use Twig\Loader\ArrayLoader;
use Twig\RuntimeLoader\RuntimeLoaderInterface;
@@ -30,12 +31,16 @@ class FunctionalTest extends TestCase
*/
public function testMarkdown(string $template, string $expected): void
{
foreach ([LeagueMarkdown::class, ErusevMarkdown::class, /* MichelfMarkdown::class, */ DefaultMarkdown::class] as $class) {
$classes = [LeagueMarkdown::class, ErusevMarkdown::class, /* MichelfMarkdown::class, */ DefaultMarkdown::class];
if (class_exists(\Tempest\Markdown\Markdown::class)) {
$classes[] = TempestMarkdown::class;
}
foreach ($classes as $class) {
$twig = new Environment(new ArrayLoader([
'index' => $template,
'html' => <<<EOF
Hello
=====
# Hello
Great!
EOF,
@@ -63,21 +68,19 @@ EOF,
return [
[<<<EOF
{% apply markdown_to_html %}
Hello
=====
# Hello
Great!
{% endapply %}
EOF, "<h1>Hello</h1>\n+<p>Great!</p>"],
EOF, "<h1[^>]*>Hello</h1>\n+<p>Great!\s*</p>"],
[<<<EOF
{% apply markdown_to_html %}
Hello
=====
# Hello
Great!
{% endapply %}
EOF, "<h1>Hello</h1>\n+<p>Great!</p>"],
["{{ include('html')|markdown_to_html }}", "<h1>Hello</h1>\n+<p>Great!</p>"],
EOF, "<h1[^>]*>Hello</h1>\n+<p>Great!\s*</p>"],
["{{ include('html')|markdown_to_html }}", "<h1[^>]*>Hello</h1>\n+<p>Great!\s*</p>"],
[<<<EOF
{% apply markdown_to_html %}
@@ -85,7 +88,7 @@ Paragraph 1
Paragraph 2
{% endapply %}
EOF, "<p>Paragraph 1</p>\n+<p>Paragraph 2</p>"],
EOF, "<p>Paragraph 1</p>\n+<p>Paragraph 2\s*</p>"],
];
}
+2 -1
View File
@@ -24,7 +24,8 @@
"erusev/parsedown": "dev-master as 1.x-dev",
"league/commonmark": "^2.7",
"league/html-to-markdown": "^4.8|^5.0",
"michelf/php-markdown": "^1.8|^2.0"
"michelf/php-markdown": "^1.8|^2.0",
"tempest/markdown": "^1.2"
},
"autoload": {
"files": [ "Resources/functions.php" ],