Uploaded From CV. Swandhana Server
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Block\AbstractBlock;
|
||||
|
||||
final class Table extends AbstractBlock
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Block\AbstractBlock;
|
||||
|
||||
final class TableCell extends AbstractBlock
|
||||
{
|
||||
public const TYPE_HEADER = 'header';
|
||||
public const TYPE_DATA = 'data';
|
||||
|
||||
public const ALIGN_LEFT = 'left';
|
||||
public const ALIGN_RIGHT = 'right';
|
||||
public const ALIGN_CENTER = 'center';
|
||||
|
||||
/**
|
||||
* @psalm-var self::TYPE_*
|
||||
* @phpstan-var self::TYPE_*
|
||||
*
|
||||
* @psalm-readonly-allow-private-mutation
|
||||
*/
|
||||
private string $type = self::TYPE_DATA;
|
||||
|
||||
/**
|
||||
* @psalm-var self::ALIGN_*|null
|
||||
* @phpstan-var self::ALIGN_*|null
|
||||
*
|
||||
* @psalm-readonly-allow-private-mutation
|
||||
*/
|
||||
private ?string $align = null;
|
||||
|
||||
/**
|
||||
* @psalm-param self::TYPE_* $type
|
||||
* @psalm-param self::ALIGN_*|null $align
|
||||
*
|
||||
* @phpstan-param self::TYPE_* $type
|
||||
* @phpstan-param self::ALIGN_*|null $align
|
||||
*/
|
||||
public function __construct(string $type = self::TYPE_DATA, ?string $align = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->type = $type;
|
||||
$this->align = $align;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return self::TYPE_*
|
||||
*
|
||||
* @phpstan-return self::TYPE_*
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param self::TYPE_* $type
|
||||
*
|
||||
* @phpstan-param self::TYPE_* $type
|
||||
*/
|
||||
public function setType(string $type): void
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return self::ALIGN_*|null
|
||||
*
|
||||
* @phpstan-return self::ALIGN_*|null
|
||||
*/
|
||||
public function getAlign(): ?string
|
||||
{
|
||||
return $this->align;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param self::ALIGN_*|null $align
|
||||
*
|
||||
* @phpstan-param self::ALIGN_*|null $align
|
||||
*/
|
||||
public function setAlign(?string $align): void
|
||||
{
|
||||
$this->align = $align;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Extension\Attributes\Util\AttributesHelper;
|
||||
use League\CommonMark\Node\Node;
|
||||
use League\CommonMark\Renderer\ChildNodeRendererInterface;
|
||||
use League\CommonMark\Renderer\NodeRendererInterface;
|
||||
use League\CommonMark\Util\HtmlElement;
|
||||
use League\CommonMark\Xml\XmlNodeRendererInterface;
|
||||
|
||||
final class TableCellRenderer implements NodeRendererInterface, XmlNodeRendererInterface
|
||||
{
|
||||
private const DEFAULT_ATTRIBUTES = [
|
||||
TableCell::ALIGN_LEFT => ['align' => 'left'],
|
||||
TableCell::ALIGN_CENTER => ['align' => 'center'],
|
||||
TableCell::ALIGN_RIGHT => ['align' => 'right'],
|
||||
];
|
||||
|
||||
/** @var array<TableCell::ALIGN_*, array<string, string|string[]|bool>> */
|
||||
private array $alignmentAttributes;
|
||||
|
||||
/**
|
||||
* @param array<TableCell::ALIGN_*, array<string, string|string[]|bool>> $alignmentAttributes
|
||||
*/
|
||||
public function __construct(array $alignmentAttributes = self::DEFAULT_ATTRIBUTES)
|
||||
{
|
||||
$this->alignmentAttributes = $alignmentAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TableCell $node
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function render(Node $node, ChildNodeRendererInterface $childRenderer): \Stringable
|
||||
{
|
||||
TableCell::assertInstanceOf($node);
|
||||
|
||||
$attrs = $node->data->get('attributes');
|
||||
if (($alignment = $node->getAlign()) !== null) {
|
||||
$attrs = AttributesHelper::mergeAttributes($attrs, $this->alignmentAttributes[$alignment]);
|
||||
}
|
||||
|
||||
$tag = $node->getType() === TableCell::TYPE_HEADER ? 'th' : 'td';
|
||||
|
||||
return new HtmlElement($tag, $attrs, $childRenderer->renderNodes($node->children()));
|
||||
}
|
||||
|
||||
public function getXmlTagName(Node $node): string
|
||||
{
|
||||
return 'table_cell';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TableCell $node
|
||||
*
|
||||
* @return array<string, scalar>
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function getXmlAttributes(Node $node): array
|
||||
{
|
||||
TableCell::assertInstanceOf($node);
|
||||
|
||||
$ret = ['type' => $node->getType()];
|
||||
|
||||
if (($align = $node->getAlign()) !== null) {
|
||||
$ret['align'] = $align;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Environment\EnvironmentBuilderInterface;
|
||||
use League\CommonMark\Extension\ConfigurableExtensionInterface;
|
||||
use League\CommonMark\Renderer\HtmlDecorator;
|
||||
use League\Config\ConfigurationBuilderInterface;
|
||||
use Nette\Schema\Expect;
|
||||
|
||||
final class TableExtension implements ConfigurableExtensionInterface
|
||||
{
|
||||
public function configureSchema(ConfigurationBuilderInterface $builder): void
|
||||
{
|
||||
$attributeArraySchema = Expect::arrayOf(
|
||||
Expect::type('string|string[]|bool'), // attribute value(s)
|
||||
'string' // attribute name
|
||||
)->mergeDefaults(false);
|
||||
|
||||
$builder->addSchema('table', Expect::structure([
|
||||
'wrap' => Expect::structure([
|
||||
'enabled' => Expect::bool()->default(false),
|
||||
'tag' => Expect::string()->default('div'),
|
||||
'attributes' => Expect::arrayOf(Expect::string()),
|
||||
]),
|
||||
'alignment_attributes' => Expect::structure([
|
||||
'left' => (clone $attributeArraySchema)->default(['align' => 'left']),
|
||||
'center' => (clone $attributeArraySchema)->default(['align' => 'center']),
|
||||
'right' => (clone $attributeArraySchema)->default(['align' => 'right']),
|
||||
]),
|
||||
]));
|
||||
}
|
||||
|
||||
public function register(EnvironmentBuilderInterface $environment): void
|
||||
{
|
||||
$tableRenderer = new TableRenderer();
|
||||
if ($environment->getConfiguration()->get('table/wrap/enabled')) {
|
||||
$tableRenderer = new HtmlDecorator($tableRenderer, $environment->getConfiguration()->get('table/wrap/tag'), $environment->getConfiguration()->get('table/wrap/attributes'));
|
||||
}
|
||||
|
||||
$environment
|
||||
->addBlockStartParser(new TableStartParser())
|
||||
|
||||
->addRenderer(Table::class, $tableRenderer)
|
||||
->addRenderer(TableSection::class, new TableSectionRenderer())
|
||||
->addRenderer(TableRow::class, new TableRowRenderer())
|
||||
->addRenderer(TableCell::class, new TableCellRenderer($environment->getConfiguration()->get('table/alignment_attributes')));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
|
||||
use League\CommonMark\Parser\Block\BlockContinue;
|
||||
use League\CommonMark\Parser\Block\BlockContinueParserInterface;
|
||||
use League\CommonMark\Parser\Block\BlockContinueParserWithInlinesInterface;
|
||||
use League\CommonMark\Parser\Cursor;
|
||||
use League\CommonMark\Parser\InlineParserEngineInterface;
|
||||
use League\CommonMark\Util\ArrayCollection;
|
||||
|
||||
final class TableParser extends AbstractBlockContinueParser implements BlockContinueParserWithInlinesInterface
|
||||
{
|
||||
/** @psalm-readonly */
|
||||
private Table $block;
|
||||
|
||||
/**
|
||||
* @var ArrayCollection<string>
|
||||
*
|
||||
* @psalm-readonly-allow-private-mutation
|
||||
*/
|
||||
private ArrayCollection $bodyLines;
|
||||
|
||||
/**
|
||||
* @var array<int, string|null>
|
||||
* @psalm-var array<int, TableCell::ALIGN_*|null>
|
||||
* @phpstan-var array<int, TableCell::ALIGN_*|null>
|
||||
*
|
||||
* @psalm-readonly
|
||||
*/
|
||||
private array $columns;
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*
|
||||
* @psalm-readonly-allow-private-mutation
|
||||
*/
|
||||
private array $headerCells;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private bool $nextIsSeparatorLine = true;
|
||||
|
||||
/**
|
||||
* @param array<int, string|null> $columns
|
||||
* @param array<int, string> $headerCells
|
||||
*
|
||||
* @psalm-param array<int, TableCell::ALIGN_*|null> $columns
|
||||
*
|
||||
* @phpstan-param array<int, TableCell::ALIGN_*|null> $columns
|
||||
*/
|
||||
public function __construct(array $columns, array $headerCells)
|
||||
{
|
||||
$this->block = new Table();
|
||||
$this->bodyLines = new ArrayCollection();
|
||||
$this->columns = $columns;
|
||||
$this->headerCells = $headerCells;
|
||||
}
|
||||
|
||||
public function canHaveLazyContinuationLines(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getBlock(): Table
|
||||
{
|
||||
return $this->block;
|
||||
}
|
||||
|
||||
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue
|
||||
{
|
||||
if (\strpos($cursor->getLine(), '|') === false) {
|
||||
return BlockContinue::none();
|
||||
}
|
||||
|
||||
return BlockContinue::at($cursor);
|
||||
}
|
||||
|
||||
public function addLine(string $line): void
|
||||
{
|
||||
if ($this->nextIsSeparatorLine) {
|
||||
$this->nextIsSeparatorLine = false;
|
||||
} else {
|
||||
$this->bodyLines[] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
public function parseInlines(InlineParserEngineInterface $inlineParser): void
|
||||
{
|
||||
$headerColumns = \count($this->headerCells);
|
||||
|
||||
$head = new TableSection(TableSection::TYPE_HEAD);
|
||||
$this->block->appendChild($head);
|
||||
|
||||
$headerRow = new TableRow();
|
||||
$head->appendChild($headerRow);
|
||||
for ($i = 0; $i < $headerColumns; $i++) {
|
||||
$cell = $this->headerCells[$i];
|
||||
$tableCell = $this->parseCell($cell, $i, $inlineParser);
|
||||
$tableCell->setType(TableCell::TYPE_HEADER);
|
||||
$headerRow->appendChild($tableCell);
|
||||
}
|
||||
|
||||
$body = null;
|
||||
foreach ($this->bodyLines as $rowLine) {
|
||||
$cells = self::split($rowLine);
|
||||
$row = new TableRow();
|
||||
|
||||
// Body can not have more columns than head
|
||||
for ($i = 0; $i < $headerColumns; $i++) {
|
||||
$cell = $cells[$i] ?? '';
|
||||
$tableCell = $this->parseCell($cell, $i, $inlineParser);
|
||||
$row->appendChild($tableCell);
|
||||
}
|
||||
|
||||
if ($body === null) {
|
||||
// It's valid to have a table without body. In that case, don't add an empty TableBody node.
|
||||
$body = new TableSection();
|
||||
$this->block->appendChild($body);
|
||||
}
|
||||
|
||||
$body->appendChild($row);
|
||||
}
|
||||
}
|
||||
|
||||
private function parseCell(string $cell, int $column, InlineParserEngineInterface $inlineParser): TableCell
|
||||
{
|
||||
$tableCell = new TableCell();
|
||||
|
||||
if ($column < \count($this->columns)) {
|
||||
$tableCell->setAlign($this->columns[$column]);
|
||||
}
|
||||
|
||||
$inlineParser->parse(\trim($cell), $tableCell);
|
||||
|
||||
return $tableCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function split(string $line): array
|
||||
{
|
||||
$cursor = new Cursor(\trim($line));
|
||||
|
||||
if ($cursor->getCurrentCharacter() === '|') {
|
||||
$cursor->advanceBy(1);
|
||||
}
|
||||
|
||||
$cells = [];
|
||||
$sb = '';
|
||||
|
||||
while (! $cursor->isAtEnd()) {
|
||||
switch ($c = $cursor->getCurrentCharacter()) {
|
||||
case '\\':
|
||||
if ($cursor->peek() === '|') {
|
||||
// Pipe is special for table parsing. An escaped pipe doesn't result in a new cell, but is
|
||||
// passed down to inline parsing as an unescaped pipe. Note that that applies even for the `\|`
|
||||
// in an input like `\\|` - in other words, table parsing doesn't support escaping backslashes.
|
||||
$sb .= '|';
|
||||
$cursor->advanceBy(1);
|
||||
} else {
|
||||
// Preserve backslash before other characters or at end of line.
|
||||
$sb .= '\\';
|
||||
}
|
||||
|
||||
break;
|
||||
case '|':
|
||||
$cells[] = $sb;
|
||||
$sb = '';
|
||||
break;
|
||||
default:
|
||||
$sb .= $c;
|
||||
}
|
||||
|
||||
$cursor->advanceBy(1);
|
||||
}
|
||||
|
||||
if ($sb !== '') {
|
||||
$cells[] = $sb;
|
||||
}
|
||||
|
||||
return $cells;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Node;
|
||||
use League\CommonMark\Renderer\ChildNodeRendererInterface;
|
||||
use League\CommonMark\Renderer\NodeRendererInterface;
|
||||
use League\CommonMark\Util\HtmlElement;
|
||||
use League\CommonMark\Xml\XmlNodeRendererInterface;
|
||||
|
||||
final class TableRenderer implements NodeRendererInterface, XmlNodeRendererInterface
|
||||
{
|
||||
/**
|
||||
* @param Table $node
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function render(Node $node, ChildNodeRendererInterface $childRenderer): \Stringable
|
||||
{
|
||||
Table::assertInstanceOf($node);
|
||||
|
||||
$attrs = $node->data->get('attributes');
|
||||
|
||||
$separator = $childRenderer->getInnerSeparator();
|
||||
|
||||
$children = $childRenderer->renderNodes($node->children());
|
||||
|
||||
return new HtmlElement('table', $attrs, $separator . \trim($children) . $separator);
|
||||
}
|
||||
|
||||
public function getXmlTagName(Node $node): string
|
||||
{
|
||||
return 'table';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getXmlAttributes(Node $node): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Block\AbstractBlock;
|
||||
|
||||
final class TableRow extends AbstractBlock
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Node;
|
||||
use League\CommonMark\Renderer\ChildNodeRendererInterface;
|
||||
use League\CommonMark\Renderer\NodeRendererInterface;
|
||||
use League\CommonMark\Util\HtmlElement;
|
||||
use League\CommonMark\Xml\XmlNodeRendererInterface;
|
||||
|
||||
final class TableRowRenderer implements NodeRendererInterface, XmlNodeRendererInterface
|
||||
{
|
||||
/**
|
||||
* @param TableRow $node
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function render(Node $node, ChildNodeRendererInterface $childRenderer): \Stringable
|
||||
{
|
||||
TableRow::assertInstanceOf($node);
|
||||
|
||||
$attrs = $node->data->get('attributes');
|
||||
|
||||
$separator = $childRenderer->getInnerSeparator();
|
||||
|
||||
return new HtmlElement('tr', $attrs, $separator . $childRenderer->renderNodes($node->children()) . $separator);
|
||||
}
|
||||
|
||||
public function getXmlTagName(Node $node): string
|
||||
{
|
||||
return 'table_row';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getXmlAttributes(Node $node): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Block\AbstractBlock;
|
||||
|
||||
final class TableSection extends AbstractBlock
|
||||
{
|
||||
public const TYPE_HEAD = 'head';
|
||||
public const TYPE_BODY = 'body';
|
||||
|
||||
/**
|
||||
* @psalm-var self::TYPE_*
|
||||
* @phpstan-var self::TYPE_*
|
||||
*
|
||||
* @psalm-readonly
|
||||
*/
|
||||
private string $type;
|
||||
|
||||
/**
|
||||
* @psalm-param self::TYPE_* $type
|
||||
*
|
||||
* @phpstan-param self::TYPE_* $type
|
||||
*/
|
||||
public function __construct(string $type = self::TYPE_BODY)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return self::TYPE_*
|
||||
*
|
||||
* @phpstan-return self::TYPE_*
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function isHead(): bool
|
||||
{
|
||||
return $this->type === self::TYPE_HEAD;
|
||||
}
|
||||
|
||||
public function isBody(): bool
|
||||
{
|
||||
return $this->type === self::TYPE_BODY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Node\Node;
|
||||
use League\CommonMark\Renderer\ChildNodeRendererInterface;
|
||||
use League\CommonMark\Renderer\NodeRendererInterface;
|
||||
use League\CommonMark\Util\HtmlElement;
|
||||
use League\CommonMark\Xml\XmlNodeRendererInterface;
|
||||
|
||||
final class TableSectionRenderer implements NodeRendererInterface, XmlNodeRendererInterface
|
||||
{
|
||||
/**
|
||||
* @param TableSection $node
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function render(Node $node, ChildNodeRendererInterface $childRenderer)
|
||||
{
|
||||
TableSection::assertInstanceOf($node);
|
||||
|
||||
if (! $node->hasChildren()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$attrs = $node->data->get('attributes');
|
||||
|
||||
$separator = $childRenderer->getInnerSeparator();
|
||||
|
||||
$tag = $node->getType() === TableSection::TYPE_HEAD ? 'thead' : 'tbody';
|
||||
|
||||
return new HtmlElement($tag, $attrs, $separator . $childRenderer->renderNodes($node->children()) . $separator);
|
||||
}
|
||||
|
||||
public function getXmlTagName(Node $node): string
|
||||
{
|
||||
return 'table_section';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TableSection $node
|
||||
*
|
||||
* @return array<string, scalar>
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function getXmlAttributes(Node $node): array
|
||||
{
|
||||
TableSection::assertInstanceOf($node);
|
||||
|
||||
return [
|
||||
'type' => $node->getType(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Martin Hasoň <[email protected]>
|
||||
* (c) Webuni s.r.o. <[email protected]>
|
||||
* (c) Colin O'Dell <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Table;
|
||||
|
||||
use League\CommonMark\Parser\Block\BlockStart;
|
||||
use League\CommonMark\Parser\Block\BlockStartParserInterface;
|
||||
use League\CommonMark\Parser\Block\ParagraphParser;
|
||||
use League\CommonMark\Parser\Cursor;
|
||||
use League\CommonMark\Parser\MarkdownParserStateInterface;
|
||||
|
||||
final class TableStartParser implements BlockStartParserInterface
|
||||
{
|
||||
public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart
|
||||
{
|
||||
$paragraph = $parserState->getParagraphContent();
|
||||
if ($paragraph === null || \strpos($paragraph, '|') === false) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
$columns = self::parseSeparator($cursor);
|
||||
if (\count($columns) === 0) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
$lines = \explode("\n", $paragraph);
|
||||
$lastLine = \array_pop($lines);
|
||||
|
||||
$headerCells = TableParser::split($lastLine);
|
||||
if (\count($headerCells) > \count($columns)) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
$cursor->advanceToEnd();
|
||||
|
||||
$parsers = [];
|
||||
|
||||
if (\count($lines) > 0) {
|
||||
$p = new ParagraphParser();
|
||||
$p->addLine(\implode("\n", $lines));
|
||||
$parsers[] = $p;
|
||||
}
|
||||
|
||||
$parsers[] = new TableParser($columns, $headerCells);
|
||||
|
||||
return BlockStart::of(...$parsers)
|
||||
->at($cursor)
|
||||
->replaceActiveBlockParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string|null>
|
||||
*
|
||||
* @psalm-return array<int, TableCell::ALIGN_*|null>
|
||||
*
|
||||
* @phpstan-return array<int, TableCell::ALIGN_*|null>
|
||||
*/
|
||||
private static function parseSeparator(Cursor $cursor): array
|
||||
{
|
||||
$columns = [];
|
||||
$pipes = 0;
|
||||
$valid = false;
|
||||
|
||||
while (! $cursor->isAtEnd()) {
|
||||
switch ($c = $cursor->getCurrentCharacter()) {
|
||||
case '|':
|
||||
$cursor->advanceBy(1);
|
||||
$pipes++;
|
||||
if ($pipes > 1) {
|
||||
// More than one adjacent pipe not allowed
|
||||
return [];
|
||||
}
|
||||
|
||||
// Need at least one pipe, even for a one-column table
|
||||
$valid = true;
|
||||
break;
|
||||
case '-':
|
||||
case ':':
|
||||
if ($pipes === 0 && \count($columns) > 0) {
|
||||
// Need a pipe after the first column (first column doesn't need to start with one)
|
||||
return [];
|
||||
}
|
||||
|
||||
$left = false;
|
||||
$right = false;
|
||||
if ($c === ':') {
|
||||
$left = true;
|
||||
$cursor->advanceBy(1);
|
||||
}
|
||||
|
||||
if ($cursor->match('/^-+/') === null) {
|
||||
// Need at least one dash
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($cursor->getCurrentCharacter() === ':') {
|
||||
$right = true;
|
||||
$cursor->advanceBy(1);
|
||||
}
|
||||
|
||||
$columns[] = self::getAlignment($left, $right);
|
||||
// Next, need another pipe
|
||||
$pipes = 0;
|
||||
break;
|
||||
case ' ':
|
||||
case "\t":
|
||||
// White space is allowed between pipes and columns
|
||||
$cursor->advanceToNextNonSpaceOrTab();
|
||||
break;
|
||||
default:
|
||||
// Any other character is invalid
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (! $valid) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return TableCell::ALIGN_*|null
|
||||
*
|
||||
* @phpstan-return TableCell::ALIGN_*|null
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
private static function getAlignment(bool $left, bool $right): ?string
|
||||
{
|
||||
if ($left && $right) {
|
||||
return TableCell::ALIGN_CENTER;
|
||||
}
|
||||
|
||||
if ($left) {
|
||||
return TableCell::ALIGN_LEFT;
|
||||
}
|
||||
|
||||
if ($right) {
|
||||
return TableCell::ALIGN_RIGHT;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user