← 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:01 2022

Filename/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm
StatementsExecuted 17973735 statements in 10.6s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
90777328.56s64.4sJSON::Schema::Modern::::_eval_subschemaJSON::Schema::Modern::_eval_subschema (recurses: max depth 74, inclusive time 1441s)
46451531.82s17.2sJSON::Schema::Modern::::_fetch_from_uriJSON::Schema::Modern::_fetch_from_uri
203030441257ms257msJSON::Schema::Modern::::CORE:matchJSON::Schema::Modern::CORE:match (opcode)
283352178ms578msJSON::Schema::Modern::::_traverse_subschemaJSON::Schema::Modern::_traverse_subschema (recurses: max depth 6, inclusive time 678ms)
3878311151ms5.70sJSON::Schema::Modern::::_get_or_load_resourceJSON::Schema::Modern::_get_or_load_resource
111150ms64.6sJSON::Schema::Modern::::evaluateJSON::Schema::Modern::evaluate
535644157.9ms57.9msJSON::Schema::Modern::::CORE:sortJSON::Schema::Modern::CORE:sort (opcode)
7414324.2ms1.12sJSON::Schema::Modern::::traverseJSON::Schema::Modern::traverse (recurses: max depth 1, inclusive time 1.66ms)
123061117.4ms17.4msJSON::Schema::Modern::::CORE:qrJSON::Schema::Modern::CORE:qr (opcode)
123061115.5ms15.5msJSON::Schema::Modern::::CORE:regcompJSON::Schema::Modern::CORE:regcomp (opcode)
1119.56ms12.7msJSON::Schema::Modern::::BEGIN@25JSON::Schema::Modern::BEGIN@25
1116.27ms65.2msJSON::Schema::Modern::::BEGIN@31JSON::Schema::Modern::BEGIN@31
741114.09ms90.3msJSON::Schema::Modern::::_get_metaschema_infoJSON::Schema::Modern::_get_metaschema_info (recurses: max depth 1, inclusive time 25µs)
1113.36ms5.69msJSON::Schema::Modern::::BEGIN@36JSON::Schema::Modern::BEGIN@36
1113.12ms31.8msJSON::Schema::Modern::::BEGIN@27JSON::Schema::Modern::BEGIN@27
1113.07ms181msJSON::Schema::Modern::::BEGIN@23JSON::Schema::Modern::BEGIN@23
1113.04ms3.17msJSON::Schema::Modern::::BEGIN@28JSON::Schema::Modern::BEGIN@28
1112.25ms28.0msJSON::Schema::Modern::::BEGIN@34JSON::Schema::Modern::BEGIN@34
1112.12ms19.3msJSON::Schema::Modern::::BEGIN@18JSON::Schema::Modern::BEGIN@18
1111.57ms38.1msJSON::Schema::Modern::::BEGIN@35JSON::Schema::Modern::BEGIN@35
1111.56ms1.77msJSON::Schema::Modern::::BEGIN@30JSON::Schema::Modern::BEGIN@30
1111.26ms5.65msJSON::Schema::Modern::::BEGIN@29JSON::Schema::Modern::BEGIN@29
1111.20ms68.3msJSON::Schema::Modern::::BEGIN@33JSON::Schema::Modern::BEGIN@33
9321.11ms183msJSON::Schema::Modern::::add_schemaJSON::Schema::Modern::add_schema
1511704µs11.6msJSON::Schema::Modern::::__ANON__[:685]JSON::Schema::Modern::__ANON__[:685]
11184µs57.9msJSON::Schema::Modern::::add_vocabularyJSON::Schema::Modern::add_vocabulary
11176µs51.6msJSON::Schema::Modern::::__ANON__[:709]JSON::Schema::Modern::__ANON__[:709]
11164µs730µsJSON::Schema::Modern::::__ANON__[:124]JSON::Schema::Modern::__ANON__[:124]
1253130µs30µsJSON::Schema::Modern::::CORE:substJSON::Schema::Modern::CORE:subst (opcode)
262120µs20µsJSON::Schema::Modern::::CACHED_METASCHEMASJSON::Schema::Modern::CACHED_METASCHEMAS (xsub)
11118µs101µsJSON::Schema::Modern::::__ANON__[:751]JSON::Schema::Modern::__ANON__[:751]
11114µs632µsJSON::Schema::Modern::::BEGIN@12JSON::Schema::Modern::BEGIN@12
11113µs454µsJSON::Schema::Modern::::BEGIN@37JSON::Schema::Modern::BEGIN@37
11113µs29µsJSON::Schema::Modern::::BEGIN@793JSON::Schema::Modern::BEGIN@793
11113µs14µsOpenAPI::Modern::::BEGIN@1 OpenAPI::Modern::BEGIN@1
11112µs45µsJSON::Schema::Modern::::BEGIN@20JSON::Schema::Modern::BEGIN@20
11112µs120µsJSON::Schema::Modern::::BEGIN@46JSON::Schema::Modern::BEGIN@46
11112µs60µsJSON::Schema::Modern::::BEGIN@787JSON::Schema::Modern::BEGIN@787
151112µs12µsJSON::Schema::Modern::::METASCHEMA_URISJSON::Schema::Modern::METASCHEMA_URIS (xsub)
1119µs36µsJSON::Schema::Modern::::BEGIN@14JSON::Schema::Modern::BEGIN@14
1118µs8µsJSON::Schema::Modern::::BEGIN@10JSON::Schema::Modern::BEGIN@10
1118µs26µsJSON::Schema::Modern::::BEGIN@21JSON::Schema::Modern::BEGIN@21
1118µs80µsJSON::Schema::Modern::::BEGIN@24JSON::Schema::Modern::BEGIN@24
1118µs51µsJSON::Schema::Modern::::BEGIN@32JSON::Schema::Modern::BEGIN@32
1118µs37µsJSON::Schema::Modern::::BEGIN@47JSON::Schema::Modern::BEGIN@47
1118µs9µsJSON::Schema::Modern::::__ANON__[:90]JSON::Schema::Modern::__ANON__[:90]
1117µs177µsJSON::Schema::Modern::::BEGIN@11JSON::Schema::Modern::BEGIN@11
1117µs18µsJSON::Schema::Modern::::BEGIN@17JSON::Schema::Modern::BEGIN@17
1117µs10µsJSON::Schema::Modern::::__ANON__[:133]JSON::Schema::Modern::__ANON__[:133]
1116µs87µsJSON::Schema::Modern::::BEGIN@13JSON::Schema::Modern::BEGIN@13
1116µs18µsJSON::Schema::Modern::::BEGIN@15JSON::Schema::Modern::BEGIN@15
1116µs51µsJSON::Schema::Modern::::BEGIN@26JSON::Schema::Modern::BEGIN@26
1116µs47µsJSON::Schema::Modern::::__ANON__[:909]JSON::Schema::Modern::__ANON__[:909]
1115µs11µsJSON::Schema::Modern::::BEGIN@16JSON::Schema::Modern::BEGIN@16
1115µs17µsJSON::Schema::Modern::::BEGIN@19JSON::Schema::Modern::BEGIN@19
1115µs19µsOpenAPI::Modern::::BEGIN@2 OpenAPI::Modern::BEGIN@2
1114µs7µsJSON::Schema::Modern::::__ANON__[:69]JSON::Schema::Modern::__ANON__[:69]
1113µs12µsJSON::Schema::Modern::::BEGIN@22JSON::Schema::Modern::BEGIN@22
1112µs2µsJSON::Schema::Modern::::__ANON__[:649]JSON::Schema::Modern::__ANON__[:649]
1111µs1µsJSON::Schema::Modern::::__ANON__[:121]JSON::Schema::Modern::__ANON__[:121]
0000s0sJSON::Schema::Modern::::FREEZEJSON::Schema::Modern::FREEZE
1110s0sJSON::Schema::Modern::::SPECIFICATION_VERSION_DEFAULTJSON::Schema::Modern::SPECIFICATION_VERSION_DEFAULT (xsub)
0000s0sJSON::Schema::Modern::::THAWJSON::Schema::Modern::THAW
2210s0sJSON::Schema::Modern::::__ANON__JSON::Schema::Modern::__ANON__ (xsub)
0000s0sJSON::Schema::Modern::::__ANON__[:177]JSON::Schema::Modern::__ANON__[:177]
0000s0sJSON::Schema::Modern::::__ANON__[:53]JSON::Schema::Modern::__ANON__[:53]
0000s0sJSON::Schema::Modern::::__ANON__[:55]JSON::Schema::Modern::__ANON__[:55]
0000s0sJSON::Schema::Modern::::__ANON__[:56]JSON::Schema::Modern::__ANON__[:56]
0000s0sJSON::Schema::Modern::::__ANON__[:705]JSON::Schema::Modern::__ANON__[:705]
0000s0sJSON::Schema::Modern::::__ANON__[:872]JSON::Schema::Modern::__ANON__[:872]
0000s0sJSON::Schema::Modern::::__ANON__[:928]JSON::Schema::Modern::__ANON__[:928]
0000s0sJSON::Schema::Modern::::__ANON__[:932]JSON::Schema::Modern::__ANON__[:932]
0000s0sJSON::Schema::Modern::::__ANON__[:935]JSON::Schema::Modern::__ANON__[:935]
0000s0sJSON::Schema::Modern::::__ANON__[:943]JSON::Schema::Modern::__ANON__[:943]
0000s0sJSON::Schema::Modern::::__ANON__[:945]JSON::Schema::Modern::__ANON__[:945]
0000s0sJSON::Schema::Modern::::__ANON__[:947]JSON::Schema::Modern::__ANON__[:947]
0000s0sJSON::Schema::Modern::::__ANON__[:960]JSON::Schema::Modern::__ANON__[:960]
0000s0sJSON::Schema::Modern::::__ANON__[:965]JSON::Schema::Modern::__ANON__[:965]
0000s0sJSON::Schema::Modern::::__ANON__[:967]JSON::Schema::Modern::__ANON__[:967]
0000s0sJSON::Schema::Modern::::evaluate_json_stringJSON::Schema::Modern::evaluate_json_string
0000s0sJSON::Schema::Modern::::getJSON::Schema::Modern::get
0000s0sJSON::Schema::Modern::::validate_schemaJSON::Schema::Modern::validate_schema
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1217µs215µs
# spent 14µs (13+1) within OpenAPI::Modern::BEGIN@1 which was called: # once (13µs+1µs) by OpenAPI::Modern::BEGIN@26 at line 1
use strict;
# spent 14µs making 1 call to OpenAPI::Modern::BEGIN@1 # spent 1µs making 1 call to strict::import
2241µs233µs
# spent 19µs (5+14) within OpenAPI::Modern::BEGIN@2 which was called: # once (5µs+14µs) by OpenAPI::Modern::BEGIN@26 at line 2
use warnings;
# spent 19µs making 1 call to OpenAPI::Modern::BEGIN@2 # spent 14µs making 1 call to warnings::import
3package JSON::Schema::Modern;
4# vim: set ts=8 sts=2 sw=2 tw=100 et :
5# ABSTRACT: Validate data against a schema
6# KEYWORDS: JSON Schema validator data validation structure specification
7
811µsour $VERSION = '0.559';
9
10222µs18µs
# spent 8µs within JSON::Schema::Modern::BEGIN@10 which was called: # once (8µs+0s) by OpenAPI::Modern::BEGIN@26 at line 10
use 5.020; # for fc, unicode_strings features
# spent 8µs making 1 call to JSON::Schema::Modern::BEGIN@10
11221µs2347µs
# spent 177µs (7+170) within JSON::Schema::Modern::BEGIN@11 which was called: # once (7µs+170µs) by OpenAPI::Modern::BEGIN@26 at line 11
use Moo;
# spent 177µs making 1 call to JSON::Schema::Modern::BEGIN@11 # spent 170µs making 1 call to Moo::import
12325µs31.25ms
# spent 632µs (14+618) within JSON::Schema::Modern::BEGIN@12 which was called: # once (14µs+618µs) by OpenAPI::Modern::BEGIN@26 at line 12
use strictures 2;
# spent 632µs making 1 call to JSON::Schema::Modern::BEGIN@12 # spent 602µs making 1 call to strictures::import # spent 15µs making 1 call to strictures::VERSION
13227µs2168µs
# spent 87µs (6+81) within JSON::Schema::Modern::BEGIN@13 which was called: # once (6µs+81µs) by OpenAPI::Modern::BEGIN@26 at line 13
use experimental qw(signatures postderef);
# spent 87µs making 1 call to JSON::Schema::Modern::BEGIN@13 # spent 81µs making 1 call to experimental::import
14222µs244µs
# spent 36µs (9+27) within JSON::Schema::Modern::BEGIN@14 which was called: # once (9µs+27µs) by OpenAPI::Modern::BEGIN@26 at line 14
use if "$]" >= 5.022, experimental => 're_strict';
# spent 36µs making 1 call to JSON::Schema::Modern::BEGIN@14 # spent 8µs making 1 call to if::import
15216µs219µs
# spent 18µs (6+12) within JSON::Schema::Modern::BEGIN@15 which was called: # once (6µs+12µs) by OpenAPI::Modern::BEGIN@26 at line 15
no if "$]" >= 5.031009, feature => 'indirect';
# spent 18µs making 1 call to JSON::Schema::Modern::BEGIN@15 # spent 1µs making 1 call to if::unimport
16214µs213µs
# spent 11µs (5+6) within JSON::Schema::Modern::BEGIN@16 which was called: # once (5µs+6µs) by OpenAPI::Modern::BEGIN@26 at line 16
no if "$]" >= 5.033001, feature => 'multidimensional';
# spent 11µs making 1 call to JSON::Schema::Modern::BEGIN@16 # spent 2µs making 1 call to if::unimport
17215µs220µs
# spent 18µs (7+11) within JSON::Schema::Modern::BEGIN@17 which was called: # once (7µs+11µs) by OpenAPI::Modern::BEGIN@26 at line 17
no if "$]" >= 5.033006, feature => 'bareword_filehandles';
# spent 18µs making 1 call to JSON::Schema::Modern::BEGIN@17 # spent 2µs making 1 call to if::unimport
1821.22ms219.3ms
# spent 19.3ms (2.12+17.2) within JSON::Schema::Modern::BEGIN@18 which was called: # once (2.12ms+17.2ms) by OpenAPI::Modern::BEGIN@26 at line 18
use JSON::MaybeXS;
# spent 19.3ms making 1 call to JSON::Schema::Modern::BEGIN@18 # spent 24µs making 1 call to Exporter::import
19223µs229µs
# spent 17µs (5+12) within JSON::Schema::Modern::BEGIN@19 which was called: # once (5µs+12µs) by OpenAPI::Modern::BEGIN@26 at line 19
use Carp qw(croak carp);
# spent 17µs making 1 call to JSON::Schema::Modern::BEGIN@19 # spent 12µs making 1 call to Exporter::import
20329µs359µs
# spent 45µs (12+33) within JSON::Schema::Modern::BEGIN@20 which was called: # once (12µs+33µs) by OpenAPI::Modern::BEGIN@26 at line 20
use List::Util 1.55 qw(pairs first uniqint pairmap uniq any);
# spent 45µs making 1 call to JSON::Schema::Modern::BEGIN@20 # spent 8µs making 1 call to List::Util::import # spent 6µs making 1 call to UNIVERSAL::VERSION
21324µs344µs
# spent 26µs (8+18) within JSON::Schema::Modern::BEGIN@21 which was called: # once (8µs+18µs) by OpenAPI::Modern::BEGIN@26 at line 21
use Ref::Util 0.100 qw(is_ref is_plain_hashref);
# spent 26µs making 1 call to JSON::Schema::Modern::BEGIN@21 # spent 14µs making 1 call to Exporter::import # spent 4µs making 1 call to UNIVERSAL::VERSION
22212µs221µs
# spent 12µs (3+9) within JSON::Schema::Modern::BEGIN@22 which was called: # once (3µs+9µs) by OpenAPI::Modern::BEGIN@26 at line 22
use Scalar::Util 'refaddr';
# spent 12µs making 1 call to JSON::Schema::Modern::BEGIN@22 # spent 9µs making 1 call to Exporter::import
2321.65ms2181ms
# spent 181ms (3.07+178) within JSON::Schema::Modern::BEGIN@23 which was called: # once (3.07ms+178ms) by OpenAPI::Modern::BEGIN@26 at line 23
use Mojo::URL;
# spent 181ms making 1 call to JSON::Schema::Modern::BEGIN@23 # spent 3µs making 1 call to Mojo::Base::import
24219µs2152µs
# spent 80µs (8+72) within JSON::Schema::Modern::BEGIN@24 which was called: # once (8µs+72µs) by OpenAPI::Modern::BEGIN@26 at line 24
use Safe::Isa;
# spent 80µs making 1 call to JSON::Schema::Modern::BEGIN@24 # spent 72µs making 1 call to Exporter::import
2521.02ms212.7ms
# spent 12.7ms (9.56+3.14) within JSON::Schema::Modern::BEGIN@25 which was called: # once (9.56ms+3.14ms) by OpenAPI::Modern::BEGIN@26 at line 25
use Path::Tiny;
# spent 12.7ms making 1 call to JSON::Schema::Modern::BEGIN@25 # spent 23µs making 1 call to Exporter::import
26220µs296µs
# spent 51µs (6+45) within JSON::Schema::Modern::BEGIN@26 which was called: # once (6µs+45µs) by OpenAPI::Modern::BEGIN@26 at line 26
use Storable 'dclone';
# spent 51µs making 1 call to JSON::Schema::Modern::BEGIN@26 # spent 45µs making 1 call to Exporter::import
2721.53ms231.8ms
# spent 31.8ms (3.12+28.7) within JSON::Schema::Modern::BEGIN@27 which was called: # once (3.12ms+28.7ms) by OpenAPI::Modern::BEGIN@26 at line 27
use File::ShareDir 'dist_dir';
# spent 31.8ms making 1 call to JSON::Schema::Modern::BEGIN@27 # spent 22µs making 1 call to Exporter::import
2821.82ms23.18ms
# spent 3.17ms (3.04+124µs) within JSON::Schema::Modern::BEGIN@28 which was called: # once (3.04ms+124µs) by OpenAPI::Modern::BEGIN@26 at line 28
use Module::Runtime qw(use_module require_module);
# spent 3.17ms making 1 call to JSON::Schema::Modern::BEGIN@28 # spent 13µs making 1 call to Module::Runtime::import
2931.13ms39.95ms
# spent 5.65ms (1.26+4.39) within JSON::Schema::Modern::BEGIN@29 which was called: # once (1.26ms+4.39ms) by OpenAPI::Modern::BEGIN@26 at line 29
use MooX::TypeTiny 0.002002;
# spent 5.65ms making 1 call to JSON::Schema::Modern::BEGIN@29 # spent 4.30ms making 1 call to MooX::TypeTiny::import # spent 7µs making 1 call to UNIVERSAL::VERSION
3021.14ms21.85ms
# spent 1.77ms (1.56+201µs) within JSON::Schema::Modern::BEGIN@30 which was called: # once (1.56ms+201µs) by OpenAPI::Modern::BEGIN@26 at line 30
use MooX::HandlesVia;
# spent 1.77ms making 1 call to JSON::Schema::Modern::BEGIN@30 # spent 80µs making 1 call to MooX::HandlesVia::import
3131.33ms366.6ms
# spent 65.2ms (6.27+59.0) within JSON::Schema::Modern::BEGIN@31 which was called: # once (6.27ms+59.0ms) by OpenAPI::Modern::BEGIN@26 at line 31
use Types::Standard 1.016003 qw(Bool Int Str HasMethods Enum InstanceOf HashRef Dict CodeRef Optional Slurpy ArrayRef Undef ClassName Tuple Map);
# spent 65.2ms making 1 call to JSON::Schema::Modern::BEGIN@31 # spent 1.41ms making 1 call to Exporter::Tiny::import # spent 9µs making 1 call to UNIVERSAL::VERSION
32220µs294µs
# spent 51µs (8+43) within JSON::Schema::Modern::BEGIN@32 which was called: # once (8µs+43µs) by OpenAPI::Modern::BEGIN@26 at line 32
use Feature::Compat::Try;
# spent 51µs making 1 call to JSON::Schema::Modern::BEGIN@32 # spent 43µs making 1 call to Feature::Compat::Try::import
332546µs268.3ms
# spent 68.3ms (1.20+67.1) within JSON::Schema::Modern::BEGIN@33 which was called: # once (1.20ms+67.1ms) by OpenAPI::Modern::BEGIN@26 at line 33
use JSON::Schema::Modern::Error;
# spent 68.3ms making 1 call to JSON::Schema::Modern::BEGIN@33 # spent 0s making 1 call to JSON::Schema::Modern::__ANON__
342634µs228.0ms
# spent 28.0ms (2.25+25.8) within JSON::Schema::Modern::BEGIN@34 which was called: # once (2.25ms+25.8ms) by OpenAPI::Modern::BEGIN@26 at line 34
use JSON::Schema::Modern::Result;
# spent 28.0ms making 1 call to JSON::Schema::Modern::BEGIN@34 # spent 0s making 1 call to JSON::Schema::Modern::__ANON__
352367µs238.1ms
# spent 38.1ms (1.57+36.5) within JSON::Schema::Modern::BEGIN@35 which was called: # once (1.57ms+36.5ms) by OpenAPI::Modern::BEGIN@26 at line 35
use JSON::Schema::Modern::Document;
# spent 38.1ms making 1 call to JSON::Schema::Modern::BEGIN@35 # spent 4µs making 1 call to Mojo::Base::import
362583µs25.79ms
# spent 5.69ms (3.36+2.33) within JSON::Schema::Modern::BEGIN@36 which was called: # once (3.36ms+2.33ms) by OpenAPI::Modern::BEGIN@26 at line 36
use JSON::Schema::Modern::Utilities qw(get_type canonical_uri E abort annotate_self);
# spent 5.69ms making 1 call to JSON::Schema::Modern::BEGIN@36 # spent 104µs making 1 call to Exporter::import
37283µs2895µs
# spent 454µs (13+441) within JSON::Schema::Modern::BEGIN@37 which was called: # once (13µs+441µs) by OpenAPI::Modern::BEGIN@26 at line 37
use namespace::clean;
# spent 454µs making 1 call to JSON::Schema::Modern::BEGIN@37 # spent 441µs making 1 call to namespace::clean::import
38
3913µsour @CARP_NOT = qw(
40 JSON::Schema::Modern::Document
41 JSON::Schema::Modern::Vocabulary
42 JSON::Schema::Modern::Vocabulary::Applicator
43 OpenAPI::Modern
44);
45
46234µs2228µs
# spent 120µs (12+108) within JSON::Schema::Modern::BEGIN@46 which was called: # once (12µs+108µs) by OpenAPI::Modern::BEGIN@26 at line 46
use constant SPECIFICATION_VERSION_DEFAULT => 'draft2020-12';
# spent 120µs making 1 call to JSON::Schema::Modern::BEGIN@46 # spent 108µs making 1 call to constant::import
4723.84ms266µs
# spent 37µs (8+29) within JSON::Schema::Modern::BEGIN@47 which was called: # once (8µs+29µs) by OpenAPI::Modern::BEGIN@26 at line 47
use constant SPECIFICATION_VERSIONS_SUPPORTED => [qw(draft7 draft2019-09 draft2020-12)];
# spent 37µs making 1 call to JSON::Schema::Modern::BEGIN@47 # spent 29µs making 1 call to constant::import
48
49has specification_version => (
50 is => 'ro',
51 isa => Enum(SPECIFICATION_VERSIONS_SUPPORTED),
52 coerce => sub {
53 return $_[0] if any { $_[0] eq $_ } SPECIFICATION_VERSIONS_SUPPORTED->@*;
54 my $real = 'draft'.($_[0]//'');
55 (any { $real eq $_ } SPECIFICATION_VERSIONS_SUPPORTED->@*) ? $real : $_[0];
56 },
5717µs21.58ms);
# spent 895µs making 1 call to MooX::HandlesVia::has # spent 687µs making 1 call to Types::Standard::Enum
58
59116µs3428µshas output_format => (
# spent 324µs making 1 call to MooX::HandlesVia::has # spent 104µs making 1 call to Types::Standard::Enum # spent 0s making 1 call to JSON::Schema::Modern::Result::OUTPUT_FORMATS
60 is => 'ro',
61 isa => Enum(JSON::Schema::Modern::Result->OUTPUT_FORMATS),
62 default => 'basic',
63);
64
65has short_circuit => (
66 is => 'ro',
67 isa => Bool,
68 lazy => 1,
69154µs13µs
# spent 7µs (4+3) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:69] which was called: # once (4µs+3µs) by JSON::Schema::Modern::short_circuit at line 23 of (eval 316)[Sub/Quote.pm:3]
default => sub { $_[0]->output_format eq 'flag' && !$_[0]->collect_annotations },
# spent 3µs making 1 call to JSON::Schema::Modern::output_format
7014µs2618µs);
# spent 617µs making 1 call to MooX::HandlesVia::has # spent 1µs making 1 call to Types::Standard::Bool
71
7212µs2366µshas max_traversal_depth => (
# spent 365µs making 1 call to MooX::HandlesVia::has # spent 1µs making 1 call to Types::Standard::Int
73 is => 'ro',
74 isa => Int,
75 default => 50,
76);
77
7812µs2284µshas validate_formats => (
# spent 282µs making 1 call to MooX::HandlesVia::has # spent 2µs making 1 call to Types::Standard::Bool
79 is => 'ro',
80 isa => Bool,
81 default => 0, # as specified by https://json-schema.org/draft/<version>/schema#/$vocabulary
82);
83
84has validate_content_schemas => (
85 is => 'ro',
86 isa => Bool,
87 lazy => 1,
88 # defaults to false in latest versions, as specified by
89 # https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.8.2
9014µs11µs
# spent 9µs (8+1) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:90] which was called: # once (8µs+1µs) by JSON::Schema::Modern::validate_content_schemas at line 23 of (eval 319)[Sub/Quote.pm:3]
default => sub { ($_[0]->specification_version//'') eq 'draft7' },
# spent 1µs making 1 call to JSON::Schema::Modern::specification_version
9114µs2581µs);
# spent 581µs making 1 call to MooX::HandlesVia::has # spent 0s making 1 call to Types::Standard::Bool
92
9310s2363µshas collect_annotations => (
# spent 363µs making 1 call to MooX::HandlesVia::has # spent 0s making 1 call to Types::Standard::Bool
94 is => 'ro',
95 isa => Bool,
96);
97
9813µs2343µshas scalarref_booleans => (
# spent 341µs making 1 call to MooX::HandlesVia::has # spent 2µs making 1 call to Types::Standard::Bool
99 is => 'ro',
100 isa => Bool,
101);
102
10311µs2332µshas strict => (
# spent 332µs making 1 call to MooX::HandlesVia::has # spent 0s making 1 call to Types::Standard::Bool
104 is => 'ro',
105 isa => Bool,
106);
107
108has _format_validations => (
109 is => 'bare',
110 isa => my $format_type = Dict[
111 (map +($_ => Optional[CodeRef]), qw(date-time date time duration email idn-email hostname idn-hostname ipv4 ipv6 uri uri-reference iri iri-reference uuid uri-template json-pointer relative-json-pointer regex)),
112 Slurpy[HashRef[Dict[type => Enum[qw(null object array boolean string number integer)], sub => CodeRef]]],
113 ],
114 init_arg => 'format_validations',
115 handles_via => 'Hash',
116 handles => {
117 _get_format_validation => 'get',
118 add_format_validation => 'set',
119 },
120 lazy => 1,
12112µs
# spent 1µs within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:121] which was called: # once (1µs+0s) by JSON::Schema::Modern::_assert__format_validations at line 23 of (eval 329)[Sub/Quote.pm:3]
default => sub { {} },
122143µs4520.4ms);
# spent 8.88ms making 1 call to MooX::HandlesVia::has # spent 6.95ms making 2 calls to Types::Standard::Dict, avg 3.48ms/call # spent 2.32ms making 1 call to Types::Standard::Slurpy # spent 879µs making 1 call to Types::Standard::HashRef # spent 781µs making 19 calls to Types::Standard::Optional, avg 41µs/call # spent 614µs making 1 call to Types::Standard::Enum # spent 8µs making 20 calls to Types::Standard::CodeRef, avg 400ns/call
123
124550µs17810µs
# spent 730µs (64+666) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:124] which was called: # once (64µs+666µs) by JSON::Schema::Modern::add_format_validation at line 4 of (eval 331)[Class/Method/Modifiers.pm:148]
before add_format_validation => sub ($self, @kvs) { $format_type->({ @$_ }) foreach pairs @kvs };
# spent 610µs making 5 calls to Sub::Defer::__ANON__[Sub/Defer.pm:178], avg 122µs/call # spent 175µs making 1 call to Moo::before # spent 21µs making 10 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 2µs/call # spent 4µs making 1 call to List::Util::pairs
125
12641µs
# spent 10µs (7+3) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:133] which was called: # once (7µs+3µs) by JSON::Schema::Modern::__ANON__[(eval 333)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Class/Method/Modifiers.pm:89]:1] at line 1 of (eval 333)[Class/Method/Modifiers.pm:89]
around BUILDARGS => sub ($orig, $class, @args) {
12712µs13µs my $args = $class->$orig(@args);
# spent 3µs making 1 call to Moo::Object::BUILDARGS
128 croak 'output_format: strict_basic can only be used with specification_version: draft2019-09'
129 if ($args->{output_format}//'') eq 'strict_basic'
13011µs and ($args->{specification_version}//'') ne 'draft2019-09';
131
13212µs return $args;
13314µs1192µs};
# spent 192µs making 1 call to Moo::around
134
135
# spent 183ms (1.11+182) within JSON::Schema::Modern::add_schema which was called 9 times, avg 20.4ms/call: # 6 times (762µs+171ms) by JSON::Schema::Modern::Document::OpenAPI::_add_vocab_and_default_schemas at line 204 of JSON/Schema/Modern/Document/OpenAPI.pm, avg 28.6ms/call # 2 times (81µs+1.32ms) by JSON::Schema::Modern::Document::OpenAPI::_add_vocab_and_default_schemas at line 206 of JSON/Schema/Modern/Document/OpenAPI.pm, avg 698µs/call # once (263µs+10.2ms) by OpenAPI::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/OpenAPI/Modern.pm:79] at line 75 of OpenAPI/Modern.pm
sub add_schema {
13697µs croak 'insufficient arguments' if @_ < 2;
137913µs my $self = shift;
138
139 # TODO: resolve $uri against $self->base_uri
140953µs10606µs my $uri = !is_ref($_[0]) ? Mojo::URL->new(shift)
# spent 543µs making 9 calls to Mojo::URL::new, avg 60µs/call # spent 63µs making 1 call to Safe::Isa::__ANON__[Safe/Isa.pm:23]
141 : $_[0]->$_isa('Mojo::URL') ? shift : Mojo::URL->new;
142
14397µs94µs croak 'cannot add a schema with a uri with a fragment' if defined $uri->fragment;
# spent 4µs making 9 calls to Mojo::URL::fragment, avg 444ns/call
144
14599µs if (not @_) {
146 my $schema_info = $self->_fetch_from_uri($uri);
147 return if not $schema_info or not defined wantarray;
148 return $schema_info->{document};
149 }
150
151 # document BUILD will trigger $self->traverse($schema)
1529107µs21149ms my $document = $_[0]->$_isa('JSON::Schema::Modern::Document') ? shift
# spent 149ms making 6 calls to JSON::Schema::Modern::Document::new, avg 24.9ms/call # spent 82µs making 9 calls to Safe::Isa::__ANON__[Safe/Isa.pm:23], avg 9µs/call # spent 11µs making 6 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 2µs/call
153 : JSON::Schema::Modern::Document->new(
154 schema => shift,
155 $uri ? (canonical_uri => $uri) : (),
156 evaluator => $self, # used mainly for traversal during document construction
157 );
158
159948µs9254µs if ($document->has_errors) {
# spent 254µs making 9 calls to JSON::Schema::Modern::Document::has_errors, avg 28µs/call
160 my $result = JSON::Schema::Modern::Result->new(
161 output_format => $self->output_format,
162 valid => 0,
163 errors => [ $document->errors ],
164 exception => 1,
165 );
166 die $result;
167 }
168
1699333µs189235µs if (not grep refaddr($_->{document}) == refaddr($document), $self->_canonical_resources) {
# spent 189µs making 9 calls to JSON::Schema::Modern::_canonical_resources, avg 21µs/call # spent 46µs making 180 calls to Scalar::Util::refaddr, avg 256ns/call
17078.41ms358.61ms my $schema_content = $document->_serialized_schema
# spent 8.27ms making 7 calls to Cpanel::JSON::XS::encode, avg 1.18ms/call # spent 272µs making 14 calls to JSON::Schema::Modern::Document::_serialized_schema, avg 19µs/call # spent 48µs making 7 calls to JSON::Schema::Modern::_json_decoder, avg 7µs/call # spent 25µs making 7 calls to JSON::Schema::Modern::Document::schema, avg 4µs/call
171 // $document->_serialized_schema($self->_json_decoder->encode($document->schema));
172
1737178µs21495µs if (my $existing_doc = first {
# spent 296µs making 7 calls to List::Util::first, avg 42µs/call # spent 122µs making 7 calls to JSON::Schema::Modern::_canonical_resources, avg 17µs/call # spent 77µs making 7 calls to List::Util::uniqint, avg 11µs/call
17429183µs61190µs my $existing_content = $_->_serialized_schema
# spent 144µs making 8 calls to Cpanel::JSON::XS::encode, avg 18µs/call # spent 32µs making 37 calls to JSON::Schema::Modern::Document::_serialized_schema, avg 865ns/call # spent 7µs making 8 calls to JSON::Schema::Modern::Document::schema, avg 875ns/call # spent 7µs making 8 calls to JSON::Schema::Modern::_json_decoder, avg 875ns/call
175 // $_->_serialized_schema($self->_json_decoder->encode($_->schema));
1762920µs $existing_content eq $schema_content
177 } uniqint map $_->{document}, $self->_canonical_resources) {
178 # we already have this schema content in another document object.
179 $document = $existing_doc;
180 }
181 else {
1827692µs148.08ms $self->_add_resources(map +($_->[0] => +{ $_->[1]->%*, document => $document }),
# spent 7.96ms making 7 calls to JSON::Schema::Modern::_add_resources, avg 1.14ms/call # spent 121µs making 7 calls to JSON::Schema::Modern::Document::resource_pairs, avg 17µs/call
183 $document->resource_pairs);
184 }
185 }
186
187961µs91.17ms if ("$uri") {
# spent 1.17ms making 9 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 130µs/call
188829µs161.03ms my $resource = $document->_get_resource($document->canonical_uri);
# spent 1.01ms making 8 calls to JSON::Schema::Modern::Document::_get_resource, avg 127µs/call # spent 17µs making 8 calls to JSON::Schema::Modern::Document::canonical_uri, avg 2µs/call
189 $self->_add_resources($uri => {
190 path => '',
191 canonical_uri => $document->canonical_uri,
192 specification_version => $resource->{specification_version},
193 vocabularies => $resource->{vocabularies}, # reference, not copy
194 document => $document,
195 configs => $resource->{configs},
196850µs164.34ms });
# spent 4.33ms making 8 calls to JSON::Schema::Modern::_add_resources, avg 541µs/call # spent 12µs making 8 calls to JSON::Schema::Modern::Document::canonical_uri, avg 2µs/call
197 }
198
199952µs return $document;
200}
201
202sub evaluate_json_string ($self, $json_data, $schema, $config_override = {}) {
203 croak 'evaluate_json_string called in void context' if not defined wantarray;
204
205 my $data;
206 try {
207 $data = $self->_json_decoder->decode($json_data)
208 }
209 catch ($e) {
210 return JSON::Schema::Modern::Result->new(
211 output_format => $self->output_format,
212 valid => 0,
213 exception => 1,
214 errors => [
215 JSON::Schema::Modern::Error->new(
216 keyword => undef,
217 instance_location => '',
218 keyword_location => '',
219 error => $e,
220 )
221 ],
222 );
223 }
224
225 return $self->evaluate($data, $schema, $config_override);
226}
227
228# this is called whenever we need to walk a document for something.
229# for now it is just called when a ::Document object is created, to verify the integrity of the
230# schema structure, to identify the metaschema (via the $schema keyword), and to extract all
231# embedded resources via $id and $anchor keywords within.
232# Returns the internal $state object accumulated during the traversal.
2332964673µs
# spent 1.12s (24.2ms+1.09) within JSON::Schema::Modern::traverse which was called 741 times, avg 1.51ms/call: # 725 times (23.5ms+926ms) by JSON::Schema::Modern::Document::OpenAPI::_traverse_schema at line 218 of JSON/Schema/Modern/Document/OpenAPI.pm, avg 1.31ms/call # 14 times (563µs+167ms) by JSON::Schema::Modern::Document::traverse at line 178 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Document.pm, avg 12.0ms/call # once (28µs+2.28ms) by JSON::Schema::Modern::Document::OpenAPI::traverse at line 115 of JSON/Schema/Modern/Document/OpenAPI.pm # once (36µs+-36µs) by JSON::Schema::Modern::_get_metaschema_info at line 763
sub traverse ($self, $schema_reference, $config_override = {}) {
234 # Note: the starting position is not guaranteed to be at the root of the $document.
2357411.20ms741214ms my $initial_uri = Mojo::URL->new($config_override->{initial_schema_uri} // '');
# spent 214ms making 741 calls to Mojo::URL::new, avg 288µs/call
236741598µs my $initial_path = $config_override->{traversed_schema_path} // '';
2377412.22ms7411.75ms my $spec_version = $self->specification_version//SPECIFICATION_VERSION_DEFAULT;
# spent 1.75ms making 741 calls to JSON::Schema::Modern::specification_version, avg 2µs/call
238
239 my $state = {
240 depth => 0,
241 data_path => '', # this never changes since we don't have an instance yet
242 initial_schema_uri => $initial_uri, # the canonical URI as of the start of this method, or last $id
243 traversed_schema_path => $initial_path, # the accumulated traversal path as of the start, or last $id
244 schema_path => '', # the rest of the path, since the start of this method, or last $id
245 effective_base_uri => Mojo::URL->new(''),
246 errors => [],
247 identifiers => [],
248 configs => {},
249 callbacks => $config_override->{callbacks} // {},
2507415.08ms74156.6ms evaluator => $self,
# spent 56.6ms making 741 calls to Mojo::URL::new, avg 76µs/call
251 traverse => 1,
252 };
253
254741375µs try {
255 my $for_canonical_uri = Mojo::URL->new(
256 (is_plain_hashref($schema_reference) && exists $schema_reference->{'$id'}
257 ? Mojo::URL->new($schema_reference->{'$id'}) : undef)
2587411.47ms755156ms // $state->{initial_schema_uri});
# spent 156ms making 755 calls to Mojo::URL::new, avg 206µs/call
259741729µs756369µs $for_canonical_uri->fragment(undef) if not length $for_canonical_uri->fragment;
# spent 369µs making 756 calls to Mojo::URL::fragment, avg 488ns/call
260
261 # a subsequent "$schema" keyword can still change these values
262 $state->@{qw(spec_version vocabularies)} = $self->_get_metaschema_info(
2637414.61ms75690.3ms $config_override->{metaschema_uri} // $self->METASCHEMA_URIS->{$spec_version},
# spent 90.3ms making 741 calls to JSON::Schema::Modern::_get_metaschema_info, avg 122µs/call, recursion: max depth 1, sum of overlapping time 25µs # spent 12µs making 15 calls to JSON::Schema::Modern::METASCHEMA_URIS, avg 800ns/call
264 $for_canonical_uri,
265 );
266 }
267 catch ($e) {
268 if ($e->$_isa('JSON::Schema::Modern::Result')) {
269 push $state->{errors}->@*, $e->errors;
270 }
271 elsif ($e->$_isa('JSON::Schema::Modern::Error')) {
272 push $state->{errors}->@*, $e;
273 }
274 else {
275 ()= E({ %$state, exception => 1 }, 'EXCEPTION: '.$e);
276 }
277
278 return $state;
279 }
280
281741307µs try {
2827411.75ms741578ms $self->_traverse_subschema($schema_reference, $state);
# spent 578ms making 741 calls to JSON::Schema::Modern::_traverse_subschema, avg 780µs/call
283 }
284 catch ($e) {
285 if ($e->$_isa('JSON::Schema::Modern::Error')) {
286 # note: we should never be here, since traversal subs are no longer be fatal
287 push $state->{errors}->@*, $e;
288 }
289 else {
290 E({ %$state, exception => 1 }, 'EXCEPTION: '.$e);
291 }
292 }
293
294741391µs delete $state->{traverse};
2957412.46ms return $state;
296}
297
298# the actual runtime evaluation of the schema against input data.
29950s
# spent 64.6s (150ms+64.4) within JSON::Schema::Modern::evaluate which was called: # once (150ms+64.4s) by JSON::Schema::Modern::Document::OpenAPI::traverse at line 147 of JSON/Schema/Modern/Document/OpenAPI.pm
sub evaluate ($self, $data, $schema_reference, $config_override = {}) {
30011µs croak 'evaluate called in void context' if not defined wantarray;
301
30211µs my $initial_path = $config_override->{traversed_schema_path} // '';
30311µs173µs my $effective_base_uri = Mojo::URL->new($config_override->{effective_base_uri}//'');
# spent 73µs making 1 call to Mojo::URL::new
304
305 my $state = {
30614µs12µs data_path => $config_override->{data_path} // '',
# spent 2µs making 1 call to Mojo::URL::new
307 traversed_schema_path => $initial_path, # the accumulated path as of the start of evaluation, or last $id or $ref
308 initial_schema_uri => Mojo::URL->new, # the canonical URI as of the start of evaluation, or last $id or $ref
309 schema_path => '', # the rest of the path, since the start of evaluation, or last $id or $ref
310 effective_base_uri => $effective_base_uri, # resolve locations against this for errors and annotations
311 errors => [],
312 };
313
314 exists $config_override->{$_} and die $_.' not supported as a config override'
31511µs foreach qw(output_format specification_version);
316
31710s my $valid;
31810s try {
31910s my $schema_info;
320
32113µs18µs if (not is_ref($schema_reference) or $schema_reference->$_isa('Mojo::URL')) {
# spent 8µs making 1 call to Safe::Isa::__ANON__[Safe/Isa.pm:23]
32211µs1304µs $schema_info = $self->_fetch_from_uri($schema_reference);
# spent 304µs making 1 call to JSON::Schema::Modern::_fetch_from_uri
32311µs161µs $state->{initial_schema_uri} = Mojo::URL->new($config_override->{initial_schema_uri} // '');
# spent 61µs making 1 call to Mojo::URL::new
324 }
325 else {
326 # traverse is called via add_schema -> ::Document->new -> ::Document->BUILD
327 my $document = $self->add_schema('', $schema_reference);
328 my $base_resource = $document->_get_resource($document->canonical_uri)
329 || croak "couldn't get resource: document parse error";
330
331 $schema_info = {
332 schema => $document->schema,
333 document => $document,
334 document_path => '',
335 $base_resource->%{qw(canonical_uri specification_version vocabularies configs)},
336 };
337 }
338
33910s abort($state, 'EXCEPTION: unable to find resource %s', $schema_reference)
340 if not $schema_info;
341
342 $state = +{
343 %$state,
344 depth => 0,
345 initial_schema_uri => $schema_info->{canonical_uri}, # the canonical URI as of the start of evaluation, or last $id or $ref
346 document => $schema_info->{document}, # the ::Document object containing this schema
347 document_path => $schema_info->{document_path}, # the path within the document of this schema, as of the start of evaluation, or last $id or $ref
348 dynamic_scope => [ $schema_info->{canonical_uri} ],
349 annotations => [],
350 seen => {},
351 spec_version => $schema_info->{specification_version},
352 vocabularies => $schema_info->{vocabularies},
353 callbacks => $config_override->{callbacks} // {},
354 evaluator => $self,
355 $schema_info->{configs}->%*,
356 (map {
357727µs691µs my $val = $config_override->{$_} // $self->$_;
# spent 67µs making 1 call to JSON::Schema::Modern::short_circuit # spent 16µs making 1 call to JSON::Schema::Modern::validate_content_schemas # spent 3µs making 1 call to JSON::Schema::Modern::collect_annotations # spent 2µs making 1 call to JSON::Schema::Modern::scalarref_booleans # spent 2µs making 1 call to JSON::Schema::Modern::validate_formats # spent 1µs making 1 call to JSON::Schema::Modern::strict
35862µs defined $val ? ( $_ => $val ) : ()
359 } qw(validate_formats validate_content_schemas short_circuit collect_annotations scalarref_booleans strict)),
360 };
361
36211µs if ($state->{validate_formats}) {
363 $state->{vocabularies} = [
364 map s/^JSON::Schema::Modern::Vocabulary::Format\KAnnotation$/Assertion/r, $state->{vocabularies}->@*
365111µs76µs ];
# spent 6µs making 7 calls to JSON::Schema::Modern::CORE:subst, avg 857ns/call
36610s require JSON::Schema::Modern::Vocabulary::FormatAssertion;
367 }
368
369 # we're going to set collect_annotations during evaluation when we see an unevaluated* keyword,
370 # but after we pass to a new data scope we'll clear it again.. unless we've got the config set
371 # globally for the entire evaluation, so we store that value in a high bit.
37211µs $state->{collect_annotations} = ($state->{collect_annotations}//0) << 8;
373
374114µs164.4s $valid = $self->_eval_subschema($data, $schema_info->{schema}, $state);
# spent 64.4s making 1 call to JSON::Schema::Modern::_eval_subschema
375118µs warn 'result is false but there are no errors' if not $valid and not $state->{errors}->@*;
376 }
377 catch ($e) {
378 if ($e->$_isa('JSON::Schema::Modern::Result')) {
379 return $e;
380 }
381 elsif ($e->$_isa('JSON::Schema::Modern::Error')) {
382 push $state->{errors}->@*, $e;
383 }
384 else {
385 $valid = E({ %$state, exception => 1 }, 'EXCEPTION: '.$e);
386 }
387 }
388
389112µs die 'evaluate validity inconstent with error count' if $valid xor !$state->{errors}->@*;
390
391 return JSON::Schema::Modern::Result->new(
392 output_format => $self->output_format,
393 valid => $valid,
394 $valid
395 # strip annotations from result if user didn't explicitly ask for them
396 ? ($config_override->{collect_annotations} // $self->collect_annotations
397 ? (annotations => $state->{annotations}) : ())
3981149ms39.08ms : (errors => $state->{errors}),
# spent 9.04ms making 1 call to JSON::Schema::Modern::Result::new # spent 23µs making 1 call to JSON::Schema::Modern::collect_annotations # spent 14µs making 1 call to JSON::Schema::Modern::output_format
399 );
400}
401
402sub validate_schema ($self, $schema, $config_override = {}) {
403 croak 'validate_schema called in void context' if not defined wantarray;
404
405 my $metaschema_uri = is_plain_hashref($schema) && $schema->{'$schema'} ? $schema->{'$schema'}
406 : $self->METASCHEMA_URIS->{$self->specification_version // $self->SPECIFICATION_VERSION_DEFAULT};
407
408 return $self->evaluate($schema, $metaschema_uri, $config_override);
409}
410
411sub get ($self, $uri) {
412 my $schema_info = $self->_fetch_from_uri($uri);
413 return if not $schema_info;
414 my $subschema = is_ref($schema_info->{schema}) ? dclone($schema_info->{schema}) : $schema_info->{schema};
415 return wantarray ? ($subschema, $schema_info->{canonical_uri}) : $subschema;
416}
417
418# defined lower down:
419# sub add_vocabulary { ... }
420# sub add_encoding { ... }
421# sub add_media_type { ... }
422
423######## NO PUBLIC INTERFACES FOLLOW THIS POINT ########
424
425# current spec version => { keyword => undef, or arrayref of alternatives }
42619µsmy %removed_keywords = (
427 'draft7' => {
428 id => [ '$id' ],
429 },
430 'draft2019-09' => {
431 id => [ '$id' ],
432 definitions => [ '$defs' ],
433 dependencies => [ qw(dependentSchemas dependentRequired) ],
434 },
435 'draft2020-12' => {
436 id => [ '$id' ],
437 definitions => [ '$defs' ],
438 dependencies => [ qw(dependentSchemas dependentRequired) ],
439 '$recursiveAnchor' => [ '$dynamicAnchor' ],
440 '$recursiveRef' => [ '$dynamicRef' ],
441 additionalItems => [ 'items' ],
442 },
443);
444
445# {
446# $spec_version => {
447# $vocabulary_class => {
448# traverse => [ [ $keyword => $subref ], [ ... ] ],
449# evaluate => [ [ $keyword => $subref ], [ ... ] ],
450# }
451# }
452# }
453# If we could serialize coderefs, this could be an object attribute;
454# otherwise, we might as well persist this for the lifetime of the process.
45510sour $vocabulary_cache = {};
456
457113321.66ms
# spent 578ms (178+400) within JSON::Schema::Modern::_traverse_subschema which was called 2833 times, avg 204µs/call: # 1334 times (91.4ms+-91.4ms) by JSON::Schema::Modern::Vocabulary::traverse_object_schemas at line 55 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 741 times (57.4ms+521ms) by JSON::Schema::Modern::traverse at line 282, avg 780µs/call # 553 times (19.2ms+-19.2ms) by JSON::Schema::Modern::Vocabulary::traverse_subschema at line 34 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 199 times (10.1ms+-10.1ms) by JSON::Schema::Modern::Vocabulary::traverse_array_schemas at line 44 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 6 times (249µs+-249µs) by JSON::Schema::Modern::Vocabulary::traverse_property_schema at line 64 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 0s/call
sub _traverse_subschema ($self, $schema, $state) {
4582833951µs delete $state->{keyword};
459
460 return E($state, 'EXCEPTION: maximum traversal depth exceeded')
46128333.33ms28333.07ms if $state->{depth}++ > $self->max_traversal_depth;
# spent 3.07ms making 2833 calls to JSON::Schema::Modern::max_traversal_depth, avg 1µs/call
462
46328333.27ms28337.19ms my $schema_type = get_type($schema);
# spent 7.19ms making 2833 calls to JSON::Schema::Modern::Utilities::get_type, avg 3µs/call
46428331.23ms return 1 if $schema_type eq 'boolean';
465
4662463623µs return E($state, 'invalid schema type: %s', $schema_type) if $schema_type ne 'object';
467
46824631.01ms return 1 if not keys %$schema;
469
4702460406µs my $valid = 1;
47124607.70ms my %unknown_keywords = map +($_ => undef), keys %$schema;
472 # we must check the array length on every iteration because some keywords can change it!
47324609.21ms for (my $idx = 0; $idx <= $state->{vocabularies}->$#*; ++$idx) {
474192105.21ms my $vocabulary = $state->{vocabularies}[$idx];
475
476 # [ [ $keyword => $subref ], [ ... ] ]
477 my $keyword_list = $vocabulary_cache->{$state->{spec_version}}{$vocabulary}{traverse} //= [
478 map [ $_ => $vocabulary->can('_traverse_keyword_'.($_ =~ s/^\$//r)) ],
479 $vocabulary->keywords($state->{spec_version})
480192109.90ms130113µs ];
# spent 55µs making 61 calls to UNIVERSAL::can, avg 902ns/call # spent 24µs making 1 call to JSON::Schema::Modern::Vocabulary::Applicator::keywords # spent 13µs making 61 calls to JSON::Schema::Modern::CORE:subst, avg 213ns/call # spent 8µs making 1 call to JSON::Schema::Modern::Vocabulary::Unevaluated::keywords # spent 4µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::keywords # spent 3µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::keywords # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::keywords # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::FormatAnnotation::keywords # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::MetaData::keywords # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::OpenAPI::keywords
481
4821921021.9ms foreach my $keyword_tuple ($keyword_list->@*) {
48314818028.8ms my ($keyword, $sub) = $keyword_tuple->@*;
48414818022.4ms next if not exists $schema->{$keyword};
485
486 # keywords adjacent to $ref are not evaluated before draft2019-09
48743251.52ms next if $keyword ne '$ref' and exists $schema->{'$ref'} and $state->{spec_version} eq 'draft7';
488
48943251.14ms delete $unknown_keywords{$keyword};
49043251.19ms $state->{keyword} = $keyword;
491
49243256.03ms4325989ms if (not $sub->($vocabulary, $schema, $state)) {
# spent 335ms making 382 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_properties, avg 876µs/call, recursion: max depth 3, sum of overlapping time 53.0ms # spent 167ms making 704 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref, avg 237µs/call # spent 108ms making 96 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_items, avg 1.13ms/call, recursion: max depth 1, sum of overlapping time 3.94ms # spent 99.2ms making 12 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs, avg 8.27ms/call, recursion: max depth 1, sum of overlapping time 9.91ms # spent 67.0ms making 270 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_required, avg 248µs/call # spent 51.9ms making 1372 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_type, avg 38µs/call # spent 44.3ms making 22 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_allOf, avg 2.01ms/call # spent 35.0ms making 63 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_if, avg 556µs/call # spent 30.9ms making 130 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_additionalProperties, avg 238µs/call, recursion: max depth 1, sum of overlapping time 5.18ms # spent 24.8ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id, avg 1.77ms/call # spent 16.1ms making 63 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_then, avg 255µs/call # spent 13.0ms making 31 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_anyOf, avg 420µs/call, recursion: max depth 1, sum of overlapping time 155µs # spent 11.6ms making 21 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_oneOf, avg 553µs/call # spent 6.08ms making 3 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_contains, avg 2.03ms/call # spent 5.36ms making 154 calls to JSON::Schema::Modern::Vocabulary::Unevaluated::_traverse_keyword_unevaluatedProperties, avg 35µs/call # spent 4.66ms making 3 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_dependentSchemas, avg 1.55ms/call # spent 4.45ms making 22 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef, avg 202µs/call # spent 4.37ms making 11 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary, avg 397µs/call # spent 3.78ms making 69 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_pattern, avg 55µs/call # spent 3.75ms making 15 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema, avg 250µs/call # spent 3.54ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor, avg 253µs/call # spent 3.33ms making 14 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_propertyNames, avg 238µs/call # spent 3.19ms making 15 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_else, avg 213µs/call # spent 2.45ms making 125 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_readOnly, avg 20µs/call # spent 1.85ms making 112 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment, avg 17µs/call # spent 1.58ms making 96 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_description, avg 16µs/call # spent 1.50ms making 6 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_patternProperties, avg 249µs/call # spent 1.47ms making 14 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_not, avg 105µs/call # spent 1.10ms making 50 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minProperties, avg 22µs/call # spent 1.04ms making 21 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minimum, avg 49µs/call # spent 660µs making 50 calls to JSON::Schema::Modern::Vocabulary::FormatAnnotation::_traverse_keyword_format, avg 13µs/call # spent 637µs making 59 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_enum, avg 11µs/call # spent 544µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor # spent 408µs making 33 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_title, avg 12µs/call # spent 288µs making 14 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minItems, avg 21µs/call # spent 185µs making 8 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxLength, avg 23µs/call # spent 152µs making 8 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maximum, avg 19µs/call # spent 145µs making 11 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_deprecated, avg 13µs/call # spent 140µs making 8 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minLength, avg 18µs/call # spent 113µs making 92 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_const, avg 1µs/call # spent 99µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_dependentRequired # spent 94µs making 3 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_uniqueItems, avg 31µs/call # spent 90µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::_traverse_keyword_contentSchema # spent 83µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::_traverse_keyword_contentMediaType # spent 76µs making 3 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxProperties, avg 25µs/call # spent 68µs making 98 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_default, avg 694ns/call # spent 51µs making 2 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxContains, avg 26µs/call # spent 22µs making 5 calls to JSON::Schema::Modern::Vocabulary::OpenAPI::_traverse_keyword_externalDocs, avg 4µs/call # spent 14µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_exclusiveMinimum # spent 13µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxItems # spent 10µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minContains
493 die 'traverse returned false but we have no errors' if not $state->{errors}->@*;
494 $valid = 0;
495 next;
496 }
497
49843252.84ms if (my $callback = $state->{callbacks}{$keyword}) {
499 $callback->($schema, $state);
500 }
501 }
502 }
503
5042460788µs delete $state->{keyword};
505
50624603.50ms24603.32ms if ($self->strict and keys %unknown_keywords) {
# spent 3.32ms making 2460 calls to JSON::Schema::Modern::strict, avg 1µs/call
507 ()= E($state, 'unknown keyword%s found: %s', keys %unknown_keywords > 1 ? 's' : '',
508 join(', ', sort keys %unknown_keywords));
509 }
510
511 # check for previously-supported but now removed keywords
512246010.9ms24602.60ms foreach my $keyword (sort keys $removed_keywords{$state->{spec_version}}->%*) {
# spent 2.60ms making 2460 calls to JSON::Schema::Modern::CORE:sort, avg 1µs/call
513147601.68ms next if not exists $schema->{$keyword};
514 my $message ='no-longer-supported "'.$keyword.'" keyword present (at location "'
515 .canonical_uri($state).'")';
516 if (my $alternates = $removed_keywords{$state->{spec_version}}->{$keyword}) {
517 my @list = map '"'.$_.'"', @$alternates;
518 @list = ((map $_.',', @list[0..$#list-1]), $list[-1]) if @list > 2;
519 splice(@list, -1, 0, 'or') if @list > 1;
520 $message .= ': this should be rewritten as '.join(' ', @list);
521 }
522 carp $message;
523 }
524
52524604.69ms return $valid;
526}
527
52845388559.6ms
# spent 64.4s (8.56+55.8) within JSON::Schema::Modern::_eval_subschema which was called 90777 times, avg 709µs/call: # 49439 times (4.19s+-4.19s) by JSON::Schema::Modern::Vocabulary::eval at line 68 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 41337 times (4.36s+-4.36s) by JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri at line 95 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # once (2.66ms+64.4s) by JSON::Schema::Modern::evaluate at line 374
sub _eval_subschema ($self, $data, $schema, $state) {
5299077720.5ms croak '_eval_subschema called in void context' if not defined wantarray;
530
531 # callers created a new $state for us, so we do not propagate upwards changes to depth, traversed
532 # paths; but annotations, errors are arrayrefs so their contents will be shared
5339077778.1ms $state->{dynamic_scope} = [ ($state->{dynamic_scope}//[])->@* ];
534907772.05s1997092227ms delete $state->@{'keyword', grep /^_/, keys %$state};
# spent 227ms making 1997092 calls to JSON::Schema::Modern::CORE:match, avg 114ns/call
535
536 abort($state, 'EXCEPTION: maximum evaluation depth exceeded')
53790777137ms90777113ms if $state->{depth}++ > $self->max_traversal_depth;
# spent 113ms making 90777 calls to JSON::Schema::Modern::max_traversal_depth, avg 1µs/call
538
5399077797.7ms90777130ms my $schema_type = get_type($schema);
# spent 130ms making 90777 calls to JSON::Schema::Modern::Utilities::get_type, avg 1µs/call
5409077724.7ms return $schema || E($state, 'subschema is false') if $schema_type eq 'boolean';
541
542 # this should never happen, due to checks in traverse
5439077722.7ms abort($state, 'invalid schema type: %s', $schema_type) if $schema_type ne 'object';
544
5459077727.9ms return 1 if not keys %$schema;
546
547 # find all schema locations in effect at this data path + canonical_uri combination
548 # if any of them are absolute prefix of this schema location, we are in a loop.
5499077777.9ms907772.06s my $canonical_uri = canonical_uri($state);
# spent 2.06s making 90777 calls to JSON::Schema::Modern::Utilities::canonical_uri, avg 23µs/call
5509077739.6ms my $schema_location = $state->{traversed_schema_path}.$state->{schema_path};
551 abort($state, 'EXCEPTION: infinite loop detected (same location evaluated twice)')
552 if grep substr($schema_location, 0, length) eq $_,
55390777343ms907777.61s keys $state->{seen}{$state->{data_path}}{$canonical_uri}->%*;
# spent 7.61s making 90777 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 84µs/call
55490777266ms907776.63s $state->{seen}{$state->{data_path}}{$canonical_uri}{$schema_location}++;
# spent 6.63s making 90777 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 73µs/call
555
5569077722.7ms my $valid = 1;
55790777263ms my %unknown_keywords = map +($_ => undef), keys %$schema;
5589077731.7ms my $orig_annotations = $state->{annotations};
5599077728.0ms $state->{annotations} = [];
5609077714.5ms my @new_annotations;
561
562 # in order to collect annotations from applicator keywords only when needed, we twiddle the low
563 # bit if we see a local unevaluated* keyword, and clear it again as we move on to a new data path.
5649077762.8ms $state->{collect_annotations} |= 0+(exists $schema->{unevaluatedItems} || exists $schema->{unevaluatedProperties});
565
566 ALL_KEYWORDS:
5679077762.8ms foreach my $vocabulary ($state->{vocabularies}->@*) {
568 # [ [ $keyword => $subref|undef ], [ ... ] ]
569 my $keyword_list = $vocabulary_cache->{$state->{spec_version}}{$vocabulary}{evaluate} //= [
570 map [ $_ => $vocabulary->can('_eval_keyword_'.($_ =~ s/^\$//r)) ],
571 $vocabulary->keywords($state->{spec_version})
572631747350ms121162µs ];
# spent 104µs making 57 calls to UNIVERSAL::can, avg 2µs/call # spent 20µs making 1 call to JSON::Schema::Modern::Vocabulary::Applicator::keywords # spent 11µs making 57 calls to JSON::Schema::Modern::CORE:subst, avg 193ns/call # spent 7µs making 1 call to JSON::Schema::Modern::Vocabulary::Unevaluated::keywords # spent 7µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::keywords # spent 5µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::keywords # spent 3µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::keywords # spent 3µs making 1 call to JSON::Schema::Modern::Vocabulary::FormatAssertion::keywords # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::MetaData::keywords
573
574631747805ms foreach my $keyword_tuple ($keyword_list->@*) {
57551613671.02s my ($keyword, $sub) = $keyword_tuple->@*;
5765161367795ms next if not exists $schema->{$keyword};
577
578 # keywords adjacent to $ref are not evaluated before draft2019-09
57930499976.4ms next if $keyword ne '$ref' and exists $schema->{'$ref'} and $state->{spec_version} eq 'draft7';
580
58130499976.6ms delete $unknown_keywords{$keyword};
58230499973.5ms $state->{keyword} = $keyword;
583
58430499969.6ms if ($sub) {
58520054851.0ms my $error_count = $state->{errors}->@*;
586
587200548301ms200548393s if (not $sub->($vocabulary, $data, $schema, $state)) {
# spent 686s making 38781 calls to JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref, avg 17.7ms/call, recursion: max depth 31, sum of overlapping time 621s # spent 301s making 32177 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_properties, avg 9.36ms/call, recursion: max depth 11, sum of overlapping time 237s # spent 77.8s making 3368 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_patternProperties, avg 23.1ms/call, recursion: max depth 2, sum of overlapping time 23.7s # spent 51.5s making 3002 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_if, avg 17.1ms/call, recursion: max depth 1, sum of overlapping time 2.77s # spent 173s making 5941 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_allOf, avg 29.1ms/call, recursion: max depth 13, sum of overlapping time 126s # spent 92.1s making 2556 calls to JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef, avg 36.0ms/call, recursion: max depth 6, sum of overlapping time 48.1s # spent 71.3s making 971 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_additionalProperties, avg 73.4ms/call, recursion: max depth 4, sum of overlapping time 27.4s # spent 16.9s making 1739 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_items, avg 9.73ms/call, recursion: max depth 4, sum of overlapping time 1.48s # spent 3.22s making 304 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_dependentSchemas, avg 10.6ms/call # spent 2.60s making 1172 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_anyOf, avg 2.22ms/call # spent 1.97s making 25562 calls to JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id, avg 77µs/call # spent 781ms making 35279 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_type, avg 22µs/call # spent 440ms making 2220 calls to JSON::Schema::Modern::Vocabulary::FormatAssertion::_eval_keyword_format, avg 198µs/call # spent 395ms making 4781 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_required, avg 83µs/call # spent 353ms making 3742 calls to JSON::Schema::Modern::Vocabulary::Unevaluated::_eval_keyword_unevaluatedProperties, avg 94µs/call # spent 265ms making 627 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_propertyNames, avg 423µs/call # spent 250ms making 304 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_oneOf, avg 823µs/call # spent 239ms making 1203 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_const, avg 199µs/call # spent 215ms making 25560 calls to JSON::Schema::Modern::Vocabulary::MetaData::_eval_keyword_title, avg 8µs/call # spent 197ms making 1527 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_enum, avg 129µs/call # spent 74.5ms making 1388 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_uniqueItems, avg 54µs/call # spent 47.6ms making 1154 calls to JSON::Schema::Modern::Vocabulary::MetaData::_eval_keyword_default, avg 41µs/call # spent 39.5ms making 5114 calls to JSON::Schema::Modern::Vocabulary::MetaData::_eval_keyword_description, avg 8µs/call # spent 9.43ms making 1232 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_minItems, avg 8µs/call # spent 4.98ms making 261 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_pattern, avg 19µs/call # spent 3.54ms making 485 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_minProperties, avg 7µs/call # spent 1.93ms making 4 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_not, avg 481µs/call # spent 1.31ms making 79 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_minimum, avg 17µs/call # spent 123µs making 15 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_maxProperties, avg 8µs/call
588 warn 'result is false but there are no errors (keyword: '.$keyword.')'
58942622.35ms if $error_count == $state->{errors}->@*;
59042621.07ms $valid = 0;
591
59242622.28ms last ALL_KEYWORDS if $state->{short_circuit};
59333392.08ms next;
594 }
595 }
596
597300737169ms41271114ms if (my $callback = $state->{callbacks}{$keyword}) {
598 $callback->($data, $schema, $state);
599 }
600
601300737231ms push @new_annotations, $state->{annotations}->@[$#new_annotations+1 .. $state->{annotations}->$#*];
602 }
603 }
604
6059077743.7ms delete $state->{keyword};
606
6079077722.4ms if ($state->{strict} and keys %unknown_keywords) {
608 abort($state, 'unknown keyword%s found: %s', keys %unknown_keywords > 1 ? 's' : '',
609 join(', ', sort keys %unknown_keywords));
610 }
611
6129077737.1ms $state->{annotations} = $orig_annotations;
613
6149077734.9ms if ($valid) {
6158651538.5ms push $state->{annotations}->@*, @new_annotations;
61686515137ms4922450.1ms if ($state->{collect_annotations} and $state->{spec_version} !~ qr/^draft(7|2019-09)$/) {
# spent 17.4ms making 12306 calls to JSON::Schema::Modern::CORE:qr, avg 1µs/call # spent 15.5ms making 12306 calls to JSON::Schema::Modern::CORE:regcomp, avg 1µs/call # spent 14.8ms making 12306 calls to JSON::Schema::Modern::CORE:match, avg 1µs/call # spent 2.37ms making 12306 calls to JSON::Schema::Modern::CORE:sort, avg 193ns/call
617 annotate_self(+{ %$state, keyword => $_, _unknown => 1 }, $schema)
618 foreach sort keys %unknown_keywords;
619 }
620 }
621
62290777385ms return $valid;
623}
624
625has _resource_index => (
626 is => 'bare',
627 isa => HashRef[my $resource_type = Dict[
628 canonical_uri => InstanceOf['Mojo::URL'],
629 path => Str,
630 specification_version => my $spec_version_type = Enum(SPECIFICATION_VERSIONS_SUPPORTED),
631 document => InstanceOf['JSON::Schema::Modern::Document'],
632 # the vocabularies used when evaluating instance data against schema
633 vocabularies => ArrayRef[my $vocabulary_class_type = ClassName->where(q{$_->DOES('JSON::Schema::Modern::Vocabulary')})],
634 configs => HashRef,
635 Slurpy[HashRef[Undef]], # no other fields allowed
636 ]],
637 handles_via => 'Hash',
638 handles => {
639 _add_resources => 'set',
640 _get_resource => 'get',
641 _remove_resource => 'delete',
642 _resource_index => 'elements',
643 _resource_keys => 'keys',
644 _add_resources_unsafe => 'set',
645 _canonical_resources => 'values',
646 _resource_exists => 'exists',
647 },
648 lazy => 1,
64913µs
# spent 2µs within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:649] which was called: # once (2µs+0s) by JSON::Schema::Modern::_assert__resource_index at line 23 of (eval 348)[Sub/Quote.pm:3]
default => sub { {} },
650141µs1414.9ms);
# spent 7.29ms making 1 call to MooX::HandlesVia::has # spent 3.33ms making 3 calls to Types::Standard::HashRef, avg 1.11ms/call # spent 3.17ms making 1 call to Types::Standard::Dict # spent 463µs making 2 calls to Types::Standard::InstanceOf, avg 232µs/call # spent 371µs making 1 call to Types::Standard::ArrayRef # spent 134µs making 1 call to Type::Tiny::where # spent 55µs making 1 call to Types::Standard::Enum # spent 34µs making 1 call to Types::Standard::Slurpy # spent 2µs making 1 call to Types::Standard::Undef # spent 1µs making 1 call to Types::Standard::ClassName # spent 1µs making 1 call to Types::Standard::Str
651
652
# spent 11.6ms (704µs+10.9) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:685] which was called 15 times, avg 771µs/call: # 15 times (704µs+10.9ms) by JSON::Schema::Modern::__ANON__[(eval 350)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Class/Method/Modifiers.pm:89]:1] at line 1 of (eval 333)[Class/Method/Modifiers.pm:89], avg 771µs/call
around _add_resources => sub {
6531517µs my ($orig, $self) = (shift, shift);
654
655156µs my @resources;
65615176µs3083µs foreach my $pair (sort { $a->[0] cmp $b->[0] } pairs @_) {
# spent 49µs making 15 calls to List::Util::pairs, avg 3µs/call # spent 34µs making 15 calls to JSON::Schema::Modern::CORE:sort, avg 2µs/call
6572411µs my ($key, $value) = @$pair;
658
65924140µs725.58ms $resource_type->($value); # check type of hash value against Dict
# spent 3.15ms making 24 calls to Sub::Defer::__ANON__[Sub/Defer.pm:178], avg 131µs/call # spent 2.43ms making 48 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 51µs/call
660
66124111µs441.42ms if (my $existing = $self->_get_resource($key)) {
# spent 1.27ms making 24 calls to JSON::Schema::Modern::_get_resource, avg 53µs/call # spent 136µs making 2 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 68µs/call # spent 13µs making 18 calls to JSON::Schema::Modern::CACHED_METASCHEMAS, avg 722ns/call
662 # we allow overwriting canonical_uri = '' to allow for ad hoc evaluation of schemas that
663 # lack all identifiers altogether, but preserve other resources from the original document
664619µs6412µs if ($key ne '') {
# spent 412µs making 6 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 69µs/call
665 next if $existing->{path} eq $value->{path}
666 and $existing->{canonical_uri} eq $value->{canonical_uri}
667 and $existing->{specification_version} eq $value->{specification_version}
6686185µs24780µs and refaddr($existing->{document}) == refaddr($value->{document});
# spent 769µs making 12 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 64µs/call # spent 11µs making 12 calls to Scalar::Util::refaddr, avg 917ns/call
669 croak 'uri "'.$key.'" conflicts with an existing schema resource';
670 }
671 }
672 elsif ($self->CACHED_METASCHEMAS->{$key}) {
673 croak 'uri "'.$key.'" conflicts with an existing meta-schema resource';
674 }
675
6761848µs1830µs my $fragment = $value->{canonical_uri}->fragment;
# spent 30µs making 18 calls to Mojo::URL::fragment, avg 2µs/call
677 croak sprintf('canonical_uri cannot contain an empty fragment (%s)', $value->{canonical_uri})
678186µs if defined $fragment and $fragment eq '';
679
680 croak sprintf('canonical_uri cannot contain a plain-name fragment (%s)', $value->{canonical_uri})
6811834µs1810µs if ($fragment // '') =~ m{^[^/]};
# spent 10µs making 18 calls to JSON::Schema::Modern::CORE:match, avg 556ns/call
682
6831835µs18779µs $self->$orig($key, $value);
# spent 779µs making 18 calls to JSON::Schema::Modern::_add_resources, avg 43µs/call
684 }
68517µs1237µs};
# spent 237µs making 1 call to Moo::around
686
687# $vocabulary uri (not its $id!) => [ spec_version, class ]
688has _vocabulary_classes => (
689 is => 'bare',
690 isa => HashRef[
691 Tuple[
692 $spec_version_type,
693 $vocabulary_class_type,
694 ]
695 ],
696 handles_via => 'Hash',
697 handles => {
698 _get_vocabulary_class => 'get',
699 _set_vocabulary_class => 'set',
700 _get_vocabulary_values => 'values',
701 },
702 lazy => 1,
703
# spent 51.6ms (76µs+51.5) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:709] which was called: # once (76µs+51.5ms) by JSON::Schema::Modern::_assert__vocabulary_classes at line 23 of (eval 359)[Sub/Quote.pm:3]
default => sub {
704 +{
7053198µs2451.5ms map { my $class = $_; pairmap { $a => [ $b, $class ] } $class->vocabulary }
# spent 51.5ms making 8 calls to Module::Runtime::use_module, avg 6.43ms/call # spent 31µs making 8 calls to List::Util::pairmap, avg 4µs/call # spent 3µs making 1 call to JSON::Schema::Modern::Vocabulary::Applicator::vocabulary # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::FormatAssertion::vocabulary # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::Unevaluated::vocabulary # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::vocabulary # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::vocabulary # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::vocabulary # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::FormatAnnotation::vocabulary # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::MetaData::vocabulary
706 map use_module('JSON::Schema::Modern::Vocabulary::'.$_),
707 qw(Core Applicator Validation FormatAssertion FormatAnnotation Content MetaData Unevaluated)
708 }
709 },
710115µs38.13ms);
# spent 4.53ms making 1 call to Types::Standard::Tuple # spent 2.99ms making 1 call to MooX::HandlesVia::has # spent 608µs making 1 call to Types::Standard::HashRef
711
71230s
# spent 57.9ms (84µs+57.8) within JSON::Schema::Modern::add_vocabulary which was called: # once (84µs+57.8ms) by JSON::Schema::Modern::Document::OpenAPI::_add_vocab_and_default_schemas at line 182 of JSON/Schema/Modern/Document/OpenAPI.pm
sub add_vocabulary ($self, $classname) {
71315µs151.9ms return if grep $_->[1] eq $classname, $self->_get_vocabulary_values;
# spent 51.9ms making 1 call to JSON::Schema::Modern::_get_vocabulary_values
714
715114µs44.58ms $vocabulary_class_type->(use_module($classname));
# spent 3.29ms making 1 call to Module::Runtime::use_module # spent 952µs making 1 call to Sub::Defer::__ANON__[Sub/Defer.pm:178] # spent 331µs making 2 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 165µs/call
716
717 # uri => version, uri => version
718135µs223µs foreach my $pair (pairs $classname->vocabulary) {
# spent 22µs making 1 call to List::Util::pairs # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::OpenAPI::vocabulary
71914µs my ($uri_string, $spec_version) = @$pair;
720114µs51.46ms Str->where(q{my $uri = Mojo::URL->new($_); $uri->is_abs && !defined $uri->fragment})->($uri_string);
# spent 733µs making 1 call to Sub::Defer::__ANON__[Sub/Defer.pm:178] # spent 374µs making 1 call to Type::Tiny::where # spent 353µs making 2 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 176µs/call # spent 2µs making 1 call to Types::Standard::Str
721152µs4357µs $spec_version_type->($spec_version);
# spent 309µs making 1 call to Sub::Defer::__ANON__[Sub/Defer.pm:178] # spent 35µs making 1 call to Type::Tiny::DESTROY # spent 13µs making 2 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 7µs/call
72214µs149µs $self->_set_vocabulary_class($uri_string => [ $spec_version, $classname ])
# spent 49µs making 1 call to JSON::Schema::Modern::_set_vocabulary_class
723 }
724}
725
726# $schema uri => [ spec_version, [ vocab classes ] ].
727has _metaschema_vocabulary_classes => (
728 is => 'bare',
729 isa => HashRef[
730 Tuple[
731 $spec_version_type,
732 ArrayRef[$vocabulary_class_type],
733 ]
734 ],
735 handles_via => 'Hash',
736 handles => {
737 _get_metaschema_vocabulary_classes => 'get',
738 _set_metaschema_vocabulary_classes => 'set',
739 __all_metaschema_vocabulary_classes => 'values',
740 },
741 lazy => 1,
742
# spent 101µs (18+83) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:751] which was called: # once (18µs+83µs) by JSON::Schema::Modern::_assert__metaschema_vocabulary_classes at line 23 of (eval 364)[Sub/Quote.pm:3]
default => sub {
74318µs783µs my @modules = map use_module('JSON::Schema::Modern::Vocabulary::'.$_),
# spent 83µs making 7 calls to Module::Runtime::use_module, avg 12µs/call
744 qw(Core Applicator Validation FormatAnnotation Content MetaData Unevaluated);
745 +{
746 'https://json-schema.org/draft/2020-12/schema' => [ 'draft2020-12', [ @modules ] ],
74738µs do { pop @modules; () },
748 'https://json-schema.org/draft/2019-09/schema' => [ 'draft2019-09', \@modules ],
749 'http://json-schema.org/draft-07/schema#' => [ 'draft7', \@modules ],
750 },
751 },
752120µs46.01ms);
# spent 3.23ms making 1 call to MooX::HandlesVia::has # spent 1.89ms making 1 call to Types::Standard::Tuple # spent 795µs making 1 call to Types::Standard::HashRef # spent 97µs making 1 call to Types::Standard::ArrayRef
753
754# retrieves metaschema info either from cache or by parsing the schema for vocabularies
755# throws a JSON::Schema::Modern::Result on error
7562964698µs
# spent 90.3ms (4.09+86.2) within JSON::Schema::Modern::_get_metaschema_info which was called 741 times, avg 122µs/call: # 741 times (4.09ms+86.2ms) by JSON::Schema::Modern::traverse at line 263, avg 122µs/call
sub _get_metaschema_info ($self, $metaschema_uri, $for_canonical_uri) {
757 # check the cache
7587411.79ms74184.6ms my $metaschema_info = $self->_get_metaschema_vocabulary_classes($metaschema_uri);
# spent 84.6ms making 741 calls to JSON::Schema::Modern::_get_metaschema_vocabulary_classes, avg 114µs/call
7597411.78ms return @$metaschema_info if $metaschema_info;
760
761 # otherwise, fetch the metaschema and parse its $vocabulary keyword.
762 # we do this by traversing a baby schema with just the $schema keyword.
76314µs10s my $state = $self->traverse({ '$schema' => $metaschema_uri.'' });
# spent 1.66ms making 1 call to JSON::Schema::Modern::traverse, recursion: max depth 1, sum of overlapping time 1.66ms
764 die JSON::Schema::Modern::Result->new(
765 output_format => $self->output_format,
766 valid => JSON::PP::false,
767 errors => [
768 map {
769 my $e = $_;
770 # absolute location is undef iff the location = '/$schema'
771 my $absolute_location = $e->absolute_keyword_location // $for_canonical_uri;
772 JSON::Schema::Modern::Error->new(
773 keyword => $e->keyword eq '$schema' ? '' : $e->keyword,
774 instance_location => $e->instance_location,
775 keyword_location => ($for_canonical_uri->fragment//'').($e->keyword_location =~ s{^/\$schema\b}{}r),
776 length $absolute_location ? ( absolute_keyword_location => $absolute_location ) : (),
777 error => $e->error,
778 )
779 }
780 $state->{errors}->@* ],
781 exception => 1,
78211µs ) if $state->{errors}->@*;
78315µs return ($state->{spec_version}, $state->{vocabularies});
784}
785
786# used for determining a default '$schema' keyword where there is none
78711µs
# spent 60µs (12+48) within JSON::Schema::Modern::BEGIN@787 which was called: # once (12µs+48µs) by OpenAPI::Modern::BEGIN@26 at line 791
use constant METASCHEMA_URIS => {
788 'draft2020-12' => 'https://json-schema.org/draft/2020-12/schema',
789 'draft2019-09' => 'https://json-schema.org/draft/2019-09/schema',
790 'draft7' => 'http://json-schema.org/draft-07/schema#',
791195µs2108µs};
# spent 60µs making 1 call to JSON::Schema::Modern::BEGIN@787 # spent 48µs making 1 call to constant::import
792
79310s
# spent 29µs (13+16) within JSON::Schema::Modern::BEGIN@793 which was called: # once (13µs+16µs) by OpenAPI::Modern::BEGIN@26 at line 816
use constant CACHED_METASCHEMAS => {
794 'https://json-schema.org/draft/2020-12/meta/applicator' => 'draft2020-12/meta/applicator.json',
795 'https://json-schema.org/draft/2020-12/meta/content' => 'draft2020-12/meta/content.json',
796 'https://json-schema.org/draft/2020-12/meta/core' => 'draft2020-12/meta/core.json',
797 'https://json-schema.org/draft/2020-12/meta/format-annotation' => 'draft2020-12/meta/format-annotation.json',
798 'https://json-schema.org/draft/2020-12/meta/format-assertion' => 'draft2020-12/meta/format-assertion.json',
799 'https://json-schema.org/draft/2020-12/meta/meta-data' => 'draft2020-12/meta/meta-data.json',
800 'https://json-schema.org/draft/2020-12/meta/unevaluated' => 'draft2020-12/meta/unevaluated.json',
801 'https://json-schema.org/draft/2020-12/meta/validation' => 'draft2020-12/meta/validation.json',
802 'https://json-schema.org/draft/2020-12/output/schema' => 'draft2020-12/output/schema.json',
803 'https://json-schema.org/draft/2020-12/schema' => 'draft2020-12/schema.json',
804
805 'https://json-schema.org/draft/2019-09/meta/applicator' => 'draft2019-09/meta/applicator.json',
806 'https://json-schema.org/draft/2019-09/meta/content' => 'draft2019-09/meta/content.json',
807 'https://json-schema.org/draft/2019-09/meta/core' => 'draft2019-09/meta/core.json',
808 'https://json-schema.org/draft/2019-09/meta/format' => 'draft2019-09/meta/format.json',
809 'https://json-schema.org/draft/2019-09/meta/meta-data' => 'draft2019-09/meta/meta-data.json',
810 'https://json-schema.org/draft/2019-09/meta/validation' => 'draft2019-09/meta/validation.json',
811 'https://json-schema.org/draft/2019-09/output/schema' => 'draft2019-09/output/schema.json',
812 'https://json-schema.org/draft/2019-09/schema' => 'draft2019-09/schema.json',
813
814 # trailing # is omitted because we always cache documents by its canonical (fragmentless) URI
815 'http://json-schema.org/draft-07/schema' => 'draft7/schema.json',
8161980µs245µs};
# spent 29µs making 1 call to JSON::Schema::Modern::BEGIN@793 # spent 16µs making 1 call to constant::import
817
818# returns the same as _get_resource
81911634919.4ms
# spent 5.70s (151ms+5.55) within JSON::Schema::Modern::_get_or_load_resource which was called 38783 times, avg 147µs/call: # 38783 times (151ms+5.55s) by JSON::Schema::Modern::_fetch_from_uri at line 866, avg 147µs/call
sub _get_or_load_resource ($self, $uri) {
8203878370.9ms387835.49s my $resource = $self->_get_resource($uri);
# spent 5.49s making 38783 calls to JSON::Schema::Modern::_get_resource, avg 142µs/call
8213878358.1ms return $resource if $resource;
822
823874µs16867µs if (my $local_filename = $self->CACHED_METASCHEMAS->{$uri}) {
# spent 860µs making 8 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 108µs/call # spent 7µs making 8 calls to JSON::Schema::Modern::CACHED_METASCHEMAS, avg 875ns/call
824844µs161.82ms my $file = path(dist_dir('JSON-Schema-Modern'), $local_filename);
# spent 1.72ms making 8 calls to File::ShareDir::dist_dir, avg 216µs/call # spent 94µs making 8 calls to Path::Tiny::path, avg 12µs/call
8258316µs24311µs my $schema = $self->_json_decoder->decode($file->slurp_raw);
# spent 218µs making 8 calls to Cpanel::JSON::XS::decode, avg 27µs/call # spent 57µs making 8 calls to JSON::Schema::Modern::_json_decoder, avg 7µs/call # spent 36µs making 8 calls to Path::Tiny::slurp_raw, avg 4µs/call
826849µs843.6ms my $document = JSON::Schema::Modern::Document->new(schema => $schema, evaluator => $self);
# spent 43.6ms making 8 calls to JSON::Schema::Modern::Document::new, avg 5.45ms/call
827
828 # this should be caught by the try/catch in evaluate()
829817µs8241µs die JSON::Schema::Modern::Result->new(
# spent 241µs making 8 calls to JSON::Schema::Modern::Document::has_errors, avg 30µs/call
830 output_format => $self->output_format,
831 valid => 0,
832 errors => [ $document->errors ],
833 exception => 1,
834 ) if $document->has_errors;
835
836 # we have already performed the appropriate collision checks, so we bypass them here
837873µs16423µs $self->_add_resources_unsafe(
# spent 307µs making 8 calls to JSON::Schema::Modern::_add_resources_unsafe, avg 38µs/call # spent 116µs making 8 calls to JSON::Schema::Modern::Document::resource_pairs, avg 14µs/call
838 map +($_->[0] => +{ $_->[1]->%*, document => $document }),
839 $document->resource_pairs
840 );
841
842853µs81.22ms return $self->_get_resource($uri);
# spent 1.22ms making 8 calls to JSON::Schema::Modern::_get_resource, avg 153µs/call
843 }
844
845 # TODO:
846 # - load from network or disk
847
848 return;
849};
850
851# returns information necessary to use a schema found at a particular URI:
852# - a schema (which may not be at a document root)
853# - the canonical uri for that schema,
854# - the JSON::Schema::Modern::Document object that holds that schema
855# - the path relative to the document root for this schema
856# - the specification version that applies to this schema
857# - the vocabularies to use when considering schema keywords
858# - the config overrides to set when considering schema keywords
859# creates a Document and adds it to the resource index, if not already present.
86013935323.9ms
# spent 17.2s (1.82+15.4) within JSON::Schema::Modern::_fetch_from_uri which was called 46451 times, avg 371µs/call: # 41337 times (1.74s+14.4s) by JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri at line 72 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary.pm, avg 391µs/call # 2556 times (47.2ms+591ms) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 238 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary/Core.pm, avg 250µs/call # 2556 times (33.4ms+420ms) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 250 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary/Core.pm, avg 177µs/call # once (117µs+341µs) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema at line 133 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Vocabulary/Core.pm # once (36µs+268µs) by JSON::Schema::Modern::evaluate at line 322
sub _fetch_from_uri ($self, $uri) {
8614645115.6ms122µs $uri = Mojo::URL->new($uri) if not is_ref($uri);
# spent 22µs making 1 call to Mojo::URL::new
8624645139.5ms4645133.8ms my $fragment = $uri->fragment;
# spent 33.8ms making 46451 calls to Mojo::URL::fragment, avg 727ns/call
863
8644645158.9ms2088815.8ms if (not length($fragment) or $fragment =~ m{^/}) {
# spent 15.8ms making 20888 calls to JSON::Schema::Modern::CORE:match, avg 757ns/call
8653878356.9ms775661.79s my $base = $uri->clone->fragment(undef);
# spent 1.75s making 38783 calls to Mojo::URL::clone, avg 45µs/call # spent 35.7ms making 38783 calls to Mojo::URL::fragment, avg 921ns/call
8663878357.1ms387835.70s if (my $resource = $self->_get_or_load_resource($base)) {
# spent 5.70s making 38783 calls to JSON::Schema::Modern::_get_or_load_resource, avg 147µs/call
86738783104ms38783626ms my $subschema = $resource->{document}->get(my $document_path = $resource->{path}.($fragment//''));
# spent 626ms making 38783 calls to Mojo::JSON::Pointer::get, avg 16µs/call
8683878311.0ms return if not defined $subschema;
8693878314.1ms my $document = $resource->{document};
870 my $closest_resource = first { !length($_->[1]{path}) # document root
87138783176ms || length($document_path)
872 && $document_path =~ m{^\Q$_->[1]{path}\E(?:/|\z)} } # path is above present location
873 sort { length($b->[1]{path}) <=> length($a->[1]{path}) } # sort by length, descending
87438783517ms2933814.60s grep { not length Mojo::URL->new($_->[0])->fragment } # omit anchors
# spent 3.79s making 88516 calls to Mojo::URL::new, avg 43µs/call # spent 617ms making 38783 calls to JSON::Schema::Modern::Document::resource_pairs, avg 16µs/call # spent 92.0ms making 38783 calls to List::Util::first, avg 2µs/call # spent 52.9ms making 38783 calls to JSON::Schema::Modern::CORE:sort, avg 1µs/call # spent 50.4ms making 88516 calls to Mojo::URL::fragment, avg 570ns/call
875 $document->resource_pairs;
876
877 my $canonical_uri = $closest_resource->[1]{canonical_uri}->clone
87838783119ms775661.24s ->fragment(substr($document_path, length($closest_resource->[1]{path})));
# spent 1.18s making 38783 calls to Mojo::URL::clone, avg 30µs/call # spent 59.3ms making 38783 calls to Mojo::URL::fragment, avg 2µs/call
8793878351.0ms6434637.3ms $canonical_uri->fragment(undef) if not length($canonical_uri->fragment);
# spent 37.3ms making 64346 calls to Mojo::URL::fragment, avg 579ns/call
880 return {
881 schema => $subschema,
882 canonical_uri => $canonical_uri,
883 document => $document,
884 document_path => $document_path,
88538783329ms $resource->%{qw(specification_version vocabularies configs)}, # reference, not copy
886 };
887 }
888 }
889 else { # we are following a URI with a plain-name fragment
890766811.1ms76681.03s if (my $resource = $self->_get_resource($uri)) {
# spent 1.03s making 7668 calls to JSON::Schema::Modern::_get_resource, avg 134µs/call
891766813.7ms7668131ms my $subschema = $resource->{document}->get($resource->{path});
# spent 131ms making 7668 calls to Mojo::JSON::Pointer::get, avg 17µs/call
89276681.28ms return if not defined $subschema;
893 return {
894 schema => $subschema,
895 canonical_uri => $resource->{canonical_uri}->clone, # this is *not* the anchor-containing URI
896 document => $resource->{document},
897 document_path => $resource->{path},
898766844.1ms7668223ms $resource->%{qw(specification_version vocabularies configs)}, # reference, not copy
# spent 223ms making 7668 calls to Mojo::URL::clone, avg 29µs/call
899 };
900 }
901 }
902}
903
904# used for internal encoding as well (when caching serialized schemas)
905has _json_decoder => (
906 is => 'ro',
907 isa => HasMethods[qw(encode decode)],
908 lazy => 1,
90916µs141µs
# spent 47µs (6+41) within JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:909] which was called: # once (6µs+41µs) by JSON::Schema::Modern::_json_decoder at line 23 of (eval 366)[Sub/Quote.pm:3]
default => sub { JSON::MaybeXS->new(allow_nonref => 1, canonical => 1, utf8 => 1, allow_bignum => 1, convert_blessed => 1) },
# spent 41µs making 1 call to JSON::MaybeXS::new
910112µs23.19ms);
# spent 2.12ms making 1 call to Types::Standard::HasMethods # spent 1.07ms making 1 call to MooX::HandlesVia::has
911
912# since media types are case-insensitive, all type names must be foldcased on insertion.
913has _media_type => (
914 is => 'bare',
915 isa => my $media_type_type = Map[Str->where(q{$_ eq CORE::fc($_)}), CodeRef],
916 handles_via => 'Hash',
917 handles => {
918 get_media_type => 'get',
919 add_media_type => 'set',
920 _media_types => 'keys',
921 },
922 lazy => 1,
923 default => sub ($self) {
924 my $_json_media_type = sub ($content_ref) {
925 # utf-8 decoding is always done, as per the JSON spec.
926 # other charsets are not supported: see RFC8259 §11
927 \ JSON::MaybeXS->new(allow_nonref => 1, utf8 => 1)->decode($content_ref->$*);
928 };
929 +{
930 (map +($_ => $_json_media_type),
931 qw(application/json application/schema+json application/schema-instance+json)),
932 map +($_ => sub ($content_ref) { $content_ref }),
933 qw(text/* application/octet-stream),
934 };
935 },
936117µs56.11ms);
# spent 3.03ms making 1 call to MooX::HandlesVia::has # spent 2.92ms making 1 call to Types::Standard::Map # spent 157µs making 1 call to Type::Tiny::where # spent 2µs making 1 call to Types::Standard::Str # spent 1µs making 1 call to Types::Standard::CodeRef
937
938# get_media_type('TExT/bloop') will fall through to matching an entry for 'text/*' or '*/*'
939around get_media_type => sub ($orig, $self, $type) {
940 my $mt = $self->$orig(fc $type);
941 return $mt if $mt;
942
943 return $self->$orig((first { m{([^/]+)/\*$} && fc($type) =~ m{^\Q$1\E/[^/]+$} } $self->_media_types)
944 // '*/*');
94513µs1172µs};
# spent 172µs making 1 call to Moo::around
946
94712µs191µsbefore add_media_type => sub ($self, $type, $sub) { $media_type_type->({ $type => $sub }) };
# spent 91µs making 1 call to Moo::before
948
949has _encoding => (
950 is => 'bare',
951 isa => HashRef[CodeRef],
952 handles_via => 'Hash',
953 handles => {
954 get_encoding => 'get',
955 add_encoding => 'set',
956 },
957 lazy => 1,
958 default => sub ($self) {
959 +{
960 identity => sub ($content_ref) { $content_ref },
961 base64 => sub ($content_ref) {
962 die "invalid characters\n"
963 if $content_ref->$* =~ m{[^A-Za-z0-9+/=]} or $content_ref->$* =~ m{=(?=[^=])};
964 require MIME::Base64; \ MIME::Base64::decode($content_ref->$*);
965 },
966 };
967 },
96819µs32.18ms);
# spent 1.80ms making 1 call to MooX::HandlesVia::has # spent 377µs making 1 call to Types::Standard::HashRef # spent 2µs making 1 call to Types::Standard::CodeRef
969
970# callback hook for Sereal::Encode
971sub FREEZE ($self, $serializer) {
972 my $data = +{ %$self };
973 # Cpanel::JSON::XS doesn't serialize: https://github.com/Sereal/Sereal/issues/266
974 # coderefs can't serialize cleanly and must be re-added by the user.
975 delete $data->@{qw(_json_decoder _format_validations _media_type _encoding)};
976 return $data;
977}
978
979# callback hook for Sereal::Decode
980sub THAW ($class, $serializer, $data) {
981 my $self = bless($data, $class);
982
983 # load all vocabulary classes
984 require_module($_) foreach uniq map $_->{vocabularies}->@*, $self->_canonical_resources;
985
986 return $self;
987}
988
9891105µs1;
9901115µs11.35ms__END__
 
# spent 20µs within JSON::Schema::Modern::CACHED_METASCHEMAS which was called 26 times, avg 769ns/call: # 18 times (13µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:685] at line 661, avg 722ns/call # 8 times (7µs+0s) by JSON::Schema::Modern::_get_or_load_resource at line 823, avg 875ns/call
sub JSON::Schema::Modern::CACHED_METASCHEMAS; # xsub
# spent 257ms within JSON::Schema::Modern::CORE:match which was called 2030304 times, avg 127ns/call: # 1997092 times (227ms+0s) by JSON::Schema::Modern::_eval_subschema at line 534, avg 114ns/call # 20888 times (15.8ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 864, avg 757ns/call # 12306 times (14.8ms+0s) by JSON::Schema::Modern::_eval_subschema at line 616, avg 1µs/call # 18 times (10µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:685] at line 681, avg 556ns/call
sub JSON::Schema::Modern::CORE:match; # opcode
# spent 17.4ms within JSON::Schema::Modern::CORE:qr which was called 12306 times, avg 1µs/call: # 12306 times (17.4ms+0s) by JSON::Schema::Modern::_eval_subschema at line 616, avg 1µs/call
sub JSON::Schema::Modern::CORE:qr; # opcode
# spent 15.5ms within JSON::Schema::Modern::CORE:regcomp which was called 12306 times, avg 1µs/call: # 12306 times (15.5ms+0s) by JSON::Schema::Modern::_eval_subschema at line 616, avg 1µs/call
sub JSON::Schema::Modern::CORE:regcomp; # opcode
# spent 57.9ms within JSON::Schema::Modern::CORE:sort which was called 53564 times, avg 1µs/call: # 38783 times (52.9ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 874, avg 1µs/call # 12306 times (2.37ms+0s) by JSON::Schema::Modern::_eval_subschema at line 616, avg 193ns/call # 2460 times (2.60ms+0s) by JSON::Schema::Modern::_traverse_subschema at line 512, avg 1µs/call # 15 times (34µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm:685] at line 656, avg 2µs/call
sub JSON::Schema::Modern::CORE:sort; # opcode
# spent 30µs within JSON::Schema::Modern::CORE:subst which was called 125 times, avg 240ns/call: # 61 times (13µs+0s) by JSON::Schema::Modern::_traverse_subschema at line 480, avg 213ns/call # 57 times (11µs+0s) by JSON::Schema::Modern::_eval_subschema at line 572, avg 193ns/call # 7 times (6µs+0s) by JSON::Schema::Modern::evaluate at line 365, avg 857ns/call
sub JSON::Schema::Modern::CORE:subst; # opcode
# spent 12µs within JSON::Schema::Modern::METASCHEMA_URIS which was called 15 times, avg 800ns/call: # 15 times (12µs+0s) by JSON::Schema::Modern::traverse at line 263, avg 800ns/call
sub JSON::Schema::Modern::METASCHEMA_URIS; # xsub
# spent 0s within JSON::Schema::Modern::SPECIFICATION_VERSION_DEFAULT which was called: # once (0s+0s) by JSON::Schema::Modern::Document::OpenAPI::traverse at line 76 of JSON/Schema/Modern/Document/OpenAPI.pm
sub JSON::Schema::Modern::SPECIFICATION_VERSION_DEFAULT; # xsub
# spent 0s within JSON::Schema::Modern::__ANON__ which was called 2 times, avg 0s/call: # once (0s+0s) by JSON::Schema::Modern::BEGIN@33 at line 33 # once (0s+0s) by JSON::Schema::Modern::BEGIN@34 at line 34
sub JSON::Schema::Modern::__ANON__; # xsub