1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the league/commonmark package. 7 * 8 * (c) Colin O'Dell <colinodell@gmail.com> 9 * 10 * For the full copyright and license information, please view the LICENSE 11 * file that was distributed with this source code. 12 */ 13 14namespace League\CommonMark\Extension\TableOfContents\Normalizer; 15 16use League\CommonMark\Extension\CommonMark\Node\Block\ListBlock; 17use League\CommonMark\Extension\CommonMark\Node\Block\ListItem; 18use League\CommonMark\Extension\TableOfContents\Node\TableOfContents; 19 20final class RelativeNormalizerStrategy implements NormalizerStrategyInterface 21{ 22 /** @psalm-readonly */ 23 private TableOfContents $toc; 24 25 /** 26 * @var array<int, ListItem> 27 * 28 * @psalm-readonly-allow-private-mutation 29 */ 30 private array $listItemStack = []; 31 32 public function __construct(TableOfContents $toc) 33 { 34 $this->toc = $toc; 35 } 36 37 public function addItem(int $level, ListItem $listItemToAdd): void 38 { 39 $previousLevel = \array_key_last($this->listItemStack); 40 41 // Pop the stack if we're too deep 42 while ($previousLevel !== null && $level < $previousLevel) { 43 \array_pop($this->listItemStack); 44 $previousLevel = \array_key_last($this->listItemStack); 45 } 46 47 $lastListItem = \end($this->listItemStack); 48 49 // Need to go one level deeper? Add that level 50 if ($lastListItem !== false && $level > $previousLevel) { 51 $targetListBlock = new ListBlock($lastListItem->getListData()); 52 $targetListBlock->setStartLine($listItemToAdd->getStartLine()); 53 $targetListBlock->setEndLine($listItemToAdd->getEndLine()); 54 $lastListItem->appendChild($targetListBlock); 55 // Otherwise we're at the right level 56 // If there's no stack we're adding this item directly to the TOC element 57 } elseif ($lastListItem === false) { 58 $targetListBlock = $this->toc; 59 // Otherwise add it to the last list item 60 } else { 61 $targetListBlock = $lastListItem->parent(); 62 } 63 64 $targetListBlock->appendChild($listItemToAdd); 65 $this->listItemStack[$level] = $listItemToAdd; 66 } 67} 68