foobara 0.0.91 → 0.0.93
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 +4 -4
 - data/CHANGELOG.md +15 -2
 - data/projects/builtin_types/src/email/validator_base.rb +1 -1
 - data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +39 -18
 - data/projects/command/src/transformed_command.rb +85 -40
 - data/projects/command_connectors/src/command_connector/commands/describe.rb +1 -5
 - data/projects/command_connectors/src/command_connector.rb +65 -55
 - data/projects/command_connectors/src/command_registry/exposed_command.rb +2 -2
 - data/projects/command_connectors/src/command_registry/exposed_domain.rb +10 -3
 - data/projects/command_connectors/src/command_registry/exposed_organization.rb +2 -2
 - data/projects/command_connectors/src/command_registry.rb +9 -0
 - data/projects/command_connectors/src/serializers/atomic_serializer.rb +1 -1
 - data/projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb +40 -0
 - data/projects/common/src/data_path.rb +16 -0
 - data/projects/common/src/error.rb +35 -5
 - data/projects/common/src/outcome.rb +11 -5
 - data/projects/common/src/possible_error.rb +9 -3
 - data/projects/detached_entity/src/concerns/associations.rb +26 -20
 - data/projects/detached_entity/src/concerns/reflection.rb +3 -3
 - data/projects/detached_entity/src/detached_entity_type.rb +8 -3
 - data/projects/detached_entity/src/extensions/builtin_types/detached_entity/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
 - data/projects/domain/src/domain_module_extension.rb +12 -4
 - data/projects/domain/src/extensions/foobara.rb +31 -28
 - data/projects/domain/src/is_manifestable.rb +6 -2
 - data/projects/domain/src/organization_module_extension.rb +6 -2
 - data/projects/entity/src/concerns/queries.rb +29 -31
 - data/projects/entity/src/extensions/builtin_types/entity/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
 - data/projects/model/src/concerns/reflection.rb +8 -2
 - data/projects/model/src/concerns/types.rb +121 -23
 - data/projects/model/src/extensions/builtin_types/model/supported_transformers/mutable.rb +1 -2
 - data/projects/model/src/extensions/builtin_types/model/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/array_with_symbolic_elements.rb +29 -0
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_desugarizer.rb +39 -0
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_validator.rb +44 -0
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/move_private_from_element_types_to_root.rb +48 -0
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/symbolize_private.rb +34 -0
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +34 -2
 - data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/valid_attribute_names.rb +54 -0
 - data/projects/model/src/model.rb +9 -0
 - data/projects/model_attribute_helpers/src/attribute_helpers.rb +25 -4
 - data/projects/namespace/src/is_namespace.rb +34 -15
 - data/projects/persistence/src/entity_attributes_crud_driver.rb +25 -1
 - data/projects/persistence/src/entity_base/transaction_table.rb +28 -3
 - data/projects/type_declarations/src/desugarizer.rb +1 -1
 - data/projects/type_declarations/src/remove_sensitive_values_transformer.rb +6 -0
 - data/projects/type_declarations/src/type_builder.rb +42 -39
 - data/projects/type_declarations/src/type_declaration_handler.rb +1 -1
 - data/projects/type_declarations/src/type_declaration_handler_registry.rb +1 -1
 - data/projects/type_declarations/src/type_declaration_validator.rb +1 -1
 - data/projects/type_declarations/src/type_declarations.rb +39 -10
 - data/projects/types/src/extensions/error.rb +3 -3
 - data/projects/types/src/type/concerns/reflection.rb +79 -4
 - data/projects/types/src/type.rb +42 -17
 - data/projects/value/src/caster.rb +1 -1
 - data/projects/value/src/mutator.rb +1 -1
 - data/projects/value/src/processor/casting.rb +1 -1
 - data/projects/value/src/processor/pipeline.rb +1 -1
 - data/projects/value/src/processor/selection.rb +1 -1
 - data/projects/value/src/processor.rb +13 -5
 - data/projects/value/src/transformer.rb +1 -1
 - data/projects/value/src/validator.rb +1 -1
 - metadata +12 -5
 
| 
         @@ -98,28 +98,29 @@ module Foobara 
     | 
|
| 
       98 
98 
     | 
    
         
             
                    path,
         
     | 
| 
       99 
99 
     | 
    
         
             
                    filter: nil,
         
     | 
| 
       100 
100 
     | 
    
         
             
                    mode: LookupMode::GENERAL,
         
     | 
| 
       101 
     | 
    
         
            -
                    visited: Set.new
         
     | 
| 
      
 101 
     | 
    
         
            +
                    visited: Set.new,
         
     | 
| 
      
 102 
     | 
    
         
            +
                    initial: true
         
     | 
| 
       102 
103 
     | 
    
         
             
                  )
         
     | 
| 
       103 
     | 
    
         
            -
                     
     | 
| 
      
 104 
     | 
    
         
            +
                    path = Namespace.to_registry_path(path)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    visited_key = [path, mode, initial, self]
         
     | 
| 
       104 
106 
     | 
    
         
             
                    return nil if visited.include?(visited_key)
         
     | 
| 
       105 
107 
     | 
    
         | 
| 
       106 
108 
     | 
    
         
             
                    visited << visited_key
         
     | 
| 
       107 
109 
     | 
    
         | 
| 
       108 
110 
     | 
    
         
             
                    LookupMode.validate!(mode)
         
     | 
| 
       109 
111 
     | 
    
         | 
| 
       110 
     | 
    
         
            -
                    path = Namespace.to_registry_path(path)
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
112 
     | 
    
         
             
                    if mode == LookupMode::RELAXED
         
     | 
| 
       113 
113 
     | 
    
         
             
                      scoped = foobara_lookup(
         
     | 
| 
       114 
114 
     | 
    
         
             
                        path,
         
     | 
| 
       115 
115 
     | 
    
         
             
                        filter:,
         
     | 
| 
       116 
116 
     | 
    
         
             
                        mode: LookupMode::GENERAL,
         
     | 
| 
       117 
     | 
    
         
            -
                        visited 
     | 
| 
      
 117 
     | 
    
         
            +
                        visited:,
         
     | 
| 
      
 118 
     | 
    
         
            +
                        initial: false
         
     | 
| 
       118 
119 
     | 
    
         
             
                      )
         
     | 
| 
       119 
120 
     | 
    
         
             
                      return scoped if scoped
         
     | 
| 
       120 
121 
     | 
    
         | 
| 
       121 
122 
     | 
    
         
             
                      candidates = foobara_children.map do |namespace|
         
     | 
| 
       122 
     | 
    
         
            -
                        namespace.foobara_lookup(path, filter:, mode:, visited:)
         
     | 
| 
      
 123 
     | 
    
         
            +
                        namespace.foobara_lookup(path, filter:, mode:, visited:, initial: false)
         
     | 
| 
       123 
124 
     | 
    
         
             
                      end.compact
         
     | 
| 
       124 
125 
     | 
    
         | 
| 
       125 
126 
     | 
    
         
             
                      if candidates.size > 1
         
     | 
| 
         @@ -129,7 +130,8 @@ module Foobara 
     | 
|
| 
       129 
130 
     | 
    
         
             
                        # :nocov:
         
     | 
| 
       130 
131 
     | 
    
         
             
                      end
         
     | 
| 
       131 
132 
     | 
    
         | 
| 
       132 
     | 
    
         
            -
                      return candidates.first || 
     | 
| 
      
 133 
     | 
    
         
            +
                      return candidates.first ||
         
     | 
| 
      
 134 
     | 
    
         
            +
                             foobara_parent_namespace&.foobara_lookup(path, filter:, mode:, visited:, initial: false)
         
     | 
| 
       133 
135 
     | 
    
         
             
                    end
         
     | 
| 
       134 
136 
     | 
    
         | 
| 
       135 
137 
     | 
    
         
             
                    if path[0] == ""
         
     | 
| 
         @@ -141,7 +143,7 @@ module Foobara 
     | 
|
| 
       141 
143 
     | 
    
         
             
                        path = path[(foobara_root_namespace.scoped_path.size + 1)..]
         
     | 
| 
       142 
144 
     | 
    
         
             
                      end
         
     | 
| 
       143 
145 
     | 
    
         | 
| 
       144 
     | 
    
         
            -
                      return foobara_root_namespace.foobara_lookup(path, filter:, mode: LookupMode::ABSOLUTE)
         
     | 
| 
      
 146 
     | 
    
         
            +
                      return foobara_root_namespace.foobara_lookup(path, filter:, mode: LookupMode::ABSOLUTE, initial: true)
         
     | 
| 
       145 
147 
     | 
    
         
             
                    end
         
     | 
| 
       146 
148 
     | 
    
         | 
| 
       147 
149 
     | 
    
         
             
                    partial = foobara_registry.lookup(path, filter)
         
     | 
| 
         @@ -166,12 +168,16 @@ module Foobara 
     | 
|
| 
       166 
168 
     | 
    
         
             
                    return scoped if scoped
         
     | 
| 
       167 
169 
     | 
    
         | 
| 
       168 
170 
     | 
    
         
             
                    if [LookupMode::GENERAL, LookupMode::STRICT].include?(mode) && foobara_parent_namespace
         
     | 
