packwerk 2.1.1 → 2.2.1

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.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +29 -20
  3. data/.github/workflows/cla.yml +22 -0
  4. data/.rubocop.yml +48 -19
  5. data/Gemfile +7 -2
  6. data/Gemfile.lock +204 -177
  7. data/README.md +7 -2
  8. data/RESOLVING_VIOLATIONS.md +81 -0
  9. data/Rakefile +1 -1
  10. data/USAGE.md +14 -5
  11. data/bin/m +1 -1
  12. data/bin/rake +1 -1
  13. data/bin/rubocop +1 -1
  14. data/bin/srb +1 -1
  15. data/bin/tapioca +1 -1
  16. data/gemfiles/Gemfile-rails-6-0 +1 -1
  17. data/gemfiles/Gemfile-rails-6-1 +22 -0
  18. data/lib/packwerk/application_load_paths.rb +12 -18
  19. data/lib/packwerk/application_validator.rb +7 -6
  20. data/lib/packwerk/association_inspector.rb +17 -15
  21. data/lib/packwerk/cache.rb +36 -29
  22. data/lib/packwerk/cli.rb +14 -8
  23. data/lib/packwerk/const_node_inspector.rb +8 -7
  24. data/lib/packwerk/constant_name_inspector.rb +2 -2
  25. data/lib/packwerk/deprecated_references.rb +34 -19
  26. data/lib/packwerk/file_processor.rb +25 -23
  27. data/lib/packwerk/files_for_processing.rb +33 -35
  28. data/lib/packwerk/formatters/offenses_formatter.rb +3 -3
  29. data/lib/packwerk/formatters/progress_formatter.rb +2 -2
  30. data/lib/packwerk/node.rb +1 -294
  31. data/lib/packwerk/node_helpers.rb +335 -0
  32. data/lib/packwerk/node_processor.rb +6 -5
  33. data/lib/packwerk/node_processor_factory.rb +3 -3
  34. data/lib/packwerk/node_visitor.rb +1 -1
  35. data/lib/packwerk/offense_collection.rb +6 -3
  36. data/lib/packwerk/offenses_formatter.rb +2 -2
  37. data/lib/packwerk/package.rb +3 -0
  38. data/lib/packwerk/package_set.rb +3 -1
  39. data/lib/packwerk/parse_run.rb +15 -13
  40. data/lib/packwerk/parsed_constant_definitions.rb +23 -20
  41. data/lib/packwerk/parsers/erb.rb +3 -3
  42. data/lib/packwerk/parsers/parser_interface.rb +2 -0
  43. data/lib/packwerk/reference_checking/checkers/checker.rb +16 -3
  44. data/lib/packwerk/reference_checking/checkers/dependency_checker.rb +16 -0
  45. data/lib/packwerk/reference_checking/checkers/privacy_checker.rb +18 -0
  46. data/lib/packwerk/reference_checking/reference_checker.rb +4 -4
  47. data/lib/packwerk/reference_extractor.rb +51 -54
  48. data/lib/packwerk/reference_offense.rb +3 -27
  49. data/lib/packwerk/run_context.rb +9 -7
  50. data/lib/packwerk/spring_command.rb +1 -1
  51. data/lib/packwerk/version.rb +1 -1
  52. data/lib/packwerk.rb +1 -0
  53. data/packwerk.gemspec +4 -11
  54. data/sorbet/rbi/gems/actioncable@7.0.3.1.rbi +2754 -0
  55. data/sorbet/rbi/gems/actionmailbox@7.0.3.1.rbi +1496 -0
  56. data/sorbet/rbi/gems/actionmailer@7.0.3.1.rbi +2362 -0
  57. data/sorbet/rbi/gems/actionpack@7.0.3.1.rbi +19397 -0
  58. data/sorbet/rbi/gems/actiontext@7.0.3.1.rbi +1569 -0
  59. data/sorbet/rbi/gems/actionview@7.0.3.1.rbi +14907 -0
  60. data/sorbet/rbi/gems/activejob@7.0.3.1.rbi +2553 -0
  61. data/sorbet/rbi/gems/activemodel@7.0.3.1.rbi +5999 -0
  62. data/sorbet/rbi/gems/activerecord@7.0.3.1.rbi +37832 -0
  63. data/sorbet/rbi/gems/activestorage@7.0.3.1.rbi +2321 -0
  64. data/sorbet/rbi/gems/activesupport@7.0.3.1.rbi +18818 -0
  65. data/sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi +11722 -0
  66. data/sorbet/rbi/gems/constant_resolver@0.2.0.rbi +90 -0
  67. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1079 -0
  68. data/sorbet/rbi/gems/digest@3.1.0.rbi +189 -0
  69. data/sorbet/rbi/gems/erubi@1.11.0.rbi +140 -0
  70. data/sorbet/rbi/gems/globalid@1.0.0.rbi +572 -0
  71. data/sorbet/rbi/gems/i18n@1.12.0.rbi +2296 -0
  72. data/sorbet/rbi/gems/json@2.6.2.rbi +1548 -0
  73. data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +8 -0
  74. data/sorbet/rbi/gems/loofah@2.18.0.rbi +877 -0
  75. data/sorbet/rbi/gems/m@1.6.0.rbi +257 -0
  76. data/sorbet/rbi/gems/marcel@1.0.2.rbi +220 -0
  77. data/sorbet/rbi/gems/mini_mime@1.1.2.rbi +170 -0
  78. data/sorbet/rbi/gems/mini_portile2@2.8.0.rbi +8 -0
  79. data/sorbet/rbi/gems/minitest-focus@1.3.1.rbi +104 -0
  80. data/sorbet/rbi/gems/minitest@5.16.2.rbi +2136 -0
  81. data/sorbet/rbi/gems/mocha@1.14.0.rbi +4177 -0
  82. data/sorbet/rbi/gems/net-imap@0.2.3.rbi +2147 -0
  83. data/sorbet/rbi/gems/net-pop@0.1.1.rbi +926 -0
  84. data/sorbet/rbi/gems/net-protocol@0.1.3.rbi +11 -0
  85. data/sorbet/rbi/gems/net-smtp@0.3.1.rbi +1108 -0
  86. data/sorbet/rbi/gems/netrc@0.11.0.rbi +153 -0
  87. data/sorbet/rbi/gems/nio4r@2.5.8.rbi +292 -0
  88. data/sorbet/rbi/gems/nokogiri@1.13.8.rbi +6478 -0
  89. data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
  90. data/sorbet/rbi/gems/parser@3.1.2.1.rbi +9029 -0
  91. data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +8 -0
  92. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  93. data/sorbet/rbi/gems/racc@1.6.0.rbi +152 -0
  94. data/sorbet/rbi/gems/rack-test@2.0.2.rbi +953 -0
  95. data/sorbet/rbi/gems/rack@2.2.4.rbi +5636 -0
  96. data/sorbet/rbi/gems/rails-html-sanitizer@1.4.3.rbi +688 -0
  97. data/sorbet/rbi/gems/rails@7.0.3.1.rbi +8 -0
  98. data/sorbet/rbi/gems/railties@7.0.3.1.rbi +3507 -0
  99. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +392 -0
  100. data/sorbet/rbi/gems/rake@13.0.6.rbi +2924 -0
  101. data/sorbet/rbi/gems/rbi@0.0.15.rbi +3007 -0
  102. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +3383 -0
  103. data/sorbet/rbi/gems/rexml@3.2.5.rbi +4714 -0
  104. data/sorbet/rbi/gems/rubocop-ast@1.21.0.rbi +6961 -0
  105. data/sorbet/rbi/gems/rubocop-performance@1.14.3.rbi +2986 -0
  106. data/sorbet/rbi/gems/{rubocop-shopify@2.0.1.rbi → rubocop-shopify@2.9.0.rbi} +4 -4
  107. data/sorbet/rbi/gems/rubocop-sorbet@0.6.11.rbi +992 -0
  108. data/sorbet/rbi/gems/rubocop@1.34.1.rbi +51820 -0
  109. data/sorbet/rbi/gems/ruby-lsp@0.2.1.rbi +11 -0
  110. data/sorbet/rbi/gems/smart_properties@1.17.0.rbi +474 -0
  111. data/sorbet/rbi/gems/spoom@1.1.11.rbi +2181 -0
  112. data/sorbet/rbi/gems/spring@4.0.0.rbi +411 -0
  113. data/sorbet/rbi/gems/strscan@3.0.4.rbi +8 -0
  114. data/sorbet/rbi/gems/syntax_tree@3.3.0.rbi +8 -0
  115. data/sorbet/rbi/gems/tapioca@0.9.2.rbi +3181 -0
  116. data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
  117. data/sorbet/rbi/gems/timeout@0.3.0.rbi +142 -0
  118. data/sorbet/rbi/gems/tzinfo@2.0.5.rbi +5896 -0
  119. data/sorbet/rbi/gems/unicode-display_width@2.2.0.rbi +48 -0
  120. data/sorbet/rbi/gems/unparser@0.6.5.rbi +4529 -0
  121. data/sorbet/rbi/gems/webrick@1.7.0.rbi +2582 -0
  122. data/sorbet/rbi/gems/websocket-driver@0.7.5.rbi +993 -0
  123. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +388 -0
  124. data/sorbet/rbi/gems/yard@0.9.28.rbi +18242 -0
  125. data/sorbet/rbi/gems/zeitwerk@2.6.0.rbi +867 -0
  126. data/sorbet/rbi/shims/psych.rbi +5 -0
  127. data/sorbet/tapioca/require.rb +2 -3
  128. metadata +88 -143
  129. data/.github/probots.yml +0 -2
  130. data/library.yml +0 -6
  131. data/service.yml +0 -1
  132. data/sorbet/rbi/gems/actioncable@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -860
  133. data/sorbet/rbi/gems/actionmailbox@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -568
  134. data/sorbet/rbi/gems/actionmailer@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -587
  135. data/sorbet/rbi/gems/actionpack@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -5314
  136. data/sorbet/rbi/gems/actiontext@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -699
  137. data/sorbet/rbi/gems/actionview@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -2515
  138. data/sorbet/rbi/gems/activejob@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -624
  139. data/sorbet/rbi/gems/activemodel@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -1248
  140. data/sorbet/rbi/gems/activerecord@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -8363
  141. data/sorbet/rbi/gems/activestorage@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -876
  142. data/sorbet/rbi/gems/activesupport@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -3987
  143. data/sorbet/rbi/gems/colorize@0.8.1.rbi +0 -40
  144. data/sorbet/rbi/gems/commander@4.5.2.rbi +0 -8
  145. data/sorbet/rbi/gems/concurrent-ruby@1.1.8.rbi +0 -1969
  146. data/sorbet/rbi/gems/constant_resolver@0.1.5.rbi +0 -26
  147. data/sorbet/rbi/gems/erubi@1.10.0.rbi +0 -41
  148. data/sorbet/rbi/gems/globalid@0.4.2.rbi +0 -178
  149. data/sorbet/rbi/gems/highline@2.0.3.rbi +0 -8
  150. data/sorbet/rbi/gems/i18n@1.8.10.rbi +0 -600
  151. data/sorbet/rbi/gems/loofah@2.9.0.rbi +0 -274
  152. data/sorbet/rbi/gems/m@1.5.1.rbi +0 -108
  153. data/sorbet/rbi/gems/marcel@1.0.0.rbi +0 -70
  154. data/sorbet/rbi/gems/mini_mime@1.0.3.rbi +0 -71
  155. data/sorbet/rbi/gems/minitest-focus@1.2.1.rbi +0 -8
  156. data/sorbet/rbi/gems/minitest@5.14.4.rbi +0 -544
  157. data/sorbet/rbi/gems/mocha@1.12.0.rbi +0 -953
  158. data/sorbet/rbi/gems/nio4r@2.5.7.rbi +0 -90
  159. data/sorbet/rbi/gems/nokogiri@1.11.2.rbi +0 -1647
  160. data/sorbet/rbi/gems/parallel@1.20.1.rbi +0 -117
  161. data/sorbet/rbi/gems/parlour@6.0.0.rbi +0 -1272
  162. data/sorbet/rbi/gems/parser@3.0.0.0.rbi +0 -1745
  163. data/sorbet/rbi/gems/pry@0.14.0.rbi +0 -8
  164. data/sorbet/rbi/gems/psych@3.3.2.rbi +0 -24
  165. data/sorbet/rbi/gems/racc@1.5.2.rbi +0 -57
  166. data/sorbet/rbi/gems/rack-test@1.1.0.rbi +0 -335
  167. data/sorbet/rbi/gems/rack@2.2.3.rbi +0 -1718
  168. data/sorbet/rbi/gems/rails-html-sanitizer@1.3.0.rbi +0 -213
  169. data/sorbet/rbi/gems/rails@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -8
  170. data/sorbet/rbi/gems/railties@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -880
  171. data/sorbet/rbi/gems/rainbow@3.0.0.rbi +0 -155
  172. data/sorbet/rbi/gems/rake@13.0.3.rbi +0 -837
  173. data/sorbet/rbi/gems/regexp_parser@2.1.1.rbi +0 -8
  174. data/sorbet/rbi/gems/rexml@3.2.4.rbi +0 -8
  175. data/sorbet/rbi/gems/rubocop-ast@1.4.1.rbi +0 -8
  176. data/sorbet/rbi/gems/rubocop-performance@1.10.2.rbi +0 -8
  177. data/sorbet/rbi/gems/rubocop-sorbet@0.6.1.rbi +0 -8
  178. data/sorbet/rbi/gems/rubocop@1.12.0.rbi +0 -8
  179. data/sorbet/rbi/gems/smart_properties@1.15.0.rbi +0 -168
  180. data/sorbet/rbi/gems/spoom@1.1.0.rbi +0 -1061
  181. data/sorbet/rbi/gems/spring@2.1.1.rbi +0 -160
  182. data/sorbet/rbi/gems/sprockets-rails@3.2.2.rbi +0 -451
  183. data/sorbet/rbi/gems/sprockets@4.0.2.rbi +0 -1133
  184. data/sorbet/rbi/gems/tapioca@0.4.19.rbi +0 -603
  185. data/sorbet/rbi/gems/thor@1.1.0.rbi +0 -893
  186. data/sorbet/rbi/gems/tzinfo@2.0.4.rbi +0 -566
  187. data/sorbet/rbi/gems/unicode-display_width@2.0.0.rbi +0 -8
  188. data/sorbet/rbi/gems/websocket-driver@0.7.3.rbi +0 -438
  189. data/sorbet/rbi/gems/zeitwerk@2.4.2.rbi +0 -177
