thephpleague / commonmark

Highly-extensible PHP Markdown parser which fully supports the CommonMark and GFM specs.

Home Page:https://commonmark.thephpleague.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FrontMatter extension only supports \n line endings

SeriousKen opened this issue · comments

Version(s) affected

2.2

Description

The FrontMatter extension expects the document to use linux \n line endings and fails to split frontmatter and markdown when this is not the case. Both YAML and Markdown support all line endings.

How to reproduce

$markdown = new CommonMarkConverter();
$markdown->getEnvironment()->addExtension(new FrontMatterExtension());

$document = "---\r\ntitle: Hello World!\r\n---\r\n# This is some markdown";

$document = $markdown->convert($document);
echo $document->getContent();

Possible solution

final class FrontMatterParser implements FrontMatterParserInterface
{
    /** @psalm-readonly */
    private FrontMatterDataParserInterface $frontMatterParser;

    private const REGEX_FRONT_MATTER = '/^---\R.*?\R---\R/s';

    public function __construct(FrontMatterDataParserInterface $frontMatterParser)
    {
        $this->frontMatterParser = $frontMatterParser;
    }

    public function parse(string $markdownContent): MarkdownInputWithFrontMatter
    {
        $cursor = new Cursor($markdownContent);

        // Locate the front matter
        $frontMatter = $cursor->match(self::REGEX_FRONT_MATTER);
        if ($frontMatter === null) {
            return new MarkdownInputWithFrontMatter($markdownContent);
        }
        
        // Trim the last line (ending ---s and newline)
        $frontMatter = preg_replace('/---\R$/', '', $frontMatter);

        // Parse the resulting YAML data
        $data = $this->frontMatterParser->parse($frontMatter);

        // Advance through any remaining newlines which separated the front matter from the Markdown text
        $trailingNewlines = $cursor->match('/^\R+/');

        // Calculate how many lines the Markdown is offset from the front matter by counting the number of newlines
        // Don't forget to add 1 because we stripped one out when trimming the trailing delims
        $lineOffset = \preg_match_all('/\R/', $frontMatter . $trailingNewlines) + 1;

        return new MarkdownInputWithFrontMatter($cursor->getRemainder(), $lineOffset, $data);
    }
}

Additional context

No response

Did this project help you today? Did it make you happy in any way?

No response

Thanks for the bug report and proposed solution! I've released the fix in versions 2.0.4, 2.1.3, and 2.2.3. Cheers!