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.
- 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 +39 -17
- data/dev.yml +1 -1
- data/exe/packwerk +1 -1
- data/gemfiles/Gemfile-rails-6-0 +22 -0
- data/lib/packwerk.rb +73 -34
- data/lib/packwerk/application_load_paths.rb +3 -2
- data/lib/packwerk/application_validator.rb +85 -69
- data/lib/packwerk/association_inspector.rb +23 -11
- data/lib/packwerk/checker.rb +4 -7
- data/lib/packwerk/cli.rb +36 -93
- 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 +25 -8
- 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 +8 -5
- data/lib/packwerk/parse_run.rb +104 -0
- data/lib/packwerk/parsed_constant_definitions.rb +2 -4
- data/lib/packwerk/parsers.rb +0 -2
- data/lib/packwerk/parsers/erb.rb +4 -2
- data/lib/packwerk/parsers/factory.rb +10 -3
- 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 -20
- 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/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 -57
- data/lib/packwerk/checking_deprecated_references.rb +0 -40
- data/lib/packwerk/output_styles.rb +0 -41
- data/lib/packwerk/reference_lister.rb +0 -23
- data/lib/packwerk/updating_deprecated_references.rb +0 -51
- 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
data/dev.yml
CHANGED
data/exe/packwerk
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source("https://rubygems.org")
|
4
|
+
|
5
|
+
gemspec path: ".."
|
6
|
+
|
7
|
+
# Specify the same dependency sources as the application Gemfile
|
8
|
+
|
9
|
+
gem("spring")
|
10
|
+
gem("rails", '~> 6.0.0')
|
11
|
+
gem("constant_resolver", require: false)
|
12
|
+
gem("sorbet-runtime", require: false)
|
13
|
+
gem("rubocop-performance", require: false)
|
14
|
+
gem("rubocop-sorbet", require: false)
|
15
|
+
gem("mocha", require: false)
|
16
|
+
gem("rubocop-shopify", require: false)
|
17
|
+
gem("tapioca", require: false)
|
18
|
+
|
19
|
+
group :development do
|
20
|
+
gem("byebug", require: false)
|
21
|
+
gem("minitest-focus", require: false)
|
22
|
+
end
|
data/lib/packwerk.rb
CHANGED
@@ -3,40 +3,79 @@
|
|
3
3
|
|
4
4
|
require "sorbet-runtime"
|
5
5
|
require "active_support"
|
6
|
-
require "
|
7
|
-
|
8
|
-
require "packwerk/offense"
|
9
|
-
|
10
|
-
require "packwerk/application_validator"
|
11
|
-
require "packwerk/association_inspector"
|
12
|
-
require "packwerk/checking_deprecated_references"
|
13
|
-
require "packwerk/cli"
|
14
|
-
require "packwerk/configuration"
|
15
|
-
require "packwerk/const_node_inspector"
|
16
|
-
require "packwerk/constant_discovery"
|
17
|
-
require "packwerk/dependency_checker"
|
18
|
-
require "packwerk/deprecated_references"
|
19
|
-
require "packwerk/files_for_processing"
|
20
|
-
require "packwerk/file_processor"
|
21
|
-
require "packwerk/formatters/progress_formatter"
|
22
|
-
require "packwerk/generators/application_validation"
|
23
|
-
require "packwerk/generators/configuration_file"
|
24
|
-
require "packwerk/generators/inflections_file"
|
25
|
-
require "packwerk/generators/root_package"
|
26
|
-
require "packwerk/graph"
|
27
|
-
require "packwerk/inflector"
|
28
|
-
require "packwerk/node_processor"
|
29
|
-
require "packwerk/node_visitor"
|
30
|
-
require "packwerk/output_styles"
|
31
|
-
require "packwerk/package"
|
32
|
-
require "packwerk/package_set"
|
33
|
-
require "packwerk/parsers"
|
34
|
-
require "packwerk/privacy_checker"
|
35
|
-
require "packwerk/reference_extractor"
|
36
|
-
require "packwerk/run_context"
|
37
|
-
require "packwerk/updating_deprecated_references"
|
38
|
-
require "packwerk/version"
|
39
|
-
require "packwerk/violation_type"
|
6
|
+
require "fileutils"
|
40
7
|
|
41
8
|
module Packwerk
|
9
|
+
extend ActiveSupport::Autoload
|
10
|
+
|
11
|
+
autoload :ApplicationLoadPaths
|
12
|
+
autoload :ApplicationValidator
|
13
|
+
autoload :AssociationInspector
|
14
|
+
autoload :OffenseCollection
|
15
|
+
autoload :Checker
|
16
|
+
autoload :Cli
|
17
|
+
autoload :Configuration
|
18
|
+
autoload :ConstantDiscovery
|
19
|
+
autoload :ConstantNameInspector
|
20
|
+
autoload :ConstNodeInspector
|
21
|
+
autoload :DependencyChecker
|
22
|
+
autoload :DeprecatedReferences
|
23
|
+
autoload :FileProcessor
|
24
|
+
autoload :FilesForProcessing
|
25
|
+
autoload :Graph
|
26
|
+
autoload :Inflector
|
27
|
+
autoload :Node
|
28
|
+
autoload :NodeProcessor
|
29
|
+
autoload :NodeProcessorFactory
|
30
|
+
autoload :NodeVisitor
|
31
|
+
autoload :Offense
|
32
|
+
autoload :OffensesFormatter
|
33
|
+
autoload :OutputStyle
|
34
|
+
autoload :Package
|
35
|
+
autoload :PackageSet
|
36
|
+
autoload :ParsedConstantDefinitions
|
37
|
+
autoload :Parsers
|
38
|
+
autoload :ParseRun
|
39
|
+
autoload :PrivacyChecker
|
40
|
+
autoload :Reference
|
41
|
+
autoload :ReferenceExtractor
|
42
|
+
autoload :ReferenceOffense
|
43
|
+
autoload :Result
|
44
|
+
autoload :RunContext
|
45
|
+
autoload :Version
|
46
|
+
autoload :ViolationType
|
47
|
+
|
48
|
+
module Inflections
|
49
|
+
extend ActiveSupport::Autoload
|
50
|
+
|
51
|
+
autoload :Custom
|
52
|
+
autoload :Default
|
53
|
+
end
|
54
|
+
|
55
|
+
module OutputStyles
|
56
|
+
extend ActiveSupport::Autoload
|
57
|
+
|
58
|
+
autoload :Coloured
|
59
|
+
autoload :Plain
|
60
|
+
end
|
61
|
+
|
62
|
+
autoload_under "commands" do
|
63
|
+
autoload :OffenseProgressMarker
|
64
|
+
end
|
65
|
+
|
66
|
+
module Formatters
|
67
|
+
extend ActiveSupport::Autoload
|
68
|
+
|
69
|
+
autoload :OffensesFormatter
|
70
|
+
autoload :ProgressFormatter
|
71
|
+
end
|
72
|
+
|
73
|
+
module Generators
|
74
|
+
extend ActiveSupport::Autoload
|
75
|
+
|
76
|
+
autoload :ApplicationValidation
|
77
|
+
autoload :ConfigurationFile
|
78
|
+
autoload :InflectionsFile
|
79
|
+
autoload :RootPackage
|
80
|
+
end
|
42
81
|
end
|
@@ -28,8 +28,9 @@ module Packwerk
|
|
28
28
|
.select { |railtie| railtie.is_a?(Rails::Engine) }
|
29
29
|
.push(Rails.application)
|
30
30
|
.flat_map do |engine|
|
31
|
-
|
32
|
-
|
31
|
+
paths = (engine.config.autoload_paths + engine.config.eager_load_paths + engine.config.autoload_once_paths)
|
32
|
+
paths.map(&:to_s).uniq
|
33
|
+
end
|
33
34
|
end
|
34
35
|
|
35
36
|
sig do
|
@@ -6,11 +6,6 @@ require "constant_resolver"
|
|
6
6
|
require "pathname"
|
7
7
|
require "yaml"
|
8
8
|
|
9
|
-
require "packwerk/package_set"
|
10
|
-
require "packwerk/graph"
|
11
|
-
require "packwerk/inflector"
|
12
|
-
require "packwerk/application_load_paths"
|
13
|
-
|
14
9
|
module Packwerk
|
15
10
|
class ApplicationValidator
|
16
11
|
def initialize(config_file_path:, configuration:)
|
@@ -32,19 +27,10 @@ module Packwerk
|
|
32
27
|
check_acyclic_graph,
|
33
28
|
check_package_manifest_paths,
|
34
29
|
check_valid_package_dependencies,
|
35
|
-
|
30
|
+
check_root_package_exists,
|
36
31
|
]
|
37
32
|
|
38
|
-
results
|
39
|
-
|
40
|
-
if results.empty?
|
41
|
-
Result.new(true)
|
42
|
-
else
|
43
|
-
Result.new(
|
44
|
-
false,
|
45
|
-
results.map(&:error_value).join("\n===\n")
|
46
|
-
)
|
47
|
-
end
|
33
|
+
merge_results(results)
|
48
34
|
end
|
49
35
|
|
50
36
|
def check_autoload_path_cache
|
@@ -65,51 +51,37 @@ module Packwerk
|
|
65
51
|
def check_package_manifests_for_privacy
|
66
52
|
privacy_settings = package_manifests_settings_for("enforce_privacy")
|
67
53
|
|
68
|
-
autoload_paths = @configuration.load_paths
|
69
|
-
|
70
54
|
resolver = ConstantResolver.new(
|
71
55
|
root_path: @configuration.root_path,
|
72
|
-
load_paths:
|
56
|
+
load_paths: @configuration.load_paths
|
73
57
|
)
|
74
58
|
|
75
|
-
|
59
|
+
results = []
|
76
60
|
|
77
|
-
privacy_settings.each do |
|
61
|
+
privacy_settings.each do |config_file_path, setting|
|
78
62
|
next unless setting.is_a?(Array)
|
63
|
+
constants = setting
|
79
64
|
|
80
|
-
|
81
|
-
# make sure the constant can be loaded
|
82
|
-
constant.constantize # rubocop:disable Sorbet/ConstantsFromStrings
|
83
|
-
context = resolver.resolve(constant)
|
84
|
-
|
85
|
-
unless context
|
86
|
-
errors << "#{constant}, listed in #{filepath.inspect}, could not be resolved"
|
87
|
-
next
|
88
|
-
end
|
89
|
-
|
90
|
-
expected_filename = constant.underscore + ".rb"
|
65
|
+
assert_constants_can_be_loaded(constants)
|
91
66
|
|
92
|
-
|
93
|
-
# file that defines their parent namespace. This restriction makes sure that we don't.
|
94
|
-
next if context.location.end_with?(expected_filename)
|
67
|
+
constant_locations = constants.map { |c| [c, resolver.resolve(c)&.location] }
|
95
68
|
|
96
|
-
|
97
|
-
|
98
|
-
|
69
|
+
constant_locations.each do |name, location|
|
70
|
+
results << if location
|
71
|
+
check_private_constant_location(name, location, config_file_path)
|
72
|
+
else
|
73
|
+
private_constant_unresolvable(name, config_file_path)
|
74
|
+
end
|
99
75
|
end
|
100
76
|
end
|
101
77
|
|
102
|
-
|
103
|
-
Result.new(true)
|
104
|
-
else
|
105
|
-
Result.new(false, errors.join("\n---\n"))
|
106
|
-
end
|
78
|
+
merge_results(results, separator: "\n---\n")
|
107
79
|
end
|
108
80
|
|
109
81
|
def check_package_manifest_syntax
|
110
82
|
errors = []
|
111
83
|
|
112
|
-
package_manifests
|
84
|
+
package_manifests.each do |f|
|
113
85
|
hash = YAML.load_file(f)
|
114
86
|
next unless hash
|
115
87
|
|
@@ -124,26 +96,26 @@ module Packwerk
|
|
124
96
|
|
125
97
|
if hash.key?("enforce_privacy")
|
126
98
|
unless [TrueClass, FalseClass, Array].include?(hash["enforce_privacy"].class)
|
127
|
-
errors << "Invalid 'enforce_privacy' option in #{f.inspect}: #{hash[
|
99
|
+
errors << "Invalid 'enforce_privacy' option in #{f.inspect}: #{hash["enforce_privacy"].inspect}"
|
128
100
|
end
|
129
101
|
end
|
130
102
|
|
131
103
|
if hash.key?("enforce_dependencies")
|
132
104
|
unless [TrueClass, FalseClass].include?(hash["enforce_dependencies"].class)
|
133
|
-
errors << "Invalid 'enforce_dependencies' option in #{f.inspect}: #{hash[
|
105
|
+
errors << "Invalid 'enforce_dependencies' option in #{f.inspect}: #{hash["enforce_dependencies"].inspect}"
|
134
106
|
end
|
135
107
|
end
|
136
108
|
|
137
109
|
if hash.key?("public_path")
|
138
110
|
unless hash["public_path"].is_a?(String)
|
139
|
-
errors << "'public_path' option must be a string in #{f.inspect}: #{hash[
|
111
|
+
errors << "'public_path' option must be a string in #{f.inspect}: #{hash["public_path"].inspect}"
|
140
112
|
end
|
141
113
|
end
|
142
114
|
|
143
115
|
next unless hash.key?("dependencies")
|
144
116
|
next if hash["dependencies"].is_a?(Array)
|
145
117
|
|
146
|
-
errors << "Invalid 'dependencies' option in #{f.inspect}: #{hash[
|
118
|
+
errors << "Invalid 'dependencies' option in #{f.inspect}: #{hash["dependencies"].inspect}"
|
147
119
|
end
|
148
120
|
|
149
121
|
if errors.empty?
|
@@ -193,24 +165,16 @@ module Packwerk
|
|
193
165
|
end
|
194
166
|
end
|
195
167
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
Result.new(
|
202
|
-
false,
|
203
|
-
"Inflections specified in #{inflections_file} don't line up with application!\n" +
|
204
|
-
errors.map(&:error_value).join("\n")
|
205
|
-
)
|
206
|
-
end
|
168
|
+
merge_results(
|
169
|
+
results,
|
170
|
+
separator: "\n",
|
171
|
+
errors_headline: "Inflections specified in #{inflections_file} don't line up with application!\n"
|
172
|
+
)
|
207
173
|
end
|
208
174
|
|
209
175
|
def check_acyclic_graph
|
210
|
-
|
211
|
-
|
212
|
-
edges = packages.flat_map do |package|
|
213
|
-
package.dependencies.map { |dependency| [package, packages.fetch(dependency)] }
|
176
|
+
edges = package_set.flat_map do |package|
|
177
|
+
package.dependencies.map { |dependency| [package, package_set.fetch(dependency)] }
|
214
178
|
end
|
215
179
|
dependency_graph = Packwerk::Graph.new(*edges)
|
216
180
|
|
@@ -225,7 +189,7 @@ module Packwerk
|
|
225
189
|
cycle_strings = dependency_graph.cycles.map do |cycle|
|
226
190
|
cycle_strings = cycle.map(&:to_s)
|
227
191
|
cycle_strings << cycle.first.to_s
|
228
|
-
"\t- #{cycle_strings.join(
|
192
|
+
"\t- #{cycle_strings.join(" → ")}"
|
229
193
|
end
|
230
194
|
|
231
195
|
if dependency_graph.acyclic?
|
@@ -297,7 +261,7 @@ module Packwerk
|
|
297
261
|
end
|
298
262
|
end
|
299
263
|
|
300
|
-
def
|
264
|
+
def check_root_package_exists
|
301
265
|
root_package_path = File.join(@configuration.root_path, "package.yml")
|
302
266
|
all_packages_manifests = package_manifests(package_glob)
|
303
267
|
|
@@ -316,8 +280,7 @@ module Packwerk
|
|
316
280
|
private
|
317
281
|
|
318
282
|
def package_manifests_settings_for(setting)
|
319
|
-
package_manifests(
|
320
|
-
.map { |f| [f, (YAML.load_file(File.join(f)) || {})[setting]] }
|
283
|
+
package_manifests.map { |f| [f, (YAML.load_file(File.join(f)) || {})[setting]] }
|
321
284
|
end
|
322
285
|
|
323
286
|
def format_yaml_strings(list)
|
@@ -328,13 +291,17 @@ module Packwerk
|
|
328
291
|
@configuration.package_paths || "**"
|
329
292
|
end
|
330
293
|
|
331
|
-
def package_manifests(glob_pattern)
|
294
|
+
def package_manifests(glob_pattern = package_glob)
|
332
295
|
PackageSet.package_paths(@configuration.root_path, glob_pattern)
|
333
296
|
.map { |f| File.realpath(f) }
|
334
297
|
end
|
335
298
|
|
336
299
|
def relative_paths(paths)
|
337
|
-
paths.map { |path|
|
300
|
+
paths.map { |path| relative_path(path) }
|
301
|
+
end
|
302
|
+
|
303
|
+
def relative_path(path)
|
304
|
+
Pathname.new(path).relative_path_from(@configuration.root_path)
|
338
305
|
end
|
339
306
|
|
340
307
|
def invalid_package_path?(path)
|
@@ -344,5 +311,54 @@ module Packwerk
|
|
344
311
|
package_path = File.join(@configuration.root_path, path, Packwerk::PackageSet::PACKAGE_CONFIG_FILENAME)
|
345
312
|
!File.file?(package_path)
|
346
313
|
end
|
314
|
+
|
315
|
+
def assert_constants_can_be_loaded(constants)
|
316
|
+
constants.each(&:constantize)
|
317
|
+
nil
|
318
|
+
end
|
319
|
+
|
320
|
+
def private_constant_unresolvable(name, config_file_path)
|
321
|
+
explicit_filepath = (name.start_with?("::") ? name[2..-1] : name).underscore + ".rb"
|
322
|
+
|
323
|
+
Result.new(
|
324
|
+
false,
|
325
|
+
"'#{name}', listed in #{config_file_path}, could not be resolved.\n"\
|
326
|
+
"This is probably because it is an autovivified namespace - a namespace module that doesn't have a\n"\
|
327
|
+
"file explicitly defining it. Packwerk currently doesn't support declaring autovivified namespaces as\n"\
|
328
|
+
"private. Add a #{explicit_filepath} file to explicitly define the constant."
|
329
|
+
)
|
330
|
+
end
|
331
|
+
|
332
|
+
def check_private_constant_location(name, location, config_file_path)
|
333
|
+
declared_package = package_set.package_from_path(relative_path(config_file_path))
|
334
|
+
constant_package = package_set.package_from_path(location)
|
335
|
+
|
336
|
+
if constant_package == declared_package
|
337
|
+
Result.new(true)
|
338
|
+
else
|
339
|
+
Result.new(
|
340
|
+
false,
|
341
|
+
"'#{name}' is declared as private in the '#{declared_package}' package but appears to be "\
|
342
|
+
"defined\nin the '#{constant_package}' package. Packwerk resolved it to #{location}."
|
343
|
+
)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def package_set
|
348
|
+
@package_set ||= Packwerk::PackageSet.load_all_from(@configuration.root_path, package_pathspec: package_glob)
|
349
|
+
end
|
350
|
+
|
351
|
+
def merge_results(results, separator: "\n===\n", errors_headline: "")
|
352
|
+
results.reject!(&:ok?)
|
353
|
+
|
354
|
+
if results.empty?
|
355
|
+
Result.new(true)
|
356
|
+
else
|
357
|
+
Result.new(
|
358
|
+
false,
|
359
|
+
errors_headline + results.map(&:error_value).join(separator)
|
360
|
+
)
|
361
|
+
end
|
362
|
+
end
|
347
363
|
end
|
348
364
|
end
|
@@ -1,26 +1,35 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "packwerk/constant_name_inspector"
|
5
|
-
require "packwerk/node"
|
6
|
-
|
7
4
|
module Packwerk
|
8
5
|
# Extracts the implicit constant reference from an active record association
|
9
6
|
class AssociationInspector
|
7
|
+
extend T::Sig
|
10
8
|
include ConstantNameInspector
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
CustomAssociations = T.type_alias { T.any(T::Array[Symbol], T::Set[Symbol]) }
|
11
|
+
|
12
|
+
RAILS_ASSOCIATIONS = T.let(
|
13
|
+
%i(
|
14
|
+
belongs_to
|
15
|
+
has_many
|
16
|
+
has_one
|
17
|
+
has_and_belongs_to_many
|
18
|
+
).to_set,
|
19
|
+
CustomAssociations
|
20
|
+
)
|
18
21
|
|
22
|
+
sig { params(inflector: Inflector, custom_associations: CustomAssociations).void }
|
19
23
|
def initialize(inflector:, custom_associations: Set.new)
|
20
24
|
@inflector = inflector
|
21
|
-
@associations = RAILS_ASSOCIATIONS + custom_associations
|
25
|
+
@associations = T.let(RAILS_ASSOCIATIONS + custom_associations, CustomAssociations)
|
22
26
|
end
|
23
27
|
|
28
|
+
sig do
|
29
|
+
override
|
30
|
+
.params(node: AST::Node, ancestors: T::Array[AST::Node])
|
31
|
+
.returns(T.nilable(String))
|
32
|
+
end
|
24
33
|
def constant_name_from_node(node, ancestors:)
|
25
34
|
return unless Node.method_call?(node)
|
26
35
|
return unless association?(node)
|
@@ -38,11 +47,13 @@ module Packwerk
|
|
38
47
|
|
39
48
|
private
|
40
49
|
|
50
|
+
sig { params(node: AST::Node).returns(T::Boolean) }
|
41
51
|
def association?(node)
|
42
52
|
method_name = Node.method_name(node)
|
43
53
|
@associations.include?(method_name)
|
44
54
|
end
|
45
55
|
|
56
|
+
sig { params(arguments: T::Array[AST::Node]).returns(T.nilable(AST::Node)) }
|
46
57
|
def custom_class_name(arguments)
|
47
58
|
association_options = arguments.detect { |n| Node.hash?(n) }
|
48
59
|
return unless association_options
|
@@ -50,6 +61,7 @@ module Packwerk
|
|
50
61
|
Node.value_from_hash(association_options, :class_name)
|
51
62
|
end
|
52
63
|
|
64
|
+
sig { params(arguments: T::Array[AST::Node]).returns(T.any(T.nilable(Symbol), T.nilable(String))) }
|
53
65
|
def association_name(arguments)
|
54
66
|
return unless Node.symbol?(arguments[0])
|
55
67
|
|