-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathReferenceResolver.php
More file actions
170 lines (140 loc) · 4.76 KB
/
Copy pathReferenceResolver.php
File metadata and controls
170 lines (140 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?php
declare(strict_types=1);
namespace Jane\Component\JsonSchemaRuntime;
/**
* Holds the configuration and the fetch caches used while resolving
* {@see Reference} instances.
*
* State that used to live in static properties on {@see Reference} moved here
* so resolution can be configured and cached per object graph instead of
* process-wide. The generation entry points ({@see \Jane\Component\JsonSchema\Jane::build()}
* and {@see \Jane\Component\OpenApiCommon\JaneOpenApi::build()}) create a
* dedicated resolver for the run and thread it through the pipeline; bare
* `new Reference($ref, $origin)` calls emitted in generated code fall back to
* the shared default instance returned by {@see self::default()}.
*/
final class ReferenceResolver
{
/** @var array<string, string> */
private array $fileCache = [];
/** @var array<string, \Rs\Json\Pointer> */
private array $pointerCache = [];
/** @var array<string, mixed> */
private array $arrayCache = [];
private bool $allowExternalRefs = false;
/** @var array<string> */
private array $allowedExternalHosts = [];
private bool $followRedirects = false;
/** @var array<string> */
private array $allowedLocalRefRoots = [];
private static ?self $default = null;
/**
* Process-wide resolver used by generated code that constructs references
* without an explicit resolver.
*/
public static function default(): self
{
return self::$default ??= new self();
}
/**
* Apply the reference-related options accepted by the generation entry
* points (`allow-external-refs`, `external-ref-allowed-hosts`,
* `external-ref-follow-redirects`, `allowed-local-ref-roots`).
*
* @param array<string, mixed> $options
*/
public function applyOptions(array $options): void
{
$this->resetConfiguration();
$this->setAllowExternalRefs((bool) ($options['allow-external-refs'] ?? false));
$this->setAllowedExternalHosts($options['external-ref-allowed-hosts'] ?? []);
$this->setFollowRedirects((bool) ($options['external-ref-follow-redirects'] ?? false));
$this->setAllowedLocalRefRoots($options['allowed-local-ref-roots'] ?? []);
}
public function setAllowExternalRefs(bool $allow = true): void
{
$this->allowExternalRefs = $allow;
}
public function setAllowedExternalHosts(array $hosts): void
{
$this->allowedExternalHosts = $hosts;
}
public function setAllowedLocalRefRoots(array $roots): void
{
$this->allowedLocalRefRoots = $roots;
}
/**
* Allow (or forbid) following HTTP redirects when fetching external
* references. Disabled by default: an allowlisted host must not be able
* to bounce the fetch to an arbitrary, possibly non allowlisted host.
*/
public function setFollowRedirects(bool $allow = true): void
{
$this->followRedirects = $allow;
}
public function resetConfiguration(): void
{
$this->allowExternalRefs = false;
$this->allowedExternalHosts = [];
$this->followRedirects = false;
$this->allowedLocalRefRoots = [];
}
public function allowsExternalRefs(): bool
{
return $this->allowExternalRefs;
}
/**
* @return array<string>
*/
public function getAllowedExternalHosts(): array
{
return $this->allowedExternalHosts;
}
/**
* @return array<string>
*/
public function getAllowedLocalRefRoots(): array
{
return $this->allowedLocalRefRoots;
}
public function followsRedirects(): bool
{
return $this->followRedirects;
}
public function hasFile(string $fragment): bool
{
return \array_key_exists($fragment, $this->fileCache);
}
public function getFile(string $fragment): string
{
return $this->fileCache[$fragment];
}
public function setFile(string $fragment, string $contents): void
{
$this->fileCache[$fragment] = $contents;
}
public function hasArray(string $reference): bool
{
return \array_key_exists($reference, $this->arrayCache);
}
public function getArray(string $reference): mixed
{
return $this->arrayCache[$reference];
}
public function setArray(string $reference, mixed $value): void
{
$this->arrayCache[$reference] = $value;
}
public function hasPointer(string $fragment): bool
{
return \array_key_exists($fragment, $this->pointerCache);
}
public function getPointer(string $fragment): \Rs\Json\Pointer
{
return $this->pointerCache[$fragment];
}
public function setPointer(string $fragment, \Rs\Json\Pointer $pointer): void
{
$this->pointerCache[$fragment] = $pointer;
}
}