← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 15:57:08 2022
Reported on Wed Dec 14 16:00:37 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern/Vocabulary/Core.pm
StatementsExecuted 812582 statements in 1.70s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
3912111799ms99.6sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_refJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref (recurses: max depth 31, inclusive time 986s)
2586211777ms2.58sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_idJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id
258611138ms70.9sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_dynamicRefJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef (recurses: max depth 6, inclusive time 79.9s)
1810341189.6ms89.6msJSON::Schema::Modern::Vocabulary::Core::::CORE:substJSON::Schema::Modern::Vocabulary::Core::CORE:subst (opcode)
732225.20ms209msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_refJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref
1111668µs6.33msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_vocabularyJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary
11811583µs2.36msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_commentJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment
1411486µs6.17msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_idJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id
1522474µs5.40msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_anchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor
1511334µs5.66msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_schemaJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema
1411205µs5.04msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_dynamicAnchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor
1331124µs141µsJSON::Schema::Modern::Vocabulary::Core::::CORE:sortJSON::Schema::Modern::Vocabulary::Core::CORE:sort (opcode)
1211113µs90.4msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_defsJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs (recurses: max depth 1, inclusive time 9.35ms)
2211104µs4.81msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_dynamicRefJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef
111100µs588µsJSON::Schema::Modern::Vocabulary::Core::::__fetch_vocabulary_dataJSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data
301198µs98µsJSON::Schema::Modern::Vocabulary::Core::::CORE:matchJSON::Schema::Modern::Vocabulary::Core::CORE:match (opcode)
11181µs92µsModule::Runtime::::BEGIN@1 Module::Runtime::BEGIN@1
11121µs1.42msJSON::Schema::Modern::Vocabulary::Core::::BEGIN@11JSON::Schema::Modern::Vocabulary::Core::BEGIN@11
11121µs50µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@13JSON::Schema::Modern::Vocabulary::Core::BEGIN@13
11121µs21µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@9JSON::Schema::Modern::Vocabulary::Core::BEGIN@9
11118µs33µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@15JSON::Schema::Modern::Vocabulary::Core::BEGIN@15
22115µs15µsJSON::Schema::Modern::Vocabulary::Core::::keywordsJSON::Schema::Modern::Vocabulary::Core::keywords
11114µs178µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@12JSON::Schema::Modern::Vocabulary::Core::BEGIN@12
11113µs29µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@14JSON::Schema::Modern::Vocabulary::Core::BEGIN@14
11112µs75µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@17JSON::Schema::Modern::Vocabulary::Core::BEGIN@17
11110µs353µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@10JSON::Schema::Modern::Vocabulary::Core::BEGIN@10
1119µs26µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@16JSON::Schema::Modern::Vocabulary::Core::BEGIN@16
1118µs294µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@18JSON::Schema::Modern::Vocabulary::Core::BEGIN@18
1118µs95µsModule::Runtime::::BEGIN@2 Module::Runtime::BEGIN@2
3112µs2µsJSON::Schema::Modern::Vocabulary::Core::::evaluation_orderJSON::Schema::Modern::Vocabulary::Core::evaluation_order
1112µs2µ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
1290µs2103µs
# spent 92µs (81+11) within Module::Runtime::BEGIN@1 which was called: # once (81µs+11µs) by Module::Runtime::require_module at line 1
use strict;
# spent 92µs making 1 call to Module::Runtime::BEGIN@1 # spent 11µs making 1 call to strict::import
2271µs2182µs
# spent 95µs (8+87) within Module::Runtime::BEGIN@2 which was called: # once (8µs+87µs) by Module::Runtime::require_module at line 2
use warnings;
# spent 95µs making 1 call to Module::Runtime::BEGIN@2 # spent 87µ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
711µsour $VERSION = '0.556';
8
9267µs121µs
# spent 21µs within JSON::Schema::Modern::Vocabulary::Core::BEGIN@9 which was called: # once (21µs+0s) by Module::Runtime::require_module at line 9
use 5.020;
10236µs2696µs
# spent 353µs (10+343) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@10 which was called: # once (10µs+343µs) by Module::Runtime::require_module at line 10
use Moo;
# spent 353µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@10 # spent 343µs making 1 call to Moo::import
11389µs32.82ms
# spent 1.42ms (21µs+1.40) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@11 which was called: # once (21µs+1.40ms) by Module::Runtime::require_module at line 11
use strictures 2;
# spent 1.42ms making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@11 # spent 1.37ms making 1 call to strictures::import # spent 27µs making 1 call to strictures::VERSION
12257µs2342µs
# spent 178µs (14+164) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@12 which was called: # once (14µs+164µs) by Module::Runtime::require_module at line 12
use experimental qw(signatures postderef);
# spent 178µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@12 # spent 164µs making 1 call to experimental::import
13249µs253µs
# spent 50µs (21+29) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@13 which was called: # once (21µs+29µs) by Module::Runtime::require_module at line 13
use if "$]" >= 5.022, experimental => 're_strict';
# spent 50µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@13 # spent 3µs making 1 call to if::import
14232µs230µs
# spent 29µs (13+16) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@14 which was called: # once (13µs+16µs) by Module::Runtime::require_module at line 14
no if "$]" >= 5.031009, feature => 'indirect';
# spent 29µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@14 # spent 1µs making 1 call to if::unimport
15228µs235µs
# spent 33µs (18+15) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@15 which was called: # once (18µs+15µs) by Module::Runtime::require_module at line 15
no if "$]" >= 5.033001, feature => 'multidimensional';
# spent 33µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@15 # spent 2µs making 1 call to if::unimport
16226µs226µs
# spent 26µs (9+17) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@16 which was called: # once (9µs+17µs) by Module::Runtime::require_module at line 16
no if "$]" >= 5.033006, feature => 'bareword_filehandles';
# spent 26µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@16 # spent 0s making 1 call to if::unimport
17231µs2138µs
# spent 75µs (12+63) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@17 which was called: # once (12µs+63µ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 75µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@17 # spent 63µs making 1 call to Exporter::import
1822.19ms2580µs
# spent 294µs (8+286) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@18 which was called: # once (8µs+286µs) by Module::Runtime::require_module at line 18
use namespace::clean;
# spent 294µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@18 # spent 286µs making 1 call to namespace::clean::import
19
20116µs14.57mswith 'JSON::Schema::Modern::Vocabulary';
# spent 4.57ms making 1 call to Moo::with
21
22
# spent 2µs within JSON::Schema::Modern::Vocabulary::Core::vocabulary which was called: # once (2µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:696] at line 692 of JSON/Schema/Modern.pm
sub vocabulary {
2314µ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
2737µ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 331, avg 667ns/call
sub evaluation_order { 0 }
28
2964µs
# spent 15µs within JSON::Schema::Modern::Vocabulary::Core::keywords which was called 2 times, avg 8µs/call: # once (10µs+0s) by JSON::Schema::Modern::_eval_subschema at line 559 of JSON/Schema/Modern.pm # once (5µs+0s) by JSON::Schema::Modern::_traverse_subschema at line 471 of JSON/Schema/Modern.pm
sub keywords ($self, $spec_version) {
30 return (
31219µ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
475612µs
# spent 6.17ms (486µs+5.68) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id which was called 14 times, avg 441µs/call: # 14 times (486µs+5.68ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 441µs/call
sub _traverse_keyword_id ($self, $schema, $state) {
481459µs282.91ms return if not assert_keyword_type($state, $schema, 'string')
# spent 2.52ms making 14 calls to JSON::Schema::Modern::Utilities::assert_uri_reference, avg 180µs/call # spent 394µs making 14 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 28µs/call
49 or not assert_uri_reference($state, $schema);
50
511427µs14622µs my $uri = Mojo::URL->new($schema->{'$id'});
# spent 622µs making 14 calls to Mojo::URL::new, avg 44µs/call
52
531412µ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 {
621414µs1412µs return E($state, '$id value "%s" cannot have a non-empty fragment', $schema->{'$id'})
# spent 12µs making 14 calls to Mojo::URL::fragment, avg 857ns/call
63 if length $uri->fragment;
64 }
65
66148µs1411µs $uri->fragment(undef);
# spent 11µs making 14 calls to Mojo::URL::fragment, avg 786ns/call
671435µs141.32ms return E($state, '$id cannot be empty') if not length $uri;
# spent 1.32ms making 14 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 95µs/call
68
691426µs1476µs $state->{initial_schema_uri} = $uri->is_abs ? $uri : $uri->to_abs($state->{initial_schema_uri});
# spent 76µs making 14 calls to Mojo::URL::is_abs, avg 5µs/call
701418µ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
72149µ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},
811483µs14726µs };
# spent 726µs making 14 calls to Mojo::URL::clone, avg 52µs/call
821432µs return 1;
83}
84
8512931028.1ms
# spent 2.58s (777ms+1.80) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id which was called 25862 times, avg 100µs/call: # 25862 times (777ms+1.80s) by JSON::Schema::Modern::_eval_subschema at line 574 of JSON/Schema/Modern.pm, avg 100µs/call
sub _eval_keyword_id ($self, $data, $schema, $state) {
862586288.9ms25862771ms my $schema_info = $state->{document}->path_to_resource($state->{document_path}.$state->{schema_path});
# spent 771ms making 25862 calls to JSON::Schema::Modern::Document::path_to_resource, avg 30µs/call
87 # this should never happen, if the pre-evaluation traversal was performed correctly
88258628.58ms abort($state, 'failed to resolve %s to canonical uri', $state->{keyword}) if not $schema_info;
89
902586245.1ms25862943ms $state->{initial_schema_uri} = $schema_info->{canonical_uri}->clone;
# spent 943ms making 25862 calls to Mojo::URL::clone, avg 36µs/call
912586231.9ms $state->{traversed_schema_path} = $state->{traversed_schema_path}.$state->{schema_path};
92258629.70ms $state->{document_path} = $state->{document_path}.$state->{schema_path};
93258629.33ms $state->{schema_path} = '';
942586210.8ms $state->{spec_version} = $schema_info->{specification_version};
95258629.80ms $state->{vocabularies} = $schema_info->{vocabularies};
96 # it's possible that a different schema resource has its own set of configs, different from the
97 # JSM attribute value
982586212.4ms if ($state->{validate_formats}) {
99 $state->{vocabularies} = [
100 map s/^JSON::Schema::Modern::Vocabulary::Format\KAnnotation$/Assertion/r, $state->{vocabularies}->@*
10125862454ms18103489.6ms ];
# spent 89.6ms making 181034 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:subst, avg 495ns/call
1022586226.7ms require JSON::Schema::Modern::Vocabulary::FormatAssertion;
103 }
104
1052586225.1ms $state->@{keys $state->{configs}->%*} = values $state->{configs}->%*;
1062586224.7ms push $state->{dynamic_scope}->@*, $state->{initial_schema_uri};
107
1082586253.7ms return 1;
109}
110
1116015µs
# spent 5.66ms (334µs+5.33) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema which was called 15 times, avg 378µs/call: # 15 times (334µs+5.33ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 378µs/call
sub _traverse_keyword_schema ($self, $schema, $state) {
1121562µs303.32ms return if not assert_keyword_type($state, $schema, 'string') or not assert_uri($state, $schema);
# spent 2.97ms making 15 calls to JSON::Schema::Modern::Utilities::assert_uri, avg 198µs/call # spent 350µs making 15 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 23µs/call
113
114 # "A JSON Schema resource is a schema which is canonically identified by an absolute URI."
115 # "A resource's root schema is its top-level schema object."
116 # note: we need not be at the document root, but simply adjacent to an $id (or be the at the
117 # document root)
118 return E($state, '$schema can only appear at the schema resource root')
1191511µs if length($state->{schema_path});
120
121154µs my ($spec_version, $vocabularies);
122
1231556µs15685µs if (my $metaschema_info = $state->{evaluator}->_get_metaschema_vocabulary_classes($schema->{'$schema'})) {
# spent 685µs making 15 calls to JSON::Schema::Modern::_get_metaschema_vocabulary_classes, avg 46µs/call
124 ($spec_version, $vocabularies) = @$metaschema_info;
125 }
126 else {
12717µs1676µs my $schema_info = $state->{evaluator}->_fetch_from_uri($schema->{'$schema'});
# spent 676µs making 1 call to JSON::Schema::Modern::_fetch_from_uri
12810s return E($state, 'EXCEPTION: unable to find resource %s', $schema->{'$schema'}) if not $schema_info;
129
130 ($spec_version, $vocabularies) = $self->__fetch_vocabulary_data({ %$state,
131 keyword => '$vocabulary', initial_schema_uri => Mojo::URL->new($schema->{'$schema'}),
132120µs3647µs traversed_schema_path => jsonp($state->{schema_path}, '$schema'),
# spent 588µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data # spent 49µs making 1 call to Mojo::URL::new # spent 10µs making 1 call to JSON::Schema::Modern::Utilities::jsonp
133 }, $schema_info);
134 }
135
136156µs return E($state, '"%s" is not a valid metaschema', $schema->{'$schema'}) if not @$vocabularies;
137
138 # we special-case this because the check in _eval_subschema for older drafts + $ref has already happened
139 return E($state, '$schema and $ref cannot be used together in older drafts')
140159µs if exists $schema->{'$ref'} and $spec_version eq 'draft7';
141
1421518µs $state->@{qw(spec_version vocabularies)} = ($spec_version, $vocabularies);
143
144 # remember, if we don't have a sibling $id, we must be at the document root with no identifiers
1451524µs if ($state->{identifiers}->@*) {
146 $state->{identifiers}[-1]->@{qw(specification_version vocabularies)} = $state->@{qw(spec_version vocabularies)};
147 }
148
1491535µs return 1;
150}
151
1526010µs
# spent 5.40ms (474µs+4.93) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor which was called 15 times, avg 360µs/call: # 14 times (391µs+4.45ms) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor at line 197, avg 346µs/call # once (83µs+482µs) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm
sub _traverse_keyword_anchor ($self, $schema, $state) {
1531540µs15302µs return if not assert_keyword_type($state, $schema, 'string');
# spent 302µs making 15 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 20µs/call
154
155 return E($state, '%s value "%s" does not match required syntax',
156 $state->{keyword}, ($state->{keyword} eq '$id' ? '#' : '').$schema->{$state->{keyword}})
157 if $state->{spec_version} =~ /^draft(?:7|2019-09)$/
158 and $schema->{$state->{keyword}} !~ /^[A-Za-z][A-Za-z0-9_:.-]*$/
159 or $state->{spec_version} eq 'draft2020-12'
16015193µs3098µs and $schema->{$state->{keyword}} !~ /^[A-Za-z_][A-Za-z0-9._-]*$/;
# spent 98µs making 30 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:match, avg 3µs/call
161
1621557µs15490µs my $canonical_uri = canonical_uri($state);
# spent 490µs making 15 calls to JSON::Schema::Modern::Utilities::canonical_uri, avg 33µs/call
163
164 push $state->{identifiers}->@*,
165 Mojo::URL->new->to_abs($canonical_uri)->fragment($schema->{$state->{keyword}}) => {
166 path => $state->{traversed_schema_path}.$state->{schema_path},
167 canonical_uri => $canonical_uri,
168 specification_version => $state->{spec_version},
169 vocabularies => $state->{vocabularies}, # reference, not copy
170 configs => $state->{configs},
17115150µs454.04ms };
# spent 3.89ms making 15 calls to Mojo::URL::to_abs, avg 259µs/call # spent 130µs making 15 calls to Mojo::URL::new, avg 9µs/call # spent 19µs making 15 calls to Mojo::URL::fragment, avg 1µs/call
1721582µs return 1;
173}
174
175# we already indexed the $anchor uri, so there is nothing more to do at evaluation time.
176# we explicitly do NOT set $state->{initial_schema_uri}.
177
178sub _traverse_keyword_recursiveAnchor ($self, $schema, $state) {
179 return if not assert_keyword_type($state, $schema, 'boolean');
180
181 # this is required because the location is used as the base URI for future resolution
182 # of $recursiveRef, and the fragment would be disregarded in the base
183 return E($state, '"$recursiveAnchor" keyword used without "$id"')
184 if length($state->{schema_path});
185 return 1;
186}
187
188sub _eval_keyword_recursiveAnchor ($self, $data, $schema, $state) {
189 return 1 if not $schema->{'$recursiveAnchor'} or exists $state->{recursive_anchor_uri};
190
191 # record the canonical location of the current position, to be used against future resolution
192 # of a $recursiveRef uri -- as if it was the current location when we encounter a $ref.
193 $state->{recursive_anchor_uri} = canonical_uri($state);
194 return 1;
195}
196
19714135µs144.84ms
# spent 5.04ms (205µs+4.84) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor which was called 14 times, avg 360µs/call: # 14 times (205µs+4.84ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 360µs/call
sub _traverse_keyword_dynamicAnchor { shift->_traverse_keyword_anchor(@_) }
# spent 4.84ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor, avg 346µs/call
198
199# we already indexed the $dynamicAnchor uri, so there is nothing more to do at evaluation time.
200# we explicitly do NOT set $state->{initial_schema_uri}.
201
2022928523µs
# spent 209ms (5.20+204) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref which was called 732 times, avg 285µs/call: # 710 times (5.11ms+199ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 288µs/call # 22 times (90µs+4.62ms) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef at line 228, avg 214µs/call
sub _traverse_keyword_ref ($self, $schema, $state) {
2037321.95ms1464204ms return if not assert_keyword_type($state, $schema, 'string')
# spent 192ms making 732 calls to JSON::Schema::Modern::Utilities::assert_uri_reference, avg 263µs/call # spent 11.6ms making 732 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 16µs/call
204 or not assert_uri_reference($state, $schema);
2057321.71ms return 1;
206}
207
20819560540.5ms
# spent 99.6s (799ms+98.8) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref which was called 39121 times, avg 2.55ms/call: # 39121 times (799ms+98.8s) by JSON::Schema::Modern::_eval_subschema at line 574 of JSON/Schema/Modern.pm, avg 2.55ms/call
sub _eval_keyword_ref ($self, $data, $schema, $state) {
20939121164ms7824213.2s my $uri = Mojo::URL->new($schema->{'$ref'})->to_abs($state->{initial_schema_uri});
# spent 8.76s making 39121 calls to Mojo::URL::to_abs, avg 224µs/call # spent 4.43s making 39121 calls to Mojo::URL::new, avg 113µs/call
21039121534ms3912199.6s $self->eval_subschema_at_uri($data, $schema, $state, $uri);
# spent 1071s making 39121 calls to JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri, avg 27.4ms/call, recursion: max depth 38, sum of overlapping time 972s
211}
212
213sub _traverse_keyword_recursiveRef { shift->_traverse_keyword_ref(@_) }
214
215sub _eval_keyword_recursiveRef ($self, $data, $schema, $state) {
216 my $uri = Mojo::URL->new($schema->{'$recursiveRef'})->to_abs($state->{initial_schema_uri});
217 my $schema_info = $state->{evaluator}->_fetch_from_uri($uri);
218 abort($state, 'EXCEPTION: unable to find resource %s', $uri) if not $schema_info;
219
220 if (is_type('boolean', $schema_info->{schema}{'$recursiveAnchor'}) and $schema_info->{schema}{'$recursiveAnchor'}) {
221 $uri = Mojo::URL->new($schema->{'$recursiveRef'})
222 ->to_abs($state->{recursive_anchor_uri} // $state->{initial_schema_uri});
223 }
224
225 return $self->eval_subschema_at_uri($data, $schema, $state, $uri);
226}
227
22822133µs224.71ms
# spent 4.81ms (104µs+4.71) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef which was called 22 times, avg 219µs/call: # 22 times (104µs+4.71ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 219µs/call
sub _traverse_keyword_dynamicRef { shift->_traverse_keyword_ref(@_) }
# spent 4.71ms making 22 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref, avg 214µs/call
229
230129303.45ms
# spent 70.9s (138ms+70.8) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef which was called 2586 times, avg 27.4ms/call: # 2586 times (138ms+70.8s) by JSON::Schema::Modern::_eval_subschema at line 574 of JSON/Schema/Modern.pm, avg 27.4ms/call
sub _eval_keyword_dynamicRef ($self, $data, $schema, $state) {
231258611.7ms5172874ms my $uri = Mojo::URL->new($schema->{'$dynamicRef'})->to_abs($state->{initial_schema_uri});
# spent 506ms making 2586 calls to Mojo::URL::to_abs, avg 196µs/call # spent 368ms making 2586 calls to Mojo::URL::new, avg 142µs/call
23225867.58ms2586732ms my $schema_info = $state->{evaluator}->_fetch_from_uri($uri);
# spent 732ms making 2586 calls to JSON::Schema::Modern::_fetch_from_uri, avg 283µs/call
23325861.25ms abort($state, 'EXCEPTION: unable to find resource %s', $uri) if not $schema_info;
234
235 # If the initially resolved starting point URI includes a fragment that was created by the
236 # "$dynamicAnchor" keyword, ...
237258611.1ms51724.14ms if (length $uri->fragment and exists $schema_info->{schema}{'$dynamicAnchor'}
# spent 4.14ms making 5172 calls to Mojo::URL::fragment, avg 801ns/call
238 and $uri->fragment eq (my $anchor = $schema_info->{schema}{'$dynamicAnchor'})) {
239 # ...the initial URI MUST be replaced by the URI (including the fragment) for the outermost
240 # schema resource in the dynamic scope that defines an identically named fragment with
241 # "$dynamicAnchor".
24225862.86ms foreach my $base_scope ($state->{dynamic_scope}->@*) {
24325865.52ms5172356ms my $test_uri = Mojo::URL->new($base_scope)->fragment($anchor);
# spent 354ms making 2586 calls to Mojo::URL::new, avg 137µs/call # spent 2.46ms making 2586 calls to Mojo::URL::fragment, avg 952ns/call
24425864.89ms2586572ms my $dynamic_anchor_subschema_info = $state->{evaluator}->_fetch_from_uri($test_uri);
# spent 572ms making 2586 calls to JSON::Schema::Modern::_fetch_from_uri, avg 221µs/call
24525862.53ms if (($dynamic_anchor_subschema_info->{schema}->{'$dynamicAnchor'}//'') eq $anchor) {
24625869.95ms $uri = $test_uri;
24725866.74ms last;
248 }
249 }
250 }
251
252258646.1ms25860s return $self->eval_subschema_at_uri($data, $schema, $state, $uri);
# spent 148s making 2586 calls to JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri, avg 57.3ms/call, recursion: max depth 34, sum of overlapping time 148s
253}
254
2554415µs
# spent 6.33ms (668µs+5.67) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary which was called 11 times, avg 576µs/call: # 11 times (668µs+5.67ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 576µs/call
sub _traverse_keyword_vocabulary ($self, $schema, $state) {
2561122µs11138µs return if not assert_keyword_type($state, $schema, 'object');
# spent 138µs making 11 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 13µs/call
257
258 return E($state, '$vocabulary can only appear at the schema resource root')
259118µs if length($state->{schema_path});
260
261113µs my $valid = 1;
262
263114µs my @vocabulary_classes;
2641188µs1137µs foreach my $uri (sort keys $schema->{'$vocabulary'}->%*) {
# spent 37µs making 11 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:sort, avg 3µs/call
26531280µs31487µs $valid = 0, next if not assert_keyword_type({ %$state, _schema_path_suffix => $uri }, $schema, 'boolean');
# spent 487µs making 31 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 16µs/call
26631170µs315.00ms $valid = 0, next if not assert_uri({ %$state, _schema_path_suffix => $uri }, undef, $uri);
# spent 5.00ms making 31 calls to JSON::Schema::Modern::Utilities::assert_uri, avg 161µs/call
267 }
268
269 # we cannot return an error here for invalid or incomplete vocabulary lists, because
270 # - the specification vocabulary schemas themselves don't list Core,
271 # - it is possible for a metaschema to $ref to another metaschema that uses an unrecognized
272 # vocabulary uri while still validating those vocabulary keywords (e.g.
273 # https://spec.openapis.org/oas/3.1/schema-base/2021-05-20)
274 # Instead, we will verify these constraints when we actually use the metaschema, in
275 # _traverse_keyword_schema -> __fetch_vocabulary_data
276
2771158µs return $valid;
278}
279
280# we do nothing with $vocabulary yet at evaluation time. When we know we are in a metaschema,
281# we can scan the URIs included here and either abort if a vocabulary is enabled that we do not
282# understand, or turn on and off certain keyword behaviours based on the boolean values seen.
283
284472109µs
# spent 2.36ms (583µs+1.77) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment which was called 118 times, avg 20µs/call: # 118 times (583µs+1.77ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 20µs/call
sub _traverse_keyword_comment ($self, $schema, $state) {
285118169µs1181.78ms return if not assert_keyword_type($state, $schema, 'string');
# spent 1.78ms making 118 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 15µs/call
286118232µs return 1;
287}
288
289# we do nothing with $comment at evaluation time, including not collecting its value for annotations.
290
291sub _traverse_keyword_definitions { shift->traverse_object_schemas(@_) }
2921271µs1290.4ms
# spent 90.4ms (113µs+90.3) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs which was called 12 times, avg 7.54ms/call: # 12 times (113µs+90.3ms) by JSON::Schema::Modern::_traverse_subschema at line 483 of JSON/Schema/Modern.pm, avg 7.54ms/call
sub _traverse_keyword_defs { shift->traverse_object_schemas(@_) }
# spent 99.7ms making 12 calls to JSON::Schema::Modern::Vocabulary::traverse_object_schemas, avg 8.31ms/call, recursion: max depth 2, sum of overlapping time 9.29ms
293
294# we do nothing directly with $defs at evaluation time, including not collecting its value for
295# annotations.
296
297
298# translate vocabulary URIs into classes, caching the results (if any)
29942µs
# spent 588µs (100+488) within JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data which was called: # once (100µs+488µs) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema at line 132
sub __fetch_vocabulary_data ($self, $state, $schema_info) {
30011µs if (not exists $schema_info->{schema}{'$vocabulary'}) {
301 # "If "$vocabulary" is absent, an implementation MAY determine behavior based on the meta-schema
302 # if it is recognized from the URI value of the referring schema's "$schema" keyword."
303 my $metaschema_uri = $state->{evaluator}->METASCHEMA_URIS->{$schema_info->{specification_version}};
304 return $state->{evaluator}->_get_metaschema_vocabulary_classes($metaschema_uri)->@*;
305 }
306
30711µs my $valid = 1;
30811µs $valid = E($state, '$vocabulary can only appear at the document root') if length $schema_info->{document_path};
30911µs $valid = E($state, 'metaschemas must have an $id') if not exists $schema_info->{schema}{'$id'};
310
31111µs return (undef, []) if not $valid;
312
31310s my @vocabulary_classes;
314
315111µs14µs foreach my $uri (sort keys $schema_info->{schema}{'$vocabulary'}->%*) {
31686µs8145µs my $class_info = $state->{evaluator}->_get_vocabulary_class($uri);
# spent 145µs making 8 calls to JSON::Schema::Modern::_get_vocabulary_class, avg 18µs/call
317 $valid = E({ %$state, _schema_path_suffix => $uri }, '"%s" is not a known vocabulary', $uri), next
318829µs86µs if $schema_info->{schema}{'$vocabulary'}{$uri} and not $class_info;
# spent 6µs making 8 calls to JSON::PP::Boolean::__ANON__[JSON/PP/Boolean.pm:7], avg 750ns/call
319
32080s next if not $class_info; # vocabulary is not known, but marked as false in the metaschema
321
32286µs my ($spec_version, $class) = @$class_info;
323 $valid = E({ %$state, _schema_path_suffix => $uri }, '"%s" uses %s, but the metaschema itself uses %s',
324 $uri, $spec_version, $schema_info->{specification_version}), next
32580s if $spec_version ne $schema_info->{specification_version};
326
32785µs push @vocabulary_classes, $class;
328 }
329
330 @vocabulary_classes = sort {
3311655µs31117µs $a->evaluation_order <=> $b->evaluation_order
# spent 100µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::CORE:sort # spent 3µs making 3 calls to JSON::Schema::Modern::Vocabulary::Content::evaluation_order, avg 1µs/call # spent 3µs making 5 calls to JSON::Schema::Modern::Vocabulary::FormatAnnotation::evaluation_order, avg 600ns/call # spent 3µs making 5 calls to JSON::Schema::Modern::Vocabulary::Validation::evaluation_order, avg 600ns/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 3 calls to JSON::Schema::Modern::Vocabulary::evaluation_order, avg 667ns/call # spent 1µs making 5 calls to JSON::Schema::Modern::Vocabulary::MetaData::evaluation_order, avg 200ns/call # spent 1µs making 2 calls to JSON::Schema::Modern::Vocabulary::Unevaluated::evaluation_order, avg 500ns/call
332 || ($a->evaluation_order == 999 ? 0
333 : ($valid = E($state, '%s and %s have a conflicting evaluation_order', sort $a, $b)))
334 } @vocabulary_classes;
335
33611µs $valid = E($state, 'the first vocabulary (by evaluation_order) must be Core')
337 if ($vocabulary_classes[0]//'') ne 'JSON::Schema::Modern::Vocabulary::Core';
338
339 $state->{evaluator}->_set_metaschema_vocabulary_classes($schema_info->{canonical_uri},
34014µs1233µs [ $schema_info->{specification_version}, \@vocabulary_classes ]) if $valid;
341
34214µs return ($schema_info->{specification_version}, $valid ? \@vocabulary_classes : []);
343}
344
34517µs1;
346
347136µs1605µs__END__
 
# spent 98µs within JSON::Schema::Modern::Vocabulary::Core::CORE:match which was called 30 times, avg 3µs/call: # 30 times (98µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor at line 160, avg 3µs/call
sub JSON::Schema::Modern::Vocabulary::Core::CORE:match; # opcode
# spent 141µs (124+17) within JSON::Schema::Modern::Vocabulary::Core::CORE:sort which was called 13 times, avg 11µs/call: # 11 times (37µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary at line 264, avg 3µs/call # once (83µs+17µs) by JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data at line 331 # once (4µs+0s) by JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data at line 315
sub JSON::Schema::Modern::Vocabulary::Core::CORE:sort; # opcode
# spent 89.6ms within JSON::Schema::Modern::Vocabulary::Core::CORE:subst which was called 181034 times, avg 495ns/call: # 181034 times (89.6ms+0s) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id at line 101, avg 495ns/call
sub JSON::Schema::Modern::Vocabulary::Core::CORE:subst; # opcode