@@ -5,6 +5,8 @@ module Packwerk
5
5
  class FilesForProcessing
6
6
  extend T::Sig
7
7
 
8
+ RelativeFileSet = T.type_alias { T::Set[String] }
9
+
8
10
  class << self
9
11
  extend T::Sig
10
12
 
@@ -13,7 +15,7 @@ module Packwerk
13
15
  relative_file_paths: T::Array[String],
14
16
  configuration: Configuration,
15
17
  ignore_nested_packages: T::Boolean
16
- ).returns(T::Array[String])
18
+ ).returns(RelativeFileSet)
17
19
  end
18
20
  def fetch(relative_file_paths:, configuration:, ignore_nested_packages: false)
19
21
  new(relative_file_paths, configuration, ignore_nested_packages).files
@@ -31,15 +33,15 @@ module Packwerk
31
33
  @relative_file_paths = relative_file_paths
32
34
  @configuration = configuration
33
35
  @ignore_nested_packages = ignore_nested_packages
34
- @custom_files = T.let(nil, T.nilable(T::Array[String]))
36
+ @custom_files = T.let(nil, T.nilable(RelativeFileSet))
35
37
  end
36
38
 
37
- sig { returns(T::Array[String]) }
39
+ sig { returns(RelativeFileSet) }
38
40
  def files
