line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
22
|
|
|
22
|
|
256756
|
use strict; |
|
22
|
|
|
|
|
74
|
|
|
22
|
|
|
|
|
787
|
|
2
|
22
|
|
|
22
|
|
149
|
use warnings; |
|
22
|
|
|
|
|
53
|
|
|
22
|
|
|
|
|
1235
|
|
3
|
|
|
|
|
|
|
package JSON::Schema::Draft201909::Utilities; |
4
|
|
|
|
|
|
|
# vim: set ts=8 sts=2 sw=2 tw=100 et : |
5
|
|
|
|
|
|
|
# ABSTRACT: Internal utilities for JSON::Schema::Draft201909 |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.028'; |
8
|
|
|
|
|
|
|
|
9
|
22
|
|
|
22
|
|
544
|
use 5.016; |
|
22
|
|
|
|
|
90
|
|
10
|
22
|
|
|
22
|
|
143
|
no if "$]" >= 5.031009, feature => 'indirect'; |
|
22
|
|
|
|
|
50
|
|
|
22
|
|
|
|
|
245
|
|
11
|
22
|
|
|
22
|
|
1146
|
no if "$]" >= 5.033001, feature => 'multidimensional'; |
|
22
|
|
|
|
|
71
|
|
|
22
|
|
|
|
|
136
|
|
12
|
22
|
|
|
22
|
|
1025
|
no if "$]" >= 5.033006, feature => 'bareword_filehandles'; |
|
22
|
|
|
|
|
53
|
|
|
22
|
|
|
|
|
140
|
|
13
|
22
|
|
|
22
|
|
2114
|
use strictures 2; |
|
22
|
|
|
|
|
3910
|
|
|
22
|
|
|
|
|
950
|
|
14
|
22
|
|
|
22
|
|
4852
|
use B; |
|
22
|
|
|
|
|
56
|
|
|
22
|
|
|
|
|
1438
|
|
15
|
22
|
|
|
22
|
|
160
|
use Carp 'croak'; |
|
22
|
|
|
|
|
54
|
|
|
22
|
|
|
|
|
1418
|
|
16
|
22
|
|
|
22
|
|
1239
|
use JSON::MaybeXS 1.004001 'is_bool'; |
|
22
|
|
|
|
|
17261
|
|
|
22
|
|
|
|
|
1646
|
|
17
|
22
|
|
|
22
|
|
1289
|
use Ref::Util 0.100 qw(is_ref is_plain_arrayref is_plain_hashref); |
|
22
|
|
|
|
|
3992
|
|
|
22
|
|
|
|
|
1440
|
|
18
|
22
|
|
|
22
|
|
1699
|
use Storable 'dclone'; |
|
22
|
|
|
|
|
8196
|
|
|
22
|
|
|
|
|
1780
|
|
19
|
22
|
|
|
22
|
|
1395
|
use Feature::Compat::Try; |
|
22
|
|
|
|
|
856
|
|
|
22
|
|
|
|
|
242
|
|
20
|
22
|
|
|
22
|
|
8719
|
use JSON::Schema::Draft201909::Error; |
|
22
|
|
|
|
|
60
|
|
|
22
|
|
|
|
|
815
|
|
21
|
22
|
|
|
22
|
|
1260
|
use JSON::Schema::Draft201909::Annotation; |
|
22
|
|
|
|
|
63
|
|
|
22
|
|
|
|
|
679
|
|
22
|
22
|
|
|
22
|
|
196
|
use namespace::clean; |
|
22
|
|
|
|
|
57
|
|
|
22
|
|
|
|
|
221
|
|
23
|
|
|
|
|
|
|
|
24
|
22
|
|
|
22
|
|
7567
|
use Exporter 'import'; |
|
22
|
|
|
|
|
63
|
|
|
22
|
|
|
|
|
1619
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
27
|
|
|
|
|
|
|
is_type |
28
|
|
|
|
|
|
|
get_type |
29
|
|
|
|
|
|
|
is_equal |
30
|
|
|
|
|
|
|
is_elements_unique |
31
|
|
|
|
|
|
|
jsonp |
32
|
|
|
|
|
|
|
local_annotations |
33
|
|
|
|
|
|
|
canonical_schema_uri |
34
|
|
|
|
|
|
|
E |
35
|
|
|
|
|
|
|
A |
36
|
|
|
|
|
|
|
abort |
37
|
|
|
|
|
|
|
assert_keyword_type |
38
|
|
|
|
|
|
|
assert_pattern |
39
|
|
|
|
|
|
|
assert_uri_reference |
40
|
|
|
|
|
|
|
assert_uri |
41
|
|
|
|
|
|
|
annotate_self |
42
|
|
|
|
|
|
|
true |
43
|
|
|
|
|
|
|
false |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
|
46
|
22
|
|
|
22
|
|
2011
|
use JSON::PP (); |
|
22
|
|
|
|
|
29745
|
|
|
22
|
|
|
|
|
1171
|
|
47
|
22
|
|
|
22
|
|
174
|
use constant { true => JSON::PP::true, false => JSON::PP::false }; |
|
22
|
|
|
|
|
57
|
|
|
22
|
|
|
|
|
128
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub is_type { |
50
|
22872
|
|
|
22872
|
0
|
288545
|
my ($type, $value) = @_; |
51
|
|
|
|
|
|
|
|
52
|
22872
|
100
|
|
|
|
52463
|
if ($type eq 'null') { |
53
|
102
|
|
|
|
|
531
|
return !(defined $value); |
54
|
|
|
|
|
|
|
} |
55
|
22770
|
100
|
|
|
|
47095
|
if ($type eq 'boolean') { |
56
|
2756
|
|
|
|
|
10342
|
return is_bool($value); |
57
|
|
|
|
|
|
|
} |
58
|
20014
|
100
|
|
|
|
40941
|
if ($type eq 'object') { |
59
|
5629
|
|
|
|
|
27331
|
return is_plain_hashref($value); |
60
|
|
|
|
|
|
|
} |
61
|
14385
|
100
|
|
|
|
30713
|
if ($type eq 'array') { |
62
|
3542
|
|
|
|
|
16396
|
return is_plain_arrayref($value); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
10843
|
100
|
100
|
|
|
40416
|
if ($type eq 'string' or $type eq 'number' or $type eq 'integer') { |
|
|
|
100
|
|
|
|
|
66
|
10842
|
100
|
100
|
|
|
45950
|
return 0 if not defined $value or is_ref($value); |
67
|
10173
|
|
|
|
|
52605
|
my $flags = B::svref_2object(\$value)->FLAGS; |
68
|
|
|
|
|
|
|
|
69
|
10173
|
100
|
|
|
|
29439
|
if ($type eq 'string') { |
70
|
6665
|
|
66
|
|
|
48642
|
return $flags & B::SVf_POK && !($flags & (B::SVf_IOK | B::SVf_NOK)); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
3508
|
100
|
|
|
|
8938
|
if ($type eq 'number') { |
74
|
2041
|
|
66
|
|
|
16100
|
return !($flags & B::SVf_POK) && ($flags & (B::SVf_IOK | B::SVf_NOK)); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
1467
|
50
|
|
|
|
3622
|
if ($type eq 'integer') { |
78
|
1467
|
|
100
|
|
|
13241
|
return !($flags & B::SVf_POK) && ($flags & (B::SVf_IOK | B::SVf_NOK)) |
79
|
|
|
|
|
|
|
&& int($value) == $value; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
1
|
|
|
|
|
161
|
croak sprintf('unknown type "%s"', $type); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# only the core six types are reported (integers are numbers) |
87
|
|
|
|
|
|
|
# use is_type('integer') to differentiate numbers from integers. |
88
|
|
|
|
|
|
|
sub get_type { |
89
|
22217
|
|
|
22217
|
0
|
100079
|
my ($value) = @_; |
90
|
|
|
|
|
|
|
|
91
|
22217
|
100
|
|
|
|
53214
|
return 'null' if not defined $value; |
92
|
22159
|
100
|
|
|
|
71909
|
return 'object' if is_plain_hashref($value); |
93
|
5034
|
100
|
|
|
|
11567
|
return 'array' if is_plain_arrayref($value); |
94
|
4684
|
100
|
|
|
|
13624
|
return 'boolean' if is_bool($value); |
95
|
|
|
|
|
|
|
|
96
|
2123
|
100
|
|
|
|
13658
|
croak sprintf('unsupported reference type %s', ref $value) if is_ref($value); |
97
|
|
|
|
|
|
|
|
98
|
2114
|
|
|
|
|
7072
|
my $flags = B::svref_2object(\$value)->FLAGS; |
99
|
2114
|
100
|
100
|
|
|
9182
|
return 'string' if $flags & B::SVf_POK && !($flags & (B::SVf_IOK | B::SVf_NOK)); |
100
|
712
|
100
|
66
|
|
|
3465
|
return 'number' if !($flags & B::SVf_POK) && ($flags & (B::SVf_IOK | B::SVf_NOK)); |
101
|
|
|
|
|
|
|
|
102
|
1
|
|
|
|
|
11
|
croak sprintf('ambiguous type for %s', |
103
|
|
|
|
|
|
|
JSON::MaybeXS->new(allow_nonref => 1, canonical => 1, utf8 => 0)->encode($value)); |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# compares two arbitrary data payloads for equality, as per |
107
|
|
|
|
|
|
|
# https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.section.4.2.3 |
108
|
|
|
|
|
|
|
# if provided with a state hashref, any differences are recorded within |
109
|
|
|
|
|
|
|
sub is_equal { |
110
|
1495
|
|
|
1495
|
0
|
3357
|
my ($x, $y, $state) = @_; |
111
|
1495
|
|
100
|
|
|
6793
|
$state->{path} //= ''; |
112
|
|
|
|
|
|
|
|
113
|
1495
|
|
|
|
|
3645
|
my @types = map get_type($_), $x, $y; |
114
|
1495
|
100
|
|
|
|
5569
|
return 0 if $types[0] ne $types[1]; |
115
|
1130
|
100
|
|
|
|
2449
|
return 1 if $types[0] eq 'null'; |
116
|
1124
|
100
|
|
|
|
4216
|
return $x eq $y if $types[0] eq 'string'; |
117
|
507
|
100
|
100
|
|
|
2767
|
return $x == $y if $types[0] eq 'boolean' or $types[0] eq 'number'; |
118
|
|
|
|
|
|
|
|
119
|
216
|
|
|
|
|
399
|
my $path = $state->{path}; |
120
|
216
|
100
|
|
|
|
469
|
if ($types[0] eq 'object') { |
121
|
88
|
100
|
|
|
|
293
|
return 0 if keys %$x != keys %$y; |
122
|
82
|
100
|
|
|
|
387
|
return 0 if not is_equal([ sort keys %$x ], [ sort keys %$y ]); |
123
|
76
|
|
|
|
|
269
|
foreach my $property (sort keys %$x) { |
124
|
94
|
|
|
|
|
208
|
$state->{path} = jsonp($path, $property); |
125
|
94
|
100
|
|
|
|
243
|
return 0 if not is_equal($x->{$property}, $y->{$property}, $state); |
126
|
|
|
|
|
|
|
} |
127
|
38
|
|
|
|
|
241
|
return 1; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
128
|
50
|
|
|
|
282
|
if ($types[0] eq 'array') { |
131
|
128
|
100
|
|
|
|
324
|
return 0 if @$x != @$y; |
132
|
124
|
|
|
|
|
198
|
foreach my $idx (0 .. $#{$x}) { |
|
124
|
|
|
|
|
382
|
|
133
|
148
|
|
|
|
|
432
|
$state->{path} = $path.'/'.$idx; |
134
|
148
|
100
|
|
|
|
358
|
return 0 if not is_equal($x->[$idx], $y->[$idx], $state); |
135
|
|
|
|
|
|
|
} |
136
|
90
|
|
|
|
|
407
|
return 1; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
0
|
return 0; # should never get here |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# checks array elements for uniqueness. short-circuits on first pair of matching elements |
143
|
|
|
|
|
|
|
# if second arrayref is provided, it is populated with the indices of identical items |
144
|
|
|
|
|
|
|
sub is_elements_unique { |
145
|
882
|
|
|
882
|
0
|
2156
|
my ($array, $equal_indices) = @_; |
146
|
882
|
|
|
|
|
1641
|
foreach my $idx0 (0 .. $#{$array}-1) { |
|
882
|
|
|
|
|
2994
|
|
147
|
357
|
|
|
|
|
715
|
foreach my $idx1 ($idx0+1 .. $#{$array}) { |
|
357
|
|
|
|
|
886
|
|
148
|
574
|
100
|
|
|
|
1500
|
if (is_equal($array->[$idx0], $array->[$idx1])) { |
149
|
62
|
50
|
|
|
|
294
|
push @$equal_indices, $idx0, $idx1 if defined $equal_indices; |
150
|
62
|
|
|
|
|
258
|
return 0; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
} |
154
|
820
|
|
|
|
|
3819
|
return 1; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# shorthand for creating and appending json pointers |
158
|
|
|
|
|
|
|
sub jsonp { |
159
|
21294
|
|
|
21294
|
0
|
224743
|
return join('/', shift, map s/~/~0/gr =~ s!/!~1!gr, grep defined, @_); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# get all annotations produced for the current instance data location (that are visible to this |
163
|
|
|
|
|
|
|
# schema location) |
164
|
|
|
|
|
|
|
sub local_annotations { |
165
|
194
|
|
|
194
|
0
|
520
|
my ($state) = @_; |
166
|
194
|
|
|
|
|
383
|
grep $_->instance_location eq $state->{data_path}, @{$state->{annotations}}; |
|
194
|
|
|
|
|
966
|
|
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# shorthand for finding the canonical uri of the present schema location |
170
|
|
|
|
|
|
|
sub canonical_schema_uri { |
171
|
13168
|
|
|
13168
|
0
|
37933
|
my ($state, @extra_path) = @_; |
172
|
|
|
|
|
|
|
|
173
|
13168
|
|
|
|
|
45617
|
my $uri = $state->{initial_schema_uri}->clone; |
174
|
13168
|
|
100
|
|
|
1046020
|
$uri->fragment(($uri->fragment//'').jsonp($state->{schema_path}, @extra_path)); |
175
|
13168
|
100
|
|
|
|
90937
|
$uri->fragment(undef) if not length($uri->fragment); |
176
|
13168
|
|
|
|
|
99587
|
$uri; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# shorthand for creating error objects |
180
|
|
|
|
|
|
|
sub E { |
181
|
3694
|
|
|
3694
|
0
|
26158
|
my ($state, $error_string, @args) = @_; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# sometimes the keyword shouldn't be at the very end of the schema path |
184
|
3694
|
|
|
|
|
14740
|
my $uri = canonical_schema_uri($state, $state->{keyword}, $state->{_schema_path_suffix}); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my $keyword_location = $state->{traversed_schema_path} |
187
|
3694
|
|
|
|
|
13618
|
.jsonp($state->{schema_path}, $state->{keyword}, delete $state->{_schema_path_suffix}); |
188
|
|
|
|
|
|
|
|
189
|
3694
|
100
|
100
|
|
|
14362
|
undef $uri if $uri eq '' and $keyword_location eq '' |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
190
|
|
|
|
|
|
|
or ($uri->fragment // '') eq $keyword_location and $uri->clone->fragment(undef) eq ''; |
191
|
|
|
|
|
|
|
|
192
|
3694
|
|
|
|
|
105577
|
push @{$state->{errors}}, JSON::Schema::Draft201909::Error->new( |
193
|
|
|
|
|
|
|
keyword => $state->{keyword}, |
194
|
|
|
|
|
|
|
instance_location => $state->{data_path}, |
195
|
3694
|
100
|
|
|
|
1241569
|
keyword_location => $keyword_location, |
|
|
100
|
|
|
|
|
|
196
|
|
|
|
|
|
|
defined $uri ? ( absolute_keyword_location => $uri ) : (), |
197
|
|
|
|
|
|
|
error => @args ? sprintf($error_string, @args) : $error_string, |
198
|
|
|
|
|
|
|
); |
199
|
|
|
|
|
|
|
|
200
|
3694
|
|
|
|
|
429478
|
return 0; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# shorthand for creating annotations |
204
|
|
|
|
|
|
|
sub A { |
205
|
2767
|
|
|
2767
|
0
|
6475
|
my ($state, $annotation) = @_; |
206
|
2767
|
100
|
|
|
|
11457
|
return 1 if not $state->{collect_annotations}; |
207
|
|
|
|
|
|
|
|
208
|
387
|
|
|
|
|
1554
|
my $uri = canonical_schema_uri($state, $state->{keyword}, $state->{_schema_path_suffix}); |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my $keyword_location = $state->{traversed_schema_path} |
211
|
387
|
|
|
|
|
1387
|
.jsonp($state->{schema_path}, $state->{keyword}, delete $state->{_schema_path_suffix}); |
212
|
|
|
|
|
|
|
|
213
|
387
|
100
|
33
|
|
|
1455
|
undef $uri if $uri eq '' and $keyword_location eq '' |
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
214
|
|
|
|
|
|
|
or ($uri->fragment // '') eq $keyword_location and $uri->clone->fragment(undef) eq ''; |
215
|
|
|
|
|
|
|
|
216
|
387
|
|
|
|
|
10014
|
push @{$state->{annotations}}, JSON::Schema::Draft201909::Annotation->new( |
217
|
|
|
|
|
|
|
keyword => $state->{keyword}, |
218
|
|
|
|
|
|
|
instance_location => $state->{data_path}, |
219
|
387
|
100
|
|
|
|
134506
|
keyword_location => $keyword_location, |
220
|
|
|
|
|
|
|
defined $uri ? ( absolute_keyword_location => $uri ) : (), |
221
|
|
|
|
|
|
|
annotation => $annotation, |
222
|
|
|
|
|
|
|
); |
223
|
|
|
|
|
|
|
|
224
|
387
|
|
|
|
|
36165
|
return 1; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# creates an error object, but also aborts evaluation immediately |
228
|
|
|
|
|
|
|
# only this error is returned, because other errors on the stack might not actually be "real" |
229
|
|
|
|
|
|
|
# errors (consider if we were in the middle of evaluating a "not" or "if") |
230
|
|
|
|
|
|
|
sub abort { |
231
|
233
|
|
|
233
|
0
|
943
|
my ($state, $error_string, @args) = @_; |
232
|
233
|
|
|
|
|
861
|
E($state, $error_string, @args); |
233
|
233
|
|
|
|
|
481
|
die pop @{$state->{errors}}; |
|
233
|
|
|
|
|
4206
|
|
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub assert_keyword_type { |
237
|
10542
|
|
|
10542
|
0
|
22737
|
my ($state, $schema, $type) = @_; |
238
|
10542
|
100
|
|
|
|
28629
|
return 1 if is_type($type, $schema->{$state->{keyword}}); |
239
|
6
|
50
|
|
|
|
40
|
E($state, '%s value is not a%s %s', $state->{keyword}, ($type =~ /^[aeiou]/ ? 'n' : ''), $type); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub assert_pattern { |
243
|
695
|
|
|
695
|
0
|
1929
|
my ($state, $pattern) = @_; |
244
|
|
|
|
|
|
|
try { |
245
|
0
|
|
|
0
|
|
0
|
local $SIG{__WARN__} = sub { die @_ }; |
246
|
|
|
|
|
|
|
qr/$pattern/; |
247
|
|
|
|
|
|
|
} |
248
|
695
|
|
|
|
|
1824
|
catch ($e) { return E($state, $e); }; |
249
|
692
|
|
|
|
|
3380
|
return 1; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub assert_uri_reference { |
253
|
769
|
|
|
769
|
0
|
1898
|
my ($state, $schema) = @_; |
254
|
|
|
|
|
|
|
|
255
|
769
|
|
|
|
|
2203
|
my $ref = $schema->{$state->{keyword}}; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
return E($state, '%s value is not a valid URI reference', $state->{keyword}) |
258
|
|
|
|
|
|
|
# see also uri-reference format sub |
259
|
769
|
100
|
66
|
|
|
2979
|
if fc(Mojo::URL->new($ref)->to_unsafe_string) ne fc($ref) |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
260
|
|
|
|
|
|
|
or $ref =~ /[^[:ascii:]]/ |
261
|
|
|
|
|
|
|
or $ref =~ /#/ |
262
|
|
|
|
|
|
|
and $ref !~ m{#$} # empty fragment |
263
|
|
|
|
|
|
|
and $ref !~ m{#[A-Za-z][A-Za-z0-9_:.-]*$} # plain-name fragment |
264
|
|
|
|
|
|
|
and $ref !~ m{#/(?:[^~]|~[01])*$}; # json pointer fragment |
265
|
|
|
|
|
|
|
|
266
|
757
|
|
|
|
|
294982
|
return 1; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub assert_uri { |
270
|
88
|
|
|
88
|
0
|
207
|
my ($state, $schema, $override) = @_; |
271
|
|
|
|
|
|
|
|
272
|
88
|
|
66
|
|
|
278
|
my $string = $override // $schema->{$state->{keyword}}; |
273
|
88
|
|
|
|
|
285
|
my $uri = Mojo::URL->new($string); |
274
|
|
|
|
|
|
|
|
275
|
88
|
50
|
66
|
|
|
8429
|
return E($state, '"%s" is not a valid URI', $string) |
|
|
|
100
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
66
|
|
|
|
|
276
|
|
|
|
|
|
|
# see also uri format sub |
277
|
|
|
|
|
|
|
if fc($uri->to_unsafe_string) ne fc($string) |
278
|
|
|
|
|
|
|
or $string =~ /[^[:ascii:]]/ |
279
|
|
|
|
|
|
|
or not $uri->is_abs |
280
|
|
|
|
|
|
|
or $string =~ /#/ |
281
|
|
|
|
|
|
|
and $string !~ m{#$} # empty fragment |
282
|
|
|
|
|
|
|
and $string !~ m{#[A-Za-z][A-Za-z0-9_:.-]*$} # plain-name fragment |
283
|
|
|
|
|
|
|
and $string !~ m{#/(?:[^~]|~[01])*$}; # json pointer fragment |
284
|
|
|
|
|
|
|
|
285
|
82
|
|
|
|
|
16881
|
return 1; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# produces an annotation whose value is the same as that of the current keyword |
289
|
|
|
|
|
|
|
sub annotate_self { |
290
|
521
|
|
|
521
|
0
|
1015
|
my ($state, $schema) = @_; |
291
|
|
|
|
|
|
|
A($state, is_ref($schema->{$state->{keyword}}) ? dclone($schema->{$state->{keyword}}) |
292
|
521
|
100
|
|
|
|
4934
|
: $schema->{$state->{keyword}}); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
1; |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
__END__ |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=pod |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=encoding UTF-8 |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head1 NAME |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
JSON::Schema::Draft201909::Utilities - Internal utilities for JSON::Schema::Draft201909 |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head1 VERSION |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
version 0.028 |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=head1 SYNOPSIS |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
use JSON::Schema::Draft201909::Utilities qw(func1 func2..); |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head1 DESCRIPTION |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
This class contains internal utilities to be used by L<JSON::Schema::Draft201909>. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=for Pod::Coverage is_type get_type is_equal is_elements_unique jsonp local_annotations |
320
|
|
|
|
|
|
|
canonical_schema_uri E A abort assert_keyword_type assert_pattern assert_uri_reference assert_uri |
321
|
|
|
|
|
|
|
annotate_self |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head1 SUPPORT |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Bugs may be submitted through L<https://github.com/karenetheridge/JSON-Schema-Draft201909/issues>. |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
I am also usually active on irc, as 'ether' at C<irc.perl.org> and C<irc.libera.chat>. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head1 AUTHOR |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Karen Etheridge <ether@cpan.org> |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENCE |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
This software is copyright (c) 2020 by Karen Etheridge. |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
338
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=cut |