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
1 change: 1 addition & 0 deletions mago.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ interface-name = { psr = false }
trait-name = { psr = false }
class-name = { psr = false }
literal-named-argument = { enabled = false } # todo
no-insecure-comparison = { enabled = false }
no-error-control-operator = { enabled = false }
too-many-methods = { enabled = false }
kan-defect = { enabled = false }
Expand Down
24 changes: 18 additions & 6 deletions src/Rules/BoldRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,31 @@
final class BoldRule implements Rule, ProvidesFirstChar, ProvidesStopChar
{
private(set) string $firstChar = '*_';
private(set) string $stopChar = '_*';
private(set) string $stopChar = '*_';

public function shouldParse(Parser $parser): bool
{
if ($parser->comesNext('**', length: 2)) {
return ! $parser->comesNext('*', length: 1, offset: 2);
$stopToken = $parser->lookaheadUntil('*_')[0] ?? null;

if (! $stopToken) {
return false;
}

$lookahead = $parser->lookaheadUntil($stopToken, $stopToken, $stopToken, $stopToken);

if (count($lookahead) !== 4) {
return false;
}

if ($parser->comesNext('__', length: 2)) {
return ! $parser->comesNext('_', length: 1, offset: 2);
$content = $lookahead[2];

$lastChar = substr($content, strlen($content) - 1, 1);

if ($lastChar !== $stopToken) {
return false;
}

return false;
return true;
}

public function parse(Parser $parser): Token
Expand Down
27 changes: 22 additions & 5 deletions src/Rules/ItalicRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,32 @@ final class ItalicRule implements Rule, ProvidesFirstChar, ProvidesStopChar

public function shouldParse(Parser $parser): bool
{
if ($parser->comesNext('_', length: 1)) {
return ! $parser->comesNext('_', length: 1, offset: 1);
$stopToken = $parser->lookaheadUntil('*_')[0] ?? null;

if (! $stopToken) {
return false;
}

$lookahead = $parser->lookaheadUntil($stopToken, $stopToken);

if (count($lookahead) !== 2) {
return false;
}

$end = $lookahead[1];

$firstChar = substr($end, 0, 1);
$lastChar = substr($end, strlen($end) - 1, 1);

if ($firstChar === $stopToken) {
return false;
}

if ($parser->comesNext('*', length: 1)) {
return ! $parser->comesNext('*', length: 1, offset: 1);
if ($lastChar !== $stopToken) {
return false;
}

return false;
return true;
}

public function parse(Parser $parser): Token
Expand Down
32 changes: 32 additions & 0 deletions tests/Rules/BoldAndItalicRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,38 @@ public function test_triple_underscore_bold_and_italic(): void
$this->assertSame('<strong><em>text</em></strong>', $html);
}

#[Test]
public function test_single_underscore_double_asterisk(): void
{
$html = (string) new Parser(highlighter: null, rules: [new BoldAndItalicRule(), new BoldRule(), new ItalicRule()])->parse('_**text**_');

$this->assertSame('<em><strong>text</strong></em>', $html);
}

#[Test]
public function test_single_asterisk_double_underscore(): void
{
$html = (string) new Parser(highlighter: null, rules: [new BoldAndItalicRule(), new BoldRule(), new ItalicRule()])->parse('*__text__*');

$this->assertSame('<em><strong>text</strong></em>', $html);
}

#[Test]
public function test_double_underscore_single_asterisk(): void
{
$html = (string) new Parser(highlighter: null, rules: [new BoldAndItalicRule(), new BoldRule(), new ItalicRule()])->parse('__*text*__');

$this->assertSame('<strong><em>text</em></strong>', $html);
}

#[Test]
public function test_double_asterisk_single_underscore(): void
{
$html = (string) new Parser(highlighter: null, rules: [new BoldAndItalicRule(), new BoldRule(), new ItalicRule()])->parse('**_text_**');

$this->assertSame('<strong><em>text</em></strong>', $html);
}

#[Test]
public function test_does_not_lex_double_asterisk(): void
{
Expand Down
21 changes: 20 additions & 1 deletion tests/Rules/BoldRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use PHPUnit\Framework\Attributes\Test;
use Tempest\Markdown\Parser;
use Tempest\Markdown\Rules\BoldRule;
use Tempest\Markdown\Rules\ItalicRule;
use Tempest\Markdown\Rules\NewLineRule;
use Tempest\Markdown\Rules\ParagraphRule;
use Tempest\Markdown\Tests\ParserTestCase;

class BoldRuleTest extends ParserTestCase
Expand All @@ -17,10 +20,18 @@ public function test_lex_double_asterisk(): void
$this->assertSame('<strong>bold</strong>', $html);
}

#[Test]
public function test_double_asterisk_must_be_terminated(): void
{
$html = (string) new Parser(highlighter: null, rules: [new NewLineRule(), new BoldRule(), new ParagraphRule()])->parse("Hello**world\n\nHi");

$this->assertSame("<p>Hello**world</p>\n\n<p>Hi</p>", $html);
}

#[Test]
public function test_lex_asterisk_with_underscore(): void
{
$html = (string) new Parser(highlighter: null, rules: [new BoldRule()])->parse('**_bold_**');
$html = (string) new Parser(highlighter: null, rules: [new BoldRule(), new ItalicRule()])->parse('**_bold_**');

$this->assertSame('<strong><em>bold</em></strong>', $html);
}
Expand All @@ -41,6 +52,14 @@ public function test_lex_double_underscore(): void
$this->assertSame('<strong>bold</strong>', $html);
}

#[Test]
public function test_double_underscore_must_be_terminated(): void
{
$html = (string) new Parser(highlighter: null, rules: [new NewLineRule(), new BoldRule(), new ParagraphRule()])->parse("Hello__world\n\nHi");

$this->assertSame("<p>Hello__world</p>\n\n<p>Hi</p>", $html);
}

#[Test]
public function test_does_not_lex_single_underscore(): void
{
Expand Down
18 changes: 18 additions & 0 deletions tests/Rules/ItalicRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use PHPUnit\Framework\Attributes\Test;
use Tempest\Markdown\Parser;
use Tempest\Markdown\Rules\ItalicRule;
use Tempest\Markdown\Rules\NewLineRule;
use Tempest\Markdown\Rules\ParagraphRule;
use Tempest\Markdown\Tests\ParserTestCase;

class ItalicRuleTest extends ParserTestCase
Expand All @@ -17,11 +19,27 @@ public function test_lex_with_underscore(): void
$this->assertSame('<em>italic</em>', $html);
}

#[Test]
public function test_underscore_must_be_terminated(): void
{
$html = (string) new Parser(highlighter: null, rules: [new NewLineRule(), new ItalicRule(), new ParagraphRule()])->parse("Hello_world\n\nHi");

$this->assertSame("<p>Hello_world</p>\n\n<p>Hi</p>", $html);
}

#[Test]
public function test_lex_with_asterisk(): void
{
$html = (string) new Parser(highlighter: null, rules: [new ItalicRule()])->parse('*italic*');

$this->assertSame('<em>italic</em>', $html);
}

#[Test]
public function test_asterisk_must_be_terminated(): void
{
$html = (string) new Parser(highlighter: null, rules: [new NewLineRule(), new ItalicRule(), new ParagraphRule()])->parse("Hello*world\n\nHi");

$this->assertSame("<p>Hello*world</p>\n\n<p>Hi</p>", $html);
}
}
Loading