packwerk 1.1.0 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +14 -5
- data/.ruby-version +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +129 -111
- data/README.md +8 -1
- data/USAGE.md +17 -16
- data/dev.yml +1 -1
- data/exe/packwerk +1 -1
- data/gemfiles/Gemfile-rails-6-0 +22 -0
- data/lib/packwerk/application_load_paths.rb +3 -2
- data/lib/packwerk/application_validator.rb +83 -67
- data/lib/packwerk/association_inspector.rb +23 -11
- data/lib/packwerk/checker.rb +4 -7
- data/lib/packwerk/cli.rb +32 -100
- data/lib/packwerk/configuration.rb +10 -2
- data/lib/packwerk/const_node_inspector.rb +13 -14
- data/lib/packwerk/constant_discovery.rb +2 -0
- data/lib/packwerk/constant_name_inspector.rb +0 -1
- data/lib/packwerk/dependency_checker.rb +12 -17
- data/lib/packwerk/deprecated_references.rb +7 -9
- data/lib/packwerk/file_processor.rb +0 -4
- data/lib/packwerk/formatters/offenses_formatter.rb +43 -0
- data/lib/packwerk/formatters/progress_formatter.rb +9 -4
- data/lib/packwerk/generators/configuration_file.rb +0 -1
- data/lib/packwerk/inflector.rb +0 -2
- data/lib/packwerk/node.rb +9 -2
- data/lib/packwerk/node_processor.rb +15 -32
- data/lib/packwerk/node_processor_factory.rb +0 -5
- data/lib/packwerk/node_visitor.rb +1 -4
- data/lib/packwerk/offense.rb +2 -8
- data/lib/packwerk/offense_collection.rb +84 -0
- data/lib/packwerk/offenses_formatter.rb +15 -0
- data/lib/packwerk/output_style.rb +20 -0
- data/lib/packwerk/output_styles/coloured.rb +29 -0
- data/lib/packwerk/output_styles/plain.rb +26 -0
- data/lib/packwerk/package.rb +8 -0
- data/lib/packwerk/package_set.rb +2 -3
- data/lib/packwerk/parse_run.rb +104 -0
- data/lib/packwerk/parsed_constant_definitions.rb +2 -4
- data/lib/packwerk/parsers/erb.rb +0 -2
- data/lib/packwerk/parsers/factory.rb +1 -3
- data/lib/packwerk/parsers.rb +0 -2
- data/lib/packwerk/privacy_checker.rb +22 -17
- data/lib/packwerk/reference_extractor.rb +0 -8
- data/lib/packwerk/reference_offense.rb +49 -0
- data/lib/packwerk/result.rb +9 -0
- data/lib/packwerk/run_context.rb +4 -21
- data/lib/packwerk/sanity_checker.rb +1 -3
- data/lib/packwerk/spring_command.rb +1 -1
- data/lib/packwerk/version.rb +1 -1
- data/lib/packwerk/violation_type.rb +0 -2
- data/lib/packwerk.rb +73 -34
- data/library.yml +1 -1
- data/packwerk.gemspec +1 -0
- data/service.yml +1 -4
- data/shipit.rubygems.yml +5 -1
- data/sorbet/rbi/gems/{actioncable@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actioncable@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +56 -36
- data/sorbet/rbi/gems/{actionmailbox@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionmailbox@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +25 -28
- data/sorbet/rbi/gems/{actionmailer@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionmailer@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +43 -24
- data/sorbet/rbi/gems/{actionpack@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionpack@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +382 -284
- data/sorbet/rbi/gems/{actiontext@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actiontext@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +76 -40
- data/sorbet/rbi/gems/{actionview@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → actionview@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +206 -195
- data/sorbet/rbi/gems/{activejob@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activejob@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +64 -75
- data/sorbet/rbi/gems/{activemodel@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activemodel@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +103 -56
- data/sorbet/rbi/gems/{activerecord@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activerecord@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +1250 -898
- data/sorbet/rbi/gems/{activestorage@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activestorage@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +92 -120
- data/sorbet/rbi/gems/{activesupport@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → activesupport@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +292 -193
- data/sorbet/rbi/gems/{ast@2.4.1.rbi → ast@2.4.2.rbi} +2 -1
- data/sorbet/rbi/gems/{better_html@1.0.15.rbi → better_html@1.0.16.rbi} +2 -2
- data/sorbet/rbi/gems/{concurrent-ruby@1.1.6.rbi → concurrent-ruby@1.1.8.rbi} +12 -9
- data/sorbet/rbi/gems/{erubi@1.9.0.rbi → erubi@1.10.0.rbi} +3 -1
- data/sorbet/rbi/gems/{i18n@1.8.2.rbi → i18n@1.8.10.rbi} +19 -52
- data/sorbet/rbi/gems/{loofah@2.5.0.rbi → loofah@2.9.0.rbi} +3 -1
- data/sorbet/rbi/gems/marcel@1.0.0.rbi +70 -0
- data/sorbet/rbi/gems/{mini_mime@1.0.2.rbi → mini_mime@1.0.3.rbi} +6 -6
- data/sorbet/rbi/gems/{mini_portile2@2.4.0.rbi → minitest-focus@1.2.1.rbi} +2 -2
- data/sorbet/rbi/gems/{minitest@5.14.0.rbi → minitest@5.14.4.rbi} +31 -29
- data/sorbet/rbi/gems/{mocha@1.11.2.rbi → mocha@1.12.0.rbi} +25 -36
- data/sorbet/rbi/gems/{nio4r@2.5.2.rbi → nio4r@2.5.7.rbi} +21 -20
- data/sorbet/rbi/gems/{nokogiri@1.10.9.rbi → nokogiri@1.11.2.rbi} +193 -154
- data/sorbet/rbi/gems/parallel@1.20.1.rbi +117 -0
- data/sorbet/rbi/gems/parlour@6.0.0.rbi +1272 -0
- data/sorbet/rbi/gems/{parser@2.7.1.4.rbi → parser@3.0.0.0.rbi} +287 -174
- data/sorbet/rbi/gems/{pry@0.13.1.rbi → pry@0.14.0.rbi} +1 -1
- data/sorbet/rbi/gems/racc@1.5.2.rbi +57 -0
- data/sorbet/rbi/gems/{rack@2.2.2.rbi → rack@2.2.3.rbi} +23 -35
- data/sorbet/rbi/gems/{rails@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → rails@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +1 -1
- data/sorbet/rbi/gems/{railties@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi → railties@7.0.0.alpha-d612542336d9a61381311c95a27d801bb4094779.rbi} +132 -121
- data/sorbet/rbi/gems/{rake@13.0.1.rbi → rake@13.0.3.rbi} +16 -20
- data/sorbet/rbi/gems/{parallel@1.19.1.rbi → regexp_parser@2.1.1.rbi} +2 -2
- data/sorbet/rbi/gems/rubocop-ast@1.4.1.rbi +8 -0
- data/sorbet/rbi/gems/{rubocop-performance@1.5.2.rbi → rubocop-performance@1.10.2.rbi} +1 -1
- data/sorbet/rbi/gems/{rubocop-shopify@1.0.2.rbi → rubocop-shopify@2.0.1.rbi} +1 -1
- data/sorbet/rbi/gems/{rubocop-sorbet@0.3.7.rbi → rubocop-sorbet@0.6.1.rbi} +1 -1
- data/sorbet/rbi/gems/{rubocop@0.82.0.rbi → rubocop@1.12.0.rbi} +1 -1
- data/sorbet/rbi/gems/{ruby-progressbar@1.10.1.rbi → ruby-progressbar@1.11.0.rbi} +1 -1
- data/sorbet/rbi/gems/spoom@1.1.0.rbi +1061 -0
- data/sorbet/rbi/gems/{spring@2.1.0.rbi → spring@2.1.1.rbi} +7 -7
- data/sorbet/rbi/gems/{sprockets-rails@3.2.1.rbi → sprockets-rails@3.2.2.rbi} +88 -68
- data/sorbet/rbi/gems/{sprockets@4.0.0.rbi → sprockets@4.0.2.rbi} +8 -7
- data/sorbet/rbi/gems/{tapioca@0.4.5.rbi → tapioca@0.4.19.rbi} +109 -24
- data/sorbet/rbi/gems/{thor@1.0.1.rbi → thor@1.1.0.rbi} +16 -15
- data/sorbet/rbi/gems/{tzinfo@2.0.2.rbi → tzinfo@2.0.4.rbi} +21 -2
- data/sorbet/rbi/gems/{unicode-display_width@1.7.0.rbi → unicode-display_width@2.0.0.rbi} +1 -1
- data/sorbet/rbi/gems/{websocket-driver@0.7.1.rbi → websocket-driver@0.7.3.rbi} +29 -29
- data/sorbet/rbi/gems/{websocket-extensions@0.1.4.rbi → websocket-extensions@0.1.5.rbi} +2 -2
- data/sorbet/rbi/gems/zeitwerk@2.4.2.rbi +177 -0
- data/sorbet/tapioca/require.rb +1 -0
- metadata +78 -61
- data/lib/packwerk/cache_deprecated_references.rb +0 -47
- data/lib/packwerk/checking_deprecated_references.rb +0 -40
- data/lib/packwerk/commands/detect_stale_violations_command.rb +0 -63
- data/lib/packwerk/commands/offense_progress_marker.rb +0 -24
- data/lib/packwerk/detect_stale_deprecated_references.rb +0 -14
- data/lib/packwerk/output_styles.rb +0 -41
- data/lib/packwerk/reference_lister.rb +0 -23
- data/lib/packwerk/updating_deprecated_references.rb +0 -14
- data/sorbet/rbi/gems/jaro_winkler@1.5.4.rbi +0 -8
- data/sorbet/rbi/gems/marcel@0.3.3.rbi +0 -30
- data/sorbet/rbi/gems/mimemagic@0.3.5.rbi +0 -47
- data/sorbet/rbi/gems/parlour@4.0.1.rbi +0 -561
- data/sorbet/rbi/gems/spoom@1.0.4.rbi +0 -418
- data/sorbet/rbi/gems/zeitwerk@2.3.0.rbi +0 -8
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "sorbet-runtime"
|
|
5
4
|
require "yaml"
|
|
6
|
-
require "sorbet-runtime"
|
|
7
|
-
|
|
8
|
-
require "packwerk/reference"
|
|
9
|
-
require "packwerk/reference_lister"
|
|
10
|
-
require "packwerk/violation_type"
|
|
11
5
|
|
|
12
6
|
module Packwerk
|
|
13
7
|
class DeprecatedReferences
|
|
14
8
|
extend T::Sig
|
|
15
|
-
include ReferenceLister
|
|
16
9
|
|
|
10
|
+
sig { params(package: Packwerk::Package, filepath: String).void }
|
|
17
11
|
def initialize(package, filepath)
|
|
18
12
|
@package = package
|
|
19
13
|
@filepath = filepath
|
|
@@ -23,7 +17,6 @@ module Packwerk
|
|
|
23
17
|
sig do
|
|
24
18
|
params(reference: Packwerk::Reference, violation_type: ViolationType)
|
|
25
19
|
.returns(T::Boolean)
|
|
26
|
-
.override
|
|
27
20
|
end
|
|
28
21
|
def listed?(reference, violation_type:)
|
|
29
22
|
violated_constants_found = deprecated_references.dig(reference.constant.package.name, reference.constant.name)
|
|
@@ -35,17 +28,19 @@ module Packwerk
|
|
|
35
28
|
violated_constants_found.fetch("violations", []).include?(violation_type.serialize)
|
|
36
29
|
end
|
|
37
30
|
|
|
31
|
+
sig { params(reference: Packwerk::Reference, violation_type: Packwerk::ViolationType).returns(T::Boolean) }
|
|
38
32
|
def add_entries(reference, violation_type)
|
|
39
33
|
package_violations = @new_entries.fetch(reference.constant.package.name, {})
|
|
40
34
|
entries_for_file = package_violations[reference.constant.name] ||= {}
|
|
41
35
|
|
|
42
36
|
entries_for_file["violations"] ||= []
|
|
43
|
-
entries_for_file["violations"] << violation_type
|
|
37
|
+
entries_for_file["violations"] << violation_type.serialize
|
|
44
38
|
|
|
45
39
|
entries_for_file["files"] ||= []
|
|
46
40
|
entries_for_file["files"] << reference.relative_path.to_s
|
|
47
41
|
|
|
48
42
|
@new_entries[reference.constant.package.name] = package_violations
|
|
43
|
+
listed?(reference, violation_type: violation_type)
|
|
49
44
|
end
|
|
50
45
|
|
|
51
46
|
sig { returns(T::Boolean) }
|
|
@@ -66,6 +61,7 @@ module Packwerk
|
|
|
66
61
|
end
|
|
67
62
|
end
|
|
68
63
|
|
|
64
|
+
sig { void }
|
|
69
65
|
def dump
|
|
70
66
|
if @new_entries.empty?
|
|
71
67
|
File.delete(@filepath) if File.exist?(@filepath)
|
|
@@ -88,6 +84,7 @@ module Packwerk
|
|
|
88
84
|
|
|
89
85
|
private
|
|
90
86
|
|
|
87
|
+
sig { returns(Hash) }
|
|
91
88
|
def prepare_entries_for_dump
|
|
92
89
|
@new_entries.each do |package_name, package_violations|
|
|
93
90
|
package_violations.each do |_, entries_for_file|
|
|
@@ -100,6 +97,7 @@ module Packwerk
|
|
|
100
97
|
@new_entries = @new_entries.sort.to_h
|
|
101
98
|
end
|
|
102
99
|
|
|
100
|
+
sig { returns(Hash) }
|
|
103
101
|
def deprecated_references
|
|
104
102
|
@deprecated_references ||= if File.exist?(@filepath)
|
|
105
103
|
YAML.load_file(@filepath) || {}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Packwerk
|
|
5
|
+
module Formatters
|
|
6
|
+
class OffensesFormatter
|
|
7
|
+
include Packwerk::OffensesFormatter
|
|
8
|
+
|
|
9
|
+
extend T::Sig
|
|
10
|
+
|
|
11
|
+
sig { params(style: OutputStyle).void }
|
|
12
|
+
def initialize(style: OutputStyles::Plain.new)
|
|
13
|
+
@style = style
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
sig { override.params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
|
|
17
|
+
def show_offenses(offenses)
|
|
18
|
+
return "No offenses detected 🎉" if offenses.empty?
|
|
19
|
+
|
|
20
|
+
<<~EOS
|
|
21
|
+
#{offenses_list(offenses)}
|
|
22
|
+
#{offenses_summary(offenses)}
|
|
23
|
+
EOS
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
sig { params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
|
|
29
|
+
def offenses_list(offenses)
|
|
30
|
+
offenses
|
|
31
|
+
.compact
|
|
32
|
+
.map { |offense| offense.to_s(@style) }
|
|
33
|
+
.join("\n")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
sig { params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
|
|
37
|
+
def offenses_summary(offenses)
|
|
38
|
+
offenses_string = Inflector.default.pluralize("offense", offenses.length)
|
|
39
|
+
"#{offenses.length} #{offenses_string} detected"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
require "benchmark"
|
|
5
5
|
|
|
6
|
-
require "packwerk/inflector"
|
|
7
|
-
require "packwerk/output_styles"
|
|
8
|
-
|
|
9
6
|
module Packwerk
|
|
10
7
|
module Formatters
|
|
11
8
|
class ProgressFormatter
|
|
12
|
-
|
|
9
|
+
extend T::Sig
|
|
10
|
+
|
|
11
|
+
sig { params(out: T.any(StringIO, IO), style: OutputStyle).void }
|
|
12
|
+
def initialize(out, style: OutputStyles::Plain.new)
|
|
13
13
|
@out = out
|
|
14
14
|
@style = style
|
|
15
15
|
end
|
|
@@ -41,6 +41,11 @@ module Packwerk
|
|
|
41
41
|
@out.puts
|
|
42
42
|
@out.puts("📦 Finished in #{execution_time.round(2)} seconds")
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
def interrupted
|
|
46
|
+
@out.puts
|
|
47
|
+
@out.puts("Manually interrupted. Violations caught so far are listed below:")
|
|
48
|
+
end
|
|
44
49
|
end
|
|
45
50
|
end
|
|
46
51
|
end
|
data/lib/packwerk/inflector.rb
CHANGED
data/lib/packwerk/node.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require "parser"
|
|
4
5
|
require "parser/ast/node"
|
|
5
6
|
|
|
6
7
|
module Packwerk
|
|
@@ -9,6 +10,8 @@ module Packwerk
|
|
|
9
10
|
Location = Struct.new(:line, :column)
|
|
10
11
|
|
|
11
12
|
class << self
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
12
15
|
def class_or_module_name(class_or_module_node)
|
|
13
16
|
case type_of(class_or_module_node)
|
|
14
17
|
when CLASS, MODULE
|
|
@@ -27,7 +30,7 @@ module Packwerk
|
|
|
27
30
|
case type_of(constant_node)
|
|
28
31
|
when CONSTANT_ROOT_NAMESPACE
|
|
29
32
|
""
|
|
30
|
-
when CONSTANT, CONSTANT_ASSIGNMENT
|
|
33
|
+
when CONSTANT, CONSTANT_ASSIGNMENT, SELF
|
|
31
34
|
# (const nil :Foo)
|
|
32
35
|
# "Foo"
|
|
33
36
|
# (const (cbase) :Foo)
|
|
@@ -40,6 +43,8 @@ module Packwerk
|
|
|
40
43
|
# "::Foo = 1"
|
|
41
44
|
# (casgn (lvar :a) :Foo (int 1))
|
|
42
45
|
# "a::Foo = 1"
|
|
46
|
+
# (casgn (self) :Foo (int 1))
|
|
47
|
+
# "self::Foo = 1"
|
|
43
48
|
namespace, name = constant_node.children
|
|
44
49
|
if namespace
|
|
45
50
|
[constant_name(namespace), name].join("::")
|
|
@@ -176,6 +181,7 @@ module Packwerk
|
|
|
176
181
|
class_node.children[1]
|
|
177
182
|
end
|
|
178
183
|
|
|
184
|
+
sig { params(ancestors: T::Array[AST::Node]).returns(String) }
|
|
179
185
|
def parent_module_name(ancestors:)
|
|
180
186
|
definitions = ancestors
|
|
181
187
|
.select { |n| [CLASS, MODULE, CONSTANT_ASSIGNMENT, BLOCK].include?(type_of(n)) }
|
|
@@ -204,12 +210,13 @@ module Packwerk
|
|
|
204
210
|
HASH_PAIR = :pair
|
|
205
211
|
METHOD_CALL = :send
|
|
206
212
|
MODULE = :module
|
|
213
|
+
SELF = :self
|
|
207
214
|
STRING = :str
|
|
208
215
|
SYMBOL = :sym
|
|
209
216
|
|
|
210
217
|
private_constant(
|
|
211
218
|
:BLOCK, :CLASS, :CONSTANT, :CONSTANT_ASSIGNMENT, :CONSTANT_ROOT_NAMESPACE, :HASH, :HASH_PAIR, :METHOD_CALL,
|
|
212
|
-
:MODULE, :STRING, :SYMBOL,
|
|
219
|
+
:MODULE, :SELF, :STRING, :SYMBOL,
|
|
213
220
|
)
|
|
214
221
|
|
|
215
222
|
def type_of(node)
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "packwerk/node"
|
|
5
|
-
require "packwerk/offense"
|
|
6
|
-
require "packwerk/checker"
|
|
7
|
-
require "packwerk/reference_lister"
|
|
8
|
-
|
|
9
4
|
module Packwerk
|
|
10
5
|
class NodeProcessor
|
|
11
6
|
extend T::Sig
|
|
@@ -13,48 +8,36 @@ module Packwerk
|
|
|
13
8
|
sig do
|
|
14
9
|
params(
|
|
15
10
|
reference_extractor: ReferenceExtractor,
|
|
16
|
-
reference_lister: ReferenceLister,
|
|
17
11
|
filename: String,
|
|
18
12
|
checkers: T::Array[Checker]
|
|
19
13
|
).void
|
|
20
14
|
end
|
|
21
|
-
def initialize(reference_extractor:,
|
|
15
|
+
def initialize(reference_extractor:, filename:, checkers:)
|
|
22
16
|
@reference_extractor = reference_extractor
|
|
23
|
-
@reference_lister = reference_lister
|
|
24
17
|
@filename = filename
|
|
25
18
|
@checkers = checkers
|
|
26
19
|
end
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
sig { params(node: Parser::AST::Node, ancestors: T::Array[Parser::AST::Node]).returns(T::Array[Offense]) }
|
|
22
|
+
def call(node, ancestors)
|
|
23
|
+
return [] unless Node.method_call?(node) || Node.constant?(node)
|
|
24
|
+
reference = @reference_extractor.reference_from_node(node, ancestors: ancestors, file_path: @filename)
|
|
25
|
+
check_reference(reference, node)
|
|
33
26
|
end
|
|
34
27
|
|
|
35
28
|
private
|
|
36
29
|
|
|
37
30
|
def check_reference(reference, node)
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Inference details: this is a reference to #{constant.name} which seems to be defined in #{constant.location}.
|
|
48
|
-
To receive help interpreting or resolving this error message, see: https://github.com/Shopify/packwerk/blob/main/TROUBLESHOOT.md#Troubleshooting-violations
|
|
49
|
-
EOS
|
|
50
|
-
)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def failed_check(reference)
|
|
54
|
-
failing_checker = @checkers.find do |checker|
|
|
55
|
-
checker.invalid_reference?(reference, @reference_lister)
|
|
31
|
+
return [] unless reference
|
|
32
|
+
@checkers.each_with_object([]) do |checker, violations|
|
|
33
|
+
next unless checker.invalid_reference?(reference)
|
|
34
|
+
offense = Packwerk::ReferenceOffense.new(
|
|
35
|
+
location: Node.location(node),
|
|
36
|
+
reference: reference,
|
|
37
|
+
violation_type: checker.violation_type
|
|
38
|
+
)
|
|
39
|
+
violations << offense
|
|
56
40
|
end
|
|
57
|
-
failing_checker&.message_for(reference)
|
|
58
41
|
end
|
|
59
42
|
end
|
|
60
43
|
end
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "packwerk/constant_name_inspector"
|
|
5
|
-
require "packwerk/checker"
|
|
6
|
-
|
|
7
4
|
module Packwerk
|
|
8
5
|
class NodeProcessorFactory < T::Struct
|
|
9
6
|
extend T::Sig
|
|
10
7
|
|
|
11
8
|
const :root_path, String
|
|
12
|
-
const :reference_lister, ReferenceLister
|
|
13
9
|
const :context_provider, Packwerk::ConstantDiscovery
|
|
14
10
|
const :constant_name_inspectors, T::Array[ConstantNameInspector]
|
|
15
11
|
const :checkers, T::Array[Checker]
|
|
@@ -18,7 +14,6 @@ module Packwerk
|
|
|
18
14
|
def for(filename:, node:)
|
|
19
15
|
::Packwerk::NodeProcessor.new(
|
|
20
16
|
reference_extractor: reference_extractor(node: node),
|
|
21
|
-
reference_lister: reference_lister,
|
|
22
17
|
filename: filename,
|
|
23
18
|
checkers: checkers,
|
|
24
19
|
)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# typed: false
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "packwerk/node"
|
|
5
|
-
|
|
6
4
|
module Packwerk
|
|
7
5
|
class NodeVisitor
|
|
8
6
|
def initialize(node_processor:)
|
|
@@ -10,8 +8,7 @@ module Packwerk
|
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def visit(node, ancestors:, result:)
|
|
13
|
-
|
|
14
|
-
result << offense if offense
|
|
11
|
+
result.concat(@node_processor.call(node, ancestors))
|
|
15
12
|
|
|
16
13
|
child_ancestors = [node] + ancestors
|
|
17
14
|
Node.each_child(node) do |child|
|
data/lib/packwerk/offense.rb
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "parser/source/map"
|
|
5
|
-
require "sorbet-runtime"
|
|
6
|
-
|
|
7
|
-
require "packwerk/output_styles"
|
|
8
5
|
|
|
9
6
|
module Packwerk
|
|
10
7
|
class Offense
|
|
@@ -23,11 +20,8 @@ module Packwerk
|
|
|
23
20
|
@message = message
|
|
24
21
|
end
|
|
25
22
|
|
|
26
|
-
sig
|
|
27
|
-
|
|
28
|
-
.returns(String)
|
|
29
|
-
end
|
|
30
|
-
def to_s(style = OutputStyles::Plain)
|
|
23
|
+
sig { params(style: OutputStyle).returns(String) }
|
|
24
|
+
def to_s(style = OutputStyles::Plain.new)
|
|
31
25
|
if location
|
|
32
26
|
<<~EOS
|
|
33
27
|
#{style.filename}#{file}#{style.reset}:#{location.line}:#{location.column}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Packwerk
|
|
5
|
+
class OffenseCollection
|
|
6
|
+
extend T::Sig
|
|
7
|
+
extend T::Helpers
|
|
8
|
+
|
|
9
|
+
sig do
|
|
10
|
+
params(
|
|
11
|
+
root_path: String,
|
|
12
|
+
deprecated_references: T::Hash[Packwerk::Package, Packwerk::DeprecatedReferences]
|
|
13
|
+
).void
|
|
14
|
+
end
|
|
15
|
+
def initialize(root_path, deprecated_references = {})
|
|
16
|
+
@root_path = root_path
|
|
17
|
+
@deprecated_references = T.let(deprecated_references, T::Hash[Packwerk::Package, Packwerk::DeprecatedReferences])
|
|
18
|
+
@new_violations = T.let([], T::Array[Packwerk::ReferenceOffense])
|
|
19
|
+
@errors = T.let([], T::Array[Packwerk::Offense])
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
sig { returns(T::Array[Packwerk::ReferenceOffense]) }
|
|
23
|
+
attr_reader :new_violations
|
|
24
|
+
|
|
25
|
+
sig { returns(T::Array[Packwerk::Offense]) }
|
|
26
|
+
attr_reader :errors
|
|
27
|
+
|
|
28
|
+
sig do
|
|
29
|
+
params(offense: Packwerk::Offense)
|
|
30
|
+
.returns(T::Boolean)
|
|
31
|
+
end
|
|
32
|
+
def listed?(offense)
|
|
33
|
+
return false unless offense.is_a?(ReferenceOffense)
|
|
34
|
+
reference = offense.reference
|
|
35
|
+
deprecated_references_for(reference.source_package).listed?(reference, violation_type: offense.violation_type)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
sig do
|
|
39
|
+
params(offense: Packwerk::Offense).void
|
|
40
|
+
end
|
|
41
|
+
def add_offense(offense)
|
|
42
|
+
unless offense.is_a?(ReferenceOffense)
|
|
43
|
+
@errors << offense
|
|
44
|
+
return
|
|
45
|
+
end
|
|
46
|
+
deprecated_references = deprecated_references_for(offense.reference.source_package)
|
|
47
|
+
unless deprecated_references.add_entries(offense.reference, offense.violation_type)
|
|
48
|
+
new_violations << offense
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
sig { returns(T::Boolean) }
|
|
53
|
+
def stale_violations?
|
|
54
|
+
@deprecated_references.values.any?(&:stale_violations?)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
sig { void }
|
|
58
|
+
def dump_deprecated_references_files
|
|
59
|
+
@deprecated_references.each do |_, deprecated_references_file|
|
|
60
|
+
deprecated_references_file.dump
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
sig { returns(T::Array[Packwerk::Offense]) }
|
|
65
|
+
def outstanding_offenses
|
|
66
|
+
errors + new_violations
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
sig { params(package: Packwerk::Package).returns(Packwerk::DeprecatedReferences) }
|
|
72
|
+
def deprecated_references_for(package)
|
|
73
|
+
@deprecated_references[package] ||= Packwerk::DeprecatedReferences.new(
|
|
74
|
+
package,
|
|
75
|
+
deprecated_references_file_for(package),
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
sig { params(package: Packwerk::Package).returns(String) }
|
|
80
|
+
def deprecated_references_file_for(package)
|
|
81
|
+
File.join(@root_path, package.name, "deprecated_references.yml")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Packwerk
|
|
5
|
+
module OffensesFormatter
|
|
6
|
+
extend T::Sig
|
|
7
|
+
extend T::Helpers
|
|
8
|
+
|
|
9
|
+
interface!
|
|
10
|
+
|
|
11
|
+
sig { abstract.params(offenses: T::Array[T.nilable(Offense)]).returns(String) }
|
|
12
|
+
def show_offenses(offenses)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Packwerk
|
|
5
|
+
module OutputStyle
|
|
6
|
+
extend T::Sig
|
|
7
|
+
extend T::Helpers
|
|
8
|
+
|
|
9
|
+
interface!
|
|
10
|
+
|
|
11
|
+
sig { abstract.returns(String) }
|
|
12
|
+
def reset; end
|
|
13
|
+
|
|
14
|
+
sig { abstract.returns(String) }
|
|
15
|
+
def filename; end
|
|
16
|
+
|
|
17
|
+
sig { abstract.returns(String) }
|
|
18
|
+
def error; end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Packwerk
|
|
5
|
+
module OutputStyles
|
|
6
|
+
# See https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit for ANSI escape colour codes
|
|
7
|
+
class Coloured
|
|
8
|
+
extend T::Sig
|
|
9
|
+
include OutputStyle
|
|
10
|
+
|
|
11
|
+
sig { override.returns(String) }
|
|
12
|
+
def reset
|
|
13
|
+
"\033[m"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
sig { override.returns(String) }
|
|
17
|
+
def filename
|
|
18
|
+
# 36 is foreground cyan
|
|
19
|
+
"\033[36m"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
sig { override.returns(String) }
|
|
23
|
+
def error
|
|
24
|
+
# 31 is foreground red
|
|
25
|
+
"\033[31m"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -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
|
data/lib/packwerk/package.rb
CHANGED
data/lib/packwerk/package_set.rb
CHANGED
|
@@ -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
|
|
@@ -60,7 +58,8 @@ module Packwerk
|
|
|
60
58
|
end
|
|
61
59
|
|
|
62
60
|
def package_from_path(file_path)
|
|
63
|
-
|
|
61
|
+
path_string = file_path.to_s
|
|
62
|
+
@packages.values.find { |package| package.package_path?(path_string) }
|
|
64
63
|
end
|
|
65
64
|
end
|
|
66
65
|
end
|