| 
       169 
     | 
    
         
            -
                      scoped = foobara_parent_namespace.foobara_lookup( 
     | 
| 
      
 171 
     | 
    
         
            +
                      scoped = foobara_parent_namespace.foobara_lookup(
         
     | 
| 
      
 172 
     | 
    
         
            +
                        path, filter:, mode: LookupMode::STRICT, visited:, initial: false
         
     | 
| 
      
 173 
     | 
    
         
            +
                      )
         
     | 
| 
       170 
174 
     | 
    
         
             
                      return scoped if scoped
         
     | 
| 
       171 
175 
     | 
    
         
             
                    end
         
     | 
| 
       172 
176 
     | 
    
         | 
| 
       173 
     | 
    
         
            -
                     
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
      
 177 
     | 
    
         
            +
                    if mode == LookupMode::GENERAL
         
     | 
| 
      
 178 
     | 
    
         
            +
                      scoped = _lookup_in(path, foobara_depends_on_namespaces, filter:, visited:)
         
     | 
| 
      
 179 
     | 
    
         
            +
                      return scoped if scoped
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
       175 
181 
     | 
    
         | 
| 
       176 
182 
     | 
    
         
             
                    to_consider = case mode
         
     | 
| 
       177 
183 
     | 
    
         
             
                                  when LookupMode::GENERAL
         
     | 
| 
         @@ -181,7 +187,7 @@ module Foobara 
     | 
|
| 
       181 
187 
     | 
    
         
             
                                  end
         
     | 
| 
       182 
188 
     | 
    
         | 
| 
       183 
189 
     | 
    
         
             
                    candidates = to_consider.map do |namespace|
         
     | 
| 
       184 
     | 
    
         
            -
                      namespace.foobara_lookup(path, filter:, mode:, visited:)
         
     | 
| 
      
 190 
     | 
    
         
            +
                      namespace.foobara_lookup(path, filter:, mode:, visited:, initial: false)
         
     | 
| 
       185 
191 
     | 
    
         
             
                    end.compact
         
     | 
| 
       186 
192 
     | 
    
         | 
| 
       187 
193 
     | 
    
         
             
                    if candidates.size > 1
         
     | 
| 
         @@ -190,7 +196,19 @@ module Foobara 
     | 
|
| 
       190 
196 
     | 
    
         
             
                      # :nocov:
         
     | 
| 
       191 
197 
     | 
    
         
             
                    end
         
     | 
| 
       192 
198 
     | 
    
         | 
| 
       193 
     | 
    
         
            -
                    candidates.first || partial
         
     | 
| 
      
 199 
     | 
    
         
            +
                    scoped = candidates.first || partial
         
     | 
| 
      
 200 
     | 
    
         
            +
                    return scoped if scoped
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                    # As a last resort we'll see if we're trying to fetch a builtin type from a different namespace
         
     | 
| 
      
 203 
     | 
    
         
            +
                    # TODO: these lookup modes are really confusing and were designed prior to having multiple root
         
     | 
| 
      
 204 
     | 
    
         
            +
                    # namespaces playing a role in command connectors.
         
     | 
| 
      
 205 
     | 
    
         
            +
                    if initial
         
     | 
| 
      
 206 
     | 
    
         
            +
                      scoped = Namespace.global.foobara_lookup(path, filter:, mode: LookupMode::ABSOLUTE, visited:, initial: false)
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                      if scoped.is_a?(Types::Type) && scoped.builtin?
         
     | 
| 
      
 209 
     | 
    
         
            +
                        scoped
         
     | 
| 
      
 210 
     | 
    
         
            +
                      end
         
     | 
| 
      
 211 
     | 
    
         
            +
                    end
         
     | 
| 
       194 
212 
     | 
    
         
             
                  end
         
     | 
| 
       195 
213 
     | 
    
         | 
| 
       196 
214 
     | 
    
         
             
                  def foobara_parent_namespace
         
     | 
| 
         @@ -330,14 +348,15 @@ module Foobara 
     | 
|
| 
       330 
348 
     | 
    
         
             
                        path[matching_child_score..],
         
     | 
| 
       331 
349 
     | 
    
         
             
                        mode: LookupMode::ABSOLUTE,
         
     | 
| 
       332 
350 
     | 
    
         
             
                        filter:,
         
     | 
| 
       333 
     | 
    
         
            -
                        visited 
     | 
| 
      
 351 
     | 
    
         
            +
                        visited:,
         
     | 
| 
      
 352 
     | 
    
         
            +
                        initial: false
         
     | 
| 
       334 
353 
     | 
    
         
             
                      )
         
     | 
| 
       335 
354 
     | 
    
         | 
| 
       336 
355 
     | 
    
         
             
                      return scoped if scoped
         
     | 
| 
       337 
356 
     | 
    
         
             
                    end
         
     | 
| 
       338 
357 
     | 
    
         | 
| 
       339 
358 
     | 
    
         
             
                    last_resort.uniq.each do |namespace|
         
     | 
| 
       340 
     | 
    
         
            -
                      scoped = namespace.foobara_lookup(path, filter:, mode: LookupMode::ABSOLUTE, visited:)
         
     | 
| 
      
 359 
     | 
    
         
            +
                      scoped = namespace.foobara_lookup(path, filter:, mode: LookupMode::ABSOLUTE, visited:, initial: false)
         
     | 
| 
       341 
360 
     | 
    
         
             
                      return scoped if scoped
         
     | 
| 
       342 
361 
     | 
    
         
             
                    end
         
     | 
| 
       343 
362 
     | 
    
         | 
| 
         @@ -155,7 +155,31 @@ module Foobara 
     | 
|
| 
       155 
155 
     | 
    
         
             
                    end
         
     | 
| 
       156 
156 
     | 
    
         | 
| 
       157 
157 
     | 
    
         
             
                    def matches_attributes_filter?(attributes, attributes_filter)
         
     | 
| 
       158 
     | 
    
         
            -
                      attributes_filter.all?  
     | 
| 
      
 158 
     | 
    
         
            +
                      attributes_filter.all? do |attribute_name_or_path, value|
         
     | 
| 
      
 159 
     | 
    
         
            +
                        type = nil
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                        if attribute_name_or_path.is_a?(::Array)
         
     | 
| 
      
 162 
     | 
    
         
            +
                          values = DataPath.values_at(attribute_name_or_path, attributes)
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                          if values.include?(value)
         
     | 
| 
      
 165 
     | 
    
         
            +
                            true
         
     | 
| 
      
 166 
     | 
    
         
            +
                          else
         
     | 
| 
      
 167 
     | 
    
         
            +
                            type ||= entity_class.model_type.type_at_path(attribute_name_or_path)
         
     | 
| 
      
 168 
     | 
    
         
            +
                            if type.extends?(:detached_entity)
         
     | 
| 
      
 169 
     | 
    
         
            +
                              values.any? do |v|
         
     | 
| 
      
 170 
     | 
    
         
            +
                                value.primary_key == v
         
     | 
| 
      
 171 
     | 
    
         
            +
                              end
         
     | 
| 
      
 172 
     | 
    
         
            +
                            end
         
     | 
| 
      
 173 
     | 
    
         
            +
                          end
         
     | 
| 
      
 174 
     | 
    
         
            +
                        elsif attributes[attribute_name_or_path] == value
         
     | 
| 
      
 175 
     | 
    
         
            +
                          true
         
     | 
| 
      
 176 
     | 
    
         
            +
                        else
         
     | 
| 
      
 177 
     | 
    
         
            +
                          type ||= entity_class.model_type.type_at_path(attribute_name_or_path)
         
     | 
| 
      
 178 
     | 
    
         
            +
                          if type.extends?(:detached_entity)
         
     | 
| 
      
 179 
     | 
    
         
            +
                            value.primary_key == attributes[attribute_name_or_path]
         
     | 
| 
      
 180 
     | 
    
         
            +
                          end
         
     | 
| 
      
 181 
     | 
    
         
            +
                        end
         
     | 
