packwerk 2.2.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -5
  3. data/.ruby-version +1 -1
  4. data/Gemfile +0 -1
  5. data/Gemfile.lock +5 -95
  6. data/README.md +2 -7
  7. data/RESOLVING_VIOLATIONS.md +7 -7
  8. data/TROUBLESHOOT.md +1 -23
  9. data/USAGE.md +149 -59
  10. data/dev.yml +1 -1
  11. data/exe/packwerk +1 -0
  12. data/gemfiles/Gemfile-rails-6-1 +1 -1
  13. data/lib/packwerk/application_validator.rb +54 -285
  14. data/lib/packwerk/association_inspector.rb +2 -0
  15. data/lib/packwerk/cache.rb +6 -5
  16. data/lib/packwerk/checker.rb +54 -0
  17. data/lib/packwerk/cli/result.rb +11 -0
  18. data/lib/packwerk/cli.rb +56 -31
  19. data/lib/packwerk/configuration.rb +61 -40
  20. data/lib/packwerk/const_node_inspector.rb +2 -0
  21. data/lib/packwerk/constant_context.rb +8 -0
  22. data/lib/packwerk/constant_discovery.rb +5 -6
  23. data/lib/packwerk/constant_name_inspector.rb +2 -0
  24. data/lib/packwerk/disable_sorbet.rb +41 -0
  25. data/lib/packwerk/extension_loader.rb +24 -0
  26. data/lib/packwerk/file_processor.rb +3 -1
  27. data/lib/packwerk/files_for_processing.rb +25 -12
  28. data/lib/packwerk/formatters/default_offenses_formatter.rb +77 -0
  29. data/lib/packwerk/formatters/progress_formatter.rb +31 -12
  30. data/lib/packwerk/generators/configuration_file.rb +7 -2
  31. data/lib/packwerk/generators/root_package.rb +5 -1
  32. data/lib/packwerk/generators/templates/package.yml +0 -10
  33. data/lib/packwerk/graph.rb +10 -2
  34. data/lib/packwerk/node.rb +1 -1
  35. data/lib/packwerk/node_helpers.rb +14 -7
  36. data/lib/packwerk/node_processor.rb +2 -0
  37. data/lib/packwerk/node_processor_factory.rb +6 -4
  38. data/lib/packwerk/node_visitor.rb +10 -1
  39. data/lib/packwerk/offense_collection.rb +43 -23
  40. data/lib/packwerk/offenses_formatter.rb +59 -2
  41. data/lib/packwerk/package.rb +7 -35
  42. data/lib/packwerk/package_set.rb +1 -1
  43. data/lib/packwerk/{deprecated_references.rb → package_todo.rb} +29 -13
  44. data/lib/packwerk/parse_run.rb +29 -36
  45. data/lib/packwerk/parsed_constant_definitions.rb +28 -5
  46. data/lib/packwerk/parsers/erb.rb +23 -4
  47. data/lib/packwerk/parsers/factory.rb +11 -2
  48. data/lib/packwerk/parsers/parser_interface.rb +1 -1
  49. data/lib/packwerk/parsers/ruby.rb +13 -3
  50. data/lib/packwerk/parsers.rb +6 -2
  51. data/lib/packwerk/{application_load_paths.rb → rails_load_paths.rb} +6 -4
  52. data/lib/packwerk/reference.rb +7 -1
  53. data/lib/packwerk/reference_checking/checkers/dependency_checker.rb +29 -6
  54. data/lib/packwerk/reference_checking/reference_checker.rb +1 -1
  55. data/lib/packwerk/reference_extractor.rb +24 -12
  56. data/lib/packwerk/reference_offense.rb +2 -2
  57. data/lib/packwerk/run_context.rb +7 -10
  58. data/lib/packwerk/spring_command.rb +11 -2
  59. data/lib/packwerk/unresolved_reference.rb +9 -1
  60. data/lib/packwerk/validator/result.rb +18 -0
  61. data/lib/packwerk/validator.rb +90 -0
  62. data/lib/packwerk/validators/dependency_validator.rb +154 -0
  63. data/lib/packwerk/version.rb +1 -1
  64. data/lib/packwerk.rb +64 -26
  65. data/packwerk.gemspec +4 -2
  66. data/sorbet/rbi/gems/{zeitwerk@2.6.0.rbi → zeitwerk@2.6.4.rbi} +291 -228
  67. data/sorbet/rbi/shims/minitest/test.rb +8 -0
  68. data/sorbet/rbi/shims/packwerk/reference.rbi +33 -0
  69. data/sorbet/rbi/shims/packwerk/unresolved_reference.rbi +33 -0
  70. data/sorbet/rbi/shims/parser.rbi +13 -0
  71. metadata +35 -16
  72. data/lib/packwerk/formatters/offenses_formatter.rb +0 -52
  73. data/lib/packwerk/reference_checking/checkers/checker.rb +0 -34
  74. data/lib/packwerk/reference_checking/checkers/privacy_checker.rb +0 -76
  75. data/lib/packwerk/result.rb +0 -9
  76. data/lib/packwerk/sanity_checker.rb +0 -8
  77. data/lib/packwerk/violation_type.rb +0 -11
  78. data/sorbet/rbi/gems/html_tokenizer@0.0.7.rbi +0 -46
  79. data/sorbet/rbi/gems/mini_portile2@2.8.0.rbi +0 -8
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "ast/node"
@@ -6,27 +6,40 @@ require "ast/node"
6
6
  module Packwerk
