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 AsIsNormalizerStrategy implements NormalizerStrategyInterface
21{
22    /** @psalm-readonly-allow-private-mutation */
23    private ListBlock $parentListBlock;
24
25    /** @psalm-readonly-allow-private-mutation */
26    private int $parentLevel = 1;
27
28    /** @psalm-readonly-allow-private-mutation */
29    private ?ListItem $lastListItem = null;
30
31    public function __construct(TableOfContents $toc)
32    {
33        $this->parentListBlock = $toc;
34    }
35
36    public function addItem(int $level, ListItem $listItemToAdd): void
37    {
38        while ($level > $this->parentLevel) {
39            // Descend downwards, creating new ListBlocks if needed, until we reach the correct depth
40            if ($this->lastListItem === null) {
41                $this->lastListItem = new ListItem($this->parentListBlock->getListData());
42                $this->parentListBlock->appendChild($this->lastListItem);
43            }
44
45            $newListBlock = new ListBlock($this->parentListBlock->getListData());
46            $newListBlock->setStartLine($listItemToAdd->getStartLine());
47            $newListBlock->setEndLine($listItemToAdd->getEndLine());
48            $this->lastListItem->appendChild($newListBlock);
49            $this->parentListBlock = $newListBlock;
50            $this->lastListItem    = null;
51
52            $this->parentLevel++;
53        }
54
55        while ($level < $this->parentLevel) {
56            // Search upwards for the previous parent list block
57            $search = $this->parentListBlock;
58            while ($search = $search->parent()) {
59                if ($search instanceof ListBlock) {
60                    $this->parentListBlock = $search;
61                    break;
62                }
63            }
64
65            $this->parentLevel--;
66        }
67
68        $this->parentListBlock->appendChild($listItemToAdd);
69
70        $this->lastListItem = $listItemToAdd;
71    }
72}
73