2024-04-20 23:27:47 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Services\Markdown;
|
|
|
|
|
2024-04-24 11:39:23 +02:00
|
|
|
use App\Classes\Bundle;
|
2024-04-20 23:27:47 +02:00
|
|
|
use Illuminate\Support\Facades\Blade;
|
|
|
|
use League\CommonMark\Environment\Environment;
|
|
|
|
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
|
|
|
use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
|
|
|
|
use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
|
|
|
|
use League\CommonMark\Extension\Footnote\FootnoteExtension;
|
|
|
|
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
|
|
|
|
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
|
|
|
|
use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
|
|
|
|
use League\CommonMark\Extension\Table\TableExtension;
|
|
|
|
use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
|
|
|
|
use League\CommonMark\Extension\TaskList\TaskListExtension;
|
|
|
|
use League\CommonMark\MarkdownConverter;
|
|
|
|
use Spatie\CommonMarkShikiHighlighter\HighlightCodeExtension;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats markdown content using a variety of CommonMark extensions
|
|
|
|
* and custom renderers, also incorporating Blade template rendering.
|
|
|
|
*/
|
|
|
|
class Formatter
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
|
|
|
* @param string $source The markdown source content.
|
|
|
|
*/
|
2024-04-24 11:39:23 +02:00
|
|
|
public function __construct(protected string $source, protected ?Bundle $bundle = null)
|
2024-04-20 23:27:47 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Renders the markdown content with all enabled extensions and custom processing.
|
|
|
|
*
|
|
|
|
* @return string The rendered HTML content.
|
|
|
|
*/
|
|
|
|
public function render(): string
|
|
|
|
{
|
2024-04-22 21:51:50 +02:00
|
|
|
if (empty($this->source)) {
|
|
|
|
return $this->source;
|
|
|
|
}
|
|
|
|
|
2024-04-20 23:27:47 +02:00
|
|
|
// First, process the source with Blade to handle any dynamic content
|
|
|
|
$result = Blade::render($this->source);
|
|
|
|
|
|
|
|
// Convert markdown to HTML using the configured environment and extensions
|
|
|
|
$converter = new MarkdownConverter($this->prepareEnvironment());
|
|
|
|
$converted = $converter->convert($result);
|
|
|
|
|
|
|
|
// Perform final adjustments like inserting non-breaking spaces
|
|
|
|
$result = $this->insertNonBreakingSpaces($converted->getContent());
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepares the markdown parser environment with extensions and custom renderers.
|
|
|
|
*
|
|
|
|
* @return Environment The configured markdown environment.
|
|
|
|
*/
|
|
|
|
protected function prepareEnvironment(): Environment
|
|
|
|
{
|
|
|
|
// Load markdown configuration and initialize the environment
|
|
|
|
$environment = new Environment(config('markdown'));
|
|
|
|
|
|
|
|
// Define all the extensions to be used
|
|
|
|
$extensions = [
|
|
|
|
new CommonMarkCoreExtension(),
|
2024-04-25 01:37:28 +02:00
|
|
|
new HighlightCodeExtension(theme: 'tokyo-night'),
|
2024-04-20 23:27:47 +02:00
|
|
|
new FrontMatterExtension(),
|
|
|
|
new FootnoteExtension(),
|
|
|
|
new ExternalLinkExtension(),
|
|
|
|
new HeadingPermalinkExtension(),
|
|
|
|
new StrikethroughExtension(),
|
|
|
|
new TableExtension(),
|
|
|
|
new TableOfContentsExtension(),
|
|
|
|
new DisallowedRawHtmlExtension(),
|
|
|
|
new TaskListExtension(),
|
|
|
|
];
|
|
|
|
|
|
|
|
// Add each extension to the environment
|
|
|
|
foreach ($extensions as $extension) {
|
|
|
|
$environment->addExtension($extension);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $environment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inserts non-breaking spaces before certain punctuation marks in French typography.
|
|
|
|
*
|
|
|
|
* @param string $html The HTML content to process.
|
|
|
|
* @return string The processed HTML content with non-breaking spaces added.
|
|
|
|
*/
|
|
|
|
protected function insertNonBreakingSpaces(string $html): string
|
|
|
|
{
|
|
|
|
// Define patterns for spaces that should be replaced with non-breaking spaces
|
|
|
|
$patterns = [
|
|
|
|
'/ (\;)/',
|
|
|
|
'/ (\:)/',
|
|
|
|
'/ (\!)/',
|
|
|
|
'/ (\?)/',
|
|
|
|
];
|
|
|
|
|
|
|
|
// Corresponding replacements for each pattern
|
|
|
|
$replacements = array_fill(0, count($patterns), ' $1');
|
|
|
|
|
|
|
|
// Perform the replacements and return the modified HTML
|
|
|
|
return preg_replace($patterns, $replacements, $html);
|
|
|
|
}
|
|
|
|
}
|