File Coverage

lib/JSON/Structure/Types.pm
Criterion Covered Total %
statement 110 121 90.9
branch 7 10 70.0
condition 20 24 83.3
subroutine 44 48 91.6
pod 4 7 57.1
total 185 210 88.1


line stmt bran cond sub pod time code
1             package JSON::Structure::Types;
2              
3 18     18   161746 use strict;
  18         35  
  18         646  
4 18     18   83 use warnings;
  18         64  
  18         875  
5 18     18   226 use v5.20;
  18         63  
6              
7             our $VERSION = '0.6.0';
8              
9 18     18   117 use Exporter 'import';
  18         33  
  18         2618  
10              
11             our @EXPORT_OK = qw(
12             make_validation_result
13             make_validation_error
14             make_json_location
15             SEVERITY_ERROR
16             SEVERITY_WARNING
17             PRIMITIVE_TYPES
18             COMPOUND_TYPES
19             ALL_TYPES
20             NUMERIC_TYPES
21             is_valid_type
22             is_numeric_type
23             is_primitive_type
24             is_compound_type
25             );
26              
27             our %EXPORT_TAGS = ( all => \@EXPORT_OK, );
28              
29             =head1 NAME
30              
31             JSON::Structure::Types - Type definitions for JSON Structure validation
32              
33             =head1 DESCRIPTION
34              
35             This module provides type definitions and constants used throughout
36             the JSON Structure validation library.
37              
38             =cut
39              
40             # Primitive types from JSON Structure Core specification
41 18         1868 use constant PRIMITIVE_TYPES => [
42             qw(
43             string boolean null
44             int8 uint8 int16 uint16 int32 uint32 int64 uint64 int128 uint128
45             float float8 double decimal
46             number integer
47             date datetime time duration
48             uuid uri binary jsonpointer
49             )
50 18     18   113 ];
  18         32  
51              
52             # Compound types from JSON Structure Core specification
53 18         1667 use constant COMPOUND_TYPES => [
54             qw(
55             object array set map tuple choice any
56             )
57 18     18   102 ];
  18         29  
58              
59             # All valid types
60 18     18   114 use constant ALL_TYPES => [ @{ PRIMITIVE_TYPES() }, @{ COMPOUND_TYPES() } ];
  18         47  
  18         86  
  18         78  
  18         1632  
61              
62             # Numeric types
63 18         6186 use constant NUMERIC_TYPES => [
64             qw(
65             number integer float double decimal float8
66             int8 uint8 int16 uint16 int32 uint32 int64 uint64 int128 uint128
67             )
68 18     18   102 ];
  18         43  
69              
70             # Create lookup hashes for O(1) type checking
71             my %_primitive_types = map { $_ => 1 } @{ PRIMITIVE_TYPES() };
72             my %_compound_types = map { $_ => 1 } @{ COMPOUND_TYPES() };
73             my %_all_types = map { $_ => 1 } @{ ALL_TYPES() };
74             my %_numeric_types = map { $_ => 1 } @{ NUMERIC_TYPES() };
75              
76             =head1 FUNCTIONS
77              
78             =head2 is_valid_type($type)
79              
80             Returns true if the given type name is a valid JSON Structure type.
81              
82             =cut
83              
84             sub is_valid_type {
85 4     4 1 191045 my ($type) = @_;
86 4         22 return exists $_all_types{$type};
87             }
88              
89             =head2 is_primitive_type($type)
90              
91             Returns true if the given type is a primitive type.
92              
93             =cut
94              
95             sub is_primitive_type {
96 3     3 1 6 my ($type) = @_;
97 3         11 return exists $_primitive_types{$type};
98             }
99              
100             =head2 is_compound_type($type)
101              
102             Returns true if the given type is a compound type.
103              
104             =cut
105              
106             sub is_compound_type {
107 3     3 1 9 my ($type) = @_;
108 3         11 return exists $_compound_types{$type};
109             }
110              
111             =head2 is_numeric_type($type)
112              
113             Returns true if the given type is a numeric type.
114              
115             =cut
116              
117             sub is_numeric_type {
118 3     3 1 8 my ($type) = @_;
119 3         37 return exists $_numeric_types{$type};
120             }
121              
122             #############################################################################
123             # JsonLocation - Represents a location in a JSON document
124             #############################################################################
125              
126             package JSON::Structure::Types::JsonLocation;
127              
128 18     18   132 use strict;
  18         125  
  18         614  
129 18     18   84 use warnings;
  18         41  
  18         6245  
130              
131             =head1 JSON::Structure::Types::JsonLocation
132              
133             Represents a location in a JSON document with line and column information.
134              
135             =cut
136              
137             sub new {
138 271     271   15932 my ( $class, %args ) = @_;
139             my $self = bless {
140             line => $args{line} // 0,
141 271   100     1428 column => $args{column} // 0,
      100        
142             }, $class;
143 271         970 return $self;
144             }
145              
146             sub unknown {
147 262     262   561 my ($class) = @_;
148 262         703 return $class->new( line => 0, column => 0 );
149             }
150              
151 5     5   61 sub line { $_[0]->{line} }
152 4     4   22 sub column { $_[0]->{column} }
153              
154             sub is_known {
155 20     20   58 my ($self) = @_;
156 20   66     167 return $self->{line} > 0 && $self->{column} > 0;
157             }
158              
159             sub to_string {
160 3     3   8 my ($self) = @_;
161 3 100       7 return $self->is_known ? "($self->{line}:$self->{column})" : "";
162             }
163              
164             #############################################################################
165             # ValidationSeverity - Enum for validation severity levels
166             #############################################################################
167              
168             package JSON::Structure::Types::ValidationSeverity;
169              
170 18     18   159 use strict;
  18         50  
  18         588  
