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\SafeMode::enabled" />
|
||||
<referencedMethod name="Erusev\Parsedown\Html\Renderables\Container::__construct" />
|
||||
<referencedMethod name="Erusev\Parsedown\Configurables\BlockTypes::settingMarked" />
|
||||
<referencedMethod name="Erusev\Parsedown\Configurables\BlockTypes::settingUnmarked" />
|
||||
</errorLevel>
|
||||
</PossiblyUnusedMethod>
|
||||
</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\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\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\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\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\Configurables\BlockTypes;
|
||||
use Erusev\Parsedown\Configurables\InlineTypes;
|
||||
use Erusev\Parsedown\Html\Renderable;
|
||||
use Erusev\Parsedown\Html\Renderables\Invisible;
|
||||
use Erusev\Parsedown\Html\Renderables\Text;
|
||||
@ -48,61 +26,15 @@ final class Parsedown
|
||||
/** @var 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)
|
||||
{
|
||||
$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;
|
||||
|
||||
if (isset($this->BlockTypes[$marker])) {
|
||||
foreach ($this->BlockTypes[$marker] as $blockType) {
|
||||
$blockTypes []= $blockType;
|
||||
}
|
||||
}
|
||||
$potentialBlockTypes = \array_merge(
|
||||
$this->State->get(BlockTypes::class)->unmarked(),
|
||||
$this->State->get(BlockTypes::class)->for($marker)
|
||||
);
|
||||
|
||||
#
|
||||
# ~
|
||||
|
||||
foreach ($blockTypes as $blockType) {
|
||||
foreach ($potentialBlockTypes as $blockType) {
|
||||
$Block = $blockType::build($Context, $CurrentBlock, $this->State);
|
||||
|
||||
if (isset($Block)) {
|
||||
@ -264,14 +193,17 @@ final class Parsedown
|
||||
|
||||
# $excerpt is based on the first occurrence of a marker
|
||||
|
||||
$InlineTypes = $this->State->get(InlineTypes::class);
|
||||
$markerMask = $InlineTypes->markers();
|
||||
|
||||
for (
|
||||
$Excerpt = (new Excerpt($text, 0))->pushingOffsetTo($this->inlineMarkers);
|
||||
$Excerpt = (new Excerpt($text, 0))->pushingOffsetTo($markerMask);
|
||||
$Excerpt->text() !== '';
|
||||
$Excerpt = $Excerpt->pushingOffsetTo($this->inlineMarkers)
|
||||
$Excerpt = $Excerpt->pushingOffsetTo($markerMask)
|
||||
) {
|
||||
$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
|
||||
|
||||
$Inline = $inlineType::build($Excerpt, $this->State);
|
||||
|
Loading…
Reference in New Issue
Block a user