Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/Rules/ParagraphRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
17 changes: 17 additions & 0 deletions tests/Rules/ParagraphRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,21 @@ public function test_paragraph_without_trailing_newline(): void

$this->assertSame('<p>Hello, world!</p>', $html);
}

#[Test]
public function test_setext_headings(): void
{
$parser = new Parser(highlighter: null, rules: [new ParagraphRule()]);

$this->assertSame('<h1 id="first-heading">First heading</h1>', (string) $parser->parse("First heading\n===="));
$this->assertSame('<h2 id="second-heading">Second heading</h2>', (string) $parser->parse("Second heading\n-----\n"));
}

#[Test]
public function test_setext_heading_can_span_multiple_lines(): void
{
$parser = new Parser(highlighter: null, rules: [new ParagraphRule()]);

$this->assertSame("<h2 id=\"first-second\">First\nSecond</h2>", (string) $parser->parse("First\nSecond\n---"));
}
}
Loading