Skip to content

Commit

Permalink
Use league/commonmark Markdown renderer (#163)
Browse files Browse the repository at this point in the history
Closes #155
  • Loading branch information
samwilson committed Mar 22, 2022
1 parent 06be605 commit 0b33a60
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 49 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7",
"endroid/qr-code": "^4.2",
"league/commonmark": "^1.6",
"league/flysystem-aws-s3-v3": "^1.0",
"samwilson/phpflickr": "^4.14",
"sensio/framework-extra-bundle": "^5.6",
Expand Down
95 changes: 94 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 17 additions & 38 deletions src/Markdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,34 @@

namespace App;

use League\CommonMark\Environment;
use League\CommonMark\Extension\CommonMarkCoreExtension;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;

/**
* This class formats *some parts* of Markdown, or rather CommonMark. It doesn't support everything (notably not HTML),
* and also adds a few extra things that are good only for this application.
*
* @link https://commonmark.org/help/
* Wrapper for rendering Markdown with the league/commonmark package.
*/
class Markdown
{

/**
* Convert Twyne-flavoured Markdown to HTML.
* Convert Markdown to HTML.
*
* @param string $in The Markdown source.
* @return string The (safe) HTML.
*/
public function toHtml(string $in): string
{
// Platform-independent newlines.
$out = preg_replace("/(\r\n|\r)/", "\n", trim($in));
// Prevent HTML.
$out = str_replace(['&', '<', '"', "'"], ['&amp;', '&lt;', '&quot;', '&#039;'], $out);
$out = preg_replace("|([^\n])>|", "$1&gt;", $out);
// Links.
$out = preg_replace("|(https?://\S+)|", "<a href=\"$1\">$1</a>", $out);
// Paragraphs.
$out = "<p>$out</p>";
$out = preg_replace("|\n+\s*\n+|", "</p>\n\n<p>", $out);
// Remove paragraphs if they contain nothing (including only whitespace).
$out = preg_replace('|<p>\s*</p>|', '', $out);
// Blockquotes
$out = preg_replace('|<p>>\s*(.*)|', "<blockquote>\n> $1", $out);
$out = preg_replace('|\n>\s*(.*)</p>|', "\n$1\n</blockquote>", $out);
$out = preg_replace('|\n>\s(.*)|', "\n$1", $out);
// Separator.
$out = preg_replace("|<p>[-*]{3}</p>|", "<hr />", $out);
// Lists.
$out = preg_replace("|<p>\d\.(.*)|", "<ol>\n#$1", $out); // begin ordered
$out = preg_replace("|\n\d\.(.*)</p>|", "\n#$1\n</ol>", $out); // end ordered
$out = preg_replace("|<p>\*(.*)|", "<ul>\n*$1", $out); // begin unordered
$out = preg_replace("|\n\*(.*)</p>|", "\n*$1\n</ul>", $out); // end unordered
$out = preg_replace("|\n[*#]\s*(.*)|", "\n<li>$1</li>", $out); // list items
// Headings.
$out = preg_replace("|<p>#{4}\s*(.*)</p>|", "\n<h4>$1</h4>\n", $out);
$out = preg_replace("|<p>#{1,3}\s*(.*)</p>|", "\n<h3>$1</h3>\n", $out);
// Emphasis.
$out = preg_replace("|\*(.*?)\*|", "<em>$1</em>", $out);
// Monospacing.
$out = preg_replace("|`(.*?)`|", "<code>$1</code>", $out);

return trim($out);
$environment = new Environment([
'html_input' => 'escape',
'allow_unsafe_links' => true,
]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$converter = new MarkdownConverter($environment);
return trim($converter->convertToHtml($in));
}
}
9 changes: 9 additions & 0 deletions symfony.lock
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@
"laminas/laminas-zendframework-bridge": {
"version": "1.3.0"
},
"league/commonmark": {
"version": "0.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "0.0",
"ref": ""
}
},
"league/flysystem": {
"version": "1.1.4"
},
Expand Down
20 changes: 10 additions & 10 deletions tests/MarkdownTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,29 @@ public function provideToHtml()
// Paragraphs.
['foo', '<p>foo</p>'],
["foo\nbar", "<p>foo\nbar</p>"],
["foo\n\nbar", "<p>foo</p>\n\n<p>bar</p>"],
["foo\n\nbar", "<p>foo</p>\n<p>bar</p>"],
// Lists.
["auf\n\n* *emph* word\n* bar", "<p>auf</p>\n\n<ul>\n<li><em>emph</em> word</li>\n<li>bar</li>\n</ul>"],
["auf\n\n* *emph* word\n* bar", "<p>auf</p>\n<ul>\n<li>\n<em>emph</em> word</li>\n<li>bar</li>\n</ul>"],
["1. foo\n2. bar\n", "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>"],
["1. foo\n2. bar\n\nbaz", "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>\n\n<p>baz</p>"],
["1. foo\n2. bar\n\nbaz", "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>\n<p>baz</p>"],
['Not a list 10.20 just numbers.', '<p>Not a list 10.20 just numbers.</p>'],
// Emphasis and code.
['the *foo* `bar` baz', '<p>the <em>foo</em> <code>bar</code> baz</p>'],
// Blockquotes.
["foo\n\n> bar\n> baz\n>last", "<p>foo</p>\n\n<blockquote>\nbar\nbaz\nlast\n</blockquote>"],
["> foo\n\nbar", "<blockquote>\nfoo\n</blockquote>\n\n<p>bar</p>"],
["foo\n\n> bar\n> baz\n>last", "<p>foo</p>\n<blockquote>\n<p>bar\nbaz\nlast</p>\n</blockquote>"],
["> foo\n\nbar", "<blockquote>\n<p>foo</p>\n</blockquote>\n<p>bar</p>"],
// Separator.
["foo\n\n---\n\nbar", "<p>foo</p>\n\n<hr />\n\n<p>bar</p>"],
["foo\n\n---\n\nbar", "<p>foo</p>\n<hr />\n<p>bar</p>"],
// Header.
["# Foo", "<h3>Foo</h3>"],
["##Foo", "<h3>Foo</h3>"],
["###Foo", "<h3>Foo</h3>"],
["# Foo", "<h1>Foo</h1>"],
["## Foo", "<h2>Foo</h2>"],
["### Foo", "<h3>Foo</h3>"],
["#### Foo", "<h4>Foo</h4>"],
// Links.
['foo https://example.org bar', '<p>foo <a href="https://example.org">https://example.org</a> bar</p>'],
['https://x.net/foo_bar', '<p><a href="https://x.net/foo_bar">https://x.net/foo_bar</a></p>'],
// No HTML.
['<p>T & <stuff x="y"></p>', '<p>&lt;p&gt;T &amp; &lt;stuff x=&quot;y&quot;&gt;&lt;/p&gt;</p>']
['a <p>T & <stuff x="y"></p>', '<p>a &lt;p&gt;T &amp; &lt;stuff x="y"&gt;&lt;/p&gt;</p>']
];
}
}

0 comments on commit 0b33a60

Please sign in to comment.