line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package JSV::Context; |
2
|
|
|
|
|
|
|
|
3
|
47
|
|
|
47
|
|
642
|
use strict; |
|
47
|
|
|
|
|
53
|
|
|
47
|
|
|
|
|
1084
|
|
4
|
47
|
|
|
47
|
|
134
|
use warnings; |
|
47
|
|
|
|
|
46
|
|
|
47
|
|
|
|
|
1895
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
use Class::Accessor::Lite ( |
7
|
47
|
|
|
|
|
326
|
new => 1, |
8
|
|
|
|
|
|
|
rw => [qw/ |
9
|
|
|
|
|
|
|
keywords |
10
|
|
|
|
|
|
|
reference |
11
|
|
|
|
|
|
|
original_schema |
12
|
|
|
|
|
|
|
throw_error |
13
|
|
|
|
|
|
|
throw_immediate |
14
|
|
|
|
|
|
|
enable_history |
15
|
|
|
|
|
|
|
enable_format |
16
|
|
|
|
|
|
|
formats |
17
|
|
|
|
|
|
|
history |
18
|
|
|
|
|
|
|
json |
19
|
|
|
|
|
|
|
loose_type |
20
|
|
|
|
|
|
|
/], |
21
|
|
|
|
|
|
|
ro => [qw/ |
22
|
|
|
|
|
|
|
errors |
23
|
|
|
|
|
|
|
current_type |
24
|
|
|
|
|
|
|
current_keyword |
25
|
|
|
|
|
|
|
current_pointer |
26
|
|
|
|
|
|
|
current_instance |
27
|
|
|
|
|
|
|
current_schema |
28
|
|
|
|
|
|
|
current_schema_pointer |
29
|
|
|
|
|
|
|
schema_pointer_history |
30
|
|
|
|
|
|
|
/], |
31
|
47
|
|
|
47
|
|
143
|
); |
|
47
|
|
|
|
|
45
|
|
32
|
|
|
|
|
|
|
|
33
|
47
|
|
|
47
|
|
7624
|
use Carp qw(croak); |
|
47
|
|
|
|
|
46
|
|
|
47
|
|
|
|
|
1819
|
|
34
|
47
|
|
|
47
|
|
143
|
use JSON; |
|
47
|
|
|
|
|
47
|
|
|
47
|
|
|
|
|
180
|
|
35
|
47
|
|
|
47
|
|
4105
|
use JSV::Keyword qw(:constants); |
|
47
|
|
|
|
|
45
|
|
|
47
|
|
|
|
|
4685
|
|
36
|
47
|
|
|
47
|
|
14461
|
use JSV::Util::Type qw(detect_instance_type detect_instance_type_loose); |
|
47
|
|
|
|
|
75
|
|
|
47
|
|
|
|
|
2176
|
|
37
|
47
|
|
|
47
|
|
13573
|
use JSV::Result; |
|
47
|
|
|
|
|
82
|
|
|
47
|
|
|
|
|
1139
|
|
38
|
47
|
|
|
47
|
|
189
|
use Clone qw(clone); |
|
47
|
|
|
|
|
45
|
|
|
47
|
|
|
|
|
32939
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub validate { |
41
|
1421
|
|
|
1421
|
0
|
1398
|
my ($self, $schema, $instance) = @_; |
42
|
|
|
|
|
|
|
|
43
|
1421
|
100
|
|
|
|
2181
|
local $self->{current_type} = !$self->loose_type ? detect_instance_type($instance) |
44
|
|
|
|
|
|
|
: detect_instance_type_loose($instance); |
45
|
|
|
|
|
|
|
|
46
|
1421
|
|
|
|
|
1968
|
local $self->{cleanup_callbacks} = []; |
47
|
|
|
|
|
|
|
|
48
|
1421
|
|
|
|
|
1059
|
my $rv; |
49
|
1421
|
|
|
|
|
1390
|
eval { |
50
|
1421
|
|
|
|
|
1018
|
for my $keyword (@{ $self->keywords->{INSTANCE_TYPE_ANY()} }) { |
|
1421
|
|
|
|
|
2172
|
|
51
|
11368
|
100
|
|
|
|
27505
|
next unless exists $schema->{$keyword->keyword}; |
52
|
1224
|
|
|
|
|
1574
|
$self->apply_keyword($keyword, $schema, $instance); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
1421
|
100
|
|
|
|
5980
|
if ($self->is_matched_types(qw/integer_or_string number_or_string/)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
56
|
212
|
|
|
|
|
173
|
for my $keyword ( |
57
|
212
|
|
|
|
|
397
|
@{ $self->keywords->{INSTANCE_TYPE_NUMERIC()} }, |
58
|
212
|
|
|
|
|
710
|
@{ $self->keywords->{INSTANCE_TYPE_STRING()} } |
59
|
|
|
|
|
|
|
) { |
60
|
1484
|
100
|
|
|
|
3987
|
next unless exists $schema->{$keyword->keyword}; |
61
|
85
|
|
|
|
|
119
|
$self->apply_keyword($keyword, $schema, $instance); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
elsif ($self->is_matched_types(qw/integer number/)) { |
65
|
237
|
|
|
|
|
188
|
for my $keyword (@{ $self->keywords->{INSTANCE_TYPE_NUMERIC()} }) { |
|
237
|
|
|
|
|
381
|
|
66
|
711
|
100
|
|
|
|
2439
|
next unless exists $schema->{$keyword->keyword}; |
67
|
62
|
|
|
|
|
90
|
$self->apply_keyword($keyword, $schema, $instance); |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
elsif ($self->is_matched_types(qw/string/)) { |
71
|
439
|
|
|
|
|
335
|
for my $keyword (@{ $self->keywords->{INSTANCE_TYPE_STRING()} }) { |
|
439
|
|
|
|
|
648
|
|
72
|
1756
|
100
|
|
|
|
5447
|
next unless exists $schema->{$keyword->keyword}; |
73
|
108
|
|
|
|
|
158
|
$self->apply_keyword($keyword, $schema, $instance); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
elsif ($self->current_type eq "array") { |
77
|
157
|
|
|
|
|
579
|
for my $keyword (@{ $self->keywords->{INSTANCE_TYPE_ARRAY()} }) { |
|
157
|
|
|
|
|
224
|
|
78
|
628
|
100
|
|
|
|
2267
|
next unless exists $schema->{$keyword->keyword}; |
79
|
139
|
|
|
|
|
197
|
$self->apply_keyword($keyword, $schema, $instance); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
elsif ($self->current_type eq "object") { |
83
|
328
|
|
|
|
|
2312
|
for my $keyword (@{ $self->keywords->{INSTANCE_TYPE_OBJECT()} }) { |
|
328
|
|
|
|
|
501
|
|
84
|
|
|
|
|
|
|
### for addtionalProperties, patternProperties keyword without properties keyword |
85
|
1640
|
50
|
|
|
|
4393
|
next unless ( ( grep { defined $_ && exists $schema->{$_} } ($keyword->keyword, @{$keyword->additional_keywords}) ) > 0 ); |
|
2296
|
100
|
|
|
|
5977
|
|
|
1640
|
|
|
|
|
2595
|
|
86
|
|
|
|
|
|
|
# next unless exists $schema->{$_->keyword}; |
87
|
418
|
|
|
|
|
638
|
$self->apply_keyword($keyword, $schema, $instance); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
1421
|
50
|
|
|
|
3503
|
$rv = JSV::Result->new( |
92
|
|
|
|
|
|
|
($self->enable_history ? (history => $self->history) : ()), |
93
|
|
|
|
|
|
|
); |
94
|
|
|
|
|
|
|
}; |
95
|
1421
|
50
|
|
|
|
2209
|
if ( my $e = $@ ) { |
96
|
0
|
|
|
|
|
0
|
$self->log_error(sprintf("Unexpected error: %s", $e)); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
1421
|
|
|
|
|
1043
|
while (my $cb = pop @{ $self->{cleanup_callbacks} }) { |
|
1542
|
|
|
|
|
2939
|
|
100
|
121
|
|
|
|
|
191
|
$cb->(); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
1421
|
100
|
|
|
|
1001
|
if ( scalar @{ $self->errors } ) { |
|
1421
|
|
|
|
|
2010
|
|
104
|
587
|
50
|
|
|
|
2491
|
$rv = JSV::Result->new( |
105
|
|
|
|
|
|
|
errors => $self->errors, |
106
|
|
|
|
|
|
|
($self->enable_history ? (history => $self->history) : ()), |
107
|
|
|
|
|
|
|
); |
108
|
587
|
50
|
|
|
|
1272
|
if ( $self->throw_error ) { |
109
|
0
|
|
|
|
|
0
|
croak $rv; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
1421
|
|
|
|
|
14117
|
return $rv; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub apply_keyword { |
117
|
2036
|
|
|
2036
|
0
|
2325
|
my ($self, $keyword, $schema, $instance) = @_; |
118
|
|
|
|
|
|
|
|
119
|
2036
|
|
|
|
|
3317
|
local $self->{current_keyword} = $keyword->keyword; |
120
|
2036
|
|
|
|
|
1923
|
local $self->{current_schema} = $schema; |
121
|
2036
|
|
|
|
|
1876
|
local $self->{current_instance} = $instance; |
122
|
|
|
|
|
|
|
|
123
|
2036
|
|
|
|
|
3872
|
$keyword->validate($self, $schema, $instance); |
124
|
|
|
|
|
|
|
|
125
|
2036
|
50
|
33
|
|
|
7005
|
if ( $ENV{JSV_DEBUG} || $self->enable_history ) { |
126
|
0
|
|
|
|
|
0
|
push @{ $self->history }, +{ |
|
0
|
|
|
|
|
0
|
|
127
|
|
|
|
|
|
|
keyword => $self->current_keyword, |
128
|
|
|
|
|
|
|
pointer => $self->current_pointer, |
129
|
|
|
|
|
|
|
schema => $self->current_schema, |
130
|
|
|
|
|
|
|
instance => $self->resolve_current_instance, |
131
|
|
|
|
|
|
|
}; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub log_error { |
136
|
422
|
|
|
422
|
0
|
427
|
my ($self, $message) = @_; |
137
|
|
|
|
|
|
|
|
138
|
422
|
|
|
|
|
724
|
my $error = +{ |
139
|
|
|
|
|
|
|
keyword => $self->current_keyword, |
140
|
|
|
|
|
|
|
pointer => $self->current_pointer, |
141
|
|
|
|
|
|
|
schema => $self->current_schema, |
142
|
|
|
|
|
|
|
instance => $self->resolve_current_instance, |
143
|
|
|
|
|
|
|
schema_pointer => $self->current_schema_pointer, |
144
|
|
|
|
|
|
|
schema_pointer_history => clone($self->schema_pointer_history), |
145
|
|
|
|
|
|
|
message => $message, |
146
|
|
|
|
|
|
|
}; |
147
|
|
|
|
|
|
|
|
148
|
422
|
50
|
|
|
|
4922
|
if ( $ENV{JSV_DEBUG} ) { |
149
|
0
|
|
|
|
|
0
|
require Data::Dump; |
150
|
0
|
|
|
|
|
0
|
warn "history = " . Data::Dump::dump($self->history); |
151
|
0
|
|
|
|
|
0
|
warn "error = " . Data::Dump::dump($error); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
422
|
50
|
|
|
|
695
|
if ( $self->throw_immediate ) { |
155
|
0
|
0
|
|
|
|
0
|
croak JSV::Result->new( |
156
|
|
|
|
|
|
|
error => $error, |
157
|
|
|
|
|
|
|
($self->enable_history ? (history => $self->history) : ()), |
158
|
|
|
|
|
|
|
); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
else { |
161
|
422
|
|
|
|
|
1136
|
push @{ $self->{errors} }, $error; |
|
422
|
|
|
|
|
991
|
|
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub resolve_current_instance { |
166
|
422
|
|
|
422
|
0
|
3117
|
my $self = shift; |
167
|
|
|
|
|
|
|
|
168
|
422
|
|
|
|
|
317
|
my $instance; |
169
|
422
|
100
|
|
|
|
636
|
if ( JSON::is_bool($self->current_instance) ) { |
170
|
11
|
100
|
|
|
|
69
|
if ( $self->current_instance == JSON::true ) { |
171
|
9
|
|
|
|
|
83
|
$instance = "true"; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
else { |
174
|
2
|
|
|
|
|
21
|
$instance = "false"; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
else { |
178
|
411
|
|
|
|
|
2924
|
$instance = $self->current_instance; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
422
|
|
|
|
|
1796
|
return $instance; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub is_matched_types { |
185
|
3602
|
|
|
3602
|
0
|
3891
|
my ($self, @types) = @_; |
186
|
|
|
|
|
|
|
|
187
|
3602
|
100
|
|
|
|
2972
|
return (grep { $self->{current_type} eq $_ } @types) > 0 ? 1 : 0; |
|
6232
|
|
|
|
|
12859
|
|
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub register_cleanup_callback { |
191
|
121
|
|
|
121
|
0
|
99
|
my ($self, $cb) = @_; |
192
|
|
|
|
|
|
|
|
193
|
121
|
|
|
|
|
82
|
push @{ $self->{cleanup_callbacks} }, $cb; |
|
121
|
|
|
|
|
208
|
|
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
1; |