1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the league/commonmark package. 7 * 8 * (c) Colin O'Dell <colinodell@gmail.com> 9 * 10 * For the full copyright and license information, please view the LICENSE 11 * file that was distributed with this source code. 12 */ 13 14namespace League\CommonMark\Extension\FrontMatter; 15 16use League\CommonMark\Extension\FrontMatter\Data\FrontMatterDataParserInterface; 17use League\CommonMark\Extension\FrontMatter\Exception\InvalidFrontMatterException; 18use League\CommonMark\Extension\FrontMatter\Input\MarkdownInputWithFrontMatter; 19use League\CommonMark\Parser\Cursor; 20 21final class FrontMatterParser implements FrontMatterParserInterface 22{ 23 /** @psalm-readonly */ 24 private FrontMatterDataParserInterface $frontMatterParser; 25 26 private const REGEX_FRONT_MATTER = '/^---\\R.*?\\R---\\R/s'; 27 28 public function __construct(FrontMatterDataParserInterface $frontMatterParser) 29 { 30 $this->frontMatterParser = $frontMatterParser; 31 } 32 33 /** 34 * @throws InvalidFrontMatterException if the front matter cannot be parsed 35 */ 36 public function parse(string $markdownContent): MarkdownInputWithFrontMatter 37 { 38 $cursor = new Cursor($markdownContent); 39 40 // Locate the front matter 41 $frontMatter = $cursor->match(self::REGEX_FRONT_MATTER); 42 if ($frontMatter === null) { 43 return new MarkdownInputWithFrontMatter($markdownContent); 44 } 45 46 // Trim the last line (ending ---s and newline) 47 $frontMatter = \preg_replace('/---\R$/', '', $frontMatter); 48 if ($frontMatter === null) { 49 return new MarkdownInputWithFrontMatter($markdownContent); 50 } 51 52 // Parse the resulting YAML data 53 $data = $this->frontMatterParser->parse($frontMatter); 54 55 // Advance through any remaining newlines which separated the front matter from the Markdown text 56 $trailingNewlines = $cursor->match('/^\R+/'); 57 58 // Calculate how many lines the Markdown is offset from the front matter by counting the number of newlines 59 // Don't forget to add 1 because we stripped one out when trimming the trailing delims 60 $lineOffset = \preg_match_all('/\R/', $frontMatter . $trailingNewlines) + 1; 61 62 return new MarkdownInputWithFrontMatter($cursor->getRemainder(), $lineOffset, $data); 63 } 64} 65