7
7
  # A collection of constant definitions parsed from an Abstract Syntax Tree (AST).
8
8
  class ParsedConstantDefinitions
9
+ extend T::Sig
10
+
9
11
  class << self
12
+ extend T::Sig
13
+
10
14
  # What fully qualified constants can this constant refer to in this context?
15
+ sig { params(constant_name: String, namespace_path: T::Array[T.nilable(String)]).returns(T::Array[String]) }
11
16
  def reference_qualifications(constant_name, namespace_path:)
12
17
  return [constant_name] if constant_name.start_with?("::")
13
18
 
14
19
  resolved_constant_name = "::#{constant_name}"
15
20
 
16
21
  possible_namespaces = namespace_path.each_with_object([""]) do |current, acc|
17
- acc << "#{acc.last}::#{current}" if acc.last && current
22
+ acc << "#{acc.last}::#{current}" if current
18
23
  end
19
24
 
20
25
  possible_namespaces.map { |namespace| namespace + resolved_constant_name }
21
26
  end
22
27
  end
23
28
 
29
+ sig { params(root_node: T.nilable(AST::Node)).void }
24
30
  def initialize(root_node:)
25
- @local_definitions = {}
31
+ @local_definitions = T.let({}, T::Hash[String, T.nilable(Node::Location)])
26
32
 
27
33
  collect_local_definitions_from_root(root_node) if root_node
28
34
  end
29
35
 
36
+ sig do
37
+ params(
38
+ constant_name: String,
39
+ location: T.nilable(Node::Location),
40
+ namespace_path: T::Array[String],
41
+ ).returns(T::Boolean)
42
+ end
30
43
  def local_reference?(constant_name, location: nil, namespace_path: [])
31
44
  qualifications = self.class.reference_qualifications(constant_name, namespace_path: namespace_path)
32
45
 
@@ -38,13 +51,14 @@ module Packwerk
38
51
 
39
52
  private
40
53
 
54
+ sig { params(node: AST::Node, current_namespace_path: T::Array[T.nilable(String)]).void }
41
55
  def collect_local_definitions_from_root(node, current_namespace_path = [])
42
56
  if NodeHelpers.constant_assignment?(node)
43
57
  add_definition(NodeHelpers.constant_name(node), current_namespace_path, NodeHelpers.name_location(node))
44
58
  elsif NodeHelpers.module_name_from_definition(node)
45
59
  # handle compact constant nesting (e.g. "module Sales::Order")
