Passed
Branch feature/first-release (5d23f8)
by Andrea Marco
10:49
created

Tree::traverseToken()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 7
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 10
ccs 8
cts 8
cp 1
crap 6
rs 9.2222
1
<?php
2
3
namespace Cerbero\JsonParser;
4
5
use Cerbero\JsonParser\Pointers\Pointers;
6
use Cerbero\JsonParser\Tokens\Token;
7
8
use function count;
9
10
/**
11
 * The JSON tree.
12
 *
13
 */
14
final class Tree
15
{
16
    /**
17
     * The original JSON tree.
18
     *
19
     * @var array<int, string|int>
20
     */
21
    private array $original = [];
22
23
    /**
24
     * The wildcarded JSON tree.
25
     *
26
     * @var array<int, string|int>
27
     */
28
    private array $wildcarded = [];
29
30
    /**
31
     * Whether a depth is within an object.
32
     *
33
     * @var array<int, bool>
34
     */
35
    private array $inObjectByDepth = [];
36
37
    /**
38
     * The JSON tree depth.
39
     *
40
     * @var int
41
     */
42
    private int $depth = -1;
43
44
    /**
45
     * Instantiate the class.
46
     *
47
     * @param Pointers $pointers
48
     */
49 140
    public function __construct(private Pointers $pointers)
50
    {
51 140
    }
52
53
    /**
54
     * Retrieve the original JSON tree
55
     *
56
     * @return array<int, string|int>
57
     */
58 95
    public function original(): array
59
    {
60 95
        return $this->original;
61
    }
62
63
    /**
64
     * Retrieve the wildcarded JSON tree
65
     *
66
     * @return array<int, string|int>
67
     */
68 88
    public function wildcarded(): array
69
    {
70 88
        return $this->wildcarded;
71
    }
72
73
    /**
74
     * Determine whether the current depth is within an object
75
     *
76
     * @return bool
77
     */
78 136
    public function inObject(): bool
79
    {
80 136
        return $this->inObjectByDepth[$this->depth] ?? false;
81
    }
82
83
    /**
84
     * Retrieve the JSON tree depth
85
     *
86
     * @return int
87
     */
88 9
    public function depth(): int
89
    {
90 9
        return $this->depth;
91
    }
92
93
    /**
94
     * Increase the tree depth by entering an object or an array
95
     *
96
     * @param bool $inObject
97
     * @return void
98
     */
99 136
    public function deepen(bool $inObject): void
100
    {
101 136
        $this->depth++;
102 136
        $this->inObjectByDepth[$this->depth] = $inObject;
103
    }
104
105
    /**
106
     * Decrease the tree depth
107
     *
108
     * @return void
109
     */
110 100
    public function emerge(): void
111
    {
112 100
        $this->depth--;
113
    }
114
115
    /**
116
     * Determine whether the tree is deep
117
     *
118
     * @return bool
119
     */
120 134
    public function isDeep(): bool
121
    {
122 134
        $pointer = $this->pointers->matching();
123
124 134
        return $pointer == '' ? $this->depth > $pointer->depth() : $this->depth >= $pointer->depth();
0 ignored issues
show
introduced by
The condition $pointer == '' is always false.
Loading history...
125
    }
126
127
    /**
128
     * Traverse the given token
129
     *
130
     * @param Token $token
131
     * @param bool $expectsKey
132
     * @return void
133
     */
134 136
    public function traverseToken(Token $token, bool $expectsKey): void
135
    {
136 136
        $pointer = $this->pointers->matching();
137
138 136
        if ($pointer != '' && $this->depth >= $pointer->depth()) {
139 47
            return;
140 136
        } elseif ($expectsKey) {
141 96
            $this->traverseKey($token);
142 136
        } elseif ($token->isValue() && !$this->inObject()) {
143 136
            $this->traverseArray();
144
        }
145
    }
146
147
    /**
148
     * Determine whether the tree is matched by the JSON pointer
149
     *
150
     * @return bool
151
     */
152 136
    public function isMatched(): bool
153
    {
154 136
        if ($isMatched = $this->depth >= 0 && $this->pointers->matching()->matchesTree($this)) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: $isMatched = ($this->dep...()->matchesTree($this)), Probably Intended Meaning: ($isMatched = $this->dep...g()->matchesTree($this)
Loading history...
155 110
            $this->pointers->markAsFound();
156
        }
157
158 136
        return $isMatched;
159
    }
160
161
    /**
162
     * Traverse the given object key
163
     *
164
     * @param string $key
165
     * @return void
166
     */
167 96
    public function traverseKey(string $key): void
168
    {
169 96
        $trimmedKey = substr($key, 1, -1);
170
171 96
        $this->original[$this->depth] = $trimmedKey;
172 96
        $this->wildcarded[$this->depth] = $trimmedKey;
173 96
        $this->pointers->matchTree($this);
174
    }
175
176
    /**
177
     * Traverse an array
178
     *
179
     * @return void
180
     */
181 136
    public function traverseArray(): void
182
    {
183 136
        $index = $this->original[$this->depth] ?? null;
184 136
        $this->original[$this->depth] = $index = is_int($index) ? $index + 1 : 0;
185
186 136
        if (count($this->original) > $this->depth + 1) {
187 136
            array_splice($this->original, $this->depth + 1);
188
        }
189
190 136
        $referenceTokens = $this->pointers->matchTree($this)->referenceTokens();
191 136
        $this->wildcarded[$this->depth] = ($referenceTokens[$this->depth] ?? null) == '-' ? '-' : $index;
192
193 136
        if (count($this->wildcarded) > $this->depth + 1) {
194 136
            array_splice($this->wildcarded, $this->depth + 1);
195
        }
196
    }
197
198
    /**
199
     * Retrieve the current key
200
     *
201
     * @return string|int
202
     */
203 102
    public function currentKey(): string|int
204
    {
205 102
        $key = $this->original[$this->depth];
206
207 102
        return is_string($key) ? "\"$key\"" : $key;
208
    }
209
}
210