class Dry::Schema::Info::SchemaCompiler

@api private

def assign_type(key, type, nullable)

Other tags:
    Api: - private
def assign_type(key, type, nullable)
  if keys[key][:type]
    keys[key][:member] = type
  else
    keys[key][:type] = type
    keys[key][:nullable] = nullable
  end
end

def call(ast)

Other tags:
    Api: - private
def call(ast)
  visit(ast)
end

def initialize

Other tags:
    Api: - private
def initialize
  @keys = EMPTY_HASH.dup
end

def to_h

Other tags:
    Api: - private
def to_h
  {keys: keys}
end

def visit(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit(node, opts = EMPTY_HASH)
  meth, rest = node
  public_send(:"visit_#{meth}", rest, opts)
end

def visit_and(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit_and(node, opts = EMPTY_HASH)
  left, right = node
  visit(left, opts)
  visit(right, opts)
end

def visit_each(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit_each(node, opts = EMPTY_HASH)
  visit(node, {**opts, member: true})
end

def visit_implication(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit_implication(node, opts = EMPTY_HASH)
  case node
  in [:not, [:predicate, [:nil?, _]]], el
    visit(el, {**opts, nullable: true})
  else
    node.each do |el|
      visit(el, {**opts, required: false})
    end
  end
end

def visit_key(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit_key(node, opts = EMPTY_HASH)
  name, rest = node
  visit(rest, {**opts, key: name, required: true})
end

def visit_predicate(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit_predicate(node, opts = EMPTY_HASH)
  name, rest = node
  key = opts[:key]
  if name.equal?(:key?)
    keys[rest[0][1]] = {
      required: opts.fetch(:required, true)
    }
  else
    type = PREDICATE_TO_TYPE[name]
    nullable = opts.fetch(:nullable, false)
    assign_type(key, type, nullable) if type
  end
end

def visit_set(node, opts = EMPTY_HASH)

Other tags:
    Api: - private
def visit_set(node, opts = EMPTY_HASH)
  target = (key = opts[:key]) ? self.class.new : self
  node.each { |child| target.visit(child, opts) }
  return unless key
  target_info = opts[:member] ? {member: target.to_h} : target.to_h
  type = opts[:member] ? "array" : "hash"
  keys.update(key => {**keys[key], type: type, **target_info})
end