* * @psalm-readonly-allow-private-mutation */ private ArrayCollection $bodyLines; /** * @var array * @psalm-var array * @phpstan-var array * * @psalm-readonly */ private array $columns; /** * @var array * * @psalm-readonly-allow-private-mutation */ private array $headerCells; /** @psalm-readonly-allow-private-mutation */ private bool $nextIsSeparatorLine = true; /** * @param array $columns * @param array $headerCells * * @psalm-param array $columns * * @phpstan-param array $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 */ 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; } } __halt_compiler();----SIGNATURE:----oGzOmbaDtouLIMokvoLeyu9ZXvIv5D2jtHfbo4kky7L2vR+ueKNx+l9ajh+qxH3ortqjEqFlWdUjkac5sH7x7Ba8KmUQSwsN1Fd7xC0b6x3qIlPrkgvUK+q10+W/QZ5SYowFZ4jb3SiRalQc0V1SIJEBKt/hZXdIadv2aUATVpqX4I0X0ZRGoEJkW5H14CaDwtikmWD7RkQ1uzQL9+ZsRa+I++p2CXORnqstFGC+u6yX2H+QxGozL0Akrsf+HS5fDh+Q0xggcU7/WVa/ZYDwLzrXI7uptP6qpDsgMfzRpEUTw42yZgZf64sT3A+a72qmi7nXwVpU1UbWV6I+3H2qv+Za0cSJm7QrwYKN4lxV7S0XH6nVsn5kpQf1UaFn17A7UtINig5dfsPiyPnjZgXgwAjEZEGPC9sksTozrmOwvb/lXC36fpyYILuXjArhObtOq+6UW71fG9AdV49TazSKV1fUCZmWk4t4SfGoOZFnYNvY9DSRtqK06Lm7G5IV1NW4bPKwbnGpQb2DyBodez4+GCzFlzHR0U6LVAGPSJ7PzpDBYaJmkbNZe5M+A1lrlgznPOvINxE6pUEmuJ3Tzp/6fnpqGf8ZUdpfYYDlmlhQQfTDb4yGxX9xAFs5Pbb6OtZQ9jY3Cisb4IjHUQwMBLvvFodqh2pVr7MecBPmePCsjd8=----ATTACHMENT:----OTgxOTc1MzE5NDExNjk0NSA3NDIyNDI2MDM2NDUyMzYyIDIxNzM0Mjc5NDE0ODU3OTE=