Skip to content

Commit 4fde140

Browse files
committed
feat(markdown): support parsing functions
1 parent 1137615 commit 4fde140

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/Markdown/MarkdownInitializer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use App\Markdown\CodeGroups\CodeGroupExtension;
1313
use App\Markdown\Symbols\AttributeParser;
1414
use App\Markdown\Symbols\FqcnParser;
15+
use App\Markdown\Symbols\FunctionParser;
1516
use App\Markdown\Symbols\HandleParser;
1617
use League\CommonMark\Environment\Environment;
1718
use League\CommonMark\Extension\Attributes\AttributesExtension;
@@ -48,6 +49,7 @@ public function initialize(Container $container): MarkdownConverter
4849
->addInlineParser(new TempestPackageParser())
4950
->addInlineParser(new FqcnParser())
5051
->addInlineParser(new AttributeParser())
52+
->addInlineParser(new FunctionParser())
5153
->addInlineParser(new HandleParser())
5254
->addRenderer(FencedCode::class, $codeBlockRenderer)
5355
->addRenderer(Code::class, new InlineCodeBlockRenderer($highlighter))
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace App\Markdown\Symbols;
4+
5+
use League\CommonMark\Extension\CommonMark\Node\Inline\Code;
6+
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
7+
use League\CommonMark\Parser\Inline\InlineParserInterface;
8+
use League\CommonMark\Parser\Inline\InlineParserMatch;
9+
use League\CommonMark\Parser\InlineParserContext;
10+
use Override;
11+
use ReflectionFunction;
12+
use Tempest\Support\Str\ImmutableString;
13+
use Throwable;
14+
15+
use function Tempest\Support\str;
16+
17+
final readonly class FunctionParser implements InlineParserInterface
18+
{
19+
#[Override]
20+
public function getMatchDefinition(): InlineParserMatch
21+
{
22+
return InlineParserMatch::regex("{(b)?`((?:\\\{1,2}\w+|\w+\\\{1,2})(?:\w+\\\{0,2})+)\(\)`}");
23+
}
24+
25+
#[Override]
26+
public function parse(InlineParserContext $inlineContext): bool
27+
{
28+
$cursor = $inlineContext->getCursor();
29+
$previousChar = $cursor->peek(-1);
30+
31+
if ($previousChar !== null && $previousChar !== ' ') {
32+
return false;
33+
}
34+
35+
$cursor->advanceBy($inlineContext->getFullMatchLength());
36+
37+
[$flag, $fqf] = $inlineContext->getSubMatches();
38+
39+
$reflection = $this->createReflectionFromFqf($fqf);
40+
$function = str($fqf)
41+
->stripStart('\\')
42+
->when($flag === 'b', fn (ImmutableString $s) => $s->afterLast('\\'))
43+
->append('()')
44+
->toString();
45+
46+
if (! $reflection) {
47+
$inlineContext->getContainer()->appendChild(new Code($function));
48+
49+
return true;
50+
}
51+
52+
$url = str($reflection->getFileName())
53+
->afterLast('tempest/framework/')
54+
->prepend('https://github.com/tempestphp/tempest-framework/blob/main/')
55+
->append("#L{$reflection->getStartLine()}-L{$reflection->getEndLine()}")
56+
->toString();
57+
58+
$link = new Link($url);
59+
$link->appendChild(new Code($function));
60+
$inlineContext->getContainer()->appendChild($link);
61+
62+
return true;
63+
}
64+
65+
private function createReflectionFromFqf(string $fqf): ?ReflectionFunction
66+
{
67+
try {
68+
return new ReflectionFunction($fqf);
69+
} catch (Throwable) {
70+
return null;
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)