class RubyLsp::Document

def ==(other)

def ==(other)
  @source == other.source
end

def cache_fetch(request_name, &block)

def cache_fetch(request_name, &block)
  cached = @cache[request_name]
  return cached if cached
  result = block.call(self)
  @cache[request_name] = result
  result
end

def cache_get(request_name)

def cache_get(request_name)
  @cache[request_name]
end

def cache_set(request_name, value)

def cache_set(request_name, value)
  @cache[request_name] = value
end

def comments

def comments
  @parse_result.comments
end

def create_scanner

def create_scanner
  Scanner.new(@source, @encoding)
end

def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind::UTF8)

def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind::UTF8)
  @cache = T.let({}, T::Hash[String, T.untyped])
  @encoding = T.let(encoding, String)
  @source = T.let(source, String)
  @version = T.let(version, Integer)
  @uri = T.let(uri, URI::Generic)
  @needs_parsing = T.let(true, T::Boolean)
  @parse_result = T.let(parse, Prism::ParseResult)
end

def locate(node, char_position, node_types: [])

def locate(node, char_position, node_types: [])
  queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
  closest = node
  parent = T.let(nil, T.nilable(Prism::Node))
  nesting = T.let([], T::Array[T.any(Prism::ClassNode, Prism::ModuleNode)])
  until queue.empty?
    candidate = queue.shift
    # Skip nil child nodes
    next if candidate.nil?
    # Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
    # same order as the visiting mechanism, which means searching the child nodes before moving on to the next
    # sibling
    T.unsafe(queue).unshift(*candidate.child_nodes)
    # Skip if the current node doesn't cover the desired position
    loc = candidate.location
    next unless (loc.start_offset...loc.end_offset).cover?(char_position)
    # If the node's start character is already past the position, then we should've found the closest node
    # already
    break if char_position < loc.start_offset
    # If the candidate starts after the end of the previous nesting level, then we've exited that nesting level and
    # need to pop the stack
    previous_level = nesting.last
    nesting.pop if previous_level && loc.start_offset > previous_level.location.end_offset
    # Keep track of the nesting where we found the target. This is used to determine the fully qualified name of the
    # target when it is a constant
    if candidate.is_a?(Prism::ClassNode) || candidate.is_a?(Prism::ModuleNode)
      nesting << candidate
    end
    # If there are node types to filter by, and the current node is not one of those types, then skip it
    next if node_types.any? && node_types.none? { |type| candidate.class == type }
    # If the current node is narrower than or equal to the previous closest node, then it is more precise
    closest_loc = closest.location
    if loc.end_offset - loc.start_offset <= closest_loc.end_offset - closest_loc.start_offset
      parent = closest
      closest = candidate
    end
  end
  [closest, parent, nesting.map { |n| n.constant_path.location.slice }]
end

def locate_node(position, node_types: [])

def locate_node(position, node_types: [])
  locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
end

def parse; end

def parse; end

def push_edits(edits, version:)

def push_edits(edits, version:)
  edits.each do |edit|
    range = edit[:range]
    scanner = create_scanner
    start_position = scanner.find_char_position(range[:start])
    end_position = scanner.find_char_position(range[:end])
    @source[start_position...end_position] = edit[:text]
  end
  @version = version
  @needs_parsing = true
  @cache.clear
end

def sorbet_sigil_is_true_or_higher

def sorbet_sigil_is_true_or_higher
  parse_result.magic_comments.any? do |comment|
    comment.key == "typed" && ["true", "strict", "strong"].include?(comment.value)
  end
end

def syntax_error?

def syntax_error?
  @parse_result.failure?
end

def tree

def tree
  @parse_result.value
end

def typechecker_enabled?

def typechecker_enabled?
  DependencyDetector.instance.typechecker && sorbet_sigil_is_true_or_higher
end