39
41
  include_files = if custom_files.empty?
40
42
  configured_included_files
41
43
  else
42
- custom_files
44
+ configured_included_files & custom_files
43
45
  end
44
46
 
45
47
  include_files - configured_excluded_files
@@ -47,59 +49,55 @@ module Packwerk
47
49
 
48
50
  private
49
51
 
50
- sig { returns(T::Array[String]) }
52
+ sig { returns(RelativeFileSet) }
51
53
  def custom_files
52
- @custom_files ||= @relative_file_paths.flat_map do |relative_file_path|
53
- absolute_file_path = File.expand_path(relative_file_path, @configuration.root_path)
54
- if File.file?(absolute_file_path)
55
- absolute_file_path
56
- else
57
- custom_included_files(absolute_file_path)
54
+ @custom_files ||= Set.new(
55
+ @relative_file_paths.map do |relative_file_path|
56
+ if File.file?(relative_file_path)
57
+ relative_file_path
58
+ else
59
+ custom_included_files(relative_file_path)
60
+ end
58
61
  end
59
- end
62
+ ).flatten
60
63
  end
61
64
 
62
- sig { params(absolute_file_path: String).returns(T::Array[String]) }
63
- def custom_included_files(absolute_file_path)
65
+ sig { params(relative_file_path: String).returns(RelativeFileSet) }
66
+ def custom_included_files(relative_file_path)
64
67
  # Note, assuming include globs are always relative paths
65
- absolute_includes = @configuration.include.map do |glob|
66
- File.expand_path(glob, @configuration.root_path)
67
- end
68
-
69
- absolute_files = Dir.glob([File.join(absolute_file_path, "**", "*")]).select do |absolute_path|
70
- absolute_includes.any? do |pattern|
71
- File.fnmatch?(pattern, absolute_path, File::FNM_EXTGLOB)
68
+ relative_includes = @configuration.include
69
+ relative_files = Dir.glob([File.join(relative_file_path, "**", "*")]).select do |relative_path|
70
+ relative_includes.any? do |pattern|
71
+ File.fnmatch?(pattern, relative_path, File::FNM_EXTGLOB)
72
72
  end
73
73
  end
74
74
 
75
75
  if @ignore_nested_packages
76
- nested_packages_absolute_file_paths = Dir.glob(File.join(absolute_file_path, "*", "**", "package.yml"))
77
- nested_packages_absolute_globs = nested_packages_absolute_file_paths.map do |npp|
76
+ nested_packages_relative_file_paths = Dir.glob(File.join(relative_file_path, "*", "**", "package.yml"))
77
+ nested_packages_relative_globs = nested_packages_relative_file_paths.map do |npp|
78
78
  npp.gsub("package.yml", "**/*")
79
79
  end
80
- nested_packages_absolute_globs.each do |absolute_glob|
81
- absolute_files -= Dir.glob(absolute_glob)
80
+ nested_packages_relative_globs.each do |relative_glob|
81
+ relative_files -= Dir.glob(relative_glob)
82
82
  end
83
83
  end
84
84
 
85
- absolute_files
85
+ Set.new(relative_files)
86
86
  end
87
87
 
88
- sig { returns(T::Array[String]) }
88
+ sig { returns(RelativeFileSet) }
89
89
  def configured_included_files
90
- absolute_files_for_globs(@configuration.include)
90
+ relative_files_for_globs(@configuration.include)
91
91
  end
92
92
 
93
- sig { returns(T::Array[String]) }
93
+ sig { returns(RelativeFileSet) }
94
94
  def configured_excluded_files
95
- absolute_files_for_globs(@configuration.exclude)
95
+ relative_files_for_globs(@configuration.exclude)
96
96
  end
97
97
 
98
- sig { params(relative_globs: T::Array[String]).returns(T::Array[String]) }
99
- def absolute_files_for_globs(relative_globs)
100
- relative_globs
101
- .flat_map { |glob| Dir[File.expand_path(glob, @configuration.root_path)] }
102
- .uniq
98
+ sig { params(relative_globs: T::Array[String]).returns(RelativeFileSet) }
99
+ def relative_files_for_globs(relative_globs)
100
+ Set.new(relative_globs.flat_map { |glob| Dir[glob] })
103
101
  end
