diff --git a/src/IsRule.php b/src/IsRule.php new file mode 100644 index 0000000..4fc3301 --- /dev/null +++ b/src/IsRule.php @@ -0,0 +1,43 @@ +, bool> */ + private(set) array $tokenSupport = []; + + public function supportsToken(Token $token): bool + { + return ( + $this->tokenSupport[$token::class] ?? in_array( + RuleContext::INLINE, + $this->contexts, + strict: true, + ) + ); + } + + /** @param class-string<\Tempest\Markdown\Token> $token */ + public function addTokenSupport(string $token): static + { + $this->tokenSupport[$token] = true; + + return $this; + } + + /** @param class-string<\Tempest\Markdown\Token> $token */ + public function removeTokenSupport(string $token): static + { + $this->tokenSupport[$token] = false; + + return $this; + } +} diff --git a/src/Markdown.php b/src/Markdown.php index f40bf71..342edba 100644 --- a/src/Markdown.php +++ b/src/Markdown.php @@ -53,4 +53,15 @@ public function removeRules(string ...$rules): self return $this; } + + /** + * The registered instance of $rule, to reconfigure it or to change the + * tokens it supports. + * + * @param class-string<\Tempest\Markdown\Rule> $rule + */ + public function getRule(string $rule): ?Rule + { + return $this->parser->getRule($rule); + } } diff --git a/src/Parser.php b/src/Parser.php index 26ce0ba..2487580 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -4,11 +4,17 @@ use Tempest\Highlight\Highlighter; use Tempest\Markdown\Exceptions\MaximumNestingDepthWasExceeded; +use Tempest\Markdown\Rules\BoldAndItalicRule; +use Tempest\Markdown\Rules\BoldRule; +use Tempest\Markdown\Rules\CodeRule; use Tempest\Markdown\Rules\DivRule; use Tempest\Markdown\Rules\FrontMatterRule; use Tempest\Markdown\Rules\HeadingRule; use Tempest\Markdown\Rules\HtmlCommentRule; use Tempest\Markdown\Rules\HtmlRule; +use Tempest\Markdown\Rules\ImageRule; +use Tempest\Markdown\Rules\ItalicRule; +use Tempest\Markdown\Rules\LinkRule; use Tempest\Markdown\Rules\ListRule; use Tempest\Markdown\Rules\NewLineRule; use Tempest\Markdown\Rules\OrderedListRule; @@ -16,7 +22,10 @@ use Tempest\Markdown\Rules\PreRule; use Tempest\Markdown\Rules\QuoteRule; use Tempest\Markdown\Rules\RawRule; +use Tempest\Markdown\Rules\SocialHandleRule; +use Tempest\Markdown\Rules\StrikethroughRule; use Tempest\Markdown\Rules\TableRule; +use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Rules\ThickRulerRule; use Tempest\Markdown\Rules\ThinRulerRule; use Tempest\Markdown\Tokens\FrontMatterToken; @@ -33,6 +42,7 @@ final class Parser private(set) ?string $current; private(set) string $content; private(set) ?Token $lastToken = null; + /** Every registered rule, whether or not it runs here. */ /** @var \Tempest\Markdown\Rule[] */ private(set) array $rules = []; /** @var \Tempest\Markdown\Rule[] */ @@ -45,6 +55,7 @@ final class Parser private static int $depth = 0; + /** @param \Tempest\Markdown\Rule[] $rules */ public function __construct( public ?Highlighter $highlighter = new Highlighter(), public ?ResponsiveImageFactory $imageFactory = null, @@ -65,12 +76,27 @@ public function __construct( new HtmlRule(), new TableRule(), new ParagraphRule(), + new BoldAndItalicRule(), + new BoldRule(), + new ItalicRule(), + new StrikethroughRule(), + new CodeRule(), + new LinkRule(), + new SocialHandleRule(), + new ImageRule(), + new TextRule(), ], ) { $this->setRules($rules); } - public function forToken(Token $token, array $rules): self + /** + * A parser for the content of $token, running every registered rule that + * supports it. Rules are never rebuilt here: they are the configured + * instances, so adding, removing or reconfiguring a rule reaches nested + * content too. + */ + public function forToken(Token $token): self { if (isset($this->cache[$token::class])) { return $this->cache[$token::class]; @@ -78,13 +104,36 @@ public function forToken(Token $token, array $rules): self $clone = clone $this; - $clone->setRules($rules); + $clone->activateRules(array_values(array_filter( + $this->rules, + static fn (Rule $rule) => $rule->supportsToken($token), + ))); $this->cache[$token::class] = $clone; return $clone; } + /** + * The registered instance of $rule, to reconfigure it or to change the + * tokens it supports. Sub-parsers are derived from the rules, so handing + * one out drops the ones already built from it. + * + * @param class-string<\Tempest\Markdown\Rule> $rule + */ + public function getRule(string $rule): ?Rule + { + $this->cache = []; + + foreach ($this->rules as $registered) { + if ($registered::class === $rule) { + return $registered; + } + } + + return null; + } + public function withRules(Rule ...$rules): self { $clone = clone $this; @@ -125,24 +174,41 @@ public function removeRules(string ...$rules): self return $clone; } + /** @param \Tempest\Markdown\Rule[] $rules */ private function setRules(array $rules): self { - /** @var \Tempest\Markdown\NeedsStopChars[] $needsStopChars */ - $needsStopChars = []; + $this->rules = $rules; + + return $this->activateRules($rules); + } + + /** @param \Tempest\Markdown\Rule[] $rules */ + private function activateRules(array $rules): self + { $providedStopChars = ''; foreach ($rules as $rule) { - if ($rule instanceof ProvidesStopChar) { - $providedStopChars .= $rule->stopChar; + if (! $rule instanceof ProvidesStopChar) { + continue; } - if ($rule instanceof NeedsStopChars) { - $needsStopChars[] = $rule; - } + $providedStopChars .= $rule->stopChar; } - foreach ($needsStopChars as $rule) { - $rule->stopChars .= $providedStopChars; + foreach ($rules as $key => $rule) { + if (! $rule instanceof NeedsStopChars) { + continue; + } + + if ($rule->stopChars === $providedStopChars) { + continue; + } + + // Stop chars belong to a rule set, not to a rule: the registered + // instance is shared between sets, so this set gets its own copy + // instead of overwriting the stop chars of the previous one. + $rules[$key] = clone $rule; + $rules[$key]->stopChars = $providedStopChars; } $perCharRules = []; @@ -167,12 +233,11 @@ private function setRules(array $rules): self } } - /** @var \Tempest\Markdown\Rule[] $rules */ /** @var \Tempest\Markdown\Rule[] $defaultRules */ /** @var \Tempest\Markdown\Rule[][] $perCharRules */ - $this->rules = $rules; $this->defaultRules = $defaultRules; $this->perCharRules = $perCharRules; + $this->cache = []; return $this; } diff --git a/src/Rule.php b/src/Rule.php index 420dc88..1de81de 100644 --- a/src/Rule.php +++ b/src/Rule.php @@ -7,4 +7,13 @@ interface Rule public function shouldParse(Parser $parser): bool; public function parse(Parser $parser): ?Token; + + /** Whether this rule runs on the content of $token. */ + public function supportsToken(Token $token): bool; + + /** @param class-string<\Tempest\Markdown\Token> $token */ + public function addTokenSupport(string $token): static; + + /** @param class-string<\Tempest\Markdown\Token> $token */ + public function removeTokenSupport(string $token): static; } diff --git a/src/RuleContext.php b/src/RuleContext.php new file mode 100644 index 0000000..54e64e9 --- /dev/null +++ b/src/RuleContext.php @@ -0,0 +1,17 @@ +contexts = [RuleContext::INLINE]; + + $this->removeTokenSupport(BoldToken::class); + $this->removeTokenSupport(ItalicToken::class); + $this->removeTokenSupport(BoldAndItalicToken::class); + } + public function shouldParse(Parser $parser): bool { return ( diff --git a/src/Rules/BoldRule.php b/src/Rules/BoldRule.php index de2a7ad..5b4ac88 100644 --- a/src/Rules/BoldRule.php +++ b/src/Rules/BoldRule.php @@ -2,18 +2,31 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; +use Tempest\Markdown\Tokens\BoldAndItalicToken; use Tempest\Markdown\Tokens\BoldToken; final class BoldRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '*_'; private(set) string $stopChar = '*_'; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + + $this->removeTokenSupport(BoldToken::class); + $this->removeTokenSupport(BoldAndItalicToken::class); + } + public function shouldParse(Parser $parser): bool { $stopToken = $parser->lookaheadUntil('*_')[0] ?? null; diff --git a/src/Rules/CodeRule.php b/src/Rules/CodeRule.php index 4a1b6cc..9f1966d 100644 --- a/src/Rules/CodeRule.php +++ b/src/Rules/CodeRule.php @@ -2,18 +2,27 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\CodeToken; final class CodeRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '`'; private(set) string $stopChar = '`'; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + } + public function shouldParse(Parser $parser): bool { return $parser->comesNext('`', 1); diff --git a/src/Rules/DivRule.php b/src/Rules/DivRule.php index 556640c..73d86c4 100644 --- a/src/Rules/DivRule.php +++ b/src/Rules/DivRule.php @@ -2,18 +2,27 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\DivToken; +use Tempest\Markdown\Tokens\ParagraphToken; final class DivRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + public string $stopChar = ':'; public string $firstChar = ':'; + public function __construct() + { + $this->addTokenSupport(ParagraphToken::class); + } + public function shouldParse(Parser $parser): bool { return $parser->comesNext(':::', 3); diff --git a/src/Rules/FrontMatterRule.php b/src/Rules/FrontMatterRule.php index 232835e..af0afb5 100644 --- a/src/Rules/FrontMatterRule.php +++ b/src/Rules/FrontMatterRule.php @@ -7,6 +7,7 @@ use Tempest\Markdown\Exceptions\FrontMatterCouldNotBeParsed; use Tempest\Markdown\Exceptions\FrontMatterShouldBeAnArray; use Tempest\Markdown\Exceptions\FrontMatterWasNotProperlyClosed; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -15,6 +16,8 @@ final class FrontMatterRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '-'; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/HeadingRule.php b/src/Rules/HeadingRule.php index edc05e7..3f8ca01 100644 --- a/src/Rules/HeadingRule.php +++ b/src/Rules/HeadingRule.php @@ -2,14 +2,18 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; use Tempest\Markdown\Token; +use Tempest\Markdown\Tokens\DivToken; use Tempest\Markdown\Tokens\HeadingToken; final class HeadingRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '#'; public function __construct( @@ -18,7 +22,9 @@ public function __construct( * content. An id written as `## Title ## id` is kept either way. */ public bool $generateIds = true, - ) {} + ) { + $this->addTokenSupport(DivToken::class); + } public function shouldParse(Parser $parser): bool { diff --git a/src/Rules/HtmlCommentRule.php b/src/Rules/HtmlCommentRule.php index 3513afc..625c022 100644 --- a/src/Rules/HtmlCommentRule.php +++ b/src/Rules/HtmlCommentRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -10,6 +11,8 @@ final class HtmlCommentRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '<'; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/HtmlRule.php b/src/Rules/HtmlRule.php index a56e0cc..51e47a3 100644 --- a/src/Rules/HtmlRule.php +++ b/src/Rules/HtmlRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -10,6 +11,8 @@ final class HtmlRule implements Rule, ProvidesFirstChar { + use IsRule; + /** * Elements whose content is raw text rather than Markdown. * diff --git a/src/Rules/ImageRule.php b/src/Rules/ImageRule.php index 7bd2bdc..bf28b35 100644 --- a/src/Rules/ImageRule.php +++ b/src/Rules/ImageRule.php @@ -4,18 +4,27 @@ use Tempest\Markdown\Exceptions\ImageSourceWasMissing; use Tempest\Markdown\Exceptions\ImageSourceWasNotClosed; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\ImageToken; final class ImageRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '!'; private(set) string $stopChar = '!'; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + } + public function shouldParse(Parser $parser): bool { return $parser->comesNext('![', 2); diff --git a/src/Rules/ItalicRule.php b/src/Rules/ItalicRule.php index 539970b..c7edc36 100644 --- a/src/Rules/ItalicRule.php +++ b/src/Rules/ItalicRule.php @@ -2,18 +2,31 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; +use Tempest\Markdown\Tokens\BoldAndItalicToken; use Tempest\Markdown\Tokens\ItalicToken; final class ItalicRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '*_'; private(set) string $stopChar = '*_'; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + + $this->removeTokenSupport(ItalicToken::class); + $this->removeTokenSupport(BoldAndItalicToken::class); + } + public function shouldParse(Parser $parser): bool { $stopToken = $parser->lookaheadUntil('*_')[0] ?? null; diff --git a/src/Rules/LinkRule.php b/src/Rules/LinkRule.php index 3c16b96..2c3f6d2 100644 --- a/src/Rules/LinkRule.php +++ b/src/Rules/LinkRule.php @@ -2,18 +2,29 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\LinkToken; final class LinkRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '['; private(set) string $stopChar = '['; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + + $this->removeTokenSupport(LinkToken::class); + } + public function shouldParse(Parser $parser): bool { return $parser->comesNext('[', 1); diff --git a/src/Rules/ListRule.php b/src/Rules/ListRule.php index 73704c0..65e0e71 100644 --- a/src/Rules/ListRule.php +++ b/src/Rules/ListRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -11,6 +12,8 @@ final class ListRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '-*+'; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/NewLineRule.php b/src/Rules/NewLineRule.php index 8bf42f5..a8d582b 100644 --- a/src/Rules/NewLineRule.php +++ b/src/Rules/NewLineRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -10,6 +11,8 @@ final class NewLineRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = "\n\r"; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/OrderedListRule.php b/src/Rules/OrderedListRule.php index 588673b..4a1245c 100644 --- a/src/Rules/OrderedListRule.php +++ b/src/Rules/OrderedListRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -11,6 +12,8 @@ final class OrderedListRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '0123456789'; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/ParagraphRule.php b/src/Rules/ParagraphRule.php index 707fb3f..239fd29 100644 --- a/src/Rules/ParagraphRule.php +++ b/src/Rules/ParagraphRule.php @@ -2,14 +2,17 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\Rule; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\HeadingToken; use Tempest\Markdown\Tokens\ParagraphToken; -final readonly class ParagraphRule implements Rule +final class ParagraphRule implements Rule { + use IsRule; + public function shouldParse(Parser $parser): bool { return true; diff --git a/src/Rules/PreRule.php b/src/Rules/PreRule.php index 7c8cc8d..ef6bc11 100644 --- a/src/Rules/PreRule.php +++ b/src/Rules/PreRule.php @@ -2,16 +2,27 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; use Tempest\Markdown\Token; +use Tempest\Markdown\Tokens\DivToken; +use Tempest\Markdown\Tokens\ParagraphToken; use Tempest\Markdown\Tokens\PreToken; final class PreRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '`~'; + public function __construct() + { + $this->addTokenSupport(DivToken::class); + $this->addTokenSupport(ParagraphToken::class); + } + public function shouldParse(Parser $parser): bool { return $parser->comesNext('```', 3) || $parser->comesNext('~~~', 3); diff --git a/src/Rules/QuoteRule.php b/src/Rules/QuoteRule.php index 90321ba..52f4fb2 100644 --- a/src/Rules/QuoteRule.php +++ b/src/Rules/QuoteRule.php @@ -2,18 +2,28 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; use Tempest\Markdown\Token; +use Tempest\Markdown\Tokens\DivToken; use Tempest\Markdown\Tokens\QuoteToken; final class QuoteRule implements Rule, ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '>'; private(set) string $stopChar = '>'; + public function __construct() + { + $this->addTokenSupport(DivToken::class); + $this->addTokenSupport(QuoteToken::class); + } + public function shouldParse(Parser $parser): bool { if (! $parser->comesNext('>', 1)) { diff --git a/src/Rules/RawRule.php b/src/Rules/RawRule.php index bc1ed13..f913411 100644 --- a/src/Rules/RawRule.php +++ b/src/Rules/RawRule.php @@ -2,13 +2,16 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\Rule; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\RawToken; -final readonly class RawRule implements Rule +final class RawRule implements Rule { + use IsRule; + public function shouldParse(Parser $parser): bool { return $parser->comesNext('@@', length: 2); diff --git a/src/Rules/SocialHandleRule.php b/src/Rules/SocialHandleRule.php index fbcf9a1..29d8245 100644 --- a/src/Rules/SocialHandleRule.php +++ b/src/Rules/SocialHandleRule.php @@ -4,10 +4,12 @@ use Tempest\Markdown\Exceptions\SocialHandlePlatformWasUnknown; use Tempest\Markdown\Exceptions\SocialHandleWasInvalid; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\LinkToken; @@ -20,9 +22,18 @@ final class SocialHandleRule implements ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '{'; private(set) string $stopChar = '{'; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + + $this->removeTokenSupport(LinkToken::class); + } + public function shouldParse(Parser $parser): bool { return ( diff --git a/src/Rules/StrikethroughRule.php b/src/Rules/StrikethroughRule.php index 2e9adc3..faf0955 100644 --- a/src/Rules/StrikethroughRule.php +++ b/src/Rules/StrikethroughRule.php @@ -2,10 +2,12 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\ProvidesStopChar; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\StrikethroughToken; use Tempest\Markdown\Tokens\TextToken; @@ -15,9 +17,18 @@ final class StrikethroughRule implements ProvidesFirstChar, ProvidesStopChar { + use IsRule; + private(set) string $firstChar = '~'; private(set) string $stopChar = '~'; + public function __construct() + { + $this->contexts = [RuleContext::INLINE]; + + $this->removeTokenSupport(StrikethroughToken::class); + } + public function shouldParse(Parser $parser): bool { return $parser->comesNext('~', 1); diff --git a/src/Rules/TableRule.php b/src/Rules/TableRule.php index c5e16f9..dd96ec9 100644 --- a/src/Rules/TableRule.php +++ b/src/Rules/TableRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -11,6 +12,8 @@ final class TableRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '|'; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/TextRule.php b/src/Rules/TextRule.php index e78f1e7..0c73735 100644 --- a/src/Rules/TextRule.php +++ b/src/Rules/TextRule.php @@ -2,17 +2,23 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\NeedsStopChars; use Tempest\Markdown\Parser; use Tempest\Markdown\Rule; +use Tempest\Markdown\RuleContext; use Tempest\Markdown\Token; use Tempest\Markdown\Tokens\TextToken; final class TextRule implements Rule, NeedsStopChars { + use IsRule; + public function __construct( public string $stopChars = '', - ) {} + ) { + $this->contexts = [RuleContext::INLINE]; + } public function shouldParse(Parser $parser): bool { diff --git a/src/Rules/ThickRulerRule.php b/src/Rules/ThickRulerRule.php index 881e8ec..fc4e648 100644 --- a/src/Rules/ThickRulerRule.php +++ b/src/Rules/ThickRulerRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -11,6 +12,8 @@ final class ThickRulerRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '='; public function shouldParse(Parser $parser): bool diff --git a/src/Rules/ThinRulerRule.php b/src/Rules/ThinRulerRule.php index 53f0b86..8e71a6d 100644 --- a/src/Rules/ThinRulerRule.php +++ b/src/Rules/ThinRulerRule.php @@ -2,6 +2,7 @@ namespace Tempest\Markdown\Rules; +use Tempest\Markdown\IsRule; use Tempest\Markdown\Parser; use Tempest\Markdown\ProvidesFirstChar; use Tempest\Markdown\Rule; @@ -11,6 +12,8 @@ final class ThinRulerRule implements Rule, ProvidesFirstChar { + use IsRule; + public string $firstChar = '-'; public function shouldParse(Parser $parser): bool diff --git a/src/Tokens/BoldAndItalicToken.php b/src/Tokens/BoldAndItalicToken.php index 271ee18..7773ace 100644 --- a/src/Tokens/BoldAndItalicToken.php +++ b/src/Tokens/BoldAndItalicToken.php @@ -3,12 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class BoldAndItalicToken implements Token @@ -20,14 +14,7 @@ public function __construct( public function parse(Parser $parser): string { $content = $parser - ->forToken($this, [ - new StrikethroughRule(), - new CodeRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->content); return "{$content}"; diff --git a/src/Tokens/BoldToken.php b/src/Tokens/BoldToken.php index cd2a8a0..2614c12 100644 --- a/src/Tokens/BoldToken.php +++ b/src/Tokens/BoldToken.php @@ -3,13 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\ItalicRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class BoldToken implements Token @@ -21,15 +14,7 @@ public function __construct( public function parse(Parser $parser): string { $content = $parser - ->forToken($this, [ - new ItalicRule(), - new StrikethroughRule(), - new CodeRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->content); return "{$content}"; diff --git a/src/Tokens/DivToken.php b/src/Tokens/DivToken.php index 0ea7470..2f19efd 100644 --- a/src/Tokens/DivToken.php +++ b/src/Tokens/DivToken.php @@ -3,18 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\BoldAndItalicRule; -use Tempest\Markdown\Rules\BoldRule; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\HeadingRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\ItalicRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\PreRule; -use Tempest\Markdown\Rules\QuoteRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class DivToken implements Token @@ -27,20 +15,7 @@ public function __construct( public function parse(Parser $parser): string { $content = $parser - ->forToken($this, [ - new HeadingRule(), - new QuoteRule(), - new BoldAndItalicRule(), - new BoldRule(), - new ItalicRule(), - new StrikethroughRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new PreRule(), - new CodeRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->content); $class = $this->class diff --git a/src/Tokens/HeadingToken.php b/src/Tokens/HeadingToken.php index 385f3b2..96c38e2 100644 --- a/src/Tokens/HeadingToken.php +++ b/src/Tokens/HeadingToken.php @@ -3,15 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\BoldAndItalicRule; -use Tempest\Markdown\Rules\BoldRule; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\ItalicRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class HeadingToken implements Token @@ -33,17 +24,7 @@ public function parse(Parser $parser): string } $content = $parser - ->forToken($this, [ - new BoldAndItalicRule(), - new BoldRule(), - new ItalicRule(), - new StrikethroughRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new CodeRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->content); return "<{$tag}{$id}>{$content}"; diff --git a/src/Tokens/HtmlToken.php b/src/Tokens/HtmlToken.php index 5663e04..a1ecfe3 100644 --- a/src/Tokens/HtmlToken.php +++ b/src/Tokens/HtmlToken.php @@ -3,15 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\BoldAndItalicRule; -use Tempest\Markdown\Rules\BoldRule; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\ItalicRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class HtmlToken implements Token @@ -30,17 +21,7 @@ public function parse(Parser $parser): string } return $parser - ->forToken($this, [ - new BoldAndItalicRule(), - new BoldRule(), - new ItalicRule(), - new StrikethroughRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new CodeRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->html) ->html; } diff --git a/src/Tokens/ItalicToken.php b/src/Tokens/ItalicToken.php index dceeb9e..aabbea1 100644 --- a/src/Tokens/ItalicToken.php +++ b/src/Tokens/ItalicToken.php @@ -3,13 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\BoldRule; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class ItalicToken implements Token @@ -21,15 +14,7 @@ public function __construct( public function parse(Parser $parser): string { $content = $parser - ->forToken($this, [ - new BoldRule(), - new StrikethroughRule(), - new CodeRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->content); return "{$content}"; diff --git a/src/Tokens/LinkToken.php b/src/Tokens/LinkToken.php index 7e8c856..785aee1 100644 --- a/src/Tokens/LinkToken.php +++ b/src/Tokens/LinkToken.php @@ -3,13 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\BoldAndItalicRule; -use Tempest\Markdown\Rules\BoldRule; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\ItalicRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class LinkToken implements Token @@ -28,15 +21,7 @@ public function parse(Parser $parser): string if ($this->parseContent) { $content = $parser - ->forToken($this, [ - new CodeRule(), - new BoldAndItalicRule(), - new BoldRule(), - new ItalicRule(), - new StrikethroughRule(), - new ImageRule(), - new TextRule(), - ]) + ->forToken($this) ->parse($this->content); } diff --git a/src/Tokens/ListToken.php b/src/Tokens/ListToken.php index e228ed3..3597f66 100644 --- a/src/Tokens/ListToken.php +++ b/src/Tokens/ListToken.php @@ -3,15 +3,6 @@ namespace Tempest\Markdown\Tokens; use Tempest\Markdown\Parser; -use Tempest\Markdown\Rules\BoldAndItalicRule; -use Tempest\Markdown\Rules\BoldRule; -use Tempest\Markdown\Rules\CodeRule; -use Tempest\Markdown\Rules\ImageRule; -use Tempest\Markdown\Rules\ItalicRule; -use Tempest\Markdown\Rules\LinkRule; -use Tempest\Markdown\Rules\SocialHandleRule; -use Tempest\Markdown\Rules\StrikethroughRule; -use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Token; final class ListToken implements Token @@ -23,17 +14,7 @@ public function __construct( public function parse(Parser $parser): string { - $parser = $parser->forToken($this, [ - new BoldAndItalicRule(), - new BoldRule(), - new ItalicRule(), - new StrikethroughRule(), - new LinkRule(), - new SocialHandleRule(), - new ImageRule(), - new CodeRule(), - new TextRule(), - ]); + $parser = $parser->forToken($this); $list = '