@@ -232,17 +232,11 @@ auto properties_as_loop(const Context &context,
232232 Known::JSON_Schema_2019_09_Validation) ||
233233 schema_context.vocabularies .contains (
234234 Known::JSON_Schema_2020_12_Validation);
235- std::set<std::string> required;
236- if (imports_validation_vocabulary &&
237- schema_context.schema .defines (" required" ) &&
238- schema_context.schema .at (" required" ).is_array ()) {
239- for (const auto &property :
240- schema_context.schema .at (" required" ).as_array ()) {
241- if (property.is_string () &&
242- // Only count the required property if its indeed in "properties"
243- properties.defines (property.to_string ())) {
244- required.insert (property.to_string ());
245- }
235+ ValueStringSet required;
236+ for (const auto &entry : required_properties (schema_context)) {
237+ // Only count the required property if its indeed in "properties"
238+ if (properties.defines (entry.first )) {
239+ required.insert (entry.first );
246240 }
247241 }
248242
@@ -460,30 +454,19 @@ auto compiler_draft3_applicator_properties_with_options(
460454 schema_context.schema .at (" type" ).to_string () ==
461455 " object" };
462456
463- using Known = sourcemeta::core::Vocabularies::Known;
464- const auto imports_top_level_required{
465- schema_context.vocabularies .contains (Known::JSON_Schema_Draft_4) ||
466- schema_context.vocabularies .contains (Known::JSON_Schema_Draft_6) ||
467- schema_context.vocabularies .contains (Known::JSON_Schema_Draft_7) ||
468- schema_context.vocabularies .contains (
469- Known::JSON_Schema_2019_09_Validation) ||
470- schema_context.vocabularies .contains (
471- Known::JSON_Schema_2020_12_Validation)};
457+ ValueStringSet required{required_properties (schema_context)};
472458
473459 auto properties{compile_properties (context, schema_context,
474460 effective_dynamic_context, current)};
475461
476- if (context.mode == Mode::FastValidation && imports_top_level_required &&
462+ if (context.mode == Mode::FastValidation && !required. empty () &&
477463 schema_context.schema .defines (" additionalProperties" ) &&
478464 schema_context.schema .at (" additionalProperties" ).is_boolean () &&
479465 !schema_context.schema .at (" additionalProperties" ).to_boolean () &&
480- schema_context.schema .defines (" required" ) &&
481- schema_context.schema .at (" required" ).is_array () &&
482- schema_context.schema .at (" required" ).size () ==
466+ required.size () ==
483467 schema_context.schema .at (dynamic_context.keyword ).size () &&
484- std::ranges::all_of (properties, [&schema_context](const auto &property) {
485- return schema_context.schema .at (" required" )
486- .contains (sourcemeta::core::JSON{property.first });
468+ std::ranges::all_of (properties, [&required](const auto &property) {
469+ return required.contains (property.first );
487470 })) {
488471 if (std::ranges::all_of (properties, [](const auto &property) {
489472 return property.second .size () == 1 &&
@@ -497,11 +480,7 @@ auto compiler_draft3_applicator_properties_with_options(
497480
498481 if (types.size () == 1 &&
499482 !schema_context.schema .defines (" patternProperties" )) {
500- if (imports_top_level_required &&
501- schema_context.schema .defines (" required" ) && assume_object) {
502- auto required_copy = schema_context.schema .at (" required" );
503- std::ranges::sort (required_copy.as_array ());
504- ValueStringSet required{json_array_to_string_set (required_copy)};
483+ if (assume_object) {
505484 if (is_closed_properties_required (schema_context.schema , required)) {
506485 sourcemeta::core::PropertyHashJSON<ValueString> hasher;
507486 std::vector<std::pair<ValueString, ValueStringSet::hash_type>>
@@ -744,12 +723,7 @@ auto compiler_draft3_applicator_properties_with_options(
744723 if (fusion_possible && substeps.size () == 1 &&
745724 substeps.front ().type != InstructionIndex::ControlJump &&
746725 substeps.front ().type != InstructionIndex::ControlDynamicAnchorJump) {
747- const auto is_required{
748- assume_object && imports_top_level_required &&
749- schema_context.schema .defines (" required" ) &&
750- schema_context.schema .at (" required" ).is_array () &&
751- schema_context.schema .at (" required" )
752- .contains (sourcemeta::core::JSON{name})};
726+ const auto is_required{assume_object && required.contains (name)};
753727 auto prop{make_property (name)};
754728 auto fusion_child{substeps.front ()};
755729 fusion_child.relative_instance_location = {};
@@ -767,11 +741,7 @@ auto compiler_draft3_applicator_properties_with_options(
767741 if (!substeps.empty ()) {
768742 // As a performance shortcut
769743 if (effective_dynamic_context.base_instance_location .empty ()) {
770- if (assume_object && imports_top_level_required &&
771- schema_context.schema .defines (" required" ) &&
772- schema_context.schema .at (" required" ).is_array () &&
773- schema_context.schema .at (" required" )
774- .contains (sourcemeta::core::JSON{name})) {
744+ if (assume_object && required.contains (name)) {
775745 for (auto &&step : substeps) {
776746 children.push_back (std::move (step));
777747 }
@@ -794,27 +764,19 @@ auto compiler_draft3_applicator_properties_with_options(
794764
795765 if (context.mode == Mode::FastValidation) {
796766 if (fusion_possible && !fusion_entries.empty ()) {
797- if (imports_top_level_required &&
798- schema_context.schema .defines (" required" ) &&
799- schema_context.schema .at (" required" ).is_array ()) {
800- for (const auto &req :
801- schema_context.schema .at (" required" ).as_array ()) {
802- if (!req.is_string ()) {
803- continue ;
804- }
805- const auto &req_name{req.to_string ()};
806- bool already_tracked{false };
807- for (const auto &entry : fusion_entries) {
808- if (std::get<0 >(entry) == req_name) {
809- already_tracked = true ;
810- break ;
811- }
812- }
813- if (!already_tracked) {
814- auto prop{make_property (req_name)};
815- fusion_entries.emplace_back (prop.first , prop.second , true );
767+ for (const auto &req : required) {
768+ const auto &req_name{req.first };
769+ bool already_tracked{false };
770+ for (const auto &entry : fusion_entries) {
771+ if (std::get<0 >(entry) == req_name) {
772+ already_tracked = true ;
773+ break ;
816774 }
817775 }
776+ if (!already_tracked) {
777+ auto prop{make_property (req_name)};
778+ fusion_entries.emplace_back (prop.first , prop.second , true );
779+ }
818780 }
819781
820782 if (fusion_entries.size () > 32 ) {
@@ -949,16 +911,6 @@ auto compiler_draft3_applicator_additionalproperties_with_options(
949911 return {};
950912 }
951913
952- using Known = sourcemeta::core::Vocabularies::Known;
953- const auto imports_top_level_required{
954- schema_context.vocabularies .contains (Known::JSON_Schema_Draft_4) ||
955- schema_context.vocabularies .contains (Known::JSON_Schema_Draft_6) ||
956- schema_context.vocabularies .contains (Known::JSON_Schema_Draft_7) ||
957- schema_context.vocabularies .contains (
958- Known::JSON_Schema_2019_09_Validation) ||
959- schema_context.vocabularies .contains (
960- Known::JSON_Schema_2020_12_Validation)};
961-
962914 Instructions children{compile (context, schema_context,
963915 relative_dynamic_context (),
964916 sourcemeta::core::empty_weak_pointer,
@@ -1028,12 +980,9 @@ auto compiler_draft3_applicator_additionalproperties_with_options(
1028980 if (context.mode == Mode::FastValidation && children.size () == 1 &&
1029981 children.front ().type == InstructionIndex::AssertionFail &&
1030982 !filter_strings.empty () && filter_prefixes.empty () &&
1031- filter_regexes.empty () && imports_top_level_required &&
1032- schema_context.schema .defines (" required" ) &&
1033- schema_context.schema .at (" required" ).is_array () &&
1034- is_closed_properties_required (
1035- schema_context.schema ,
1036- json_array_to_string_set (schema_context.schema .at (" required" )))) {
983+ filter_regexes.empty () &&
984+ is_closed_properties_required (schema_context.schema ,
985+ required_properties (schema_context))) {
1037986 return {};
1038987 }
1039988
0 commit comments