Skip to content

Commit

Permalink
Merge pull request #1112 from phpDocumentor/backport/1.x/pr-1104
Browse files Browse the repository at this point in the history
[1.x] [FEATURE] add basic support for tables
  • Loading branch information
phpdoc-bot authored Oct 2, 2024
2 parents 3f53a50 + b0b34a5 commit 2985f7f
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 21 deletions.
5 changes: 5 additions & 0 deletions packages/guides-markdown/resources/config/guides-markdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use phpDocumentor\Guides\Markdown\Parsers\ListItemParser;
use phpDocumentor\Guides\Markdown\Parsers\ParagraphParser;
use phpDocumentor\Guides\Markdown\Parsers\SeparatorParser;
use phpDocumentor\Guides\Markdown\Parsers\Table\TableParser;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\String\Slugger\AsciiSlugger;

Expand Down Expand Up @@ -58,6 +59,10 @@
->tag('phpdoc.guides.markdown.parser.blockParser')
->tag('phpdoc.guides.markdown.parser.subParser')

->set(TableParser::class)
->arg('$subParsers', tagged_iterator('phpdoc.guides.markdown.parser.inlineParser'))
->tag('phpdoc.guides.markdown.parser.blockParser')

->set(EmphasisParser::class)
->arg('$inlineParsers', tagged_iterator('phpdoc.guides.markdown.parser.inlineParser'))
->tag('phpdoc.guides.markdown.parser.inlineParser')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use League\CommonMark\Environment\Environment as CommonMarkEnvironment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Table\TableExtension;
use League\CommonMark\Node\Block\Document;
use League\CommonMark\Node\NodeWalker;
use League\CommonMark\Parser\MarkdownParser;
Expand Down Expand Up @@ -46,6 +47,7 @@ public function __construct(
) {
$cmEnvironment = new CommonMarkEnvironment(['html_input' => 'strip']);
$cmEnvironment->addExtension(new CommonMarkCoreExtension());
$cmEnvironment->addExtension(new TableExtension());
$cmEnvironment->addExtension(new AutolinkExtension());
$this->markdownParser = new MarkdownParser($cmEnvironment);
}
Expand Down
20 changes: 20 additions & 0 deletions packages/guides-markdown/src/Markdown/ParserException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Markdown;

use RuntimeException;

class ParserException extends RuntimeException
{
}
143 changes: 143 additions & 0 deletions packages/guides-markdown/src/Markdown/Parsers/Table/TableParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Markdown\Parsers\Table;

use League\CommonMark\Extension\Table\Table as CommonMarkTable;
use League\CommonMark\Extension\Table\TableCell;
use League\CommonMark\Extension\Table\TableRow as CommonMarkTableRow;
use League\CommonMark\Extension\Table\TableSection;
use League\CommonMark\Node\Node as CommonMarkNode;
use League\CommonMark\Node\NodeWalker;
use League\CommonMark\Node\NodeWalkerEvent;
use phpDocumentor\Guides\Markdown\ParserException;
use phpDocumentor\Guides\Markdown\Parsers\AbstractBlockParser;
use phpDocumentor\Guides\MarkupLanguageParser as GuidesParser;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\Table\TableColumn;
use phpDocumentor\Guides\Nodes\Table\TableRow;
use phpDocumentor\Guides\Nodes\TableNode;
use Psr\Log\LoggerInterface;

use function sprintf;

/** @extends AbstractBlockParser<TableNode> */
final class TableParser extends AbstractBlockParser
{
/** @param iterable<AbstractBlockParser<Node>> $subParsers */
public function __construct(
private readonly iterable $subParsers,
private readonly LoggerInterface $logger,
) {
}

public function parse(GuidesParser $parser, NodeWalker $walker, CommonMarkNode $current): TableNode
{
$headerRows = [];
$bodyRows = [];

while ($event = $walker->next()) {
$commonMarkNode = $event->getNode();

if ($event->isEntering()) {
if ($commonMarkNode instanceof TableSection) {
if ($commonMarkNode->isHead()) {
$headerRows = $this->parseTableSection($parser, $walker);
continue;
}

$bodyRows = $this->parseTableSection($parser, $walker);
}

continue;
}

if ($commonMarkNode instanceof CommonMarkTable) {
return new TableNode($bodyRows, $headerRows);
}

$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $commonMarkNode::class, 'Header'));
}

throw new ParserException('Unexpected end of NodeWalker');
}

public function supports(NodeWalkerEvent $event): bool
{
return $event->isEntering() && $event->getNode() instanceof CommonMarkTable;
}

/** @return TableRow[] */
private function parseTableSection(GuidesParser $parser, NodeWalker $walker): array
{
$rows = [];
while ($event = $walker->next()) {
if ($event->isEntering()) {
$rows[] = $this->parseRow($parser, $walker);
continue;
}

if ($event->getNode() instanceof TableSection) {
return $rows;
}

$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $event->getNode()::class, 'Table section'));
}

throw new ParserException('Unexpected end of NodeWalker');
}

private function parseRow(GuidesParser $parser, NodeWalker $walker): TableRow
{
$cells = [];
while ($event = $walker->next()) {
if ($event->isEntering()) {
$cells[] = $this->parseCell($parser, $walker);
continue;
}

if ($event->getNode() instanceof CommonMarkTableRow) {
return new TableRow($cells);
}

$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $event->getNode()::class, 'Table row'));
}

throw new ParserException('Unexpected end of NodeWalker');
}

private function parseCell(GuidesParser $parser, NodeWalker $walker): TableColumn
{
$nodes = [];
while ($event = $walker->next()) {
if ($event->isEntering()) {
foreach ($this->subParsers as $subParser) {
if ($subParser->supports($event)) {
$nodes[] = $subParser->parse($parser, $walker, $event->getNode());
break;
}
}

continue;
}

if ($event->getNode() instanceof TableCell) {
return new TableColumn('', 1, $nodes, 1);
}

$this->logger->warning(sprintf('"%s" node is not yet supported in context %s. ', $event->getNode()::class, 'Table Cell'));
}

throw new ParserException('Unexpected end of NodeWalker');
}
}
39 changes: 19 additions & 20 deletions tests/Integration/tests/markdown/table-md/expected/index.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
<!-- content start -->
<div class="section" id="table-markdown">
<h1>Table Markdown</h1>

<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>City</th>
</tr>
<div class="section" id="table-markdown">
<h1>Table Markdown</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr>
<tbody>
<tr>
<td>John Doe</td>
<td>29</td>
<td>New York</td>
</tr>
<tr>
</tr>
<tr>
<td>Jane Smith</td>
<td>34</td>
<td>San Francisco</td>
</tr>
<tr>
</tr>
<tr>
<td>Sam Green</td>
<td>22</td>
<td>Boston</td>
</tr>
</tbody>
</table>
</div>
</tr>
</tbody>
</table>
</div>
<!-- content end -->
1 change: 0 additions & 1 deletion tests/Integration/tests/markdown/table-md/input/skip

This file was deleted.

0 comments on commit 2985f7f

Please sign in to comment.