Skip to content

Commit 5f76026

Browse files
jaapiolinawolf
authored andcommitted
[FEATURE] add basic support for tables
This patch includes basic parsing of markdown tables. Tables in markdown seem to be very limited in perspective to what ReST supports. Missing feature right now is the cell allignment, which can be applied in markdown. But not in ReST. refs #1086
1 parent ea0a4e4 commit 5f76026

File tree

5 files changed

+170
-1
lines changed

5 files changed

+170
-1
lines changed

packages/guides-markdown/resources/config/guides-markdown.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use phpDocumentor\Guides\Markdown\Parsers\ListItemParser;
1919
use phpDocumentor\Guides\Markdown\Parsers\ParagraphParser;
2020
use phpDocumentor\Guides\Markdown\Parsers\SeparatorParser;
21+
use phpDocumentor\Guides\Markdown\Parsers\Table\TableParser;
2122
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
2223
use Symfony\Component\String\Slugger\AsciiSlugger;
2324

@@ -58,6 +59,10 @@
5859
->tag('phpdoc.guides.markdown.parser.blockParser')
5960
->tag('phpdoc.guides.markdown.parser.subParser')
6061

62+
->set(TableParser::class)
63+
->arg('$subParsers', tagged_iterator('phpdoc.guides.markdown.parser.inlineParser'))
64+
->tag('phpdoc.guides.markdown.parser.blockParser')
65+
6166
->set(EmphasisParser::class)
6267
->arg('$inlineParsers', tagged_iterator('phpdoc.guides.markdown.parser.inlineParser'))
6368
->tag('phpdoc.guides.markdown.parser.inlineParser')

packages/guides-markdown/src/Markdown/MarkupLanguageParser.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use League\CommonMark\Environment\Environment as CommonMarkEnvironment;
1717
use League\CommonMark\Extension\Autolink\AutolinkExtension;
1818
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
19+
use League\CommonMark\Extension\Table\TableExtension;
1920
use League\CommonMark\Node\Block\Document;
2021
use League\CommonMark\Node\NodeWalker;
2122
use League\CommonMark\Parser\MarkdownParser;
@@ -46,6 +47,7 @@ public function __construct(
4647
) {
4748
$cmEnvironment = new CommonMarkEnvironment(['html_input' => 'strip']);
4849
$cmEnvironment->addExtension(new CommonMarkCoreExtension());
50+
$cmEnvironment->addExtension(new TableExtension());
4951
$cmEnvironment->addExtension(new AutolinkExtension());
5052
$this->markdownParser = new MarkdownParser($cmEnvironment);
5153
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Guides\Markdown;
15+
16+
use RuntimeException;
17+
18+
class ParserException extends RuntimeException
19+
{
20+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Guides\Markdown\Parsers\Table;
15+
16+
use League\CommonMark\Extension\Table\Table as CommonMarkTable;
17+
use League\CommonMark\Extension\Table\TableCell;
18+
use League\CommonMark\Extension\Table\TableRow as CommonMarkTableRow;
19+
use League\CommonMark\Extension\Table\TableSection;
20+
use League\CommonMark\Node\Node as CommonMarkNode;
21+
use League\CommonMark\Node\NodeWalker;
22+
use League\CommonMark\Node\NodeWalkerEvent;
23+
use phpDocumentor\Guides\Markdown\ParserException;
24+
use phpDocumentor\Guides\Markdown\Parsers\AbstractBlockParser;
25+
use phpDocumentor\Guides\MarkupLanguageParser as GuidesParser;
26+
use phpDocumentor\Guides\Nodes\Node;
27+
use phpDocumentor\Guides\Nodes\Table\TableColumn;
28+
use phpDocumentor\Guides\Nodes\Table\TableRow;
29+
use phpDocumentor\Guides\Nodes\TableNode;
30+
use Psr\Log\LoggerInterface;
31+
32+
use function sprintf;
33+
34+
/** @extends AbstractBlockParser<TableNode> */
35+
final class TableParser extends AbstractBlockParser
36+
{
37+
/** @param iterable<AbstractBlockParser<Node>> $subParsers */
38+
public function __construct(
39+
private readonly iterable $subParsers,
40+
private readonly LoggerInterface $logger,
41+
) {
42+
}
43+
44+
public function parse(GuidesParser $parser, NodeWalker $walker, CommonMarkNode $current): TableNode
45+
{
46+
$headerRows = [];
47+
$bodyRows = [];
48+
49+
while ($event = $walker->next()) {
50+
$commonMarkNode = $event->getNode();
51+
52+
if ($event->isEntering()) {
53+
if ($commonMarkNode instanceof TableSection) {
54+
if ($commonMarkNode->isHead()) {
55+
$headerRows = $this->parseTableSection($parser, $walker);
56+
continue;
57+
}
58+
59+
$bodyRows = $this->parseTableSection($parser, $walker);
60+
}
61+
62+
continue;
63+
}
64+
65+
if ($commonMarkNode instanceof CommonMarkTable) {
66+
return new TableNode($bodyRows, $headerRows);
67+
}
68+
69+
$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $commonMarkNode::class, 'Header'));
70+
}
71+
72+
throw new ParserException('Unexpected end of NodeWalker');
73+
}
74+
75+
public function supports(NodeWalkerEvent $event): bool
76+
{
77+
return $event->isEntering() && $event->getNode() instanceof CommonMarkTable;
78+
}
79+
80+
/** @return TableRow[] */
81+
private function parseTableSection(GuidesParser $parser, NodeWalker $walker): array
82+
{
83+
$rows = [];
84+
while ($event = $walker->next()) {
85+
if ($event->isEntering()) {
86+
$rows[] = $this->parseRow($parser, $walker);
87+
continue;
88+
}
89+
90+
if ($event->getNode() instanceof TableSection) {
91+
return $rows;
92+
}
93+
94+
$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $event->getNode()::class, 'Table section'));
95+
}
96+
97+
throw new ParserException('Unexpected end of NodeWalker');
98+
}
99+
100+
private function parseRow(GuidesParser $parser, NodeWalker $walker): TableRow
101+
{
102+
$cells = [];
103+
while ($event = $walker->next()) {
104+
if ($event->isEntering()) {
105+
$cells[] = $this->parseCell($parser, $walker);
106+
continue;
107+
}
108+
109+
if ($event->getNode() instanceof CommonMarkTableRow) {
110+
return new TableRow($cells);
111+
}
112+
113+
$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $event->getNode()::class, 'Table row'));
114+
}
115+
116+
throw new ParserException('Unexpected end of NodeWalker');
117+
}
118+
119+
private function parseCell(GuidesParser $parser, NodeWalker $walker): TableColumn
120+
{
121+
$nodes = [];
122+
while ($event = $walker->next()) {
123+
if ($event->isEntering()) {
124+
foreach ($this->subParsers as $subParser) {
125+
if ($subParser->supports($event)) {
126+
$nodes[] = $subParser->parse($parser, $walker, $event->getNode());
127+
break;
128+
}
129+
}
130+
131+
continue;
132+
}
133+
134+
if ($event->getNode() instanceof TableCell) {
135+
return new TableColumn('', 1, $nodes, 1);
136+
}
137+
138+
$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $event->getNode()::class, 'Table Cell'));
139+
}
140+
141+
throw new ParserException('Unexpected end of NodeWalker');
142+
}
143+
}

tests/Integration/tests/markdown/table-md/input/skip

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)