← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 16:10:05 2022
Reported on Wed Dec 14 16:12:58 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern/Vocabulary/Core.pm
StatementsExecuted 812582 statements in 1.74s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
3912111887ms87.2sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_refJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref (recurses: max depth 31, inclusive time 854s)
2586211726ms2.64sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_idJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id
258611155ms61.5sJSON::Schema::Modern::Vocabulary::Core::::_eval_keyword_dynamicRefJSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef (recurses: max depth 6, inclusive time 67.1s)
1810341198.3ms98.3msJSON::Schema::Modern::Vocabulary::Core::::CORE:substJSON::Schema::Modern::Vocabulary::Core::CORE:subst (opcode)
732224.73ms175msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_refJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref
11811851µs2.38msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_commentJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment
1111511µs5.26msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_vocabularyJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary
1411472µs5.89msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_idJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id
1522381µs4.07msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_anchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor
1511230µs4.39msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_schemaJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema
1211115µs69.6msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_defsJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs (recurses: max depth 1, inclusive time 9.78ms)
133190µs104µsJSON::Schema::Modern::Vocabulary::Core::::CORE:sortJSON::Schema::Modern::Vocabulary::Core::CORE:sort (opcode)
141186µs3.91msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_dynamicAnchorJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor
221181µs6.15msJSON::Schema::Modern::Vocabulary::Core::::_traverse_keyword_dynamicRefJSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef
301166µs66µsJSON::Schema::Modern::Vocabulary::Core::::CORE:matchJSON::Schema::Modern::Vocabulary::Core::CORE:match (opcode)
11163µs390µsJSON::Schema::Modern::Vocabulary::Core::::__fetch_vocabulary_dataJSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data
11129µs31µsModule::Runtime::::BEGIN@1 Module::Runtime::BEGIN@1
11117µs570µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@11JSON::Schema::Modern::Vocabulary::Core::BEGIN@11
11110µs32µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@13JSON::Schema::Modern::Vocabulary::Core::BEGIN@13
11110µs10µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@9JSON::Schema::Modern::Vocabulary::Core::BEGIN@9
22110µs10µsJSON::Schema::Modern::Vocabulary::Core::::keywordsJSON::Schema::Modern::Vocabulary::Core::keywords
1118µs200µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@10JSON::Schema::Modern::Vocabulary::Core::BEGIN@10
1118µs52µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@17JSON::Schema::Modern::Vocabulary::Core::BEGIN@17
1118µs162µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@18JSON::Schema::Modern::Vocabulary::Core::BEGIN@18
1117µs20µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@14JSON::Schema::Modern::Vocabulary::Core::BEGIN@14
1117µs15µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@15JSON::Schema::Modern::Vocabulary::Core::BEGIN@15
1116µs16µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@16JSON::Schema::Modern::Vocabulary::Core::BEGIN@16
1116µs28µsModule::Runtime::::BEGIN@2 Module::Runtime::BEGIN@2
1115µs95µsJSON::Schema::Modern::Vocabulary::Core::::BEGIN@12JSON::Schema::Modern::Vocabulary::Core::BEGIN@12
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
1228µs233µs
# spent 31µs (29+2) within Module::Runtime::BEGIN@1 which was called: # once (29µs+2µs) by Module::Runtime::require_module at line 1
use strict;
# spent 31µs making 1 call to Module::Runtime::BEGIN@1 # spent 2µs making 1 call to strict::import
2235µs250µs
# spent 28µs (6+22) within Module::Runtime::BEGIN@2 which was called: # once (6µs+22µs) by Module::Runtime::require_module at line 2
use warnings;
# spent 28µs making 1 call to Module::Runtime::BEGIN@2 # spent 22µ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.558';
8
9227µs110µs
# spent 10µs within JSON::Schema::Modern::Vocabulary::Core::BEGIN@9 which was called: # once (10µs+0s) by Module::Runtime::require_module at line 9
use 5.020;
10223µs2392µs
# spent 200µs (8+192) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@10 which was called: # once (8µs+192µs) by Module::Runtime::require_module at line 10
use Moo;
# spent 200µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@10 # spent 192µs making 1 call to Moo::import
11326µs31.12ms
# spent 570µs (17+553) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@11 which was called: # once (17µs+553µs) by Module::Runtime::require_module at line 11
use strictures 2;
# spent 570µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@11 # spent 538µs making 1 call to strictures::import # spent 15µs making 1 call to strictures::VERSION
12234µs2185µs
# spent 95µs (5+90) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@12 which was called: # once (5µs+90µs) by Module::Runtime::require_module at line 12
use experimental qw(signatures postderef);
# spent 95µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@12 # spent 90µs making 1 call to experimental::import
13221µs235µs
# spent 32µs (10+22) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@13 which was called: # once (10µs+22µ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
14217µs222µs
# spent 20µs (7+13) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@14 which was called: # once (7µs+13µs) by Module::Runtime::require_module at line 14
no if "$]" >= 5.031009, feature => 'indirect';
# spent 20µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@14 # spent 2µs making 1 call to if::unimport
15216µs216µs
# spent 15µs (7+8) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@15 which was called: # once (7µs+8µs) by Module::Runtime::require_module at line 15
no if "$]" >= 5.033001, feature => 'multidimensional';
# spent 15µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@15 # spent 1µs making 1 call to if::unimport
16217µs216µs
# spent 16µs (6+10) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@16 which was called: # once (6µs+10µs) by Module::Runtime::require_module at line 16
no if "$]" >= 5.033006, feature => 'bareword_filehandles';
# spent 16µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@16 # spent 0s making 1 call to if::unimport
17219µs296µs
# spent 52µs (8+44) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@17 which was called: # once (8µs+44µ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 52µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@17 # spent 44µs making 1 call to Exporter::import
1822.23ms2316µs
# spent 162µs (8+154) within JSON::Schema::Modern::Vocabulary::Core::BEGIN@18 which was called: # once (8µs+154µs) by Module::Runtime::require_module at line 18
use namespace::clean;
# spent 162µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::BEGIN@18 # spent 154µs making 1 call to namespace::clean::import
19
2011µs15.47mswith 'JSON::Schema::Modern::Vocabulary';
# spent 5.47ms 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:700] at line 696 of 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
2733µ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
2962µs
# spent 10µs within JSON::Schema::Modern::Vocabulary::Core::keywords which was called 2 times, avg 5µs/call: # once (5µs+0s) by JSON::Schema::Modern::_traverse_subschema at line 475 of JSON/Schema/Modern.pm # once (5µs+0s) by JSON::Schema::Modern::_eval_subschema at line 563 of JSON/Schema/Modern.pm
sub keywords ($self, $spec_version) {
30 return (
31211µ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
475620µs
# spent 5.89ms (472µs+5.42) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id which was called 14 times, avg 421µs/call: # 14 times (472µs+5.42ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 421µs/call
sub _traverse_keyword_id ($self, $schema, $state) {
481457µs282.96ms return if not assert_keyword_type($state, $schema, 'string')
# spent 2.58ms making 14 calls to JSON::Schema::Modern::Utilities::assert_uri_reference, avg 184µs/call # spent 377µs making 14 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 27µs/call
49 or not assert_uri_reference($state, $schema);
50
511428µs14628µs my $uri = Mojo::URL->new($schema->{'$id'});
# spent 628µs making 14 calls to Mojo::URL::new, avg 45µs/call
52
531417µ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 {
621413µs149µs return E($state, '$id value "%s" cannot have a non-empty fragment', $schema->{'$id'})
# spent 9µs making 14 calls to Mojo::URL::fragment, avg 643ns/call
63 if length $uri->fragment;
64 }
65
661435µs1410µs $uri->fragment(undef);
# spent 10µs making 14 calls to Mojo::URL::fragment, avg 714ns/call
671429µs141.22ms return E($state, '$id cannot be empty') if not length $uri;
# spent 1.22ms making 14 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 87µs/call
68
691426µs1444µs $state->{initial_schema_uri} = $uri->is_abs ? $uri : $uri->to_abs($state->{initial_schema_uri});
# spent 44µs making 14 calls to Mojo::URL::is_abs, avg 3µs/call
701413µ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
72142µ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},
811465µs14555µs };
# spent 555µs making 14 calls to Mojo::URL::clone, avg 40µs/call
821433µs return 1;
83}
84
8512931043.3ms
# spent 2.64s (726ms+1.91) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id which was called 25862 times, avg 102µs/call: # 25862 times (726ms+1.91s) by JSON::Schema::Modern::_eval_subschema at line 578 of JSON/Schema/Modern.pm, avg 102µs/call
sub _eval_keyword_id ($self, $data, $schema, $state) {
862586289.1ms25862792ms my $schema_info = $state->{document}->path_to_resource($state->{document_path}.$state->{schema_path});
# spent 792ms making 25862 calls to JSON::Schema::Modern::Document::path_to_resource, avg 31µs/call
87 # this should never happen, if the pre-evaluation traversal was performed correctly
88258628.52ms abort($state, 'failed to resolve %s to canonical uri', $state->{keyword}) if not $schema_info;
89
902586244.1ms258621.02s $state->{initial_schema_uri} = $schema_info->{canonical_uri}->clone;
# spent 1.02s making 25862 calls to Mojo::URL::clone, avg 40µs/call
912586234.5ms $state->{traversed_schema_path} = $state->{traversed_schema_path}.$state->{schema_path};
922586212.2ms $state->{document_path} = $state->{document_path}.$state->{schema_path};
932586214.0ms $state->{schema_path} = '';
942586214.7ms $state->{spec_version} = $schema_info->{specification_version};
952586210.6ms $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
982586211.9ms if ($state->{validate_formats}) {
99 $state->{vocabularies} = [
100 map s/^JSON::Schema::Modern::Vocabulary::Format\KAnnotation$/Assertion/r, $state->{vocabularies}->@*
10125862380ms18103498.3ms ];
# spent 98.3ms making 181034 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:subst, avg 543ns/call
1022586228.5ms require JSON::Schema::Modern::Vocabulary::FormatAssertion;
103 }
104
1052586230.4ms $state->@{keys $state->{configs}->%*} = values $state->{configs}->%*;
1062586227.2ms push $state->{dynamic_scope}->@*, $state->{initial_schema_uri};
107
1082586270.4ms return 1;
109}
110
1116013µs
# spent 4.39ms (230µs+4.16) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema which was called 15 times, avg 292µs/call: # 15 times (230µs+4.16ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 292µs/call
sub _traverse_keyword_schema ($self, $schema, $state) {
1121548µs302.78ms return if not assert_keyword_type($state, $schema, 'string') or not assert_uri($state, $schema);
# spent 2.47ms making 15 calls to JSON::Schema::Modern::Utilities::assert_uri, avg 164µs/call # spent 313µs making 15 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 21µ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')
119157µs if length($state->{schema_path});
120
121155µs my ($spec_version, $vocabularies);
122
1231546µs15439µs if (my $metaschema_info = $state->{evaluator}->_get_metaschema_vocabulary_classes($schema->{'$schema'})) {
# spent 439µs making 15 calls to JSON::Schema::Modern::_get_metaschema_vocabulary_classes, avg 29µs/call
124 ($spec_version, $vocabularies) = @$metaschema_info;
125 }
126 else {
12713µs1526µs my $schema_info = $state->{evaluator}->_fetch_from_uri($schema->{'$schema'});
# spent 526µ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'}),
132117µs3414µs traversed_schema_path => jsonp($state->{schema_path}, '$schema'),
# spent 390µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data # spent 18µs making 1 call to Mojo::URL::new # spent 6µs making 1 call to JSON::Schema::Modern::Utilities::jsonp
133 }, $schema_info);
134 }
135
136158µ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')
140155µs if exists $schema->{'$ref'} and $spec_version eq 'draft7';
141
1421515µ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
1451521µs if ($state->{identifiers}->@*) {
146 $state->{identifiers}[-1]->@{qw(specification_version vocabularies)} = $state->@{qw(spec_version vocabularies)};
147 }
148
1491529µs return 1;
150}
151
1526020µs
# spent 4.07ms (381µs+3.69) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor which was called 15 times, avg 271µs/call: # 14 times (326µs+3.49ms) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor at line 197, avg 273µs/call # once (55µs+194µs) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm
sub _traverse_keyword_anchor ($self, $schema, $state) {
1531519µs15243µs return if not assert_keyword_type($state, $schema, 'string');
# spent 243µs making 15 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 16µ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'
16015146µs3066µs and $schema->{$state->{keyword}} !~ /^[A-Za-z_][A-Za-z0-9._-]*$/;
# spent 66µs making 30 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:match, avg 2µs/call
161
1621536µs15267µs my $canonical_uri = canonical_uri($state);
# spent 267µs making 15 calls to JSON::Schema::Modern::Utilities::canonical_uri, avg 18µ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},
17115126µs453.11ms };
# spent 3.05ms making 15 calls to Mojo::URL::to_abs, avg 203µs/call # spent 41µs making 15 calls to Mojo::URL::new, avg 3µs/call # spent 19µs making 15 calls to Mojo::URL::fragment, avg 1µs/call
1721558µ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
1971471µs143.82ms
# spent 3.91ms (86µs+3.82) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor which was called 14 times, avg 279µs/call: # 14 times (86µs+3.82ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 279µs/call
sub _traverse_keyword_dynamicAnchor { shift->_traverse_keyword_anchor(@_) }
# spent 3.82ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor, avg 273µ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
2022928509µs
# spent 175ms (4.73+170) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref which was called 732 times, avg 238µs/call: # 710 times (4.60ms+164ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 237µs/call # 22 times (128µs+5.94ms) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef at line 228, avg 276µs/call
sub _traverse_keyword_ref ($self, $schema, $state) {
2037321.66ms1464170ms return if not assert_keyword_type($state, $schema, 'string')
# spent 160ms making 732 calls to JSON::Schema::Modern::Utilities::assert_uri_reference, avg 218µs/call # spent 10.1ms making 732 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 14µs/call
204 or not assert_uri_reference($state, $schema);
2057321.31ms return 1;
206}
207
20819560547.9ms
# spent 87.2s (887ms+86.3) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref which was called 39121 times, avg 2.23ms/call: # 39121 times (887ms+86.3s) by JSON::Schema::Modern::_eval_subschema at line 578 of JSON/Schema/Modern.pm, avg 2.23ms/call
sub _eval_keyword_ref ($self, $data, $schema, $state) {
20939121184ms7824213.6s my $uri = Mojo::URL->new($schema->{'$ref'})->to_abs($state->{initial_schema_uri});
# spent 9.13s making 39121 calls to Mojo::URL::to_abs, avg 233µs/call # spent 4.51s making 39121 calls to Mojo::URL::new, avg 115µs/call
21039121563ms3912187.2s $self->eval_subschema_at_uri($data, $schema, $state, $uri);
# spent 927s making 39121 calls to JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri, avg 23.7ms/call, recursion: max depth 38, sum of overlapping time 840s
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
2282282µs226.07ms
# spent 6.15ms (81µs+6.07) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef which was called 22 times, avg 280µs/call: # 22 times (81µs+6.07ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 280µs/call
sub _traverse_keyword_dynamicRef { shift->_traverse_keyword_ref(@_) }
# spent 6.07ms making 22 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref, avg 276µs/call
229
230129304.19ms
# spent 61.5s (155ms+61.3) within JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef which was called 2586 times, avg 23.8ms/call: # 2586 times (155ms+61.3s) by JSON::Schema::Modern::_eval_subschema at line 578 of JSON/Schema/Modern.pm, avg 23.8ms/call
sub _eval_keyword_dynamicRef ($self, $data, $schema, $state) {
231258612.5ms5172861ms my $uri = Mojo::URL->new($schema->{'$dynamicRef'})->to_abs($state->{initial_schema_uri});
# spent 496ms making 2586 calls to Mojo::URL::to_abs, avg 192µs/call # spent 365ms making 2586 calls to Mojo::URL::new, avg 141µs/call
23225868.46ms2586818ms my $schema_info = $state->{evaluator}->_fetch_from_uri($uri);
# spent 818ms making 2586 calls to JSON::Schema::Modern::_fetch_from_uri, avg 316µs/call
23325861.26ms 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, ...
237258610.1ms51724.22ms if (length $uri->fragment and exists $schema_info->{schema}{'$dynamicAnchor'}
# spent 4.22ms making 5172 calls to Mojo::URL::fragment, avg 816ns/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.10ms foreach my $base_scope ($state->{dynamic_scope}->@*) {
24325864.51ms5172362ms my $test_uri = Mojo::URL->new($base_scope)->fragment($anchor);
# spent 359ms making 2586 calls to Mojo::URL::new, avg 139µs/call # spent 2.49ms making 2586 calls to Mojo::URL::fragment, avg 962ns/call
24425865.22ms2586557ms my $dynamic_anchor_subschema_info = $state->{evaluator}->_fetch_from_uri($test_uri);
# spent 557ms making 2586 calls to JSON::Schema::Modern::_fetch_from_uri, avg 215µs/call
24525862.51ms if (($dynamic_anchor_subschema_info->{schema}->{'$dynamicAnchor'}//'') eq $anchor) {
246258610.6ms $uri = $test_uri;
24725867.08ms last;
248 }
249 }
250 }
251
252258646.2ms25860s return $self->eval_subschema_at_uri($data, $schema, $state, $uri);
# spent 126s making 2586 calls to JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri, avg 48.6ms/call, recursion: max depth 34, sum of overlapping time 126s
253}
254
255447µs
# spent 5.26ms (511µs+4.75) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary which was called 11 times, avg 478µs/call: # 11 times (511µs+4.75ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 478µs/call
sub _traverse_keyword_vocabulary ($self, $schema, $state) {
2561118µs1176µs return if not assert_keyword_type($state, $schema, 'object');
# spent 76µs making 11 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 7µs/call
257
258 return E($state, '$vocabulary can only appear at the schema resource root')
259114µs if length($state->{schema_path});
260
2611186µs my $valid = 1;
262
263114µs my @vocabulary_classes;
2641158µs1115µs foreach my $uri (sort keys $schema->{'$vocabulary'}->%*) {
# spent 15µs making 11 calls to JSON::Schema::Modern::Vocabulary::Core::CORE:sort, avg 1µs/call
26531185µs31490µs $valid = 0, next if not assert_keyword_type({ %$state, _schema_path_suffix => $uri }, $schema, 'boolean');
# spent 490µs making 31 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 16µs/call
26631115µs314.17ms $valid = 0, next if not assert_uri({ %$state, _schema_path_suffix => $uri }, undef, $uri);
# spent 4.17ms making 31 calls to JSON::Schema::Modern::Utilities::assert_uri, avg 134µ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
2771138µ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
28447299µs
# spent 2.38ms (851µs+1.53) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment which was called 118 times, avg 20µs/call: # 118 times (851µs+1.53ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 20µs/call
sub _traverse_keyword_comment ($self, $schema, $state) {
285118163µs1181.53ms return if not assert_keyword_type($state, $schema, 'string');
# spent 1.53ms making 118 calls to JSON::Schema::Modern::Utilities::assert_keyword_type, avg 13µs/call
286118302µ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(@_) }
29212113µs1269.5ms
# spent 69.6ms (115µs+69.5) within JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs which was called 12 times, avg 5.80ms/call: # 12 times (115µs+69.5ms) by JSON::Schema::Modern::_traverse_subschema at line 487 of JSON/Schema/Modern.pm, avg 5.80ms/call
sub _traverse_keyword_defs { shift->traverse_object_schemas(@_) }
# spent 79.2ms making 12 calls to JSON::Schema::Modern::Vocabulary::traverse_object_schemas, avg 6.60ms/call, recursion: max depth 2, sum of overlapping time 9.76ms
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)
29940s
# spent 390µs (63+327) within JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data which was called: # once (63µs+327µ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;
30810s $valid = E($state, '$vocabulary can only appear at the document root') if length $schema_info->{document_path};
30910s $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
31519µs12µs foreach my $uri (sort keys $schema_info->{schema}{'$vocabulary'}->%*) {
31687µs889µs my $class_info = $state->{evaluator}->_get_vocabulary_class($uri);
# spent 89µs making 8 calls to JSON::Schema::Modern::_get_vocabulary_class, avg 11µs/call
317 $valid = E({ %$state, _schema_path_suffix => $uri }, '"%s" is not a known vocabulary', $uri), next
318817µs84µs if $schema_info->{schema}{'$vocabulary'}{$uri} and not $class_info;
# spent 4µs making 8 calls to JSON::PP::Boolean::__ANON__[JSON/PP/Boolean.pm:7], avg 500ns/call
319
32080s next if not $class_info; # vocabulary is not known, but marked as false in the metaschema
321
32287µ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
32581µs if $spec_version ne $schema_info->{specification_version};
326
32784µs push @vocabulary_classes, $class;
328 }
329
330 @vocabulary_classes = sort {
3311638µs31101µs $a->evaluation_order <=> $b->evaluation_order
# spent 87µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::CORE:sort # 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 5 calls to JSON::Schema::Modern::Vocabulary::FormatAnnotation::evaluation_order, avg 400ns/call # spent 2µs making 5 calls to JSON::Schema::Modern::Vocabulary::MetaData::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 # spent 1µs making 3 calls to JSON::Schema::Modern::Vocabulary::evaluation_order, avg 333ns/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},
34015µs1145µs [ $schema_info->{specification_version}, \@vocabulary_classes ]) if $valid;
341
34212µs return ($schema_info->{specification_version}, $valid ? \@vocabulary_classes : []);
343}
344
34515µs1;
346
347125µs1303µs__END__
 
# spent 66µs within JSON::Schema::Modern::Vocabulary::Core::CORE:match which was called 30 times, avg 2µs/call: # 30 times (66µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor at line 160, avg 2µs/call
sub JSON::Schema::Modern::Vocabulary::Core::CORE:match; # opcode
# spent 104µs (90+14) within JSON::Schema::Modern::Vocabulary::Core::CORE:sort which was called 13 times, avg 8µs/call: # 11 times (15µs+0s) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary at line 264, avg 1µs/call # once (73µs+14µs) by JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data at line 331 # once (2µs+0s) by JSON::Schema::Modern::Vocabulary::Core::__fetch_vocabulary_data at line 315
sub JSON::Schema::Modern::Vocabulary::Core::CORE:sort; # opcode
# spent 98.3ms within JSON::Schema::Modern::Vocabulary::Core::CORE:subst which was called 181034 times, avg 543ns/call: # 181034 times (98.3ms+0s) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id at line 101, avg 543ns/call
sub JSON::Schema::Modern::Vocabulary::Core::CORE:subst; # opcode