104
102
  end
105
103
  end
@@ -23,9 +23,9 @@ module Packwerk
23
23
  EOS
24
24
  end
25
25
 
26
- sig { override.params(offense_collection: Packwerk::OffenseCollection).returns(String) }
27
- def show_stale_violations(offense_collection)
28
- if offense_collection.stale_violations?
26
+ sig { override.params(offense_collection: Packwerk::OffenseCollection, fileset: T::Set[String]).returns(String) }
27
+ def show_stale_violations(offense_collection, fileset)
28
+ if offense_collection.stale_violations?(fileset)
29
29
  "There were stale violations found, please run `packwerk update-deprecations`"
30
30
  else
31
31
  "No stale violations detected"
@@ -20,10 +20,10 @@ module Packwerk
20
20
  @out.puts("📦 Packwerk is inspecting #{files_size} #{files_string}")
21
21
  end
22
22
 
23
- def started_validation
23
+ def started_validation(&block)
24
24
  @out.puts("📦 Packwerk is running validation...")
25
25
 
26
- execution_time = Benchmark.realtime { yield }
26
+ execution_time = Benchmark.realtime(&block)
27
27
  finished(execution_time)
28
28
 
29
29
  @out.puts("✅ Packages are valid. Use `packwerk check` to run static checks.")
data/lib/packwerk/node.rb CHANGED
@@ -1,301 +1,8 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require "parser"
5
- require "parser/ast/node"
6
-
7
4
  module Packwerk
8
- # Convenience methods for working with Parser::AST::Node nodes.
9
- module Node
10
- class TypeError < ArgumentError; end
5
+ class Node
11
6
  Location = Struct.new(:line, :column)
