| Filename | /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern.pm |
| Statements | Executed 17973735 statements in 10.6s |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 90777 | 3 | 2 | 8.56s | 64.4s | JSON::Schema::Modern::_eval_subschema (recurses: max depth 74, inclusive time 1441s) |
| 46451 | 5 | 3 | 1.82s | 17.2s | JSON::Schema::Modern::_fetch_from_uri |
| 2030304 | 4 | 1 | 257ms | 257ms | JSON::Schema::Modern::CORE:match (opcode) |
| 2833 | 5 | 2 | 178ms | 578ms | JSON::Schema::Modern::_traverse_subschema (recurses: max depth 6, inclusive time 678ms) |
| 38783 | 1 | 1 | 151ms | 5.70s | JSON::Schema::Modern::_get_or_load_resource |
| 1 | 1 | 1 | 150ms | 64.6s | JSON::Schema::Modern::evaluate |
| 53564 | 4 | 1 | 57.9ms | 57.9ms | JSON::Schema::Modern::CORE:sort (opcode) |
| 741 | 4 | 3 | 24.2ms | 1.12s | JSON::Schema::Modern::traverse (recurses: max depth 1, inclusive time 1.66ms) |
| 12306 | 1 | 1 | 17.4ms | 17.4ms | JSON::Schema::Modern::CORE:qr (opcode) |
| 12306 | 1 | 1 | 15.5ms | 15.5ms | JSON::Schema::Modern::CORE:regcomp (opcode) |
| 1 | 1 | 1 | 9.56ms | 12.7ms | JSON::Schema::Modern::BEGIN@25 |
| 1 | 1 | 1 | 6.27ms | 65.2ms | JSON::Schema::Modern::BEGIN@31 |
| 741 | 1 | 1 | 4.09ms | 90.3ms | JSON::Schema::Modern::_get_metaschema_info (recurses: max depth 1, inclusive time 25µs) |
| 1 | 1 | 1 | 3.36ms | 5.69ms | JSON::Schema::Modern::BEGIN@36 |
| 1 | 1 | 1 | 3.12ms | 31.8ms | JSON::Schema::Modern::BEGIN@27 |
| 1 | 1 | 1 | 3.07ms | 181ms | JSON::Schema::Modern::BEGIN@23 |
| 1 | 1 | 1 | 3.04ms | 3.17ms | JSON::Schema::Modern::BEGIN@28 |
| 1 | 1 | 1 | 2.25ms | 28.0ms | JSON::Schema::Modern::BEGIN@34 |
| 1 | 1 | 1 | 2.12ms | 19.3ms | JSON::Schema::Modern::BEGIN@18 |
| 1 | 1 | 1 | 1.57ms | 38.1ms | JSON::Schema::Modern::BEGIN@35 |
| 1 | 1 | 1 | 1.56ms | 1.77ms | JSON::Schema::Modern::BEGIN@30 |
| 1 | 1 | 1 | 1.26ms | 5.65ms | JSON::Schema::Modern::BEGIN@29 |
| 1 | 1 | 1 | 1.20ms | 68.3ms | JSON::Schema::Modern::BEGIN@33 |
| 9 | 3 | 2 | 1.11ms | 183ms | JSON::Schema::Modern::add_schema |
| 15 | 1 | 1 | 704µs | 11.6ms | JSON::Schema::Modern::__ANON__[:685] |
| 1 | 1 | 1 | 84µs | 57.9ms | JSON::Schema::Modern::add_vocabulary |
| 1 | 1 | 1 | 76µs | 51.6ms | JSON::Schema::Modern::__ANON__[:709] |
| 1 | 1 | 1 | 64µs | 730µs | JSON::Schema::Modern::__ANON__[:124] |
| 125 | 3 | 1 | 30µs | 30µs | JSON::Schema::Modern::CORE:subst (opcode) |
| 26 | 2 | 1 | 20µs | 20µs | JSON::Schema::Modern::CACHED_METASCHEMAS (xsub) |
| 1 | 1 | 1 | 18µs | 101µs | JSON::Schema::Modern::__ANON__[:751] |
| 1 | 1 | 1 | 14µs | 632µs | JSON::Schema::Modern::BEGIN@12 |
| 1 | 1 | 1 | 13µs | 454µs | JSON::Schema::Modern::BEGIN@37 |
| 1 | 1 | 1 | 13µs | 29µs | JSON::Schema::Modern::BEGIN@793 |
| 1 | 1 | 1 | 13µs | 14µs | OpenAPI::Modern::BEGIN@1 |
| 1 | 1 | 1 | 12µs | 45µs | JSON::Schema::Modern::BEGIN@20 |
| 1 | 1 | 1 | 12µs | 120µs | JSON::Schema::Modern::BEGIN@46 |
| 1 | 1 | 1 | 12µs | 60µs | JSON::Schema::Modern::BEGIN@787 |
| 15 | 1 | 1 | 12µs | 12µs | JSON::Schema::Modern::METASCHEMA_URIS (xsub) |
| 1 | 1 | 1 | 9µs | 36µs | JSON::Schema::Modern::BEGIN@14 |
| 1 | 1 | 1 | 8µs | 8µs | JSON::Schema::Modern::BEGIN@10 |
| 1 | 1 | 1 | 8µs | 26µs | JSON::Schema::Modern::BEGIN@21 |
| 1 | 1 | 1 | 8µs | 80µs | JSON::Schema::Modern::BEGIN@24 |
| 1 | 1 | 1 | 8µs | 51µs | JSON::Schema::Modern::BEGIN@32 |
| 1 | 1 | 1 | 8µs | 37µs | JSON::Schema::Modern::BEGIN@47 |
| 1 | 1 | 1 | 8µs | 9µs | JSON::Schema::Modern::__ANON__[:90] |
| 1 | 1 | 1 | 7µs | 177µs | JSON::Schema::Modern::BEGIN@11 |
| 1 | 1 | 1 | 7µs | 18µs | JSON::Schema::Modern::BEGIN@17 |
| 1 | 1 | 1 | 7µs | 10µs | JSON::Schema::Modern::__ANON__[:133] |
| 1 | 1 | 1 | 6µs | 87µs | JSON::Schema::Modern::BEGIN@13 |
| 1 | 1 | 1 | 6µs | 18µs | JSON::Schema::Modern::BEGIN@15 |
| 1 | 1 | 1 | 6µs | 51µs | JSON::Schema::Modern::BEGIN@26 |
| 1 | 1 | 1 | 6µs | 47µs | JSON::Schema::Modern::__ANON__[:909] |
| 1 | 1 | 1 | 5µs | 11µs | JSON::Schema::Modern::BEGIN@16 |
| 1 | 1 | 1 | 5µs | 17µs | JSON::Schema::Modern::BEGIN@19 |
| 1 | 1 | 1 | 5µs | 19µs | OpenAPI::Modern::BEGIN@2 |
| 1 | 1 | 1 | 4µs | 7µs | JSON::Schema::Modern::__ANON__[:69] |
| 1 | 1 | 1 | 3µs | 12µs | JSON::Schema::Modern::BEGIN@22 |
| 1 | 1 | 1 | 2µs | 2µs | JSON::Schema::Modern::__ANON__[:649] |
| 1 | 1 | 1 | 1µs | 1µs | JSON::Schema::Modern::__ANON__[:121] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::FREEZE |
| 1 | 1 | 1 | 0s | 0s | JSON::Schema::Modern::SPECIFICATION_VERSION_DEFAULT (xsub) |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::THAW |
| 2 | 2 | 1 | 0s | 0s | JSON::Schema::Modern::__ANON__ (xsub) |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:177] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:53] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:55] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:56] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:705] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:872] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:928] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:932] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:935] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:943] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:945] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:947] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:960] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:965] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::__ANON__[:967] |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::evaluate_json_string |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::get |
| 0 | 0 | 0 | 0s | 0s | JSON::Schema::Modern::validate_schema |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | 2 | 17µs | 2 | 15µ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 # spent 14µs making 1 call to OpenAPI::Modern::BEGIN@1
# spent 1µs making 1 call to strict::import |
| 2 | 2 | 41µs | 2 | 33µ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 # spent 19µs making 1 call to OpenAPI::Modern::BEGIN@2
# spent 14µs making 1 call to warnings::import |
| 3 | package 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 | |||||
| 8 | 1 | 1µs | our $VERSION = '0.559'; | ||
| 9 | |||||
| 10 | 2 | 22µs | 1 | 8µ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 # spent 8µs making 1 call to JSON::Schema::Modern::BEGIN@10 |
| 11 | 2 | 21µs | 2 | 347µ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 # spent 177µs making 1 call to JSON::Schema::Modern::BEGIN@11
# spent 170µs making 1 call to Moo::import |
| 12 | 3 | 25µs | 3 | 1.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 # 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 |
| 13 | 2 | 27µs | 2 | 168µ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 # spent 87µs making 1 call to JSON::Schema::Modern::BEGIN@13
# spent 81µs making 1 call to experimental::import |
| 14 | 2 | 22µs | 2 | 44µ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 # spent 36µs making 1 call to JSON::Schema::Modern::BEGIN@14
# spent 8µs making 1 call to if::import |
| 15 | 2 | 16µs | 2 | 19µ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 # spent 18µs making 1 call to JSON::Schema::Modern::BEGIN@15
# spent 1µs making 1 call to if::unimport |
| 16 | 2 | 14µs | 2 | 13µ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 # spent 11µs making 1 call to JSON::Schema::Modern::BEGIN@16
# spent 2µs making 1 call to if::unimport |
| 17 | 2 | 15µs | 2 | 20µ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 # spent 18µs making 1 call to JSON::Schema::Modern::BEGIN@17
# spent 2µs making 1 call to if::unimport |
| 18 | 2 | 1.22ms | 2 | 19.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 # spent 19.3ms making 1 call to JSON::Schema::Modern::BEGIN@18
# spent 24µs making 1 call to Exporter::import |
| 19 | 2 | 23µs | 2 | 29µ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 # spent 17µs making 1 call to JSON::Schema::Modern::BEGIN@19
# spent 12µs making 1 call to Exporter::import |
| 20 | 3 | 29µs | 3 | 59µ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 # 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 |
| 21 | 3 | 24µs | 3 | 44µ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 # 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 |
| 22 | 2 | 12µs | 2 | 21µ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 # spent 12µs making 1 call to JSON::Schema::Modern::BEGIN@22
# spent 9µs making 1 call to Exporter::import |
| 23 | 2 | 1.65ms | 2 | 181ms | # 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 # spent 181ms making 1 call to JSON::Schema::Modern::BEGIN@23
# spent 3µs making 1 call to Mojo::Base::import |
| 24 | 2 | 19µs | 2 | 152µ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 # spent 80µs making 1 call to JSON::Schema::Modern::BEGIN@24
# spent 72µs making 1 call to Exporter::import |
| 25 | 2 | 1.02ms | 2 | 12.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 # spent 12.7ms making 1 call to JSON::Schema::Modern::BEGIN@25
# spent 23µs making 1 call to Exporter::import |
| 26 | 2 | 20µs | 2 | 96µ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 # spent 51µs making 1 call to JSON::Schema::Modern::BEGIN@26
# spent 45µs making 1 call to Exporter::import |
| 27 | 2 | 1.53ms | 2 | 31.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 # spent 31.8ms making 1 call to JSON::Schema::Modern::BEGIN@27
# spent 22µs making 1 call to Exporter::import |
| 28 | 2 | 1.82ms | 2 | 3.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 # spent 3.17ms making 1 call to JSON::Schema::Modern::BEGIN@28
# spent 13µs making 1 call to Module::Runtime::import |
| 29 | 3 | 1.13ms | 3 | 9.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 # 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 |
| 30 | 2 | 1.14ms | 2 | 1.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 # spent 1.77ms making 1 call to JSON::Schema::Modern::BEGIN@30
# spent 80µs making 1 call to MooX::HandlesVia::import |
| 31 | 3 | 1.33ms | 3 | 66.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 # 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 |
| 32 | 2 | 20µs | 2 | 94µ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 # spent 51µs making 1 call to JSON::Schema::Modern::BEGIN@32
# spent 43µs making 1 call to Feature::Compat::Try::import |
| 33 | 2 | 546µs | 2 | 68.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 # spent 68.3ms making 1 call to JSON::Schema::Modern::BEGIN@33
# spent 0s making 1 call to JSON::Schema::Modern::__ANON__ |
| 34 | 2 | 634µs | 2 | 28.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 # spent 28.0ms making 1 call to JSON::Schema::Modern::BEGIN@34
# spent 0s making 1 call to JSON::Schema::Modern::__ANON__ |
| 35 | 2 | 367µs | 2 | 38.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 # spent 38.1ms making 1 call to JSON::Schema::Modern::BEGIN@35
# spent 4µs making 1 call to Mojo::Base::import |
| 36 | 2 | 583µs | 2 | 5.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 # spent 5.69ms making 1 call to JSON::Schema::Modern::BEGIN@36
# spent 104µs making 1 call to Exporter::import |
| 37 | 2 | 83µs | 2 | 895µ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 # spent 454µs making 1 call to JSON::Schema::Modern::BEGIN@37
# spent 441µs making 1 call to namespace::clean::import |
| 38 | |||||
| 39 | 1 | 3µs | our @CARP_NOT = qw( | ||
| 40 | JSON::Schema::Modern::Document | ||||
| 41 | JSON::Schema::Modern::Vocabulary | ||||
| 42 | JSON::Schema::Modern::Vocabulary::Applicator | ||||
| 43 | OpenAPI::Modern | ||||
| 44 | ); | ||||
| 45 | |||||
| 46 | 2 | 34µs | 2 | 228µ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 # spent 120µs making 1 call to JSON::Schema::Modern::BEGIN@46
# spent 108µs making 1 call to constant::import |
| 47 | 2 | 3.84ms | 2 | 66µ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 # spent 37µs making 1 call to JSON::Schema::Modern::BEGIN@47
# spent 29µs making 1 call to constant::import |
| 48 | |||||
| 49 | has 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 | }, | ||||
| 57 | 1 | 7µs | 2 | 1.58ms | ); # spent 895µs making 1 call to MooX::HandlesVia::has
# spent 687µs making 1 call to Types::Standard::Enum |
| 58 | |||||
| 59 | 1 | 16µs | 3 | 428µs | has 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 | |||||
| 65 | has short_circuit => ( | ||||
| 66 | is => 'ro', | ||||
| 67 | isa => Bool, | ||||
| 68 | lazy => 1, | ||||
| 69 | 1 | 54µs | 1 | 3µ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] # spent 3µs making 1 call to JSON::Schema::Modern::output_format |
| 70 | 1 | 4µs | 2 | 618µs | ); # spent 617µs making 1 call to MooX::HandlesVia::has
# spent 1µs making 1 call to Types::Standard::Bool |
| 71 | |||||
| 72 | 1 | 2µs | 2 | 366µs | has 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 | |||||
| 78 | 1 | 2µs | 2 | 284µs | has 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 | |||||
| 84 | has 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 | ||||
| 90 | 1 | 4µs | 1 | 1µ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] # spent 1µs making 1 call to JSON::Schema::Modern::specification_version |
| 91 | 1 | 4µs | 2 | 581µs | ); # spent 581µs making 1 call to MooX::HandlesVia::has
# spent 0s making 1 call to Types::Standard::Bool |
| 92 | |||||
| 93 | 1 | 0s | 2 | 363µs | has 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 | |||||
| 98 | 1 | 3µs | 2 | 343µs | has 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 | |||||
| 103 | 1 | 1µs | 2 | 332µs | has 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 | |||||
| 108 | has _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, | ||||
| 121 | 1 | 2µ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] | ||
| 122 | 1 | 43µs | 45 | 20.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 | |||||
| 124 | 5 | 50µs | 17 | 810µ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] # 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 | |||||
| 126 | 4 | 1µ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] | ||
| 127 | 1 | 2µs | 1 | 3µ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' | ||||
| 130 | 1 | 1µs | and ($args->{specification_version}//'') ne 'draft2019-09'; | ||
| 131 | |||||
| 132 | 1 | 2µs | return $args; | ||
| 133 | 1 | 4µs | 1 | 192µ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 | ||||
| 136 | 9 | 7µs | croak 'insufficient arguments' if @_ < 2; | ||
| 137 | 9 | 13µs | my $self = shift; | ||
| 138 | |||||
| 139 | # TODO: resolve $uri against $self->base_uri | ||||
| 140 | 9 | 53µs | 10 | 606µ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 | |||||
| 143 | 9 | 7µs | 9 | 4µ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 | |||||
| 145 | 9 | 9µ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) | ||||
| 152 | 9 | 107µs | 21 | 149ms | 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 | |||||
| 159 | 9 | 48µs | 9 | 254µ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 | |||||
| 169 | 9 | 333µs | 189 | 235µ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 |
| 170 | 7 | 8.41ms | 35 | 8.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 | |||||
| 173 | 7 | 178µs | 21 | 495µ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 |
| 174 | 29 | 183µs | 61 | 190µ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)); | ||||
| 176 | 29 | 20µ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 { | ||||
| 182 | 7 | 692µs | 14 | 8.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 | |||||
| 187 | 9 | 61µs | 9 | 1.17ms | if ("$uri") { # spent 1.17ms making 9 calls to Mojo::URL::__ANON__[Mojo/URL.pm:3], avg 130µs/call |
| 188 | 8 | 29µs | 16 | 1.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}, | ||||
| 196 | 8 | 50µs | 16 | 4.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 | |||||
| 199 | 9 | 52µs | return $document; | ||
| 200 | } | ||||
| 201 | |||||
| 202 | sub 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. | ||||
| 233 | 2964 | 673µ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 | ||
| 234 | # Note: the starting position is not guaranteed to be at the root of the $document. | ||||
| 235 | 741 | 1.20ms | 741 | 214ms | my $initial_uri = Mojo::URL->new($config_override->{initial_schema_uri} // ''); # spent 214ms making 741 calls to Mojo::URL::new, avg 288µs/call |
| 236 | 741 | 598µs | my $initial_path = $config_override->{traversed_schema_path} // ''; | ||
| 237 | 741 | 2.22ms | 741 | 1.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} // {}, | ||||
| 250 | 741 | 5.08ms | 741 | 56.6ms | evaluator => $self, # spent 56.6ms making 741 calls to Mojo::URL::new, avg 76µs/call |
| 251 | traverse => 1, | ||||
| 252 | }; | ||||
| 253 | |||||
| 254 | 741 | 375µ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) | ||||
| 258 | 741 | 1.47ms | 755 | 156ms | // $state->{initial_schema_uri}); # spent 156ms making 755 calls to Mojo::URL::new, avg 206µs/call |
| 259 | 741 | 729µs | 756 | 369µ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( | ||||
| 263 | 741 | 4.61ms | 756 | 90.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 | |||||
| 281 | 741 | 307µs | try { | ||
| 282 | 741 | 1.75ms | 741 | 578ms | $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 | |||||
| 294 | 741 | 391µs | delete $state->{traverse}; | ||
| 295 | 741 | 2.46ms | return $state; | ||
| 296 | } | ||||
| 297 | |||||
| 298 | # the actual runtime evaluation of the schema against input data. | ||||
| 299 | 5 | 0s | # 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 | ||
| 300 | 1 | 1µs | croak 'evaluate called in void context' if not defined wantarray; | ||
| 301 | |||||
| 302 | 1 | 1µs | my $initial_path = $config_override->{traversed_schema_path} // ''; | ||
| 303 | 1 | 1µs | 1 | 73µ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 = { | ||||
| 306 | 1 | 4µs | 1 | 2µ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' | ||||
| 315 | 1 | 1µs | foreach qw(output_format specification_version); | ||
| 316 | |||||
| 317 | 1 | 0s | my $valid; | ||
| 318 | 1 | 0s | try { | ||
| 319 | 1 | 0s | my $schema_info; | ||
| 320 | |||||
| 321 | 1 | 3µs | 1 | 8µ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] |
| 322 | 1 | 1µs | 1 | 304µs | $schema_info = $self->_fetch_from_uri($schema_reference); # spent 304µs making 1 call to JSON::Schema::Modern::_fetch_from_uri |
| 323 | 1 | 1µs | 1 | 61µ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 | |||||
| 339 | 1 | 0s | 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 { | ||||
| 357 | 7 | 27µs | 6 | 91µ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 |
| 358 | 6 | 2µs | defined $val ? ( $_ => $val ) : () | ||
| 359 | } qw(validate_formats validate_content_schemas short_circuit collect_annotations scalarref_booleans strict)), | ||||
| 360 | }; | ||||
| 361 | |||||
| 362 | 1 | 1µs | if ($state->{validate_formats}) { | ||
| 363 | $state->{vocabularies} = [ | ||||
| 364 | map s/^JSON::Schema::Modern::Vocabulary::Format\KAnnotation$/Assertion/r, $state->{vocabularies}->@* | ||||
| 365 | 1 | 11µs | 7 | 6µs | ]; # spent 6µs making 7 calls to JSON::Schema::Modern::CORE:subst, avg 857ns/call |
| 366 | 1 | 0s | 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. | ||||
| 372 | 1 | 1µs | $state->{collect_annotations} = ($state->{collect_annotations}//0) << 8; | ||
| 373 | |||||
| 374 | 1 | 14µs | 1 | 64.4s | $valid = $self->_eval_subschema($data, $schema_info->{schema}, $state); # spent 64.4s making 1 call to JSON::Schema::Modern::_eval_subschema |
| 375 | 1 | 18µ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 | |||||
| 389 | 1 | 12µ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}) : ()) | ||||
| 398 | 1 | 149ms | 3 | 9.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 | |||||
| 402 | sub 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 | |||||
| 411 | sub 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 } | ||||
| 426 | 1 | 9µs | my %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. | ||||
| 455 | 1 | 0s | our $vocabulary_cache = {}; | ||
| 456 | |||||
| 457 | 11332 | 1.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 | ||
| 458 | 2833 | 951µs | delete $state->{keyword}; | ||
| 459 | |||||
| 460 | return E($state, 'EXCEPTION: maximum traversal depth exceeded') | ||||
| 461 | 2833 | 3.33ms | 2833 | 3.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 | |||||
| 463 | 2833 | 3.27ms | 2833 | 7.19ms | my $schema_type = get_type($schema); # spent 7.19ms making 2833 calls to JSON::Schema::Modern::Utilities::get_type, avg 3µs/call |
| 464 | 2833 | 1.23ms | return 1 if $schema_type eq 'boolean'; | ||
| 465 | |||||
| 466 | 2463 | 623µs | return E($state, 'invalid schema type: %s', $schema_type) if $schema_type ne 'object'; | ||
| 467 | |||||
| 468 | 2463 | 1.01ms | return 1 if not keys %$schema; | ||
| 469 | |||||
| 470 | 2460 | 406µs | my $valid = 1; | ||
| 471 | 2460 | 7.70ms | my %unknown_keywords = map +($_ => undef), keys %$schema; | ||
| 472 | # we must check the array length on every iteration because some keywords can change it! | ||||
| 473 | 2460 | 9.21ms | for (my $idx = 0; $idx <= $state->{vocabularies}->$#*; ++$idx) { | ||
| 474 | 19210 | 5.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}) | ||||
| 480 | 19210 | 9.90ms | 130 | 113µ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 | |||||
| 482 | 19210 | 21.9ms | foreach my $keyword_tuple ($keyword_list->@*) { | ||
| 483 | 148180 | 28.8ms | my ($keyword, $sub) = $keyword_tuple->@*; | ||
| 484 | 148180 | 22.4ms | next if not exists $schema->{$keyword}; | ||
| 485 | |||||
| 486 | # keywords adjacent to $ref are not evaluated before draft2019-09 | ||||
| 487 | 4325 | 1.52ms | next if $keyword ne '$ref' and exists $schema->{'$ref'} and $state->{spec_version} eq 'draft7'; | ||
| 488 | |||||
| 489 | 4325 | 1.14ms | delete $unknown_keywords{$keyword}; | ||
| 490 | 4325 | 1.19ms | $state->{keyword} = $keyword; | ||
| 491 | |||||
| 492 | 4325 | 6.03ms | 4325 | 989ms | 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 | |||||
| 498 | 4325 | 2.84ms | if (my $callback = $state->{callbacks}{$keyword}) { | ||
| 499 | $callback->($schema, $state); | ||||
| 500 | } | ||||
| 501 | } | ||||
| 502 | } | ||||
| 503 | |||||
| 504 | 2460 | 788µs | delete $state->{keyword}; | ||
| 505 | |||||
| 506 | 2460 | 3.50ms | 2460 | 3.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 | ||||
| 512 | 2460 | 10.9ms | 2460 | 2.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 |
| 513 | 14760 | 1.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 | |||||
| 525 | 2460 | 4.69ms | return $valid; | ||
| 526 | } | ||||
| 527 | |||||
| 528 | 453885 | 59.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 | ||
| 529 | 90777 | 20.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 | ||||
| 533 | 90777 | 78.1ms | $state->{dynamic_scope} = [ ($state->{dynamic_scope}//[])->@* ]; | ||
| 534 | 90777 | 2.05s | 1997092 | 227ms | 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') | ||||
| 537 | 90777 | 137ms | 90777 | 113ms | if $state->{depth}++ > $self->max_traversal_depth; # spent 113ms making 90777 calls to JSON::Schema::Modern::max_traversal_depth, avg 1µs/call |
| 538 | |||||
| 539 | 90777 | 97.7ms | 90777 | 130ms | my $schema_type = get_type($schema); # spent 130ms making 90777 calls to JSON::Schema::Modern::Utilities::get_type, avg 1µs/call |
| 540 | 90777 | 24.7ms | return $schema || E($state, 'subschema is false') if $schema_type eq 'boolean'; | ||
| 541 | |||||
| 542 | # this should never happen, due to checks in traverse | ||||
| 543 | 90777 | 22.7ms | abort($state, 'invalid schema type: %s', $schema_type) if $schema_type ne 'object'; | ||
| 544 | |||||
| 545 | 90777 | 27.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. | ||||
| 549 | 90777 | 77.9ms | 90777 | 2.06s | my $canonical_uri = canonical_uri($state); # spent 2.06s making 90777 calls to JSON::Schema::Modern::Utilities::canonical_uri, avg 23µs/call |
| 550 | 90777 | 39.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 $_, | ||||
| 553 | 90777 | 343ms | 90777 | 7.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 |
| 554 | 90777 | 266ms | 90777 | 6.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 | |||||
| 556 | 90777 | 22.7ms | my $valid = 1; | ||
| 557 | 90777 | 263ms | my %unknown_keywords = map +($_ => undef), keys %$schema; | ||
| 558 | 90777 | 31.7ms | my $orig_annotations = $state->{annotations}; | ||
| 559 | 90777 | 28.0ms | $state->{annotations} = []; | ||
| 560 | 90777 | 14.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. | ||||
| 564 | 90777 | 62.8ms | $state->{collect_annotations} |= 0+(exists $schema->{unevaluatedItems} || exists $schema->{unevaluatedProperties}); | ||
| 565 | |||||
| 566 | ALL_KEYWORDS: | ||||
| 567 | 90777 | 62.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}) | ||||
| 572 | 631747 | 350ms | 121 | 162µ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 | |||||
| 574 | 631747 | 805ms | foreach my $keyword_tuple ($keyword_list->@*) { | ||
| 575 | 5161367 | 1.02s | my ($keyword, $sub) = $keyword_tuple->@*; | ||
| 576 | 5161367 | 795ms | next if not exists $schema->{$keyword}; | ||
| 577 | |||||
| 578 | # keywords adjacent to $ref are not evaluated before draft2019-09 | ||||
| 579 | 304999 | 76.4ms | next if $keyword ne '$ref' and exists $schema->{'$ref'} and $state->{spec_version} eq 'draft7'; | ||
| 580 | |||||
| 581 | 304999 | 76.6ms | delete $unknown_keywords{$keyword}; | ||
| 582 | 304999 | 73.5ms | $state->{keyword} = $keyword; | ||
| 583 | |||||
| 584 | 304999 | 69.6ms | if ($sub) { | ||
| 585 | 200548 | 51.0ms | my $error_count = $state->{errors}->@*; | ||
| 586 | |||||
| 587 | 200548 | 301ms | 200548 | 393s | 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.')' | ||||
| 589 | 4262 | 2.35ms | if $error_count == $state->{errors}->@*; | ||
| 590 | 4262 | 1.07ms | $valid = 0; | ||
| 591 | |||||
| 592 | 4262 | 2.28ms | last ALL_KEYWORDS if $state->{short_circuit}; | ||
| 593 | 3339 | 2.08ms | next; | ||
| 594 | } | ||||
| 595 | } | ||||
| 596 | |||||
| 597 | 300737 | 169ms | 41271 | 114ms | if (my $callback = $state->{callbacks}{$keyword}) { # spent 106ms making 38715 calls to JSON::Schema::Modern::Document::OpenAPI::__ANON__[JSON/Schema/Modern/Document/OpenAPI.pm:144], avg 3µs/call
# spent 8.57ms making 2556 calls to JSON::Schema::Modern::Document::OpenAPI::__ANON__[JSON/Schema/Modern/Document/OpenAPI.pm:140], avg 3µs/call |
| 598 | $callback->($data, $schema, $state); | ||||
| 599 | } | ||||
| 600 | |||||
| 601 | 300737 | 231ms | push @new_annotations, $state->{annotations}->@[$#new_annotations+1 .. $state->{annotations}->$#*]; | ||
| 602 | } | ||||
| 603 | } | ||||
| 604 | |||||
| 605 | 90777 | 43.7ms | delete $state->{keyword}; | ||
| 606 | |||||
| 607 | 90777 | 22.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 | |||||
| 612 | 90777 | 37.1ms | $state->{annotations} = $orig_annotations; | ||
| 613 | |||||
| 614 | 90777 | 34.9ms | if ($valid) { | ||
| 615 | 86515 | 38.5ms | push $state->{annotations}->@*, @new_annotations; | ||
| 616 | 86515 | 137ms | 49224 | 50.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 | |||||
| 622 | 90777 | 385ms | return $valid; | ||
| 623 | } | ||||
| 624 | |||||
| 625 | has _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, | ||||
| 649 | 1 | 3µ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] | ||
| 650 | 1 | 41µs | 14 | 14.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 | ||||
| 653 | 15 | 17µs | my ($orig, $self) = (shift, shift); | ||
| 654 | |||||
| 655 | 15 | 6µs | my @resources; | ||
| 656 | 15 | 176µs | 30 | 83µ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 |
| 657 | 24 | 11µs | my ($key, $value) = @$pair; | ||
| 658 | |||||
| 659 | 24 | 140µs | 72 | 5.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 | |||||
| 661 | 24 | 111µs | 44 | 1.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 | ||||
| 664 | 6 | 19µs | 6 | 412µ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} | ||||
| 668 | 6 | 185µs | 24 | 780µ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 | |||||
| 676 | 18 | 48µs | 18 | 30µ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}) | ||||
| 678 | 18 | 6µs | if defined $fragment and $fragment eq ''; | ||
| 679 | |||||
| 680 | croak sprintf('canonical_uri cannot contain a plain-name fragment (%s)', $value->{canonical_uri}) | ||||
| 681 | 18 | 34µs | 18 | 10µs | if ($fragment // '') =~ m{^[^/]}; # spent 10µs making 18 calls to JSON::Schema::Modern::CORE:match, avg 556ns/call |
| 682 | |||||
| 683 | 18 | 35µs | 18 | 779µs | $self->$orig($key, $value); # spent 779µs making 18 calls to JSON::Schema::Modern::_add_resources, avg 43µs/call |
| 684 | } | ||||
| 685 | 1 | 7µs | 1 | 237µs | }; # spent 237µs making 1 call to Moo::around |
| 686 | |||||
| 687 | # $vocabulary uri (not its $id!) => [ spec_version, class ] | ||||
| 688 | has _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] | ||||
| 704 | +{ | ||||
| 705 | 31 | 98µs | 24 | 51.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 | }, | ||||
| 710 | 1 | 15µs | 3 | 8.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 | |||||
| 712 | 3 | 0s | # 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 | ||
| 713 | 1 | 5µs | 1 | 51.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 | |||||
| 715 | 1 | 14µs | 4 | 4.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 | ||||
| 718 | 1 | 35µs | 2 | 23µ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 |
| 719 | 1 | 4µs | my ($uri_string, $spec_version) = @$pair; | ||
| 720 | 1 | 14µs | 5 | 1.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 |
| 721 | 1 | 52µs | 4 | 357µ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 |
| 722 | 1 | 4µs | 1 | 49µ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 ] ]. | ||||
| 727 | has _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] | ||||
| 743 | 1 | 8µs | 7 | 83µ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 ] ], | ||||
| 747 | 3 | 8µ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 | }, | ||||
| 752 | 1 | 20µs | 4 | 6.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 | ||||
| 756 | 2964 | 698µ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 | ||
| 757 | # check the cache | ||||
| 758 | 741 | 1.79ms | 741 | 84.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 |
| 759 | 741 | 1.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. | ||||
| 763 | 1 | 4µs | 1 | 0s | 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, | ||||
| 782 | 1 | 1µs | ) if $state->{errors}->@*; | ||
| 783 | 1 | 5µs | return ($state->{spec_version}, $state->{vocabularies}); | ||
| 784 | } | ||||
| 785 | |||||
| 786 | # used for determining a default '$schema' keyword where there is none | ||||
| 787 | 1 | 1µ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 | ||
| 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#', | ||||
| 791 | 1 | 95µs | 2 | 108µs | }; # spent 60µs making 1 call to JSON::Schema::Modern::BEGIN@787
# spent 48µs making 1 call to constant::import |
| 792 | |||||
| 793 | 1 | 0s | # 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 | ||
| 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', | ||||
| 816 | 1 | 980µs | 2 | 45µ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 | ||||
| 819 | 116349 | 19.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 | ||
| 820 | 38783 | 70.9ms | 38783 | 5.49s | my $resource = $self->_get_resource($uri); # spent 5.49s making 38783 calls to JSON::Schema::Modern::_get_resource, avg 142µs/call |
| 821 | 38783 | 58.1ms | return $resource if $resource; | ||
| 822 | |||||
| 823 | 8 | 74µs | 16 | 867µ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 |
| 824 | 8 | 44µs | 16 | 1.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 |
| 825 | 8 | 316µs | 24 | 311µ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 |
| 826 | 8 | 49µs | 8 | 43.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() | ||||
| 829 | 8 | 17µs | 8 | 241µ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 | ||||
| 837 | 8 | 73µs | 16 | 423µ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 | |||||
| 842 | 8 | 53µs | 8 | 1.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. | ||||
| 860 | 139353 | 23.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 | ||
| 861 | 46451 | 15.6ms | 1 | 22µs | $uri = Mojo::URL->new($uri) if not is_ref($uri); # spent 22µs making 1 call to Mojo::URL::new |
| 862 | 46451 | 39.5ms | 46451 | 33.8ms | my $fragment = $uri->fragment; # spent 33.8ms making 46451 calls to Mojo::URL::fragment, avg 727ns/call |
| 863 | |||||
| 864 | 46451 | 58.9ms | 20888 | 15.8ms | if (not length($fragment) or $fragment =~ m{^/}) { # spent 15.8ms making 20888 calls to JSON::Schema::Modern::CORE:match, avg 757ns/call |
| 865 | 38783 | 56.9ms | 77566 | 1.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 |
| 866 | 38783 | 57.1ms | 38783 | 5.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 |
| 867 | 38783 | 104ms | 38783 | 626ms | 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 |
| 868 | 38783 | 11.0ms | return if not defined $subschema; | ||
| 869 | 38783 | 14.1ms | my $document = $resource->{document}; | ||
| 870 | my $closest_resource = first { !length($_->[1]{path}) # document root | ||||
| 871 | 38783 | 176ms | || 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 | ||||
| 874 | 38783 | 517ms | 293381 | 4.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 | ||||
| 878 | 38783 | 119ms | 77566 | 1.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 |
| 879 | 38783 | 51.0ms | 64346 | 37.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, | ||||
| 885 | 38783 | 329ms | $resource->%{qw(specification_version vocabularies configs)}, # reference, not copy | ||
| 886 | }; | ||||
| 887 | } | ||||
| 888 | } | ||||
| 889 | else { # we are following a URI with a plain-name fragment | ||||
| 890 | 7668 | 11.1ms | 7668 | 1.03s | if (my $resource = $self->_get_resource($uri)) { # spent 1.03s making 7668 calls to JSON::Schema::Modern::_get_resource, avg 134µs/call |
| 891 | 7668 | 13.7ms | 7668 | 131ms | my $subschema = $resource->{document}->get($resource->{path}); # spent 131ms making 7668 calls to Mojo::JSON::Pointer::get, avg 17µs/call |
| 892 | 7668 | 1.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}, | ||||
| 898 | 7668 | 44.1ms | 7668 | 223ms | $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) | ||||
| 905 | has _json_decoder => ( | ||||
| 906 | is => 'ro', | ||||
| 907 | isa => HasMethods[qw(encode decode)], | ||||
| 908 | lazy => 1, | ||||
| 909 | 1 | 6µs | 1 | 41µ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] # spent 41µs making 1 call to JSON::MaybeXS::new |
| 910 | 1 | 12µs | 2 | 3.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. | ||||
| 913 | has _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 | }, | ||||
| 936 | 1 | 17µs | 5 | 6.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 '*/*' | ||||
| 939 | around 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 | // '*/*'); | ||||
| 945 | 1 | 3µs | 1 | 172µs | }; # spent 172µs making 1 call to Moo::around |
| 946 | |||||
| 947 | 1 | 2µs | 1 | 91µs | before add_media_type => sub ($self, $type, $sub) { $media_type_type->({ $type => $sub }) }; # spent 91µs making 1 call to Moo::before |
| 948 | |||||
| 949 | has _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 | }, | ||||
| 968 | 1 | 9µs | 3 | 2.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 | ||||
| 971 | sub 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 | ||||
| 980 | sub 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 | |||||
| 989 | 1 | 105µs | 1; | ||
| 990 | 1 | 115µs | 1 | 1.35ms | __END__ # spent 1.35ms making 1 call to B::Hooks::EndOfScope::XS::__ANON__[B/Hooks/EndOfScope/XS.pm:26] |
# 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 | |||||
# 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 | |||||
# 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 | |||||
# 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 | |||||
# 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 | |||||
# 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 | |||||
# 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 | |||||
# 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::__ANON__; # xsub |