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\TaskList;
15
16use League\CommonMark\Extension\CommonMark\Node\Block\ListItem;
17use League\CommonMark\Node\Block\Paragraph;
18use League\CommonMark\Parser\Inline\InlineParserInterface;
19use League\CommonMark\Parser\Inline\InlineParserMatch;
20use League\CommonMark\Parser\InlineParserContext;
21
22final class TaskListItemMarkerParser implements InlineParserInterface
23{
24    public function getMatchDefinition(): InlineParserMatch
25    {
26        return InlineParserMatch::oneOf('[ ]', '[x]');
27    }
28
29    public function parse(InlineParserContext $inlineContext): bool
30    {
31        $container = $inlineContext->getContainer();
32
33        // Checkbox must come at the beginning of the first paragraph of the list item
34        if ($container->hasChildren() || ! ($container instanceof Paragraph && $container->parent() && $container->parent() instanceof ListItem)) {
35            return false;
36        }
37
38        $cursor   = $inlineContext->getCursor();
39        $oldState = $cursor->saveState();
40
41        $cursor->advanceBy(3);
42
43        if ($cursor->getNextNonSpaceCharacter() === null) {
44            $cursor->restoreState($oldState);
45
46            return false;
47        }
48
49        $isChecked = $inlineContext->getFullMatch() !== '[ ]';
50
51        $container->appendChild(new TaskListItemMarker($isChecked));
52
53        return true;
54    }
55}
56