Completed
Push — feature/resolve-parent-class ( 1a8a55...248da8 )
by Colin
35:17 queued 33:54
created

Node::walker()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 *
8
 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
9
 *  - (c) John MacFarlane
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace League\CommonMark\Node;
16
17
abstract class Node
18
{
19
    /**
20
     * @var int
21
     */
22
    protected $depth = 0;
23
24
    /**
25
     * @var Node|null
26
     */
27
    protected $parent;
28
29
    /**
30
     * @var Node|null
31
     */
32
    protected $previous;
33
34
    /**
35
     * @var Node|null
36
     */
37
    protected $next;
38
39
    /**
40
     * @var Node|null
41
     */
42
    protected $firstChild;
43
44
    /**
45
     * @var Node|null
46
     */
47
    protected $lastChild;
48
49
    /**
50
     * @return Node|null
51
     */
52 534
    public function previous(): ?Node
53
    {
54 534
        return $this->previous;
55
    }
56
57
    /**
58
     * @return Node|null
59
     */
60 2487
    public function next(): ?Node
61
    {
62 2487
        return $this->next;
63
    }
64
65
    /**
66
     * @return Node|null
67
     */
68 2517
    public function parent(): ?Node
69
    {
70 2517
        return $this->parent;
71
    }
72
73
    /**
74
     * @param Node|null $node
75
     */
76 2571
    protected function setParent(Node $node = null)
77
    {
78 2571
        $this->parent = $node;
79 2571
        $this->depth = ($node === null) ? 0 : $node->depth + 1;
80 2571
    }
81
82
    /**
83
     * Inserts the $sibling node after $this
84
     *
85
     * @param Node $sibling
86
     */
87 2049
    public function insertAfter(Node $sibling)
88
    {
89 2049
        $sibling->detach();
90 2049
        $sibling->next = $this->next;
91
92 2049
        if ($sibling->next) {
93 807
            $sibling->next->previous = $sibling;
94
        }
95
96 2049
        $sibling->previous = $this;
97 2049
        $this->next = $sibling;
98 2049
        $sibling->setParent($this->parent);
99
100 2049
        if (!$sibling->next && $sibling->parent) {
101 2040
            $sibling->parent->lastChild = $sibling;
102
        }
103 2049
    }
104
105
    /**
106
     * Inserts the $sibling node before $this
107
     *
108
     * @param Node $sibling
109
     */
110 186
    public function insertBefore(Node $sibling)
111
    {
112 186
        $sibling->detach();
113 186
        $sibling->previous = $this->previous;
114
115 186
        if ($sibling->previous) {
116 111
            $sibling->previous->next = $sibling;
117
        }
118
119 186
        $sibling->next = $this;
120 186
        $this->previous = $sibling;
121 186
        $sibling->setParent($this->parent);
122
123 186
        if (!$sibling->previous && $sibling->parent) {
124 138
            $sibling->parent->firstChild = $sibling;
125
        }
126 186
    }
127
128 483
    public function replaceWith(Node $replacement)
129
    {
130 483
        $replacement->detach();
131 483
        $this->insertAfter($replacement);
132 483
        $this->detach();
133 483
    }
134
135 2568
    public function detach()
136
    {
137 2568
        if ($this->previous) {
138 1332
            $this->previous->next = $this->next;
139 2568
        } elseif ($this->parent) {
140 690
            $this->parent->firstChild = $this->next;
141
        }
142
143 2568
        if ($this->next) {
144 1191
            $this->next->previous = $this->previous;
145 2568
        } elseif ($this->parent) {
146 1149
            $this->parent->lastChild = $this->previous;
147
        }
148
149 2568
        $this->parent = null;
150 2568
        $this->next = null;
151 2568
        $this->previous = null;
152 2568
        $this->depth = 0;
153 2568
    }
154
155
    /**
156
     * @return bool
157
     */
158
    abstract public function isContainer(): bool;
159
160
    /**
161
     * @return Node|null
162
     */
163 2484
    public function firstChild(): ?Node
164
    {
165 2484
        return $this->firstChild;
166
    }
167
168
    /**
169
     * @return Node|null
170
     */
171 2469
    public function lastChild(): ?Node
172
    {
173 2469
        return $this->lastChild;
174
    }
175
176
    /**
177
     * @return Node[]
178
     */
179 2574
    public function children(): iterable
180
    {
181 2574
        $children = [];
182 2574
        for ($current = $this->firstChild; null !== $current; $current = $current->next) {
183 2484
            $children[] = $current;
184
        }
185
186 2574
        return $children;
187
    }
188
189
    /**
190
     * @param Node $child
191
     */
192 2550
    public function appendChild(Node $child)
193
    {
194 2550
        if ($this->lastChild) {
195 2022
            $this->lastChild->insertAfter($child);
196
        } else {
197 2550
            $child->detach();
198 2550
            $child->setParent($this);
199 2550
            $this->lastChild = $this->firstChild = $child;
200
        }
201 2550
    }
202
203
    /**
204
     * Adds $child as the very first child of $this
205
     *
206
     * @param Node $child
207
     */
208 18
    public function prependChild(Node $child)
209
    {
210 18
        if ($this->firstChild) {
211 15
            $this->firstChild->insertBefore($child);
212
        } else {
213 6
            $child->detach();
214 6
            $child->setParent($this);
215 6
            $this->lastChild = $this->firstChild = $child;
216
        }
217 18
    }
218
219
    /**
220
     * Detaches all child nodes of given node
221
     */
222 6
    public function detachChildren()
223
    {
224 6
        foreach ($this->children() as $children) {
225 6
            $children->setParent(null);
226
        }
227 6
        $this->firstChild = $this->lastChild = null;
228 6
    }
229
230
    /**
231
     * Replace all children of given node with collection of another
232
     *
233
     * @param iterable $children
234
     *
235
     * @return $this
236
     */
237 3
    public function replaceChildren(iterable $children)
238
    {
239 3
        $this->detachChildren();
240 3
        foreach ($children as $item) {
241 3
            $this->appendChild($item);
242
        }
243
244 3
        return $this;
245
    }
246
247
    /**
248
     * @return int
249
     */
250 432
    public function getDepth(): int
251
    {
252 432
        return $this->depth;
253
    }
254
255
    /**
256
     * @return NodeWalker
257
     */
258 2469
    public function walker(): NodeWalker
259
    {
260 2469
        return new NodeWalker($this);
261
    }
262
}
263