NodeWalker::next()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 26
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 8

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 26
ccs 18
cts 18
cp 1
rs 8.4444
c 0
b 0
f 0
cc 8
nc 6
nop 0
crap 8
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the league/commonmark package.
7
 *
8
 * (c) Colin O'Dell <[email protected]>
9
 *
10
 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
11
 *  - (c) John MacFarlane
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
17
namespace League\CommonMark\Node;
18
19
use League\CommonMark\Node\Block\AbstractBlock;
20
21
final class NodeWalker
22
{
23
    /**
24
     * @var Node
25
     *
26
     * @psalm-readonly
27
     */
28
    private $root;
29
30
    /**
31
     * @var Node|null
32
     *
33
     * @psalm-readonly-allow-private-mutation
34
     */
35
    private $current;
36
37
    /**
38
     * @var bool
39
     *
40
     * @psalm-readonly-allow-private-mutation
41
     */
42
    private $entering;
43
44 510
    public function __construct(Node $root)
45
    {
46 510
        $this->root     = $root;
47 510
        $this->current  = $this->root;
48 510
        $this->entering = true;
49 510
    }
50
51
    /**
52
     * Returns an event which contains node and entering flag
53
     * (entering is true when we enter a Node from a parent or sibling,
54
     * and false when we reenter it from child)
55
     */
56 510
    public function next(): ?NodeWalkerEvent
57
    {
58 510
        $current  = $this->current;
59 510
        $entering = $this->entering;
60 510
        if ($current === null) {
61 498
            return null;
62
        }
63
64 510
        if ($entering && ($current instanceof AbstractBlock || $current->hasChildren())) {
65 504
            if ($current->firstChild()) {
66 501
                $this->current  = $current->firstChild();
67 501
                $this->entering = true;
68
            } else {
69 504
                $this->entering = false;
70
            }
71 507
        } elseif ($current === $this->root) {
72 498
            $this->current = null;
73 498
        } elseif ($current->next() === null) {
74 498
            $this->current  = $current->parent();
75 498
            $this->entering = false;
76
        } else {
77 477
            $this->current  = $current->next();
78 477
            $this->entering = true;
79
        }
80
81 510
        return new NodeWalkerEvent($current, $entering);
82
    }
83
84
    /**
85
     * Resets the iterator to resume at the specified node
86
     */
87 45
    public function resumeAt(Node $node, bool $entering = true): void
88
    {
89 45
        $this->current  = $node;
90 45
        $this->entering = $entering;
91 45
    }
92
}
93