packwerk 2.2.0 → 2.2.2
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +29 -20
- data/.github/workflows/cla.yml +22 -0
- data/.rubocop.yml +48 -19
- data/Gemfile +7 -2
- data/Gemfile.lock +202 -175
- data/README.md +1 -1
- data/RESOLVING_VIOLATIONS.md +81 -0
- data/Rakefile +1 -1
- data/USAGE.md +14 -5
- data/bin/m +1 -1
- data/bin/rake +1 -1
- data/bin/rubocop +1 -1
- data/bin/srb +1 -1
- data/bin/tapioca +1 -1
- data/gemfiles/Gemfile-rails-6-0 +1 -1
- data/gemfiles/Gemfile-rails-6-1 +22 -0
- data/lib/packwerk/application_load_paths.rb +1 -1
- data/lib/packwerk/application_validator.rb +7 -6
- data/lib/packwerk/association_inspector.rb +17 -15
- data/lib/packwerk/cache.rb +36 -29
- data/lib/packwerk/cli.rb +24 -20
- data/lib/packwerk/const_node_inspector.rb +8 -7
- data/lib/packwerk/constant_name_inspector.rb +2 -2
- data/lib/packwerk/deprecated_references.rb +40 -20
- data/lib/packwerk/file_processor.rb +14 -14
- data/lib/packwerk/files_for_processing.rb +27 -31
- data/lib/packwerk/formatters/offenses_formatter.rb +3 -3
- data/lib/packwerk/formatters/progress_formatter.rb +2 -2
- data/lib/packwerk/node.rb +1 -294
- data/lib/packwerk/node_helpers.rb +335 -0
- data/lib/packwerk/node_processor.rb +6 -5
- data/lib/packwerk/node_processor_factory.rb +3 -3
- data/lib/packwerk/node_visitor.rb +1 -1
- data/lib/packwerk/offense_collection.rb +27 -8
- data/lib/packwerk/offenses_formatter.rb +2 -2
- data/lib/packwerk/package.rb +3 -0
- data/lib/packwerk/package_set.rb +2 -0
- data/lib/packwerk/parse_run.rb +29 -20
- data/lib/packwerk/parsed_constant_definitions.rb +23 -20
- data/lib/packwerk/parsers/erb.rb +3 -3
- data/lib/packwerk/reference_checking/checkers/checker.rb +16 -3
- data/lib/packwerk/reference_checking/checkers/dependency_checker.rb +16 -0
- data/lib/packwerk/reference_checking/checkers/privacy_checker.rb +18 -0
- data/lib/packwerk/reference_checking/reference_checker.rb +3 -1
- data/lib/packwerk/reference_extractor.rb +51 -48
- data/lib/packwerk/reference_offense.rb +3 -27
- data/lib/packwerk/run_context.rb +9 -8
- data/lib/packwerk/spring_command.rb +1 -1
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk.rb +1 -0
- data/packwerk.gemspec +5 -12
- data/sorbet/rbi/gems/actioncable@7.0.3.1.rbi +2754 -0
- data/sorbet/rbi/gems/actionmailbox@7.0.3.1.rbi +1496 -0
- data/sorbet/rbi/gems/actionmailer@7.0.3.1.rbi +2362 -0
- data/sorbet/rbi/gems/actionpack@7.0.3.1.rbi +19397 -0
- data/sorbet/rbi/gems/actiontext@7.0.3.1.rbi +1569 -0
- data/sorbet/rbi/gems/actionview@7.0.3.1.rbi +14907 -0
- data/sorbet/rbi/gems/activejob@7.0.3.1.rbi +2553 -0
- data/sorbet/rbi/gems/activemodel@7.0.3.1.rbi +5999 -0
- data/sorbet/rbi/gems/activerecord@7.0.3.1.rbi +37832 -0
- data/sorbet/rbi/gems/activestorage@7.0.3.1.rbi +2321 -0
- data/sorbet/rbi/gems/activesupport@7.0.3.1.rbi +18818 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi +11722 -0
- data/sorbet/rbi/gems/constant_resolver@0.2.0.rbi +90 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1079 -0
- data/sorbet/rbi/gems/digest@3.1.0.rbi +189 -0
- data/sorbet/rbi/gems/erubi@1.11.0.rbi +140 -0
- data/sorbet/rbi/gems/globalid@1.0.0.rbi +572 -0
- data/sorbet/rbi/gems/i18n@1.12.0.rbi +2296 -0
- data/sorbet/rbi/gems/json@2.6.2.rbi +1548 -0
- data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +8 -0
- data/sorbet/rbi/gems/loofah@2.18.0.rbi +877 -0
- data/sorbet/rbi/gems/m@1.6.0.rbi +257 -0
- data/sorbet/rbi/gems/marcel@1.0.2.rbi +220 -0
- data/sorbet/rbi/gems/mini_mime@1.1.2.rbi +170 -0
- data/sorbet/rbi/gems/mini_portile2@2.8.0.rbi +8 -0
- data/sorbet/rbi/gems/minitest-focus@1.3.1.rbi +104 -0
- data/sorbet/rbi/gems/minitest@5.16.2.rbi +2136 -0
- data/sorbet/rbi/gems/mocha@1.14.0.rbi +4177 -0
- data/sorbet/rbi/gems/net-imap@0.2.3.rbi +2147 -0
- data/sorbet/rbi/gems/net-pop@0.1.1.rbi +926 -0
- data/sorbet/rbi/gems/net-protocol@0.1.3.rbi +11 -0
- data/sorbet/rbi/gems/net-smtp@0.3.1.rbi +1108 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +153 -0
- data/sorbet/rbi/gems/nio4r@2.5.8.rbi +292 -0
- data/sorbet/rbi/gems/nokogiri@1.13.8.rbi +6478 -0
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
- data/sorbet/rbi/gems/parser@3.1.2.1.rbi +9029 -0
- data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +8 -0
- data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
- data/sorbet/rbi/gems/racc@1.6.0.rbi +152 -0
- data/sorbet/rbi/gems/rack-test@2.0.2.rbi +953 -0
- data/sorbet/rbi/gems/rack@2.2.4.rbi +5636 -0
- data/sorbet/rbi/gems/rails-html-sanitizer@1.4.3.rbi +688 -0
- data/sorbet/rbi/gems/rails@7.0.3.1.rbi +8 -0
- data/sorbet/rbi/gems/railties@7.0.3.1.rbi +3507 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +392 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +2924 -0
- data/sorbet/rbi/gems/rbi@0.0.15.rbi +3007 -0
- data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +3383 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +4714 -0
- data/sorbet/rbi/gems/rubocop-ast@1.21.0.rbi +6961 -0
- data/sorbet/rbi/gems/rubocop-performance@1.14.3.rbi +2986 -0
- data/sorbet/rbi/gems/{rubocop-shopify@2.0.1.rbi → rubocop-shopify@2.9.0.rbi} +4 -4
- data/sorbet/rbi/gems/rubocop-sorbet@0.6.11.rbi +992 -0
- data/sorbet/rbi/gems/rubocop@1.34.1.rbi +51820 -0
- data/sorbet/rbi/gems/ruby-lsp@0.2.1.rbi +11 -0
- data/sorbet/rbi/gems/smart_properties@1.17.0.rbi +474 -0
- data/sorbet/rbi/gems/spoom@1.1.11.rbi +2181 -0
- data/sorbet/rbi/gems/spring@4.0.0.rbi +411 -0
- data/sorbet/rbi/gems/strscan@3.0.4.rbi +8 -0
- data/sorbet/rbi/gems/syntax_tree@3.3.0.rbi +8 -0
- data/sorbet/rbi/gems/tapioca@0.9.2.rbi +3181 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
- data/sorbet/rbi/gems/timeout@0.3.0.rbi +142 -0
- data/sorbet/rbi/gems/tzinfo@2.0.5.rbi +5896 -0
- data/sorbet/rbi/gems/unicode-display_width@2.2.0.rbi +48 -0
- data/sorbet/rbi/gems/unparser@0.6.5.rbi +4529 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +2582 -0
- data/sorbet/rbi/gems/websocket-driver@0.7.5.rbi +993 -0
- data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +388 -0
- data/sorbet/rbi/gems/yard@0.9.28.rbi +18242 -0
- data/sorbet/rbi/gems/zeitwerk@2.6.0.rbi +867 -0
- data/sorbet/rbi/shims/psych.rbi +5 -0
- data/sorbet/tapioca/require.rb +2 -3
- metadata +91 -146
- data/.github/probots.yml +0 -2
- data/library.yml +0 -6
- data/service.yml +0 -1
- data/sorbet/rbi/gems/actioncable@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -860
- data/sorbet/rbi/gems/actionmailbox@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -568
- data/sorbet/rbi/gems/actionmailer@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -587
- data/sorbet/rbi/gems/actionpack@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -5314
- data/sorbet/rbi/gems/actiontext@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -699
- data/sorbet/rbi/gems/actionview@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -2515
- data/sorbet/rbi/gems/activejob@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -624
- data/sorbet/rbi/gems/activemodel@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -1248
- data/sorbet/rbi/gems/activerecord@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -8363
- data/sorbet/rbi/gems/activestorage@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -876
- data/sorbet/rbi/gems/activesupport@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -3987
- data/sorbet/rbi/gems/colorize@0.8.1.rbi +0 -40
- data/sorbet/rbi/gems/commander@4.5.2.rbi +0 -8
- data/sorbet/rbi/gems/concurrent-ruby@1.1.8.rbi +0 -1969
- data/sorbet/rbi/gems/constant_resolver@0.1.5.rbi +0 -26
- data/sorbet/rbi/gems/erubi@1.10.0.rbi +0 -41
- data/sorbet/rbi/gems/globalid@0.4.2.rbi +0 -178
- data/sorbet/rbi/gems/highline@2.0.3.rbi +0 -8
- data/sorbet/rbi/gems/i18n@1.8.10.rbi +0 -600
- data/sorbet/rbi/gems/loofah@2.9.0.rbi +0 -274
- data/sorbet/rbi/gems/m@1.5.1.rbi +0 -108
- data/sorbet/rbi/gems/marcel@1.0.0.rbi +0 -70
- data/sorbet/rbi/gems/mini_mime@1.0.3.rbi +0 -71
- data/sorbet/rbi/gems/minitest-focus@1.2.1.rbi +0 -8
- data/sorbet/rbi/gems/minitest@5.14.4.rbi +0 -544
- data/sorbet/rbi/gems/mocha@1.12.0.rbi +0 -953
- data/sorbet/rbi/gems/nio4r@2.5.7.rbi +0 -90
- data/sorbet/rbi/gems/nokogiri@1.11.2.rbi +0 -1647
- data/sorbet/rbi/gems/parallel@1.20.1.rbi +0 -117
- data/sorbet/rbi/gems/parlour@6.0.0.rbi +0 -1272
- data/sorbet/rbi/gems/parser@3.0.0.0.rbi +0 -1745
- data/sorbet/rbi/gems/pry@0.14.0.rbi +0 -8
- data/sorbet/rbi/gems/psych@3.3.2.rbi +0 -24
- data/sorbet/rbi/gems/racc@1.5.2.rbi +0 -57
- data/sorbet/rbi/gems/rack-test@1.1.0.rbi +0 -335
- data/sorbet/rbi/gems/rack@2.2.3.rbi +0 -1718
- data/sorbet/rbi/gems/rails-html-sanitizer@1.3.0.rbi +0 -213
- data/sorbet/rbi/gems/rails@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -8
- data/sorbet/rbi/gems/railties@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi +0 -880
- data/sorbet/rbi/gems/rainbow@3.0.0.rbi +0 -155
- data/sorbet/rbi/gems/rake@13.0.3.rbi +0 -837
- data/sorbet/rbi/gems/regexp_parser@2.1.1.rbi +0 -8
- data/sorbet/rbi/gems/rexml@3.2.4.rbi +0 -8
- data/sorbet/rbi/gems/rubocop-ast@1.4.1.rbi +0 -8
- data/sorbet/rbi/gems/rubocop-performance@1.10.2.rbi +0 -8
- data/sorbet/rbi/gems/rubocop-sorbet@0.6.1.rbi +0 -8
- data/sorbet/rbi/gems/rubocop@1.12.0.rbi +0 -8
- data/sorbet/rbi/gems/smart_properties@1.15.0.rbi +0 -168
- data/sorbet/rbi/gems/spoom@1.1.0.rbi +0 -1061
- data/sorbet/rbi/gems/spring@2.1.1.rbi +0 -160
- data/sorbet/rbi/gems/sprockets-rails@3.2.2.rbi +0 -451
- data/sorbet/rbi/gems/sprockets@4.0.2.rbi +0 -1133
- data/sorbet/rbi/gems/tapioca@0.4.19.rbi +0 -603
- data/sorbet/rbi/gems/thor@1.1.0.rbi +0 -893
- data/sorbet/rbi/gems/tzinfo@2.0.4.rbi +0 -566
- data/sorbet/rbi/gems/unicode-display_width@2.0.0.rbi +0 -8
- data/sorbet/rbi/gems/websocket-driver@0.7.3.rbi +0 -438
- data/sorbet/rbi/gems/zeitwerk@2.4.2.rbi +0 -177
data/lib/packwerk/parsers/erb.rb
CHANGED
|
@@ -49,8 +49,8 @@ module Packwerk
|
|
|
49
49
|
)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def code_nodes(node)
|
|
53
|
-
return enum_for(:code_nodes, node) unless
|
|
52
|
+
def code_nodes(node, &block)
|
|
53
|
+
return enum_for(:code_nodes, node) unless block
|
|
54
54
|
return unless node.is_a?(::AST::Node)
|
|
55
55
|
|
|
56
56
|
yield node if node.type == :code
|
|
@@ -62,7 +62,7 @@ module Packwerk
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
node.children.each do |child|
|
|
65
|
-
code_nodes(child)
|
|
65
|
+
code_nodes(child, &block)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -8,13 +8,26 @@ module Packwerk
|
|
|
8
8
|
extend T::Sig
|
|
9
9
|
extend T::Helpers
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
abstract!
|
|
12
12
|
|
|
13
|
-
sig { returns(ViolationType)
|
|
13
|
+
sig { abstract.returns(ViolationType) }
|
|
14
14
|
def violation_type; end
|
|
15
15
|
|
|
16
|
-
sig { params(reference: Reference).returns(T::Boolean)
|
|
16
|
+
sig { abstract.params(reference: Reference).returns(T::Boolean) }
|
|
17
17
|
def invalid_reference?(reference); end
|
|
18
|
+
|
|
19
|
+
sig { abstract.params(reference: Reference).returns(String) }
|
|
20
|
+
def message(reference); end
|
|
21
|
+
|
|
22
|
+
sig { params(reference: Reference).returns(String) }
|
|
23
|
+
def standard_help_message(reference)
|
|
24
|
+
standard_message = <<~EOS
|
|
25
|
+
Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
|
|
26
|
+
To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
|
|
27
|
+
EOS
|
|
28
|
+
|
|
29
|
+
standard_message.chomp
|
|
30
|
+
end
|
|
18
31
|
end
|
|
19
32
|
end
|
|
20
33
|
end
|
|
@@ -23,8 +23,24 @@ module Packwerk
|
|
|
23
23
|
return false unless reference.source_package
|
|
24
24
|
return false unless reference.source_package.enforce_dependencies?
|
|
25
25
|
return false if reference.source_package.dependency?(reference.constant.package)
|
|
26
|
+
|
|
26
27
|
true
|
|
27
28
|
end
|
|
29
|
+
|
|
30
|
+
sig do
|
|
31
|
+
override
|
|
32
|
+
.params(reference: Packwerk::Reference)
|
|
33
|
+
.returns(String)
|
|
34
|
+
end
|
|
35
|
+
def message(reference)
|
|
36
|
+
<<~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}'.
|
|
38
|
+
Are we missing an abstraction?
|
|
39
|
+
Is the code making the reference, and the referenced constant, in the right packages?
|
|
40
|
+
|
|
41
|
+
#{standard_help_message(reference)}
|
|
42
|
+
EOS
|
|
43
|
+
end
|
|
28
44
|
end
|
|
29
45
|
end
|
|
30
46
|
end
|
|
@@ -31,6 +31,24 @@ module Packwerk
|
|
|
31
31
|
true
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
sig do
|
|
35
|
+
override
|
|
36
|
+
.params(reference: Packwerk::Reference)
|
|
37
|
+
.returns(String)
|
|
38
|
+
end
|
|
39
|
+
def message(reference)
|
|
40
|
+
source_desc = "'#{reference.source_package}'"
|
|
41
|
+
|
|
42
|
+
message = <<~EOS
|
|
43
|
+
Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but referenced from #{source_desc}.
|
|
44
|
+
Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?
|
|
45
|
+
|
|
46
|
+
#{standard_help_message(reference)}
|
|
47
|
+
EOS
|
|
48
|
+
|
|
49
|
+
message.chomp
|
|
50
|
+
end
|
|
51
|
+
|
|
34
52
|
private
|
|
35
53
|
|
|
36
54
|
sig do
|
|
@@ -19,10 +19,12 @@ module Packwerk
|
|
|
19
19
|
def call(reference)
|
|
20
20
|
@checkers.each_with_object([]) do |checker, violations|
|
|
21
21
|
next unless checker.invalid_reference?(reference)
|
|
22
|
+
|
|
22
23
|
offense = Packwerk::ReferenceOffense.new(
|
|
23
24
|
location: reference.source_location,
|
|
24
25
|
reference: reference,
|
|
25
|
-
violation_type: checker.violation_type
|
|
26
|
+
violation_type: checker.violation_type,
|
|
27
|
+
message: checker.message(reference)
|
|
26
28
|
)
|
|
27
29
|
violations << offense
|
|
28
30
|
end
|
|
@@ -6,6 +6,49 @@ module Packwerk
|
|
|
6
6
|
class ReferenceExtractor
|
|
7
7
|
extend T::Sig
|
|
8
8
|
|
|
9
|
+
class << self
|
|
10
|
+
extend T::Sig
|
|
11
|
+
|
|
12
|
+
sig do
|
|
13
|
+
params(
|
|
14
|
+
unresolved_references: T::Array[UnresolvedReference],
|
|
15
|
+
context_provider: ConstantDiscovery
|
|
16
|
+
).returns(T::Array[Reference])
|
|
17
|
+
end
|
|
18
|
+
def get_fully_qualified_references_from(unresolved_references, context_provider)
|
|
19
|
+
fully_qualified_references = T.let([], T::Array[Reference])
|
|
20
|
+
|
|
21
|
+
unresolved_references.each do |unresolved_references_or_offense|
|
|
22
|
+
unresolved_reference = unresolved_references_or_offense
|
|
23
|
+
|
|
24
|
+
constant =
|
|
25
|
+
context_provider.context_for(
|
|
26
|
+
unresolved_reference.constant_name,
|
|
27
|
+
current_namespace_path: unresolved_reference.namespace_path
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
next if constant.nil?
|
|
31
|
+
|
|
32
|
+
package_for_constant = constant.package
|
|
33
|
+
|
|
34
|
+
next if package_for_constant.nil?
|
|
35
|
+
|
|
36
|
+
source_package = context_provider.package_from_path(unresolved_reference.relative_path)
|
|
37
|
+
|
|
38
|
+
next if source_package == package_for_constant
|
|
39
|
+
|
|
40
|
+
fully_qualified_references << Reference.new(
|
|
41
|
+
source_package,
|
|
42
|
+
unresolved_reference.relative_path,
|
|
43
|
+
constant,
|
|
44
|
+
unresolved_reference.source_location
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
fully_qualified_references
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
9
52
|
sig do
|
|
10
53
|
params(
|
|
11
54
|
constant_name_inspectors: T::Array[Packwerk::ConstantNameInspector],
|
|
@@ -27,10 +70,10 @@ module Packwerk
|
|
|
27
70
|
params(
|
|
28
71
|
node: Parser::AST::Node,
|
|
29
72
|
ancestors: T::Array[Parser::AST::Node],
|
|
30
|
-
|
|
73
|
+
relative_file: String
|
|
31
74
|
).returns(T.nilable(UnresolvedReference))
|
|
32
75
|
end
|
|
33
|
-
def reference_from_node(node, ancestors:,
|
|
76
|
+
def reference_from_node(node, ancestors:, relative_file:)
|
|
34
77
|
constant_name = T.let(nil, T.nilable(String))
|
|
35
78
|
|
|
36
79
|
@constant_name_inspectors.each do |inspector|
|
|
@@ -44,50 +87,11 @@ module Packwerk
|
|
|
44
87
|
constant_name,
|
|
45
88
|
node: node,
|
|
46
89
|
ancestors: ancestors,
|
|
47
|
-
|
|
90
|
+
relative_file: relative_file
|
|
48
91
|
)
|
|
49
92
|
end
|
|
50
93
|
end
|
|
51
94
|
|
|
52
|
-
sig do
|
|
53
|
-
params(
|
|
54
|
-
unresolved_references: T::Array[UnresolvedReference],
|
|
55
|
-
context_provider: ConstantDiscovery
|
|
56
|
-
).returns(T::Array[Reference])
|
|
57
|
-
end
|
|
58
|
-
def self.get_fully_qualified_references_from(unresolved_references, context_provider)
|
|
59
|
-
fully_qualified_references = T.let([], T::Array[Reference])
|
|
60
|
-
|
|
61
|
-
unresolved_references.each do |unresolved_references_or_offense|
|
|
62
|
-
unresolved_reference = unresolved_references_or_offense
|
|
63
|
-
|
|
64
|
-
constant =
|
|
65
|
-
context_provider.context_for(
|
|
66
|
-
unresolved_reference.constant_name,
|
|
67
|
-
current_namespace_path: unresolved_reference.namespace_path
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
next if constant.nil?
|
|
71
|
-
|
|
72
|
-
package_for_constant = constant.package
|
|
73
|
-
|
|
74
|
-
next if package_for_constant.nil?
|
|
75
|
-
|
|
76
|
-
source_package = context_provider.package_from_path(unresolved_reference.relative_path)
|
|
77
|
-
|
|
78
|
-
next if source_package == package_for_constant
|
|
79
|
-
|
|
80
|
-
fully_qualified_references << Reference.new(
|
|
81
|
-
source_package,
|
|
82
|
-
unresolved_reference.relative_path,
|
|
83
|
-
constant,
|
|
84
|
-
unresolved_reference.source_location
|
|
85
|
-
)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
fully_qualified_references
|
|
89
|
-
end
|
|
90
|
-
|
|
91
95
|
private
|
|
92
96
|
|
|
93
97
|
sig do
|
|
@@ -95,16 +99,15 @@ module Packwerk
|
|
|
95
99
|
constant_name: String,
|
|
96
100
|
node: Parser::AST::Node,
|
|
97
101
|
ancestors: T::Array[Parser::AST::Node],
|
|
98
|
-
|
|
102
|
+
relative_file: String
|
|
99
103
|
).returns(T.nilable(UnresolvedReference))
|
|
100
104
|
end
|
|
101
|
-
def reference_from_constant(constant_name, node:, ancestors:,
|
|
102
|
-
namespace_path =
|
|
105
|
+
def reference_from_constant(constant_name, node:, ancestors:, relative_file:)
|
|
106
|
+
namespace_path = NodeHelpers.enclosing_namespace_path(node, ancestors: ancestors)
|
|
103
107
|
|
|
104
|
-
return if local_reference?(constant_name,
|
|
108
|
+
return if local_reference?(constant_name, NodeHelpers.name_location(node), namespace_path)
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
location = Node.location(node)
|
|
110
|
+
location = NodeHelpers.location(node)
|
|
108
111
|
|
|
109
112
|
UnresolvedReference.new(
|
|
110
113
|
constant_name,
|
|
@@ -17,39 +17,15 @@ module Packwerk
|
|
|
17
17
|
params(
|
|
18
18
|
reference: Packwerk::Reference,
|
|
19
19
|
violation_type: Packwerk::ViolationType,
|
|
20
|
+
message: String,
|
|
20
21
|
location: T.nilable(Node::Location)
|
|
21
22
|
)
|
|
22
23
|
.void
|
|
23
24
|
end
|
|
24
|
-
def initialize(reference:, violation_type:, location: nil)
|
|
25
|
-
super(file: reference.relative_path, message:
|
|
25
|
+
def initialize(reference:, violation_type:, message:, location: nil)
|
|
26
|
+
super(file: reference.relative_path, message: message, location: location)
|
|
26
27
|
@reference = reference
|
|
27
28
|
@violation_type = violation_type
|
|
28
29
|
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
sig { params(reference: Reference, violation_type: ViolationType).returns(String) }
|
|
33
|
-
def build_message(reference, violation_type)
|
|
34
|
-
violation_message = case violation_type
|
|
35
|
-
when ViolationType::Privacy
|
|
36
|
-
source_desc = "'#{reference.source_package}'"
|
|
37
|
-
"Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
|
|
38
|
-
"referenced from #{source_desc}.\n" \
|
|
39
|
-
"Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?"
|
|
40
|
-
when ViolationType::Dependency
|
|
41
|
-
"Dependency violation: #{reference.constant.name} belongs to '#{reference.constant.package}', but " \
|
|
42
|
-
"'#{reference.source_package}' does not specify a dependency on " \
|
|
43
|
-
"'#{reference.constant.package}'.\n" \
|
|
44
|
-
"Are we missing an abstraction?\n" \
|
|
45
|
-
"Is the code making the reference, and the referenced constant, in the right packages?\n"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
<<~EOS
|
|
49
|
-
#{violation_message}
|
|
50
|
-
Inference details: this is a reference to #{reference.constant.name} which seems to be defined in #{reference.constant.location}.
|
|
51
|
-
To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
|
|
52
|
-
EOS
|
|
53
|
-
end
|
|
54
30
|
end
|
|
55
31
|
end
|
data/lib/packwerk/run_context.rb
CHANGED
|
@@ -71,15 +71,16 @@ module Packwerk
|
|
|
71
71
|
|
|
72
72
|
@file_processor = T.let(nil, T.nilable(FileProcessor))
|
|
73
73
|
@context_provider = T.let(nil, T.nilable(ConstantDiscovery))
|
|
74
|
+
@package_set = T.let(nil, T.nilable(PackageSet))
|
|
74
75
|
# We need to initialize this before we fork the process, see https://github.com/Shopify/packwerk/issues/182
|
|
75
76
|
@cache = T.let(
|
|
76
77
|
Cache.new(enable_cache: @cache_enabled, cache_directory: @cache_directory, config_path: @config_path), Cache
|
|
77
78
|
)
|
|
78
79
|
end
|
|
79
80
|
|
|
80
|
-
sig { params(
|
|
81
|
-
def process_file(
|
|
82
|
-
processed_file = file_processor.call(
|
|
81
|
+
sig { params(relative_file: String).returns(T::Array[Packwerk::Offense]) }
|
|
82
|
+
def process_file(relative_file:)
|
|
83
|
+
processed_file = file_processor.call(relative_file)
|
|
83
84
|
|
|
84
85
|
references = ReferenceExtractor.get_fully_qualified_references_from(
|
|
85
86
|
processed_file.unresolved_references,
|
|
@@ -90,6 +91,11 @@ module Packwerk
|
|
|
90
91
|
processed_file.offenses + references.flat_map { |reference| reference_checker.call(reference) }
|
|
91
92
|
end
|
|
92
93
|
|
|
94
|
+
sig { returns(PackageSet) }
|
|
95
|
+
def package_set
|
|
96
|
+
@package_set ||= ::Packwerk::PackageSet.load_all_from(@root_path, package_pathspec: @package_paths)
|
|
97
|
+
end
|
|
98
|
+
|
|
93
99
|
private
|
|
94
100
|
|
|
95
101
|
sig { returns(FileProcessor) }
|
|
@@ -123,11 +129,6 @@ module Packwerk
|
|
|
123
129
|
)
|
|
124
130
|
end
|
|
125
131
|
|
|
126
|
-
sig { returns(PackageSet) }
|
|
127
|
-
def package_set
|
|
128
|
-
::Packwerk::PackageSet.load_all_from(@root_path, package_pathspec: @package_paths)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
132
|
sig { returns(T::Array[ConstantNameInspector]) }
|
|
132
133
|
def constant_name_inspectors
|
|
133
134
|
[
|
data/lib/packwerk/version.rb
CHANGED
data/lib/packwerk.rb
CHANGED
data/packwerk.gemspec
CHANGED
|
@@ -36,23 +36,16 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.files = Dir.chdir(__dir__) do
|
|
37
37
|
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features|static)/}) }
|
|
38
38
|
end
|
|
39
|
-
spec.require_paths =
|
|
39
|
+
spec.require_paths = ["lib"]
|
|
40
40
|
|
|
41
41
|
spec.required_ruby_version = ">= 2.6"
|
|
42
42
|
|
|
43
43
|
spec.add_dependency("activesupport", ">= 5.2")
|
|
44
|
-
spec.add_dependency("constant_resolver", ">=0.2.0")
|
|
45
|
-
spec.add_dependency("parallel")
|
|
46
|
-
spec.add_dependency("sorbet-runtime", ">=0.5.9914")
|
|
47
44
|
spec.add_dependency("bundler")
|
|
48
|
-
spec.add_dependency("
|
|
49
|
-
|
|
50
|
-
spec.
|
|
51
|
-
spec.
|
|
52
|
-
spec.add_development_dependency("m")
|
|
53
|
-
# https://github.com/ruby/psych/pull/487
|
|
54
|
-
spec.add_development_dependency("psych", "~> 3")
|
|
55
|
-
spec.add_development_dependency("zeitwerk")
|
|
45
|
+
spec.add_dependency("constant_resolver", ">= 0.2.0")
|
|
46
|
+
spec.add_dependency("parallel")
|
|
47
|
+
spec.add_dependency("sorbet-runtime", ">= 0.5.9914")
|
|
48
|
+
spec.add_dependency("zeitwerk", ">= 2.6.1")
|
|
56
49
|
|
|
57
50
|
# For Ruby parsing
|
|
58
51
|
spec.add_dependency("ast")
|