line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package JSONSchema::Validator; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Validator for JSON Schema Draft4/Draft6/Draft7 and OpenAPI Specification 3.0 |
4
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
413989
|
use strict; |
|
6
|
|
|
|
|
68
|
|
|
6
|
|
|
|
|
170
|
|
6
|
6
|
|
|
6
|
|
30
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
136
|
|
7
|
6
|
|
|
6
|
|
2594
|
use URI::file; |
|
6
|
|
|
|
|
82562
|
|
|
6
|
|
|
|
|
196
|
|
8
|
6
|
|
|
6
|
|
46
|
use Carp 'croak'; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
289
|
|
9
|
6
|
|
|
6
|
|
33
|
use Cwd; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
246
|
|
10
|
|
|
|
|
|
|
|
11
|
6
|
|
|
6
|
|
2942
|
use JSONSchema::Validator::Draft4; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
193
|
|
12
|
6
|
|
|
6
|
|
2895
|
use JSONSchema::Validator::Draft6; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
165
|
|
13
|
6
|
|
|
6
|
|
2753
|
use JSONSchema::Validator::Draft7; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
175
|
|
14
|
6
|
|
|
6
|
|
2825
|
use JSONSchema::Validator::OAS30; |
|
6
|
|
|
|
|
37
|
|
|
6
|
|
|
|
|
239
|
|
15
|
6
|
|
|
6
|
|
50
|
use JSONSchema::Validator::Util qw(get_resource decode_content read_file); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
5927
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.010'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $SPECIFICATIONS = { |
20
|
|
|
|
|
|
|
JSONSchema::Validator::OAS30::ID => JSONSchema::Validator::OAS30::SPECIFICATION, |
21
|
|
|
|
|
|
|
JSONSchema::Validator::Draft4::ID => JSONSchema::Validator::Draft4::SPECIFICATION, |
22
|
|
|
|
|
|
|
JSONSchema::Validator::Draft6::ID => JSONSchema::Validator::Draft6::SPECIFICATION, |
23
|
|
|
|
|
|
|
JSONSchema::Validator::Draft7::ID => JSONSchema::Validator::Draft7::SPECIFICATION |
24
|
|
|
|
|
|
|
}; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our $JSON_SCHEMA_VALIDATORS = ['JSONSchema::Validator::Draft4', 'JSONSchema::Validator::Draft6', 'JSONSchema::Validator::Draft7']; |
27
|
|
|
|
|
|
|
our $OAS_VALIDATORS = ['JSONSchema::Validator::OAS30']; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub new { |
31
|
25
|
|
|
25
|
1
|
10244
|
my ($class, %params) = @_; |
32
|
|
|
|
|
|
|
|
33
|
25
|
|
|
|
|
70
|
my $resource = delete $params{resource}; |
34
|
25
|
|
50
|
|
|
117
|
my $validate_schema = delete($params{validate_schema}) // 1; |
35
|
25
|
|
|
|
|
62
|
my $schema = delete $params{schema}; |
36
|
25
|
|
|
|
|
52
|
my $base_uri = delete $params{base_uri}; |
37
|
25
|
|
|
|
|
47
|
my $specification = delete $params{specification}; |
38
|
|
|
|
|
|
|
|
39
|
25
|
100
|
66
|
|
|
134
|
$schema = resource_schema($resource, \%params) if !$schema && $resource; |
40
|
25
|
50
|
|
|
|
73
|
croak 'resource or schema must be specified' unless defined $schema; |
41
|
|
|
|
|
|
|
|
42
|
25
|
|
100
|
|
|
111
|
my $validator_class = find_validator($specification // schema_specification($schema)); |
43
|
25
|
100
|
|
|
|
1187
|
croak 'unknown specification' unless $validator_class; |
44
|
|
|
|
|
|
|
|
45
|
19
|
50
|
|
|
|
53
|
if ($validate_schema) { |
46
|
19
|
|
|
|
|
98
|
my ($result, $errors) = $class->validate_resource_schema($schema, $validator_class->SPECIFICATION); |
47
|
19
|
100
|
|
|
|
149
|
croak "invalid schema:\n" . join "\n", @$errors unless $result; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# schema may be boolean value according to json schema draft6 |
51
|
15
|
50
|
|
|
|
53
|
if (ref $schema eq 'HASH') { |
52
|
15
|
|
66
|
|
|
108
|
$base_uri //= $resource || $schema->{'$id'} || $schema->{id}; |
|
|
|
66
|
|
|
|
|
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
15
|
|
|
|
|
102
|
return $validator_class->new(schema => $schema, base_uri => $base_uri, %params); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub validate_paths { |
60
|
2
|
|
|
2
|
1
|
3440
|
my ($class, $globs) = @_; |
61
|
2
|
|
|
|
|
6
|
my $results = {}; |
62
|
2
|
|
|
|
|
10
|
for my $glob (@$globs) { |
63
|
2
|
|
|
|
|
326
|
my @resources = map { Cwd::abs_path($_) } glob $glob; |
|
6
|
|
|
|
|
334
|
|
64
|
2
|
|
|
|
|
10
|
for my $resource (@resources) { |
65
|
6
|
|
|
|
|
58
|
my $uri = URI::file->new($resource)->as_string; |
66
|
6
|
|
|
|
|
2941
|
my ($result, $errors) = $class->validate_resource($uri); |
67
|
6
|
|
|
|
|
33
|
$results->{$resource} = [$result, $errors]; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
} |
70
|
2
|
|
|
|
|
12
|
return $results; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub validate_resource { |
75
|
6
|
|
|
6
|
1
|
20
|
my ($class, $resource, %params) = @_; |
76
|
6
|
|
|
|
|
26
|
my $schema_to_validate = resource_schema($resource, \%params); |
77
|
|
|
|
|
|
|
|
78
|
6
|
|
|
|
|
19
|
my $validator_class = find_validator(schema_specification($schema_to_validate)); |
79
|
6
|
50
|
|
|
|
15
|
croak "unknown specification of resource $resource" unless $validator_class; |
80
|
|
|
|
|
|
|
|
81
|
6
|
|
|
|
|
33
|
return $class->validate_resource_schema($schema_to_validate, $validator_class->SPECIFICATION); |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub validate_resource_schema { |
86
|
25
|
|
|
25
|
1
|
71
|
my ($class, $schema_to_validate, $schema_specification) = @_; |
87
|
|
|
|
|
|
|
|
88
|
25
|
|
|
|
|
72
|
my $schema = read_specification($schema_specification); |
89
|
25
|
|
|
|
|
74
|
my $meta_schema = $schema->{'$schema'}; |
90
|
|
|
|
|
|
|
|
91
|
25
|
|
33
|
|
|
96
|
my $meta_schema_specification = $SPECIFICATIONS->{$meta_schema} // $SPECIFICATIONS->{$meta_schema . '#'}; |
92
|
25
|
50
|
|
|
|
73
|
croak "unknown meta schema: $meta_schema" unless $meta_schema_specification; |
93
|
|
|
|
|
|
|
|
94
|
25
|
|
|
|
|
62
|
my $validator_class = find_validator($meta_schema_specification); |
95
|
25
|
50
|
|
|
|
71
|
croak "can't find validator by meta schema: $meta_schema" unless $validator_class; |
96
|
|
|
|
|
|
|
|
97
|
25
|
|
|
|
|
119
|
my $validator = $validator_class->new(schema => $schema); |
98
|
25
|
|
|
|
|
103
|
my ($result, $errors) = $validator->validate_schema($schema_to_validate); |
99
|
25
|
|
|
|
|
140
|
return ($result, $errors); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub read_specification { |
103
|
25
|
|
|
25
|
0
|
62
|
my $filename = shift; |
104
|
25
|
|
|
|
|
49
|
my $curret_filepath = __FILE__; |
105
|
25
|
|
|
|
|
183
|
my $schema_filepath = ($curret_filepath =~ s/\.pm$//r) . '/schemas/' . lc($filename) . '.json'; |
106
|
25
|
|
|
|
|
87
|
my ($content, $mime_type) = read_file($schema_filepath); |
107
|
25
|
|
|
|
|
114
|
return decode_content($content, $mime_type, $schema_filepath); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub resource_schema { |
111
|
20
|
|
|
20
|
0
|
87
|
my ($resource, $params) = @_; |
112
|
20
|
|
|
|
|
119
|
my ($response, $mime_type) = get_resource($params->{scheme_handlers}, $resource); |
113
|
20
|
|
|
|
|
105
|
my $schema = decode_content($response, $mime_type, $resource); |
114
|
20
|
|
|
|
|
51
|
return $schema; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub find_validator { |
118
|
56
|
|
|
56
|
0
|
95
|
my $specification = shift; |
119
|
56
|
|
100
|
|
|
168
|
my ($validator_class) = grep { lc($_->SPECIFICATION) eq lc($specification // '') } @$JSON_SCHEMA_VALIDATORS, @$OAS_VALIDATORS; |
|
224
|
|
|
|
|
1395
|
|
120
|
56
|
|
|
|
|
132
|
return $validator_class; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub schema_specification { |
124
|
24
|
|
|
24
|
0
|
62
|
my $schema = shift; |
125
|
24
|
50
|
|
|
|
90
|
return if ref $schema ne 'HASH'; |
126
|
|
|
|
|
|
|
|
127
|
24
|
|
|
|
|
54
|
my $meta_schema = $schema->{'$schema'}; |
128
|
24
|
100
|
66
|
|
|
125
|
my $specification = $meta_schema ? $SPECIFICATIONS->{$meta_schema} // $SPECIFICATIONS->{$meta_schema . '#'} : undef; |
129
|
|
|
|
|
|
|
|
130
|
24
|
100
|
100
|
|
|
92
|
if (!$specification && $schema->{openapi}) { |
131
|
3
|
|
|
|
|
12
|
my @vers = split /\./, $schema->{openapi}; |
132
|
3
|
|
|
|
|
8
|
$specification = 'OAS' . $vers[0] . $vers[1]; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
24
|
|
|
|
|
95
|
return $specification; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
1; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
__END__ |