1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 * (c) Rezo Zero / Ambroise Maupate
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13declare(strict_types=1);
14
15namespace League\CommonMark\Extension\Footnote\Event;
16
17use League\CommonMark\Event\DocumentParsedEvent;
18use League\CommonMark\Extension\Footnote\Node\FootnoteRef;
19use League\CommonMark\Reference\Reference;
20
21final class NumberFootnotesListener
22{
23    public function onDocumentParsed(DocumentParsedEvent $event): void
24    {
25        $document = $event->getDocument();
26        $walker = $document->walker();
27        $nextCounter = 1;
28        $usedLabels = [];
29        $usedCounters = [];
30
31        while ($event = $walker->next()) {
32            if (!$event->isEntering()) {
33                continue;
34            }
35
36            $node = $event->getNode();
37
38            if (!$node instanceof FootnoteRef) {
39                continue;
40            }
41
42            $existingReference = $node->getReference();
43            $label = $existingReference->getLabel();
44            $counter = $nextCounter;
45            $canIncrementCounter = true;
46
47            if (\array_key_exists($label, $usedLabels)) {
48                /*
49                 * Reference is used again, we need to point
50                 * to the same footnote. But with a different ID
51                 */
52                $counter = $usedCounters[$label];
53                $label = $label . '__' . ++$usedLabels[$label];
54                $canIncrementCounter = false;
55            }
56
57            // rewrite reference title to use a numeric link
58            $newReference = new Reference(
59                $label,
60                $existingReference->getDestination(),
61                (string) $counter
62            );
63
64            // Override reference with numeric link
65            $node->setReference($newReference);
66            $document->getReferenceMap()->addReference($newReference);
67
68            /*
69             * Store created references in document for
70             * creating FootnoteBackrefs
71             */
72            if (false === $document->getData($existingReference->getDestination(), false)) {
73                $document->data[$existingReference->getDestination()] = [];
74            }
75
76            $document->data[$existingReference->getDestination()][] = $newReference;
77
78            $usedLabels[$label] = 1;
79            $usedCounters[$label] = $nextCounter;
80
81            if ($canIncrementCounter) {
82                $nextCounter++;
83            }
84        }
85    }
86}
87