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 | final class ListParser implements BlockParserInterface |
||
26 | { |
||
27 | /** |
||
28 | * @param ContextInterface $context |
||
29 | * @param Cursor $cursor |
||
30 | * |
||
31 | * @return bool |
||
32 | */ |
||
33 | 1836 | public function parse(ContextInterface $context, Cursor $cursor): bool |
|
34 | { |
||
35 | 1836 | if ($cursor->isIndented() && !($context->getContainer() instanceof ListBlock)) { |
|
36 | 168 | return false; |
|
37 | } |
||
38 | |||
39 | 1773 | $indent = $cursor->getIndent(); |
|
40 | 1773 | if ($indent >= 4) { |
|
41 | 12 | return false; |
|
42 | } |
||
43 | |||
44 | 1773 | $tmpCursor = clone $cursor; |
|
45 | 1773 | $tmpCursor->advanceToNextNonSpaceOrTab(); |
|
46 | 1773 | $rest = $tmpCursor->getRemainder(); |
|
47 | |||
48 | 1773 | if (\preg_match('/^[*+-]/', $rest) === 1) { |
|
49 | 417 | $data = new ListData(); |
|
50 | 417 | $data->markerOffset = $indent; |
|
51 | 417 | $data->type = ListBlock::TYPE_UNORDERED; |
|
52 | 417 | $data->delimiter = null; |
|
53 | 417 | $data->bulletChar = $rest[0]; |
|
54 | 417 | $markerLength = 1; |
|
55 | 1581 | } elseif (($matches = RegexHelper::matchAll('/^(\d{1,9})([.)])/', $rest)) && (!($context->getContainer() instanceof Paragraph) || $matches[1] === '1')) { |
|
56 | 87 | $data = new ListData(); |
|
57 | 87 | $data->markerOffset = $indent; |
|
58 | 87 | $data->type = ListBlock::TYPE_ORDERED; |
|
59 | 87 | $data->start = (int) $matches[1]; |
|
60 | 87 | $data->delimiter = $matches[2]; |
|
61 | 87 | $data->bulletChar = null; |
|
62 | 87 | $markerLength = \strlen($matches[0]); |
|
63 | } else { |
||
64 | 1581 | return false; |
|
65 | } |
||
66 | |||
67 | // Make sure we have spaces after |
||
68 | 483 | $nextChar = $tmpCursor->peek($markerLength); |
|
69 | 483 | if (!($nextChar === null || $nextChar === "\t" || $nextChar === ' ')) { |
|
70 | 234 | return false; |
|
71 | } |
||
72 | |||
73 | // If it interrupts paragraph, make sure first line isn't blank |
||
74 | 252 | $container = $context->getContainer(); |
|
75 | 252 | if ($container instanceof Paragraph && !RegexHelper::matchAt(RegexHelper::REGEX_NON_SPACE, $rest, $markerLength)) { |
|
0 ignored issues
–
show
|
|||
76 | 6 | return false; |
|
77 | } |
||
78 | |||
79 | // We've got a match! Advance offset and calculate padding |
||
80 | 246 | $cursor->advanceToNextNonSpaceOrTab(); // to start of marker |
|
81 | 246 | $cursor->advanceBy($markerLength, true); // to end of marker |
|
82 | 246 | $data->padding = $this->calculateListMarkerPadding($cursor, $markerLength); |
|
83 | |||
84 | // add the list if needed |
||
85 | 246 | if (!($container instanceof ListBlock) || !$data->equals($container->getListData())) { |
|
86 | 246 | $context->addBlock(new ListBlock($data)); |
|
87 | } |
||
88 | |||
89 | // add the list item |
||
90 | 246 | $context->addBlock(new ListItem($data)); |
|
91 | |||
92 | 246 | return true; |
|
93 | } |
||
94 | |||
95 | /** |
||
96 | * @param Cursor $cursor |
||
97 | * @param int $markerLength |
||
98 | * |
||
99 | * @return int |
||
100 | */ |
||
101 | 246 | private function calculateListMarkerPadding(Cursor $cursor, int $markerLength): int |
|
102 | { |
||
103 | 246 | $start = $cursor->saveState(); |
|
104 | 246 | $spacesStartCol = $cursor->getColumn(); |
|
105 | |||
106 | 246 | while ($cursor->getColumn() - $spacesStartCol < 5) { |
|
107 | 246 | if (!$cursor->advanceBySpaceOrTab()) { |
|
108 | 237 | break; |
|
109 | } |
||
110 | } |
||
111 | |||
112 | 246 | $blankItem = $cursor->peek() === null; |
|
113 | 246 | $spacesAfterMarker = $cursor->getColumn() - $spacesStartCol; |
|
114 | |||
115 | 246 | if ($spacesAfterMarker >= 5 || $spacesAfterMarker < 1 || $blankItem) { |
|
116 | 78 | $cursor->restoreState($start); |
|
117 | 78 | $cursor->advanceBySpaceOrTab(); |
|
118 | |||
119 | 78 | return $markerLength + 1; |
|
120 | } |
||
121 | |||
122 | 183 | return $markerLength + $spacesAfterMarker; |
|
123 | } |
||
124 | } |
||
125 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
integer
values, zero is a special case, in particular the following results might be unexpected: