au_ps_inferno 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/lib/au_ps_inferno/generator/constants.rb +61 -0
- data/lib/au_ps_inferno/generator/generator.rb +76 -0
- data/lib/au_ps_inferno/generator/generator_group_based_metadata_module.rb +113 -0
- data/lib/au_ps_inferno/generator/ig_resources_extractor.rb +149 -0
- data/lib/au_ps_inferno/generator/metadata_manager.rb +608 -0
- data/lib/au_ps_inferno/generator/naming.rb +52 -0
- data/lib/au_ps_inferno/generator/sections_validation_group_generator.rb +182 -0
- data/lib/au_ps_inferno/generator/test_file_generator.rb +77 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_bundle_instance.rb +56 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_bundle_must_support_conformance/suite_au_ps_bundle_instance_au_ps_bundle_must_support_conformance_bundle_must_support_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_bundle_must_support_conformance.rb +16 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_attester/suite_au_ps_bundle_instance_au_ps_composition_attester_attester_party_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_attester/suite_au_ps_bundle_instance_au_ps_composition_attester_attester_party_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_attester/suite_au_ps_bundle_instance_au_ps_composition_attester_attester_party_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_attester.rb +26 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_author/suite_au_ps_bundle_instance_au_ps_composition_author_author_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_author/suite_au_ps_bundle_instance_au_ps_composition_author_author_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_author/suite_au_ps_bundle_instance_au_ps_composition_author_author_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_author/suite_au_ps_bundle_instance_au_ps_composition_author_author_resource_type_is_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_author.rb +28 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_custodian/suite_au_ps_bundle_instance_au_ps_composition_custodian_custodian_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_custodian/suite_au_ps_bundle_instance_au_ps_composition_custodian_custodian_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_custodian/suite_au_ps_bundle_instance_au_ps_composition_custodian_custodian_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_custodian.rb +26 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_mandatory_sections/composition_mandatory_sections_mandatory_sections_entry_profiles.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_mandatory_sections/suite_au_ps_bundle_instance_au_ps_composition_mandatory_sections_sections_shall_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_mandatory_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_mandatory_ms_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_ms_subelements_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_optional_ms_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_optional_ms_slices.rb +22 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_must_support_conformance.rb +28 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_optional_sections/suite_au_ps_bundle_instance_au_ps_composition_optional_sections_optional_sections_entry_profiles.rb +22 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_optional_sections/suite_au_ps_bundle_instance_au_ps_composition_optional_sections_sections_may_populated.rb +24 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_optional_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_recommended_sections/composition_recommended_sections_recommended_sections_entry_profiles.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_recommended_sections/suite_au_ps_bundle_instance_au_ps_composition_recommended_sections_sections_should_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_recommended_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_subject/suite_au_ps_bundle_instance_au_ps_composition_subject_subject_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_subject/suite_au_ps_bundle_instance_au_ps_composition_subject_subject_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_subject/suite_au_ps_bundle_instance_au_ps_composition_subject_subject_ms_subelements_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_subject/suite_au_ps_bundle_instance_au_ps_composition_subject_subject_resource_type_is_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_subject.rb +28 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_undefined_sections/suite_au_ps_bundle_instance_au_ps_composition_undefined_sections_sections_may_undefined.rb +24 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/au_ps_composition_undefined_sections.rb +18 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/bundle_validation/suite_au_ps_bundle_instance_bundle_validation_bundle_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/bundle_validation/suite_au_ps_bundle_instance_bundle_validation_bundle_valid_ips.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_bundle_instance/bundle_validation.rb +20 -0
- data/lib/au_ps_inferno/suite/au_ps_retrieve_cs_group/au_ps_cs_is_valid_test.rb +21 -0
- data/lib/au_ps_inferno/suite/au_ps_retrieve_cs_group/au_ps_cs_supports_au_ps_profiles.rb +40 -0
- data/lib/au_ps_inferno/suite/au_ps_retrieve_cs_group/au_ps_cs_supports_ips_recommended_ops.rb +19 -0
- data/lib/au_ps_inferno/suite/au_ps_retrieve_cs_group/au_ps_retrieve_cs_group.rb +47 -0
- data/lib/au_ps_inferno/suite/au_ps_v100.rb +39 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_bundle_must_support_conformance/bundle_must_support_conformance_bundle_must_support_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_bundle_must_support_conformance.rb +16 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_attester/composition_attester_attester_party_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_attester/composition_attester_attester_party_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_attester/composition_attester_attester_party_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_attester.rb +26 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_author/composition_author_author_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_author/composition_author_author_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_author/composition_author_author_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_author/composition_author_author_resource_type_is_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_author.rb +28 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_custodian/composition_custodian_custodian_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_custodian/composition_custodian_custodian_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_custodian/composition_custodian_custodian_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_custodian.rb +26 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_mandatory_sections/composition_mandatory_sections_mandatory_sections_entry_profiles.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_mandatory_sections/composition_mandatory_sections_sections_shall_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_mandatory_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_mandatory_ms_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_ms_subelements_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_optional_ms_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_optional_ms_slices.rb +22 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_must_support_conformance.rb +28 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_optional_sections/composition_optional_sections_optional_sections_entry_profiles.rb +22 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_optional_sections/composition_optional_sections_sections_may_populated.rb +24 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_optional_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_recommended_sections/composition_recommended_sections_recommended_sections_entry_profiles.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_recommended_sections/composition_recommended_sections_sections_should_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_recommended_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_subject/composition_subject_subject_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_subject/composition_subject_subject_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_subject/composition_subject_subject_ms_subelements_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_subject/composition_subject_subject_resource_type_is_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_subject.rb +28 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_undefined_sections/composition_undefined_sections_sections_may_undefined.rb +24 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/au_ps_composition_undefined_sections.rb +18 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/bundle_validation/suite_generate_au_ps_using_ips_summary_validation_tests_bundle_validation_bundle_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/bundle_validation/suite_generate_au_ps_using_ips_summary_validation_tests_bundle_validation_bundle_valid_ips.rb +21 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/bundle_validation.rb +20 -0
- data/lib/au_ps_inferno/suite/generate_au_ps_using_ips_summary_validation_tests/generate_au_ps_using_ips_summary_validation_tests.rb +56 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_bundle_must_support_conformance/bundle_must_support_conformance_bundle_must_support_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_bundle_must_support_conformance.rb +16 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_attester/composition_attester_attester_party_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_attester/composition_attester_attester_party_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_attester/composition_attester_attester_party_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_attester.rb +26 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_author/composition_author_author_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_author/composition_author_author_resource_type_is_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_author/suite_retrieve_au_ps_bundle_validation_tests_au_ps_composition_author_author_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_author/suite_retrieve_au_ps_bundle_validation_tests_au_ps_composition_author_author_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_author.rb +28 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_custodian/composition_custodian_custodian_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_custodian/composition_custodian_custodian_ms_subelements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_custodian/suite_retrieve_au_ps_bundle_validation_tests_au_ps_composition_custodian_custodian_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_custodian.rb +26 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_mandatory_sections/composition_mandatory_sections_mandatory_sections_entry_profiles.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_mandatory_sections/composition_mandatory_sections_sections_shall_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_mandatory_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_mandatory_ms_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_ms_subelements_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_optional_ms_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_must_support_conformance/composition_must_support_conformance_composition_optional_ms_slices.rb +22 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_must_support_conformance.rb +28 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_optional_sections/composition_optional_sections_optional_sections_entry_profiles.rb +22 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_optional_sections/composition_optional_sections_sections_may_populated.rb +24 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_optional_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_recommended_sections/composition_recommended_sections_recommended_sections_entry_profiles.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_recommended_sections/composition_recommended_sections_sections_should_populated.rb +22 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_recommended_sections.rb +20 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_subject/composition_subject_subject_ms_identifier_slices.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_subject/composition_subject_subject_ms_subelements_populated.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_subject/composition_subject_subject_resource_type_is_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_subject/suite_retrieve_au_ps_bundle_validation_tests_au_ps_composition_subject_subject_ms_elements.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_subject.rb +28 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_undefined_sections/composition_undefined_sections_sections_may_undefined.rb +24 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/au_ps_composition_undefined_sections.rb +18 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/bundle_validation/suite_retrieve_au_ps_bundle_validation_tests_bundle_validation_bundle_valid.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/bundle_validation/suite_retrieve_au_ps_bundle_validation_tests_bundle_validation_bundle_valid_ips.rb +21 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/bundle_validation.rb +20 -0
- data/lib/au_ps_inferno/suite/retrieve_au_ps_bundle_validation_tests/retrieve_au_ps_bundle_validation_tests.rb +56 -0
- data/lib/au_ps_inferno/utils/attester/basic_test_attester_identifier_slices.rb +74 -0
- data/lib/au_ps_inferno/utils/attester/basic_test_attester_message_helpers.rb +16 -0
- data/lib/au_ps_inferno/utils/attester/basic_test_attester_module.rb +14 -0
- data/lib/au_ps_inferno/utils/attester/basic_test_attester_resource.rb +54 -0
- data/lib/au_ps_inferno/utils/author/basic_test_author_module.rb +12 -0
- data/lib/au_ps_inferno/utils/author/basic_test_author_resource.rb +32 -0
- data/lib/au_ps_inferno/utils/author/basic_test_author_tests.rb +24 -0
- data/lib/au_ps_inferno/utils/basic_test/bundle_module.rb +87 -0
- data/lib/au_ps_inferno/utils/basic_test/capability_operations_module.rb +37 -0
- data/lib/au_ps_inferno/utils/basic_test/composition_elements_and_slices_module.rb +98 -0
- data/lib/au_ps_inferno/utils/basic_test/composition_section_check_resources_ms_elements_module.rb +197 -0
- data/lib/au_ps_inferno/utils/basic_test/composition_section_read_issues_helpers_module.rb +66 -0
- data/lib/au_ps_inferno/utils/basic_test/composition_section_read_module.rb +127 -0
- data/lib/au_ps_inferno/utils/basic_test/composition_subelements_module.rb +84 -0
- data/lib/au_ps_inferno/utils/basic_test/ms_elements_populated_helpers_module.rb +38 -0
- data/lib/au_ps_inferno/utils/basic_test/ms_elements_populated_module.rb +71 -0
- data/lib/au_ps_inferno/utils/basic_test/ms_identifier_slices_module.rb +61 -0
- data/lib/au_ps_inferno/utils/basic_test/ms_sub_elements_populated_module.rb +128 -0
- data/lib/au_ps_inferno/utils/basic_test/paths_module.rb +26 -0
- data/lib/au_ps_inferno/utils/basic_test/resolve_path_debug_module.rb +45 -0
- data/lib/au_ps_inferno/utils/basic_test/resolve_resource_type_module.rb +52 -0
- data/lib/au_ps_inferno/utils/basic_test/resource_helpers_module.rb +129 -0
- data/lib/au_ps_inferno/utils/basic_test/scratch_bundle_entries_module.rb +30 -0
- data/lib/au_ps_inferno/utils/basic_test/section_bundle_validation_module.rb +70 -0
- data/lib/au_ps_inferno/utils/basic_test_class.rb +56 -0
- data/lib/au_ps_inferno/utils/basic_test_contants_module.rb +32 -0
- data/lib/au_ps_inferno/utils/basic_test_with_url.rb +8 -0
- data/lib/au_ps_inferno/utils/basic_validate_bundle_test.rb +43 -0
- data/lib/au_ps_inferno/utils/bundle_decorator.rb +81 -0
- data/lib/au_ps_inferno/utils/bundle_entry_decorator.rb +19 -0
- data/lib/au_ps_inferno/utils/bundle_is_valid_class.rb +31 -0
- data/lib/au_ps_inferno/utils/capability_statement_decorator.rb +20 -0
- data/lib/au_ps_inferno/utils/composition_decorator.rb +56 -0
- data/lib/au_ps_inferno/utils/composition_utils/boolean_and_stats.rb +28 -0
- data/lib/au_ps_inferno/utils/composition_utils.rb +29 -0
- data/lib/au_ps_inferno/utils/custodian/basic_test_custodian_identifier_slices.rb +47 -0
- data/lib/au_ps_inferno/utils/custodian/basic_test_custodian_module.rb +14 -0
- data/lib/au_ps_inferno/utils/custodian/basic_test_custodian_resource.rb +32 -0
- data/lib/au_ps_inferno/utils/custodian/basic_test_custodian_tests.rb +19 -0
- data/lib/au_ps_inferno/utils/inferno_suite_generator_compat.rb +7 -0
- data/lib/au_ps_inferno/utils/ips_bundle_is_valid_class.rb +15 -0
- data/lib/au_ps_inferno/utils/ips_retrieve_bundle_test_class.rb +17 -0
- data/lib/au_ps_inferno/utils/ips_summary_valid_bundle_class.rb +15 -0
- data/lib/au_ps_inferno/utils/metadata_manager.rb +58 -0
- data/lib/au_ps_inferno/utils/retrieve_bundle_test_class.rb +81 -0
- data/lib/au_ps_inferno/utils/rich_message_class.rb +23 -0
- data/lib/au_ps_inferno/utils/rich_validation_message.rb +42 -0
- data/lib/au_ps_inferno/utils/section_decorator.rb +23 -0
- data/lib/au_ps_inferno/utils/section_names_mapping.rb +31 -0
- data/lib/au_ps_inferno/utils/section_test_class.rb +18 -0
- data/lib/au_ps_inferno/utils/section_test_module.rb +16 -0
- data/lib/au_ps_inferno/utils/structure_definition_decorator.rb +28 -0
- data/lib/au_ps_inferno/utils/subject/basic_test_subject_module.rb +12 -0
- data/lib/au_ps_inferno/utils/subject/basic_test_subject_patient_ms_other_tests.rb +15 -0
- data/lib/au_ps_inferno/utils/subject/basic_test_subject_resource.rb +21 -0
- data/lib/au_ps_inferno/utils/summary_valid_bundle_class.rb +84 -0
- data/lib/au_ps_inferno/utils/validator_helpers.rb +92 -0
- data/lib/au_ps_inferno/version.rb +6 -0
- data/lib/au_ps_inferno.rb +3 -0
- metadata +310 -0
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require_relative 'constants'
|
|
6
|
+
require_relative '../../au_ps_inferno/utils/structure_definition_decorator'
|
|
7
|
+
|
|
8
|
+
class Generator
|
|
9
|
+
# Builds and persists metadata for Composition sections from IG resources.
|
|
10
|
+
#
|
|
11
|
+
# Extracts Composition StructureDefinition sections and their entry constraints
|
|
12
|
+
# (profiles, cardinality, mustSupport, section codes) and serializes them to YAML.
|
|
13
|
+
# Output hash keys: +composition_sections+, +composition_mandatory_ms_elements+,
|
|
14
|
+
# +composition_optional_ms_elements+, +profiles+.
|
|
15
|
+
#
|
|
16
|
+
# @see Generator::IGResourcesExtractor for loading IG resources
|
|
17
|
+
# rubocop:disable Metrics/ClassLength
|
|
18
|
+
class MetadataManager
|
|
19
|
+
# @return [Array<Hash>] Array of section metadata hashes
|
|
20
|
+
attr_reader :composition_sections
|
|
21
|
+
|
|
22
|
+
include Constants
|
|
23
|
+
|
|
24
|
+
RECOMMENDED_SECTIONS_CODES = %w[11369-6 30954-2 47519-4 46264-8].freeze
|
|
25
|
+
OPTIONAL_SECTIONS_CODES = %w[42348-3 104605-1 47420-5 11348-0 10162-6 81338-6 18776-5 29762-2 8716-3].freeze
|
|
26
|
+
SUB_ELEMENTS_TO_SKIP = %w[event.period event.code section.emptyReason section.entry section.code section.text
|
|
27
|
+
section.title meta.profile].freeze
|
|
28
|
+
|
|
29
|
+
ATTESTER_PROFILE_REFS = [
|
|
30
|
+
'Patient|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-patient',
|
|
31
|
+
'RelatedPerson|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-relatedperson',
|
|
32
|
+
'Practitioner|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-practitioner',
|
|
33
|
+
'PractitionerRole|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-practitionerrole',
|
|
34
|
+
'Organization|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-organization'
|
|
35
|
+
].freeze
|
|
36
|
+
|
|
37
|
+
AUTHOR_PROFILE_REFS = [
|
|
38
|
+
'Practitioner|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-practitioner',
|
|
39
|
+
'PractitionerRole|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-practitionerrole',
|
|
40
|
+
'Patient|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-patient',
|
|
41
|
+
'RelatedPerson|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-relatedperson',
|
|
42
|
+
'Organization|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-organization',
|
|
43
|
+
'Device|http://hl7.org/fhir/uv/ips/StructureDefinition/Device-uv-ips'
|
|
44
|
+
].freeze
|
|
45
|
+
|
|
46
|
+
CUSTODIAN_PROFILE_REFS = [
|
|
47
|
+
'Organization|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-organization'
|
|
48
|
+
].freeze
|
|
49
|
+
|
|
50
|
+
SUBJECT_PROFILE_REFS = [
|
|
51
|
+
'Patient|http://hl7.org.au/fhir/ps/StructureDefinition/au-ps-patient'
|
|
52
|
+
].freeze
|
|
53
|
+
|
|
54
|
+
# Initializes a MetadataManager for the given IG resources.
|
|
55
|
+
#
|
|
56
|
+
# @param ig_resources [Array<FHIR::Model>] Parsed IG resources (e.g. from IGResourcesExtractor#ig_resources)
|
|
57
|
+
def initialize(ig_resources)
|
|
58
|
+
@ig_resources = ig_resources
|
|
59
|
+
reset_composition_metadata_ivars!
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def reset_composition_metadata_ivars!
|
|
63
|
+
@composition_sections = []
|
|
64
|
+
@composition_mandatory_ms_elements = []
|
|
65
|
+
@composition_mandatory_ms_sub_elements = []
|
|
66
|
+
@composition_optional_ms_elements = []
|
|
67
|
+
@composition_optional_ms_sub_elements = []
|
|
68
|
+
@composition_mandatory_ms_slices = []
|
|
69
|
+
@composition_optional_ms_slices = []
|
|
70
|
+
@profiles = []
|
|
71
|
+
@resources_filters = {}
|
|
72
|
+
@normalized_sections_data = []
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Generates composition section metadata from IG resources (in-memory only).
|
|
76
|
+
# Populates the internal composition sections and related metadata used by {#save_to_file}.
|
|
77
|
+
#
|
|
78
|
+
# @return [void]
|
|
79
|
+
def initiate_build
|
|
80
|
+
generate_metadata_for_composition
|
|
81
|
+
extract_required_ms_elements
|
|
82
|
+
extract_optional_ms_elements
|
|
83
|
+
extract_profiles
|
|
84
|
+
extract_resource_filters
|
|
85
|
+
normalize_sections_data
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def normalize_sections_data
|
|
89
|
+
@normalized_sections_data = @composition_sections.map do |section|
|
|
90
|
+
normalize_section_data(section[:id])
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def extract_resource_filters
|
|
95
|
+
@resources_filters = RESOURCES_FILTERS_MAPPING.map do |resource_profile, filters|
|
|
96
|
+
{
|
|
97
|
+
resource_profile: resource_profile,
|
|
98
|
+
filters: filters
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def metadata_to_dump
|
|
104
|
+
metadata_dump_sections.merge(metadata_dump_ms_elements).merge(metadata_dump_tail)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def metadata_dump_sections
|
|
108
|
+
{
|
|
109
|
+
composition_sections: @composition_sections,
|
|
110
|
+
subject: build_metadata_for_subject,
|
|
111
|
+
author: build_metadata_for_author,
|
|
112
|
+
custodian: build_metadata_for_custodian,
|
|
113
|
+
attester: build_metadata_for_attester
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def metadata_dump_ms_elements
|
|
118
|
+
{
|
|
119
|
+
composition_mandatory_ms_elements: @composition_mandatory_ms_elements,
|
|
120
|
+
composition_mandatory_ms_sub_elements: @composition_mandatory_ms_sub_elements,
|
|
121
|
+
composition_optional_ms_elements: @composition_optional_ms_elements,
|
|
122
|
+
composition_optional_ms_sub_elements: @composition_optional_ms_sub_elements,
|
|
123
|
+
composition_mandatory_ms_slices: @composition_mandatory_ms_slices,
|
|
124
|
+
composition_optional_ms_slices: @composition_optional_ms_slices
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def metadata_dump_tail
|
|
129
|
+
{
|
|
130
|
+
profiles: @profiles,
|
|
131
|
+
resources_filters: @resources_filters
|
|
132
|
+
}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def normalize_section_data(section_id)
|
|
136
|
+
section_data = @composition_sections.find { |section| section[:id] == section_id }
|
|
137
|
+
return section_data if section_data.nil?
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
'code' => section_data[:code],
|
|
141
|
+
'display' => section_data[:short],
|
|
142
|
+
'resources' => build_section_resources(section_data)
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def composition_ms_sections_elements
|
|
147
|
+
filtered = composition_extract_ms_elements_without_slices.filter do |element|
|
|
148
|
+
element&.path&.include?('Composition.section.')
|
|
149
|
+
end
|
|
150
|
+
filtered.map { |element| section_element_expression_min(element) }.uniq
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def section_element_expression_min(element)
|
|
154
|
+
path = element.path.gsub('Composition.section.', '')
|
|
155
|
+
{ expression: path, min: element.min }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def build_section_resources(section_data)
|
|
159
|
+
resources = {}
|
|
160
|
+
section_data[:entries].each do |entry|
|
|
161
|
+
entry[:profiles].each do |profile|
|
|
162
|
+
requirements = requirements_for_profile(profile)
|
|
163
|
+
resources[profile] = { 'requirements' => requirements }
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
resources
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def requirements_for_profile(profile)
|
|
170
|
+
filter = @resources_filters.find { |f| f[:resource_profile] == profile }
|
|
171
|
+
filter ? filter[:filters] : []
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Populates @profiles with AU PS StructureDefinitions (url, name, title, required).
|
|
175
|
+
#
|
|
176
|
+
# @return [void]
|
|
177
|
+
def extract_profiles
|
|
178
|
+
@profiles = main_profiles.map do |profile|
|
|
179
|
+
{
|
|
180
|
+
url: profile.url.to_s,
|
|
181
|
+
name: profile.name,
|
|
182
|
+
title: profile.title,
|
|
183
|
+
required: profile_required?(profile)
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Returns whether the given AU PS StructureDefinition is required.
|
|
189
|
+
#
|
|
190
|
+
# @param profile [FHIR::StructureDefinition] AU PS StructureDefinition
|
|
191
|
+
# @return [Boolean] true if the profile URL is in {Generator::Constants::REQUIRED_PROFILES}
|
|
192
|
+
def profile_required?(profile)
|
|
193
|
+
REQUIRED_PROFILES.include?(profile.url.to_s)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# StructureDefinitions from the IG whose URL is an AU PS profile
|
|
197
|
+
# (http://hl7.org.au/fhir/ps/StructureDefinition/...)
|
|
198
|
+
#
|
|
199
|
+
# @return [Array<FHIR::StructureDefinition>]
|
|
200
|
+
def main_profiles
|
|
201
|
+
@ig_resources.filter do |resource|
|
|
202
|
+
next unless resource.resourceType == 'StructureDefinition'
|
|
203
|
+
|
|
204
|
+
resource.url.to_s.include?('http://hl7.org.au/fhir/ps/StructureDefinition/')
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Populates @composition_optional_ms_elements with mustSupport elements where min is 0.
|
|
209
|
+
#
|
|
210
|
+
# @return [void]
|
|
211
|
+
def extract_optional_all_ms_elements
|
|
212
|
+
extract_ms_elements_by_predicate(->(element) { element.min.zero? })
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def path_is_not_slice?(path)
|
|
216
|
+
!composition_mandatory_ms_slices_paths.include?(path) && !composition_optional_ms_slices_paths.include?(path)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def extract_optional_ms_elements
|
|
220
|
+
@composition_optional_ms_elements = extract_optional_all_ms_elements.filter do |path|
|
|
221
|
+
path_is_not_slice?(path) && !path.include?('.') && path != 'section'
|
|
222
|
+
end + ['event']
|
|
223
|
+
@composition_optional_ms_sub_elements = extract_optional_all_ms_elements.filter do |path|
|
|
224
|
+
path_is_not_slice?(path) && path.include?('.') && !SUB_ELEMENTS_TO_SKIP.include?(path)
|
|
225
|
+
end
|
|
226
|
+
@composition_optional_ms_slices = composition_optional_ms_slices
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Populates @composition_mandatory_ms_elements with mustSupport elements where min > 0.
|
|
230
|
+
#
|
|
231
|
+
# @return [void]
|
|
232
|
+
def extract_required_all_ms_elements
|
|
233
|
+
extract_ms_elements_by_predicate(->(element) { element.min.positive? })
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def extract_required_ms_elements
|
|
237
|
+
@composition_mandatory_ms_elements = extract_required_all_ms_elements.filter do |path|
|
|
238
|
+
path_is_not_slice?(path) && !path.include?('.') && path != 'section'
|
|
239
|
+
end
|
|
240
|
+
@composition_mandatory_ms_sub_elements = extract_required_all_ms_elements.filter do |path|
|
|
241
|
+
path_is_not_slice?(path) && path.include?('.') && !SUB_ELEMENTS_TO_SKIP.include?(path)
|
|
242
|
+
end
|
|
243
|
+
@composition_mandatory_ms_slices = composition_mandatory_ms_slices
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Filters Composition mustSupport elements (no slices) by predicate and returns path suffixes.
|
|
247
|
+
# Uses element.path so suffixes are relative to Composition (e.g. subject.reference), not the base type.
|
|
248
|
+
#
|
|
249
|
+
# @param predicate [Proc] Called with each element; keeps element when truthy (e.g. min.zero?, min.positive?)
|
|
250
|
+
# @return [Array<String>] Sorted unique paths with "Composition." prefix removed (e.g. +subject.reference+)
|
|
251
|
+
def extract_ms_elements_by_predicate(predicate)
|
|
252
|
+
elements = composition_extract_ms_elements_without_slices.filter do |element|
|
|
253
|
+
predicate.call(element)
|
|
254
|
+
end
|
|
255
|
+
elements.map do |element|
|
|
256
|
+
element.path.gsub('Composition.', '')
|
|
257
|
+
end.uniq.sort
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Returns Composition snapshot elements that are mustSupport, non-sliced, and under Composition.
|
|
261
|
+
# Uses element.path (profile path) not element.base.path, so inherited sub-elements like
|
|
262
|
+
# Composition.subject.reference are included (base.path would be Reference.reference).
|
|
263
|
+
#
|
|
264
|
+
# @return [Array<FHIR::Element>] Snapshot elements; empty if no Composition StructureDefinition
|
|
265
|
+
def composition_extract_ms_elements_without_slices
|
|
266
|
+
composition_structure_definition = get_structure_definition_by_type('Composition')
|
|
267
|
+
return [] if composition_structure_definition.nil?
|
|
268
|
+
|
|
269
|
+
elements = composition_structure_definition.snapshot.element
|
|
270
|
+
elements.filter { |element| ms_composition_path?(element) }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def ms_composition_path?(element)
|
|
274
|
+
element.mustSupport == true && !element.path.include?(':') && element.path.include?('Composition.')
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def all_ms_elements_related_to_slice(slice)
|
|
278
|
+
composition_structure_definition = get_structure_definition_by_type('Composition')
|
|
279
|
+
return [] if composition_structure_definition.nil?
|
|
280
|
+
|
|
281
|
+
elements = composition_structure_definition.snapshot.element
|
|
282
|
+
elements.filter do |element|
|
|
283
|
+
ms_composition_path?(element) && element.path.include?(slice)
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def composition_mandatory_ms_slices
|
|
288
|
+
composition_extract_slices.filter { |slice| slice[:mustSupport] == true && slice[:min].positive? }
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def composition_mandatory_ms_slices_paths
|
|
292
|
+
composition_mandatory_ms_slices.map { |slice| slice[:path] }
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def composition_optional_ms_slices
|
|
296
|
+
composition_extract_slices.filter { |slice| slice[:mustSupport] == true && slice[:min].zero? }
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def composition_optional_ms_slices_paths
|
|
300
|
+
composition_optional_ms_slices.map { |slice| slice[:path] }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def composition_extract_slices
|
|
304
|
+
composition_structure_definition = get_structure_definition_by_type('Composition')
|
|
305
|
+
return [] if composition_structure_definition.nil?
|
|
306
|
+
|
|
307
|
+
elements = composition_structure_definition.snapshot.element
|
|
308
|
+
filtered_elements = elements.filter { |element| element_is_slice?(element) }
|
|
309
|
+
filtered_elements.map { |element| build_metadata_for_slice(element) }
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def build_metadata_for_slice(element)
|
|
313
|
+
related = all_ms_elements_related_to_slice(element.path)
|
|
314
|
+
base = element.path
|
|
315
|
+
slice_metadata_base(element).merge(
|
|
316
|
+
mandatory_ms_sub_elements: slice_relative_sub_paths(related, base, &:zero?),
|
|
317
|
+
optional_ms_sub_elements: slice_relative_sub_paths(related, base, &:positive?)
|
|
318
|
+
)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def slice_metadata_base(element)
|
|
322
|
+
{
|
|
323
|
+
path: element.path.gsub('Composition.', ''),
|
|
324
|
+
sliceName: element.sliceName,
|
|
325
|
+
min: element.min,
|
|
326
|
+
max: element.max,
|
|
327
|
+
mustSupport: element.mustSupport
|
|
328
|
+
}
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def slice_relative_sub_paths(related_elements, base_path, &min_pred)
|
|
332
|
+
picked = related_elements.filter { |el| min_pred.call(el.min) }
|
|
333
|
+
paths = picked.map { |el| el.path.gsub(base_path, '').gsub('.', '') }
|
|
334
|
+
paths.reject(&:empty?)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def element_is_slice?(element)
|
|
338
|
+
element.id.include?(':') && element&.sliceName &&
|
|
339
|
+
!element.path.include?('section') &&
|
|
340
|
+
!element.path.include?('extension')
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Returns IG resources whose resourceType matches the given type.
|
|
344
|
+
#
|
|
345
|
+
# @param type [String] FHIR resource type (e.g. +StructureDefinition+)
|
|
346
|
+
# @return [Array<FHIR::Model>]
|
|
347
|
+
def get_resources_by_type(type)
|
|
348
|
+
@ig_resources.filter do |resource|
|
|
349
|
+
resource.resourceType == type
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Finds the StructureDefinition for a logical resource type (e.g. Composition, Patient).
|
|
354
|
+
#
|
|
355
|
+
# @param type [String] Logical type (e.g. +Composition+)
|
|
356
|
+
# @return [FHIR::StructureDefinition, nil]
|
|
357
|
+
def get_structure_definition_by_type(type)
|
|
358
|
+
get_resources_by_type('StructureDefinition').find do |resource|
|
|
359
|
+
resource.type == type
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# Finds a StructureDefinition in ig_resources whose canonical URL matches the given profile.
|
|
364
|
+
# Matches by URL with or without version (canonical form "url|version").
|
|
365
|
+
#
|
|
366
|
+
# @param profile_url [String] Canonical profile URL (e.g. from Reference.type.targetProfile)
|
|
367
|
+
# @param entry_id [String, nil] Optional entry element id for error context
|
|
368
|
+
# @return [FHIR::StructureDefinition]
|
|
369
|
+
# @raise [RuntimeError] when no StructureDefinition in ig_resources has this profile URL
|
|
370
|
+
def get_structure_definition_by_profile(profile_url, entry_id = nil)
|
|
371
|
+
base_url = profile_url.to_s.split('|').first
|
|
372
|
+
sd = find_structure_definition_by_base_url(base_url)
|
|
373
|
+
return sd if sd
|
|
374
|
+
|
|
375
|
+
available = structure_definition_urls
|
|
376
|
+
raise profile_not_found_error(profile_url, entry_id, available)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Finds a StructureDefinition by canonical base URL (version stripped).
|
|
380
|
+
#
|
|
381
|
+
# @param base_url [String] Canonical URL without version (e.g. +http://hl7.org/fhir/StructureDefinition/Patient+)
|
|
382
|
+
# @return [FHIR::StructureDefinition, nil]
|
|
383
|
+
def find_structure_definition_by_base_url(base_url)
|
|
384
|
+
get_resources_by_type('StructureDefinition').find do |resource|
|
|
385
|
+
resource.url.to_s.split('|').first == base_url
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Collects all non-empty canonical URLs from StructureDefinitions in the IG.
|
|
390
|
+
#
|
|
391
|
+
# @return [Array<String>] Sorted list of URL strings
|
|
392
|
+
def structure_definition_urls
|
|
393
|
+
get_resources_by_type('StructureDefinition').map { |r| r.url.to_s }.reject(&:empty?).sort
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Builds the error message when a profile has no matching StructureDefinition.
|
|
397
|
+
#
|
|
398
|
+
# @param profile_url [String] Requested profile URL
|
|
399
|
+
# @param entry_id [String, nil] Optional entry id for context
|
|
400
|
+
# @param available [Array<String>] List of available StructureDefinition URLs
|
|
401
|
+
# @return [String] Error message suitable for RuntimeError
|
|
402
|
+
def profile_not_found_error(profile_url, entry_id, available)
|
|
403
|
+
context = entry_id ? " (entry: #{entry_id})" : ''
|
|
404
|
+
hint = 'Add JSON via ADDITIONAL_IG_RESOURCES or additional_resources_path.'
|
|
405
|
+
sample = available.join(', ')
|
|
406
|
+
"No StructureDefinition found in IG resources for profile: #{profile_url.inspect}#{context}. " \
|
|
407
|
+
"Ensure the IG includes it or #{hint} " \
|
|
408
|
+
"Available URLs (#{available.size}): #{sample}"
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Populates @composition_sections from the Composition StructureDefinition.
|
|
412
|
+
# No-op when no Composition StructureDefinition is present in the IG.
|
|
413
|
+
#
|
|
414
|
+
# @return [void]
|
|
415
|
+
def generate_metadata_for_composition
|
|
416
|
+
composition_structure_definition = get_structure_definition_by_type('Composition')
|
|
417
|
+
return if composition_structure_definition.nil?
|
|
418
|
+
|
|
419
|
+
elements = composition_structure_definition.snapshot.element
|
|
420
|
+
sections = elements.filter do |element|
|
|
421
|
+
element.path == 'Composition.section' && !element.sliceName.nil?
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
sections.each do |section|
|
|
425
|
+
@composition_sections << build_section_data(section, elements)
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Builds a full section metadata hash including code and entries.
|
|
430
|
+
#
|
|
431
|
+
# @param section [FHIR::Element] Snapshot element for Composition.section (with sliceName)
|
|
432
|
+
# @param elements [Array<FHIR::Element>] All snapshot elements from the Composition StructureDefinition
|
|
433
|
+
# @return [Hash] Section metadata hash including keys:
|
|
434
|
+
# :id, :short, :definition, :min, :max, :required, :mustSupport, :code, :entries
|
|
435
|
+
def build_section_data(section, elements)
|
|
436
|
+
basic_section_data = build_basic_section_data(section)
|
|
437
|
+
{
|
|
438
|
+
**basic_section_data,
|
|
439
|
+
code: section_code(section.id, elements),
|
|
440
|
+
entries: get_section_entry_data(elements, section.id)
|
|
441
|
+
}
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Builds the basic section fields from a snapshot element (no code or entries).
|
|
445
|
+
#
|
|
446
|
+
# @param section [FHIR::Element] Snapshot element for Composition.section (with sliceName)
|
|
447
|
+
# @return [Hash] Basic section fields:
|
|
448
|
+
# :id, :short, :definition, :min, :max, :required, :mustSupport
|
|
449
|
+
def build_basic_section_data(section)
|
|
450
|
+
{
|
|
451
|
+
id: section.id,
|
|
452
|
+
short: section.short,
|
|
453
|
+
definition: section.definition,
|
|
454
|
+
min: section.min,
|
|
455
|
+
max: section.max,
|
|
456
|
+
required: section.min.positive?,
|
|
457
|
+
mustSupport: section.mustSupport || false,
|
|
458
|
+
ms_elements: composition_ms_sections_elements
|
|
459
|
+
}
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# Extracts the LOINC (or other) section code from the section's +code+ element.
|
|
463
|
+
#
|
|
464
|
+
# @param section_id [String] Section element id (e.g. +Composition.section:sectionProblems+)
|
|
465
|
+
# @param elements [Array<FHIR::Element>] All snapshot elements
|
|
466
|
+
# @return [String, nil] First coding code from the section's pattern CodeableConcept, or nil if absent
|
|
467
|
+
def section_code(section_id, elements)
|
|
468
|
+
filtered_element = elements.find do |element|
|
|
469
|
+
element.id == "#{section_id}.code"
|
|
470
|
+
end
|
|
471
|
+
return nil if filtered_element.nil?
|
|
472
|
+
|
|
473
|
+
filtered_element.patternCodeableConcept.coding.first.code
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
# Collects entry elements for a section and builds entry metadata for each.
|
|
477
|
+
#
|
|
478
|
+
# @param elements [Array<FHIR::Element>] Snapshot elements
|
|
479
|
+
# @param section_id [String] Section element id (e.g. +Composition.section:sectionProblems+)
|
|
480
|
+
# @return [Array<Hash>] Entry metadata hashes (see {#build_section_entry_data})
|
|
481
|
+
def get_section_entry_data(elements, section_id)
|
|
482
|
+
entries = elements.filter do |element|
|
|
483
|
+
element.id.include?("#{section_id}.entry")
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
entries.map do |entry|
|
|
487
|
+
build_section_entry_data(entry)
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# Builds entry metadata from a section entry snapshot element (id, cardinality, mustSupport, profiles).
|
|
492
|
+
#
|
|
493
|
+
# @param entry [FHIR::Element] Snapshot element for section entry (e.g. Composition.section:...entry:problem)
|
|
494
|
+
# @return [Hash] Entry metadata hash including keys:
|
|
495
|
+
# :id, :min, :max, :required, :mustSupport, :profiles
|
|
496
|
+
def build_section_entry_data(entry)
|
|
497
|
+
{
|
|
498
|
+
id: entry.id,
|
|
499
|
+
min: entry.min,
|
|
500
|
+
max: entry.max,
|
|
501
|
+
required: entry.min.positive?,
|
|
502
|
+
mustSupport: entry.mustSupport || false,
|
|
503
|
+
profiles: get_section_entry_profiles(entry.id, entry)
|
|
504
|
+
}
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Resolves Reference type targetProfile URLs to "resourceType|profile" using IG StructureDefinitions.
|
|
508
|
+
#
|
|
509
|
+
# @param entry_id [String] Entry element id (for error messages when profile is missing)
|
|
510
|
+
# @param element [FHIR::Element] Snapshot element with type Reference and targetProfile
|
|
511
|
+
# @return [Array<String>] Strings in the form "resourceType|profile" for each target profile
|
|
512
|
+
# @raise [RuntimeError] when no StructureDefinition matches a targetProfile.
|
|
513
|
+
# See {#get_structure_definition_by_profile}.
|
|
514
|
+
def get_section_entry_profiles(entry_id, element)
|
|
515
|
+
ref_types = element.type&.select { |t| t.code == 'Reference' } || []
|
|
516
|
+
profile_urls = ref_types.flat_map(&:targetProfile).to_a.compact
|
|
517
|
+
|
|
518
|
+
profile_urls.map do |profile_url|
|
|
519
|
+
sd = get_structure_definition_by_profile(profile_url, entry_id)
|
|
520
|
+
"#{sd.type}|#{profile_url}"
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
def normalize_path_to_hash(path)
|
|
525
|
+
{ expression: path, label: path }
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
def mandatory_ms_sub_elements
|
|
529
|
+
@composition_mandatory_ms_sub_elements.map { |element| normalize_path_to_hash(element) }
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def build_metadata_for_subject
|
|
533
|
+
SUBJECT_PROFILE_REFS.map { |profile| metadata_hash_for_profile_ref(profile) }
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
def build_metadata_for_custodian
|
|
537
|
+
# Custodian is only AU PS Organization
|
|
538
|
+
build_metadata_for_mapping(CUSTODIAN_PROFILE_REFS)
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
def build_metadata_for_attester
|
|
542
|
+
# attester.party: AU PS Patient | RelatedPerson | Practitioner | PractitionerRole | Organization (no Device)
|
|
543
|
+
build_metadata_for_mapping(ATTESTER_PROFILE_REFS)
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
def build_metadata_for_author
|
|
547
|
+
# AU PS Practitioner, AU PS PractitionerRole, AU PS Patient, AU PS RelatedPerson,
|
|
548
|
+
# AU PS Organization profiles or Device resource
|
|
549
|
+
build_metadata_for_mapping(AUTHOR_PROFILE_REFS)
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def build_metadata_for_mapping(profile_refs)
|
|
553
|
+
profile_refs.map { |profile| metadata_hash_for_profile_ref(profile) }
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
def metadata_hash_for_profile_ref(profile)
|
|
557
|
+
url = profile.split('|')[1]
|
|
558
|
+
sd = get_structure_definition_by_profile(url)
|
|
559
|
+
{
|
|
560
|
+
resource_type: sd.type,
|
|
561
|
+
profile: url,
|
|
562
|
+
elements: get_elements_from_structure_definition(sd),
|
|
563
|
+
slices: get_extension_slices_from_structure_definition(sd)
|
|
564
|
+
}
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
def get_extension_slices_from_structure_definition(sd_data)
|
|
568
|
+
# Return mandatory MS extension slices
|
|
569
|
+
sd_decorator = StructureDefinitionDecorator.new(sd_data)
|
|
570
|
+
extension_slices = sd_decorator.extension_slices
|
|
571
|
+
filtered_extension_slices = extension_slices.filter { |element| element.mustSupport == true }
|
|
572
|
+
filtered_extension_slices.map do |element|
|
|
573
|
+
build_normalized_element_data(element, sd_decorator)
|
|
574
|
+
end.uniq
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def build_normalized_element_data(element, sd_decorator)
|
|
578
|
+
first_element_type = element&.type&.first
|
|
579
|
+
profile = first_element_type&.profile&.first || ''
|
|
580
|
+
{
|
|
581
|
+
id: element.id,
|
|
582
|
+
expression: element.path.gsub("#{sd_decorator.type}.", ''),
|
|
583
|
+
label: element.sliceName,
|
|
584
|
+
min: element.min,
|
|
585
|
+
max: element.max,
|
|
586
|
+
profile: profile
|
|
587
|
+
}
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def get_elements_from_structure_definition(sd_data)
|
|
591
|
+
structure_definition_data = StructureDefinitionDecorator.new(sd_data)
|
|
592
|
+
elements = structure_definition_data.simple_elements(include_str: "#{sd_data.type}.")
|
|
593
|
+
filtered_elements = elements.reject { |element| element.id.include?(':') }
|
|
594
|
+
filtered_elements.map do |element|
|
|
595
|
+
{
|
|
596
|
+
id: element.id,
|
|
597
|
+
expression: element.path.gsub("#{sd_data.type}.", ''),
|
|
598
|
+
min: element.min
|
|
599
|
+
}
|
|
600
|
+
end.uniq
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
private :reset_composition_metadata_ivars!, :metadata_dump_sections, :metadata_dump_ms_elements,
|
|
604
|
+
:metadata_dump_tail, :section_element_expression_min, :slice_metadata_base,
|
|
605
|
+
:slice_relative_sub_paths, :ms_composition_path?, :metadata_hash_for_profile_ref
|
|
606
|
+
end
|
|
607
|
+
# rubocop:enable Metrics/ClassLength
|
|
608
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Generator
|
|
4
|
+
# Shared naming and ID helpers for suite, group, and test generation.
|
|
5
|
+
# Use these when adding new groups or tests so IDs and class names stay consistent.
|
|
6
|
+
module Naming
|
|
7
|
+
class << self
|
|
8
|
+
# @param string [String] space-separated or mixed-case string
|
|
9
|
+
# @return [String] PascalCase (e.g. "Bundle Validation" => "BundleValidation")
|
|
10
|
+
def camel_case(string)
|
|
11
|
+
string.to_s.split.map(&:capitalize).join
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @param string [String]
|
|
15
|
+
# @return [String] with $ . , ( ) - removed
|
|
16
|
+
def remove_special_characters(string)
|
|
17
|
+
special_characters = ['$', '.', ',', '(', ')', '-']
|
|
18
|
+
string.to_s.gsub(Regexp.union(special_characters), '')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param string [String] human-readable name
|
|
22
|
+
# @return [String] Ruby class name (PascalCase, no spaces/special chars)
|
|
23
|
+
def build_class_name(string)
|
|
24
|
+
camel_case(remove_special_characters(string)).gsub(' ', '')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param string [String, Symbol] human-readable name or test type id (symbol); Symbol converted via .to_s
|
|
28
|
+
# @return [String] snake_case id (lowercase, underscores, no special chars)
|
|
29
|
+
def build_id(string)
|
|
30
|
+
s = string.to_s
|
|
31
|
+
remove_special_characters(s.include?(' ') ? s.gsub(' ', '_') : s).downcase
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Instance methods for use with include Naming
|
|
36
|
+
def camel_case(string)
|
|
37
|
+
Naming.camel_case(string)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def remove_special_characters(string)
|
|
41
|
+
Naming.remove_special_characters(string)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def build_class_name(string)
|
|
45
|
+
Naming.build_class_name(string)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def build_id(string)
|
|
49
|
+
Naming.build_id(string)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|