diff --git a/src/Rules/ParagraphRule.php b/src/Rules/ParagraphRule.php index 57af132..98c4785 100644 --- a/src/Rules/ParagraphRule.php +++ b/src/Rules/ParagraphRule.php @@ -5,6 +5,7 @@ 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 @@ -34,6 +35,14 @@ public function parse(Parser $parser): Token $content .= $parser->consumeWhile(Parser::NEW_LINE); } + $trimmed = rtrim($content, "\r\n"); + if (preg_match('/\A(.+)\r?\n {0,3}(=+|-+)[ \t]*\z/s', $trimmed, $matches)) { + $heading = trim($matches[1]); + $id = mb_strtolower($heading) |> (fn (string $value) => trim(preg_replace('/[^\p{L}\p{N}]+/u', '-', $value) ?? '', '-')); + + return new HeadingToken($heading, $matches[2][0] === '=' ? 1 : 2, $id); + } + return new ParagraphToken($content); } } diff --git a/tests/Rules/ParagraphRuleTest.php b/tests/Rules/ParagraphRuleTest.php index 98f498f..16daa5e 100644 --- a/tests/Rules/ParagraphRuleTest.php +++ b/tests/Rules/ParagraphRuleTest.php @@ -41,4 +41,21 @@ public function test_paragraph_without_trailing_newline(): void $this->assertSame('
Hello, world!
', $html); } + + #[Test] + public function test_setext_headings(): void + { + $parser = new Parser(highlighter: null, rules: [new ParagraphRule()]); + + $this->assertSame('