Pointer   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 24
c 5
b 0
f 0
dl 0
loc 124
ccs 28
cts 28
cp 1
rs 10
wmc 15

7 Methods

Rating   Name   Duplication   Size   Complexity  
A call() 0 7 2
A includesTree() 0 8 3
A depthMatchesKey() 0 6 3
A matchesTree() 0 5 3
A toReferenceTokens() 0 10 2
A __construct() 0 7 1
A __toString() 0 3 1
1
<?php
2
3
namespace Cerbero\JsonParser\Pointers;
4
5
use Cerbero\JsonParser\Exceptions\InvalidPointerException;
6
use Cerbero\JsonParser\ValueObjects\Tree;
7
use Closure;
8
use Stringable;
9
10
use function count;
11
use function is_int;
12
use function array_slice;
13
14
/**
15
 * The JSON pointer.
16
 *
17
 */
18
final class Pointer implements Stringable
19
{
20
    /**
21
     * The reference tokens.
22
     *
23
     * @var string[]
24
     */
25
    public readonly array $referenceTokens;
26
27
    /**
28
     * The pointer depth.
29
     *
30
     * @var int
31
     */
32
    public readonly int $depth;
33
34
    /**
35
     * Whether the pointer was found.
36
     *
37
     * @var bool
38
     */
39
    public bool $wasFound = false;
40
41
    /**
42
     * Instantiate the class.
43
     *
44
     * @param string $pointer
45
     * @param bool $isLazy
46
     * @param Closure|null $callback
47
     */
48 369
    public function __construct(
49
        private readonly string $pointer,
50
        public readonly bool $isLazy = false,
51
        private readonly ?Closure $callback = null,
52
    ) {
53 369
        $this->referenceTokens = $this->toReferenceTokens();
0 ignored issues
show
Bug introduced by
The property referenceTokens is declared read-only in Cerbero\JsonParser\Pointers\Pointer.
Loading history...
54 365
        $this->depth = count($this->referenceTokens);
0 ignored issues
show
Bug introduced by
The property depth is declared read-only in Cerbero\JsonParser\Pointers\Pointer.
Loading history...
55
    }
56
57
    /**
58
     * Turn the JSON pointer into reference tokens
59
     *
60
     * @return string[]
61
     */
62 369
    private function toReferenceTokens(): array
63
    {
64 369
        if (preg_match('#^(?:/(?:(?:[^/~])|(?:~[01]))*)*$#', $this->pointer) === 0) {
65 4
            throw new InvalidPointerException($this->pointer);
66
        }
67
68 365
        $tokens = explode('/', $this->pointer);
69 365
        $referenceTokens = array_map(fn (string $token) => str_replace(['~1', '~0'], ['/', '~'], $token), $tokens);
70
71 365
        return array_slice($referenceTokens, 1);
72
    }
73
74
    /**
75
     * Call the pointer callback
76
     *
77
     * @param mixed $value
78
     * @param mixed $key
79
     * @return mixed
80
     */
81 264
    public function call(mixed $value, mixed &$key): mixed
82
    {
83 264
        if ($this->callback === null) {
84 260
            return $value;
85
        }
86
87 4
        return ($this->callback)($value, $key) ?? $value;
88
    }
89
90
    /**
91
     * Determine whether the reference token at the given depth matches the provided key
92
     *
93
     * @param int $depth
94
     * @param string|int $key
95
     * @return bool
96
     */
97 84
    public function depthMatchesKey(int $depth, string|int $key): bool
98
    {
99 84
        $referenceToken = $this->referenceTokens[$depth] ?? null;
100
101 84
        return $referenceToken === (string) $key
102 84
            || (is_int($key) && $referenceToken === '-');
103
    }
104
105
    /**
106
     * Determine whether the pointer matches the given tree
107
     *
108
     * @param Tree $tree
109
     * @return bool
110
     */
111 355
    public function matchesTree(Tree $tree): bool
112
    {
113 355
        return $this->referenceTokens == []
114 355
            || $this->referenceTokens == $tree->original()
115 355
            || $this->referenceTokens == $tree->wildcarded();
116
    }
117
118
    /**
119
     * Determine whether the pointer includes the given tree
120
     *
121
     * @param Tree $tree
122
     * @return bool
123
     */
124 214
    public function includesTree(Tree $tree): bool
125
    {
126 214
        if ($this->pointer == '') {
127 28
            return true;
128
        }
129
130 197
        return is_int($firstNest = array_search('-', $this->referenceTokens))
131 197
            && array_slice($this->referenceTokens, 0, $firstNest) === array_slice($tree->original(), 0, $firstNest);
132
    }
133
134
    /**
135
     * Retrieve the underlying JSON pointer
136
     *
137
     * @return string
138
     */
139 365
    public function __toString(): string
140
    {
141 365
        return $this->pointer;
142
    }
143
}
144