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).
-
#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 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 77 def all_must_support_elements profile_elements.select { |element| element.mustSupport || by_requirement_extension_only?(element) } 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
108 109 110 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 108 def canonical_url_without_version(url) url&.split('|')&.first end |
#discriminator_path(discriminator) ⇒ Object
291 292 293 294 295 296 297 298 299 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 291 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
126 127 128 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 126 def discriminators(slice) slice&.slicing&.discriminator end |
#element_matches_choice_type?(element, target_path, target_type) ⇒ Boolean
221 222 223 224 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 221 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
396 397 398 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 396 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
154 155 156 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 154 def extension_discriminator_step?(path) path.start_with?('extension(') || path.start_with?('modifierExtension(') end |
#extension_profile_matches?(type, ext_url) ⇒ Boolean
170 171 172 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 170 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".
104 105 106 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 104 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
268 269 270 271 272 273 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 268 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
516 517 518 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 516 def extract_supported_types(current_element) current_element.type.select { |type| save_type_code?(type) }.map(&:code) end |
#extract_target_profiles(type) ⇒ Object
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 453 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
213 214 215 216 217 218 219 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 213 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
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 136 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
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 429 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
470 471 472 473 474 475 476 477 478 479 480 481 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 470 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
404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 404 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
445 446 447 448 449 450 451 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 445 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
190 191 192 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 190 def legacy_choice_discriminator_step?(path) path.match?(/\A.+\s+as\s+[[:word:]]+\z/) end |
#must_support_elements ⇒ Object
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 483 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
81 82 83 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 81 def must_support_extension_elements all_must_support_elements.select { |element| element.path.end_with? 'xtension' } end |
#must_support_extensions ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 85 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
112 113 114 115 116 117 118 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 112 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
388 389 390 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 388 def must_support_slices type_slices + value_slices end |
#must_support_type_slice_elements ⇒ Object
275 276 277 278 279 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 275 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
326 327 328 329 330 331 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 326 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
281 282 283 284 285 286 287 288 289 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 281 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
392 393 394 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 392 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 |
#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
520 521 522 523 524 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 520 def (, ) .delete_if do || [:path] == [:path] && [:fixed_value].blank? end end |
#required_binding_pattern?(pattern_element) ⇒ Boolean
264 265 266 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 264 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
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 226 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
425 426 427 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 425 def save_type_code?(type) type.code == 'Reference' end |
#slice_has_must_support_descendants?(slice) ⇒ Boolean
130 131 132 133 134 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 130 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
120 121 122 123 124 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 120 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
194 195 196 197 198 199 200 201 202 203 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 194 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
148 149 150 151 152 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 148 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
158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 158 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
205 206 207 208 209 210 211 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 205 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
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 174 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
418 419 420 421 422 423 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 418 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
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 301 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
400 401 402 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 400 def value_not_empty?(value) value.present? || value == false end |
#value_slices ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity
333 334 335 336 337 338 339 340 341 342 343 344 345 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 |
# File 'lib/inferno/dsl/must_support_metadata_extractor.rb', line 333 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_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 |