diff --git a/composer.json b/composer.json index 0f07717..965783c 100644 --- a/composer.json +++ b/composer.json @@ -2,17 +2,17 @@ "name": "rareloop/primer-core", "require": { "php": ">=8.1", - "symfony/finder": "^6.4.17", - "twig/twig": "^3.20", + "symfony/finder": "^6.4.24", + "twig/twig": "^3.21.1", "illuminate/collections": "^8.53.1||^9.52.16", - "league/commonmark": "^1.6.7", + "league/commonmark": "^2.7.1", "spatie/yaml-front-matter": "^2.1" }, "require-dev": { - "phpunit/phpunit": "^9.6.22", - "php-coveralls/php-coveralls": "^2.7", + "phpunit/phpunit": "^9.6.23", + "php-coveralls/php-coveralls": "^2.8", "mockery/mockery": "^1.6.12", - "squizlabs/php_codesniffer": "^3.12.2", + "squizlabs/php_codesniffer": "^3.13.2", "mikey179/vfsstream": "^1.6.12", "antecedent/patchwork": "^2.2.1" }, diff --git a/src/DocumentParsers/Markdown/PrimerExtension.php b/src/DocumentParsers/Markdown/PrimerExtension.php index 413ac13..1b962b8 100644 --- a/src/DocumentParsers/Markdown/PrimerExtension.php +++ b/src/DocumentParsers/Markdown/PrimerExtension.php @@ -2,70 +2,140 @@ namespace Rareloop\Primer\DocumentParsers\Markdown; -use League\CommonMark\Block\Parser as BlockParser; +use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote; +use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode; +use League\CommonMark\Extension\CommonMark\Node\Block\Heading; +use League\CommonMark\Extension\CommonMark\Node\Block\HtmlBlock; +use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode; +use League\CommonMark\Extension\CommonMark\Node\Block\ListBlock; +use League\CommonMark\Extension\CommonMark\Node\Block\ListItem; +use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak; +use League\CommonMark\Extension\CommonMark\Node\Inline\Code; +use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis; +use League\CommonMark\Extension\CommonMark\Node\Inline\HtmlInline; +use League\CommonMark\Extension\CommonMark\Node\Inline\Image; +use League\CommonMark\Extension\CommonMark\Node\Inline\Link; +use League\CommonMark\Extension\CommonMark\Node\Inline\Strong; +use League\CommonMark\Extension\CommonMark\Parser\Block\BlockQuoteStartParser; +use League\CommonMark\Extension\CommonMark\Parser\Block\FencedCodeStartParser; +use League\CommonMark\Extension\CommonMark\Parser\Block\HeadingStartParser; +use League\CommonMark\Extension\CommonMark\Parser\Block\HtmlBlockStartParser; +use League\CommonMark\Extension\CommonMark\Parser\Block\ListBlockStartParser; +use League\CommonMark\Extension\CommonMark\Parser\Block\ThematicBreakStartParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\AutolinkParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\BacktickParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\BangParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\CloseBracketParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\EntityParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\EscapableParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\HtmlInlineParser; +use League\CommonMark\Extension\CommonMark\Parser\Inline\OpenBracketParser; +use League\CommonMark\Extension\CommonMark\Renderer\Block\BlockQuoteRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\FencedCodeRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\HeadingRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\HtmlBlockRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\IndentedCodeRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\ListBlockRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\ListItemRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Block\ThematicBreakRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Inline\CodeRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Inline\EmphasisRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Inline\HtmlInlineRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Inline\ImageRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Inline\LinkRenderer; +use League\CommonMark\Extension\CommonMark\Renderer\Inline\StrongRenderer; use League\CommonMark\Extension\ExtensionInterface; -use League\CommonMark\Block\Element as BlockElement; -use League\CommonMark\Inline\Parser as InlineParser; -use League\CommonMark\Block\Renderer as BlockRenderer; -use League\CommonMark\Inline\Element as InlineElement; -use League\CommonMark\ConfigurableEnvironmentInterface; -use League\CommonMark\Inline\Renderer as InlineRenderer; -use League\CommonMark\Delimiter\Processor\EmphasisDelimiterProcessor; +use League\CommonMark\Environment\EnvironmentBuilderInterface; +use League\CommonMark\Extension\CommonMark\Delimiter\Processor\EmphasisDelimiterProcessor; +use League\CommonMark\Extension\ConfigurableExtensionInterface; +use League\CommonMark\Node\Block\Document; +use League\CommonMark\Node\Block\Paragraph; +use League\CommonMark\Node\Inline\Newline; +use League\CommonMark\Node\Inline\Text; +use League\CommonMark\Parser\Inline\NewlineParser; +use League\CommonMark\Renderer\Block\DocumentRenderer; +use League\CommonMark\Renderer\Block\ParagraphRenderer; +use League\CommonMark\Renderer\Inline\NewlineRenderer; +use League\CommonMark\Renderer\Inline\TextRenderer; +use League\Config\ConfigurationBuilderInterface; +use Nette\Schema\Expect; /** * Primer flavoured Markdown setup. It is the same as the CommonMarkCoreExtension but with the - * `IndentedCodeParser` removed to allow for embedded Twig code in Markdown to be interpretted + * `IndentedCodeStartParser` removed to allow for embedded Twig code in Markdown to be interpretted * rather than code blocked. */ -class PrimerExtension implements ExtensionInterface +class PrimerExtension implements ConfigurableExtensionInterface { - public function register(ConfigurableEnvironmentInterface $environment) + public function configureSchema(ConfigurationBuilderInterface $builder): void + { + $builder->addSchema( + 'commonmark', + Expect::structure( + [ + 'use_asterisk' => Expect::bool(true), + 'use_underscore' => Expect::bool(true), + 'enable_strong' => Expect::bool(true), + 'enable_em' => Expect::bool(true), + 'unordered_list_markers' => Expect::listOf('string') + ->min(1) + ->default([ + '*', + '+', + '-' + ])->mergeDefaults(false), + ] + ) + ); + } + + public function register(EnvironmentBuilderInterface $environment): void { $environment - ->addBlockParser(new BlockParser\BlockQuoteParser(), 70) - ->addBlockParser(new BlockParser\ATXHeadingParser(), 60) - ->addBlockParser(new BlockParser\FencedCodeParser(), 50) - ->addBlockParser(new BlockParser\HtmlBlockParser(), 40) - ->addBlockParser(new BlockParser\SetExtHeadingParser(), 30) - ->addBlockParser(new BlockParser\ThematicBreakParser(), 20) - ->addBlockParser(new BlockParser\ListParser(), 10) - ->addBlockParser(new BlockParser\LazyParagraphParser(), -200) + ->addBlockStartParser(new BlockQuoteStartParser(), 70) + ->addBlockStartParser(new HeadingStartParser(), 60) + ->addBlockStartParser(new FencedCodeStartParser(), 50) + ->addBlockStartParser(new HtmlBlockStartParser(), 40) + ->addBlockStartParser(new ThematicBreakStartParser(), 20) + ->addBlockStartParser(new ListBlockStartParser(), 10) + // ->addBlockStartParser(new IndentedCodeStartParser(), -100) + + ->addInlineParser(new NewlineParser(), 200) + ->addInlineParser(new BacktickParser(), 150) + ->addInlineParser(new EscapableParser(), 80) + ->addInlineParser(new EntityParser(), 70) + ->addInlineParser(new AutolinkParser(), 50) + ->addInlineParser(new HtmlInlineParser(), 40) + ->addInlineParser(new CloseBracketParser(), 30) + ->addInlineParser(new OpenBracketParser(), 20) + ->addInlineParser(new BangParser(), 10) - ->addInlineParser(new InlineParser\NewlineParser(), 200) - ->addInlineParser(new InlineParser\BacktickParser(), 150) - ->addInlineParser(new InlineParser\EscapableParser(), 80) - ->addInlineParser(new InlineParser\EntityParser(), 70) - ->addInlineParser(new InlineParser\AutolinkParser(), 50) - ->addInlineParser(new InlineParser\HtmlInlineParser(), 40) - ->addInlineParser(new InlineParser\CloseBracketParser(), 30) - ->addInlineParser(new InlineParser\OpenBracketParser(), 20) - ->addInlineParser(new InlineParser\BangParser(), 10) + ->addRenderer(BlockQuote::class, new BlockQuoteRenderer(), 0) + ->addRenderer(Document::class, new DocumentRenderer(), 0) + ->addRenderer(FencedCode::class, new FencedCodeRenderer(), 0) + ->addRenderer(Heading::class, new HeadingRenderer(), 0) + ->addRenderer(HtmlBlock::class, new HtmlBlockRenderer(), 0) + ->addRenderer(IndentedCode::class, new IndentedCodeRenderer(), 0) + ->addRenderer(ListBlock::class, new ListBlockRenderer(), 0) + ->addRenderer(ListItem::class, new ListItemRenderer(), 0) + ->addRenderer(Paragraph::class, new ParagraphRenderer(), 0) + ->addRenderer(ThematicBreak::class, new ThematicBreakRenderer(), 0) - ->addBlockRenderer(BlockElement\BlockQuote::class, new BlockRenderer\BlockQuoteRenderer(), 0) - ->addBlockRenderer(BlockElement\Document::class, new BlockRenderer\DocumentRenderer(), 0) - ->addBlockRenderer(BlockElement\FencedCode::class, new BlockRenderer\FencedCodeRenderer(), 0) - ->addBlockRenderer(BlockElement\Heading::class, new BlockRenderer\HeadingRenderer(), 0) - ->addBlockRenderer(BlockElement\HtmlBlock::class, new BlockRenderer\HtmlBlockRenderer(), 0) - ->addBlockRenderer(BlockElement\IndentedCode::class, new BlockRenderer\IndentedCodeRenderer(), 0) - ->addBlockRenderer(BlockElement\ListBlock::class, new BlockRenderer\ListBlockRenderer(), 0) - ->addBlockRenderer(BlockElement\ListItem::class, new BlockRenderer\ListItemRenderer(), 0) - ->addBlockRenderer(BlockElement\Paragraph::class, new BlockRenderer\ParagraphRenderer(), 0) - ->addBlockRenderer(BlockElement\ThematicBreak::class, new BlockRenderer\ThematicBreakRenderer(), 0) + ->addRenderer(Code::class, new CodeRenderer(), 0) + ->addRenderer(Emphasis::class, new EmphasisRenderer(), 0) + ->addRenderer(HtmlInline::class, new HtmlInlineRenderer(), 0) + ->addRenderer(Image::class, new ImageRenderer(), 0) + ->addRenderer(Link::class, new LinkRenderer(), 0) + ->addRenderer(Newline::class, new NewlineRenderer(), 0) + ->addRenderer(Strong::class, new StrongRenderer(), 0) + ->addRenderer(Text::class, new TextRenderer(), 0); - ->addInlineRenderer(InlineElement\Code::class, new InlineRenderer\CodeRenderer(), 0) - ->addInlineRenderer(InlineElement\Emphasis::class, new InlineRenderer\EmphasisRenderer(), 0) - ->addInlineRenderer(InlineElement\HtmlInline::class, new InlineRenderer\HtmlInlineRenderer(), 0) - ->addInlineRenderer(InlineElement\Image::class, new InlineRenderer\ImageRenderer(), 0) - ->addInlineRenderer(InlineElement\Link::class, new InlineRenderer\LinkRenderer(), 0) - ->addInlineRenderer(InlineElement\Newline::class, new InlineRenderer\NewlineRenderer(), 0) - ->addInlineRenderer(InlineElement\Strong::class, new InlineRenderer\StrongRenderer(), 0) - ->addInlineRenderer(InlineElement\Text::class, new InlineRenderer\TextRenderer(), 0); - if ($environment->getConfig('use_asterisk', true)) { + if ($environment->getConfiguration()->get('commonmark/use_asterisk')) { $environment->addDelimiterProcessor(new EmphasisDelimiterProcessor('*')); } - if ($environment->getConfig('use_underscore', true)) { + if ($environment->getConfiguration()->get('commonmark/use_underscore')) { $environment->addDelimiterProcessor(new EmphasisDelimiterProcessor('_')); } } diff --git a/src/DocumentParsers/MarkdownDocumentParser.php b/src/DocumentParsers/MarkdownDocumentParser.php index 0249f3b..de016c0 100644 --- a/src/DocumentParsers/MarkdownDocumentParser.php +++ b/src/DocumentParsers/MarkdownDocumentParser.php @@ -3,7 +3,10 @@ namespace Rareloop\Primer\DocumentParsers; use League\CommonMark\CommonMarkConverter; -use League\CommonMark\Environment; +use League\CommonMark\Environment\Environment; +use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; +use League\CommonMark\MarkdownConverter; +use League\CommonMark\Util\HtmlFilter; use Rareloop\Primer\DocumentParsers\Markdown\PrimerExtension; use Rareloop\Primer\Contracts\DocumentParser; use Rareloop\Primer\Document; @@ -12,27 +15,28 @@ class MarkdownDocumentParser implements DocumentParser { public function parse(Document $document): Document { - $converter = new CommonMarkConverter([], $this->createEnvironment()); - $document->setContent($converter->convertToHtml($document->content())); + $converter = new MarkdownConverter($this->createEnvironment()); + + $document->setContent( + $converter->convert($document->content()) + ); return $document; } protected function createEnvironment(): Environment { - $environment = new Environment(); - $environment->addExtension(new PrimerExtension()); - $environment->mergeConfig([ + $environment = new Environment([ 'renderer' => [ 'block_separator' => "\n", 'inner_separator' => "\n", 'soft_break' => "\n", ], - 'safe' => false, // deprecated option - 'html_input' => Environment::HTML_INPUT_ALLOW, + 'html_input' => HtmlFilter::ALLOW, 'allow_unsafe_links' => true, - 'max_nesting_level' => INF, + 'max_nesting_level' => PHP_INT_MAX, ]); + $environment->addExtension(new PrimerExtension()); return $environment; }