12
-
13
- class << self
14
- extend T::Sig
15
-
16
- def class_or_module_name(class_or_module_node)
17
- case type_of(class_or_module_node)
18
- when CLASS, MODULE
19
- # (class (const nil :Foo) (const nil :Bar) (nil))
20
- # "class Foo < Bar; end"
21
- # (module (const nil :Foo) (nil))
22
- # "module Foo; end"
23
- identifier = class_or_module_node.children[0]
24
- constant_name(identifier)
25
- else
26
- raise TypeError
27
- end
28
- end
29
-
30
- def constant_name(constant_node)
31
- case type_of(constant_node)
32
- when CONSTANT_ROOT_NAMESPACE
33
- ""
34
- when CONSTANT, CONSTANT_ASSIGNMENT, SELF
35
- # (const nil :Foo)
36
- # "Foo"
37
- # (const (cbase) :Foo)
38
- # "::Foo"
39
- # (const (lvar :a) :Foo)
40
- # "a::Foo"
41
- # (casgn nil :Foo (int 1))
42
- # "Foo = 1"
43
- # (casgn (cbase) :Foo (int 1))
44
- # "::Foo = 1"
45
- # (casgn (lvar :a) :Foo (int 1))
46
- # "a::Foo = 1"
47
- # (casgn (self) :Foo (int 1))
48
- # "self::Foo = 1"
49
- namespace, name = constant_node.children
50
- if namespace
51
- [constant_name(namespace), name].join("::")
52
- else
53
- name.to_s
54
- end
55
- else
56
- raise TypeError
57
- end
58
- end
59
-
60
- def each_child(node)
61
- if block_given?
62
- node.children.each do |child|
63
- yield child if child.is_a?(Parser::AST::Node)
64
- end
65
- else
66
- enum_for(:each_child, node)
67
- end
68
- end
69
-
70
- def enclosing_namespace_path(starting_node, ancestors:)
71
- ancestors.select { |n| [CLASS, MODULE].include?(type_of(n)) }
72
- .each_with_object([]) do |node, namespace|
73
- # when evaluating `class Child < Parent`, the const node for `Parent` is a child of the class
74
- # node, so it'll be an ancestor, but `Parent` is not evaluated in the namespace of `Child`, so
75
- # we need to skip it here
76
- next if type_of(node) == CLASS && parent_class(node) == starting_node
77
-
78
- namespace.prepend(class_or_module_name(node))
79
- end
80
- end
81
-
82
- def literal_value(string_or_symbol_node)
83
- case type_of(string_or_symbol_node)
84
- when STRING, SYMBOL
85
- # (str "foo")
86
- # "'foo'"
87
- # (sym :foo)
88
- # ":foo"
89
- string_or_symbol_node.children[0]
90
- else
91
- raise TypeError
92
- end
93
- end
94
-
95
- def location(node)
96
- location = node.location
97
- Location.new(location.line, location.column)
98
- end
99
-
100
- def constant?(node)
101
- type_of(node) == CONSTANT
102
- end
103
-
104
- def constant_assignment?(node)
105
- type_of(node) == CONSTANT_ASSIGNMENT
106
- end
107
-
108
- def class?(node)
109
- type_of(node) == CLASS
110
- end
111
-
112
- def method_call?(node)
113
- type_of(node) == METHOD_CALL
114
- end
115
-
116
- def hash?(node)
117
- type_of(node) == HASH
118
- end
119
-
120
- def string?(node)
121
- type_of(node) == STRING
122
- end
123
-
124
- def symbol?(node)
125
- type_of(node) == SYMBOL
126
- end
127
-
128
- def method_arguments(method_call_node)
129
- raise TypeError unless method_call?(method_call_node)
130
-
131
- # (send (lvar :foo) :bar (int 1))
132
- # "foo.bar(1)"
133
- method_call_node.children.slice(2..-1)
134
- end
135
-
136
- def method_name(method_call_node)
137
- raise TypeError unless method_call?(method_call_node)
138
-
139
- # (send (lvar :foo) :bar (int 1))
140
- # "foo.bar(1)"
141
- method_call_node.children[1]
142
- end
143
-
144
- def module_name_from_definition(node)
145
- case type_of(node)
146
- when CLASS, MODULE
147
- # "class My::Class; end"
148
- # "module My::Module; end"
149
- class_or_module_name(node)
150
- when CONSTANT_ASSIGNMENT
151
- # "My::Class = ..."
152
- # "My::Module = ..."
153
- rvalue = node.children.last
154
-
155
- case type_of(rvalue)
156
- when METHOD_CALL
157
- # "Class.new"
158
- # "Module.new"
159
- constant_name(node) if module_creation?(rvalue)
160
- when BLOCK
161
- # "Class.new do end"
162
- # "Module.new do end"
163
- constant_name(node) if module_creation?(method_call_node(rvalue))
164
- end
165
- end
166
- end
167
-
168
- def name_location(node)
169
- location = node.location
170
-
171
- if location.respond_to?(:name)
172
- name = location.name
173
- Location.new(name.line, name.column)
174
- end
175
- end
176
-
177
- def parent_class(class_node)
178
- raise TypeError unless type_of(class_node) == CLASS
179
-
180
- # (class (const nil :Foo) (const nil :Bar) (nil))
181
- # "class Foo < Bar; end"
182
- class_node.children[1]
183
- end
184
-
185
- sig { params(ancestors: T::Array[AST::Node]).returns(String) }
186
- def parent_module_name(ancestors:)
187
- definitions = ancestors
188
- .select { |n| [CLASS, MODULE, CONSTANT_ASSIGNMENT, BLOCK].include?(type_of(n)) }
189
-
190
- names = definitions.map do |definition|
191
- name_part_from_definition(definition)
192
- end.compact
193
-
194
- names.empty? ? "Object" : names.reverse.join("::")
195
- end
196
-
197
- def value_from_hash(hash_node, key)
198
- raise TypeError unless hash?(hash_node)
199
- pair = hash_pairs(hash_node).detect { |pair_node| literal_value(hash_pair_key(pair_node)) == key }
200
- hash_pair_value(pair) if pair
201
- end
202
-
203
- private
204
-
205
- BLOCK = :block
206
- CLASS = :class
207
- CONSTANT = :const
208
- CONSTANT_ASSIGNMENT = :casgn
209
- CONSTANT_ROOT_NAMESPACE = :cbase
210
- HASH = :hash
211
- HASH_PAIR = :pair
212
- METHOD_CALL = :send
213
- MODULE = :module
214
- SELF = :self
215
- STRING = :str
216
- SYMBOL = :sym
217
-
218
- private_constant(
219
- :BLOCK, :CLASS, :CONSTANT, :CONSTANT_ASSIGNMENT, :CONSTANT_ROOT_NAMESPACE, :HASH, :HASH_PAIR, :METHOD_CALL,
220
- :MODULE, :SELF, :STRING, :SYMBOL,
221
- )
222
-
223
- def type_of(node)
224
- node.type
225
- end
226
-
227
- def hash_pair_key(hash_pair_node)
228
- raise TypeError unless type_of(hash_pair_node) == HASH_PAIR
229
-
230
- # (pair (int 1) (int 2))
231
- # "1 => 2"
232
- # (pair (sym :answer) (int 42))
233
- # "answer: 42"
234
- hash_pair_node.children[0]
235
- end
236
-
237
- def hash_pair_value(hash_pair_node)
238
- raise TypeError unless type_of(hash_pair_node) == HASH_PAIR
239
-
240
- # (pair (int 1) (int 2))
241
- # "1 => 2"
242
- # (pair (sym :answer) (int 42))
243
- # "answer: 42"
244
- hash_pair_node.children[1]
245
- end
246
-
247
- def hash_pairs(hash_node)
248
- raise TypeError unless hash?(hash_node)
249
-
250
- # (hash (pair (int 1) (int 2)) (pair (int 3) (int 4)))
251
- # "{1 => 2, 3 => 4}"
252
- hash_node.children.select { |n| type_of(n) == HASH_PAIR }
253
- end
254
-
255
- def method_call_node(block_node)
256
- raise TypeError unless type_of(block_node) == BLOCK
257
-
258
- # (block (send (lvar :foo) :bar) (args) (int 42))
259
- # "foo.bar do 42 end"
260
- block_node.children[0]
261
- end
262
-
263
- def module_creation?(node)
264
- # "Class.new"
265
- # "Module.new"
266
- method_call?(node) &&
267
- receiver(node) &&
268
- constant?(receiver(node)) &&
269
- ["Class", "Module"].include?(constant_name(receiver(node))) &&
270
- method_name(node) == :new
271
- end
272
-
273
- def name_from_block_definition(node)
274
- if method_name(method_call_node(node)) == :class_eval
275
- receiver = receiver(node)
276
- constant_name(receiver) if receiver && constant?(receiver)
277
- end
278
- end
279
-
280
- def name_part_from_definition(node)
281
- case type_of(node)
282
- when CLASS, MODULE, CONSTANT_ASSIGNMENT
283
- module_name_from_definition(node)
284
- when BLOCK
285
- name_from_block_definition(node)
286
- end
287
- end
288
-
289
- def receiver(method_call_or_block_node)
290
- case type_of(method_call_or_block_node)
291
- when METHOD_CALL
292
- method_call_or_block_node.children[0]
293
- when BLOCK
294
- receiver(method_call_node(method_call_or_block_node))
295
- else
296
- raise TypeError
297
- end
298
- end
299
- end
300
7
  end
301
8
  end