← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Thu Dec 15 15:23:56 2022
Reported on Thu Dec 15 15:27:04 2022

Filename/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary/Core.pm
StatementsExecuted 803950 statements in 1.24s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
3878111651ms64.4sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_refJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref (recurses: max depth 31, inclusive time 621s)
2556211535ms1.97sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_idJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id
255611109ms44.0sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_dynamicRefJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef (recurses: max depth 6, inclusive time 48.1s)
726223.87ms172msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_refJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref
11211530µs1.85msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_commentJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment
1411478µs24.8msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_idJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id
1111425µs4.37msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_vocabularyJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary
1522362µs4.01msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_anchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor
1511261µs3.75msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_schemaJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema
141175µs3.54msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_dynamicAnchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor
121160µs89.3msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_defsJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs (recurses: max depth 1, inclusive time 9.91ms)
221158µs4.45msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_dynamicRefJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef
11156µs485µsJSON::Schema::Modern::Vocabulary::Core::::__fetch_vocabulary_dataJSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data
11126µs29µsModule::Runtime::::BEGIN@1 Module::Runtime::BEGIN@1
11115µs778µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@11JSON::Schema::Modern::Vocabulary::Core::BEGIN@11
11113µs13µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@9JSON::Schema::Modern::Vocabulary::Core::BEGIN@9
11112µs32µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@13JSON::Schema::Modern::Vocabulary::Core::BEGIN@13
11111µs28µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@14JSON::Schema::Modern::Vocabulary::Core::BEGIN@14
2219µs9µsJSON::Schema::Modern::Vocabulary::Core::::keywordsJSON::Schema::Modern::Vocabulary::Core::keywords
1118µs96µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@12JSON::Schema::Modern::Vocabulary::Core::BEGIN@12
1117µs17µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@15JSON::Schema::Modern::Vocabulary::Core::BEGIN@15
1117µs17µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@16JSON::Schema::Modern::Vocabulary::Core::BEGIN@16
1117µs174µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@18JSON::Schema::Modern::Vocabulary::Core::BEGIN@18
1116µs223µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@10JSON::Schema::Modern::Vocabulary::Core::BEGIN@10
1116µs48µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@17JSON::Schema::Modern::Vocabulary::Core::BEGIN@17
1115µs33µsModule::Runtime::::BEGIN@2 Module::Runtime::BEGIN@2
3112µs2µsJSON::Schema::Modern::Vocabulary::Core::::evaluation_orderJSON::Schema::Modern::Vocabulary::Core::evaluation_order
1111µs1µsJSON::Schema::Modern::Vocabulary::Core::::vocabularyJSON::Schema::Modern::Vocabulary::Core::vocabulary
0000s0sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_recursiveAnchorJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_recursiveAnchor
0000s0sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_recursiveRefJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_recursiveRef
0000s0sJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_definitionsJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_definitions
0000s0sJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_recursiveAnchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_recursiveAnchor
0000s0sJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_recursiveRefJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_recursiveRef
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1231µs232µs
# spent 29µs (26+3) within Module::Runtime::BEGIN@1 which was called: # once (26µs+3µs) by Module::Runtime::require_module at line 1
use strict;
# spent 29µs making 1 call to Module::Runtime::BEGIN@1 # spent 3µs making 1 call to strict::import
2270µs261µs
# spent 33µs (5+28) within Module::Runtime::BEGIN@2 which was called: # once (5µs+28µs) by Module::Runtime::require_module at line 2
use warnings;
# spent 33µs making 1 call to Module::Runtime::BEGIN@2 # spent 28µs making 1 call to warnings::import
3package JSON::Schema::Modern::Vocabulary::Core;
4# vim: set ts=8 sts=2 sw=2 tw=100 et :
5# ABSTRACT: Implementation of the JSON Schema Core vocabulary
6
710sour $VERSION = '0.559';
8
9228µs113µs
# spent 13µs within JSON::Schema::Modern::Vocabulary::Core::BEGIN@9 which was called: # once (13µs+0s) by Module::Runtime::require_module at line 9
use 5.020;
10224µs2440µs
# spent 223µs (6+217) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@10 which was called: # once (6µs+217µs) by Module::Runtime::require_module at line 10
use Moo;
# spent 223µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@10 # spent 217µs making 1 call to Moo::import
113159µs31.54ms
# spent 778µs (15+763) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@11 which was called: # once (15µs+763µs) by Module::Runtime::require_module at line 11
use strictures 2;
# spent 778µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@11 # spent 747µs making 1 call to strictures::import # spent 16µs making 1 call to strictures::VERSION
12230µs2184µs
# spent 96µs (8+88) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@12 which was called: # once (8µs+88µs) by Module::Runtime::require_module at line 12
use experimental qw(signatures postderef);
# spent 96µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@12 # spent 88µs making 1 call to experimental::import
13223µs235µs
# spent 32µs (12+20) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@13 which was called: # once (12µs+20µs) by Module::Runtime::require_module at line 13
use if "$]" >= 5.022, experimental => 're_strict';
# spent 32µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@13 # spent 3µs making 1 call to if::import
14222µs229µs
# spent 28µs (11+17) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@14 which was called: # once (11µs+17µs) by Module::Runtime::require_module at line 14
no if "$]" >= 5.031009, feature => 'indirect';
# spent 28µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@14 # spent 1µs making 1 call to if::unimport
15216µs218µs
# spent 17µs (7+10) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@15 which was called: # once (7µs+10µs) by Module::Runtime::require_module at line 15
no if "$]" >= 5.033001, feature => 'multidimensional';
# spent 17µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@15 # spent 1µs making 1 call to if::unimport
16220µs218µs
# spent 17µs (7+10) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@16 which was called: # once (7µs+10µs) by Module::Runtime::require_module at line 16
no if "$]" >= 5.033006, feature => 'bareword_filehandles';
# spent 17µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@16 # spent 1µs making 1 call to if::unimport
17217µs290µs
# spent 48µs (6+42) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@17 which was called: # once (6µs+42µs) by Module::Runtime::require_module at line 17
use JSON::Schema::Modern::Utilities qw(is_type abort assert_keyword_type canonical_uri E assert_uri_reference assert_uri jsonp);
# spent 48µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@17 # spent 42µs making 1 call to Exporter::import
1822.12ms2341µs
# spent 174µs (7+167) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@18 which was called: # once (7µs+167µs) by Module::Runtime::require_module at line 18
use namespace::clean;
# spent 174µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@18 # spent 167µs making 1 call to namespace::clean::import
19
2011µs13.67mswith 'JSON::Schema::Modern::Vocabulary';
# spent 3.67ms making 1 call to Moo::with
21
22
# spent 1µs within JSON::Schema::Modern::Vocabulary::Core::vocabulary which was called: # once (1µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:709] at line 705 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
sub vocabulary {
2313µs 'https://json-schema.org/draft/2019-09/vocab/core' => 'draft2019-09',
24 'https://json-schema.org/draft/2020-12/vocab/core' => 'draft2020-12';
25}
26
2734µs
# spent 2µs within JSON::Schema::Modern::Vocabulary::Core::evaluation_order which was called 3 times, avg 667ns/call: # 3 times (2µs+0s) by JSON::Schema::Modern::Vocabulary::Core::CORE:sort at line 337, avg 667ns/call
sub evaluation_order { 0 }
28
2962µs
# spent 9µs within JSON::Schema::Modern::Vocabulary::Core::keywords which was called 2 times, avg 4µs/call: # once (5µs+0s) by JSON::Schema::Modern::_eval_subschema at line 572 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm # once (4µs+0s) by JSON::Schema::Modern::_traverse_subschema at line 480 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
sub keywords ($self, $spec_version) {
30 return (
31213µs qw($id $schema),
32 $spec_version ne 'draft7' ? '$anchor' : (),
33 $spec_version eq 'draft2019-09' ? '$recursiveAnchor' : (),
34 $spec_version eq 'draft2020-12' ? '$dynamicAnchor' : (),
35 '$ref',
36 $spec_version eq 'draft2019-09' ? '$recursiveRef' : (),
37 $spec_version eq 'draft2020-12' ? '$dynamicRef' : (),
38 $spec_version eq 'draft7' ? 'definitions' : qw($vocabulary $comment $defs),
39 );
40}
41
42# adds the following keys to $state during traversal:
43# - identifiers: an arrayref of tuples:
44# $uri => { path => $path_to_identifier, canonical_uri => Mojo::URL (absolute when possible) }
45# this is used by the Document constructor to build its resource_index.
46
47569µs
# spent 24.8ms (478µs+24.3) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id which was called 14 times, avg 1.77ms/call: # 14 times (478µs+24.3ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 1.77ms/call
sub _traverse_keyword_id ($self, $schema, $state) {
481477µs2821.9ms return if not assert_keyword_type($state, $schema, 'string')
# spent 21.5ms making 14 calls to JSON::Schema::Modern::Utilities::assert_uri_reference, avg 1.54ms/call # spent 335µs making 14 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 24µs/call
49 or not assert_uri_reference($state, $schema);
50
511417µs14582µs my $uri = Mojo::URL->new($schema->{'$id'});
# spent 582µs making 14 calls to Mojo::URL::new, avg 42µs/call
52
531453µs if ($state->{spec_version} eq 'draft7') {
54 if (length($uri->fragment)) {
55 return E($state, '$id cannot change the base uri at the same time as declaring an anchor')
56 if length($uri->clone->fragment(undef));
57
58 return $self->_traverse_keyword_anchor({ %$schema, $state->{keyword} => $uri->fragment }, $state);
59 }
60 }
61 else {
621417µs147µs return E($state, '$id value "%s" cannot have a non-empty fragment', $schema->{'$id'})
# spent 7µs making 14 calls to Mojo::URL::fragment, avg 500ns/call
63 if length $uri->fragment;
64 }
65
661415µs1419µs $uri->fragment(undef);
# spent 19µs making 14 calls to Mojo::URL::fragment, avg 1µs/call
671426µs141.17ms return E($state, '$id cannot be empty') if not length $uri;
# spent 1.17ms making 14 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 83µs/call
68
691423µs1455µs $state->{initial_schema_uri} = $uri->is_abs ? $uri : $uri->to_abs($state->{initial_schema_uri});
# spent 55µs making 14 calls to Mojo::URL::is_abs, avg 4µs/call
701411µs $state->{traversed_schema_path} = $state->{traversed_schema_path}.$state->{schema_path};
71 # we don't set or update document_path because it is identical to traversed_schema_path
72146µs $state->{schema_path} = '';
73
74 push $state->{identifiers}->@*,
75 $state->{initial_schema_uri} => {
76 path => $state->{traversed_schema_path},
77 canonical_uri => $state->{initial_schema_uri}->clone,
78 specification_version => $state->{spec_version}, # note! $schema keyword can change this
79 vocabularies => $state->{vocabularies}, # reference, not copy
80 configs => $state->{configs},
811494µs14608µs };
# spent 608µs making 14 calls to Mojo::URL::clone, avg 43µs/call
821430µs return 1;
83}
84
8512781019.9ms
# spent 1.97s (535ms+1.44) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id which was called 25562 times, avg 77µs/call: # 25562 times (535ms+1.44s) by JSON::Schema::Modern::_eval_subschema at line 587 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 77µs/call
sub _eval_keyword_id ($self, $data, $schema, $state) {
862556262.0ms25562574ms my $schema_info = $state->{document}->path_to_resource($state->{document_path}.$state->{schema_path});
# spent 574ms making 25562 calls to JSON::Schema::Modern::Document::path_to_resource, avg 22µs/call
87 # this should never happen, if the pre-evaluation traversal was performed correctly
88255626.34ms abort($state, 'failed to resolve %s to canonical uri', $state->{keyword}) if not $schema_info;
89
902556236.3ms25562791ms $state->{initial_schema_uri} = $schema_info->{canonical_uri}->clone;
# spent 791ms making 25562 calls to Mojo::URL::clone, avg 31µs/call
912556223.3ms $state->{traversed_schema_path} = $state->{traversed_schema_path}.$state->{schema_path};
92255629.66ms $state->{document_path} = $state->{document_path}.$state->{schema_path};
93255628.21ms $state->{schema_path} = '';
94255629.41ms $state->{spec_version} = $schema_info->{specification_version};
95255627.94ms $state->{vocabularies} = $schema_info->{vocabularies};
96
97# XXX this code doesn't belong here - but rather in eval_subschema_at_uri
98 # it's possible that a different schema resource has its own set of configs, different from the
99 # JSM attribute value
100
101 # XXX come up with a test!
102 # it involves processing a 'format' after going through a $ref.
103
1042556210.2ms if ($state->{validate_formats}) {
105 $state->{vocabularies} = [
106 map s/^JSON::Schema::Modern::Vocabulary::Format\KAnnotation$/Assertion/r, $state->{vocabularies}->@*
10725562298ms17893470.9ms ];
# spent 70.9ms making 178934 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:subst, avg 396ns/call
1082556210.6ms require JSON::Schema::Modern::Vocabulary::FormatAssertion;
109 }
110
1112556219.1ms $state->@{keys $state->{configs}->%*} = values $state->{configs}->%*;
1122556222.9ms push $state->{dynamic_scope}->@*, $state->{initial_schema_uri};
113
1142556245.9ms return 1;
115}
116
1176013µs
# spent 3.75ms (261µs+3.49) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema which was called 15 times, avg 250µs/call: # 15 times (261µs+3.49ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 250µs/call
sub _traverse_keyword_schema ($self, $schema, $state) {
1181576µs302.09ms return if not assert_keyword_type($state, $schema, 'string') or not assert_uri($state, $schema);
# spent 1.90ms making 15 calls to JSON::Schema::Modern::Utilities::assert_uri, avg 127µs/call # spent 189µs making 15 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 13µs/call
119
120 # "A JSON Schema resource is a schema which is canonically identified by an absolute URI."
121 # "A resource's root schema is its top-level schema object."
122 # note: we need not be at the document root, but simply adjacent to an $id (or be the at the
123 # document root)
124 return E($state, '$schema can only appear at the schema resource root')
125157µs if length($state->{schema_path});
126
127155µs my ($spec_version, $vocabularies);
128
1291537µs15416µs if (my $metaschema_info = $state->{evaluator}->_get_metaschema_vocabulary_classes($schema->{'$schema'})) {
# spent 416µs making 15 calls to JSON::Schema::Modern::_get_metaschema_vocabulary_classes, avg 28µs/call
130 ($spec_version, $vocabularies) = @$metaschema_info;
131 }
132 else {
13313µs1458µs my $schema_info = $state->{evaluator}->_fetch_from_uri($schema->{'$schema'});
# spent 458µs making 1 call to JSON::Schema::Modern::_fetch_from_uri
13410s return E($state, 'EXCEPTION: unable to find resource %s', $schema->{'$schema'}) if not $schema_info;
135
136 ($spec_version, $vocabularies) = $self->__fetch_vocabulary_data({ %$state,
137 keyword => '$vocabulary', initial_schema_uri => Mojo::URL->new($schema->{'$schema'}),
138112µs3526µs traversed_schema_path => jsonp($state->{schema_path}, '$schema'),
# spent 485µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data # spent 33µs making 1 call to Mojo::URL::new # spent 8µs making 1 call to JSON::Schema::Modern::Utilities::jsonp
139 }, $schema_info);
140 }
141
142157µs return E($state, '"%s" is not a valid metaschema', $schema->{'$schema'}) if not @$vocabularies;
143
144 # we special-case this because the check in _eval_subschema for older drafts + $ref has already happened
145 return E($state, '$schema and $ref cannot be used together in older drafts')
146157µs if exists $schema->{'$ref'} and $spec_version eq 'draft7';
147
1481514µs $state->@{qw(spec_version vocabularies)} = ($spec_version, $vocabularies);
149
150 # remember, if we don't have a sibling $id, we must be at the document root with no identifiers
1511520µs if ($state->{identifiers}->@*) {
152 $state->{identifiers}[-1]->@{qw(specification_version vocabularies)} = $state->@{qw(spec_version vocabularies)};
153 }
154
1551529µs return 1;
156}
157
1586028µs
# spent 4.01ms (362µs+3.65) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor which was called 15 times, avg 268µs/call: # 14 times (302µs+3.17ms) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor at line 203, avg 248µs/call # once (60µs+484µs) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
sub _traverse_keyword_anchor ($self, $schema, $state) {
1591517µs15167µs return if not assert_keyword_type($state, $schema, 'string');
# spent 167µs making 15 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 11µs/call
160
161 return E($state, '%s value "%s" does not match required syntax',
162 $state->{keyword}, ($state->{keyword} eq '$id' ? '#' : '').$schema->{$state->{keyword}})
163 if $state->{spec_version} =~ /^draft(?:7|2019-09)$/
164 and $schema->{$state->{keyword}} !~ /^[A-Za-z][A-Za-z0-9_:.-]*$/
165 or $state->{spec_version} eq 'draft2020-12'
16615106µs3051µs and $schema->{$state->{keyword}} !~ /^[A-Za-z_][A-Za-z0-9._-]*$/;
# spent 51µs making 30 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:match, avg 2µs/call
167
1681535µs15324µs my $canonical_uri = canonical_uri($state);
# spent 324µs making 15 calls to JSON::Schema::Modern::Utilities::canonical_uri, avg 22µs/call
169
170 push $state->{identifiers}->@*,
171 Mojo::URL->new->to_abs($canonical_uri)->fragment($schema->{$state->{keyword}}) => {
172 path => $state->{traversed_schema_path}.$state->{schema_path},
173 canonical_uri => $canonical_uri,
174 specification_version => $state->{spec_version},
175 vocabularies => $state->{vocabularies}, # reference, not copy
176 configs => $state->{configs},
17715156µs453.11ms };
# spent 3.05ms making 15 calls to Mojo::URL::to_abs, avg 203µs/call # spent 48µs making 15 calls to Mojo::URL::new, avg 3µs/call # spent 13µs making 15 calls to Mojo::URL::fragment, avg 867ns/call
1781530µs return 1;
179}
180
181# we already indexed the $anchor uri, so there is nothing more to do at evaluation time.
182# we explicitly do NOT set $state->{initial_schema_uri}.
183
184sub _traverse_keyword_recursiveAnchor ($self, $schema, $state) {
185 return if not assert_keyword_type($state, $schema, 'boolean');
186
187 # this is required because the location is used as the base URI for future resolution
188 # of $recursiveRef, and the fragment would be disregarded in the base
189 return E($state, '"$recursiveAnchor" keyword used without "$id"')
190 if length($state->{schema_path});
191 return 1;
192}
193
194sub _eval_keyword_recursiveAnchor ($self, $data, $schema, $state) {
195 return 1 if not $schema->{'$recursiveAnchor'} or exists $state->{recursive_anchor_uri};
196
197 # record the canonical location of the current position, to be used against future resolution
198 # of a $recursiveRef uri -- as if it was the current location when we encounter a $ref.
199 $state->{recursive_anchor_uri} = canonical_uri($state);
200 return 1;
201}
202
2031466µs143.47ms
# spent 3.54ms (75µs+3.47) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor which was called 14 times, avg 253µs/call: # 14 times (75µs+3.47ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 253µs/call
sub _traverse_keyword_dynamicAnchor { shift->_traverse_keyword_anchor(@_) }
# spent 3.47ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor, avg 248µs/call
204
205# we already indexed the $dynamicAnchor uri, so there is nothing more to do at evaluation time.
206# we explicitly do NOT set $state->{initial_schema_uri}.
207
2082904352µs
# spent 172ms (3.87+168) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref which was called 726 times, avg 236µs/call: # 704 times (3.76ms+163ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 237µs/call # 22 times (111µs+4.28ms) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef at line 234, avg 200µs/call
sub _traverse_keyword_ref ($self, $schema, $state) {
2097261.53ms1452168ms return if not assert_keyword_type($state, $schema, 'string')
# spent 159ms making 726 calls to JSON::Schema::Modern::Utilities::assert_uri_reference, avg 219µs/call # spent 8.60ms making 726 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 12µs/call
210 or not assert_uri_reference($state, $schema);
2117261.32ms return 1;
212}
213
21419390533.7ms
# spent 64.4s (651ms+63.7) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref which was called 38781 times, avg 1.66ms/call: # 38781 times (651ms+63.7s) by JSON::Schema::Modern::_eval_subschema at line 587 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 1.66ms/call
sub _eval_keyword_ref ($self, $data, $schema, $state) {
21538781143ms7756210.7s my $uri = Mojo::URL->new($schema->{'$ref'})->to_abs($state->{initial_schema_uri});
# spent 7.13s making 38781 calls to Mojo::URL::to_abs, avg 184µs/call # spent 3.58s making 38781 calls to Mojo::URL::new, avg 92µs/call
21638781378ms3878164.4s $self->eval_subschema_at_uri($data, $schema, $state, $uri);
# spent 674s making 38781 calls to JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri, avg 17.4ms/call, recursion: max depth 38, sum of overlapping time 610s
217}
218
219sub _traverse_keyword_recursiveRef { shift->_traverse_keyword_ref(@_) }
220
221sub _eval_keyword_recursiveRef ($self, $data, $schema, $state) {
222 my $uri = Mojo::URL->new($schema->{'$recursiveRef'})->to_abs($state->{initial_schema_uri});
223 my $schema_info = $state->{evaluator}->_fetch_from_uri($uri);
224 abort($state, 'EXCEPTION: unable to find resource %s', $uri) if not $schema_info;
225
226 if (is_type('boolean', $schema_info->{schema}{'$recursiveAnchor'}) and $schema_info->{schema}{'$recursiveAnchor'}) {
227 $uri = Mojo::URL->new($schema->{'$recursiveRef'})
228 ->to_abs($state->{recursive_anchor_uri} // $state->{initial_schema_uri});
229 }
230
231 return $self->eval_subschema_at_uri($data, $schema, $state, $uri);
232}
233
2342252µs224.39ms
# spent 4.45ms (58µs+4.39) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef which was called 22 times, avg 202µs/call: # 22 times (58µs+4.39ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 202µs/call
sub _traverse_keyword_dynamicRef { shift->_traverse_keyword_ref(@_) }
# spent 4.39ms making 22 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref, avg 200µs/call
235
236127803.12ms
# spent 44.0s (109ms+43.9) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef which was called 2556 times, avg 17.2ms/call: # 2556 times (109ms+43.9s) by JSON::Schema::Modern::_eval_subschema at line 587 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 17.2ms/call
sub _eval_keyword_dynamicRef ($self, $data, $schema, $state) {
237255610.8ms5112664ms my $uri = Mojo::URL->new($schema->{'$dynamicRef'})->to_abs($state->{initial_schema_uri});
# spent 375ms making 2556 calls to Mojo::URL::to_abs, avg 147µs/call # spent 288ms making 2556 calls to Mojo::URL::new, avg 113µs/call
23825565.58ms2556638ms my $schema_info = $state->{evaluator}->_fetch_from_uri($uri);
# spent 638ms making 2556 calls to JSON::Schema::Modern::_fetch_from_uri, avg 250µs/call
23925561.06ms abort($state, 'EXCEPTION: unable to find resource %s', $uri) if not $schema_info;
240
241 # If the initially resolved starting point URI includes a fragment that was created by the
242 # "$dynamicAnchor" keyword, ...
24325568.22ms51123.42ms if (length $uri->fragment and exists $schema_info->{schema}{'$dynamicAnchor'}
# spent 3.42ms making 5112 calls to Mojo::URL::fragment, avg 668ns/call
244 and $uri->fragment eq (my $anchor = $schema_info->{schema}{'$dynamicAnchor'})) {
245 # ...the initial URI MUST be replaced by the URI (including the fragment) for the outermost
246 # schema resource in the dynamic scope that defines an identically named fragment with
247 # "$dynamicAnchor".
24825561.45ms foreach my $base_scope ($state->{dynamic_scope}->@*) {
24925563.96ms5112286ms my $test_uri = Mojo::URL->new($base_scope)->fragment($anchor);
# spent 284ms making 2556 calls to Mojo::URL::new, avg 111µs/call # spent 2.08ms making 2556 calls to Mojo::URL::fragment, avg 812ns/call
25025563.48ms2556453ms my $dynamic_anchor_subschema_info = $state->{evaluator}->_fetch_from_uri($test_uri);
# spent 453ms making 2556 calls to JSON::Schema::Modern::_fetch_from_uri, avg 177µs/call
25125561.97ms if (($dynamic_anchor_subschema_info->{schema}->{'$dynamicAnchor'}//'') eq $anchor) {
25225567.62ms $uri = $test_uri;
25325565.23ms last;
254 }
255 }
256 }
257
258255637.6ms25560s return $self->eval_subschema_at_uri($data, $schema, $state, $uri);
# spent 89.9s making 2556 calls to JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri, avg 35.2ms/call, recursion: max depth 34, sum of overlapping time 89.9s
259}
260
2614424µs
# spent 4.37ms (425µs+3.94) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary which was called 11 times, avg 397µs/call: # 11 times (425µs+3.94ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 397µs/call
sub _traverse_keyword_vocabulary ($self, $schema, $state) {
2621120µs11105µs return if not assert_keyword_type($state, $schema, 'object');
# spent 105µs making 11 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 10µs/call
263
264 return E($state, '$vocabulary can only appear at the schema resource root')
265113µs if length($state->{schema_path});
266
267117µs my $valid = 1;
268
269112µs my @vocabulary_classes;
2701154µs1113µs foreach my $uri (sort keys $schema->{'$vocabulary'}->%*) {
# spent 13µs making 11 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:sort, avg 1µs/call
27131149µs31384µs $valid = 0, next if not assert_keyword_type({ %$state, _schema_path_suffix => $uri }, $schema, 'boolean');
# spent 384µs making 31 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 12µs/call
27231108µs313.44ms $valid = 0, next if not assert_uri({ %$state, _schema_path_suffix => $uri }, undef, $uri);
# spent 3.44ms making 31 calls to JSON::Schema::Modern::Utilities::assert_uri, avg 111µs/call
273 }
274
275 # we cannot return an error here for invalid or incomplete vocabulary lists, because
276 # - the specification vocabulary schemas themselves don't list Core,
277 # - it is possible for a metaschema to $ref to another metaschema that uses an unrecognized
278 # vocabulary uri while still validating those vocabulary keywords (e.g.
279 # https://spec.openapis.org/oas/3.1/schema-base/2021-05-20)
280 # Instead, we will verify these constraints when we actually use the metaschema, in
281 # _traverse_keyword_schema -> __fetch_vocabulary_data
282
2831124µs return $valid;
284}
285
286# we do nothing with $vocabulary yet at evaluation time. When we know we are in a metaschema,
287# we can scan the URIs included here and either abort if a vocabulary is enabled that we do not
288# understand, or turn on and off certain keyword behaviours based on the boolean values seen.
289
29044887µs
# spent 1.85ms (530µs+1.32) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment which was called 112 times, avg 17µs/call: # 112 times (530µs+1.32ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 17µs/call
sub _traverse_keyword_comment ($self, $schema, $state) {
291112117µs1121.32ms return if not assert_keyword_type($state, $schema, 'string');
# spent 1.32ms making 112 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 12µs/call
292112199µs return 1;
293}
294
295# we do nothing with $comment at evaluation time, including not collecting its value for annotations.
296
297sub _traverse_keyword_definitions { shift->traverse_object_schemas(@_) }
2981264µs1289.3ms
# spent 89.3ms (60µs+89.3) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs which was called 12 times, avg 7.44ms/call: # 12 times (60µs+89.3ms) by JSON::Schema::Modern::_traverse_subschema at line 492 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm, avg 7.44ms/call
sub _traverse_keyword_defs { shift->traverse_object_schemas(@_) }
# spent 99.2ms making 12 calls to JSON::Schema::Modern::Vocabulary::traverse_object_schemas, avg 8.26ms/call, recursion: max depth 2, sum of overlapping time 9.89ms
299
300# we do nothing directly with $defs at evaluation time, including not collecting its value for
301# annotations.
302
303
304# translate vocabulary URIs into classes, caching the results (if any)
30540s
# spent 485µs (56+429) within JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data which was called: # once (56µs+429µs) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema at line 138
sub __fetch_vocabulary_data ($self, $state, $schema_info) {
30611µs if (not exists $schema_info->{schema}{'$vocabulary'}) {
307 # "If "$vocabulary" is absent, an implementation MAY determine behavior based on the meta-schema
308 # if it is recognized from the URI value of the referring schema's "$schema" keyword."
309 my $metaschema_uri = $state->{evaluator}->METASCHEMA_URIS->{$schema_info->{specification_version}};
310 return $state->{evaluator}->_get_metaschema_vocabulary_classes($metaschema_uri)->@*;
311 }
312
31310s my $valid = 1;
31411µs $valid = E($state, '$vocabulary can only appear at the document root') if length $schema_info->{document_path};
31510s $valid = E($state, 'metaschemas must have an $id') if not exists $schema_info->{schema}{'$id'};
316
31711µs return (undef, []) if not $valid;
318
31910s my @vocabulary_classes;
320
32118µs12µs foreach my $uri (sort keys $schema_info->{schema}{'$vocabulary'}->%*) {
32286µs8155µs my $class_info = $state->{evaluator}->_get_vocabulary_class($uri);
# spent 155µs making 8 calls to JSON::Schema::Modern::_get_vocabulary_class, avg 19µs/call
323 $valid = E({ %$state, _schema_path_suffix => $uri }, '"%s" is not a known vocabulary', $uri), next
324844µs831µs if $schema_info->{schema}{'$vocabulary'}{$uri} and not $class_info;
# spent 31µs making 8 calls to JSON::PP::Boolean::__ANON__[JSON/PP/Boolean.pm:8], avg 4µs/call
325
32680s next if not $class_info; # vocabulary is not known, but marked as false in the metaschema
327
32884µs my ($spec_version, $class) = @$class_info;
329 $valid = E({ %$state, _schema_path_suffix => $uri }, '"%s" uses %s, but the metaschema itself uses %s',
330 $uri, $spec_version, $schema_info->{specification_version}), next
33183µs if $spec_version ne $schema_info->{specification_version};
332
33383µs push @vocabulary_classes, $class;
334 }
335
336 @vocabulary_classes = sort {
3371633µs3186µs $a->evaluation_order <=> $b->evaluation_order
# spent 70µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::CORE:sort # spent 3µs making 5 calls to JSON::Schema::Modern::Vocabulary::MetaData::evaluation_order, avg 600ns/call # spent 3µs making 3 calls to JSON::Schema::Modern::Vocabulary::evaluation_order, avg 1µs/call # spent 2µs making 4 calls to JSON::Schema::Modern::Vocabulary::Applicator::evaluation_order, avg 500ns/call # spent 2µs making 3 calls to JSON::Schema::Modern::Vocabulary::Core::evaluation_order, avg 667ns/call # spent 2µs making 5 calls to JSON::Schema::Modern::Vocabulary::FormatAnnotation::evaluation_order, avg 400ns/call # spent 2µs making 5 calls to JSON::Schema::Modern::Vocabulary::Validation::evaluation_order, avg 400ns/call # spent 1µs making 3 calls to JSON::Schema::Modern::Vocabulary::Content::evaluation_order, avg 333ns/call # spent 1µs making 2 calls to JSON::Schema::Modern::Vocabulary::Unevaluated::evaluation_order, avg 500ns/call
338 || ($a->evaluation_order == 999 ? 0
339 : ($valid = E($state, '%s and %s have a conflicting evaluation_order', sort $a, $b)))
340 } @vocabulary_classes;
341
34210s $valid = E($state, 'the first vocabulary (by evaluation_order) must be Core')
343 if ($vocabulary_classes[0]//'') ne 'JSON::Schema::Modern::Vocabulary::Core';
344
345 $state->{evaluator}->_set_metaschema_vocabulary_classes($schema_info->{canonical_uri},
34612µs1171µs [ $schema_info->{specification_version}, \@vocabulary_classes ]) if $valid;
347
34812µs return ($schema_info->{specification_version}, $valid ? \@vocabulary_classes : []);
349}
350
35117µs1;
352122µs1335µs__END__