mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Inlines and Blocks as Configurables
This commit is contained in:
parent
eb90905d27
commit
fce4633ff9
@ -28,6 +28,8 @@
|
|||||||
<referencedMethod name="Erusev\Parsedown\Configurables\StrictMode::enabled" />
|
<referencedMethod name="Erusev\Parsedown\Configurables\StrictMode::enabled" />
|
||||||
<referencedMethod name="Erusev\Parsedown\Configurables\SafeMode::enabled" />
|
<referencedMethod name="Erusev\Parsedown\Configurables\SafeMode::enabled" />
|
||||||
<referencedMethod name="Erusev\Parsedown\Html\Renderables\Container::__construct" />
|
<referencedMethod name="Erusev\Parsedown\Html\Renderables\Container::__construct" />
|
||||||
|
<referencedMethod name="Erusev\Parsedown\Configurables\BlockTypes::settingMarked" />
|
||||||
|
<referencedMethod name="Erusev\Parsedown\Configurables\BlockTypes::settingUnmarked" />
|
||||||
</errorLevel>
|
</errorLevel>
|
||||||
</PossiblyUnusedMethod>
|
</PossiblyUnusedMethod>
|
||||||
</issueHandlers>
|
</issueHandlers>
|
||||||
|
123
src/Configurables/BlockTypes.php
Normal file
123
src/Configurables/BlockTypes.php
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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;
|
||||||
|
use Erusev\Parsedown\Components\Blocks\Markup as BlockMarkup;
|
||||||
|
use Erusev\Parsedown\Components\Blocks\Reference;
|
||||||
|
use Erusev\Parsedown\Components\Blocks\Rule;
|
||||||
|
use Erusev\Parsedown\Components\Blocks\SetextHeader;
|
||||||
|
use Erusev\Parsedown\Components\Blocks\Table;
|
||||||
|
use Erusev\Parsedown\Components\Blocks\TList;
|
||||||
|
use Erusev\Parsedown\Configurable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @psalm-type _Data=array{url: string, title: string|null}
|
||||||
|
*/
|
||||||
|
final class BlockTypes implements Configurable
|
||||||
|
{
|
||||||
|
/** @var array<array-key, class-string<Block>[]> */
|
||||||
|
private static $defaultBlockTypes = [
|
||||||
|
'#' => [Header::class],
|
||||||
|
'*' => [Rule::class, TList::class],
|
||||||
|
'+' => [TList::class],
|
||||||
|
'-' => [SetextHeader::class, Table::class, Rule::class, TList::class],
|
||||||
|
'0' => [TList::class],
|
||||||
|
'1' => [TList::class],
|
||||||
|
'2' => [TList::class],
|
||||||
|
'3' => [TList::class],
|
||||||
|
'4' => [TList::class],
|
||||||
|
'5' => [TList::class],
|
||||||
|
'6' => [TList::class],
|
||||||
|
'7' => [TList::class],
|
||||||
|
'8' => [TList::class],
|
||||||
|
'9' => [TList::class],
|
||||||
|
':' => [Table::class],
|
||||||
|
'<' => [Comment::class, BlockMarkup::class],
|
||||||
|
'=' => [SetextHeader::class],
|
||||||
|
'>' => [BlockQuote::class],
|
||||||
|
'[' => [Reference::class],
|
||||||
|
'_' => [Rule::class],
|
||||||
|
'`' => [FencedCode::class],
|
||||||
|
'|' => [Table::class],
|
||||||
|
'~' => [FencedCode::class],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var class-string<Block>[] */
|
||||||
|
private static $defaultUnmarkedBlockTypes = [
|
||||||
|
IndentedCode::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array<array-key, class-string<Block>[]> */
|
||||||
|
private $blockTypes;
|
||||||
|
|
||||||
|
/** @var class-string<Block>[] */
|
||||||
|
private $unmarkedBlockTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<array-key, class-string<Block>[]> $blockTypes
|
||||||
|
* @param class-string<Block>[] $unmarkedBlockTypes
|
||||||
|
*/
|
||||||
|
public function __construct(array $blockTypes, array $unmarkedBlockTypes)
|
||||||
|
{
|
||||||
|
$this->blockTypes = $blockTypes;
|
||||||
|
$this->unmarkedBlockTypes = $unmarkedBlockTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return self */
|
||||||
|
public static function initial()
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
self::$defaultBlockTypes,
|
||||||
|
self::$defaultUnmarkedBlockTypes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $marker
|
||||||
|
* @param class-string<Block>[] $newBlockTypes
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function settingMarked($marker, array $newBlockTypes)
|
||||||
|
{
|
||||||
|
$blockTypes = $this->blockTypes;
|
||||||
|
$blockTypes[$marker] = $newBlockTypes;
|
||||||
|
|
||||||
|
return new self($blockTypes, $this->unmarkedBlockTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param class-string<Block>[] $newUnmarkedBlockTypes
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function settingUnmarked(array $newUnmarkedBlockTypes)
|
||||||
|
{
|
||||||
|
return new self($this->blockTypes, $newUnmarkedBlockTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $marker
|
||||||
|
* @return class-string<Block>[]
|
||||||
|
*/
|
||||||
|
public function for($marker)
|
||||||
|
{
|
||||||
|
if (isset($this->blockTypes[$marker])) {
|
||||||
|
return $this->blockTypes[$marker];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return class-string<Block>[]
|
||||||
|
*/
|
||||||
|
public function unmarked()
|
||||||
|
{
|
||||||
|
return $this->unmarkedBlockTypes;
|
||||||
|
}
|
||||||
|
}
|
80
src/Configurables/InlineTypes.php
Normal file
80
src/Configurables/InlineTypes.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Erusev\Parsedown\Configurables;
|
||||||
|
|
||||||
|
use Erusev\Parsedown\Components\Inline;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Code;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Email;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Emphasis;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\EscapeSequence;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\HardBreak;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Image;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Link;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Markup as InlineMarkup;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\SoftBreak;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\SpecialCharacter;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Strikethrough;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\Url;
|
||||||
|
use Erusev\Parsedown\Components\Inlines\UrlTag;
|
||||||
|
use Erusev\Parsedown\Configurable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @psalm-type _Data=array{url: string, title: string|null}
|
||||||
|
*/
|
||||||
|
final class InlineTypes implements Configurable
|
||||||
|
{
|
||||||
|
/** @var array<array-key, class-string<Inline>[]> */
|
||||||
|
private static $defaultInlineTypes = [
|
||||||
|
'!' => [Image::class],
|
||||||
|
'*' => [Emphasis::class],
|
||||||
|
'_' => [Emphasis::class],
|
||||||
|
'&' => [SpecialCharacter::class],
|
||||||
|
'[' => [Link::class],
|
||||||
|
':' => [Url::class],
|
||||||
|
'<' => [UrlTag::class, Email::class, InlineMarkup::class],
|
||||||
|
'`' => [Code::class],
|
||||||
|
'~' => [Strikethrough::class],
|
||||||
|
'\\' => [EscapeSequence::class],
|
||||||
|
"\n" => [HardBreak::class, SoftBreak::class],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array<array-key, class-string<Inline>[]> */
|
||||||
|
private $inlineTypes;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $inlineMarkers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<array-key, class-string<Inline>[]> $inlineTypes
|
||||||
|
*/
|
||||||
|
public function __construct(array $inlineTypes)
|
||||||
|
{
|
||||||
|
$this->inlineTypes = $inlineTypes;
|
||||||
|
$this->inlineMarkers = \implode('', \array_keys($inlineTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return self */
|
||||||
|
public static function initial()
|
||||||
|
{
|
||||||
|
return new self(self::$defaultInlineTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $marker
|
||||||
|
* @return class-string<Inline>[]
|
||||||
|
*/
|
||||||
|
public function for($marker)
|
||||||
|
{
|
||||||
|
if (isset($this->inlineTypes[$marker])) {
|
||||||
|
return $this->inlineTypes[$marker];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string */
|
||||||
|
public function markers()
|
||||||
|
{
|
||||||
|
return $this->inlineMarkers;
|
||||||
|
}
|
||||||
|
}
|
@ -4,35 +4,13 @@ namespace Erusev\Parsedown;
|
|||||||
|
|
||||||
use Erusev\Parsedown\AST\StateRenderable;
|
use Erusev\Parsedown\AST\StateRenderable;
|
||||||
use Erusev\Parsedown\Components\Block;
|
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;
|
|
||||||
use Erusev\Parsedown\Components\Blocks\Markup as BlockMarkup;
|
|
||||||
use Erusev\Parsedown\Components\Blocks\Paragraph;
|
use Erusev\Parsedown\Components\Blocks\Paragraph;
|
||||||
use Erusev\Parsedown\Components\Blocks\Reference;
|
|
||||||
use Erusev\Parsedown\Components\Blocks\Rule;
|
|
||||||
use Erusev\Parsedown\Components\Blocks\SetextHeader;
|
|
||||||
use Erusev\Parsedown\Components\Blocks\Table;
|
|
||||||
use Erusev\Parsedown\Components\Blocks\TList;
|
|
||||||
use Erusev\Parsedown\Components\ContinuableBlock;
|
use Erusev\Parsedown\Components\ContinuableBlock;
|
||||||
use Erusev\Parsedown\Components\Inline;
|
use Erusev\Parsedown\Components\Inline;
|
||||||
use Erusev\Parsedown\Components\Inlines\Code;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Email;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Emphasis;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\EscapeSequence;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\HardBreak;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Image;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Link;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Markup as InlineMarkup;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\PlainText;
|
use Erusev\Parsedown\Components\Inlines\PlainText;
|
||||||
use Erusev\Parsedown\Components\Inlines\SoftBreak;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\SpecialCharacter;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Strikethrough;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\Url;
|
|
||||||
use Erusev\Parsedown\Components\Inlines\UrlTag;
|
|
||||||
use Erusev\Parsedown\Components\StateUpdatingBlock;
|
use Erusev\Parsedown\Components\StateUpdatingBlock;
|
||||||
|
use Erusev\Parsedown\Configurables\BlockTypes;
|
||||||
|
use Erusev\Parsedown\Configurables\InlineTypes;
|
||||||
use Erusev\Parsedown\Html\Renderable;
|
use Erusev\Parsedown\Html\Renderable;
|
||||||
use Erusev\Parsedown\Html\Renderables\Invisible;
|
use Erusev\Parsedown\Html\Renderables\Invisible;
|
||||||
use Erusev\Parsedown\Html\Renderables\Text;
|
use Erusev\Parsedown\Html\Renderables\Text;
|
||||||
@ -48,61 +26,15 @@ final class Parsedown
|
|||||||
/** @var State */
|
/** @var State */
|
||||||
private $State;
|
private $State;
|
||||||
|
|
||||||
/** @var array<array-key, class-string<Block>[]> */
|
|
||||||
private $BlockTypes = [
|
|
||||||
'#' => [Header::class],
|
|
||||||
'*' => [Rule::class, TList::class],
|
|
||||||
'+' => [TList::class],
|
|
||||||
'-' => [SetextHeader::class, Table::class, Rule::class, TList::class],
|
|
||||||
'0' => [TList::class],
|
|
||||||
'1' => [TList::class],
|
|
||||||
'2' => [TList::class],
|
|
||||||
'3' => [TList::class],
|
|
||||||
'4' => [TList::class],
|
|
||||||
'5' => [TList::class],
|
|
||||||
'6' => [TList::class],
|
|
||||||
'7' => [TList::class],
|
|
||||||
'8' => [TList::class],
|
|
||||||
'9' => [TList::class],
|
|
||||||
':' => [Table::class],
|
|
||||||
'<' => [Comment::class, BlockMarkup::class],
|
|
||||||
'=' => [SetextHeader::class],
|
|
||||||
'>' => [BlockQuote::class],
|
|
||||||
'[' => [Reference::class],
|
|
||||||
'_' => [Rule::class],
|
|
||||||
'`' => [FencedCode::class],
|
|
||||||
'|' => [Table::class],
|
|
||||||
'~' => [FencedCode::class],
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @var class-string<Block>[] */
|
|
||||||
private $unmarkedBlockTypes = [
|
|
||||||
IndentedCode::class,
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @var array<array-key, class-string<Inline>[]> */
|
|
||||||
private $InlineTypes = [
|
|
||||||
'!' => [Image::class],
|
|
||||||
'*' => [Emphasis::class],
|
|
||||||
'_' => [Emphasis::class],
|
|
||||||
'&' => [SpecialCharacter::class],
|
|
||||||
'[' => [Link::class],
|
|
||||||
':' => [Url::class],
|
|
||||||
'<' => [UrlTag::class, Email::class, InlineMarkup::class],
|
|
||||||
'`' => [Code::class],
|
|
||||||
'~' => [Strikethrough::class],
|
|
||||||
'\\' => [EscapeSequence::class],
|
|
||||||
"\n" => [HardBreak::class, SoftBreak::class],
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
private $inlineMarkers;
|
|
||||||
|
|
||||||
public function __construct(State $State = null)
|
public function __construct(State $State = null)
|
||||||
{
|
{
|
||||||
$this->State = $State ?: new State;
|
$this->State = $State ?: new State;
|
||||||
|
|
||||||
$this->inlineMarkers = \implode('', \array_keys($this->InlineTypes));
|
// ensure we cache the initial value if these weren't explicitly set
|
||||||
|
$this->State = $this->State->mergingWith(new State([
|
||||||
|
$this->State->get(BlockTypes::class),
|
||||||
|
$this->State->get(InlineTypes::class),
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,18 +106,15 @@ final class Parsedown
|
|||||||
|
|
||||||
# ~
|
# ~
|
||||||
|
|
||||||
$blockTypes = $this->unmarkedBlockTypes;
|
$potentialBlockTypes = \array_merge(
|
||||||
|
$this->State->get(BlockTypes::class)->unmarked(),
|
||||||
if (isset($this->BlockTypes[$marker])) {
|
$this->State->get(BlockTypes::class)->for($marker)
|
||||||
foreach ($this->BlockTypes[$marker] as $blockType) {
|
);
|
||||||
$blockTypes []= $blockType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ~
|
# ~
|
||||||
|
|
||||||
foreach ($blockTypes as $blockType) {
|
foreach ($potentialBlockTypes as $blockType) {
|
||||||
$Block = $blockType::build($Context, $CurrentBlock, $this->State);
|
$Block = $blockType::build($Context, $CurrentBlock, $this->State);
|
||||||
|
|
||||||
if (isset($Block)) {
|
if (isset($Block)) {
|
||||||
@ -264,14 +193,17 @@ final class Parsedown
|
|||||||
|
|
||||||
# $excerpt is based on the first occurrence of a marker
|
# $excerpt is based on the first occurrence of a marker
|
||||||
|
|
||||||
|
$InlineTypes = $this->State->get(InlineTypes::class);
|
||||||
|
$markerMask = $InlineTypes->markers();
|
||||||
|
|
||||||
for (
|
for (
|
||||||
$Excerpt = (new Excerpt($text, 0))->pushingOffsetTo($this->inlineMarkers);
|
$Excerpt = (new Excerpt($text, 0))->pushingOffsetTo($markerMask);
|
||||||
$Excerpt->text() !== '';
|
$Excerpt->text() !== '';
|
||||||
$Excerpt = $Excerpt->pushingOffsetTo($this->inlineMarkers)
|
$Excerpt = $Excerpt->pushingOffsetTo($markerMask)
|
||||||
) {
|
) {
|
||||||
$marker = \substr($Excerpt->text(), 0, 1);
|
$marker = \substr($Excerpt->text(), 0, 1);
|
||||||
|
|
||||||
foreach ($this->InlineTypes[$marker] as $inlineType) {
|
foreach ($InlineTypes->for($marker) as $inlineType) {
|
||||||
# check to see if the current inline type is nestable in the current context
|
# check to see if the current inline type is nestable in the current context
|
||||||
|
|
||||||
$Inline = $inlineType::build($Excerpt, $this->State);
|
$Inline = $inlineType::build($Excerpt, $this->State);
|
||||||
|
Loading…
Reference in New Issue
Block a user