packwerk 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- data/.github/probots.yml +2 -0
- data/.github/pull_request_template.md +27 -0
- data/.github/workflows/ci.yml +50 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +46 -0
- data/.ruby-version +1 -0
- data/CODEOWNERS +1 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/CONTRIBUTING.md +17 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +236 -0
- data/LICENSE.md +7 -0
- data/README.md +73 -0
- data/Rakefile +13 -0
- data/TROUBLESHOOT.md +67 -0
- data/USAGE.md +250 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/dev.yml +32 -0
- data/docs/cohesion.png +0 -0
- data/exe/packwerk +6 -0
- data/lib/packwerk.rb +44 -0
- data/lib/packwerk/application_validator.rb +343 -0
- data/lib/packwerk/association_inspector.rb +44 -0
- data/lib/packwerk/checking_deprecated_references.rb +40 -0
- data/lib/packwerk/cli.rb +238 -0
- data/lib/packwerk/configuration.rb +82 -0
- data/lib/packwerk/const_node_inspector.rb +44 -0
- data/lib/packwerk/constant_discovery.rb +60 -0
- data/lib/packwerk/constant_name_inspector.rb +22 -0
- data/lib/packwerk/dependency_checker.rb +28 -0
- data/lib/packwerk/deprecated_references.rb +92 -0
- data/lib/packwerk/file_processor.rb +43 -0
- data/lib/packwerk/files_for_processing.rb +67 -0
- data/lib/packwerk/formatters/progress_formatter.rb +46 -0
- data/lib/packwerk/generators/application_validation.rb +62 -0
- data/lib/packwerk/generators/configuration_file.rb +69 -0
- data/lib/packwerk/generators/inflections_file.rb +43 -0
- data/lib/packwerk/generators/root_package.rb +37 -0
- data/lib/packwerk/generators/templates/inflections.yml +6 -0
- data/lib/packwerk/generators/templates/package.yml +17 -0
- data/lib/packwerk/generators/templates/packwerk +23 -0
- data/lib/packwerk/generators/templates/packwerk.yml.erb +23 -0
- data/lib/packwerk/generators/templates/packwerk_validator_test.rb +11 -0
- data/lib/packwerk/graph.rb +74 -0
- data/lib/packwerk/inflections/custom.rb +33 -0
- data/lib/packwerk/inflections/default.rb +73 -0
- data/lib/packwerk/inflector.rb +41 -0
- data/lib/packwerk/node.rb +259 -0
- data/lib/packwerk/node_processor.rb +49 -0
- data/lib/packwerk/node_visitor.rb +22 -0
- data/lib/packwerk/offense.rb +44 -0
- data/lib/packwerk/output_styles.rb +41 -0
- data/lib/packwerk/package.rb +56 -0
- data/lib/packwerk/package_set.rb +59 -0
- data/lib/packwerk/parsed_constant_definitions.rb +62 -0
- data/lib/packwerk/parsers.rb +23 -0
- data/lib/packwerk/parsers/erb.rb +66 -0
- data/lib/packwerk/parsers/factory.rb +34 -0
- data/lib/packwerk/parsers/ruby.rb +42 -0
- data/lib/packwerk/privacy_checker.rb +45 -0
- data/lib/packwerk/reference.rb +6 -0
- data/lib/packwerk/reference_extractor.rb +81 -0
- data/lib/packwerk/reference_lister.rb +23 -0
- data/lib/packwerk/run_context.rb +103 -0
- data/lib/packwerk/sanity_checker.rb +10 -0
- data/lib/packwerk/spring_command.rb +28 -0
- data/lib/packwerk/updating_deprecated_references.rb +51 -0
- data/lib/packwerk/version.rb +6 -0
- data/lib/packwerk/violation_type.rb +13 -0
- data/library.yml +6 -0
- data/packwerk.gemspec +58 -0
- data/service.yml +6 -0
- data/shipit.rubygems.yml +1 -0
- data/sorbet/config +2 -0
- data/sorbet/rbi/gems/actioncable@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +840 -0
- data/sorbet/rbi/gems/actionmailbox@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +571 -0
- data/sorbet/rbi/gems/actionmailer@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +568 -0
- data/sorbet/rbi/gems/actionpack@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +5216 -0
- data/sorbet/rbi/gems/actiontext@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +663 -0
- data/sorbet/rbi/gems/actionview@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +2504 -0
- data/sorbet/rbi/gems/activejob@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +635 -0
- data/sorbet/rbi/gems/activemodel@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +1201 -0
- data/sorbet/rbi/gems/activerecord@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +8011 -0
- data/sorbet/rbi/gems/activestorage@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +904 -0
- data/sorbet/rbi/gems/activesupport@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +3888 -0
- data/sorbet/rbi/gems/ast@2.4.1.rbi +54 -0
- data/sorbet/rbi/gems/better_html@1.0.15.rbi +317 -0
- data/sorbet/rbi/gems/builder@3.2.4.rbi +8 -0
- data/sorbet/rbi/gems/byebug@11.1.3.rbi +8 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
- data/sorbet/rbi/gems/colorize@0.8.1.rbi +40 -0
- data/sorbet/rbi/gems/commander@4.5.2.rbi +8 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.1.6.rbi +1966 -0
- data/sorbet/rbi/gems/constant_resolver@0.1.5.rbi +26 -0
- data/sorbet/rbi/gems/crass@1.0.6.rbi +138 -0
- data/sorbet/rbi/gems/erubi@1.9.0.rbi +39 -0
- data/sorbet/rbi/gems/globalid@0.4.2.rbi +178 -0
- data/sorbet/rbi/gems/highline@2.0.3.rbi +8 -0
- data/sorbet/rbi/gems/html_tokenizer@0.0.7.rbi +46 -0
- data/sorbet/rbi/gems/i18n@1.8.2.rbi +633 -0
- data/sorbet/rbi/gems/jaro_winkler@1.5.4.rbi +8 -0
- data/sorbet/rbi/gems/loofah@2.5.0.rbi +272 -0
- data/sorbet/rbi/gems/m@1.5.1.rbi +108 -0
- data/sorbet/rbi/gems/mail@2.7.1.rbi +2490 -0
- data/sorbet/rbi/gems/marcel@0.3.3.rbi +30 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +76 -0
- data/sorbet/rbi/gems/mimemagic@0.3.5.rbi +47 -0
- data/sorbet/rbi/gems/mini_mime@1.0.2.rbi +71 -0
- data/sorbet/rbi/gems/mini_portile2@2.4.0.rbi +8 -0
- data/sorbet/rbi/gems/minitest@5.14.0.rbi +542 -0
- data/sorbet/rbi/gems/mocha@1.11.2.rbi +964 -0
- data/sorbet/rbi/gems/nio4r@2.5.2.rbi +89 -0
- data/sorbet/rbi/gems/nokogiri@1.10.9.rbi +1608 -0
- data/sorbet/rbi/gems/parallel@1.19.1.rbi +8 -0
- data/sorbet/rbi/gems/parlour@4.0.1.rbi +561 -0
- data/sorbet/rbi/gems/parser@2.7.1.4.rbi +1632 -0
- data/sorbet/rbi/gems/pry@0.13.1.rbi +8 -0
- data/sorbet/rbi/gems/rack-test@1.1.0.rbi +335 -0
- data/sorbet/rbi/gems/rack@2.2.2.rbi +1730 -0
- data/sorbet/rbi/gems/rails-dom-testing@2.0.3.rbi +123 -0
- data/sorbet/rbi/gems/rails-html-sanitizer@1.3.0.rbi +213 -0
- data/sorbet/rbi/gems/rails@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +8 -0
- data/sorbet/rbi/gems/railties@6.1.0.alpha-d80c18a391e33552ae2d943e68af56946f883f65.rbi +869 -0
- data/sorbet/rbi/gems/rainbow@3.0.0.rbi +155 -0
- data/sorbet/rbi/gems/rake@13.0.1.rbi +841 -0
- data/sorbet/rbi/gems/rexml@3.2.4.rbi +8 -0
- data/sorbet/rbi/gems/rubocop-performance@1.5.2.rbi +8 -0
- data/sorbet/rbi/gems/rubocop-shopify@1.0.2.rbi +8 -0
- data/sorbet/rbi/gems/rubocop-sorbet@0.3.7.rbi +8 -0
- data/sorbet/rbi/gems/rubocop@0.82.0.rbi +8 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.10.1.rbi +8 -0
- data/sorbet/rbi/gems/smart_properties@1.15.0.rbi +168 -0
- data/sorbet/rbi/gems/spoom@1.0.4.rbi +418 -0
- data/sorbet/rbi/gems/spring@2.1.0.rbi +160 -0
- data/sorbet/rbi/gems/sprockets-rails@3.2.1.rbi +431 -0
- data/sorbet/rbi/gems/sprockets@4.0.0.rbi +1132 -0
- data/sorbet/rbi/gems/tapioca@0.4.5.rbi +518 -0
- data/sorbet/rbi/gems/thor@1.0.1.rbi +892 -0
- data/sorbet/rbi/gems/tzinfo@2.0.2.rbi +547 -0
- data/sorbet/rbi/gems/unicode-display_width@1.7.0.rbi +8 -0
- data/sorbet/rbi/gems/websocket-driver@0.7.1.rbi +438 -0
- data/sorbet/rbi/gems/websocket-extensions@0.1.4.rbi +71 -0
- data/sorbet/rbi/gems/zeitwerk@2.3.0.rbi +8 -0
- data/sorbet/tapioca/require.rb +25 -0
- data/static/packwerk-check-demo.png +0 -0
- data/static/packwerk_check.gif +0 -0
- data/static/packwerk_check_violation.gif +0 -0
- data/static/packwerk_update.gif +0 -0
- data/static/packwerk_validate.gif +0 -0
- metadata +341 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "parser"
|
5
|
+
require "parser/current"
|
6
|
+
|
7
|
+
module Packwerk
|
8
|
+
module Parsers
|
9
|
+
class Ruby
|
10
|
+
class RaiseExceptionsParser < Parser::CurrentRuby
|
11
|
+
def initialize(builder)
|
12
|
+
super(builder)
|
13
|
+
super.diagnostics.all_errors_are_fatal = true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class TolerateInvalidUtf8Builder < Parser::Builders::Default
|
18
|
+
def string_value(token)
|
19
|
+
value(token)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(parser_class: RaiseExceptionsParser)
|
24
|
+
@builder = TolerateInvalidUtf8Builder.new
|
25
|
+
@parser_class = parser_class
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(io:, file_path: "<unknown>")
|
29
|
+
buffer = Parser::Source::Buffer.new(file_path)
|
30
|
+
buffer.source = io.read
|
31
|
+
parser = @parser_class.new(@builder)
|
32
|
+
parser.parse(buffer)
|
33
|
+
rescue EncodingError => e
|
34
|
+
result = ParseResult.new(file: file_path, message: e.message)
|
35
|
+
raise Parsers::ParseError, result
|
36
|
+
rescue Parser::SyntaxError => e
|
37
|
+
result = ParseResult.new(file: file_path, message: "Syntax error: #{e}")
|
38
|
+
raise Parsers::ParseError, result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "packwerk/violation_type"
|
5
|
+
|
6
|
+
module Packwerk
|
7
|
+
class PrivacyChecker
|
8
|
+
def violation_type
|
9
|
+
ViolationType::Privacy
|
10
|
+
end
|
11
|
+
|
12
|
+
def invalid_reference?(reference, reference_lister)
|
13
|
+
return if reference.constant.public?
|
14
|
+
|
15
|
+
privacy_option = reference.constant.package.enforce_privacy
|
16
|
+
return if enforcement_disabled?(privacy_option)
|
17
|
+
|
18
|
+
return unless privacy_option == true ||
|
19
|
+
explicitly_private_constant?(reference.constant, explicitly_private_constants: privacy_option)
|
20
|
+
|
21
|
+
return if reference_lister.listed?(reference, violation_type: violation_type)
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def message_for(reference)
|
27
|
+
source_desc = reference.source_package ? "'#{reference.source_package}'" : "here"
|
28
|
+
"Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
|
29
|
+
"referenced from #{source_desc}.\n" \
|
30
|
+
"Is there a public entrypoint in '#{reference.constant.package.public_path}' that you can use instead?"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def explicitly_private_constant?(constant, explicitly_private_constants:)
|
36
|
+
explicitly_private_constants.include?(constant.name) ||
|
37
|
+
# nested constants
|
38
|
+
explicitly_private_constants.any? { |epc| constant.name.start_with?(epc + "::") }
|
39
|
+
end
|
40
|
+
|
41
|
+
def enforcement_disabled?(privacy_option)
|
42
|
+
[false, nil].include?(privacy_option)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
require "packwerk/constant_discovery"
|
7
|
+
require "packwerk/constant_name_inspector"
|
8
|
+
require "packwerk/node"
|
9
|
+
require "packwerk/parsed_constant_definitions"
|
10
|
+
require "packwerk/reference"
|
11
|
+
|
12
|
+
module Packwerk
|
13
|
+
# extracts a possible constant reference from a given AST node
|
14
|
+
class ReferenceExtractor
|
15
|
+
extend T::Sig
|
16
|
+
|
17
|
+
sig do
|
18
|
+
params(
|
19
|
+
context_provider: Packwerk::ConstantDiscovery,
|
20
|
+
constant_name_inspectors: T::Array[Packwerk::ConstantNameInspector],
|
21
|
+
root_node: ::AST::Node,
|
22
|
+
root_path: String,
|
23
|
+
).void
|
24
|
+
end
|
25
|
+
def initialize(
|
26
|
+
context_provider:,
|
27
|
+
constant_name_inspectors:,
|
28
|
+
root_node:,
|
29
|
+
root_path:
|
30
|
+
)
|
31
|
+
@context_provider = context_provider
|
32
|
+
@constant_name_inspectors = constant_name_inspectors
|
33
|
+
@root_path = root_path
|
34
|
+
@local_constant_definitions = ParsedConstantDefinitions.new(root_node: root_node)
|
35
|
+
end
|
36
|
+
|
37
|
+
def reference_from_node(node, ancestors:, file_path:)
|
38
|
+
constant_name = T.let(nil, T.nilable(String))
|
39
|
+
|
40
|
+
@constant_name_inspectors.each do |inspector|
|
41
|
+
constant_name = inspector.constant_name_from_node(node, ancestors: ancestors)
|
42
|
+
break if constant_name
|
43
|
+
end
|
44
|
+
|
45
|
+
reference_from_constant(constant_name, node: node, ancestors: ancestors, file_path: file_path) if constant_name
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def reference_from_constant(constant_name, node:, ancestors:, file_path:)
|
51
|
+
namespace_path = Node.enclosing_namespace_path(node, ancestors: ancestors)
|
52
|
+
return if local_reference?(constant_name, Node.name_location(node), namespace_path)
|
53
|
+
|
54
|
+
constant =
|
55
|
+
@context_provider.context_for(
|
56
|
+
constant_name,
|
57
|
+
current_namespace_path: namespace_path
|
58
|
+
)
|
59
|
+
|
60
|
+
return if constant&.package.nil?
|
61
|
+
|
62
|
+
relative_path =
|
63
|
+
Pathname.new(file_path)
|
64
|
+
.relative_path_from(@root_path).to_s
|
65
|
+
|
66
|
+
source_package = @context_provider.package_from_path(relative_path)
|
67
|
+
|
68
|
+
return if source_package == constant.package
|
69
|
+
|
70
|
+
Reference.new(source_package, relative_path, constant)
|
71
|
+
end
|
72
|
+
|
73
|
+
def local_reference?(constant_name, name_location, namespace_path)
|
74
|
+
@local_constant_definitions.local_reference?(
|
75
|
+
constant_name,
|
76
|
+
location: name_location,
|
77
|
+
namespace_path: namespace_path
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
require "packwerk/reference"
|
7
|
+
require "packwerk/violation_type"
|
8
|
+
|
9
|
+
module Packwerk
|
10
|
+
module ReferenceLister
|
11
|
+
extend T::Sig
|
12
|
+
extend T::Helpers
|
13
|
+
|
14
|
+
interface!
|
15
|
+
|
16
|
+
sig do
|
17
|
+
params(reference: Packwerk::Reference, violation_type: ViolationType)
|
18
|
+
.returns(T::Boolean)
|
19
|
+
.abstract
|
20
|
+
end
|
21
|
+
def listed?(reference, violation_type:); end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "active_support/inflector"
|
5
|
+
require "constant_resolver"
|
6
|
+
|
7
|
+
require "packwerk/association_inspector"
|
8
|
+
require "packwerk/checking_deprecated_references"
|
9
|
+
require "packwerk/constant_discovery"
|
10
|
+
require "packwerk/const_node_inspector"
|
11
|
+
require "packwerk/dependency_checker"
|
12
|
+
require "packwerk/file_processor"
|
13
|
+
require "packwerk/node_processor"
|
14
|
+
require "packwerk/package_set"
|
15
|
+
require "packwerk/privacy_checker"
|
16
|
+
require "packwerk/reference_extractor"
|
17
|
+
|
18
|
+
module Packwerk
|
19
|
+
class RunContext
|
20
|
+
attr_reader(
|
21
|
+
:checkers,
|
22
|
+
:constant_name_inspectors,
|
23
|
+
:context_provider,
|
24
|
+
:root_path,
|
25
|
+
:file_processor,
|
26
|
+
:node_processor_class,
|
27
|
+
:reference_lister
|
28
|
+
)
|
29
|
+
|
30
|
+
DEFAULT_CHECKERS = [
|
31
|
+
::Packwerk::DependencyChecker,
|
32
|
+
::Packwerk::PrivacyChecker,
|
33
|
+
]
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def from_configuration(configuration, reference_lister: nil)
|
37
|
+
default_reference_lister = reference_lister ||
|
38
|
+
::Packwerk::CheckingDeprecatedReferences.new(configuration.root_path)
|
39
|
+
new(
|
40
|
+
root_path: configuration.root_path,
|
41
|
+
load_paths: configuration.load_paths,
|
42
|
+
inflector: ActiveSupport::Inflector,
|
43
|
+
custom_associations: configuration.custom_associations,
|
44
|
+
reference_lister: default_reference_lister,
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(
|
50
|
+
root_path:,
|
51
|
+
load_paths:,
|
52
|
+
package_paths: nil,
|
53
|
+
inflector: nil,
|
54
|
+
custom_associations: [],
|
55
|
+
checker_classes: DEFAULT_CHECKERS,
|
56
|
+
node_processor_class: NodeProcessor,
|
57
|
+
reference_lister: nil
|
58
|
+
)
|
59
|
+
@root_path = File.expand_path(root_path)
|
60
|
+
|
61
|
+
resolver = ConstantResolver.new(
|
62
|
+
root_path: @root_path,
|
63
|
+
load_paths: load_paths,
|
64
|
+
inflector: inflector,
|
65
|
+
)
|
66
|
+
|
67
|
+
package_set = ::Packwerk::PackageSet.load_all_from(@root_path, package_pathspec: package_paths)
|
68
|
+
|
69
|
+
@context_provider = ::Packwerk::ConstantDiscovery.new(
|
70
|
+
constant_resolver: resolver,
|
71
|
+
packages: package_set
|
72
|
+
)
|
73
|
+
|
74
|
+
@reference_lister = reference_lister || ::Packwerk::CheckingDeprecatedReferences.new(@root_path)
|
75
|
+
|
76
|
+
@checkers = checker_classes.map(&:new)
|
77
|
+
|
78
|
+
@constant_name_inspectors = [
|
79
|
+
::Packwerk::ConstNodeInspector.new,
|
80
|
+
::Packwerk::AssociationInspector.new(inflector: inflector, custom_associations: custom_associations),
|
81
|
+
]
|
82
|
+
|
83
|
+
@node_processor_class = node_processor_class
|
84
|
+
@file_processor = FileProcessor.new(run_context: self)
|
85
|
+
end
|
86
|
+
|
87
|
+
def node_processor_for(filename:, ast_node:)
|
88
|
+
reference_extractor = ::Packwerk::ReferenceExtractor.new(
|
89
|
+
context_provider: context_provider,
|
90
|
+
constant_name_inspectors: constant_name_inspectors,
|
91
|
+
root_node: ast_node,
|
92
|
+
root_path: root_path,
|
93
|
+
)
|
94
|
+
|
95
|
+
node_processor_class.new(
|
96
|
+
reference_extractor: reference_extractor,
|
97
|
+
reference_lister: @reference_lister,
|
98
|
+
filename: filename,
|
99
|
+
checkers: checkers,
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "packwerk/application_validator"
|
5
|
+
|
6
|
+
module Packwerk
|
7
|
+
# To do: This alias and file should be removed as it is deprecated
|
8
|
+
warn("DEPRECATION WARNING: Packwerk::SanityChecker is deprecated, use Packwerk::ApplicationValidator instead.")
|
9
|
+
SanityChecker = ApplicationValidator
|
10
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: ignore
|
3
|
+
|
4
|
+
require "spring/commands"
|
5
|
+
|
6
|
+
module Packwerk
|
7
|
+
class SpringCommand
|
8
|
+
def env(*)
|
9
|
+
# Packwerk needs to run in a test environment, which has a set of autoload paths that are
|
10
|
+
# often a superset of the dev/prod paths (for example, test/support/helpers)
|
11
|
+
"test"
|
12
|
+
end
|
13
|
+
|
14
|
+
def exec_name
|
15
|
+
"packwerk"
|
16
|
+
end
|
17
|
+
|
18
|
+
def gem_name
|
19
|
+
"packwerk"
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
load(Gem.bin_path(gem_name, exec_name))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Spring.register_command("packwerk", SpringCommand.new)
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
require "packwerk/deprecated_references"
|
7
|
+
require "packwerk/reference"
|
8
|
+
require "packwerk/reference_lister"
|
9
|
+
require "packwerk/violation_type"
|
10
|
+
|
11
|
+
module Packwerk
|
12
|
+
class UpdatingDeprecatedReferences
|
13
|
+
extend T::Sig
|
14
|
+
include ReferenceLister
|
15
|
+
|
16
|
+
def initialize(root_path, deprecated_references = {})
|
17
|
+
@root_path = root_path
|
18
|
+
@deprecated_references = deprecated_references
|
19
|
+
end
|
20
|
+
|
21
|
+
sig do
|
22
|
+
params(reference: Packwerk::Reference, violation_type: ViolationType)
|
23
|
+
.returns(T::Boolean)
|
24
|
+
.override
|
25
|
+
end
|
26
|
+
def listed?(reference, violation_type:)
|
27
|
+
deprecated_references = deprecated_references_for(reference.source_package)
|
28
|
+
deprecated_references.add_entries(reference, violation_type.serialize)
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def dump_deprecated_references_files
|
33
|
+
@deprecated_references.each do |_, deprecated_references_file|
|
34
|
+
deprecated_references_file.dump
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def deprecated_references_for(package)
|
41
|
+
@deprecated_references[package] ||= Packwerk::DeprecatedReferences.new(
|
42
|
+
package,
|
43
|
+
deprecated_references_file_for(package),
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def deprecated_references_file_for(package)
|
48
|
+
File.join(@root_path, package.name, "deprecated_references.yml")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/library.yml
ADDED
data/packwerk.gemspec
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/packwerk/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "packwerk"
|
7
|
+
spec.version = Packwerk::VERSION
|
8
|
+
spec.authors = ["Shopify Inc."]
|
9
|
+
spec.email = ["gems@shopify.com"]
|
10
|
+
|
11
|
+
spec.summary = "Packages for applications based on the zeitwerk autoloader"
|
12
|
+
|
13
|
+
spec.description = <<~DESCRIPTION
|
14
|
+
Sets package level boundaries between a specified set of ruby
|
15
|
+
constants to minimize cross-boundary referencing and dependency.
|
16
|
+
DESCRIPTION
|
17
|
+
spec.homepage = "https://github.com/Shopify/packwerk"
|
18
|
+
spec.license = "MIT"
|
19
|
+
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
22
|
+
spec.metadata["source_code_uri"] = "https://github.com/Shopify/packwerk"
|
23
|
+
spec.metadata["changelog_uri"] = "https://github.com/Shopify/packwerk/releases"
|
24
|
+
end
|
25
|
+
|
26
|
+
if spec.respond_to?(:metadata)
|
27
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
28
|
+
else
|
29
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
30
|
+
"public gem pushes."
|
31
|
+
end
|
32
|
+
|
33
|
+
spec.bindir = "exe"
|
34
|
+
spec.executables << "packwerk"
|
35
|
+
|
36
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
37
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
38
|
+
end
|
39
|
+
spec.require_paths = %w(lib)
|
40
|
+
|
41
|
+
spec.required_ruby_version = ">= 2.6"
|
42
|
+
|
43
|
+
spec.add_dependency("activesupport", ">= 5.2")
|
44
|
+
spec.add_dependency("constant_resolver")
|
45
|
+
spec.add_dependency("sorbet-runtime")
|
46
|
+
|
47
|
+
spec.add_development_dependency("bundler")
|
48
|
+
spec.add_development_dependency("rake")
|
49
|
+
spec.add_development_dependency("sorbet")
|
50
|
+
spec.add_development_dependency("m")
|
51
|
+
|
52
|
+
# For Ruby parsing
|
53
|
+
spec.add_dependency("ast")
|
54
|
+
spec.add_dependency("parser")
|
55
|
+
|
56
|
+
# For ERB parsing
|
57
|
+
spec.add_dependency("better_html")
|
58
|
+
end
|