TableParser::parseRow()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 13
cts 13
cp 1
rs 8.6026
c 0
b 0
f 0
cc 7
nc 6
nop 3
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This is part of the league/commonmark-ext-table 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\Ext\Table;
17
18
use League\CommonMark\Block\Element\Paragraph;
19
use League\CommonMark\Block\Parser\BlockParserInterface;
20
use League\CommonMark\ContextInterface;
21
use League\CommonMark\Cursor;
22
use League\CommonMark\Util\RegexHelper;
23
24
final class TableParser implements BlockParserInterface
25
{
26
    const REGEXP_DEFINITION = '/(?: *(:?) *-+ *(:?) *)+(?=\||$)/';
27
    const REGEXP_CELLS = '/(?:`[^`]*`|\\\\\||\\\\|[^|`\\\\]+)+(?=\||$)/';
28
    const REGEXP_CAPTION = '/^\[(.+?)\](?:\[(.+)\])?\s*$/';
29
30 34
    public function parse(ContextInterface $context, Cursor $cursor): bool
31
    {
32 34
        $container = $context->getContainer();
33
34 34
        if (!$container instanceof Paragraph) {
35 34
            return false;
36
        }
37
38 34
        $lines = $container->getStrings();
39 34
        if (count($lines) < 1) {
40
            return false;
41
        }
42
43 34
        $expressionOffset = $cursor->getNextNonSpacePosition();
44
45 34
        $match = RegexHelper::matchAll(self::REGEXP_DEFINITION, $cursor->getLine(), $expressionOffset);
46 34
        if (null === $match) {
47 4
            return false;
48
        }
49
50 34
        $columns = $this->parseColumns($match);
51 34
        $head = $this->parseRow(trim((string) array_pop($lines)), $columns, TableCell::TYPE_HEAD);
52 34
        if (null === $head) {
53
            return false;
54
        }
55
56
        $table = new Table(function (Cursor $cursor, Table $table) use ($columns): bool {
57 34
            $row = $this->parseRow($cursor->getLine(), $columns);
58 34
            if (null === $row) {
59 12
                if (null !== $table->getCaption()) {
60 4
                    return false;
61
                }
62
63 12
                if (null !== ($caption = $this->parseCaption($cursor->getLine()))) {
64 4
                    $table->setCaption($caption);
65
66 4
                    return true;
67
                }
68
69 8
                return false;
70
            }
71
72 34
            $table->getBody()->appendChild($row);
73
74 34
            return true;
75 34
        });
76
77 34
        $table->getHead()->appendChild($head);
78
79 34
        if (count($lines) >= 1) {
80 4
            $paragraph = new Paragraph();
81 4
            foreach ($lines as $line) {
82 4
                $paragraph->addLine($line);
83
            }
84
85 4
            $context->replaceContainerBlock($paragraph);
86 4
            $context->addBlock($table);
87
        } else {
88 32
            $context->replaceContainerBlock($table);
89
        }
90
91 34
        return true;
92
    }
93
94 34
    private function parseColumns(array $match): array
95
    {
96 34
        $columns = [];
97 34
        foreach ((array) $match[0] as $i => $column) {
98 34
            if (isset($match[1][$i]) && $match[1][$i] && isset($match[2][$i]) && $match[2][$i]) {
99 6
                $columns[] = TableCell::ALIGN_CENTER;
100 34
            } elseif (isset($match[1][$i]) && $match[1][$i]) {
101 6
                $columns[] = TableCell::ALIGN_LEFT;
102 34
            } elseif (isset($match[2][$i]) && $match[2][$i]) {
103 6
                $columns[] = TableCell::ALIGN_RIGHT;
104
            } else {
105 32
                $columns[] = '';
106
            }
107
        }
108
109 34
        return $columns;
110
    }
111
112 34
    private function parseRow(string $line, array $columns, string $type = TableCell::TYPE_BODY): ?TableRow
113
    {
114 34
        $cells = RegexHelper::matchAll(self::REGEXP_CELLS, $line);
115
116 34
        if (null === $cells || $line === $cells[0]) {
117 12
            return null;
118
        }
119
120 34
        $i = 0;
121 34
        $row = new TableRow();
122 34
        foreach ((array) $cells[0] as $i => $cell) {
123 34
            if (!isset($columns[$i])) {
124 2
                return $row;
125
            }
126
127 34
            $row->appendChild(new TableCell(trim($cell), $type, isset($columns[$i]) ? $columns[$i] : null));
128
        }
129
130 34
        for ($j = count($columns) - 1; $j > $i; --$j) {
131 2
            $row->appendChild(new TableCell('', $type, null));
132
        }
133
134 34
        return $row;
135
    }
136
137 12
    private function parseCaption(string $line): ?TableCaption
138
    {
139 12
        $caption = RegexHelper::matchAll(self::REGEXP_CAPTION, $line);
140
141 12
        if (null === $caption) {
142 8
            return null;
143
        }
144
145 4
        return new TableCaption($caption[1], $caption[2]);
146
    }
147
}
148