Snips/src/Service/SnipParser/Markdown/MarkdownParser.php
2025-05-27 21:12:56 +02:00

81 lines
2.7 KiB
PHP

<?php
namespace App\Service\SnipParser\Markdown;
use App\Repository\SnipRepository;
use App\Service\SnipParser\AbstractParser;
use League\CommonMark\Event\DocumentParsedEvent;
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
use League\CommonMark\Extension\Footnote\FootnoteExtension;
use League\CommonMark\Extension\Table\Table;
use League\CommonMark\GithubFlavoredMarkdownConverter;
use League\CommonMark\Node\Inline\Text;
use League\CommonMark\Node\Query;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Routing\RouterInterface;
use Tempest\Highlight\CommonMark\HighlightExtension;
use Tempest\Highlight\Highlighter;
class MarkdownParser extends AbstractParser
{
public function __construct(
#[Autowire(lazy: true)] private readonly RouterInterface $router,
#[Autowire(lazy: true)] private readonly SnipRepository $snipRepo,
) {}
public function safeParseView(string $content): string
{
$config = [
'default_attributes' => [
Table::class => [
'class' => 'table table-hover',
],
Link::class => [
'class' => 'btn btn-sm btn-secondary',
],
],
];
$converter = new GithubFlavoredMarkdownConverter($config);
$converter
->getEnvironment()
->addExtension(new HighlightExtension(new Highlighter()->withGutter()))
->addExtension(new FootnoteExtension())
->addExtension(new DefaultAttributesExtension())
->addEventListener(DocumentParsedEvent::class, $this->documentParsed(...))
;
return $converter->convert($content);
}
private function documentParsed(DocumentParsedEvent $event): void
{
$document = $event->getDocument();
$linkNodes = new Query()
->where(Query::type(Link::class))
->findAll($document)
;
/** @var Link $linkNode */
foreach ($linkNodes as $linkNode) {
$url = $linkNode->getUrl();
if (!is_numeric($url)) {
continue;
}
$snip = $this->snipRepo->find($url);
if ($snip === null) {
continue;
}
$linkNode->setUrl($this->router->generate('snip_single', [
'snip' => $url,
]));
$textNode = $linkNode->firstChild();
if (!$textNode) {
$linkNode->appendChild(new Text($snip));
}
}
}
}