packwerk 1.0.2 → 1.2.0

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 (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