46
- tempnode = node
47
- while (tempnode = NodeHelpers.each_child(tempnode).find { |n| NodeHelpers.constant?(n) })
60
+ tempnode = T.let(node, T.nilable(AST::Node))
61
+ while (tempnode = NodeHelpers.each_child(T.must(tempnode)).find { |node| NodeHelpers.constant?(node) })
48
62
  add_definition(NodeHelpers.constant_name(tempnode), current_namespace_path,
49
63
  NodeHelpers.name_location(tempnode))
50
64
  end
@@ -55,10 +69,19 @@ module Packwerk
55
69
  NodeHelpers.each_child(node) { |child| collect_local_definitions_from_root(child, current_namespace_path) }
56
70
  end
57
71
 
72
+ sig do
73
+ params(
74
+ constant_name: String,
75
+ current_namespace_path: T::Array[T.nilable(String)],
76
+ location: T.nilable(Node::Location),
77
+ ).void
78
+ end
58
79
  def add_definition(constant_name, current_namespace_path, location)
59
80
  resolved_constant = [""].concat(current_namespace_path).push(constant_name).join("::")
60
81
 
61
82
  @local_definitions[resolved_constant] = location
62
83
  end
63
84
  end
85
+
86
+ private_constant :ParsedConstantDefinitions
64
87
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "ast/node"
@@ -9,19 +9,24 @@ require "parser/source/buffer"
9
9
  module Packwerk
10
10
  module Parsers
11
11
  class Erb
12
+ extend T::Sig
13
+
12
14
  include ParserInterface
13
15
 
16
+ sig { params(parser_class: T.untyped, ruby_parser: Ruby).void }
14
17
  def initialize(parser_class: BetterHtml::Parser, ruby_parser: Ruby.new)
15
- @parser_class = parser_class
18
+ @parser_class = T.let(parser_class, T.class_of(BetterHtml::Parser))
16
19
  @ruby_parser = ruby_parser
17
20
  end
18
21
 
22
+ sig { override.params(io: T.any(IO, StringIO), file_path: String).returns(T.untyped) }
19
23
  def call(io:, file_path: "<unknown>")
20
24
  buffer = Parser::Source::Buffer.new(file_path)
21
25
  buffer.source = io.read
22
26
  parse_buffer(buffer, file_path: file_path)
23
27
  end
24
28
 
29
+ sig { params(buffer: Parser::Source::Buffer, file_path: String).returns(T.nilable(AST::Node)) }
25
30
  def parse_buffer(buffer, file_path:)
26
31
  parser = @parser_class.new(buffer, template_language: :html)
27
32
  to_ruby_ast(parser.ast, file_path)
@@ -35,12 +40,18 @@ module Packwerk
35
40
 
36
41
  private
37
42
 
43
+ sig do
44
+ params(
45
+ erb_ast: T.all(::AST::Node, Object),
46
+ file_path: String
47
+ ).returns(T.nilable(::AST::Node))
48
+ end
38
49
  def to_ruby_ast(erb_ast, file_path)
39
50
  # Note that we're not using the source location (line/column) at the moment, but if we did
40
51
  # care about that, we'd need to tweak this to insert empty lines and spaces so that things
41
52
  # line up with the ERB file
42
- code_pieces = code_nodes(erb_ast).map do |node|
43
- node.children.first
53
+ code_pieces = T.must(code_nodes(erb_ast)).map do |node|
54
+ T.cast(node, ::AST::Node).children.first
44
55
  end
45
56
 
46
57
  @ruby_parser.call(
@@ -49,6 +60,14 @@ module Packwerk
49
60
  )
50
61
  end
51
62
 
63
+ sig do
64
+ params(
65
+ node: T.any(::AST::Node, String, NilClass),
66
+ block: T.nilable(T.proc.params(arg0: ::AST::Node).void),
67
+ ).returns(
68
+ T.any(T::Enumerator[::AST::Node], T::Array[String], NilClass)
69
+ )
70
+ end
52
71
  def code_nodes(node, &block)
53
72
  return enum_for(:code_nodes, node) unless block
