TableStartParser::parseSeparator()   C
last analyzed

Complexity

Conditions 14
Paths 32

Size

Total Lines 63
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 14.2288

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 38
c 1
b 0
f 0
dl 0
loc 63
ccs 34
cts 38
cp 0.8947
rs 6.2666
cc 14
nc 32
nop 1
crap 14.2288

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This is part of the league/commonmark package.
7
 *
8
 * (c) Martin Hasoň <[email protected]>
9
 * (c) Webuni s.r.o. <[email protected]>
10
 * (c) Colin O'Dell <[email protected]>
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
16
namespace League\CommonMark\Extension\Table;
17
18
use League\CommonMark\Parser\Block\BlockStart;
19
use League\CommonMark\Parser\Block\BlockStartParserInterface;
20
use League\CommonMark\Parser\Block\ParagraphParser;
21
use League\CommonMark\Parser\Cursor;
22
use League\CommonMark\Parser\MarkdownParserStateInterface;
23
24
final class TableStartParser implements BlockStartParserInterface
25
{
26 111
    public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart
27
    {
28 111
        $paragraph = $parserState->getParagraphContent();
29 111
        if ($paragraph === null || \strpos($paragraph, '|') === false) {
30 90
            return BlockStart::none();
31
        }
32
33 81
        $columns = self::parseSeparator($cursor);
34 81
        if (\count($columns) === 0) {
35 3
            return BlockStart::none();
36
        }
37
38 81
        $lines    = \explode("\n", $paragraph);
39 81
        $lastLine = \array_pop($lines);
40
41 81
        $headerCells = TableParser::split($lastLine);
42 81
        if (\count($headerCells) > \count($columns)) {
43 3
            return BlockStart::none();
44
        }
45
46 78
        $cursor->advanceToEnd();
47
48 78
        $parsers = [];
49
50 78
        if (\count($lines) > 0) {
51 9
            $p = new ParagraphParser();
52 9
            $p->addLine(\implode("\n", $lines));
53 9
            $parsers[] = $p;
54
        }
55
56 78
        $parsers[] = new TableParser($columns, $headerCells);
57
58 78
        return BlockStart::of(...$parsers)
59 78
            ->at($cursor)
60 78
            ->replaceActiveBlockParser();
61
    }
62
63
    /**
64
     * @return array<int, string|null>
65
     *
66
     * @psalm-return list<string|null>
67
     */
68 81
    private static function parseSeparator(Cursor $cursor): array
69
    {
70 81
        $columns = [];
71 81
        $pipes   = 0;
72 81
        $valid   = false;
73
74 81
        while (! $cursor->isAtEnd()) {
75 81
            switch ($c = $cursor->getCharacter()) {
76 81
                case '|':
77 81
                    $cursor->advanceBy(1);
78 81
                    $pipes++;
79 81
                    if ($pipes > 1) {
80
                        // More than one adjacent pipe not allowed
81
                        return [];
82
                    }
83
84
                    // Need at least one pipe, even for a one-column table
85 81
                    $valid = true;
86 81
                    break;
87 81
                case '-':
88 72
                case ':':
89 81
                    if ($pipes === 0 && \count($columns) > 0) {
90
                        // Need a pipe after the first column (first column doesn't need to start with one)
91
                        return [];
92
                    }
93
94 81
                    $left  = false;
95 81
                    $right = false;
96 81
                    if ($c === ':') {
97 15
                        $left = true;
98 15
                        $cursor->advanceBy(1);
99
                    }
100
101 81
                    if ($cursor->match('/^-+/') === null) {
102
                        // Need at least one dash
103
                        return [];
104
                    }
105
106 81
                    if ($cursor->getCharacter() === ':') {
107 9
                        $right = true;
108 9
                        $cursor->advanceBy(1);
109
                    }
110
111 81
                    $columns[] = self::getAlignment($left, $right);
112
                    // Next, need another pipe
113 81
                    $pipes = 0;
114 81
                    break;
115 69
                case ' ':
116 3
                case "\t":
117
                    // White space is allowed between pipes and columns
118 69
                    $cursor->advanceToNextNonSpaceOrTab();
119 69
                    break;
120
                default:
121
                    // Any other character is invalid
122 3
                    return [];
123
            }
124
        }
125
126 81
        if (! $valid) {
127
            return [];
128
        }
129
130 81
        return $columns;
131
    }
132
133
    /**
134
     * @psalm-pure
135
     */
136 81
    private static function getAlignment(bool $left, bool $right): ?string
137
    {
138 81
        if ($left && $right) {
139 9
            return TableCell::ALIGN_CENTER;
140
        }
141
142 81
        if ($left) {
143 9
            return TableCell::ALIGN_LEFT;
144
        }
145
146 78
        if ($right) {
147 9
            return TableCell::ALIGN_RIGHT;
148
        }
149
150 72
        return null;
151
    }
152
}
153