Class: Inferno::DSL::MustSupportMetadataExtractor
- Inherits:
-
Object
- Object
- Inferno::DSL::MustSupportMetadataExtractor
- Defined in:
- lib/inferno/dsl/must_support_metadata_extractor.rb
Overview
The MustSupportMetadataExtractor takes a StructureDefinition and parses it into a hash-based metadata that simplifies checking for MustSupport elements. MustSupport elements may be either plain elements, extensions, or slices. This logic was originally developed for the US Core Test Kit and has been migrated into Inferno core.
Instance Attribute Summary collapse
-
#ig_resources ⇒ Object
Returns the value of attribute ig_resources.
-
#profile ⇒ Object
Returns the value of attribute profile.
-
#profile_elements ⇒ Object
Returns the value of attribute profile_elements.
-
#requirement_extension_url ⇒ Object
Returns the value of attribute requirement_extension_url.
-
#resource ⇒ Object
Returns the value of attribute resource.
Instance Method Summary collapse
- #all_must_support_elements ⇒ Object
- #by_requirement_extension_only?(element) ⇒ Boolean
- #canonical_url_without_version(url) ⇒ Object
- #discriminator_path(discriminator) ⇒ Object
- #discriminators(slice) ⇒ Object
- #element_matches_choice_type?(element, target_path, target_type) ⇒ Boolean
- #element_part_of_slice_discrimination?(element) ⇒ Boolean
- #extension_discriminator_step?(path) ⇒ Boolean
- #extension_profile_matches?(type, ext_url) ⇒ Boolean
-
#extension_slice_name(element_id) ⇒ String?
The name of the deepest slice in a FHIR ElementDefinition id, eg "us-core-race" for "Patient.extension:us-core-race" or "ombCategory" for "Patient.extension:us-core-race.extension:ombCategory".
- #extract_required_binding_values(pattern_element, metadata) ⇒ Object
- #extract_supported_types(current_element) ⇒ Object
- #extract_target_profiles(type) ⇒ Object
- #find_choice_element(current_element, target_element, target_type) ⇒ Object
- #find_element_by_discriminator_path(current_element, discriminator_path) ⇒ Object
- #get_type_must_support_metadata(current_metadata, current_element) ⇒ Object
- #handle_choice_type_in_sliced_element(current_metadata, must_support_elements_metadata) ⇒ Object
- #handle_fixed_values(metadata, element) ⇒ Object
- #handle_type_must_support_target_profiles(type, metadata) ⇒ Object
-
#initialize(profile_elements, profile, resource, ig_resources, requirement_extension_url = nil) ⇒ MustSupportMetadataExtractor
constructor
Construct a new extractor.
- #legacy_choice_discriminator_step?(path) ⇒ Boolean
- #must_support_elements ⇒ Object
- #must_support_extension_elements ⇒ Object
- #must_support_extensions ⇒ Object
- #must_support_slice_elements ⇒ Object
- #must_support_slices ⇒ Object
- #must_support_type_slice_elements ⇒ Object
- #must_support_value_slice_elements ⇒ Object
-
#must_supports ⇒ Hash
Retrieval method for the must support metadata.
- #navigation_compatible_discriminator_path(discriminator_path) ⇒ Object
- #plain_must_support_elements ⇒ Object
-
#profile_name ⇒ String
The human-readable name of the profile, eg for display purposes.
-
#profile_url ⇒ String
The canonical URL of the profile.
-
#profile_version ⇒ String
The version of the profile itself (distinct from the IG's own version).
-
#prohibited_by_cardinality?(element) ⇒ Boolean
A profile can inherit mustSupport flags from a base profile while constraining the element to a max cardinality of 0.
-
#recursive_element_segments ⇒ Array<String>
Names of path segments that are self-referential, ie, they may repeat at arbitrary depth.
- #remove_conflicting_metadata_without_fixed_value(must_support_elements_metadata, current_metadata) ⇒ Object
- #required_binding_pattern?(pattern_element) ⇒ Boolean
- #save_pattern_slice(pattern_element, discriminator_path, metadata) ⇒ Object
- #save_type_code?(type) ⇒ Boolean
- #slice_has_must_support_descendants?(slice) ⇒ Boolean
- #sliced_element(slice) ⇒ Object
- #take_choice_discriminator_step(current_element, step_path, remaining_path) ⇒ Object
- #take_discriminator_step(current_element, path) ⇒ Object
- #take_extension_discriminator_step(current_element, path) ⇒ Object
- #take_legacy_choice_discriminator_step(current_element, step_path, remaining_path) ⇒ Object
- #take_standard_discriminator_step(current_element, path) ⇒ Object
- #type_must_support_extension?(extensions) ⇒ Boolean
- #type_slices ⇒ Object
- #value_not_empty?(value) ⇒ Boolean
-
#value_slices ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity.
Constructor Details
#initialize(profile_elements, profile, resource, ig_resources, requirement_extension_url = nil) ⇒ MustSupportMetadataExtractor
Construct a new extractor
19 20 21 22 23 24 25 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 19 def initialize(profile_elements, profile, resource, ig_resources, requirement_extension_url = nil) self.profile_elements = profile_elements self.profile = profile self.resource = resource self.ig_resources = ig_resources self.requirement_extension_url = requirement_extension_url end |
Instance Attribute Details
#ig_resources ⇒ Object
Returns the value of attribute ig_resources.
10 11 12 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 10 def ig_resources @ig_resources end |
#profile ⇒ Object
Returns the value of attribute profile.
10 11 12 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 10 def profile @profile end |
#profile_elements ⇒ Object
Returns the value of attribute profile_elements.
10 11 12 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 10 def profile_elements @profile_elements end |
#requirement_extension_url ⇒ Object
Returns the value of attribute requirement_extension_url.
10 11 12 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 10 def requirement_extension_url @requirement_extension_url end |
#resource ⇒ Object
Returns the value of attribute resource.
10 11 12 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 10 def resource @resource end |
Instance Method Details
#all_must_support_elements ⇒ Object
77 78 79 80 81 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 77 def all_must_support_elements profile_elements.select do |element| (element.mustSupport || by_requirement_extension_only?(element)) && !prohibited_by_cardinality?(element) end end |
#by_requirement_extension_only?(element) ⇒ Boolean
70 71 72 73 74 75 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 70 def by_requirement_extension_only?(element) requirement_extension_url && !element.mustSupport && element.extension.any? do |extension| extension.url == requirement_extension_url && extension.valueBoolean end end |
#canonical_url_without_version(url) ⇒ Object
121 122 123 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 121 def canonical_url_without_version(url) url&.split('|')&.first end |
#discriminator_path(discriminator) ⇒ Object
304 305 306 307 308 309 310 311 312 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 304 def discriminator_path(discriminator) if discriminator.path == '$this' '' elsif discriminator.path.start_with?('$this.') discriminator.path[6..] else discriminator.path end end |
#discriminators(slice) ⇒ Object
139 140 141 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 139 def discriminators(slice) slice&.slicing&.discriminator end |
#element_matches_choice_type?(element, target_path, target_type) ⇒ Boolean
234 235 236 237 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 234 def element_matches_choice_type?(element, target_path, target_type) [element.id, element.path].include?(target_path) && element.type.any? { |type| type.code.casecmp?(target_type) } end |
#element_part_of_slice_discrimination?(element) ⇒ Boolean
414 415 416 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 414 def element_part_of_slice_discrimination?(element) must_support_slice_elements.any? { |ms_slice| element.id.include?(ms_slice.id) } end |
#extension_discriminator_step?(path) ⇒ Boolean
167 168 169 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 167 def extension_discriminator_step?(path) path.start_with?('extension(') || path.start_with?('modifierExtension(') end |
#extension_profile_matches?(type, ext_url) ⇒ Boolean
183 184 185 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 183 def extension_profile_matches?(type, ext_url) type.code == 'Extension' && type.profile.any? { |profile| profile.start_with?(ext_url) } end |
#extension_slice_name(element_id) ⇒ String?
The name of the deepest slice in a FHIR ElementDefinition id, eg "us-core-race" for "Patient.extension:us-core-race" or "ombCategory" for "Patient.extension:us-core-race.extension:ombCategory".
117 118 119 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 117 def extension_slice_name(element_id) element_id.split('.').reverse.find { |segment| segment.include?(':') }&.split(':', 2)&.last end |
#extract_required_binding_values(pattern_element, metadata) ⇒ Object
281 282 283 284 285 286 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 281 def extract_required_binding_values(pattern_element, ) value_extractor = ValueExtractor.new(ig_resources, resource, profile_elements) value_extractor.codings_from_value_set_binding(pattern_element).presence || value_extractor.([[:path]]).presence || [] end |
#extract_supported_types(current_element) ⇒ Object
534 535 536 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 534 def extract_supported_types(current_element) current_element.type.select { |type| save_type_code?(type) }.map(&:code) end |
#extract_target_profiles(type) ⇒ Object
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 471 def extract_target_profiles(type) target_profiles = [] if type.targetProfile&.length == 1 target_profiles << type.targetProfile.first else type.source_hash['_targetProfile']&.each_with_index do |hash, index| if hash.present? element = FHIR::Element.new(hash) target_profiles << type.targetProfile[index] if type_must_support_extension?(element.extension) end end end target_profiles end |
#find_choice_element(current_element, target_element, target_type) ⇒ Object
226 227 228 229 230 231 232 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 226 def find_choice_element(current_element, target_element, target_type) [current_element.id, current_element.path].filter_map do |base_path| profile_elements.find do |element| element_matches_choice_type?(element, "#{base_path}.#{target_element}", target_type) end end.first end |
#find_element_by_discriminator_path(current_element, discriminator_path) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 149 def find_element_by_discriminator_path(current_element, discriminator_path) target_element = current_element remaining_path = discriminator_path while remaining_path.present? target_element, remaining_path = take_discriminator_step(target_element, remaining_path) return nil if target_element.nil? end target_element end |
#get_type_must_support_metadata(current_metadata, current_element) ⇒ Object
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 447 def (, current_element) current_element.type.map do |type| next unless type_must_support_extension?(type.extension) = { path: "#{[:path].delete_suffix('[x]')}#{type.code.upcase_first}", original_path: [:path] } [:types] = [type.code] if save_type_code?(type) handle_type_must_support_target_profiles(type, ) if type.code == 'Reference' end.compact end |
#handle_choice_type_in_sliced_element(current_metadata, must_support_elements_metadata) ⇒ Object
488 489 490 491 492 493 494 495 496 497 498 499 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 488 def handle_choice_type_in_sliced_element(, ) = .find do || [:original_path].present? && [:path].include?([:original_path]) end return unless .present? [:original_path] = [:path] [:path] = [:path].sub([:original_path], [:path]) end |
#handle_fixed_values(metadata, element) ⇒ Object
422 423 424 425 426 427 428 429 430 431 432 433 434 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 422 def handle_fixed_values(, element) if value_not_empty?(element.fixed) [:fixed_value] = element.fixed elsif element.patternCodeableConcept.present? && !element_part_of_slice_discrimination?(element) [:fixed_value] = element.patternCodeableConcept.coding.first.code [:path] += '.coding.code' elsif element.fixedCode.present? [:fixed_value] = element.fixedCode elsif element.patternIdentifier.present? && !element_part_of_slice_discrimination?(element) [:fixed_value] = element.patternIdentifier.system [:path] += '.system' end end |
#handle_type_must_support_target_profiles(type, metadata) ⇒ Object
463 464 465 466 467 468 469 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 463 def handle_type_must_support_target_profiles(type, ) target_profiles = extract_target_profiles(type) # remove target_profile for FHIR Base resource type. target_profiles.delete_if { |reference| reference.start_with?('http://hl7.org/fhir/StructureDefinition') } [:target_profiles] = target_profiles if target_profiles.present? end |
#legacy_choice_discriminator_step?(path) ⇒ Boolean
203 204 205 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 203 def legacy_choice_discriminator_step?(path) path.match?(/\A.+\s+as\s+[[:word:]]+\z/) end |
#must_support_elements ⇒ Object
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 501 def must_support_elements = [] plain_must_support_elements.each do |current_element| = { path: current_element.id.gsub("#{resource}.", '') } [:by_requirement_extension_only] = true if by_requirement_extension_only?(current_element) = (, current_element) if .any? .concat() else handle_choice_type_in_sliced_element(, ) supported_types = extract_supported_types(current_element) [:types] = supported_types if supported_types.present? if current_element.type.first&.code == 'Reference' handle_type_must_support_target_profiles(current_element.type.first, ) end handle_fixed_values(, current_element) (, ) << end end .uniq end |
#must_support_extension_elements ⇒ Object
94 95 96 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 94 def must_support_extension_elements all_must_support_elements.select { |element| element.path.end_with? 'xtension' } end |
#must_support_extensions ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 98 def must_support_extensions must_support_extension_elements.map do |element| { id: element.id, slice_name: extension_slice_name(element.id), path: element.path.gsub("#{resource}.", ''), url: canonical_url_without_version(element.type.first.profile.first), modifier_extension: element.path.end_with?('modifierExtension') }.tap do || [:by_requirement_extension_only] = true if by_requirement_extension_only?(element) end end end |
#must_support_slice_elements ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 125 def must_support_slice_elements profile_elements.select do |element| next false if element.sliceName.blank? || element.path.end_with?('xtension') all_must_support_elements.include?(element) || slice_has_must_support_descendants?(element) end end |
#must_support_slices ⇒ Object
406 407 408 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 406 def must_support_slices type_slices + value_slices end |
#must_support_type_slice_elements ⇒ Object
288 289 290 291 292 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 288 def must_support_type_slice_elements must_support_slice_elements.select do |element| discriminators(sliced_element(element))&.first&.type == 'type' end end |
#must_support_value_slice_elements ⇒ Object
339 340 341 342 343 344 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 339 def must_support_value_slice_elements must_support_slice_elements.select do |element| # discriminator type 'pattern' is deprecated in FHIR R5 and made equivalent to 'value' ['value', 'pattern'].include?(discriminators(sliced_element(element))&.first&.type) end end |
#must_supports ⇒ Hash
Retrieval method for the must support metadata
45 46 47 48 49 50 51 52 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 45 def must_supports @must_supports ||= { extensions: must_support_extensions, slices: must_support_slices, elements: must_support_elements, recursive_elements: recursive_element_segments } end |
#navigation_compatible_discriminator_path(discriminator_path) ⇒ Object
294 295 296 297 298 299 300 301 302 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 294 def (discriminator_path) normalized_path = discriminator_path&.gsub(/(modifierExtension|extension)\('([^']+)'\)/, "\\1.where(url='\\2')") normalized_path = normalized_path&.gsub(/([[:word:]\[\]]+)\.ofType\(([^)]+)\)/) do "#{Regexp.last_match(1).delete_suffix('[x]')}#{Regexp.last_match(2).upcase_first}" end normalized_path&.gsub(/([[:word:]\[\]]+)\s+as\s+([[:word:]]+)/) do "#{Regexp.last_match(1).delete_suffix('[x]')}#{Regexp.last_match(2).upcase_first}" end end |
#plain_must_support_elements ⇒ Object
410 411 412 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 410 def plain_must_support_elements all_must_support_elements - must_support_extension_elements - must_support_slice_elements end |
#profile_name ⇒ String
Returns the human-readable name of the profile, eg for display purposes. Collapses any runs of repeated whitespace, since profile titles occasionally have them.
34 35 36 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 34 def profile_name profile.title&.squeeze(' ') end |
#profile_url ⇒ String
Returns the canonical URL of the profile.
28 29 30 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 28 def profile_url profile.url end |
#profile_version ⇒ String
Returns the version of the profile itself (distinct from the IG's own version).
39 40 41 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 39 def profile_version profile.version end |
#prohibited_by_cardinality?(element) ⇒ Boolean
A profile can inherit mustSupport flags from a base profile while constraining the element to a max cardinality of 0. Such an element, and its descendants, cannot appear in a conformant resource.
85 86 87 88 89 90 91 92 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 85 def prohibited_by_cardinality?(element) profile_elements.any? do |profile_element| profile_element.max == '0' && (element.id == profile_element.id || element.id.start_with?("#{profile_element.id}.") || element.id.start_with?("#{profile_element.id}:")) end end |
#recursive_element_segments ⇒ Array<String>
Names of path segments that are self-referential, ie, they may repeat at
arbitrary depth. FHIR marks this with a contentReference back to an
ancestor element instead of re-declaring the element's children, eg,
Questionnaire.item.item has a contentReference of "#Questionnaire.item".
A MustSupport flag on an element under such a segment (eg Questionnaire.item.text)
should be considered met if it's populated at any depth of nesting
(item.text, item.item.text, item.item.item.text, ...), not just the literal depth
at which the flag is declared. NOTE: does not currently handle sliced recursive elements.
63 64 65 66 67 68 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 63 def recursive_element_segments profile_elements .select { |element| element.contentReference.present? } .map { |element| element.id.split('.').last } .uniq end |
#remove_conflicting_metadata_without_fixed_value(must_support_elements_metadata, current_metadata) ⇒ Object
538 539 540 541 542 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 538 def (, ) .delete_if do || [:path] == [:path] && [:fixed_value].blank? end end |
#required_binding_pattern?(pattern_element) ⇒ Boolean
277 278 279 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 277 def required_binding_pattern?(pattern_element) pattern_element.binding&.strength == 'required' && pattern_element.binding&.valueSet end |
#save_pattern_slice(pattern_element, discriminator_path, metadata) ⇒ Object
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 239 def save_pattern_slice(pattern_element, discriminator_path, ) runtime_path = (discriminator_path) if pattern_element.patternCodeableConcept { type: 'patternCodeableConcept', path: runtime_path, code: pattern_element.patternCodeableConcept.coding.first.code, system: pattern_element.patternCodeableConcept.coding.first.system } elsif pattern_element.patternCoding { type: 'patternCoding', path: runtime_path, code: pattern_element.patternCoding.code, system: pattern_element.patternCoding.system } elsif pattern_element.patternIdentifier { type: 'patternIdentifier', path: runtime_path, system: pattern_element.patternIdentifier.system } elsif required_binding_pattern?(pattern_element) { type: 'requiredBinding', path: runtime_path, values: extract_required_binding_values(pattern_element, ) } else # prevent errors in case an IG does something different { type: 'unsupported', path: runtime_path } end end |
#save_type_code?(type) ⇒ Boolean
443 444 445 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 443 def save_type_code?(type) type.code == 'Reference' end |
#slice_has_must_support_descendants?(slice) ⇒ Boolean
143 144 145 146 147 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 143 def slice_has_must_support_descendants?(slice) all_must_support_elements.any? do |element| element.id.start_with?("#{slice.id}.") end end |
#sliced_element(slice) ⇒ Object
133 134 135 136 137 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 133 def sliced_element(slice) profile_elements.find do |element| element.id == slice.path || element.id == slice.id.sub(":#{slice.sliceName}", '') end end |
#take_choice_discriminator_step(current_element, step_path, remaining_path) ⇒ Object
207 208 209 210 211 212 213 214 215 216 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 207 def take_choice_discriminator_step(current_element, step_path, remaining_path) target_element = "#{step_path}[x]" target_type, remaining_path = remaining_path.delete_prefix('ofType(').split(')', 2) next_element = profile_elements.find do |element| element.id == "#{current_element.id}.#{target_element}" && element.type.any? { |type| type.code.casecmp?(target_type) } end [next_element, remaining_path&.delete_prefix('.')] end |
#take_discriminator_step(current_element, path) ⇒ Object
161 162 163 164 165 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 161 def take_discriminator_step(current_element, path) return take_extension_discriminator_step(current_element, path) if extension_discriminator_step?(path) take_standard_discriminator_step(current_element, path) end |
#take_extension_discriminator_step(current_element, path) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 171 def take_extension_discriminator_step(current_element, path) extension_type = path.start_with?('modifierExtension(') ? 'modifierExtension' : 'extension' ext_url, remaining_path = path.delete_prefix("#{extension_type}('").split("')", 2) next_element = profile_elements.find do |element| element.path == "#{current_element.path}.#{extension_type}" && element.id.start_with?("#{current_element.id}.#{extension_type}:") && element.type.any? { |type| extension_profile_matches?(type, ext_url) } end [next_element, remaining_path&.delete_prefix('.')] end |
#take_legacy_choice_discriminator_step(current_element, step_path, remaining_path) ⇒ Object
218 219 220 221 222 223 224 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 218 def take_legacy_choice_discriminator_step(current_element, step_path, remaining_path) target_element, target_type = step_path.split(/\s+as\s+/, 2) target_element = "#{target_element}[x]" unless target_element.end_with?('[x]') next_element = find_choice_element(current_element, target_element, target_type) [next_element, remaining_path&.delete_prefix('.')] end |
#take_standard_discriminator_step(current_element, path) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 187 def take_standard_discriminator_step(current_element, path) step_path, remaining_path = path.split('.', 2) if remaining_path&.start_with?('ofType(') return take_choice_discriminator_step(current_element, step_path, remaining_path) end if legacy_choice_discriminator_step?(step_path) return take_legacy_choice_discriminator_step(current_element, step_path, remaining_path) end next_element = profile_elements.find { |element| element.id == "#{current_element.id}.#{step_path}" } || profile_elements.find { |element| element.id == "#{current_element.path}.#{step_path}" } [next_element, remaining_path&.delete_prefix('.')] end |
#type_must_support_extension?(extensions) ⇒ Boolean
436 437 438 439 440 441 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 436 def type_must_support_extension?(extensions) extensions&.any? do |extension| extension.url == 'http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support' && extension.valueBoolean end end |
#type_slices ⇒ Object
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 314 def type_slices must_support_type_slice_elements.map do |current_element| discriminator = discriminators(sliced_element(current_element)).first type_path = discriminator_path(discriminator) type_element = find_element_by_discriminator_path(current_element, type_path) type_code = type_element.type.first.code = { type: 'type', code: type_code.upcase_first } runtime_path = (type_path) [:path] = runtime_path if runtime_path.present? { slice_id: current_element.id, slice_name: current_element.sliceName, path: current_element.path.gsub("#{resource}.", ''), discriminator: }.tap do || [:by_requirement_extension_only] = true if by_requirement_extension_only?(current_element) end end end |
#value_not_empty?(value) ⇒ Boolean
418 419 420 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 418 def value_not_empty?(value) value.present? || value == false end |
#value_slices ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 346 def value_slices # rubocop:disable Metrics/CyclomaticComplexity must_support_value_slice_elements.map do |current_element| { slice_id: current_element.id, slice_name: current_element.sliceName, path: current_element.path.gsub("#{resource}.", '') }.tap do || fixed_values = [] pattern_value = {} element_discriminators = discriminators(sliced_element(current_element)) element_discriminators.each do |discriminator| discriminator_path = discriminator_path(discriminator) pattern_element = find_element_by_discriminator_path(current_element, discriminator_path) # This is a workaround for a known version of a profile that has a bad discriminator: # the discriminator refers to a nested field within a CodeableConcept, # but the profile doesn't contain an element definition for it, so there's no way to # define a fixed value on the element to define the slice. # In this instance the element has a second (good) discriminator on the CodeableConcept field itself, # and in subsequent versions of the profile, the bad discriminator was removed. next if pattern_element.nil? && element_discriminators.length > 1 if pattern_element.nil? pattern_value = { type: 'unsupported', path: (discriminator_path) } elsif value_not_empty?(pattern_element.fixed) fixed_values << { path: (discriminator_path), value: pattern_element.fixed } elsif pattern_element.patternString fixed_values << { path: (discriminator_path), value: pattern_element.patternString } elsif pattern_value.present? raise StandardError, "Found more than one pattern slices for the same element #{pattern_element}." else pattern_value = save_pattern_slice(pattern_element, discriminator_path, ) end end if fixed_values.present? [:discriminator] = { type: 'value', values: fixed_values } elsif pattern_value.present? [:discriminator] = pattern_value end [:by_requirement_extension_only] = true if by_requirement_extension_only?(current_element) end end end |