Completed
Push — master ( 742fba...7a6aee )
by Colin
14s
created

src/Block/Parser/ListParser.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
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
15
namespace League\CommonMark\Block\Parser;
16
17
use League\CommonMark\Block\Element\ListBlock;
18
use League\CommonMark\Block\Element\ListData;
19
use League\CommonMark\Block\Element\ListItem;
20
use League\CommonMark\Block\Element\Paragraph;
21
use League\CommonMark\ContextInterface;
22
use League\CommonMark\Cursor;
23
use League\CommonMark\Util\RegexHelper;
24
25
class ListParser extends AbstractBlockParser
26
{
27
    /**
28
     * @param ContextInterface $context
29
     * @param Cursor           $cursor
30
     *
31
     * @return bool
32
     */
33 1716
    public function parse(ContextInterface $context, Cursor $cursor)
34
    {
35 1716
        if ($cursor->isIndented() && !($context->getContainer() instanceof ListBlock)) {
36 168
            return false;
37
        }
38
39 1653
        $tmpCursor = clone $cursor;
40 1653
        $tmpCursor->advanceToNextNonSpaceOrTab();
41 1653
        $rest = $tmpCursor->getRemainder();
42
43 1653
        $data = new ListData();
44 1653
        $data->markerOffset = $cursor->getIndent();
45
46 1653
        if ($matches = RegexHelper::matchAll('/^[*+-]/', $rest)) {
47 405
            $data->type = ListBlock::TYPE_UNORDERED;
48 405
            $data->delimiter = null;
49 405
            $data->bulletChar = $matches[0][0];
50 1590
        } elseif (($matches = RegexHelper::matchAll('/^(\d{1,9})([.)])/', $rest)) && (!($context->getContainer() instanceof Paragraph) || $matches[1] === '1')) {
51 84
            $data->type = ListBlock::TYPE_ORDERED;
52 84
            $data->start = intval($matches[1]);
53 84
            $data->delimiter = $matches[2];
54 84
            $data->bulletChar = null;
55 56
        } else {
56 1464
            return false;
57
        }
58
59 468
        $markerLength = strlen($matches[0]);
60
61
        // Make sure we have spaces after
62 468
        $nextChar = $tmpCursor->peek($markerLength);
63 468
        if (!($nextChar === null || $nextChar === "\t" || $nextChar === ' ')) {
64 228
            return false;
65
        }
66
67
        // If it interrupts paragraph, make sure first line isn't blank
68 243
        if ($context->getContainer() instanceof Paragraph && !RegexHelper::matchAt(RegexHelper::REGEX_NON_SPACE, $rest, $markerLength)) {
69 6
            return false;
70
        }
71
72
        // We've got a match! Advance offset and calculate padding
73 237
        $cursor->advanceToNextNonSpaceOrTab(); // to start of marker
74 237
        $cursor->advanceBy($markerLength, true); // to end of marker
75 237
        $data->padding = $this->calculateListMarkerPadding($cursor, $markerLength);
76
77
        // add the list if needed
78 237
        $container = $context->getContainer();
79 237
        if (!$container || !($context->getContainer() instanceof ListBlock) || !$data->equals($container->getListData())) {
0 ignored issues
show
The method getListData() does not seem to exist on object<League\CommonMark\Block\Element\Paragraph>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
80 237
            $context->addBlock(new ListBlock($data));
81 158
        }
82
83
        // add the list item
84 237
        $context->addBlock(new ListItem($data));
85
86 237
        return true;
87
    }
88
89
    /**
90
     * @param Cursor $cursor
91
     * @param int    $markerLength
92
     *
93
     * @return int
94
     */
95 237
    private function calculateListMarkerPadding(Cursor $cursor, $markerLength)
96
    {
97 237
        $start = $cursor->saveState();
98 237
        $spacesStartCol = $cursor->getColumn();
99
100 237
        while ($cursor->getColumn() - $spacesStartCol < 5) {
101 237
            if (!$cursor->advanceBySpaceOrTab()) {
102 228
                break;
103
            }
104 152
        }
105
106 237
        $blankItem = $cursor->peek() === null;
107 237
        $spacesAfterMarker = $cursor->getColumn() - $spacesStartCol;
108
109 237
        if ($spacesAfterMarker >= 5 || $spacesAfterMarker < 1 || $blankItem) {
110 72
            $cursor->restoreState($start);
111 72
            $cursor->advanceBySpaceOrTab();
112
113 72
            return $markerLength + 1;
114
        }
115
116 180
        return $markerLength + $spacesAfterMarker;
117
    }
118
}
119