54
73
  return unless node.is_a?(::AST::Node)
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "singleton"
@@ -20,20 +20,29 @@ module Packwerk
20
20
  ERB_REGEX = /\.erb\Z/
21
21
  private_constant :ERB_REGEX
22
22
 
23
+ sig { void }
24
+ def initialize
25
+ @ruby_parser = T.let(nil, T.nilable(ParserInterface))
26
+ @erb_parser = T.let(nil, T.nilable(ParserInterface))
27
+ @erb_parser_class = T.let(nil, T.nilable(Class))
28
+ end
29
+
23
30
  sig { params(path: String).returns(T.nilable(ParserInterface)) }
24
31
  def for_path(path)
25
32
  case path
26
33
  when RUBY_REGEX
27
34
  @ruby_parser ||= Ruby.new
28
35
  when ERB_REGEX
29
- @erb_parser ||= erb_parser_class.new
36
+ @erb_parser ||= T.unsafe(erb_parser_class).new
30
37
  end
31
38
  end
32
39
 
40
+ sig { returns(Class) }
33
41
  def erb_parser_class
34
42
  @erb_parser_class ||= Erb
35
43
  end
36
44
 
45
+ sig { params(klass: T.nilable(Class)).void }
37
46
  def erb_parser_class=(klass)
38
47
  @erb_parser_class = klass
39
48
  @erb_parser = nil
@@ -11,7 +11,7 @@ module Packwerk
11
11
 
12
12
  interface!
13
13
 
14
- sig { abstract.params(io: File, file_path: String).returns(T.untyped) }
14
+ sig { abstract.params(io: T.any(IO, StringIO), file_path: String).returns(T.untyped) }
15
15
  def call(io:, file_path:)
16
16
  end
17
17
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "parser"
@@ -7,9 +7,14 @@ require "parser/current"
7
7
  module Packwerk
8
8
  module Parsers
9
9
  class Ruby
10
+ extend T::Sig
11
+
10
12
  include ParserInterface
11
13
 
12
14
  class RaiseExceptionsParser < Parser::CurrentRuby
15
+ extend T::Sig
16
+
17
+ sig { params(builder: T.untyped).void }
13
18
  def initialize(builder)
14
19
  super(builder)
15
20
  super.diagnostics.all_errors_are_fatal = true
@@ -17,16 +22,21 @@ module Packwerk
17
22
  end
18
23
 
19
24
  class TolerateInvalidUtf8Builder < Parser::Builders::Default
25
+ extend T::Sig
26
+
27
+ sig { params(token: T.untyped).returns(T.untyped) }
20
28
  def string_value(token)
21
29
  value(token)
22
30
  end
23
31
  end
24
32
 
33
+ sig { params(parser_class: T.untyped).void }
25
34
  def initialize(parser_class: RaiseExceptionsParser)
26
- @builder = TolerateInvalidUtf8Builder.new
27
- @parser_class = parser_class
35
+ @builder = T.let(TolerateInvalidUtf8Builder.new, Object)
36
+ @parser_class = T.let(parser_class, T.class_of(RaiseExceptionsParser))
28
37
  end
29
38
 
39
+ sig { override.params(io: T.any(IO, StringIO), file_path: String).returns(T.nilable(Parser::AST::Node)) }
30
40
  def call(io:, file_path: "<unknown>")
31
41
  buffer = Parser::Source::Buffer.new(file_path)
32
42
  buffer.source = io.read
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
@@ -11,8 +11,12 @@ module Packwerk
11
11
  class ParseResult < Offense; end
12
12
 
13
13
  class ParseError < StandardError
14
- attr_reader :result
14
+ extend T::Sig
15
15
 
16
+ sig { returns(ParseResult) }
17
+ attr_reader(:result)
18
+
19
+ sig { params(result: ParseResult).void }
16
20
  def initialize(result)
17
21
  super(result.message)
18
22
  @result = result
@@ -2,15 +2,17 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "bundler"
5
+ gem "railties", ">= 6.0"
6
+ require "rails/railtie"
5
7
 
6
8
  module Packwerk
