Completed
Push — master ( afd04b...3b4c22 )
by Colin
10s
created

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

Check for loose comparison of integers.

Best Practice Bug Major

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 (preg_match('/^[*+-]/', $rest) === 1) {
47 405
            $data->type = ListBlock::TYPE_UNORDERED;
48 405
            $data->delimiter = null;
49 405
            $data->bulletChar = $rest[0];
50 405
            $markerLength = 1;
51 1527
        } elseif (($matches = RegexHelper::matchAll('/^(\d{1,9})([.)])/', $rest)) && (!($context->getContainer() instanceof Paragraph) || $matches[1] === '1')) {
52 84
            $data->type = ListBlock::TYPE_ORDERED;
53 84
            $data->start = (int) $matches[1];
54 84
            $data->delimiter = $matches[2];
55 84
            $data->bulletChar = null;
56 84
            $markerLength = strlen($matches[0]);
57 28
        } else {
58 1464
            return false;
59
        }
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
        $container = $context->getContainer();
69 243
        if ($container instanceof Paragraph && !RegexHelper::matchAt(RegexHelper::REGEX_NON_SPACE, $rest, $markerLength)) {
0 ignored issues
show
Bug Best Practice introduced by Colin O'Dell
The expression \League\CommonMark\Util\..., $rest, $markerLength) of type null|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
70 6
            return false;
71
        }
72
73
        // We've got a match! Advance offset and calculate padding
74 237
        $cursor->advanceToNextNonSpaceOrTab(); // to start of marker
75 237
        $cursor->advanceBy($markerLength, true); // to end of marker
76 237
        $data->padding = $this->calculateListMarkerPadding($cursor, $markerLength);
77
78
        // add the list if needed
79 237
        if (!$container || !($container instanceof ListBlock) || !$data->equals($container->getListData())) {
80 237
            $context->addBlock(new ListBlock($data));
81 79
        }
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 76
        }
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