| 
      
 182 
     | 
    
         
            +
                      end
         
     | 
| 
       159 
183 
     | 
    
         
             
                    end
         
     | 
| 
       160 
184 
     | 
    
         | 
| 
       161 
185 
     | 
    
         
             
                    def insert(_attributes)
         
     | 
| 
         @@ -225,8 +225,8 @@ module Foobara 
     | 
|
| 
       225 
225 
     | 
    
         
             
                      find_by(attribute_name => value)
         
     | 
| 
       226 
226 
     | 
    
         
             
                    end
         
     | 
| 
       227 
227 
     | 
    
         | 
| 
       228 
     | 
    
         
            -
                    def find_all_by_attribute( 
     | 
| 
       229 
     | 
    
         
            -
                      find_many_by( 
     | 
| 
      
 228 
     | 
    
         
            +
                    def find_all_by_attribute(attribute_name_or_path, value)
         
     | 
| 
      
 229 
     | 
    
         
            +
                      find_many_by(attribute_name_or_path => value)
         
     | 
| 
       230 
230 
     | 
    
         
             
                    end
         
     | 
| 
       231 
231 
     | 
    
         | 
| 
       232 
232 
     | 
    
         
             
                    def find_by_attribute_containing(attribute_name, value)
         
     | 
| 
         @@ -283,13 +283,38 @@ module Foobara 
     | 
|
| 
       283 
283 
     | 
    
         | 
| 
       284 
284 
     | 
    
         
             
                    def find_many_by(attributes_filter)
         
     | 
| 
       285 
285 
     | 
    
         
             
                      find_by_type = entity_class.domain.foobara_type_from_declaration(entity_class.attributes_for_find_by)
         
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
                      path_filters = {}
         
     | 
| 
      
 288 
     | 
    
         
            +
                      regular_filters = {}
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
                      attributes_filter.each_pair do |attribute_name_or_path, value|
         
     | 
| 
      
 291 
     | 
    
         
            +
                        case attribute_name_or_path
         
     | 
| 
      
 292 
     | 
    
         
            +
                        when ::Symbol, ::String
         
     | 
| 
      
 293 
     | 
    
         
            +
                          regular_filters[attribute_name_or_path] = value
         
     | 
| 
      
 294 
     | 
    
         
            +
                        when ::Array, Value::DataPath
         
     | 
| 
      
 295 
     | 
    
         
            +
                          path_filters[attribute_name_or_path] = value
         
     | 
| 
      
 296 
     | 
    
         
            +
                        else
         
     | 
| 
      
 297 
     | 
    
         
            +
                          # :nocov:
         
     | 
| 
      
 298 
     | 
    
         
            +
                          raise "Unexpected filter type: #{attribute_name_or_path.class}"
         
     | 
| 
      
 299 
     | 
    
         
            +
                          # :nocov:
         
     | 
| 
      
 300 
     | 
    
         
            +
                        end
         
     | 
| 
      
 301 
     | 
    
         
            +
                      end
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                      regular_filters = find_by_type.process_value!(regular_filters)
         
     | 
| 
      
 304 
     | 
    
         
            +
             
     | 
| 
      
 305 
     | 
    
         
            +
                      path_filters.keys.each do |path|
         
     | 
| 
      
 306 
     | 
    
         
            +
                        type = entity_class.deep_associations[DataPath.for(path).to_s]
         
     | 
| 
      
 307 
     | 
    
         
            +
                        path_filters[path] = type.process_value!(path_filters[path])
         
     | 
| 
      
 308 
     | 
    
         
            +
                      end
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
                      attributes_filter = regular_filters.merge(path_filters)
         
     | 
| 
       287 
311 
     | 
    
         | 
| 
       288 
312 
     | 
    
         
             
                      yielded_ids = Set.new
         
     | 
| 
       289 
313 
     | 
    
         | 
| 
       290 
314 
     | 
    
         
             
                      Enumerator.new do |yielder|
         
     | 
| 
       291 
315 
     | 
    
         
             
                        tracked_records.each do |record|
         
     | 
| 
       292 
316 
     | 
    
         
             
                          next if hard_deleted?(record)
         
     | 
| 
      
 317 
     | 
    
         
            +
                          next unless record.loaded? || record.built? || record.created?
         
     | 
| 
       293 
318 
     | 
    
         | 
| 
       294 
319 
     | 
    
         
             
                          if entity_attributes_crud_driver_table.matches_attributes_filter?(record.attributes, attributes_filter)
         
     | 
| 
       295 
320 
     | 
    
         
             
                            yielded_ids << record.primary_key
         
     | 
| 
         @@ -8,9 +8,15 @@ module Foobara 
     | 
|
| 
       8 
8 
     | 
    
         
             
                      associations = Foobara::DetachedEntity.construct_deep_associations(from_type)
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
                      associations&.values&.reverse&.each do |entity_type|
         
     | 
| 
      
 11 
     | 
    
         
            +
                        next if entity_type.sensitive?
         
     | 
| 
      
 12 
     | 
    
         
            +
                        next unless entity_type.has_sensitive_types?
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       11 
14 
     | 
    
         
             
                        declaration = entity_type.declaration_data
         
     | 
| 
       12 
15 
     | 
    
         
             
                        sanitized_type_declaration = TypeDeclarations.remove_sensitive_types(declaration)
         
     | 
| 
       13 
16 
     | 
    
         | 
| 
      
 17 
     | 
    
         
            +
                        # We want to make sure that any types that change due to having sensitive types
         
     | 
| 
      
 18 
     | 
    
         
            +
                        # has a corresponding registered type in the command registry domain if needed
         
     | 
| 
      
 19 
     | 
    
         
            +
                        # TODO: this all feels so messy and brittle.
         
     | 
| 
       14 
20 
     | 
    
         
             
                        Domain.current.foobara_type_from_declaration(sanitized_type_declaration)
         
     | 
| 
       15 
21 
     | 
    
         
             
                      end
         
     | 
| 
       16 
22 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -2,6 +2,46 @@ require "foobara/lru_cache" 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Foobara
         
     | 
| 
       4 
4 
     | 
    
         
             
              module TypeDeclarations
         
     | 
| 
      
 5 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # TODO: relocate these to a different file
         
     | 
| 
      
 7 
     | 
    
         
            +
                  def args_to_type_declaration(*args, &block)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    if block
         
     | 
| 
      
 9 
     | 
    
         
            +
                      unless args.empty?
         
     | 
| 
      
 10 
     | 
    
         
            +
                        # :nocov:
         
     | 
| 
      
 11 
     | 
    
         
            +
                        raise ArgumentError, "Cannot provide both block and declaration"
         
     | 
| 
      
 12 
     | 
    
         
            +
                        # :nocov:
         
     | 
| 
      
 13 
     | 
    
         
            +
                      end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      block
         
     | 
| 
      
 16 
     | 
    
         
            +
                    else
         
     | 
| 
      
 17 
     | 
    
         
            +
                      case args.size
         
     | 
| 
      
 18 
     | 
    
         
            +
                      when 0
         
     | 
| 
      
 19 
     | 
    
         
            +
                        # :nocov:
         
     | 
| 
      
 20 
     | 
    
         
            +
                        raise ArgumentError, "expected 1 argument or a block but got 0 arguments and no block"
         
     | 
| 
      
 21 
     | 
    
         
            +
                        # :nocov:
         
     | 
| 
      
 22 
     | 
    
         
            +
                      when 1
         
     | 
| 
      
 23 
     | 
    
         
            +
                        args.first
         
     | 
| 
      
 24 
     | 
    
         
            +
                      else
         
     | 
| 
      
 25 
     | 
    
         
            +
                        type, *symbolic_processors, processor_data = args
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                        if !symbolic_processors.empty?
         
     | 
| 
      
 28 
     | 
    
         
            +
                          symbolic_processors = symbolic_processors.to_h { |symbol| [symbol, true] }
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                          if processor_data.is_a?(::Hash) && !processor_data.empty?
         
     | 
| 
      
 31 
     | 
    
         
            +
                            processor_data.merge(symbolic_processors)
         
     | 
| 
      
 32 
     | 
    
         
            +
                          else
         
     | 
| 
      
 33 
     | 
    
         
            +
                            symbolic_processors
         
     | 
| 
      
 34 
     | 
    
         
            +
                          end
         
     | 
| 
      
 35 
     | 
    
         
            +
                        elsif processor_data.is_a?(::Hash)
         
     | 
| 
      
 36 
     | 
    
         
            +
                          processor_data
         
     | 
| 
      
 37 
     | 
    
         
            +
                        else
         
     | 
| 
      
 38 
     | 
    
         
            +
                          { processor_data.to_sym => true }
         
     | 
| 
      
 39 
     | 
    
         
            +
                        end.merge(type:)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
       5 
45 
     | 
    
         
             
                class TypeBuilder
         
     | 
| 
       6 
46 
     | 
    
         
             
                  class NoTypeDeclarationHandlerFoundError < StandardError; end
         
     | 
| 
       7 
47 
     | 
    
         | 
| 
         @@ -70,27 +110,8 @@ module Foobara 
     | 
|
| 
       70 
110 
     | 
    
         
             
                    end
         
     | 
| 
       71 
111 
     | 
    
         
             
                  end
         
     | 
| 
       72 
112 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                  def type_for_declaration_without_cache(*type_declaration_bits, & 
     | 
| 
       74 
     | 
    
         
            -
                    type_declaration =  
     | 
| 
       75 
     | 
    
         
            -
                                         unless type_declaration_bits.empty?
         
     | 
| 
       76 
     | 
    
         
            -
                                           # :nocov:
         
     | 
| 
       77 
     | 
    
         
            -
                                           raise ArgumentError, "Cannot provide both block and declaration"
         
     | 
| 
       78 
     | 
    
         
            -
                                           # :nocov:
         
     | 
| 
       79 
     | 
    
         
            -
                                         end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
                                         block
         
     | 
| 
       82 
     | 
    
         
            -
                                       else
         
     | 
| 
       83 
     | 
    
         
            -
                                         case type_declaration_bits.size
         
     | 
| 
       84 
     | 
    
         
            -
                                         when 0
         
     | 
| 
       85 
     | 
    
         
            -
                                           # :nocov:
         
     | 
| 
       86 
     | 
    
         
            -
                                           raise ArgumentError, "expected 1 argument or a block but got 0 arguments and no block"
         
     | 
| 
       87 
     | 
    
         
            -
                                           # :nocov:
         
     | 
| 
       88 
     | 
    
         
            -
                                         when 1
         
     | 
| 
       89 
     | 
    
         
            -
                                           type_declaration_bits.first
         
     | 
| 
       90 
     | 
    
         
            -
                                         else
         
     | 
| 
       91 
     | 
    
         
            -
                                           type_declaration_bits_to_type_declaration(type_declaration_bits)
         
     | 
| 
       92 
     | 
    
         
            -
                                         end
         
     | 
| 
       93 
     | 
    
         
            -
                                       end
         
     | 
| 
      
 113 
     | 
    
         
            +
                  def type_for_declaration_without_cache(*type_declaration_bits, &)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    type_declaration = TypeDeclarations.args_to_type_declaration(*type_declaration_bits, &)
         
     | 
| 
       94 
115 
     | 
    
         | 
| 
       95 
116 
     | 
    
         
             
                    handler = type_declaration_handler_for(type_declaration)
         
     | 
| 
       96 
117 
     | 
    
         
             
                    handler.process_value!(type_declaration)
         
     | 
| 
         @@ -107,24 +128,6 @@ module Foobara 
     | 
|
| 
       107 
128 
     | 
    
         
             
                  def lru_cache
         
     | 
| 
       108 
129 
     | 
    
         
             
                    @lru_cache ||= Foobara::LruCache.new(100)
         
     | 
| 
       109 
130 
     | 
    
         
             
                  end
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                  def type_declaration_bits_to_type_declaration(type_declaration_bits)
         
     | 
| 
       112 
     | 
    
         
            -
                    type, *symbolic_processors, processor_data = type_declaration_bits
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                    if !symbolic_processors.empty?
         
     | 
| 
       115 
     | 
    
         
            -
                      symbolic_processors = symbolic_processors.to_h { |symbol| [symbol, true] }
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                      if processor_data.is_a?(::Hash) && !processor_data.empty?
         
     | 
| 
       118 
     | 
    
         
            -
                        processor_data.merge(symbolic_processors)
         
     | 
| 
       119 
     | 
    
         
            -
                      else
         
     | 
| 
       120 
     | 
    
         
            -
                        symbolic_processors
         
     | 
| 
       121 
     | 
    
         
            -
                      end
         
     | 
| 
       122 
     | 
    
         
            -
                    elsif processor_data.is_a?(::Hash)
         
     | 
| 
       123 
     | 
    
         
            -
                      processor_data
         
     | 
| 
       124 
     | 
    
         
            -
                    else
         
     | 
| 
       125 
     | 
    
         
            -
                      { processor_data.to_sym => true }
         
     | 
| 
       126 
     | 
    
         
            -
                    end.merge(type:)
         
     | 
| 
       127 
     | 
    
         
            -
                  end
         
     | 
| 
       128 
131 
     | 
    
         
             
                end
         
     | 
| 
       129 
132 
     | 
    
         
             
              end
         
     | 
| 
       130 
133 
     | 
    
         
             
            end
         
     | 
| 
         @@ -4,7 +4,7 @@ module Foobara 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module TypeDeclarations
         
     | 
| 
       5 
5 
     | 
    
         
             
                class TypeDeclarationHandler < Value::Processor::Pipeline
         
     | 
| 
       6 
6 
     | 
    
         
             
                  class << self
         
     | 
| 
       7 
     | 
    
         
            -
                    def foobara_manifest 
     | 
| 
      
 7 
     | 
    
         
            +
                    def foobara_manifest
         
     | 
| 
       8 
8 
     | 
    
         
             
                      # :nocov:
         
     | 
| 
       9 
9 
     | 
    
         
             
                      super.merge(processor_type: :type_declaration_handler)
         
     | 
| 
       10 
10 
     | 
    
         
             
                      # :nocov:
         
     | 
| 
         @@ -2,7 +2,7 @@ module Foobara 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module TypeDeclarations
         
     | 
| 
       3 
3 
     | 
    
         
             
                class TypeDeclarationHandlerRegistry < Value::Processor::Selection
         
     | 
| 
       4 
4 
     | 
    
         
             
                  class << self
         
     | 
| 
       5 
     | 
    
         
            -
                    def foobara_manifest 
     | 
| 
      
 5 
     | 
    
         
            +
                    def foobara_manifest
         
     | 
| 
       6 
6 
     | 
    
         
             
                      # :nocov:
         
     | 
| 
       7 
7 
     | 
    
         
             
                      super.merge(processor_type: :type_declaration_handler_registry)
         
     | 
| 
       8 
8 
     | 
    
         
             
                      # :nocov:
         
     | 
| 
         @@ -68,22 +68,17 @@ module Foobara 
     | 
|
| 
       68 
68 
     | 
    
         
             
                    using_mode(Mode::STRICT_STRINGIFIED, &)
         
     | 
| 
       69 
69 
     | 
    
         
             
                  end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
                   
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                     
     | 
| 
       74 
     | 
    
         
            -
                      Thread.foobara_var_set(:foobara_type_declarations_mode, new_mode)
         
     | 
| 
       75 
     | 
    
         
            -
                      yield
         
     | 
| 
       76 
     | 
    
         
            -
                    ensure
         
     | 
| 
       77 
     | 
    
         
            -
                      Thread.foobara_var_set(:foobara_type_declarations_mode, old_mode)
         
     | 
| 
       78 
     | 
    
         
            -
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  # TODO: use manifest context instead
         
     | 
| 
      
 72 
     | 
    
         
            +
                  def using_mode(new_mode, &)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    with_manifest_context(mode: new_mode, &)
         
     | 
| 
       79 
74 
     | 
    
         
             
                  end
         
     | 
| 
       80 
75 
     | 
    
         | 
| 
       81 
76 
     | 
    
         
             
                  def strict?
         
     | 
| 
       82 
     | 
    
         
            -
                     
     | 
| 
      
 77 
     | 
    
         
            +
                    foobara_manifest_context_mode == Mode::STRICT
         
     | 
| 
       83 
78 
     | 
    
         
             
                  end
         
     | 
| 
       84 
79 
     | 
    
         | 
| 
       85 
80 
     | 
    
         
             
                  def strict_stringified?
         
     | 
| 
       86 
     | 
    
         
            -
                     
     | 
| 
      
 81 
     | 
    
         
            +
                    foobara_manifest_context_mode == Mode::STRICT_STRINGIFIED
         
     | 
| 
       87 
82 
     | 
    
         
             
                  end
         
     | 
| 
       88 
83 
     | 
    
         | 
| 
       89 
84 
     | 
    
         
             
                  # TODO: we should desugarize these but can't because of a bug where desugarizing entities results in creating the
         
     | 
| 
         @@ -94,6 +89,40 @@ module Foobara 
     | 
|
| 
       94 
89 
     | 
    
         | 
| 
       95 
90 
     | 
    
         
             
                    declaration1 == declaration2
         
     | 
| 
       96 
91 
     | 
    
         
             
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  def foobara_manifest_context
         
     | 
| 
      
 94 
     | 
    
         
            +
                    Thread.foobara_var_get("foobara_manifest_context")
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  allowed_context_keys = %i[detached to_include mode remove_sensitive]
         
     | 
| 
      
 98 
     | 
    
         
            +
                  booleans = %i[detached remove_sensitive]
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  booleans.each do |context_item|
         
     | 
| 
      
 101 
     | 
    
         
            +
                    define_method "foobara_manifest_context_#{context_item}?" do
         
     | 
| 
      
 102 
     | 
    
         
            +
                      !!foobara_manifest_context&.[](context_item)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
                  end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                  (allowed_context_keys - booleans).each do |context_item|
         
     | 
| 
      
 107 
     | 
    
         
            +
                    define_method "foobara_manifest_context_#{context_item}" do
         
     | 
| 
      
 108 
     | 
    
         
            +
                      foobara_manifest_context&.[](context_item)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  def manifest_context_set?(context_item)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    foobara_manifest_context&.key?(context_item)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  def with_manifest_context(context)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    old_context = foobara_manifest_context
         
     | 
| 
      
 118 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 119 
     | 
    
         
            +
                      new_context = (old_context || {}).merge(context)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      Thread.foobara_var_set("foobara_manifest_context", new_context)
         
     | 
| 
      
 121 
     | 
    
         
            +
                      yield
         
     | 
| 
      
 122 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 123 
     | 
    
         
            +
                      Thread.foobara_var_set("foobara_manifest_context", old_context)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    end
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
       97 
126 
     | 
    
         
             
                end
         
     | 
| 
       98 
127 
     | 
    
         
             
              end
         
     | 
| 
       99 
128 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,13 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Foobara
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Error
         
     | 
| 
       3 
3 
     | 
    
         
             
                class << self
         
     | 
| 
       4 
     | 
    
         
            -
                  def types_depended_on(*args 
     | 
| 
      
 4 
     | 
    
         
            +
                  def types_depended_on(*args)
         
     | 
| 
       5 
5 
     | 
    
         
             
                    if args.size == 1
         
     | 
| 
       6 
     | 
    
         
            -
                      context_type.types_depended_on(args.first 
     | 
| 
      
 6 
     | 
    
         
            +
                      context_type.types_depended_on(args.first)
         
     | 
| 
       7 
7 
     | 
    
         
             
                    elsif args.empty?
         
     | 
| 
       8 
8 
     | 
    
         
             
                      begin
         
     | 
| 
       9 
9 
     | 
    
         
             
                        if context_type
         
     | 
| 
       10 
     | 
    
         
            -
                          context_type.types_depended_on 
     | 
| 
      
 10 
     | 
    
         
            +
                          context_type.types_depended_on
         
     | 
| 
       11 
11 
     | 
    
         
             
                        else
         
     | 
| 
       12 
12 
     | 
    
         
             
                          raise Foobara::TypeDeclarations::ErrorExtension::NoContextTypeSetError
         
     | 
| 
       13 
13 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -6,7 +6,9 @@ module Foobara 
     | 
|
| 
       6 
6 
     | 
    
         
             
                      include Concern
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                      # as soon as we hit a registered type, don't go further down that path
         
     | 
| 
       9 
     | 
    
         
            -
                      def types_depended_on(result = nil 
     | 
| 
      
 9 
     | 
    
         
            +
                      def types_depended_on(result = nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                        remove_sensitive = TypeDeclarations.foobara_manifest_context_remove_sensitive?
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       10 
12 
     | 
    
         
             
                        start = result.nil?
         
     | 
| 
       11 
13 
     | 
    
         
             
                        result ||= Set.new
         
     | 
| 
       12 
14 
     | 
    
         
             
                        return if result.include?(self)
         
     | 
| 
         @@ -15,7 +17,7 @@ module Foobara 
     | 
|
| 
       15 
17 
     | 
    
         | 
| 
       16 
18 
     | 
    
         
             
                        return if !start && registered?
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                        to_process = types_to_add_to_manifest 
     | 
| 
      
 20 
     | 
    
         
            +
                        to_process = types_to_add_to_manifest
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
22 
     | 
    
         
             
                        if element_types
         
     | 
| 
       21 
23 
     | 
    
         
             
                          to_process += case element_types
         
     | 
| 
         @@ -48,7 +50,7 @@ module Foobara 
     | 
|
| 
       48 
50 
     | 
    
         
             
                        end
         
     | 
| 
       49 
51 
     | 
    
         | 
| 
       50 
52 
     | 
    
         
             
                        to_process.each do |type|
         
     | 
| 
       51 
     | 
    
         
            -
                          type.types_depended_on(result 
     | 
| 
      
 53 
     | 
    
         
            +
                          type.types_depended_on(result)
         
     | 
| 
       52 
54 
     | 
    
         
             
                        end
         
     | 
| 
       53 
55 
     | 
    
         | 
| 
       54 
56 
     | 
    
         
             
                        if start
         
     | 
| 
         @@ -58,7 +60,9 @@ module Foobara 
     | 
|
| 
       58 
60 
     | 
    
         
             
                        result
         
     | 
| 
       59 
61 
     | 
    
         
             
                      end
         
     | 
| 
       60 
62 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
                      def types_to_add_to_manifest 
     | 
| 
      
 63 
     | 
    
         
            +
                      def types_to_add_to_manifest
         
     | 
| 
      
 64 
     | 
    
         
            +
                        remove_sensitive = TypeDeclarations.foobara_manifest_context_remove_sensitive?
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
       62 
66 
     | 
    
         
             
                        types = [*base_type, *possible_errors.map(&:error_class)]
         
     | 
| 
       63 
67 
     | 
    
         | 
| 
       64 
68 
     | 
    
         
             
                        if element_type && (!remove_sensitive || !element_type.sensitive?)
         
     | 
| 
         @@ -86,6 +90,77 @@ module Foobara 
     | 
|
| 
       86 
90 
     | 
    
         
             
                        result.select(&:registered?)
         
     | 
| 
       87 
91 
     | 
    
         
             
                      end
         
     | 
| 
       88 
92 
     | 
    
         | 
| 
      
 93 
     | 
    
         
            +
                      def type_at_path(data_path)
         
     | 
| 
      
 94 
     | 
    
         
            +
                        path_parts = DataPath.for(data_path).path
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                        path_part, *path_parts = path_parts
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                        next_type = case path_part
         
     | 
| 
      
 99 
     | 
    
         
            +
                                    when :"#"
         
     | 
| 
      
 100 
     | 
    
         
            +
                                      unless element_type
         
     | 
| 
      
 101 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 102 
     | 
    
         
            +
                                        raise "Expected element_type to be set but is not"
         
     | 
| 
      
 103 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 104 
     | 
    
         
            +
                                      end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                                      element_type
         
     | 
| 
      
 107 
     | 
    
         
            +
                                    when Symbol
         
     | 
| 
      
 108 
     | 
    
         
            +
                                      case element_types
         
     | 
| 
      
 109 
     | 
    
         
            +
                                      when ::Hash
         
     | 
| 
      
 110 
     | 
    
         
            +
                                        unless element_types.key?(path_part)
         
     | 
| 
      
 111 
     | 
    
         
            +
                                          # :nocov:
         
     | 
| 
      
 112 
     | 
    
         
            +
                                          raise "Expected element type to have key #{path_part} but does not"
         
     | 
| 
      
 113 
     | 
    
         
            +
                                          # :nocov:
         
     | 
| 
      
 114 
     | 
    
         
            +
                                        end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                                        element_types[path_part]
         
     | 
| 
      
 117 
     | 
    
         
            +
                                      when Types::Type
         
     | 
| 
      
 118 
     | 
    
         
            +
                                        unless element_types.extends?(BuiltinTypes[:attributes])
         
     | 
| 
      
 119 
     | 
    
         
            +
                                          # :nocov:
         
     | 
| 
      
 120 
     | 
    
         
            +
                                          raise "Expected element type to be a Type but is not"
         
     | 
| 
      
 121 
     | 
    
         
            +
                                          # :nocov:
         
     | 
| 
      
 122 
     | 
    
         
            +
                                        end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                                        # TODO: We assume it's attributes here but maybe we should assert that
         
     | 
| 
      
 125 
     | 
    
         
            +
                                        element_types.element_types[path_part]
         
     | 
| 
      
 126 
     | 
    
         
            +
                                      when nil
         
     | 
| 
      
 127 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 128 
     | 
    
         
            +
                                        raise "Expected element_types to be set but is not"
         
     | 
| 
      
 129 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 130 
     | 
    
         
            +
                                      else
         
     | 
| 
      
 131 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 132 
     | 
    
         
            +
                                        raise "Unsure how to handle path part #{path_part}"
         
     | 
| 
      
 133 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 134 
     | 
    
         
            +
                                      end
         
     | 
| 
      
 135 
     | 
    
         
            +
                                    when Integer
         
     | 
| 
      
 136 
     | 
    
         
            +
                                      if extends?(BuiltinTypes[:tuple])
         
     | 
| 
      
 137 
     | 
    
         
            +
                                        element_types[path_part]
         
     | 
| 
      
 138 
     | 
    
         
            +
                                      elsif extends?(BuiltinTypes[:array])
         
     | 
| 
      
 139 
     | 
    
         
            +
                                        element_type
         
     | 
| 
      
 140 
     | 
    
         
            +
                                      else
         
     | 
| 
      
 141 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 142 
     | 
    
         
            +
                                        raise "Unsure how to handle path part #{path_part}"
         
     | 
| 
      
 143 
     | 
    
         
            +
                                        # :nocov:
         
     | 
| 
      
 144 
     | 
    
         
            +
                                      end
         
     | 
| 
      
 145 
     | 
    
         
            +
                                    else
         
     | 
| 
      
 146 
     | 
    
         
            +
                                      # :nocov:
         
     | 
| 
      
 147 
     | 
    
         
            +
                                      raise "Bad path part #{path_part}"
         
     | 
| 
      
 148 
     | 
    
         
            +
                                      # :nocov:
         
     | 
| 
      
 149 
     | 
    
         
            +
                                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                        unless next_type
         
     | 
| 
      
 152 
     | 
    
         
            +
                          # :nocov:
         
     | 
| 
      
 153 
     | 
    
         
            +
                          raise "Expected to find a type at #{path_part}"
         
     | 
| 
      
 154 
     | 
    
         
            +
                          # :nocov:
         
     | 
| 
      
 155 
     | 
    
         
            +
                        end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                        if path_parts.empty?
         
     | 
| 
      
 158 
     | 
    
         
            +
                          next_type
         
     | 
| 
      
 159 
     | 
    
         
            +
                        else
         
     | 
| 
      
 160 
     | 
    
         
            +
                          next_type.type_at_path(path_parts)
         
     | 
| 
      
 161 
     | 
    
         
            +
                        end
         
     | 
| 
      
 162 
     | 
    
         
            +
                      end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
       89 
164 
     | 
    
         
             
                      def inspect
         
     | 
| 
       90 
165 
     | 
    
         
             
                        # :nocov:
         
     | 
| 
       91 
166 
     | 
    
         
             
                        name = if scoped_path_set?
         
     |