7
9
  # Extracts the load paths from the analyzed application so that we can map constant names to paths.
8
- module ApplicationLoadPaths
10
+ module RailsLoadPaths
9
11
  class << self
10
12
  extend T::Sig
11
13
 
12
14
  sig { params(root: String, environment: String).returns(T::Hash[String, Module]) }
13
- def extract_relevant_paths(root, environment)
15
+ def for(root, environment:)
14
16
  require_application(root, environment)
15
17
  all_paths = extract_application_autoload_paths
16
18
  relevant_paths = filter_relevant_paths(all_paths)
@@ -18,6 +20,8 @@ module Packwerk
18
20
  relative_path_strings(relevant_paths)
19
21
  end
20
22
 
23
+ private
24
+
21
25
  sig { returns(T::Hash[String, Module]) }
22
26
  def extract_application_autoload_paths
23
27
  Rails.autoloaders.inject({}) do |h, loader|
@@ -44,8 +48,6 @@ module Packwerk
44
48
  load_paths.transform_keys { |path| Pathname.new(path).relative_path_from(rails_root).to_s }
45
49
  end
46
50
 
47
- private
48
-
49
51
  sig { params(root: String, environment: String).void }
50
52
  def require_application(root, environment)
51
53
  environment_file = "#{root}/config/environment"
@@ -3,5 +3,11 @@
3
3
 
4
4
  module Packwerk
5
5
  # A reference from a file in one package to a constant that may be defined in a different package.
6
- Reference = Struct.new(:source_package, :relative_path, :constant, :source_location)
6
+ Reference = Struct.new(
7
+ :package,
8
+ :relative_path,
9
+ :constant,
10
+ :source_location,
11
+ keyword_init: true,
12
+ )
7
13
  end
@@ -9,9 +9,11 @@ module Packwerk
9
9
  extend T::Sig
10
10
  include Checker
11
11
 
12
- sig { override.returns(ViolationType) }
12
+ VIOLATION_TYPE = T.let("dependency", String)
13
+
14
+ sig { override.returns(String) }
13
15
  def violation_type
14
- ViolationType::Dependency
16
+ VIOLATION_TYPE
15
17
  end
16
18
 
17
19
  sig do
@@ -20,9 +22,8 @@ module Packwerk
20
22
  .returns(T::Boolean)
21
23
  end
22
24
  def invalid_reference?(reference)
23
- return false unless reference.source_package
24
- return false unless reference.source_package.enforce_dependencies?
25
- return false if reference.source_package.dependency?(reference.constant.package)
25
+ return false unless reference.package.enforce_dependencies?
26
+ return false if reference.package.dependency?(reference.constant.package)
26
27
 
27
28
  true
28
29
  end
@@ -33,14 +34,36 @@ module Packwerk
33
34
  .returns(String)
34
35
  end
35
36
  def message(reference)
37
+ const_name = reference.constant.name
38
+ const_package = reference.constant.package
39
+ ref_package = reference.package
40
+
36
41
  <<~EOS
37
- Dependency violation: #{reference.constant.name} belongs to '#{reference.constant.package}', but '#{reference.source_package}' does not specify a dependency on '#{reference.constant.package}'.
42
+ Dependency violation: #{const_name} belongs to '#{const_package}', but '#{ref_package}' does not specify a dependency on '#{const_package}'.
38
43
  Are we missing an abstraction?
39
44
  Is the code making the reference, and the referenced constant, in the right packages?
40
45
 
41
46
  #{standard_help_message(reference)}
42
47
  EOS
43
48
  end
49
+
50
+ sig { override.params(listed_offense: ReferenceOffense).returns(T::Boolean) }
51
+ def strict_mode_violation?(listed_offense)
52
+ referencing_package = listed_offense.reference.package
53
+ referencing_package.config["enforce_dependencies"] == "strict"
54
+ end
55
+
56
+ private
57
+
58
+ sig { params(reference: Reference).returns(String) }
59
+ def standard_help_message(reference)
60
+ standard_message = <<~EOS
61
+ Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
62
+ To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
63
+ EOS
64
+
65
+ standard_message.chomp
66
+ end
44
67
  end
