1
0
mirror of https://github.com/erusev/parsedown.git synced 2023-08-10 21:13:06 +03:00

Markup like CommonMark

This commit is contained in:
Aidan Woods 2019-01-27 19:38:07 +00:00
parent 7fd6e0bb31
commit 82d20d8ffe
No known key found for this signature in database
GPG Key ID: 9A6A8EFAA512BBB9
4 changed files with 81 additions and 98 deletions

View File

@ -1,88 +0,0 @@
<?php
namespace Erusev\Parsedown\Components\Blocks;
use Erusev\Parsedown\AST\Handler;
use Erusev\Parsedown\AST\StateRenderable;
use Erusev\Parsedown\Components\Block;
use Erusev\Parsedown\Components\ContinuableBlock;
use Erusev\Parsedown\Configurables\SafeMode;
use Erusev\Parsedown\Html\Renderables\RawHtml;
use Erusev\Parsedown\Html\Renderables\Text;
use Erusev\Parsedown\Parsing\Context;
use Erusev\Parsedown\State;
final class Comment implements ContinuableBlock
{
use BlockAcquisition;
/** @var string */
private $html;
/** @var bool */
private $isClosed;
/**
* @param string $html
* @param bool $isClosed
*/
public function __construct($html, $isClosed)
{
$this->html = $html;
$this->isClosed = $isClosed;
}
/**
* @param Context $Context
* @param Block|null $Block
* @param State|null $State
* @return static|null
*/
public static function build(
Context $Context,
Block $Block = null,
State $State = null
) {
if (\strpos($Context->line()->text(), '<!--') === 0) {
return new self(
$Context->line()->rawLine(),
\strpos($Context->line()->text(), '-->') !== false
);
}
return null;
}
/**
* @param Context $Context
* @return self|null
*/
public function advance(Context $Context)
{
if ($this->isClosed) {
return null;
}
return new self(
$this->html . "\n" . $Context->line()->rawLine(),
\strpos($Context->line()->text(), '-->') !== false
);
}
/**
* @return Handler<Text|RawHtml>
*/
public function stateRenderable()
{
return new Handler(
/** @return Text|RawHtml */
function (State $State) {
if ($State->get(SafeMode::class)->isEnabled()) {
return new Text($this->html);
} else {
return new RawHtml($this->html);
}
}
);
}
}

View File

@ -19,15 +19,33 @@ final class Markup implements ContinuableBlock
const REGEX_HTML_ATTRIBUTE = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+';
/** @var array{2: string, 3: string, 4: string, 5: string} */
private static $simpleContainsEndConditions = [
2 => '-->',
3 => '?>',
4 => '>',
5 => ']]>'
];
/** @var string */
private $html;
/** @var 1|2|3|4|5|6|7 */
private $type;
/** @var bool */
private $closed;
/**
* @param string $html
* @param 1|2|3|4|5|6|7 $type
* @param bool $closed
*/
public function __construct($html)
private function __construct($html, $type, $closed = false)
{
$this->html = $html;
$this->type = $type;
$this->closed = $closed;
}
/**
@ -41,15 +59,40 @@ final class Markup implements ContinuableBlock
Block $Block = null,
State $State = null
) {
if (\preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.self::REGEX_HTML_ATTRIBUTE.')*+[ ]*+(\/)?>/', $Context->line()->text(), $matches)) {
$text = $Context->line()->text();
$rawLine = $Context->line()->rawLine();
if (\preg_match('/^<(?:script|pre|style)(?:\s++|>|$)/i', $text)) {
return new self($rawLine, 1, self::closes12345TypeMarkup(1, $text));
}
if (\substr($text, 0, 4) === '<!--') {
return new self($rawLine, 2, self::closes12345TypeMarkup(2, $text));
}
if (\substr($text, 0, 2) === '<?') {
return new self($rawLine, 3, self::closes12345TypeMarkup(3, $text));
}
if (\preg_match('/^<![A-Z]/', $text)) {
return new self($rawLine, 4, self::closes12345TypeMarkup(4, $text));
}
if (\substr($text, 0, 9) === '<![CDATA[') {
return new self($rawLine, 5, self::closes12345TypeMarkup(5, $text));
}
if (\preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.self::REGEX_HTML_ATTRIBUTE.')*+[ ]*+(\/)?>/', $text, $matches)) {
$element = \strtolower($matches[1]);
if (\array_key_exists($element, Element::$TEXT_LEVEL_ELEMENTS)) {
return null;
}
return new self($Context->line()->text());
return new self($rawLine, 6);
}
return null;
}
/**
@ -58,13 +101,43 @@ final class Markup implements ContinuableBlock
*/
public function advance(Context $Context)
{
if ($Context->previousEmptyLines() > 0) {
$closed = $this->closed;
$type = $this->type;
if ($closed) {
return null;
}
$html = $this->html . "\n" . $Context->line()->rawLine();
if (($type === 6 || $type === 7) && $Context->previousEmptyLines() > 0) {
return null;
}
return new self($html);
if ($type === 1 || $type === 2 || $type === 3 || $type === 4 || $type === 5) {
$closed = self::closes12345TypeMarkup($type, $Context->line()->text());
}
$html = $this->html . \str_repeat("\n", $Context->previousEmptyLines() + 1);
$html .= $Context->line()->rawLine();
return new self($html, $type, $closed);
}
/**
* @param 1|2|3|4|5 $type
* @param string $text
* @return bool
*/
private static function closes12345TypeMarkup($type, $text)
{
if ($type === 1) {
if (\preg_match('/<\/(?:script|pre|style)>/i', $text)) {
return true;
}
} elseif (\stripos($text, self::$simpleContainsEndConditions[$type]) !== false) {
return true;
}
return false;
}
/**

View File

@ -4,7 +4,6 @@ namespace Erusev\Parsedown\Configurables;
use Erusev\Parsedown\Components\Block;
use Erusev\Parsedown\Components\Blocks\BlockQuote;
use Erusev\Parsedown\Components\Blocks\Comment;
use Erusev\Parsedown\Components\Blocks\FencedCode;
use Erusev\Parsedown\Components\Blocks\Header;
use Erusev\Parsedown\Components\Blocks\IndentedCode;
@ -38,7 +37,7 @@ final class BlockTypes implements Configurable
'8' => [TList::class],
'9' => [TList::class],
':' => [Table::class],
'<' => [Comment::class, BlockMarkup::class],
'<' => [BlockMarkup::class],
'=' => [SetextHeader::class],
'>' => [BlockQuote::class],
'[' => [Reference::class],

View File

@ -2,7 +2,6 @@
namespace Erusev\Parsedown\Tests;
use Erusev\Parsedown\Components\Blocks\Comment;
use Erusev\Parsedown\Components\Blocks\Markup as BlockMarkup;
use Erusev\Parsedown\Components\Inlines\Markup as InlineMarkup;
use Erusev\Parsedown\Configurables\BlockTypes;
@ -139,7 +138,7 @@ color: red;
EXPECTED_HTML;
$parsedownWithNoMarkup = new Parsedown(new State([
BlockTypes::initial()->removing([BlockMarkup::class, Comment::class]),
BlockTypes::initial()->removing([BlockMarkup::class]),
InlineTypes::initial()->removing([InlineMarkup::class]),
]));