Passed
Pull Request — latest (#3)
by Mark
35:03
created

NodeWalker   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 70
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 10
eloc 28
c 1
b 0
f 0
dl 0
loc 70
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
B next() 0 26 8
A resumeAt() 0 4 1
A __construct() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file was originally 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 UnicornFail\Emoji\Node;
18
19
use UnicornFail\Emoji\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
    public function __construct(Node $root)
45
    {
46
        $this->root     = $root;
47
        $this->current  = $this->root;
48
        $this->entering = true;
49
    }
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
    public function next(): ?NodeWalkerEvent
57
    {
58
        $current  = $this->current;
59
        $entering = $this->entering;
60
        if ($current === null) {
61
            return null;
62
        }
63
64
        if ($entering && ($current instanceof AbstractBlock || $current->hasChildren())) {
65
            if ($current->firstChild()) {
66
                $this->current  = $current->firstChild();
67
                $this->entering = true;
68
            } else {
69
                $this->entering = false;
70
            }
71
        } elseif ($current === $this->root) {
72
            $this->current = null;
73
        } elseif ($current->next() === null) {
74
            $this->current  = $current->parent();
75
            $this->entering = false;
76
        } else {
77
            $this->current  = $current->next();
78
            $this->entering = true;
79
        }
80
81
        return new NodeWalkerEvent($current, $entering);
82
    }
83
84
    /**
85
     * Resets the iterator to resume at the specified node
86
     */
87
    public function resumeAt(Node $node, bool $entering = true): void
88
    {
89
        $this->current  = $node;
90
        $this->entering = $entering;
91
    }
92
}
93