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

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm
StatementsExecuted 18081506 statements in 15.0s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
915953211.8s99.6sJSON::Schema::Modern::::_eval_subschemaJSON::Schema::Modern::_eval_subschema (recurses: max depth 74, inclusive time 2294s)
46881532.44s21.5sJSON::Schema::Modern::::_fetch_from_uriJSON::Schema::Modern::_fetch_from_uri
212343441389ms389msJSON::Schema::Modern::::CORE:matchJSON::Schema::Modern::CORE:match (opcode)
111327ms99.9sJSON::Schema::Modern::::evaluateJSON::Schema::Modern::evaluate
286352204ms685msJSON::Schema::Modern::::_traverse_subschemaJSON::Schema::Modern::_traverse_subschema (recurses: max depth 6, inclusive time 702ms)
3912311200ms7.07sJSON::Schema::Modern::::_get_or_load_resourceJSON::Schema::Modern::_get_or_load_resource
8731111124ms124msJSON::Schema::Modern::::CORE:qrJSON::Schema::Modern::CORE:qr (opcode)
8731111116ms116msJSON::Schema::Modern::::CORE:regcompJSON::Schema::Modern::CORE:regcomp (opcode)
1289374196.6ms96.6msJSON::Schema::Modern::::CORE:sortJSON::Schema::Modern::CORE:sort (opcode)
7434334.2ms1.47sJSON::Schema::Modern::::traverseJSON::Schema::Modern::traverse (recurses: max depth 1, inclusive time 2.72ms)
1119.64ms85.9msJSON::Schema::Modern::::BEGIN@31JSON::Schema::Modern::BEGIN@31
1118.37ms11.5msJSON::Schema::Modern::::BEGIN@25JSON::Schema::Modern::BEGIN@25
743117.91ms129msJSON::Schema::Modern::::_get_metaschema_infoJSON::Schema::Modern::_get_metaschema_info (recurses: max depth 1, inclusive time 53µs)
1114.74ms7.74msJSON::Schema::Modern::::BEGIN@36JSON::Schema::Modern::BEGIN@36
1112.99ms55.2msJSON::Schema::Modern::::BEGIN@35JSON::Schema::Modern::BEGIN@35
1112.59ms36.9msJSON::Schema::Modern::::BEGIN@34JSON::Schema::Modern::BEGIN@34
1112.56ms2.77msJSON::Schema::Modern::::BEGIN@28JSON::Schema::Modern::BEGIN@28
1112.51ms29.8msJSON::Schema::Modern::::BEGIN@27JSON::Schema::Modern::BEGIN@27
1112.31ms166msJSON::Schema::Modern::::BEGIN@23JSON::Schema::Modern::BEGIN@23
1111.68ms66.8msJSON::Schema::Modern::::BEGIN@33JSON::Schema::Modern::BEGIN@33
1111.38ms10.1msJSON::Schema::Modern::::BEGIN@18JSON::Schema::Modern::BEGIN@18
9321.16ms159msJSON::Schema::Modern::::add_schemaJSON::Schema::Modern::add_schema
1111.13ms1.37msJSON::Schema::Modern::::BEGIN@30JSON::Schema::Modern::BEGIN@30
111636µs4.68msJSON::Schema::Modern::::BEGIN@29JSON::Schema::Modern::BEGIN@29
1511557µs12.0msJSON::Schema::Modern::::__ANON__[:672]JSON::Schema::Modern::__ANON__[:672]
111122µs66.5msJSON::Schema::Modern::::add_vocabularyJSON::Schema::Modern::add_vocabulary
11176µs60.3msJSON::Schema::Modern::::__ANON__[:696]JSON::Schema::Modern::__ANON__[:696]
11155µs104µsJSON::Schema::Modern::::BEGIN@32JSON::Schema::Modern::BEGIN@32
11146µs196µsJSON::Schema::Modern::::__ANON__[:738]JSON::Schema::Modern::__ANON__[:738]
1263132µs32µsJSON::Schema::Modern::::CORE:substJSON::Schema::Modern::CORE:subst (opcode)
11124µs735µsJSON::Schema::Modern::::__ANON__[:124]JSON::Schema::Modern::__ANON__[:124]
11121µs607µsJSON::Schema::Modern::::BEGIN@12JSON::Schema::Modern::BEGIN@12
11121µs93µsJSON::Schema::Modern::::BEGIN@20JSON::Schema::Modern::BEGIN@20
11120µs22µsOpenAPI::Modern::::BEGIN@1 OpenAPI::Modern::BEGIN@1
11119µs93µsJSON::Schema::Modern::::BEGIN@774JSON::Schema::Modern::BEGIN@774
11118µs51µsJSON::Schema::Modern::::BEGIN@780JSON::Schema::Modern::BEGIN@780
11117µs151µsJSON::Schema::Modern::::BEGIN@13JSON::Schema::Modern::BEGIN@13
11116µs48µsJSON::Schema::Modern::::BEGIN@21JSON::Schema::Modern::BEGIN@21
262116µs16µsJSON::Schema::Modern::::CACHED_METASCHEMASJSON::Schema::Modern::CACHED_METASCHEMAS (xsub)
11114µs47µsJSON::Schema::Modern::::BEGIN@14JSON::Schema::Modern::BEGIN@14
11112µs943µsJSON::Schema::Modern::::BEGIN@37JSON::Schema::Modern::BEGIN@37
11111µs98µsJSON::Schema::Modern::::BEGIN@46JSON::Schema::Modern::BEGIN@46
151111µs11µsJSON::Schema::Modern::::METASCHEMA_URISJSON::Schema::Modern::METASCHEMA_URIS (xsub)
11110µs31µsJSON::Schema::Modern::::BEGIN@15JSON::Schema::Modern::BEGIN@15
11110µs40µsJSON::Schema::Modern::::BEGIN@19JSON::Schema::Modern::BEGIN@19
1119µs24µsJSON::Schema::Modern::::BEGIN@22JSON::Schema::Modern::BEGIN@22
1119µs84µsJSON::Schema::Modern::::BEGIN@24JSON::Schema::Modern::BEGIN@24
1118µs8µsJSON::Schema::Modern::::BEGIN@10JSON::Schema::Modern::BEGIN@10
1118µs18µsJSON::Schema::Modern::::BEGIN@16JSON::Schema::Modern::BEGIN@16
1118µs54µsJSON::Schema::Modern::::BEGIN@26JSON::Schema::Modern::BEGIN@26
1118µs39µsJSON::Schema::Modern::::BEGIN@47JSON::Schema::Modern::BEGIN@47
1118µs12µsJSON::Schema::Modern::::__ANON__[:133]JSON::Schema::Modern::__ANON__[:133]
1117µs10µsJSON::Schema::Modern::::__ANON__[:90]JSON::Schema::Modern::__ANON__[:90]
1116µs8µsJSON::Schema::Modern::::__ANON__[:69]JSON::Schema::Modern::__ANON__[:69]
1116µs45µsJSON::Schema::Modern::::__ANON__[:896]JSON::Schema::Modern::__ANON__[:896]
1115µs185µsJSON::Schema::Modern::::BEGIN@11JSON::Schema::Modern::BEGIN@11
1115µs16µsJSON::Schema::Modern::::BEGIN@17JSON::Schema::Modern::BEGIN@17
1115µs24µsOpenAPI::Modern::::BEGIN@2 OpenAPI::Modern::BEGIN@2
1113µs3µsJSON::Schema::Modern::::__ANON__[:636]JSON::Schema::Modern::__ANON__[:636]
1111µs1µsJSON::Schema::Modern::::SPECIFICATION_VERSION_DEFAULTJSON::Schema::Modern::SPECIFICATION_VERSION_DEFAULT (xsub)
2211µs1µsJSON::Schema::Modern::::__ANON__JSON::Schema::Modern::__ANON__ (xsub)
1111µs1µsJSON::Schema::Modern::::__ANON__[:121]JSON::Schema::Modern::__ANON__[:121]
0000s0sJSON::Schema::Modern::::FREEZEJSON::Schema::Modern::FREEZE
0000s0sJSON::Schema::Modern::::THAWJSON::Schema::Modern::THAW
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__[:692]JSON::Schema::Modern::__ANON__[:692]
0000s0sJSON::Schema::Modern::::__ANON__[:859]JSON::Schema::Modern::__ANON__[:859]
0000s0sJSON::Schema::Modern::::__ANON__[:913]JSON::Schema::Modern::__ANON__[:913]
0000s0sJSON::Schema::Modern::::__ANON__[:919]JSON::Schema::Modern::__ANON__[:919]
0000s0sJSON::Schema::Modern::::__ANON__[:922]JSON::Schema::Modern::__ANON__[:922]
0000s0sJSON::Schema::Modern::::__ANON__[:931]JSON::Schema::Modern::__ANON__[:931]
0000s0sJSON::Schema::Modern::::__ANON__[:933]JSON::Schema::Modern::__ANON__[:933]
0000s0sJSON::Schema::Modern::::__ANON__[:935]JSON::Schema::Modern::__ANON__[:935]
0000s0sJSON::Schema::Modern::::__ANON__[:948]JSON::Schema::Modern::__ANON__[:948]
0000s0sJSON::Schema::Modern::::__ANON__[:953]JSON::Schema::Modern::__ANON__[:953]
0000s0sJSON::Schema::Modern::::__ANON__[:955]JSON::Schema::Modern::__ANON__[:955]
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
1222µs224µs
# spent 22µs (20+2) within OpenAPI::Modern::BEGIN@1 which was called: # once (20µs+2µs) by OpenAPI::Modern::BEGIN@26 at line 1
use strict;
# spent 22µs making 1 call to OpenAPI::Modern::BEGIN@1 # spent 2µs making 1 call to strict::import
2240µs243µs
# spent 24µs (5+19) within OpenAPI::Modern::BEGIN@2 which was called: # once (5µs+19µs) by OpenAPI::Modern::BEGIN@26 at line 2
use warnings;
# spent 24µs making 1 call to OpenAPI::Modern::BEGIN@2 # spent 19µs making 1 call to warnings::import
3package JSON::Schema::Modern; # git description: v0.555-12-g5cd1dee9
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.556';
9
10227µ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
11225µs2365µs
# spent 185µs (5+180) within JSON::Schema::Modern::BEGIN@11 which was called: # once (5µs+180µs) by OpenAPI::Modern::BEGIN@26 at line 11
use Moo;
# spent 185µs making 1 call to JSON::Schema::Modern::BEGIN@11 # spent 180µs making 1 call to Moo::import
12341µs31.19ms
# spent 607µs (21+586) within JSON::Schema::Modern::BEGIN@12 which was called: # once (21µs+586µs) by OpenAPI::Modern::BEGIN@26 at line 12
use strictures 2;
# spent 607µs making 1 call to JSON::Schema::Modern::BEGIN@12 # spent 572µs making 1 call to strictures::import # spent 14µs making 1 call to strictures::VERSION
13260µs2285µs
# spent 151µs (17+134) within JSON::Schema::Modern::BEGIN@13 which was called: # once (17µs+134µs) by OpenAPI::Modern::BEGIN@26 at line 13
use experimental qw(signatures postderef);
# spent 151µs making 1 call to JSON::Schema::Modern::BEGIN@13 # spent 134µs making 1 call to experimental::import
14230µs250µs
# spent 47µs (14+33) within JSON::Schema::Modern::BEGIN@14 which was called: # once (14µs+33µs) by OpenAPI::Modern::BEGIN@26 at line 14
use if "$]" >= 5.022, experimental => 're_strict';
# spent 47µs making 1 call to JSON::Schema::Modern::BEGIN@14 # spent 3µs making 1 call to if::import
15220µs238µs
# spent 31µs (10+21) within JSON::Schema::Modern::BEGIN@15 which was called: # once (10µs+21µs) by OpenAPI::Modern::BEGIN@26 at line 15
no if "$]" >= 5.031009, feature => 'indirect';
# spent 31µs making 1 call to JSON::Schema::Modern::BEGIN@15 # spent 7µs making 1 call to if::unimport
16216µs218µs
# spent 18µs (8+10) within JSON::Schema::Modern::BEGIN@16 which was called: # once (8µs+10µs) by OpenAPI::Modern::BEGIN@26 at line 16
no if "$]" >= 5.033001, feature => 'multidimensional';
# spent 18µs making 1 call to JSON::Schema::Modern::BEGIN@16 # spent 0s making 1 call to if::unimport
17213µs218µs
# spent 16µs (5+11) within JSON::Schema::Modern::BEGIN@17 which was called: # once (5µs+11µs) by OpenAPI::Modern::BEGIN@26 at line 17
no if "$]" >= 5.033006, feature => 'bareword_filehandles';
# spent 16µs making 1 call to JSON::Schema::Modern::BEGIN@17 # spent 2µs making 1 call to if::unimport
182265µs210.2ms
# spent 10.1ms (1.38+8.75) within JSON::Schema::Modern::BEGIN@18 which was called: # once (1.38ms+8.75ms) by OpenAPI::Modern::BEGIN@26 at line 18
use JSON::MaybeXS;
# spent 10.1ms making 1 call to JSON::Schema::Modern::BEGIN@18 # spent 46µs making 1 call to Exporter::import
19277µs270µs
# spent 40µs (10+30) within JSON::Schema::Modern::BEGIN@19 which was called: # once (10µs+30µs) by OpenAPI::Modern::BEGIN@26 at line 19
use Carp qw(croak carp);
# spent 40µs making 1 call to JSON::Schema::Modern::BEGIN@19 # spent 30µs making 1 call to Exporter::import
20358µs3119µs
# spent 93µs (21+72) within JSON::Schema::Modern::BEGIN@20 which was called: # once (21µs+72µs) by OpenAPI::Modern::BEGIN@26 at line 20
use List::Util 1.55 qw(pairs first uniqint pairmap uniq any);
# spent 93µs making 1 call to JSON::Schema::Modern::BEGIN@20 # spent 15µs making 1 call to List::Util::import # spent 11µs making 1 call to UNIVERSAL::VERSION
21347µs380µs
# spent 48µs (16+32) within JSON::Schema::Modern::BEGIN@21 which was called: # once (16µs+32µs) by OpenAPI::Modern::BEGIN@26 at line 21
use Ref::Util 0.100 qw(is_ref is_plain_hashref);
# spent 48µs making 1 call to JSON::Schema::Modern::BEGIN@21 # spent 25µs making 1 call to Exporter::import # spent 7µs making 1 call to UNIVERSAL::VERSION
22223µs239µs
# spent 24µs (9+15) within JSON::Schema::Modern::BEGIN@22 which was called: # once (9µs+15µs) by OpenAPI::Modern::BEGIN@26 at line 22
use Scalar::Util 'refaddr';
# spent 24µs making 1 call to JSON::Schema::Modern::BEGIN@22 # spent 15µs making 1 call to Exporter::import
232658µs2166ms
# spent 166ms (2.31+164) within JSON::Schema::Modern::BEGIN@23 which was called: # once (2.31ms+164ms) by OpenAPI::Modern::BEGIN@26 at line 23
use Mojo::URL;
# spent 166ms making 1 call to JSON::Schema::Modern::BEGIN@23 # spent 4µs making 1 call to Mojo::Base::import
24221µs2159µs
# spent 84µs (9+75) within JSON::Schema::Modern::BEGIN@24 which was called: # once (9µs+75µs) by OpenAPI::Modern::BEGIN@26 at line 24
use Safe::Isa;
# spent 84µs making 1 call to JSON::Schema::Modern::BEGIN@24 # spent 75µs making 1 call to Exporter::import
252495µs211.5ms
# spent 11.5ms (8.37+3.12) within JSON::Schema::Modern::BEGIN@25 which was called: # once (8.37ms+3.12ms) by OpenAPI::Modern::BEGIN@26 at line 25
use Path::Tiny;
# spent 11.5ms making 1 call to JSON::Schema::Modern::BEGIN@25 # spent 36µs making 1 call to Exporter::import
26219µs2100µs
# spent 54µs (8+46) within JSON::Schema::Modern::BEGIN@26 which was called: # once (8µs+46µs) by OpenAPI::Modern::BEGIN@26 at line 26
use Storable 'dclone';
# spent 54µs making 1 call to JSON::Schema::Modern::BEGIN@26 # spent 46µs making 1 call to Exporter::import
272609µs229.9ms
# spent 29.8ms (2.51+27.3) within JSON::Schema::Modern::BEGIN@27 which was called: # once (2.51ms+27.3ms) by OpenAPI::Modern::BEGIN@26 at line 27
use File::ShareDir 'dist_dir';
# spent 29.8ms making 1 call to JSON::Schema::Modern::BEGIN@27 # spent 35µs making 1 call to Exporter::import
282777µs22.79ms
# spent 2.77ms (2.56+203µs) within JSON::Schema::Modern::BEGIN@28 which was called: # once (2.56ms+203µs) by OpenAPI::Modern::BEGIN@26 at line 28
use Module::Runtime qw(use_module require_module);
# spent 2.77ms making 1 call to JSON::Schema::Modern::BEGIN@28 # spent 20µs making 1 call to Module::Runtime::import
293493µs38.62ms
# spent 4.68ms (636µs+4.05) within JSON::Schema::Modern::BEGIN@29 which was called: # once (636µs+4.05ms) by OpenAPI::Modern::BEGIN@26 at line 29
use MooX::TypeTiny 0.002002;
# spent 4.68ms making 1 call to JSON::Schema::Modern::BEGIN@29 # spent 3.93ms making 1 call to MooX::TypeTiny::import # spent 9µs making 1 call to UNIVERSAL::VERSION
302558µs21.44ms
# spent 1.37ms (1.13+239µs) within JSON::Schema::Modern::BEGIN@30 which was called: # once (1.13ms+239µs) by OpenAPI::Modern::BEGIN@26 at line 30
use MooX::HandlesVia;
# spent 1.37ms making 1 call to JSON::Schema::Modern::BEGIN@30 # spent 74µs making 1 call to MooX::HandlesVia::import
313520µs388.9ms
# spent 85.9ms (9.64+76.3) within JSON::Schema::Modern::BEGIN@31 which was called: # once (9.64ms+76.3ms) 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 85.9ms making 1 call to JSON::Schema::Modern::BEGIN@31 # spent 2.96ms making 1 call to Exporter::Tiny::import # spent 20µs making 1 call to UNIVERSAL::VERSION
32251µs2153µs
# spent 104µs (55+49) within JSON::Schema::Modern::BEGIN@32 which was called: # once (55µs+49µs) by OpenAPI::Modern::BEGIN@26 at line 32
use Feature::Compat::Try;
# spent 104µs making 1 call to JSON::Schema::Modern::BEGIN@32 # spent 49µs making 1 call to Feature::Compat::Try::import
332639µs266.8ms
# spent 66.8ms (1.68+65.1) within JSON::Schema::Modern::BEGIN@33 which was called: # once (1.68ms+65.1ms) by OpenAPI::Modern::BEGIN@26 at line 33
use JSON::Schema::Modern::Error;
# spent 66.8ms making 1 call to JSON::Schema::Modern::BEGIN@33 # spent 0s making 1 call to JSON::Schema::Modern::__ANON__
342632µs236.9ms
# spent 36.9ms (2.59+34.3) within JSON::Schema::Modern::BEGIN@34 which was called: # once (2.59ms+34.3ms) by OpenAPI::Modern::BEGIN@26 at line 34
use JSON::Schema::Modern::Result;
# spent 36.9ms making 1 call to JSON::Schema::Modern::BEGIN@34 # spent 1µs making 1 call to JSON::Schema::Modern::__ANON__
352704µs255.2ms
# spent 55.2ms (2.99+52.2) within JSON::Schema::Modern::BEGIN@35 which was called: # once (2.99ms+52.2ms) by OpenAPI::Modern::BEGIN@26 at line 35
use JSON::Schema::Modern::Document;
# spent 55.2ms making 1 call to JSON::Schema::Modern::BEGIN@35 # spent 6µs making 1 call to Mojo::Base::import
362748µs27.83ms
# spent 7.74ms (4.74+2.99) within JSON::Schema::Modern::BEGIN@36 which was called: # once (4.74ms+2.99ms) by OpenAPI::Modern::BEGIN@26 at line 36
use JSON::Schema::Modern::Utilities qw(get_type canonical_uri E abort annotate_self);
# spent 7.74ms making 1 call to JSON::Schema::Modern::BEGIN@36 # spent 96µs making 1 call to Exporter::import
37294µs21.87ms
# spent 943µs (12+931) within JSON::Schema::Modern::BEGIN@37 which was called: # once (12µs+931µs) by OpenAPI::Modern::BEGIN@26 at line 37
use namespace::clean;
# spent 943µs making 1 call to JSON::Schema::Modern::BEGIN@37 # spent 931µs making 1 call to namespace::clean::import
38
3912µ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
46271µs2185µs
# spent 98µs (11+87) within JSON::Schema::Modern::BEGIN@46 which was called: # once (11µs+87µs) by OpenAPI::Modern::BEGIN@26 at line 46
use constant SPECIFICATION_VERSION_DEFAULT => 'draft2020-12';
# spent 98µs making 1 call to JSON::Schema::Modern::BEGIN@46 # spent 87µs making 1 call to constant::import
4725.02ms270µs
# spent 39µs (8+31) within JSON::Schema::Modern::BEGIN@47 which was called: # once (8µs+31µs) by OpenAPI::Modern::BEGIN@26 at line 47
use constant SPECIFICATION_VERSIONS_SUPPORTED => [qw(draft7 draft2019-09 draft2020-12)];
# spent 39µs making 1 call to JSON::Schema::Modern::BEGIN@47 # spent 31µ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 },
57114µs22.85ms);
# spent 1.49ms making 1 call to Types::Standard::Enum # spent 1.36ms making 1 call to MooX::HandlesVia::has
58
59127µs3741µshas output_format => (
# spent 456µs making 1 call to MooX::HandlesVia::has # spent 284µs making 1 call to Types::Standard::Enum # spent 1µs 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,
6917µs12µs
# spent 8µs (6+2) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:69] which was called: # once (6µs+2µs) by JSON::Schema::Modern::short_circuit at line 23 of (eval 312)[Sub/Quote.pm:3]
default => sub { $_[0]->output_format eq 'flag' && !$_[0]->collect_annotations },
# spent 2µs making 1 call to JSON::Schema::Modern::output_format
7016µs2735µs);
# spent 733µs making 1 call to MooX::HandlesVia::has # spent 2µs making 1 call to Types::Standard::Bool
71
7214µs2684µshas max_traversal_depth => (
# spent 683µ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
78115µs2669µshas validate_formats => (
# spent 657µs making 1 call to MooX::HandlesVia::has # spent 12µ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
9016µs13µs
# spent 10µs (7+3) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:90] which was called: # once (7µs+3µs) by JSON::Schema::Modern::validate_content_schemas at line 23 of (eval 315)[Sub/Quote.pm:3]
default => sub { ($_[0]->specification_version//'') eq 'draft7' },
# spent 3µs making 1 call to JSON::Schema::Modern::specification_version
9114µs2704µs);
# spent 702µs making 1 call to MooX::HandlesVia::has # spent 2µs making 1 call to Types::Standard::Bool
92
9312µs2316µshas collect_annotations => (
# spent 315µs making 1 call to MooX::HandlesVia::has # spent 1µs making 1 call to Types::Standard::Bool
94 is => 'ro',
95 isa => Bool,
96);
97
9813µs2298µshas scalarref_booleans => (
# spent 297µs making 1 call to MooX::HandlesVia::has # spent 1µs making 1 call to Types::Standard::Bool
99 is => 'ro',
100 isa => Bool,
101);
102
10312µs2304µshas strict => (
# spent 303µs making 1 call to MooX::HandlesVia::has # spent 1µs 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/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:121] which was called: # once (1µs+0s) by JSON::Schema::Modern::_assert__format_validations at line 23 of (eval 325)[Sub/Quote.pm:3]
default => sub { {} },
122174µs4531.2ms);
# spent 15.1ms making 1 call to MooX::HandlesVia::has # spent 8.88ms making 2 calls to Types::Standard::Dict, avg 4.44ms/call # spent 3.42ms making 1 call to Types::Standard::Slurpy # spent 2.14ms making 1 call to Types::Standard::HashRef # spent 932µs making 19 calls to Types::Standard::Optional, avg 49µs/call # spent 674µs making 1 call to Types::Standard::Enum # spent 11µs making 20 calls to Types::Standard::CodeRef, avg 550ns/call
123
124553µs17985µs
# spent 735µs (24+711) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:124] which was called: # once (24µs+711µs) by JSON::Schema::Modern::add_format_validation at line 4 of (eval 327)[Class/Method/Modifiers.pm:148]
before add_format_validation => sub ($self, @kvs) { $format_type->({ @$_ }) foreach pairs @kvs };
# spent 668µs making 5 calls to Sub::Defer::__ANON__[Sub/Defer.pm:178], avg 134µs/call # spent 293µs making 1 call to Moo::before # spent 20µ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 12µs (8+4) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:133] which was called: # once (8µs+4µs) by JSON::Schema::Modern::__ANON__[(eval 329)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Class/Method/Modifiers.pm:89]:1] at line 1 of (eval 329)[Class/Method/Modifiers.pm:89]
around BUILDARGS => sub ($orig, $class, @args) {
12712µs14µs my $args = $class->$orig(@args);
# spent 4µ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
13215µs return $args;
13315µs1264µs};
# spent 264µs making 1 call to Moo::around
134
135
# spent 159ms (1.16+158) within JSON::Schema::Modern::add_schema which was called 9 times, avg 17.7ms/call: # 6 times (867µs+147ms) by JSON::Schema::Modern::Document::OpenAPI::_add_vocab_and_default_schemas at line 204 of JSON/Schema/Modern/Document/OpenAPI.pm, avg 24.6ms/call # 2 times (110µs+1.55ms) by JSON::Schema::Modern::Document::OpenAPI::_add_vocab_and_default_schemas at line 206 of JSON/Schema/Modern/Document/OpenAPI.pm, avg 832µs/call # once (181µs+9.74ms) 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 {
13699µs croak 'insufficient arguments' if @_ < 2;
13799µs my $self = shift;
138
139 # TODO: resolve $uri against $self->base_uri
140962µs10918µs my $uri = !is_ref($_[0]) ? Mojo::URL->new(shift)
# spent 892µs making 9 calls to Mojo::URL::new, avg 99µs/call # spent 26µs making 1 call to Safe::Isa::__ANON__[Safe/Isa.pm:23]
141 : $_[0]->$_isa('Mojo::URL') ? shift : Mojo::URL->new;
142
143918µs915µs croak 'cannot add a schema with a uri with a fragment' if defined $uri->fragment;
# spent 15µs making 9 calls to Mojo::URL::fragment, avg 2µs/call
144
14592µ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)
1529188µs21117ms my $document = $_[0]->$_isa('JSON::Schema::Modern::Document') ? shift
# spent 117ms making 6 calls to JSON::Schema::Modern::Document::new, avg 19.5ms/call # spent 139µs making 9 calls to Safe::Isa::__ANON__[Safe/Isa.pm:23], avg 15µs/call # spent 14µ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
159925µs9253µs if ($document->has_errors) {
# spent 253µ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
1699314µs189251µs if (not grep refaddr($_->{document}) == refaddr($document), $self->_canonical_resources) {
# spent 213µs making 9 calls to JSON::Schema::Modern::_canonical_resources, avg 24µs/call # spent 38µs making 180 calls to Scalar::Util::refaddr, avg 211ns/call
17078.87ms359.33ms my $schema_content = $document->_serialized_schema
# spent 8.76ms making 7 calls to Cpanel::JSON::XS::encode, avg 1.25ms/call # spent 535µs making 14 calls to JSON::Schema::Modern::Document::_serialized_schema, avg 38µs/call # spent 26µs making 7 calls to JSON::Schema::Modern::_json_decoder, avg 4µs/call # spent 13µs making 7 calls to JSON::Schema::Modern::Document::schema, avg 2µs/call
171 // $document->_serialized_schema($self->_json_decoder->encode($document->schema));
172
1737159µs21424µs if (my $existing_doc = first {
# spent 249µs making 7 calls to List::Util::first, avg 36µs/call # spent 124µs making 7 calls to JSON::Schema::Modern::_canonical_resources, avg 18µs/call # spent 51µs making 7 calls to List::Util::uniqint, avg 7µs/call
17429155µs61133µs my $existing_content = $_->_serialized_schema
# spent 94µs making 8 calls to Cpanel::JSON::XS::encode, avg 12µs/call # spent 28µs making 37 calls to JSON::Schema::Modern::Document::_serialized_schema, avg 757ns/call # spent 7µs making 8 calls to JSON::Schema::Modern::Document::schema, avg 875ns/call # spent 4µs making 8 calls to JSON::Schema::Modern::_json_decoder, avg 500ns/call
175 // $_->_serialized_schema($self->_json_decoder->encode($_->schema));
1762918µ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 {
182783µs147.70ms $self->_add_resources(map +($_->[0] => +{ $_->[1]->%*, document => $document }),
# spent 7.56ms making 7 calls to JSON::Schema::Modern::_add_resources, avg 1.08ms/call # spent 141µs making 7 calls to JSON::Schema::Modern::Document::resource_pairs, avg 20µs/call
183 $document->resource_pairs);
184 }
185 }
186
187942µs91.05ms if ("$uri") {
# spent 1.05ms making 9 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 117µs/call
188829µs16968µs my $resource = $document->_get_resource($document->canonical_uri);
# spent 950µs making 8 calls to JSON::Schema::Modern::Document::_get_resource, avg 119µs/call # spent 18µ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},
196852µs164.58ms });
# spent 4.58ms making 8 calls to JSON::Schema::Modern::_add_resources, avg 572µs/call # spent 5µs making 8 calls to JSON::Schema::Modern::Document::canonical_uri, avg 625ns/call
197 }
198
199939µ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.
2332972846µs
# spent 1.47s (34.2ms+1.43) within JSON::Schema::Modern::traverse which was called 743 times, avg 1.97ms/call: # 727 times (33.2ms+1.28s) by JSON::Schema::Modern::Document::OpenAPI::_traverse_schema at line 218 of JSON/Schema/Modern/Document/OpenAPI.pm, avg 1.81ms/call # 14 times (890µs+143ms) by JSON::Schema::Modern::Document::traverse at line 178 of JSON/Schema/Modern/Document.pm, avg 10.3ms/call # once (52µs+4.03ms) by JSON::Schema::Modern::Document::OpenAPI::traverse at line 115 of JSON/Schema/Modern/Document/OpenAPI.pm # once (56µs+-56µs) by JSON::Schema::Modern::_get_metaschema_info at line 750
sub traverse ($self, $schema_reference, $config_override = {}) {
234 # Note: the starting position is not guaranteed to be at the root of the $document.
2357431.69ms743309ms my $initial_uri = Mojo::URL->new($config_override->{initial_schema_uri} // '');
# spent 309ms making 743 calls to Mojo::URL::new, avg 416µs/call
236743801µs my $initial_path = $config_override->{traversed_schema_path} // '';
2377432.67ms7432.13ms my $spec_version = $self->specification_version//SPECIFICATION_VERSION_DEFAULT;
# spent 2.13ms making 743 calls to JSON::Schema::Modern::specification_version, avg 3µ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} // {},
2507437.46ms74377.9ms evaluator => $self,
# spent 77.9ms making 743 calls to Mojo::URL::new, avg 105µs/call
251 };
252
253743470µs try {
254 my $for_canonical_uri = Mojo::URL->new(
255 (is_plain_hashref($schema_reference) && exists $schema_reference->{'$id'}
256 ? Mojo::URL->new($schema_reference->{'$id'}) : undef)
2577432.27ms757232ms // $state->{initial_schema_uri});
# spent 232ms making 757 calls to Mojo::URL::new, avg 306µs/call
258743945µs758514µs $for_canonical_uri->fragment(undef) if not length $for_canonical_uri->fragment;
# spent 514µs making 758 calls to Mojo::URL::fragment, avg 678ns/call
259
260 # a subsequent "$schema" keyword can still change these values
261 $state->@{qw(spec_version vocabularies)} = $self->_get_metaschema_info(
2627436.60ms758129ms $config_override->{metaschema_uri} // $self->METASCHEMA_URIS->{$spec_version},
# spent 129ms making 743 calls to JSON::Schema::Modern::_get_metaschema_info, avg 173µs/call, recursion: max depth 1, sum of overlapping time 53µs # spent 11µs making 15 calls to JSON::Schema::Modern::METASCHEMA_URIS, avg 733ns/call
263 $for_canonical_uri,
264 );
265 }
266 catch ($e) {
267 if ($e->$_isa('JSON::Schema::Modern::Result')) {
268 push $state->{errors}->@*, $e->errors;
269 }
270 elsif ($e->$_isa('JSON::Schema::Modern::Error')) {
271 push $state->{errors}->@*, $e;
272 }
273 else {
274 ()= E({ %$state, exception => 1 }, 'EXCEPTION: '.$e);
275 }
276
277 return $state;
278 }
279
280743383µs try {
2817432.70ms743685ms $self->_traverse_subschema($schema_reference, $state);
# spent 685ms making 743 calls to JSON::Schema::Modern::_traverse_subschema, avg 922µs/call
282 }
283 catch ($e) {
284 if ($e->$_isa('JSON::Schema::Modern::Error')) {
285 # note: we should never be here, since traversal subs are no longer be fatal
286 push $state->{errors}->@*, $e;
287 }
288 else {
289 E({ %$state, exception => 1 }, 'EXCEPTION: '.$e);
290 }
291 }
292
293743351µs delete $state->{traverse};
2947433.02ms return $state;
295}
296
297# the actual runtime evaluation of the schema against input data.
29852µs
# spent 99.9s (327ms+99.6) within JSON::Schema::Modern::evaluate which was called: # once (327ms+99.6s) 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 = {}) {
29910s croak 'evaluate called in void context' if not defined wantarray;
300
30111µs my $initial_path = $config_override->{traversed_schema_path} // '';
30212µs1133µs my $effective_base_uri = Mojo::URL->new($config_override->{effective_base_uri}//'');
# spent 133µs making 1 call to Mojo::URL::new
303
304 my $state = {
30515µs13µs data_path => $config_override->{data_path} // '',
# spent 3µs making 1 call to Mojo::URL::new
306 traversed_schema_path => $initial_path, # the accumulated path as of the start of evaluation, or last $id or $ref
307 initial_schema_uri => Mojo::URL->new, # the canonical URI as of the start of evaluation, or last $id or $ref
308 schema_path => '', # the rest of the path, since the start of evaluation, or last $id or $ref
309 effective_base_uri => $effective_base_uri, # resolve locations against this for errors and annotations
310 errors => [],
311 };
312
31311µs my $valid;
31410s try {
31510s my $schema_info;
316
31713µs112µs if (not is_ref($schema_reference) or $schema_reference->$_isa('Mojo::URL')) {
# spent 12µs making 1 call to Safe::Isa::__ANON__[Safe/Isa.pm:23]
31812µs1473µs $schema_info = $self->_fetch_from_uri($schema_reference);
# spent 473µs making 1 call to JSON::Schema::Modern::_fetch_from_uri
31912µs1236µs $state->{initial_schema_uri} = Mojo::URL->new($config_override->{initial_schema_uri} // '');
# spent 236µs making 1 call to Mojo::URL::new
320 }
321 else {
322 # traverse is called via add_schema -> ::Document->new -> ::Document->BUILD
323 my $document = $self->add_schema('', $schema_reference);
324 my $base_resource = $document->_get_resource($document->canonical_uri)
325 || croak "couldn't get resource: document parse error";
326
327 $schema_info = {
328 schema => $document->schema,
329 document => $document,
330 document_path => '',
331 $base_resource->%{qw(canonical_uri specification_version vocabularies configs)},
332 };
333 }
334
33511µs abort($state, 'EXCEPTION: unable to find resource %s', $schema_reference)
336 if not $schema_info;
337
338 $state = +{
339 %$state,
340 depth => 0,
341 initial_schema_uri => $schema_info->{canonical_uri}, # the canonical URI as of the start of evaluation, or last $id or $ref
342 document => $schema_info->{document}, # the ::Document object containing this schema
343 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
344 dynamic_scope => [ $schema_info->{canonical_uri} ],
345 annotations => [],
346 seen => {},
347 spec_version => $schema_info->{specification_version},
348 vocabularies => $schema_info->{vocabularies},
349 callbacks => $config_override->{callbacks} // {},
350 evaluator => $self,
351 $schema_info->{configs}->%*,
352 (map {
353737µs644µs my $val = $config_override->{$_} // $self->$_;
# spent 19µs making 1 call to JSON::Schema::Modern::validate_content_schemas # spent 15µs making 1 call to JSON::Schema::Modern::short_circuit # spent 3µs making 1 call to JSON::Schema::Modern::collect_annotations # spent 3µs making 1 call to JSON::Schema::Modern::validate_formats # spent 2µs making 1 call to JSON::Schema::Modern::scalarref_booleans # spent 2µs making 1 call to JSON::Schema::Modern::strict
35463µs defined $val ? ( $_ => $val ) : ()
355 } qw(validate_formats validate_content_schemas short_circuit collect_annotations scalarref_booleans strict)),
356 };
357
35810s if ($state->{validate_formats}) {
359 $state->{vocabularies} = [
360 map s/^JSON::Schema::Modern::Vocabulary::Format\KAnnotation$/Assertion/r, $state->{vocabularies}->@*
361114µs75µs ];
# spent 5µs making 7 calls to JSON::Schema::Modern::CORE:subst, avg 714ns/call
36211µs require JSON::Schema::Modern::Vocabulary::FormatAssertion;
363 }
364
36514µs199.6s $valid = $self->_eval_subschema($data, $schema_info->{schema}, $state);
# spent 99.6s making 1 call to JSON::Schema::Modern::_eval_subschema
366122µs warn 'result is false but there are no errors' if not $valid and not $state->{errors}->@*;
367 }
368 catch ($e) {
369 if ($e->$_isa('JSON::Schema::Modern::Result')) {
370 return $e;
371 }
372 elsif ($e->$_isa('JSON::Schema::Modern::Error')) {
373 push $state->{errors}->@*, $e;
374 }
375 else {
376 $valid = E({ %$state, exception => 1 }, 'EXCEPTION: '.$e);
377 }
378 }
379
38012µs die 'evaluate validity inconstent with error count' if $valid xor !$state->{errors}->@*;
381
382 return JSON::Schema::Modern::Result->new(
383 output_format => $self->output_format,
384 valid => $valid,
385 $valid
386 # strip annotations from result if user didn't explicitly ask for them
387 ? ($config_override->{collect_annotations} // $self->collect_annotations
388 ? (annotations => $state->{annotations}) : ())
3891327ms32.65ms : (errors => $state->{errors}),
# spent 2.64ms making 1 call to JSON::Schema::Modern::Result::new # spent 5µs making 1 call to JSON::Schema::Modern::output_format # spent 2µs making 1 call to JSON::Schema::Modern::collect_annotations
390 );
391}
392
393sub validate_schema ($self, $schema, $config_override = {}) {
394 croak 'validate_schema called in void context' if not defined wantarray;
395
396 my $metaschema_uri = is_plain_hashref($schema) && $schema->{'$schema'} ? $schema->{'$schema'}
397 : $self->METASCHEMA_URIS->{$self->specification_version // $self->SPECIFICATION_VERSION_DEFAULT};
398
399 return $self->evaluate($schema, $metaschema_uri, $config_override);
400}
401
402sub get ($self, $uri) {
403 my $schema_info = $self->_fetch_from_uri($uri);
404 return if not $schema_info;
405 my $subschema = is_ref($schema_info->{schema}) ? dclone($schema_info->{schema}) : $schema_info->{schema};
406 return wantarray ? ($subschema, $schema_info->{canonical_uri}) : $subschema;
407}
408
409# defined lower down:
410# sub add_vocabulary { ... }
411# sub add_encoding { ... }
412# sub add_media_type { ... }
413
414######## NO PUBLIC INTERFACES FOLLOW THIS POINT ########
415
416# current spec version => { keyword => undef, or arrayref of alternatives }
417114µsmy %removed_keywords = (
418 'draft7' => {
419 id => [ '$id' ],
420 },
421 'draft2019-09' => {
422 id => [ '$id' ],
423 definitions => [ '$defs' ],
424 dependencies => [ qw(dependentSchemas dependentRequired) ],
425 },
426 'draft2020-12' => {
427 id => [ '$id' ],
428 definitions => [ '$defs' ],
429 dependencies => [ qw(dependentSchemas dependentRequired) ],
430 '$recursiveAnchor' => [ '$dynamicAnchor' ],
431 '$recursiveRef' => [ '$dynamicRef' ],
432 additionalItems => [ 'items' ],
433 },
434);
435
436# {
437# $spec_version => {
438# $vocabulary_class => {
439# traverse => [ [ $keyword => $subref ], [ ... ] ],
440# evaluate => [ [ $keyword => $subref ], [ ... ] ],
441# }
442# }
443# }
444# If we could serialize coderefs, this could be an object attribute;
445# otherwise, we might as well persist this for the lifetime of the process.
44611µsour $vocabulary_cache = {};
447
448114522.20ms
# spent 685ms (204+481) within JSON::Schema::Modern::_traverse_subschema which was called 2863 times, avg 239µs/call: # 1349 times (88.3ms+-88.3ms) by JSON::Schema::Modern::Vocabulary::traverse_object_schemas at line 55 of JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 743 times (78.8ms+606ms) by JSON::Schema::Modern::traverse at line 281, avg 922µs/call # 562 times (24.2ms+-24.2ms) by JSON::Schema::Modern::Vocabulary::traverse_subschema at line 34 of JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 203 times (12.6ms+-12.6ms) by JSON::Schema::Modern::Vocabulary::traverse_array_schemas at line 44 of JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 6 times (280µs+-280µs) by JSON::Schema::Modern::Vocabulary::traverse_property_schema at line 64 of JSON/Schema/Modern/Vocabulary.pm, avg 0s/call
sub _traverse_subschema ($self, $schema, $state) {
44928631.25ms delete $state->{keyword};
450
451 return E($state, 'EXCEPTION: maximum traversal depth exceeded')
45228635.12ms28634.80ms if $state->{depth}++ > $self->max_traversal_depth;
# spent 4.80ms making 2863 calls to JSON::Schema::Modern::max_traversal_depth, avg 2µs/call
453
45428634.17ms286310.5ms my $schema_type = get_type($schema);
# spent 10.5ms making 2863 calls to JSON::Schema::Modern::Utilities::get_type, avg 4µs/call
45528631.59ms return 1 if $schema_type eq 'boolean';
456
4572491710µs return E($state, 'invalid schema type: %s', $schema_type) if $schema_type ne 'object';
458
45924911.36ms return 1 if not keys %$schema;
460
4612488368µs my $valid = 1;
46224889.87ms my %unknown_keywords = map +($_ => undef), keys %$schema;
463 # we must check the array length on every iteration because some keywords can change it!
464248811.8ms for (my $idx = 0; $idx <= $state->{vocabularies}->$#*; ++$idx) {
465194346.98ms my $vocabulary = $state->{vocabularies}[$idx];
466
467 # [ [ $keyword => $subref ], [ ... ] ]
468 my $keyword_list = $vocabulary_cache->{$state->{spec_version}}{$vocabulary}{traverse} //= [
469 map [ $_ => $vocabulary->can('_traverse_keyword_'.($_ =~ s/^\$//r)) ],
470 $vocabulary->keywords($state->{spec_version})
4711943413.7ms130195µs ];
# spent 99µs making 61 calls to UNIVERSAL::can, avg 2µs/call # spent 37µs making 1 call to JSON::Schema::Modern::Vocabulary::Applicator::keywords # spent 15µs making 1 call to JSON::Schema::Modern::Vocabulary::Unevaluated::keywords # spent 10µs making 61 calls to JSON::Schema::Modern::CORE:subst, avg 164ns/call # spent 10µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::keywords # spent 8µ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 5µs making 1 call to JSON::Schema::Modern::Vocabulary::MetaData::keywords # spent 4µs making 1 call to JSON::Schema::Modern::Vocabulary::OpenAPI::keywords # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::FormatAnnotation::keywords
472
4731943428.0ms foreach my $keyword_tuple ($keyword_list->@*) {
47414988838.9ms my ($keyword, $sub) = $keyword_tuple->@*;
47514988828.5ms next if not exists $schema->{$keyword};
476
477 # keywords adjacent to $ref are not evaluated before draft2019-09
47843882.08ms next if $keyword ne '$ref' and exists $schema->{'$ref'} and $state->{spec_version} eq 'draft7';
479
48043881.53ms delete $unknown_keywords{$keyword};
48143881.68ms $state->{keyword} = $keyword;
482
48343888.21ms43881.10s if (not $sub->($vocabulary, $schema, $state)) {
# spent 384ms making 387 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_properties, avg 993µs/call, recursion: max depth 3, sum of overlapping time 40.9ms # spent 204ms making 710 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_ref, avg 288µs/call # spent 110ms making 98 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_items, avg 1.13ms/call, recursion: max depth 1, sum of overlapping time 5.42ms # spent 96.3ms making 275 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_required, avg 350µs/call # spent 99.8ms making 12 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_defs, avg 8.32ms/call, recursion: max depth 1, sum of overlapping time 9.35ms # spent 47.7ms making 1382 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_type, avg 35µs/call # spent 40.5ms making 130 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_additionalProperties, avg 311µs/call, recursion: max depth 1, sum of overlapping time 7.05ms # spent 26.2ms making 23 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_allOf, avg 1.14ms/call # spent 21.3ms making 65 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_then, avg 327µs/call # spent 18.6ms making 21 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_oneOf, avg 887µs/call # spent 15.3ms making 32 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_anyOf, avg 479µs/call, recursion: max depth 1, sum of overlapping time 192µs # spent 13.3ms making 65 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_if, avg 205µs/call # spent 7.75ms making 156 calls to JSON::Schema::Modern::Vocabulary::Unevaluated::_traverse_keyword_unevaluatedProperties, avg 50µs/call # spent 7.47ms making 3 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_contains, avg 2.49ms/call # spent 6.33ms making 11 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_vocabulary, avg 576µs/call # spent 6.17ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_id, avg 441µs/call # spent 5.66ms making 15 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema, avg 378µs/call # spent 5.34ms making 15 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_else, avg 356µs/call # spent 5.18ms making 14 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_propertyNames, avg 370µs/call # spent 5.04ms making 14 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicAnchor, avg 360µs/call # spent 4.96ms making 69 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_pattern, avg 72µs/call # spent 4.81ms making 22 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_dynamicRef, avg 219µs/call # spent 4.78ms making 3 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_dependentSchemas, avg 1.59ms/call # spent 3.03ms making 135 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_readOnly, avg 22µs/call # spent 2.36ms making 118 calls to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_comment, avg 20µs/call # spent 2.29ms making 97 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_description, avg 24µs/call # spent 1.96ms making 6 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_patternProperties, avg 327µs/call # spent 1.54ms making 15 calls to JSON::Schema::Modern::Vocabulary::Applicator::_traverse_keyword_not, avg 102µs/call # spent 1.41ms making 50 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minProperties, avg 28µs/call # spent 705µs making 50 calls to JSON::Schema::Modern::Vocabulary::FormatAnnotation::_traverse_keyword_format, avg 14µs/call # spent 646µs making 34 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_title, avg 19µs/call # spent 601µs making 60 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_enum, avg 10µs/call # spent 565µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_anchor # spent 528µs making 21 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minimum, avg 25µs/call # spent 308µs making 15 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_deprecated, avg 21µs/call # spent 256µs making 14 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minItems, avg 18µs/call # spent 183µs making 8 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minLength, avg 23µs/call # spent 172µs making 8 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxLength, avg 22µs/call # spent 166µs making 8 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maximum, avg 21µs/call # spent 147µs making 95 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_const, avg 2µs/call # spent 86µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::_traverse_keyword_contentSchema # spent 82µs making 98 calls to JSON::Schema::Modern::Vocabulary::MetaData::_traverse_keyword_default, avg 837ns/call # spent 76µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_dependentRequired # spent 73µs making 3 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxProperties, avg 24µs/call # spent 62µs making 2 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxContains, avg 31µs/call # spent 61µs making 3 calls to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_uniqueItems, avg 20µs/call # spent 41µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_minContains # spent 29µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::_traverse_keyword_contentMediaType # spent 19µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_exclusiveMinimum # spent 14µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::_traverse_keyword_maxItems # spent 7µs making 5 calls to JSON::Schema::Modern::Vocabulary::OpenAPI::_traverse_keyword_externalDocs, avg 1µs/call
484 die 'traverse returned false but we have no errors' if not $state->{errors}->@*;
485 $valid = 0;
486 next;
487 }
488
48943884.04ms if (my $callback = $state->{callbacks}{$keyword}) {
490 $callback->($schema, $state);
491 }
492 }
493 }
494
49524881.32ms delete $state->{keyword};
496
49724884.82ms24884.76ms if ($self->strict and keys %unknown_keywords) {
# spent 4.76ms making 2488 calls to JSON::Schema::Modern::strict, avg 2µs/call
498 ()= E($state, 'unknown keyword%s found: %s', keys %unknown_keywords > 1 ? 's' : '',
499 join(', ', sort keys %unknown_keywords));
500 }
501
502 # check for previously-supported but now removed keywords
503248814.4ms24883.52ms foreach my $keyword (sort keys $removed_keywords{$state->{spec_version}}->%*) {
# spent 3.52ms making 2488 calls to JSON::Schema::Modern::CORE:sort, avg 1µs/call
504149281.88ms next if not exists $schema->{$keyword};
505 my $message ='no-longer-supported "'.$keyword.'" keyword present (at location "'
506 .canonical_uri($state).'")';
507 if (my $alternates = $removed_keywords{$state->{spec_version}}->{$keyword}) {
508 my @list = map '"'.$_.'"', @$alternates;
509 @list = ((map $_.',', @list[0..$#list-1]), $list[-1]) if @list > 2;
510 splice(@list, -1, 0, 'or') if @list > 1;
511 $message .= ': this should be rewritten as '.join(' ', @list);
512 }
513 carp $message;
514 }
515
51624886.98ms return $valid;
517}
518
51945797583.2ms
# spent 99.6s (11.8+87.8) within JSON::Schema::Modern::_eval_subschema which was called 91595 times, avg 1.09ms/call: # 49887 times (5.76s+-5.76s) by JSON::Schema::Modern::Vocabulary::eval at line 68 of JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # 41707 times (6.06s+-6.06s) by JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri at line 89 of JSON/Schema/Modern/Vocabulary.pm, avg 0s/call # once (18.9ms+99.6s) by JSON::Schema::Modern::evaluate at line 365
sub _eval_subschema ($self, $data, $schema, $state) {
5209159536.3ms croak '_eval_subschema called in void context' if not defined wantarray;
521
522 # callers created a new $state for us, so we do not propagate upwards changes to depth, traversed
523 # paths; but annotations, errors are arrayrefs so their contents will be shared
52491595115ms $state->{dynamic_scope} = [ ($state->{dynamic_scope}//[])->@* ];
525915952.45s2015087264ms delete $state->@{'keyword', grep /^_/, keys %$state};
# spent 264ms making 2015087 calls to JSON::Schema::Modern::CORE:match, avg 131ns/call
526
527 abort($state, 'EXCEPTION: maximum evaluation depth exceeded')
52891595207ms91595175ms if $state->{depth}++ > $self->max_traversal_depth;
# spent 175ms making 91595 calls to JSON::Schema::Modern::max_traversal_depth, avg 2µs/call
529
53091595131ms91595164ms my $schema_type = get_type($schema);
# spent 164ms making 91595 calls to JSON::Schema::Modern::Utilities::get_type, avg 2µs/call
5319159536.4ms return $schema || E($state, 'subschema is false') if $schema_type eq 'boolean';
532
533 # this should never happen, due to checks in traverse
5349159527.7ms abort($state, 'invalid schema type: %s', $schema_type) if $schema_type ne 'object';
535
5369159536.3ms return 1 if not keys %$schema;
537
538 # find all schema locations in effect at this data path + canonical_uri combination
539 # if any of them are absolute prefix of this schema location, we are in a loop.
5409159599.5ms915952.54s my $canonical_uri = canonical_uri($state);
# spent 2.54s making 91595 calls to JSON::Schema::Modern::Utilities::canonical_uri, avg 28µs/call
5419159556.1ms my $schema_location = $state->{traversed_schema_path}.$state->{schema_path};
542 abort($state, 'EXCEPTION: infinite loop detected (same location evaluated twice)')
543 if grep substr($schema_location, 0, length) eq $_,
54491595480ms915959.11s keys $state->{seen}{$state->{data_path}}{$canonical_uri}->%*;
# spent 9.11s making 91595 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 99µs/call
54591595336ms915957.85s $state->{seen}{$state->{data_path}}{$canonical_uri}{$schema_location}++;
# spent 7.85s making 91595 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 86µs/call
546
5479159529.2ms my $valid = 1;
54891595348ms my %unknown_keywords = map +($_ => undef), keys %$schema;
5499159536.4ms my $orig_annotations = $state->{annotations};
5509159549.0ms $state->{annotations} = [];
5519159520.3ms my @new_annotations;
552
553 ALL_KEYWORDS:
5549159584.0ms foreach my $vocabulary ($state->{vocabularies}->@*) {
555 # [ [ $keyword => $subref|undef ], [ ... ] ]
556 my $keyword_list = $vocabulary_cache->{$state->{spec_version}}{$vocabulary}{evaluate} //= [
557 map [ $_ => $vocabulary->can('_eval_keyword_'.($_ =~ s/^\$//r)) ],
558 $vocabulary->keywords($state->{spec_version})
559641165557ms124211µs ];
# spent 125µs making 58 calls to UNIVERSAL::can, avg 2µs/call # spent 28µs making 1 call to JSON::Schema::Modern::Vocabulary::Applicator::keywords # spent 17µs making 58 calls to JSON::Schema::Modern::CORE:subst, avg 293ns/call # spent 10µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::keywords # spent 9µs making 1 call to JSON::Schema::Modern::Vocabulary::Unevaluated::keywords # spent 8µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::keywords # spent 5µs making 1 call to JSON::Schema::Modern::Vocabulary::MetaData::keywords # spent 4µ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::FormatAnnotation::keywords
560
561641165955ms foreach my $keyword_tuple ($keyword_list->@*) {
56252209151.40s my ($keyword, $sub) = $keyword_tuple->@*;
56352209151.00s next if not exists $schema->{$keyword};
564
565 # keywords adjacent to $ref are not evaluated before draft2019-09
566308026108ms next if $keyword ne '$ref' and exists $schema->{'$ref'} and $state->{spec_version} eq 'draft7';
567
56830802699.2ms delete $unknown_keywords{$keyword};
56930802687.7ms $state->{keyword} = $keyword;
570
57130802686.8ms if ($sub) {
57220247170.9ms my $error_count = $state->{errors}->@*;
573
574202471433ms202471620s if (not $sub->($vocabulary, $data, $schema, $state)) {
# spent 1085s making 39121 calls to JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_ref, avg 27.7ms/call, recursion: max depth 31, sum of overlapping time 986s # spent 479s making 32492 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_properties, avg 14.7ms/call, recursion: max depth 11, sum of overlapping time 379s # spent 120s making 3369 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_patternProperties, avg 35.8ms/call, recursion: max depth 2, sum of overlapping time 38.2s # spent 79.3s making 3013 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_if, avg 26.3ms/call, recursion: max depth 1, sum of overlapping time 4.49s # spent 280s making 6002 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_allOf, avg 46.7ms/call, recursion: max depth 13, sum of overlapping time 206s # spent 151s making 2586 calls to JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef, avg 58.3ms/call, recursion: max depth 6, sum of overlapping time 79.9s # spent 115s making 977 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_additionalProperties, avg 118ms/call, recursion: max depth 4, sum of overlapping time 44.7s # spent 26.1s making 1758 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_items, avg 14.9ms/call, recursion: max depth 4, sum of overlapping time 2.52s # spent 7.33s making 25860 calls to JSON::Schema::Modern::Vocabulary::MetaData::_eval_keyword_title, avg 284µs/call # spent 4.19s making 305 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_dependentSchemas, avg 13.7ms/call # spent 3.25s making 1182 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_anyOf, avg 2.75ms/call # spent 2.58s making 25862 calls to JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_id, avg 100µs/call # spent 2.07s making 3747 calls to JSON::Schema::Modern::Vocabulary::Unevaluated::_eval_keyword_unevaluatedProperties, avg 552µs/call # spent 1.44s making 5174 calls to JSON::Schema::Modern::Vocabulary::MetaData::_eval_keyword_description, avg 277µs/call # spent 974ms making 35648 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_type, avg 27µs/call # spent 611ms making 2167 calls to JSON::Schema::Modern::Vocabulary::FormatAnnotation::_eval_keyword_format, avg 282µs/call # spent 468ms making 4795 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_required, avg 98µs/call # spent 449ms making 627 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_propertyNames, avg 716µs/call # spent 373ms making 1180 calls to JSON::Schema::Modern::Vocabulary::MetaData::_eval_keyword_default, avg 316µs/call # spent 315ms making 305 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_oneOf, avg 1.03ms/call # spent 278ms making 1208 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_const, avg 230µs/call # spent 248ms making 1538 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_enum, avg 161µs/call # spent 86.1ms making 1403 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_uniqueItems, avg 61µs/call # spent 25.7ms making 63 calls to JSON::Schema::Modern::Vocabulary::FormatAssertion::_eval_keyword_format, avg 408µs/call # spent 11.1ms making 1244 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_minItems, avg 9µs/call # spent 7.01ms making 262 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_pattern, avg 27µs/call # spent 4.87ms making 485 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_minProperties, avg 10µs/call # spent 2.98ms making 4 calls to JSON::Schema::Modern::Vocabulary::Applicator::_eval_keyword_not, avg 746µs/call # spent 1.42ms making 79 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_minimum, avg 18µs/call # spent 164µs making 15 calls to JSON::Schema::Modern::Vocabulary::Validation::_eval_keyword_maxProperties, avg 11µs/call
575 warn 'result is false but there are no errors (keyword: '.$keyword.')'
57642832.55ms if $error_count == $state->{errors}->@*;
57742831.08ms $valid = 0;
578
57942831.28ms last ALL_KEYWORDS if $state->{short_circuit};
58042833.56ms next;
581 }
582 }
583
584303743242ms41641133ms if (my $callback = $state->{callbacks}{$keyword}) {
585 $callback->($data, $schema, $state);
586 }
587
588303743489ms push @new_annotations, $state->{annotations}->@[$#new_annotations+1 .. $state->{annotations}->$#*];
589 }
590 }
591
5929159551.0ms delete $state->{keyword};
593
5949159523.9ms if ($state->{strict} and keys %unknown_keywords) {
595 abort($state, 'unknown keyword%s found: %s', keys %unknown_keywords > 1 ? 's' : '',
596 join(', ', sort keys %unknown_keywords));
597 }
598
59991595103ms $state->{annotations} = $orig_annotations;
600
6019159579.2ms if ($valid) {
60287312176ms push $state->{annotations}->@*, @new_annotations;
60387312962ms349244375ms if ($state->{collect_annotations} and $state->{spec_version} !~ qr/^draft(7|2019-09)$/) {
# spent 124ms making 87311 calls to JSON::Schema::Modern::CORE:qr, avg 1µs/call # spent 116ms making 87311 calls to JSON::Schema::Modern::CORE:regcomp, avg 1µs/call # spent 107ms making 87311 calls to JSON::Schema::Modern::CORE:match, avg 1µs/call # spent 28.4ms making 87311 calls to JSON::Schema::Modern::CORE:sort, avg 325ns/call
604 annotate_self(+{ %$state, keyword => $_, _unknown => 1 }, $schema)
605 foreach sort keys %unknown_keywords;
606 }
607 }
608
60991595419ms return $valid;
610}
611
612has _resource_index => (
613 is => 'bare',
614 isa => HashRef[my $resource_type = Dict[
615 canonical_uri => InstanceOf['Mojo::URL'],
616 path => Str,
617 specification_version => my $spec_version_type = Enum(SPECIFICATION_VERSIONS_SUPPORTED),
618 document => InstanceOf['JSON::Schema::Modern::Document'],
619 # the vocabularies used when evaluating instance data against schema
620 vocabularies => ArrayRef[my $vocabulary_class_type = ClassName->where(q{$_->DOES('JSON::Schema::Modern::Vocabulary')})],
621 configs => HashRef,
622 Slurpy[HashRef[Undef]], # no other fields allowed
623 ]],
624 handles_via => 'Hash',
625 handles => {
626 _add_resources => 'set',
627 _get_resource => 'get',
628 _remove_resource => 'delete',
629 _resource_index => 'elements',
630 _resource_keys => 'keys',
631 _add_resources_unsafe => 'set',
632 _canonical_resources => 'values',
633 _resource_exists => 'exists',
634 },
635 lazy => 1,
636110µs
# spent 3µs within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:636] which was called: # once (3µs+0s) by JSON::Schema::Modern::_assert__resource_index at line 23 of (eval 344)[Sub/Quote.pm:3]
default => sub { {} },
637152µs1418.6ms);
# spent 8.73ms making 1 call to MooX::HandlesVia::has # spent 5.09ms making 1 call to Types::Standard::Dict # spent 3.02ms making 3 calls to Types::Standard::HashRef, avg 1.01ms/call # spent 754µs making 1 call to Types::Standard::ArrayRef # spent 673µs making 2 calls to Types::Standard::InstanceOf, avg 336µs/call # spent 195µs making 1 call to Type::Tiny::where # spent 89µs making 1 call to Types::Standard::Enum # spent 77µs making 1 call to Types::Standard::Slurpy # spent 8µs making 1 call to Types::Standard::Undef # spent 3µs making 1 call to Types::Standard::Str # spent 2µs making 1 call to Types::Standard::ClassName
638
639
# spent 12.0ms (557µs+11.4) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:672] which was called 15 times, avg 799µs/call: # 15 times (557µs+11.4ms) by JSON::Schema::Modern::__ANON__[(eval 346)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Class/Method/Modifiers.pm:89]:1] at line 1 of (eval 329)[Class/Method/Modifiers.pm:89], avg 799µs/call
around _add_resources => sub {
640158µs my ($orig, $self) = (shift, shift);
641
642155µs my @resources;
64315274µs30102µs foreach my $pair (sort { $a->[0] cmp $b->[0] } pairs @_) {
# spent 54µs making 15 calls to List::Util::pairs, avg 4µs/call # spent 48µs making 15 calls to JSON::Schema::Modern::CORE:sort, avg 3µs/call
6442410µs my ($key, $value) = @$pair;
645
64624119µs727.73ms $resource_type->($value); # check type of hash value against Dict
# spent 4.30ms making 24 calls to Sub::Defer::__ANON__[Sub/Defer.pm:178], avg 179µs/call # spent 3.43ms making 48 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 71µs/call
647
6482493µs441.48ms if (my $existing = $self->_get_resource($key)) {
# spent 1.37ms making 24 calls to JSON::Schema::Modern::_get_resource, avg 57µs/call # spent 97µs making 2 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 48µs/call # spent 9µs making 18 calls to JSON::Schema::Modern::CACHED_METASCHEMAS, avg 500ns/call
649 # we allow overwriting canonical_uri = '' to allow for ad hoc evaluation of schemas that
650 # lack all identifiers altogether, but preserve other resources from the original document
651613µs6486µs if ($key ne '') {
# spent 486µs making 6 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 81µs/call
652 next if $existing->{path} eq $value->{path}
653 and $existing->{canonical_uri} eq $value->{canonical_uri}
654 and $existing->{specification_version} eq $value->{specification_version}
655688µs24875µs and refaddr($existing->{document}) == refaddr($value->{document});
# spent 867µs making 12 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 72µs/call # spent 8µs making 12 calls to Scalar::Util::refaddr, avg 667ns/call
656 croak 'uri "'.$key.'" conflicts with an existing schema resource';
657 }
658 }
659 elsif ($self->CACHED_METASCHEMAS->{$key}) {
660 croak 'uri "'.$key.'" conflicts with an existing meta-schema resource';
661 }
662
6631847µs1816µs my $fragment = $value->{canonical_uri}->fragment;
# spent 16µs making 18 calls to Mojo::URL::fragment, avg 889ns/call
664 croak sprintf('canonical_uri cannot contain an empty fragment (%s)', $value->{canonical_uri})
665188µs if defined $fragment and $fragment eq '';
666
667 croak sprintf('canonical_uri cannot contain a plain-name fragment (%s)', $value->{canonical_uri})
6681828µs1810µs if ($fragment // '') =~ m{^[^/]};
# spent 10µs making 18 calls to JSON::Schema::Modern::CORE:match, avg 556ns/call
669
6701827µs18570µs $self->$orig($key, $value);
# spent 570µs making 18 calls to JSON::Schema::Modern::_add_resources, avg 32µs/call
671 }
67215µs1204µs};
# spent 204µs making 1 call to Moo::around
673
674# $vocabulary uri (not its $id!) => [ spec_version, class ]
675has _vocabulary_classes => (
676 is => 'bare',
677 isa => HashRef[
678 Tuple[
679 $spec_version_type,
680 $vocabulary_class_type,
681 ]
682 ],
683 handles_via => 'Hash',
684 handles => {
685 _get_vocabulary_class => 'get',
686 _set_vocabulary_class => 'set',
687 _get_vocabulary_values => 'values',
688 },
689 lazy => 1,
690
# spent 60.3ms (76µs+60.2) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:696] which was called: # once (76µs+60.2ms) by JSON::Schema::Modern::_assert__vocabulary_classes at line 23 of (eval 355)[Sub/Quote.pm:3]
default => sub {
691 +{
6923191µs2460.2ms map { my $class = $_; pairmap { $a => [ $b, $class ] } $class->vocabulary }
# spent 60.2ms making 8 calls to Module::Runtime::use_module, avg 7.52ms/call # spent 29µs making 8 calls to List::Util::pairmap, avg 4µs/call # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::Applicator::vocabulary # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::Content::vocabulary # spent 2µs making 1 call to JSON::Schema::Modern::Vocabulary::Core::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 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 # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::Validation::vocabulary
693 map use_module('JSON::Schema::Modern::Vocabulary::'.$_),
694 qw(Core Applicator Validation FormatAssertion FormatAnnotation Content MetaData Unevaluated)
695 }
696 },
697121µs39.20ms);
# spent 4.48ms making 1 call to Types::Standard::Tuple # spent 4.13ms making 1 call to MooX::HandlesVia::has # spent 585µs making 1 call to Types::Standard::HashRef
698
69932µs
# spent 66.5ms (122µs+66.4) within JSON::Schema::Modern::add_vocabulary which was called: # once (122µs+66.4ms) 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) {
70016µs160.5ms return if grep $_->[1] eq $classname, $self->_get_vocabulary_values;
# spent 60.5ms making 1 call to JSON::Schema::Modern::_get_vocabulary_values
701
70218µs44.47ms $vocabulary_class_type->(use_module($classname));
# spent 3.62ms making 1 call to Module::Runtime::use_module # spent 617µs making 1 call to Sub::Defer::__ANON__[Sub/Defer.pm:178] # spent 229µs making 2 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 114µs/call
703
704 # uri => version, uri => version
705130µs219µs foreach my $pair (pairs $classname->vocabulary) {
# spent 18µs making 1 call to List::Util::pairs # spent 1µs making 1 call to JSON::Schema::Modern::Vocabulary::OpenAPI::vocabulary
70619µs my ($uri_string, $spec_version) = @$pair;
707111µs51.16ms Str->where(q{my $uri = Mojo::URL->new($_); $uri->is_abs && !defined $uri->fragment})->($uri_string);
# spent 522µs making 1 call to Sub::Defer::__ANON__[Sub/Defer.pm:178] # spent 403µs making 1 call to Type::Tiny::where # spent 232µs making 2 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 116µs/call # spent 2µs making 1 call to Types::Standard::Str
708139µs4334µs $spec_version_type->($spec_version);
# spent 300µs making 1 call to Sub::Defer::__ANON__[Sub/Defer.pm:178] # spent 27µs making 1 call to Type::Tiny::DESTROY # spent 7µs making 2 calls to Type::Tiny::__ANON__[Type/Tiny.pm:89], avg 4µs/call
70915µs1116µs $self->_set_vocabulary_class($uri_string => [ $spec_version, $classname ])
# spent 116µs making 1 call to JSON::Schema::Modern::_set_vocabulary_class
710 }
711}
712
713# $schema uri => [ spec_version, [ vocab classes ] ].
714has _metaschema_vocabulary_classes => (
715 is => 'bare',
716 isa => HashRef[
717 Tuple[
718 $spec_version_type,
719 ArrayRef[$vocabulary_class_type],
720 ]
721 ],
722 handles_via => 'Hash',
723 handles => {
724 _get_metaschema_vocabulary_classes => 'get',
725 _set_metaschema_vocabulary_classes => 'set',
726 __all_metaschema_vocabulary_classes => 'values',
727 },
728 lazy => 1,
729
# spent 196µs (46+150) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:738] which was called: # once (46µs+150µs) by JSON::Schema::Modern::_assert__metaschema_vocabulary_classes at line 23 of (eval 360)[Sub/Quote.pm:3]
default => sub {
730115µs7150µs my @modules = map use_module('JSON::Schema::Modern::Vocabulary::'.$_),
# spent 150µs making 7 calls to Module::Runtime::use_module, avg 21µs/call
731 qw(Core Applicator Validation FormatAnnotation Content MetaData Unevaluated);
732 +{
733 'https://json-schema.org/draft/2020-12/schema' => [ 'draft2020-12', [ @modules ] ],
734326µs do { pop @modules; () },
735 'https://json-schema.org/draft/2019-09/schema' => [ 'draft2019-09', \@modules ],
736 'http://json-schema.org/draft-07/schema#' => [ 'draft7', \@modules ],
737 },
738 },
739123µs49.33ms);
# spent 4.58ms making 1 call to MooX::HandlesVia::has # spent 3.32ms making 1 call to Types::Standard::Tuple # spent 1.23ms making 1 call to Types::Standard::HashRef # spent 217µs making 1 call to Types::Standard::ArrayRef
740
741# retrieves metaschema info either from cache or by parsing the schema for vocabularies
742# throws a JSON::Schema::Modern::Result on error
74329721.07ms
# spent 129ms (7.91+121) within JSON::Schema::Modern::_get_metaschema_info which was called 743 times, avg 173µs/call: # 743 times (7.91ms+121ms) by JSON::Schema::Modern::traverse at line 262, avg 173µs/call
sub _get_metaschema_info ($self, $metaschema_uri, $for_canonical_uri) {
744 # check the cache
7457432.54ms743118ms my $metaschema_info = $self->_get_metaschema_vocabulary_classes($metaschema_uri);
# spent 118ms making 743 calls to JSON::Schema::Modern::_get_metaschema_vocabulary_classes, avg 159µs/call
7467432.30ms return @$metaschema_info if $metaschema_info;
747
748 # otherwise, fetch the metaschema and parse its $vocabulary keyword.
749 # we do this by traversing a baby schema with just the $schema keyword.
750110µs10s my $state = $self->traverse({ '$schema' => $metaschema_uri.'' });
# spent 2.72ms making 1 call to JSON::Schema::Modern::traverse, recursion: max depth 1, sum of overlapping time 2.72ms
751 die JSON::Schema::Modern::Result->new(
752 output_format => $self->output_format,
753 valid => JSON::PP::false,
754 errors => [
755 map {
756 my $e = $_;
757 # absolute location is undef iff the location = '/$schema'
758 my $absolute_location = $e->absolute_keyword_location // $for_canonical_uri;
759 JSON::Schema::Modern::Error->new(
760 keyword => $e->keyword eq '$schema' ? '' : $e->keyword,
761 instance_location => $e->instance_location,
762 keyword_location => ($for_canonical_uri->fragment//'').($e->keyword_location =~ s{^/\$schema\b}{}r),
763 length $absolute_location ? ( absolute_keyword_location => $absolute_location ) : (),
764 error => $e->error,
765 )
766 }
767 $state->{errors}->@* ],
768 exception => 1,
76911µs ) if $state->{errors}->@*;
77018µs return ($state->{spec_version}, $state->{vocabularies});
771}
772
773# used for determining a default '$schema' keyword where there is none
77412µs
# spent 93µs (19+74) within JSON::Schema::Modern::BEGIN@774 which was called: # once (19µs+74µs) by OpenAPI::Modern::BEGIN@26 at line 778
use constant METASCHEMA_URIS => {
775 'draft2020-12' => 'https://json-schema.org/draft/2020-12/schema',
776 'draft2019-09' => 'https://json-schema.org/draft/2019-09/schema',
777 'draft7' => 'http://json-schema.org/draft-07/schema#',
7781120µs2167µs};
# spent 93µs making 1 call to JSON::Schema::Modern::BEGIN@774 # spent 74µs making 1 call to constant::import
779
78011µs
# spent 51µs (18+33) within JSON::Schema::Modern::BEGIN@780 which was called: # once (18µs+33µs) by OpenAPI::Modern::BEGIN@26 at line 803
use constant CACHED_METASCHEMAS => {
781 'https://json-schema.org/draft/2020-12/meta/applicator' => 'draft2020-12/meta/applicator.json',
782 'https://json-schema.org/draft/2020-12/meta/content' => 'draft2020-12/meta/content.json',
783 'https://json-schema.org/draft/2020-12/meta/core' => 'draft2020-12/meta/core.json',
784 'https://json-schema.org/draft/2020-12/meta/format-annotation' => 'draft2020-12/meta/format-annotation.json',
785 'https://json-schema.org/draft/2020-12/meta/format-assertion' => 'draft2020-12/meta/format-assertion.json',
786 'https://json-schema.org/draft/2020-12/meta/meta-data' => 'draft2020-12/meta/meta-data.json',
787 'https://json-schema.org/draft/2020-12/meta/unevaluated' => 'draft2020-12/meta/unevaluated.json',
788 'https://json-schema.org/draft/2020-12/meta/validation' => 'draft2020-12/meta/validation.json',
789 'https://json-schema.org/draft/2020-12/output/schema' => 'draft2020-12/output/schema.json',
790 'https://json-schema.org/draft/2020-12/schema' => 'draft2020-12/schema.json',
791
792 'https://json-schema.org/draft/2019-09/meta/applicator' => 'draft2019-09/meta/applicator.json',
793 'https://json-schema.org/draft/2019-09/meta/content' => 'draft2019-09/meta/content.json',
794 'https://json-schema.org/draft/2019-09/meta/core' => 'draft2019-09/meta/core.json',
795 'https://json-schema.org/draft/2019-09/meta/format' => 'draft2019-09/meta/format.json',
796 'https://json-schema.org/draft/2019-09/meta/meta-data' => 'draft2019-09/meta/meta-data.json',
797 'https://json-schema.org/draft/2019-09/meta/validation' => 'draft2019-09/meta/validation.json',
798 'https://json-schema.org/draft/2019-09/output/schema' => 'draft2019-09/output/schema.json',
799 'https://json-schema.org/draft/2019-09/schema' => 'draft2019-09/schema.json',
800
801 # trailing # is omitted because we always cache documents by its canonical (fragmentless) URI
802 'http://json-schema.org/draft-07/schema' => 'draft7/schema.json',
80311.92ms284µs};
# spent 51µs making 1 call to JSON::Schema::Modern::BEGIN@780 # spent 33µs making 1 call to constant::import
804
805# returns the same as _get_resource
80611736922.4ms
# spent 7.07s (200ms+6.87) within JSON::Schema::Modern::_get_or_load_resource which was called 39123 times, avg 181µs/call: # 39123 times (200ms+6.87s) by JSON::Schema::Modern::_fetch_from_uri at line 853, avg 181µs/call
sub _get_or_load_resource ($self, $uri) {
8073912389.7ms391236.80s my $resource = $self->_get_resource($uri);
# spent 6.80s making 39123 calls to JSON::Schema::Modern::_get_resource, avg 174µs/call
8083912376.3ms return $resource if $resource;
809
810860µs161.08ms if (my $local_filename = $self->CACHED_METASCHEMAS->{$uri}) {
# spent 1.07ms making 8 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 134µs/call # spent 7µs making 8 calls to JSON::Schema::Modern::CACHED_METASCHEMAS, avg 875ns/call
811836µs161.35ms my $file = path(dist_dir('JSON-Schema-Modern'), $local_filename);
# spent 1.27ms making 8 calls to File::ShareDir::dist_dir, avg 158µs/call # spent 83µs making 8 calls to Path::Tiny::path, avg 10µs/call
8128323µs24299µs my $schema = $self->_json_decoder->decode($file->slurp_raw);
# spent 238µs making 8 calls to Cpanel::JSON::XS::decode, avg 30µs/call # spent 32µs making 8 calls to JSON::Schema::Modern::_json_decoder, avg 4µs/call # spent 29µs making 8 calls to Path::Tiny::slurp_raw, avg 4µs/call
813865µs858.2ms my $document = JSON::Schema::Modern::Document->new(schema => $schema, evaluator => $self);
# spent 58.2ms making 8 calls to JSON::Schema::Modern::Document::new, avg 7.28ms/call
814
815 # this should be caught by the try/catch in evaluate()
816824µs8254µs die JSON::Schema::Modern::Result->new(
# spent 254µs making 8 calls to JSON::Schema::Modern::Document::has_errors, avg 32µs/call
817 output_format => $self->output_format,
818 valid => 0,
819 errors => [ $document->errors ],
820 exception => 1,
821 ) if $document->has_errors;
822
823 # we have already performed the appropriate collision checks, so we bypass them here
824896µs16372µs $self->_add_resources_unsafe(
# spent 240µs making 8 calls to JSON::Schema::Modern::_add_resources_unsafe, avg 30µs/call # spent 132µs making 8 calls to JSON::Schema::Modern::Document::resource_pairs, avg 16µs/call
825 map +($_->[0] => +{ $_->[1]->%*, document => $document }),
826 $document->resource_pairs
827 );
828
829866µs81.73ms return $self->_get_resource($uri);
# spent 1.73ms making 8 calls to JSON::Schema::Modern::_get_resource, avg 216µs/call
830 }
831
832 # TODO:
833 # - load from network or disk
834
835 return;
836};
837
838# returns information necessary to use a schema found at a particular URI:
839# - a schema (which may not be at a document root)
840# - the canonical uri for that schema,
841# - the JSON::Schema::Modern::Document object that holds that schema
842# - the path relative to the document root for this schema
843# - the specification version that applies to this schema
844# - the vocabularies to use when considering schema keywords
845# - the config overrides to set when considering schema keywords
846# creates a Document and adds it to the resource index, if not already present.
84714064328.7ms
# spent 21.5s (2.44+19.1) within JSON::Schema::Modern::_fetch_from_uri which was called 46881 times, avg 459µs/call: # 41707 times (2.34s+17.9s) by JSON::Schema::Modern::Vocabulary::eval_subschema_at_uri at line 72 of JSON/Schema/Modern/Vocabulary.pm, avg 485µs/call # 2586 times (60.5ms+672ms) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 232 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 283µs/call # 2586 times (45.2ms+527ms) by JSON::Schema::Modern::Vocabulary::Core::_eval_keyword_dynamicRef at line 244 of JSON/Schema/Modern/Vocabulary/Core.pm, avg 221µs/call # once (111µs+565µs) by JSON::Schema::Modern::Vocabulary::Core::_traverse_keyword_schema at line 127 of JSON/Schema/Modern/Vocabulary/Core.pm # once (73µs+400µs) by JSON::Schema::Modern::evaluate at line 318
sub _fetch_from_uri ($self, $uri) {
8484688121.4ms162µs $uri = Mojo::URL->new($uri) if not is_ref($uri);
# spent 62µs making 1 call to Mojo::URL::new
8494688157.4ms4688140.8ms my $fragment = $uri->fragment;
# spent 40.8ms making 46881 calls to Mojo::URL::fragment, avg 870ns/call
850
8514688165.0ms2101818.5ms if (not length($fragment) or $fragment =~ m{^/}) {
# spent 18.5ms making 21018 calls to JSON::Schema::Modern::CORE:match, avg 879ns/call
8523912374.9ms782462.17s my $base = $uri->clone->fragment(undef);
# spent 2.13s making 39123 calls to Mojo::URL::clone, avg 55µs/call # spent 40.0ms making 39123 calls to Mojo::URL::fragment, avg 1µs/call
8533912374.3ms391237.07s if (my $resource = $self->_get_or_load_resource($base)) {
# spent 7.07s making 39123 calls to JSON::Schema::Modern::_get_or_load_resource, avg 181µs/call
85439123133ms39123803ms my $subschema = $resource->{document}->get(my $document_path = $resource->{path}.($fragment//''));
# spent 803ms making 39123 calls to Mojo::JSON::Pointer::get, avg 21µs/call
8553912314.6ms return if not defined $subschema;
8563912317.7ms my $document = $resource->{document};
857 my $closest_resource = first { !length($_->[1]{path}) # document root
85839123219ms || length($document_path)
859 && $document_path =~ m{^\Q$_->[1]{path}\E(?:/|\z)} } # path is above present location
860 sort { length($b->[1]{path}) <=> length($a->[1]{path}) } # sort by length, descending
86139123700ms2957955.75s grep { not length Mojo::URL->new($_->[0])->fragment } # omit anchors
# spent 4.72s making 89213 calls to Mojo::URL::new, avg 53µs/call # spent 795ms making 39123 calls to JSON::Schema::Modern::Document::resource_pairs, avg 20µs/call # spent 109ms making 39123 calls to List::Util::first, avg 3µs/call # spent 64.7ms making 39123 calls to JSON::Schema::Modern::CORE:sort, avg 2µs/call # spent 58.1ms making 89213 calls to Mojo::URL::fragment, avg 651ns/call
862 $document->resource_pairs;
863
864 my $canonical_uri = $closest_resource->[1]{canonical_uri}->clone
86539123144ms782461.54s ->fragment(substr($document_path, length($closest_resource->[1]{path})));
# spent 1.47s making 39123 calls to Mojo::URL::clone, avg 38µs/call # spent 68.8ms making 39123 calls to Mojo::URL::fragment, avg 2µs/call
8663912358.8ms6498642.0ms $canonical_uri->fragment(undef) if not length($canonical_uri->fragment);
# spent 42.0ms making 64986 calls to Mojo::URL::fragment, avg 646ns/call
867 return {
868 schema => $subschema,
869 canonical_uri => $canonical_uri,
870 document => $document,
871 document_path => $document_path,
87239123497ms $resource->%{qw(specification_version vocabularies configs)}, # reference, not copy
873 };
874 }
875 }
876 else { # we are following a URI with a plain-name fragment
877775814.0ms77581.17s if (my $resource = $self->_get_resource($uri)) {
# spent 1.17s making 7758 calls to JSON::Schema::Modern::_get_resource, avg 150µs/call
878775818.4ms7758169ms my $subschema = $resource->{document}->get($resource->{path});
# spent 169ms making 7758 calls to Mojo::JSON::Pointer::get, avg 22µs/call
87977581.86ms return if not defined $subschema;
880 return {
881 schema => $subschema,
882 canonical_uri => $resource->{canonical_uri}->clone, # this is *not* the anchor-containing URI
883 document => $resource->{document},
884 document_path => $resource->{path},
885775862.1ms7758298ms $resource->%{qw(specification_version vocabularies configs)}, # reference, not copy
# spent 298ms making 7758 calls to Mojo::URL::clone, avg 38µs/call
886 };
887 }
888 }
889}
890
891# used for internal encoding as well (when caching serialized schemas)
892has _json_decoder => (
893 is => 'ro',
894 isa => HasMethods[qw(encode decode)],
895 lazy => 1,
89615µs139µs
# spent 45µs (6+39) within JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:896] which was called: # once (6µs+39µs) by JSON::Schema::Modern::_json_decoder at line 23 of (eval 362)[Sub/Quote.pm:3]
default => sub { JSON::MaybeXS->new(allow_nonref => 1, canonical => 1, utf8 => 1, allow_bignum => 1, convert_blessed => 1) },
# spent 39µs making 1 call to JSON::MaybeXS::new
897117µs25.03ms);
# spent 3.07ms making 1 call to Types::Standard::HasMethods # spent 1.96ms making 1 call to MooX::HandlesVia::has
898
899# since media types are case-insensitive, all type names must be foldcased on insertion.
900has _media_type => (
901 is => 'bare',
902 isa => my $media_type_type = Map[Str->where(q{$_ eq CORE::fc($_)}), CodeRef],
903 handles_via => 'Hash',
904 handles => {
905 get_media_type => 'get',
906 add_media_type => 'set',
907 _media_types => 'keys',
908 },
909 lazy => 1,
910 default => sub ($self) {
911 my $_json_media_type = sub ($content_ref) {
912 \ JSON::MaybeXS->new(allow_nonref => 1, utf8 => 0)->decode($content_ref->$*);
913 };
914 +{
915 # note: utf-8 decoding is NOT done, as we can't be sure that's the correct charset!
916 'application/json' => $_json_media_type,
917 'application/schema+json' => $_json_media_type,
918 'application/schema-instance+json' => $_json_media_type,
919 map +($_ => sub ($content_ref) { $content_ref }),
920 qw(text/plain application/octet-stream),
921 };
922 },
923125µs58.46ms);
# spent 4.13ms making 1 call to Types::Standard::Map # spent 4.02ms making 1 call to MooX::HandlesVia::has # spent 304µs making 1 call to Type::Tiny::where # spent 4µs making 1 call to Types::Standard::Str # spent 2µs making 1 call to Types::Standard::CodeRef
924
925# get_media_type('TExT/bloop') will match an entry for 'text/*' or '*/*'
926# TODO: support queries for application/schema+json to match entry of application/json
927around get_media_type => sub ($orig, $self, $type) {
928 my $mt = $self->$orig(fc $type);
929 return $mt if $mt;
930
931 return $self->$orig((first { m{([^/]+)/\*$} && fc($type) =~ m{^\Q$1\E/[^/]+$} } $self->_media_types)
932 // '*/*');
93316µs1249µs};
# spent 249µs making 1 call to Moo::around
934
93513µs1120µsbefore add_media_type => sub ($self, $type, $sub) { $media_type_type->({ $type => $sub }) };
# spent 120µs making 1 call to Moo::before
936
937has _encoding => (
938 is => 'bare',
939 isa => HashRef[CodeRef],
940 handles_via => 'Hash',
941 handles => {
942 get_encoding => 'get',
943 add_encoding => 'set',
944 },
945 lazy => 1,
946 default => sub ($self) {
947 +{
948 identity => sub ($content_ref) { $content_ref },
949 base64 => sub ($content_ref) {
950 die "invalid characters in base64 string"
951 if $content_ref->$* =~ m{[^A-Za-z0-9+/=]} or $content_ref->$* =~ m{=(?=[^=])};
952 require MIME::Base64; \ MIME::Base64::decode($content_ref->$*);
953 },
954 };
955 },
956112µs31.90ms);
# spent 1.63ms making 1 call to MooX::HandlesVia::has # spent 263µs making 1 call to Types::Standard::HashRef # spent 3µs making 1 call to Types::Standard::CodeRef
957
958sub FREEZE ($self, $serializer) {
959 my $data = +{ %$self };
960 # Cpanel::JSON::XS doesn't serialize: https://github.com/Sereal/Sereal/issues/266
961 # coderefs can't serialize cleanly and must be re-added by the user.
962 delete $data->@{qw(_json_decoder _format_validations _media_type _encoding)};
963 return $data;
964}
965
966sub THAW ($class, $serializer, $data) {
967 my $self = bless($data, $class);
968
969 # load all vocabulary classes
970 require_module($_) foreach uniq map $_->{vocabularies}->@*, $self->_canonical_resources;
971
972 return $self;
973}
974
975171µs1;
976
9771336µs11.83ms__END__
 
# spent 16µs within JSON::Schema::Modern::CACHED_METASCHEMAS which was called 26 times, avg 615ns/call: # 18 times (9µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:672] at line 648, avg 500ns/call # 8 times (7µs+0s) by JSON::Schema::Modern::_get_or_load_resource at line 810, avg 875ns/call
sub JSON::Schema::Modern::CACHED_METASCHEMAS; # xsub
# spent 389ms within JSON::Schema::Modern::CORE:match which was called 2123434 times, avg 183ns/call: # 2015087 times (264ms+0s) by JSON::Schema::Modern::_eval_subschema at line 525, avg 131ns/call # 87311 times (107ms+0s) by JSON::Schema::Modern::_eval_subschema at line 603, avg 1µs/call # 21018 times (18.5ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 851, avg 879ns/call # 18 times (10µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:672] at line 668, avg 556ns/call
sub JSON::Schema::Modern::CORE:match; # opcode
# spent 124ms within JSON::Schema::Modern::CORE:qr which was called 87311 times, avg 1µs/call: # 87311 times (124ms+0s) by JSON::Schema::Modern::_eval_subschema at line 603, avg 1µs/call
sub JSON::Schema::Modern::CORE:qr; # opcode
# spent 116ms within JSON::Schema::Modern::CORE:regcomp which was called 87311 times, avg 1µs/call: # 87311 times (116ms+0s) by JSON::Schema::Modern::_eval_subschema at line 603, avg 1µs/call
sub JSON::Schema::Modern::CORE:regcomp; # opcode
# spent 96.6ms within JSON::Schema::Modern::CORE:sort which was called 128937 times, avg 750ns/call: # 87311 times (28.4ms+0s) by JSON::Schema::Modern::_eval_subschema at line 603, avg 325ns/call # 39123 times (64.7ms+0s) by JSON::Schema::Modern::_fetch_from_uri at line 861, avg 2µs/call # 2488 times (3.52ms+0s) by JSON::Schema::Modern::_traverse_subschema at line 503, avg 1µs/call # 15 times (48µs+0s) by JSON::Schema::Modern::__ANON__[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/Schema/Modern.pm:672] at line 643, avg 3µs/call
sub JSON::Schema::Modern::CORE:sort; # opcode
# spent 32µs within JSON::Schema::Modern::CORE:subst which was called 126 times, avg 254ns/call: # 61 times (10µs+0s) by JSON::Schema::Modern::_traverse_subschema at line 471, avg 164ns/call # 58 times (17µs+0s) by JSON::Schema::Modern::_eval_subschema at line 559, avg 293ns/call # 7 times (5µs+0s) by JSON::Schema::Modern::evaluate at line 361, avg 714ns/call
sub JSON::Schema::Modern::CORE:subst; # opcode
# spent 11µs within JSON::Schema::Modern::METASCHEMA_URIS which was called 15 times, avg 733ns/call: # 15 times (11µs+0s) by JSON::Schema::Modern::traverse at line 262, avg 733ns/call
sub JSON::Schema::Modern::METASCHEMA_URIS; # xsub
# spent 1µs within JSON::Schema::Modern::SPECIFICATION_VERSION_DEFAULT which was called: # once (1µs+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 1µs within JSON::Schema::Modern::__ANON__ which was called 2 times, avg 500ns/call: # once (1µs+0s) by JSON::Schema::Modern::BEGIN@34 at line 34 # once (0s+0s) by JSON::Schema::Modern::BEGIN@33 at line 33
sub JSON::Schema::Modern::__ANON__; # xsub