45
68
  end
46
69
  end
@@ -6,7 +6,7 @@ module Packwerk
6
6
  class ReferenceChecker
7
7
  extend T::Sig
8
8
 
9
- sig { params(checkers: T::Array[Checkers::Checker]).void }
9
+ sig { params(checkers: T::Array[Checker]).void }
10
10
  def initialize(checkers)
11
11
  @checkers = checkers
12
12
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
@@ -38,10 +38,10 @@ module Packwerk
38
38
  next if source_package == package_for_constant
39
39
 
40
40
  fully_qualified_references << Reference.new(
41
- source_package,
42
- unresolved_reference.relative_path,
43
- constant,
44
- unresolved_reference.source_location
41
+ package: source_package,
42
+ relative_path: unresolved_reference.relative_path,
43
+ constant: constant,
44
+ source_location: unresolved_reference.source_location,
45
45
  )
46
46
  end
47
47
 
@@ -51,8 +51,8 @@ module Packwerk
51
51
 
52
52
  sig do
53
53
  params(
54
- constant_name_inspectors: T::Array[Packwerk::ConstantNameInspector],
55
- root_node: ::AST::Node,
54
+ constant_name_inspectors: T::Array[ConstantNameInspector],
55
+ root_node: AST::Node,
56
56
  root_path: String,
57
57
  ).void
58
58
  end
@@ -63,7 +63,10 @@ module Packwerk
63
63
  )
64
64
  @constant_name_inspectors = constant_name_inspectors
65
65
  @root_path = root_path
66
- @local_constant_definitions = ParsedConstantDefinitions.new(root_node: root_node)
66
+ @local_constant_definitions = T.let(
67
+ ParsedConstantDefinitions.new(root_node: root_node),
68
+ ParsedConstantDefinitions,
69
+ )
67
70
  end
68
71
 
69
72
  sig do
@@ -110,13 +113,20 @@ module Packwerk
110
113
  location = NodeHelpers.location(node)
111
114
 
112
115
  UnresolvedReference.new(
113
- constant_name,
114
- namespace_path,
115
- relative_file,
116
- location
116
+ constant_name: constant_name,
117
+ namespace_path: namespace_path,
118
+ relative_path: relative_file,
119
+ source_location: location
117
120
  )
118
121
  end
119
122
 
123
+ sig do
124
+ params(
125
+ constant_name: String,
126
+ name_location: T.nilable(Node::Location),
127
+ namespace_path: T::Array[String],
128
+ ).returns(T::Boolean)
129
+ end
120
130
  def local_reference?(constant_name, name_location, namespace_path)
121
131
  @local_constant_definitions.local_reference?(
122
132
  constant_name,
@@ -125,4 +135,6 @@ module Packwerk
125
135
  )
126
136
  end
127
137
  end
138
+
139
+ private_constant :ReferenceExtractor
128
140
  end
@@ -10,13 +10,13 @@ module Packwerk
10
10
  sig { returns(Reference) }
11
11
  attr_reader :reference
12
12
 
13
- sig { returns(ViolationType) }
13
+ sig { returns(String) }
14
14
  attr_reader :violation_type
15
15
 
16
16
  sig do
17
17
  params(
18
18
  reference: Packwerk::Reference,
19
- violation_type: Packwerk::ViolationType,
19
+ violation_type: String,
20
20
  message: String,
21
21
  location: T.nilable(Node::Location)
22
22
  )
@@ -8,11 +8,6 @@ module Packwerk
8
8
  class RunContext
9
9
  extend T::Sig
10
10
 
11
- DEFAULT_CHECKERS = T.let([
12
- ::Packwerk::ReferenceChecking::Checkers::DependencyChecker.new,
13
- ::Packwerk::ReferenceChecking::Checkers::PrivacyChecker.new,
14
- ], T::Array[ReferenceChecking::Checkers::Checker])
15
-
16
11
  class << self
17
12
  extend T::Sig
18
13
 
