gl-website-deployer/vendor/doctrine/rst-parser/lib/Parser/TableParser.php
2024-11-19 08:02:04 +01:00

163 lines
4.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Doctrine\RST\Parser;
use Doctrine\RST\Nodes\TableNode;
use Exception;
use function count;
use function in_array;
use function sprintf;
use function strlen;
use function trim;
final class TableParser
{
private const SIMPLE_TABLE_LETTER = '=';
// "-" is valid as a separator in a simple table, except
// on the first and last lines
private const SIMPLE_TABLE_LETTER_ALT = '-';
private const PRETTY_TABLE_LETTER = '-';
private const PRETTY_TABLE_HEADER = '=';
private const PRETTY_TABLE_JOINT = '+';
/**
* Parses a line from a table to see if it is a separator line.
*
* Returns TableSeparatorLineConfig if it *is* a separator, null otherwise.
*/
public function parseTableSeparatorLine(string $line): ?TableSeparatorLineConfig
{
$header = false;
$pretty = false;
$line = trim($line);
if ($line === '') {
return null;
}
// Finds the table chars
$chars = $this->findTableChars($line);
if ($chars === null) {
return null;
}
if ($chars[0] === self::PRETTY_TABLE_JOINT && $chars[1] === self::PRETTY_TABLE_LETTER) {
$pretty = true;
// reverse the chars: - is the line char, + is the space char
$chars = [self::PRETTY_TABLE_LETTER, self::PRETTY_TABLE_JOINT];
} elseif ($chars[0] === self::PRETTY_TABLE_JOINT && $chars[1] === self::PRETTY_TABLE_HEADER) {
$pretty = true;
$header = true;
// reverse the chars: = is the line char, + is the space char
$chars = [self::PRETTY_TABLE_HEADER, self::PRETTY_TABLE_JOINT];
} else {
// either a simple table or not a separator line
// if line char is not "=" or "-", not a separator line
if (! in_array($chars[0], [self::SIMPLE_TABLE_LETTER, self::SIMPLE_TABLE_LETTER_ALT], true)) {
return null;
}
// if space char is not a space, not a separator line
if ($chars[1] !== ' ') {
return null;
}
}
$parts = [];
$currentPartStart = null;
for ($i = 0; $i < strlen($line); $i++) {
// we found the "line char": "-" or "="
if ($line[$i] === $chars[0]) {
if ($currentPartStart === null) {
$currentPartStart = $i;
}
continue;
}
if ($line[$i] !== $chars[1]) {
throw new Exception(sprintf('Unexpected char "%s"', $line[$i]));
}
// found the "space" char
// record the part "range" if we're at the end of a range
if ($currentPartStart === null) {
continue;
}
$parts[] = [$currentPartStart, $i];
$currentPartStart = null;
}
// finish the last "part"
if ($currentPartStart !== null) {
$parts[] = [$currentPartStart, $i];
}
if (count($parts) > 1) {
return new TableSeparatorLineConfig(
$header,
$pretty ? TableNode::TYPE_PRETTY : TableNode::TYPE_SIMPLE,
$parts,
$chars[0],
$line
);
}
return null;
}
public function guessTableType(string $line): string
{
return $line[0] === self::SIMPLE_TABLE_LETTER ? TableNode::TYPE_SIMPLE : TableNode::TYPE_PRETTY;
}
/**
* A "line" separator always has only two characters.
* This method returns those two characters.
*
* This returns null if this is not a separator line
* or it's malformed in any way.
*
* @return string[]|null
* @psalm-return array{string, ?string}
*/
private function findTableChars(string $line): ?array
{
$lineChar = $line[0];
$spaceChar = null;
for ($i = 0; $i < strlen($line); $i++) {
if ($line[$i] === $lineChar) {
continue;
}
if ($spaceChar === null) {
$spaceChar = $line[$i];
continue;
}
if ($line[$i] !== $spaceChar) {
return null;
}
}
if ($spaceChar === null) {
return null;
}
return [$lineChar, $spaceChar];
}
}