diff options
Diffstat (limited to 'vendor/league/commonmark/src/Extension/TableOfContents/TableOfContentsBuilder.php')
| -rw-r--r-- | vendor/league/commonmark/src/Extension/TableOfContents/TableOfContentsBuilder.php | 157 |
1 files changed, 59 insertions, 98 deletions
diff --git a/vendor/league/commonmark/src/Extension/TableOfContents/TableOfContentsBuilder.php b/vendor/league/commonmark/src/Extension/TableOfContents/TableOfContentsBuilder.php index 05d8be9d57..8ff06afc7b 100644 --- a/vendor/league/commonmark/src/Extension/TableOfContents/TableOfContentsBuilder.php +++ b/vendor/league/commonmark/src/Extension/TableOfContents/TableOfContentsBuilder.php @@ -13,32 +13,44 @@ namespace League\CommonMark\Extension\TableOfContents; use League\CommonMark\Block\Element\Document; use League\CommonMark\Block\Element\Heading; -use League\CommonMark\Block\Element\ListBlock; -use League\CommonMark\Block\Element\ListData; -use League\CommonMark\Block\Element\ListItem; -use League\CommonMark\Block\Element\Paragraph; use League\CommonMark\Event\DocumentParsedEvent; use League\CommonMark\Exception\InvalidOptionException; use League\CommonMark\Extension\HeadingPermalink\HeadingPermalink; -use League\CommonMark\Extension\TableOfContents\Normalizer\AsIsNormalizerStrategy; -use League\CommonMark\Extension\TableOfContents\Normalizer\FlatNormalizerStrategy; -use League\CommonMark\Extension\TableOfContents\Normalizer\NormalizerStrategyInterface; -use League\CommonMark\Extension\TableOfContents\Normalizer\RelativeNormalizerStrategy; -use League\CommonMark\Inline\Element\Link; +use League\CommonMark\Extension\TableOfContents\Node\TableOfContents; +use League\CommonMark\Extension\TableOfContents\Node\TableOfContentsPlaceholder; use League\CommonMark\Util\ConfigurationAwareInterface; use League\CommonMark\Util\ConfigurationInterface; final class TableOfContentsBuilder implements ConfigurationAwareInterface { - public const STYLE_BULLET = ListBlock::TYPE_BULLET; - public const STYLE_ORDERED = ListBlock::TYPE_ORDERED; + /** + * @deprecated Use TableOfContentsGenerator::STYLE_BULLET instead + */ + public const STYLE_BULLET = TableOfContentsGenerator::STYLE_BULLET; + + /** + * @deprecated Use TableOfContentsGenerator::STYLE_ORDERED instead + */ + public const STYLE_ORDERED = TableOfContentsGenerator::STYLE_ORDERED; + + /** + * @deprecated Use TableOfContentsGenerator::NORMALIZE_DISABLED instead + */ + public const NORMALIZE_DISABLED = TableOfContentsGenerator::NORMALIZE_DISABLED; - public const NORMALIZE_DISABLED = 'as-is'; - public const NORMALIZE_RELATIVE = 'relative'; - public const NORMALIZE_FLAT = 'flat'; + /** + * @deprecated Use TableOfContentsGenerator::NORMALIZE_RELATIVE instead + */ + public const NORMALIZE_RELATIVE = TableOfContentsGenerator::NORMALIZE_RELATIVE; + + /** + * @deprecated Use TableOfContentsGenerator::NORMALIZE_FLAT instead + */ + public const NORMALIZE_FLAT = TableOfContentsGenerator::NORMALIZE_FLAT; public const POSITION_TOP = 'top'; public const POSITION_BEFORE_HEADINGS = 'before-headings'; + public const POSITION_PLACEHOLDER = 'placeholder'; /** @var ConfigurationInterface */ private $config; @@ -46,43 +58,24 @@ final class TableOfContentsBuilder implements ConfigurationAwareInterface public function onDocumentParsed(DocumentParsedEvent $event): void { $document = $event->getDocument(); - $toc = $this->createToc(); - - $normalizer = $this->getNormalizer($toc); - [$min, $max] = $this->getMinAndMaxHeadingLevels(); - $firstHeading = null; - - foreach ($this->getHeadingLinks($document) as $headingLink) { - $heading = $headingLink->parent(); - // Make sure this is actually tied to a heading - if (!$heading instanceof Heading) { - continue; - } - - // Skip any headings outside the configured min/max levels - if ($heading->getLevel() < $min || $heading->getLevel() > $max) { - continue; - } - - // Keep track of the first heading we see - we might need this later - $firstHeading = $firstHeading ?? $heading; - - // Create the new link - $link = new Link('#' . $headingLink->getSlug(), $heading->getStringContent()); - $paragraph = new Paragraph(); - $paragraph->appendChild($link); - - $listItem = new ListItem($toc->getListData()); - $listItem->appendChild($paragraph); + $generator = new TableOfContentsGenerator( + $this->config->get('table_of_contents/style', TableOfContentsGenerator::STYLE_BULLET), + $this->config->get('table_of_contents/normalize', TableOfContentsGenerator::NORMALIZE_RELATIVE), + (int) $this->config->get('table_of_contents/min_heading_level', 1), + (int) $this->config->get('table_of_contents/max_heading_level', 6) + ); - // Add it to the correct place - $normalizer->addItem($heading->getLevel(), $listItem); + $toc = $generator->generate($document); + if ($toc === null) { + // No linkable headers exist, so no TOC could be generated + return; } - // Don't add the TOC if no headings were present - if (!$toc->hasChildren() || $firstHeading === null) { - return; + // Add custom CSS class(es), if defined + $class = $this->config->get('table_of_contents/html_class', 'table-of-contents'); + if (!empty($class)) { + $toc->data['attributes']['class'] = $class; } // Add the TOC to the Document @@ -90,73 +83,41 @@ final class TableOfContentsBuilder implements ConfigurationAwareInterface if ($position === self::POSITION_TOP) { $document->prependChild($toc); } elseif ($position === self::POSITION_BEFORE_HEADINGS) { - $firstHeading->insertBefore($toc); + $this->insertBeforeFirstLinkedHeading($document, $toc); + } elseif ($position === self::POSITION_PLACEHOLDER) { + $this->replacePlaceholders($document, $toc); } else { throw new InvalidOptionException(\sprintf('Invalid config option "%s" for "table_of_contents/position"', $position)); } } - private function createToc(): TableOfContents + private function insertBeforeFirstLinkedHeading(Document $document, TableOfContents $toc): void { - $listData = new ListData(); - - $style = $this->config->get('table_of_contents/style', self::STYLE_BULLET); - if ($style === self::STYLE_BULLET) { - $listData->type = ListBlock::TYPE_BULLET; - } elseif ($style === self::STYLE_ORDERED) { - $listData->type = ListBlock::TYPE_ORDERED; - } else { - throw new InvalidOptionException(\sprintf('Invalid config option "%s" for "table_of_contents/style"', $style)); - } - - $toc = new TableOfContents($listData); + $walker = $document->walker(); + while ($event = $walker->next()) { + if ($event->isEntering() && ($node = $event->getNode()) instanceof HeadingPermalink && ($parent = $node->parent()) instanceof Heading) { + $parent->insertBefore($toc); - $class = $this->config->get('table_of_contents/html_class', 'table-of-contents'); - if (!empty($class)) { - $toc->data['attributes']['class'] = $class; + return; + } } - - return $toc; - } - - /** - * @return array<int> - */ - private function getMinAndMaxHeadingLevels(): array - { - return [ - (int) $this->config->get('table_of_contents/min_heading_level', 1), - (int) $this->config->get('table_of_contents/max_heading_level', 6), - ]; } - /** - * @param Document $document - * - * @return iterable<HeadingPermalink> - */ - private function getHeadingLinks(Document $document) + private function replacePlaceholders(Document $document, TableOfContents $toc): void { $walker = $document->walker(); while ($event = $walker->next()) { - if ($event->isEntering() && ($node = $event->getNode()) instanceof HeadingPermalink) { - yield $node; + // Add the block once we find a placeholder (and we're about to leave it) + if (!$event->getNode() instanceof TableOfContentsPlaceholder) { + continue; } - } - } - private function getNormalizer(TableOfContents $toc): NormalizerStrategyInterface - { - $strategy = $this->config->get('table_of_contents/normalize', self::NORMALIZE_RELATIVE); - if ($strategy === self::NORMALIZE_DISABLED) { - return new AsIsNormalizerStrategy($toc); - } elseif ($strategy === self::NORMALIZE_RELATIVE) { - return new RelativeNormalizerStrategy($toc); - } elseif ($strategy === self::NORMALIZE_FLAT) { - return new FlatNormalizerStrategy($toc); - } + if ($event->isEntering()) { + continue; + } - throw new InvalidOptionException(\sprintf('Invalid config option "%s" for "table_of_contents/normalize"', $strategy)); + $event->getNode()->replaceWith(clone $toc); + } } public function setConfiguration(ConfigurationInterface $config) |
