Class: RuboCop::Cop::PackwerkLite::ConstantResolver::ConstantReference

Inherits:
T::Struct
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/rubocop/cop/packwerk_lite/constant_resolver.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.resolve(node, processed_source) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rubocop/cop/packwerk_lite/constant_resolver.rb', line 37

def self.resolve(node, processed_source)
  constant_name = node.const_name
  namespaces = constant_name.split('::')
  global_namespace = namespaces.first

  expected_containing_pack_last_name = global_namespace.underscore

  # We don't use Packs.find(...) here because we want to look for nested packs, and this pack could be a child pack in a nested pack too.
  # In the future, we might want `find` to be able to take a glob or a regex to look for packs with a specific name structure.
  expected_containing_pack = ParsePackwerk.all.find { |p| p.name.include?("/#{expected_containing_pack_last_name}") }
  return if expected_containing_pack.nil?

  if namespaces.count == 1
    found_files = expected_containing_pack.directory.glob("app/*/#{expected_containing_pack_last_name}.rb")
  else
    expected_location_in_pack = namespaces[1..].map(&:underscore).join('/')
    found_files = expected_containing_pack.directory.glob("app/*/#{expected_containing_pack_last_name}/#{expected_location_in_pack}.rb")
  end

  # Because of how Zietwerk works, we know two things:
  # 1) Since namespaces map one to one with files, Zeitwerk does not permit multiple files to define the same fully-qualified class/module.
  # (Note it does permit multiple files to open up portions of other namespaces)
  # 2) If a file *could* define a fully qualified constant, then it *must* define that constant!
  #
  # Therefore when we've found possible files, we can sanity check there is only one,
  # and then assume the found pack defines the constant!
  raise if found_files.count > 1

  expected_pack_contains_constant = found_files.any?

  return if !expected_pack_contains_constant

  found_file = found_files.first

  ConstantReference.new(
    constant_name: constant_name,
    global_namespace: global_namespace,
    source_package: expected_containing_pack,
    constant_definition_location: T.must(found_file),
    referencing_file: Pathname.new(processed_source.path).relative_path_from(Pathname.pwd)
  )
end

Instance Method Details

#public_api?Boolean

Returns:

  • (Boolean)


29
30
31
32
33
34
# File 'lib/rubocop/cop/packwerk_lite/constant_resolver.rb', line 29

def public_api?
  # PackwerkExtensions should have a method to take in a path and determine if the file is public.
  # For now we put it here and only support the public folder (and not specific private constants).
  # However if we declare that dependency we may want to extract this into `rubocop-packwerk_lite` or something liek that!
  constant_definition_location.to_s.include?('/public/')
end

#referencing_packageObject



24
25
26
# File 'lib/rubocop/cop/packwerk_lite/constant_resolver.rb', line 24

def referencing_package
  ParsePackwerk.package_from_path(referencing_file)
end