packwerk 1.0.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +14 -5
  3. data/.ruby-version +1 -1
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +129 -111
  6. data/README.md +8 -1
  7. data/USAGE.md +39 -17
  8. data/dev.yml +1 -1
  9. data/exe/packwerk +1 -1
  10. data/gemfiles/Gemfile-rails-6-0 +22 -0
  11. data/lib/packwerk.rb +73 -34
  12. data/lib/packwerk/application_load_paths.rb +3 -2
  13. data/lib/packwerk/application_validator.rb +85 -69
  14. data/lib/packwerk/association_inspector.rb +23 -11
  15. data/lib/packwerk/checker.rb +4 -7
  16. data/lib/packwerk/cli.rb +36 -93
  17. data/lib/packwerk/configuration.rb +10 -2
  18. data/lib/packwerk/const_node_inspector.rb +13 -14
  19. data/lib/packwerk/constant_discovery.rb +2 -0
  20. data/lib/packwerk/constant_name_inspector.rb +0 -1
  21. data/lib/packwerk/dependency_checker.rb +12 -17
  22. data/lib/packwerk/deprecated_references.rb +25 -8
  23. data/lib/packwerk/file_processor.rb +0 -4
  24. data/lib/packwerk/formatters/offenses_formatter.rb +43 -0
  25. data/lib/packwerk/formatters/progress_formatter.rb +9 -4
  26. data/lib/packwerk/generators/configuration_file.rb +0 -1
  27. data/lib/packwerk/inflector.rb +0 -2
  28. data/lib/packwerk/node.rb +9 -2
  29. data/lib/packwerk/node_processor.rb +15 -32
  30. data/lib/packwerk/node_processor_factory.rb +0 -5
  31. data/lib/packwerk/node_visitor.rb +1 -4
  32. data/lib/packwerk/offense.rb +2 -8
  33. data/lib/packwerk/offense_collection.rb +84 -0
  34. data/lib/packwerk/offenses_formatter.rb +15 -0
  35. data/lib/packwerk/output_style.rb +20 -0
  36. data/lib/packwerk/output_styles/coloured.rb +29 -0
  37. data/lib/packwerk/output_styles/plain.rb +26 -0
  38. data/lib/packwerk/package.rb +8 -0
  39. data/lib/packwerk/package_set.rb +8 -5
  40. data/lib/packwerk/parse_run.rb +104 -0
  41. data/lib/packwerk/parsed_constant_definitions.rb +2 -4
  42. data/lib/packwerk/parsers.rb +0 -2
  43. data/lib/packwerk/parsers/erb.rb +4 -2
  44. data/lib/packwerk/parsers/factory.rb +10 -3
  45. data/lib/packwerk/privacy_checker.rb +22 -17
  46. data/lib/packwerk/reference_extractor.rb +0 -8
  47. data/lib/packwerk/reference_offense.rb +49 -0
  48. data/lib/packwerk/result.rb +9 -0
  49. data/lib/packwerk/run_context.rb +4 -20
  50. data/lib/packwerk/sanity_checker.rb +1 -3
  51. data/lib/packwerk/spring_command.rb +1 -1
  52. data/lib/packwerk/version.rb +1 -1
  53. data/lib/packwerk/violation_type.rb +0 -2
  54. data/library.yml +1 -1
  55. data/packwerk.gemspec +1 -0
  56. data/service.yml +1 -4
  57. data/shipit.rubygems.yml +5 -1
  58. data/sorbet/rbi/gems/{actioncable@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actioncable@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +56 -36
  59. data/sorbet/rbi/gems/{actionmailbox@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionmailbox@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +25 -28
  60. data/sorbet/rbi/gems/{actionmailer@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionmailer@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +43 -24
  61. data/sorbet/rbi/gems/{actionpack@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionpack@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +382 -284
  62. data/sorbet/rbi/gems/{actiontext@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actiontext@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +76 -40
  63. data/sorbet/rbi/gems/{actionview@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionview@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +206 -195
  64. data/sorbet/rbi/gems/{activejob@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activejob@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +64 -75
  65. data/sorbet/rbi/gems/{activemodel@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activemodel@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +103 -56
  66. data/sorbet/rbi/gems/{activerecord@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activerecord@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +1250 -898
  67. data/sorbet/rbi/gems/{activestorage@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activestorage@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +92 -120
  68. data/sorbet/rbi/gems/{activesupport@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activesupport@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +292 -193
  69. data/sorbet/rbi/gems/{ast@2.4.1.rbi → ast@2.4.2.rbi} +2 -1
  70. data/sorbet/rbi/gems/{better_html@1.0.15.rbi → better_html@1.0.16.rbi} +2 -2
  71. data/sorbet/rbi/gems/{concurrent-ruby@1.1.6.rbi → concurrent-ruby@1.1.8.rbi} +12 -9
  72. data/sorbet/rbi/gems/{erubi@1.9.0.rbi → erubi@1.10.0.rbi} +3 -1
  73. data/sorbet/rbi/gems/{i18n@1.8.2.rbi → i18n@1.8.10.rbi} +19 -52
  74. data/sorbet/rbi/gems/{loofah@2.5.0.rbi → loofah@2.9.0.rbi} +3 -1
  75. data/sorbet/rbi/gems/marcel@1.0.0.rbi +70 -0
  76. data/sorbet/rbi/gems/{mini_mime@1.0.2.rbi → mini_mime@1.0.3.rbi} +6 -6
  77. data/sorbet/rbi/gems/{mini_portile2@2.4.0.rbi → minitest-focus@1.2.1.rbi} +2 -2
  78. data/sorbet/rbi/gems/{minitest@5.14.0.rbi → minitest@5.14.4.rbi} +31 -29
  79. data/sorbet/rbi/gems/{mocha@1.11.2.rbi → mocha@1.12.0.rbi} +25 -36
  80. data/sorbet/rbi/gems/{nio4r@2.5.2.rbi → nio4r@2.5.7.rbi} +21 -20
  81. data/sorbet/rbi/gems/{nokogiri@1.10.9.rbi → nokogiri@1.11.2.rbi} +193 -154
  82. data/sorbet/rbi/gems/parallel@1.20.1.rbi +117 -0
  83. data/sorbet/rbi/gems/parlour@6.0.0.rbi +1272 -0
  84. data/sorbet/rbi/gems/{parser@2.7.1.4.rbi → parser@3.0.0.0.rbi} +287 -174
  85. data/sorbet/rbi/gems/{pry@0.13.1.rbi → pry@0.14.0.rbi} +1 -1
  86. data/sorbet/rbi/gems/racc@1.5.2.rbi +57 -0
  87. data/sorbet/rbi/gems/{rack@2.2.2.rbi → rack@2.2.3.rbi} +23 -35
  88. data/sorbet/rbi/gems/{rails@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → rails@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +1 -1
  89. data/sorbet/rbi/gems/{railties@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → railties@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +132 -121
  90. data/sorbet/rbi/gems/{rake@13.0.1.rbi → rake@13.0.3.rbi} +16 -20
  91. data/sorbet/rbi/gems/{parallel@1.19.1.rbi → regexp_parser@2.1.1.rbi} +2 -2
  92. data/sorbet/rbi/gems/rubocop-ast@1.4.1.rbi +8 -0
  93. data/sorbet/rbi/gems/{rubocop-performance@1.5.2.rbi → rubocop-performance@1.10.2.rbi} +1 -1
  94. data/sorbet/rbi/gems/{rubocop-shopify@1.0.2.rbi → rubocop-shopify@2.0.1.rbi} +1 -1
  95. data/sorbet/rbi/gems/{rubocop-sorbet@0.3.7.rbi → rubocop-sorbet@0.6.1.rbi} +1 -1
  96. data/sorbet/rbi/gems/{rubocop@0.82.0.rbi → rubocop@1.12.0.rbi} +1 -1
  97. data/sorbet/rbi/gems/{ruby-progressbar@1.10.1.rbi → ruby-progressbar@1.11.0.rbi} +1 -1
  98. data/sorbet/rbi/gems/spoom@1.1.0.rbi +1061 -0
  99. data/sorbet/rbi/gems/{spring@2.1.0.rbi → spring@2.1.1.rbi} +7 -7
  100. data/sorbet/rbi/gems/{sprockets-rails@3.2.1.rbi → sprockets-rails@3.2.2.rbi} +88 -68
  101. data/sorbet/rbi/gems/{sprockets@4.0.0.rbi → sprockets@4.0.2.rbi} +8 -7
  102. data/sorbet/rbi/gems/{tapioca@0.4.5.rbi → tapioca@0.4.19.rbi} +109 -24
  103. data/sorbet/rbi/gems/{thor@1.0.1.rbi → thor@1.1.0.rbi} +16 -15
  104. data/sorbet/rbi/gems/{tzinfo@2.0.2.rbi → tzinfo@2.0.4.rbi} +21 -2
  105. data/sorbet/rbi/gems/{unicode-display_width@1.7.0.rbi → unicode-display_width@2.0.0.rbi} +1 -1
  106. data/sorbet/rbi/gems/{websocket-driver@0.7.1.rbi → websocket-driver@0.7.3.rbi} +29 -29
  107. data/sorbet/rbi/gems/{websocket-extensions@0.1.4.rbi → websocket-extensions@0.1.5.rbi} +2 -2
  108. data/sorbet/rbi/gems/zeitwerk@2.4.2.rbi +177 -0
  109. data/sorbet/tapioca/require.rb +1 -0
  110. metadata +78 -57
  111. data/lib/packwerk/checking_deprecated_references.rb +0 -40
  112. data/lib/packwerk/output_styles.rb +0 -41
  113. data/lib/packwerk/reference_lister.rb +0 -23
  114. data/lib/packwerk/updating_deprecated_references.rb +0 -51
  115. data/sorbet/rbi/gems/jaro_winkler@1.5.4.rbi +0 -8
  116. data/sorbet/rbi/gems/marcel@0.3.3.rbi +0 -30
  117. data/sorbet/rbi/gems/mimemagic@0.3.5.rbi +0 -47
  118. data/sorbet/rbi/gems/parlour@4.0.1.rbi +0 -561
  119. data/sorbet/rbi/gems/spoom@1.0.4.rbi +0 -418
  120. data/sorbet/rbi/gems/zeitwerk@2.3.0.rbi +0 -8
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ module OutputStyles
6
+ class Plain
7
+ extend T::Sig
8
+ include OutputStyle
9
+
10
+ sig { override.returns(String) }
11
+ def reset
12
+ ""
13
+ end
14
+
15
+ sig { override.returns(String) }
16
+ def filename
17
+ ""
18
+ end
19
+
20
+ sig { override.returns(String) }
21
+ def error
22
+ ""
23
+ end
24
+ end
25
+ end
26
+ end
@@ -52,6 +52,14 @@ module Packwerk
52
52
  name <=> other.name
53
53
  end
54
54
 
55
+ def eql?(other)
56
+ self == other
57
+ end
58
+
59
+ def hash
60
+ name.hash
61
+ end
62
+
55
63
  def to_s
56
64
  name
57
65
  end
@@ -3,8 +3,6 @@
3
3
 
4
4
  require "pathname"
5
5
 
6
- require "packwerk/package"
7
-
8
6
  module Packwerk
9
7
  class PackageSet
10
8
  include Enumerable
@@ -28,8 +26,12 @@ module Packwerk
28
26
  def package_paths(root_path, package_pathspec)
29
27
  bundle_path_match = Bundler.bundle_path.join("**").to_s
30
28
 
31
- Dir.glob(File.join(root_path, package_pathspec, PACKAGE_CONFIG_FILENAME))
32
- .map { |path| Pathname.new(path) }
29
+ glob_patterns = Array(package_pathspec).map do |pathspec|
30
+ File.join(root_path, pathspec, PACKAGE_CONFIG_FILENAME)
31
+ end
32
+
33
+ Dir.glob(glob_patterns)
34
+ .map { |path| Pathname.new(path).cleanpath }
33
35
  .reject { |path| path.realpath.fnmatch(bundle_path_match) }
34
36
  end
35
37
 
@@ -56,7 +58,8 @@ module Packwerk
56
58
  end
57
59
 
58
60
  def package_from_path(file_path)
59
- @packages.values.find { |package| package.package_path?(file_path) }
61
+ path_string = file_path.to_s
62
+ @packages.values.find { |package| package.package_path?(path_string) }
60
63
  end
61
64
  end
62
65
  end
@@ -0,0 +1,104 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "benchmark"
5
+ require "parallel"
6
+
7
+ module Packwerk
8
+ class ParseRun
9
+ extend T::Sig
10
+
11
+ def initialize(
12
+ files:,
13
+ configuration:,
14
+ progress_formatter: Formatters::ProgressFormatter.new(StringIO.new),
15
+ offenses_formatter: Formatters::OffensesFormatter.new
16
+ )
17
+ @configuration = configuration
18
+ @progress_formatter = progress_formatter
19
+ @offenses_formatter = offenses_formatter
20
+ @files = files
21
+ end
22
+
23
+ def detect_stale_violations
24
+ offense_collection = find_offenses
25
+
26
+ result_status = !offense_collection.stale_violations?
27
+ message = if result_status
28
+ "No stale violations detected"
29
+ else
30
+ "There were stale violations found, please run `packwerk update-deprecations`"
31
+ end
32
+
33
+ Result.new(message: message, status: result_status)
34
+ end
35
+
36
+ def update_deprecations
37
+ offense_collection = find_offenses
38
+ offense_collection.dump_deprecated_references_files
39
+
40
+ message = <<~EOS
41
+ #{@offenses_formatter.show_offenses(offense_collection.errors)}
42
+ ✅ `deprecated_references.yml` has been updated.
43
+ EOS
44
+
45
+ Result.new(message: message, status: offense_collection.errors.empty?)
46
+ end
47
+
48
+ def check
49
+ offense_collection = find_offenses(show_errors: true)
50
+ message = @offenses_formatter.show_offenses(offense_collection.outstanding_offenses)
51
+ Result.new(message: message, status: offense_collection.outstanding_offenses.empty?)
52
+ end
53
+
54
+ private
55
+
56
+ def find_offenses(show_errors: false)
57
+ offense_collection = OffenseCollection.new(@configuration.root_path)
58
+ @progress_formatter.started(@files)
59
+
60
+ run_context = Packwerk::RunContext.from_configuration(@configuration)
61
+ all_offenses = T.let([], T.untyped)
62
+
63
+ process_file = -> (path) do
64
+ run_context.process_file(file: path).tap do |offenses|
65
+ failed = show_errors && offenses.any? { |offense| !offense_collection.listed?(offense) }
66
+ update_progress(failed: failed)
67
+ end
68
+ end
69
+
70
+ execution_time = Benchmark.realtime do
71
+ all_offenses = if @configuration.parallel?
72
+ Parallel.flat_map(@files, &process_file)
73
+ else
74
+ serial_find_offenses(&process_file)
75
+ end
76
+ end
77
+
78
+ @progress_formatter.finished(execution_time)
79
+
80
+ all_offenses.each { |offense| offense_collection.add_offense(offense) }
81
+ offense_collection
82
+ end
83
+
84
+ def serial_find_offenses
85
+ all_offenses = T.let([], T.untyped)
86
+ @files.each do |path|
87
+ offenses = yield path
88
+ all_offenses.concat(offenses)
89
+ end
90
+ all_offenses
91
+ rescue Interrupt
92
+ @progress_formatter.interrupted
93
+ all_offenses
94
+ end
95
+
96
+ def update_progress(failed: false)
97
+ if failed
98
+ @progress_formatter.mark_as_failed
99
+ else
100
+ @progress_formatter.mark_as_inspected
101
+ end
102
+ end
103
+ end
104
+ end
@@ -3,8 +3,6 @@
3
3
 
4
4
  require "ast/node"
5
5
 
6
- require "packwerk/node"
7
-
8
6
  module Packwerk
9
7
  class ParsedConstantDefinitions
10
8
  def initialize(root_node:)
@@ -28,8 +26,8 @@ module Packwerk
28
26
 
29
27
  fully_qualified_constant_name = "::#{constant_name}"
30
28
 
31
- possible_namespaces = namespace_path.reduce([""]) do |acc, current|
32
- acc << acc.last + "::" + current
29
+ possible_namespaces = namespace_path.each_with_object([""]) do |current, acc|
30
+ acc << "#{acc.last}::#{current}" if acc.last && current
33
31
  end
34
32
 
35
33
  possible_namespaces.map { |namespace| namespace + fully_qualified_constant_name }
@@ -1,8 +1,6 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require "packwerk/offense"
5
-
6
4
  module Packwerk
7
5
  module Parsers
8
6
  autoload :Erb, "packwerk/parsers/erb"
@@ -6,8 +6,6 @@ require "better_html"
6
6
  require "better_html/parser"
7
7
  require "parser/source/buffer"
8
8
 
9
- require "packwerk/parsers"
10
-
11
9
  module Packwerk
12
10
  module Parsers
13
11
  class Erb
@@ -19,6 +17,10 @@ module Packwerk
19
17
  def call(io:, file_path: "<unknown>")
20
18
  buffer = Parser::Source::Buffer.new(file_path)
21
19
  buffer.source = io.read
20
+ parse_buffer(buffer, file_path: file_path)
21
+ end
22
+
23
+ def parse_buffer(buffer, file_path:)
22
24
  parser = @parser_class.new(buffer, template_language: :html)
23
25
  to_ruby_ast(parser.ast, file_path)
24
26
  rescue EncodingError => e
@@ -3,8 +3,6 @@
3
3
 
4
4
  require "singleton"
5
5
 
6
- require "packwerk/parsers"
7
-
8
6
  module Packwerk
9
7
  module Parsers
10
8
  class Factory
@@ -26,9 +24,18 @@ module Packwerk
26
24
  when RUBY_REGEX
27
25
  @ruby_parser ||= Ruby.new
28
26
  when ERB_REGEX
29
- @erb_parser ||= Erb.new
27
+ @erb_parser ||= erb_parser_class.new
30
28
  end
31
29
  end
30
+
31
+ def erb_parser_class
32
+ @erb_parser_class ||= Erb
33
+ end
34
+
35
+ def erb_parser_class=(klass)
36
+ @erb_parser_class = klass
37
+ @erb_parser = nil
38
+ end
32
39
  end
33
40
  end
34
41
  end
@@ -1,46 +1,51 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "packwerk/violation_type"
5
- require "packwerk/checker"
6
-
7
4
  module Packwerk
8
5
  class PrivacyChecker
6
+ extend T::Sig
9
7
  include Checker
10
8
 
9
+ sig { override.returns(Packwerk::ViolationType) }
11
10
  def violation_type
12
11
  ViolationType::Privacy
13
12
  end
14
13
 
15
- def invalid_reference?(reference, reference_lister)
16
- return if reference.constant.public?
14
+ sig do
15
+ override
16
+ .params(reference: Packwerk::Reference)
17
+ .returns(T::Boolean)
18
+ end
19
+ def invalid_reference?(reference)
20
+ return false if reference.constant.public?
17
21
 
18
22
  privacy_option = reference.constant.package.enforce_privacy
19
- return if enforcement_disabled?(privacy_option)
23
+ return false if enforcement_disabled?(privacy_option)
20
24
 
21
- return unless privacy_option == true ||
25
+ return false unless privacy_option == true ||
22
26
  explicitly_private_constant?(reference.constant, explicitly_private_constants: privacy_option)
23
27
 
24
- return if reference_lister.listed?(reference, violation_type: violation_type)
25
-
26
28
  true
27
29
  end
28
30
 
29
- def message_for(reference)
30
- source_desc = reference.source_package ? "'#{reference.source_package}'" : "here"
31
- "Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
32
- "referenced from #{source_desc}.\n" \
33
- "Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?"
34
- end
35
-
36
31
  private
37
32
 
33
+ sig do
34
+ params(
35
+ constant: ConstantDiscovery::ConstantContext,
36
+ explicitly_private_constants: T::Array[String]
37
+ ).returns(T::Boolean)
38
+ end
38
39
  def explicitly_private_constant?(constant, explicitly_private_constants:)
39
40
  explicitly_private_constants.include?(constant.name) ||
40
41
  # nested constants
41
42
  explicitly_private_constants.any? { |epc| constant.name.start_with?(epc + "::") }
42
43
  end
43
44
 
45
+ sig do
46
+ params(privacy_option: T.nilable(T.any(T::Boolean, T::Array[String])))
47
+ .returns(T::Boolean)
48
+ end
44
49
  def enforcement_disabled?(privacy_option)
45
50
  [false, nil].include?(privacy_option)
46
51
  end
@@ -1,14 +1,6 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require "sorbet-runtime"
5
-
6
- require "packwerk/constant_discovery"
7
- require "packwerk/constant_name_inspector"
8
- require "packwerk/node"
9
- require "packwerk/parsed_constant_definitions"
10
- require "packwerk/reference"
11
-
12
4
  module Packwerk
13
5
  # extracts a possible constant reference from a given AST node
14
6
  class ReferenceExtractor
@@ -0,0 +1,49 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ class ReferenceOffense < Offense
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ attr_reader :reference, :violation_type
10
+
11
+ sig do
12
+ params(
13
+ reference: Packwerk::Reference,
14
+ violation_type: Packwerk::ViolationType,
15
+ location: T.nilable(Node::Location)
16
+ )
17
+ .void
18
+ end
19
+ def initialize(reference:, violation_type:, location: nil)
20
+ super(file: reference.relative_path, message: build_message(reference, violation_type), location: location)
21
+ @reference = reference
22
+ @violation_type = violation_type
23
+ end
24
+
25
+ private
26
+
27
+ def build_message(reference, violation_type)
28
+ violation_message = case violation_type
29
+ when ViolationType::Privacy
30
+ source_desc = reference.source_package ? "'#{reference.source_package}'" : "here"
31
+ "Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
32
+ "referenced from #{source_desc}.\n" \
33
+ "Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?"
34
+ when ViolationType::Dependency
35
+ "Dependency violation: #{reference.constant.name} belongs to '#{reference.constant.package}', but " \
36
+ "'#{reference.source_package}' does not specify a dependency on " \
37
+ "'#{reference.constant.package}'.\n" \
38
+ "Are we missing an abstraction?\n" \
39
+ "Is the code making the reference, and the referenced constant, in the right packages?\n"
40
+ end
41
+
42
+ <<~EOS
43
+ #{violation_message}
44
+ Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
45
+ To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
46
+ EOS
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ class Result < T::Struct
6
+ prop :message, String
7
+ prop :status, T::Boolean
8
+ end
9
+ end
@@ -3,17 +3,6 @@
3
3
 
4
4
  require "constant_resolver"
5
5
 
6
- require "packwerk/association_inspector"
7
- require "packwerk/constant_discovery"
8
- require "packwerk/const_node_inspector"
9
- require "packwerk/dependency_checker"
10
- require "packwerk/file_processor"
11
- require "packwerk/inflector"
12
- require "packwerk/package_set"
13
- require "packwerk/privacy_checker"
14
- require "packwerk/reference_extractor"
15
- require "packwerk/node_processor_factory"
16
-
17
6
  module Packwerk
18
7
  class RunContext
19
8
  extend T::Sig
@@ -25,7 +14,6 @@ module Packwerk
25
14
  :inflector,
26
15
  :custom_associations,
27
16
  :checker_classes,
28
- :reference_lister,
29
17
  )
30
18
 
31
19
  DEFAULT_CHECKERS = [
@@ -34,15 +22,14 @@ module Packwerk
34
22
  ]
35
23
 
36
24
  class << self
37
- def from_configuration(configuration, reference_lister:)
25
+ def from_configuration(configuration)
38
26
  inflector = ::Packwerk::Inflector.from_file(configuration.inflections_file)
39
27
  new(
40
28
  root_path: configuration.root_path,
41
29
  load_paths: configuration.load_paths,
42
30
  package_paths: configuration.package_paths,
43
31
  inflector: inflector,
44
- custom_associations: configuration.custom_associations,
45
- reference_lister: reference_lister,
32
+ custom_associations: configuration.custom_associations
46
33
  )
47
34
  end
48
35
  end
@@ -53,8 +40,7 @@ module Packwerk
53
40
  package_paths: nil,
54
41
  inflector: nil,
55
42
  custom_associations: [],
56
- checker_classes: DEFAULT_CHECKERS,
57
- reference_lister:
43
+ checker_classes: DEFAULT_CHECKERS
58
44
  )
59
45
  @root_path = root_path
60
46
  @load_paths = load_paths
@@ -62,7 +48,6 @@ module Packwerk
62
48
  @inflector = inflector
63
49
  @custom_associations = custom_associations
64
50
  @checker_classes = checker_classes
65
- @reference_lister = reference_lister
66
51
  end
67
52
 
68
53
  sig { params(file: String).returns(T::Array[T.nilable(::Packwerk::Offense)]) }
@@ -83,8 +68,7 @@ module Packwerk
83
68
  context_provider: context_provider,
84
69
  checkers: checkers,
85
70
  root_path: root_path,
86
- constant_name_inspectors: constant_name_inspectors,
87
- reference_lister: reference_lister
71
+ constant_name_inspectors: constant_name_inspectors
88
72
  )
89
73
  end
90
74