diff --git a/composer.json b/composer.json
index 2287a44..17488fe 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,7 @@
"cache/void-adapter": "^1.1",
"jakeasmith/http_build_url": "^1",
"jbbcode/jbbcode": "^1.4",
+ "league/commonmark": "^2.0",
"youthweb/urllinker": "^1.4"
},
"require-dev": {
diff --git a/src/Extension/BBCode/BBCodeExtension.php b/src/Extension/BBCode/BBCodeExtension.php
new file mode 100644
index 0000000..91e5e86
--- /dev/null
+++ b/src/Extension/BBCode/BBCodeExtension.php
@@ -0,0 +1,51 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Extension\BBCode;
+
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Node as CoreNode;
+use League\CommonMark\Parser as CoreParser;
+use League\CommonMark\Renderer as CoreRenderer;
+use Youthweb\BBCodeParser\Extension\BBCode\Delimiter\Processor\EmphasisDelimiterProcessor;
+
+/**
+ * BBCodeExtension
+ */
+final class BBCodeExtension implements ExtensionInterface
+{
+ public function register(EnvironmentBuilderInterface $environment): void
+ {
+ $environment
+ ->addBlockStartParser(new Parser\Block\BoldBlockStartParser(), 40)
+
+ ->addInlineParser(new CoreParser\Inline\NewlineParser(), 200)
+
+ ->addRenderer(CoreNode\Block\Document::class, new CoreRenderer\Block\DocumentRenderer(), 0)
+ ->addRenderer(Node\Block\BoldBlock::class, new Renderer\Block\BoldBlockRenderer(), 0)
+ ->addRenderer(CoreNode\Block\Paragraph::class, new CoreRenderer\Block\ParagraphRenderer(), 0)
+
+ ->addRenderer(CoreNode\Inline\Text::class, new CoreRenderer\Inline\TextRenderer(), 0)
+ ;
+ }
+}
diff --git a/src/Extension/BBCode/Node/Block/BoldBlock.php b/src/Extension/BBCode/Node/Block/BoldBlock.php
new file mode 100644
index 0000000..69715eb
--- /dev/null
+++ b/src/Extension/BBCode/Node/Block/BoldBlock.php
@@ -0,0 +1,42 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Extension\BBCode\Node\Block;
+
+use League\CommonMark\Node\Block\AbstractBlock;
+use League\CommonMark\Node\RawMarkupContainerInterface;
+use League\CommonMark\Node\StringContainerInterface;
+
+final class BoldBlock extends AbstractBlock implements RawMarkupContainerInterface, StringContainerInterface
+{
+ private string $literal = '';
+
+ public function getLiteral(): string
+ {
+ return $this->literal;
+ }
+
+ public function setLiteral(string $literal): void
+ {
+ $this->literal = $literal;
+ }
+}
diff --git a/src/Extension/BBCode/Parser/Block/BoldBlockParser.php b/src/Extension/BBCode/Parser/Block/BoldBlockParser.php
new file mode 100644
index 0000000..3711b75
--- /dev/null
+++ b/src/Extension/BBCode/Parser/Block/BoldBlockParser.php
@@ -0,0 +1,93 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Extension\BBCode\Parser\Block;
+
+use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockContinue;
+use League\CommonMark\Parser\Block\BlockContinueParserInterface;
+use League\CommonMark\Parser\Block\BlockContinueParserWithInlinesInterface;
+use League\CommonMark\Parser\Cursor;
+use League\CommonMark\Parser\InlineParserEngineInterface;
+use League\CommonMark\Util\RegexHelper;
+use Youthweb\BBCodeParser\Extension\BBCode\Node\Block\BoldBlock;
+
+final class BoldBlockParser extends AbstractBlockContinueParser implements BlockContinueParserWithInlinesInterface
+{
+ private BoldBlock $block;
+
+ private string $content = '';
+
+ private bool $finished = false;
+
+ public function __construct()
+ {
+ $this->block = new BoldBlock();
+ }
+
+ public function getBlock(): BoldBlock
+ {
+ return $this->block;
+ }
+
+ public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue
+ {
+ if ($cursor->getNextNonSpaceCharacter() !== '[') {
+ return BlockContinue::at($cursor);
+ }
+
+ $tmpCursor = clone $cursor;
+ $tmpCursor->advanceToNextNonSpaceOrTab();
+ $line = $tmpCursor->getSubstring(0, 4);
+
+ if ($line === '[/b]') {
+ return BlockStart::none();
+ }
+
+ return BlockContinue::at($cursor);
+ }
+
+ public function addLine(string $line): void
+ {
+ if ($this->content !== '') {
+ $this->content .= "\n";
+ }
+
+ $line = substr($line, 0, -4);
+
+ $this->content .= $line;
+ }
+
+ public function closeBlock(): void
+ {
+ $this->block->setLiteral($this->content);
+ $this->content = '';
+ }
+
+ /**
+ * Parse any inlines inside of the current block
+ */
+ public function parseInlines(InlineParserEngineInterface $inlineParser): void
+ {
+ // #TODO
+ }
+}
diff --git a/src/Extension/BBCode/Parser/Block/BoldBlockStartParser.php b/src/Extension/BBCode/Parser/Block/BoldBlockStartParser.php
new file mode 100644
index 0000000..507bc34
--- /dev/null
+++ b/src/Extension/BBCode/Parser/Block/BoldBlockStartParser.php
@@ -0,0 +1,51 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Extension\BBCode\Parser\Block;
+
+use League\CommonMark\Parser\Block\BlockStart;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+use League\CommonMark\Parser\Cursor;
+use League\CommonMark\Parser\MarkdownParserStateInterface;
+use League\CommonMark\Util\RegexHelper;
+
+final class BoldBlockStartParser implements BlockStartParserInterface
+{
+ public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart
+ {
+ if ($cursor->isIndented() || $cursor->getNextNonSpaceCharacter() !== '[') {
+ return BlockStart::none();
+ }
+
+ $tmpCursor = clone $cursor;
+ $tmpCursor->advanceToNextNonSpaceOrTab();
+ $line = $tmpCursor->getSubstring(0, 3);
+
+ if ($line !== '[b]') {
+ return BlockStart::none();
+ }
+
+ $cursor->advanceBy(3);
+
+ return BlockStart::of(new BoldBlockParser())->at($cursor);
+ }
+}
diff --git a/src/Extension/BBCode/Renderer/Block/BoldBlockRenderer.php b/src/Extension/BBCode/Renderer/Block/BoldBlockRenderer.php
new file mode 100644
index 0000000..750dc00
--- /dev/null
+++ b/src/Extension/BBCode/Renderer/Block/BoldBlockRenderer.php
@@ -0,0 +1,73 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Extension\BBCode\Renderer\Block;
+
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+use Youthweb\BBCodeParser\Extension\BBCode\Node\Block\BoldBlock;
+
+final class BoldBlockRenderer implements NodeRendererInterface, XmlNodeRendererInterface, ConfigurationAwareInterface
+{
+ private ConfigurationInterface $config;
+
+ /**
+ * @param BoldBlock $node
+ *
+ * {@inheritDoc}
+ */
+ public function render(Node $node, ChildNodeRendererInterface $childRenderer): HtmlElement
+ {
+ BoldBlock::assertInstanceOf($node);
+
+ $innerHtml = $childRenderer->renderNodes($node->children());
+
+ if ($innerHtml === '') {
+ $innerHtml = $node->getLiteral();
+ }
+
+ return new HtmlElement('b', [], $innerHtml);
+ }
+
+ public function setConfiguration(ConfigurationInterface $configuration): void
+ {
+ $this->config = $configuration;
+ }
+
+ public function getXmlTagName(Node $node): string
+ {
+ return 'strong';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getXmlAttributes(Node $node): array
+ {
+ return [];
+ }
+}
diff --git a/src/Parser/CommonMarkParser.php b/src/Parser/CommonMarkParser.php
new file mode 100644
index 0000000..a0563e9
--- /dev/null
+++ b/src/Parser/CommonMarkParser.php
@@ -0,0 +1,81 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Parser;
+
+use Youthweb\BBCodeParser\Extension\BBCode\BBCodeExtension;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+/**
+ * CommonMarkParser
+ */
+final class CommonMarkParser
+{
+ /**
+ * Create the Parser
+ */
+ public static function create(): CommonMarkParser
+ {
+ return new self();
+ }
+
+ private MarkdownParser $markdownParser;
+
+ private HtmlRenderer $htmlRenderer;
+
+ /**
+ * Create the Parser
+ */
+ private function __construct()
+ {
+ $config = [
+ 'html_input' => 'escape',
+ 'allow_unsafe_links' => false,
+ 'max_nesting_level' => 5,
+ 'renderer' => [
+ 'block_separator' => \PHP_EOL,
+ 'inner_separator' => \PHP_EOL,
+ 'soft_break' => \PHP_EOL,
+ ],
+ ];
+
+ $environment = new Environment($config);
+ $environment->addExtension(new BBCodeExtension());
+
+ $this->markdownParser = new MarkdownParser($environment);
+ $this->htmlRenderer = new HtmlRenderer($environment);
+ }
+
+ /**
+ * parse $test with BBCode to Html
+ */
+ public function parseBbcodeToHtml(string $text): string
+ {
+ $documentAST = $this->markdownParser->parse($text);
+
+ $content = $this->htmlRenderer->renderDocument($documentAST);
+
+ return trim($content->getContent());
+ }
+}
diff --git a/tests/Integration/Parser/CommonMarkParserTest.php b/tests/Integration/Parser/CommonMarkParserTest.php
new file mode 100644
index 0000000..9e9bc0c
--- /dev/null
+++ b/tests/Integration/Parser/CommonMarkParserTest.php
@@ -0,0 +1,58 @@
+
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Youthweb\BBCodeParser\Tests\Integration\Parser;
+
+use PHPUnit\Framework\TestCase;
+use Youthweb\BBCodeParser\Parser\CommonMarkParser;
+
+class CommonMarkParserTest extends TestCase
+{
+ /**
+ * @dataProvider provideBbcodeAndHtml
+ */
+ public function testParseBbcodeToHtml(string $text, string $expected)
+ {
+ $parser = CommonMarkParser::create();
+
+ $this->assertSame($expected, $parser->parseBbcodeToHtml($text));
+ }
+
+ public function provideBbcodeAndHtml()
+ {
+ return [
+ [
+ 'Hello World!',
+ '
Hello World!
',
+ ],
+ [
+ 'Hello World! ',
+ 'Hello World! </div>
',
+ ],
+ [
+ 'Hello World!
',
+ 'Hello World! <img src="javascript:alert(\'XSS\')">
',
+ ],
+ [
+ '[b]Hello World![/b]',
+ 'Hello World!
',
+ ],
+ ];
+ }
+}