171 18     18   86 use warnings;
  18         43  
  18         1128  
172              
173 18     18   98 use constant ERROR => 'error';
  18         28  
  18         1486  
174 18     18   104 use constant WARNING => 'warning';
  18         55  
  18         1206  
175              
176             #############################################################################
177             # ValidationError - Represents a single validation error
178             #############################################################################
179              
180             package JSON::Structure::Types::ValidationError;
181              
182 18     18   108 use strict;
  18         30  
  18         482  
183 18     18   171 use warnings;
  18         102  
  18         8666  
184              
185             =head1 JSON::Structure::Types::ValidationError
186              
187             Represents a validation error with code, message, and location information.
188              
189             =cut
190              
191             sub new {
192 264     264   14881 my ( $class, %args ) = @_;
193             my $self = bless {
194             code => $args{code} // '',
195             message => $args{message} // '',
196             path => $args{path} // '',
197             severity => $args{severity}
198             // JSON::Structure::Types::ValidationSeverity::ERROR,
199             location => $args{location}
200             // JSON::Structure::Types::JsonLocation->unknown(),
201             schema_path => $args{schema_path},
202 264   50     2744 }, $class;
      50        
      100        
      100        
      66        
203 264         1221 return $self;
204             }
205              
206 39     39   375 sub code { $_[0]->{code} }
207 8     8   32 sub message { $_[0]->{message} }
208 10     10   187 sub path { $_[0]->{path} }
209 3     3   36 sub severity { $_[0]->{severity} }
210 9     9   578 sub location { $_[0]->{location} }
211 7     7   32 sub schema_path { $_[0]->{schema_path} }
212              
213             sub to_string {
214 3     3   522 my ($self) = @_;
215 3         6 my @parts;
216              
217 3 50       15 push @parts, $self->{path} if $self->{path};
218             push @parts, $self->{location}->to_string
219 3 100       81 if $self->{location}->is_known;
220 3         31 push @parts, "[$self->{code}]";
221 3         6 push @parts, $self->{message};
222             push @parts, "(schema: $self->{schema_path})"
223 3 100       12 if defined $self->{schema_path};
224              
225 3         33 return join( ' ', @parts );
226             }
227              
228             #############################################################################
229             # ValidationResult - Represents the result of a validation operation
230             #############################################################################
231              
232             package JSON::Structure::Types::ValidationResult;
233              
234 18     18   139 use strict;
  18         30  
  18         440  
235 18     18   97 use warnings;
  18         33  
  18         13198  
236              
237             =head1 JSON::Structure::Types::ValidationResult
238              
239             Represents the result of a validation operation.
240              
241             =cut
242              
243             sub new {
244 552     552   201625 my ( $class, %args ) = @_;
245             my $self = bless {
246             is_valid => $args{is_valid} // 1,
247             errors => $args{errors} // [],
248 552   100     3076 warnings => $args{warnings} // [],
      100        
      100        
249             }, $class;
250 552         3168 return $self;
251             }
252              
253 554     554   3071 sub is_valid { $_[0]->{is_valid} }
254 50     50   237 sub errors { $_[0]->{errors} }
255 2     2   120 sub warnings { $_[0]->{warnings} }
256              
257             sub add_error {
258 2     2   14 my ( $self, $error ) = @_;
259 2         8 push @{ $self->{errors} }, $error;
  2         7  
260 2         6 $self->{is_valid} = 0;
261             }
262              
263             sub add_warning {
264 1     1   4 my ( $self, $warning ) = @_;
265 1         3 push @{ $self->{warnings} }, $warning;
  1         4  
266             }
267              
268             sub merge {
269 0     0     my ( $self, $other ) = @_;
270 0           push @{ $self->{errors} }, @{ $other->errors };
  0            
  0            
271 0           push @{ $self->{warnings} }, @{ $other->warnings };
  0            
  0            
272 0 0         $self->{is_valid} = 0 if !$other->is_valid;
273             }
274              
275             # Export convenience constructors and constants
276             package JSON::Structure::Types;
277              
278             sub make_validation_result {
279 0     0 0   JSON::Structure::Types::ValidationResult->new(@_);
280             }
281              
282             sub make_validation_error {
283 0     0 0   JSON::Structure::Types::ValidationError->new(@_);
284             }
285 0     0 0   sub make_json_location { JSON::Structure::Types::JsonLocation->new(@_) }
286              
287             # Severity constants
288 18         1273 use constant SEVERITY_ERROR =>
289 18     18   143 JSON::Structure::Types::ValidationSeverity::ERROR;
  18         61  
290 18         1499 use constant SEVERITY_WARNING =>
291 18     18   113 JSON::Structure::Types::ValidationSeverity::WARNING;
  18         44  
292              
293             1;
294              
295             __END__