@@ -44,7 +39,7 @@ module Packwerk
44
39
  config_path: T.nilable(String),
45
40
  package_paths: T.nilable(T.any(T::Array[String], String)),
46
41
  custom_associations: AssociationInspector::CustomAssociations,
47
- checkers: T::Array[ReferenceChecking::Checkers::Checker],
42
+ checkers: T::Array[Checker],
48
43
  cache_enabled: T::Boolean,
49
44
  ).void
50
45
  end
@@ -56,7 +51,7 @@ module Packwerk
56
51
  config_path: nil,
57
52
  package_paths: nil,
58
53
  custom_associations: [],
59
- checkers: DEFAULT_CHECKERS,
54
+ checkers: Checker.all,
60
55
  cache_enabled: false
61
56
  )
62
57
  @root_path = root_path
@@ -114,7 +109,7 @@ module Packwerk
114
109
 
115
110
  sig { returns(ConstantDiscovery) }
116
111
  def context_provider
117
- @context_provider ||= ::Packwerk::ConstantDiscovery.new(
112
+ @context_provider ||= ConstantDiscovery.new(
118
113
  constant_resolver: resolver,
119
114
  packages: package_set
120
115
  )
@@ -132,9 +127,11 @@ module Packwerk
132
127
  sig { returns(T::Array[ConstantNameInspector]) }
133
128
  def constant_name_inspectors
134
129
  [
135
- ::Packwerk::ConstNodeInspector.new,
136
- ::Packwerk::AssociationInspector.new(inflector: @inflector, custom_associations: @custom_associations),
130
+ ConstNodeInspector.new,
131
+ AssociationInspector.new(inflector: @inflector, custom_associations: @custom_associations),
137
132
  ]
138
133
  end
139
134
  end
135
+
136
+ private_constant :RunContext
140
137
  end
@@ -1,24 +1,31 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "spring/commands"
5
+ require "sorbet-runtime"
5
6
 
6
7
  module Packwerk
7
8
  class SpringCommand
8
- def env(*)
9
+ extend T::Sig
10
+
11
+ sig { params(args: T.untyped).returns(String) }
12
+ def env(args)
9
13
  # Packwerk needs to run in a test environment, which has a set of autoload paths that are
10
14
  # often a superset of the dev/prod paths (for example, test/support/helpers)
11
15
  "test"
12
16
  end
13
17
 
18
+ sig { returns(String) }
14
19
  def exec_name
15
20
  "packwerk"
16
21
  end
17
22
 
23
+ sig { returns(String) }
18
24
  def gem_name
19
25
  "packwerk"
20
26
  end
21
27
 
28
+ sig { returns(T::Boolean) }
22
29
  def call
23
30
  load(Gem.bin_path(gem_name, exec_name))
24
31
  end
@@ -26,3 +33,5 @@ module Packwerk
26
33
 
27
34
  Spring.register_command("packwerk", SpringCommand.new)
28
35
  end
36
+
37
+ require "packwerk/disable_sorbet"
@@ -6,5 +6,13 @@ module Packwerk
6
6
  # Unresolved means that we know how it's referred to in the file,
7
7
  # and we have enough context on that reference to figure out the fully qualified reference such that we
8
8
  # can produce a Reference in a separate pass. However, we have not yet resolved it to its fully qualified version.
9
- UnresolvedReference = Struct.new(:constant_name, :namespace_path, :relative_path, :source_location)
9
+ UnresolvedReference = Struct.new(
10
+ :constant_name,
11
+ :namespace_path,
12
+ :relative_path,
13
+ :source_location,
14
+ keyword_init: true,
15
+ )
16
+
17
+ private_constant :UnresolvedReference
10
18
  end
@@ -0,0 +1,18 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ module Validator
6
+ class Result < T::Struct
7
+ extend T::Sig
8
+
9
+ const :ok, T::Boolean
10
+ const :error_value, T.nilable(String)
11
+
12
+ sig { returns(T::Boolean) }
13
+ def ok?
14
+ ok
15
+ end
16
+ end
17
+ end
18
+ end