1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 *
8 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
9 *  - (c) John MacFarlane
10 *
11 * For the full copyright and license information, please view the LICENSE
12 * file that was distributed with this source code.
13 */
14
15namespace League\CommonMark\Block\Parser;
16
17use League\CommonMark\Block\Element\Heading;
18use League\CommonMark\Block\Element\Paragraph;
19use League\CommonMark\ContextInterface;
20use League\CommonMark\Cursor;
21use League\CommonMark\Reference\ReferenceParser;
22use League\CommonMark\Util\RegexHelper;
23
24final class SetExtHeadingParser implements BlockParserInterface
25{
26    public function parse(ContextInterface $context, Cursor $cursor): bool
27    {
28        if ($cursor->isIndented()) {
29            return false;
30        }
31
32        if (!($context->getContainer() instanceof Paragraph)) {
33            return false;
34        }
35
36        $match = RegexHelper::matchFirst('/^(?:=+|-+)[ \t]*$/', $cursor->getLine(), $cursor->getNextNonSpacePosition());
37        if ($match === null) {
38            return false;
39        }
40
41        $level = $match[0][0] === '=' ? 1 : 2;
42        $strings = $context->getContainer()->getStrings();
43
44        $strings = $this->resolveReferenceLinkDefinitions($strings, $context->getReferenceParser());
45        if (empty($strings)) {
46            return false;
47        }
48
49        $context->replaceContainerBlock(new Heading($level, $strings));
50
51        return true;
52    }
53
54    /**
55     * Resolve reference link definition
56     *
57     * @see https://github.com/commonmark/commonmark.js/commit/993bbe335931af847460effa99b2411eb643577d
58     *
59     * @param string[]        $strings
60     * @param ReferenceParser $referenceParser
61     *
62     * @return string[]
63     */
64    private function resolveReferenceLinkDefinitions(array $strings, ReferenceParser $referenceParser): array
65    {
66        foreach ($strings as &$string) {
67            $cursor = new Cursor($string);
68            while ($cursor->getCharacter() === '[' && $referenceParser->parse($cursor)) {
69                $string = $cursor->getRemainder();
70            }
71
72            if ($string !== '') {
73                break;
74            }
75        }
76
77        return \array_filter($strings, function ($s) {
78            return $s !== '';
79        });
80    }
81}
82