rubocop-modularization 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -3
- data/config/default.yml +5 -0
- data/lib/rubocop/cop/modularization/namespaced_under_package_name/desired_zeitwerk_api.rb +110 -0
- data/lib/rubocop/cop/modularization/namespaced_under_package_name.rb +119 -0
- data/lib/rubocop/cop/modularization/typed_public_api.rb +39 -0
- data/lib/rubocop/cop/modularization_cops.rb +1 -0
- data/lib/rubocop/modularization/inject.rb +4 -0
- data/lib/rubocop/modularization/private.rb +11 -0
- data/lib/rubocop/modularization.rb +8 -4
- data/lib/rubocop-modularization.rb +5 -2
- data/sorbet/rbi/gems/activesupport@7.0.4.rbi +15914 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi +11263 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1079 -0
- data/sorbet/rbi/gems/i18n@1.12.0.rbi +2296 -0
- data/sorbet/rbi/gems/json@2.6.2.rbi +1547 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
- data/sorbet/rbi/gems/minitest@5.16.3.rbi +1459 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +161 -0
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
- data/sorbet/rbi/gems/parse_packwerk@0.12.1.rbi +203 -0
- data/sorbet/rbi/gems/parser@3.1.2.1.rbi +8944 -0
- data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +392 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +2899 -0
- data/sorbet/rbi/gems/rbi@0.0.16.rbi +3007 -0
- data/sorbet/rbi/gems/regexp_parser@2.6.0.rbi +3498 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +4717 -0
- data/sorbet/rbi/gems/rspec-core@3.11.0.rbi +10934 -0
- data/sorbet/rbi/gems/rspec-expectations@3.11.1.rbi +8090 -0
- data/sorbet/rbi/gems/rspec-mocks@3.11.1.rbi +5291 -0
- data/sorbet/rbi/gems/rspec-support@3.11.1.rbi +1610 -0
- data/sorbet/rbi/gems/rspec@3.11.0.rbi +88 -0
- data/sorbet/rbi/gems/rubocop-ast@1.21.0.rbi +6898 -0
- data/sorbet/rbi/gems/rubocop-extension-generator@0.5.1.rbi +86 -0
- data/sorbet/rbi/gems/rubocop-sorbet@0.6.11.rbi +1002 -0
- data/sorbet/rbi/gems/rubocop@1.36.0.rbi +52209 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +1239 -0
- data/sorbet/rbi/gems/spoom@1.1.12.rbi +2369 -0
- data/sorbet/rbi/gems/tapioca@0.10.2.rbi +3439 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
- data/sorbet/rbi/gems/tzinfo@2.0.5.rbi +5896 -0
- data/sorbet/rbi/gems/unicode-display_width@2.3.0.rbi +48 -0
- data/sorbet/rbi/gems/unparser@0.6.5.rbi +4529 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +2586 -0
- data/sorbet/rbi/gems/yard-sorbet@0.7.0.rbi +389 -0
- data/sorbet/rbi/gems/yard@0.9.28.rbi +17775 -0
- data/sorbet/rbi/todo.rbi +0 -3
- metadata +105 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7be2735c3d928d9c4ccf2643f2d07c533926ded38120b0d50e825d021065d92
|
4
|
+
data.tar.gz: dc19628fa31d58ced5e4b93af213d31f475c23669da692722b41c3c12140fc71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55916f5fdcf893b864f41d69b69cb595f2b32427164e6cfd9f32cd2859d8ff6b2db012c7fc4a14a665b600efae8645a73bdab8f26f8b2455c0e4b461e21bcdb0
|
7
|
+
data.tar.gz: 5a558caa1855c9aeb2317c574d9c6983fe6ca35ef9a1fb34af4d285cc432810961273928cf628293452102dd1ba0d0c5d817ab6feb3fe6c833a49485fec1aa5f
|
data/README.md
CHANGED
@@ -1,5 +1,84 @@
|
|
1
1
|
# rubocop-modularization
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
A collection of Rubocop rules for modularization..
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Just install the `rubocop-modularization` gem
|
8
|
+
|
9
|
+
```sh
|
10
|
+
gem install rubocop-modularization
|
11
|
+
```
|
12
|
+
or, if you use `Bundler`, add this line your application's `Gemfile`:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'rubocop-modularization', require: false
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
You need to tell RuboCop to load the Modularization extension. There are three ways to do this:
|
21
|
+
|
22
|
+
### RuboCop configuration file
|
23
|
+
|
24
|
+
Put this into your `.rubocop.yml`:
|
25
|
+
|
26
|
+
```yaml
|
27
|
+
require: rubocop-modularization
|
28
|
+
```
|
29
|
+
|
30
|
+
Alternatively, use the following array notation when specifying multiple extensions:
|
31
|
+
|
32
|
+
```yaml
|
33
|
+
require:
|
34
|
+
- rubocop-other-extension
|
35
|
+
- rubocop-modularization
|
36
|
+
```
|
37
|
+
|
38
|
+
Now you can run `rubocop` and it will automatically load the RuboCop Modularization cops together with the standard cops.
|
39
|
+
|
40
|
+
### Command line
|
41
|
+
|
42
|
+
```sh
|
43
|
+
rubocop --require rubocop-modularization
|
44
|
+
```
|
45
|
+
|
46
|
+
### Rake task
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
RuboCop::RakeTask.new do |task|
|
50
|
+
task.requires << 'rubocop-modularization'
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
## The Cops
|
55
|
+
All cops are located under [`lib/rubocop/cop/modularization`](lib/rubocop/cop/modularization), and contain examples/documentation.
|
56
|
+
|
57
|
+
In your `.rubocop.yml`, you may treat the Modularization cops just like any other cop. For example:
|
58
|
+
|
59
|
+
```yaml
|
60
|
+
Modularization/NamespacedUnderPackageName:
|
61
|
+
Exclude:
|
62
|
+
- lib/example.rb
|
63
|
+
```
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rubyatscale/rubocop-modularization. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Code Of Conduct](CODE_OF_CONDUCT.MD).
|
67
|
+
|
68
|
+
To contribute a new cop, please use the supplied generator like this:
|
69
|
+
|
70
|
+
```sh
|
71
|
+
bundle exec rake new_cop[Modularization/NewCopName]
|
72
|
+
```
|
73
|
+
|
74
|
+
which will create a skeleton cop, a skeleton spec, an entry in the default config file and will require the new cop so that it is properly exported from the gem.
|
75
|
+
|
76
|
+
Don't forget to update the documentation with:
|
77
|
+
|
78
|
+
```sh
|
79
|
+
VERIFYING_DOCUMENTATION=1 bundle exec rake generate_cops_documentation
|
80
|
+
```
|
81
|
+
|
82
|
+
## License
|
83
|
+
|
84
|
+
The gem is available as open source under the terms of the [MIT License](https://github.com/Shopify/rubocop-modularization/blob/main/LICENSE.txt).
|
data/config/default.yml
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Modularization
|
6
|
+
class NamespacedUnderPackageName < Base
|
7
|
+
#
|
8
|
+
# This is a private class that represents API that we would prefer to be available somehow in Zeitwerk.
|
9
|
+
#
|
10
|
+
class DesiredZeitwerkApi
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
class NamespaceContext < T::Struct
|
14
|
+
const :current_namespace, String
|
15
|
+
const :expected_namespace, String
|
16
|
+
const :expected_filepath, String
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# For now, this API includes `package_for_path`
|
21
|
+
# If this were truly zeitwerk API, it wouldn't include any mention of packs and it would likely not need the package at all
|
22
|
+
# Since it could get the actual namespace without knowing anything about packs.
|
23
|
+
# However, we would need to pass to it the desired namespace based on the pack name for it to be able to suggest
|
24
|
+
# a desired filepath.
|
25
|
+
# Likely this means that our own cop should determine the desired namespace and pass that in
|
26
|
+
# and this can determine actual namespace and how to get to expected.
|
27
|
+
#
|
28
|
+
sig { params(relative_filename: String, package_for_path: ParsePackwerk::Package).returns(T.nilable(NamespaceContext)) }
|
29
|
+
def for_file(relative_filename, package_for_path)
|
30
|
+
package_name = package_for_path.name
|
31
|
+
|
32
|
+
# Zeitwerk establishes a standard convention by which namespaces are defined.
|
33
|
+
# The package protections namespace checker is coupled to a specific assumption about how auto-loading works.
|
34
|
+
#
|
35
|
+
# Namely, we expect the following autoload paths: `packs/**/app/**/`
|
36
|
+
# Examples:
|
37
|
+
# 1) `packs/package_1/app/public/package_1/my_constant.rb` produces constant `Package1::MyConstant`
|
38
|
+
# 2) `packs/package_1/app/services/package_1/my_service.rb` produces constant `Package1::MyService`
|
39
|
+
# 3) `packs/package_1/app/services/package_1.rb` produces constant `Package1`
|
40
|
+
# 4) `packs/package_1/app/public/package_1.rb` produces constant `Package1`
|
41
|
+
#
|
42
|
+
# Described another way, we expect any part of the directory labeled NAMESPACE to establish a portion of the fully qualified runtime constant:
|
43
|
+
# `packs/**/app/**/NAMESPACE1/NAMESPACE2/[etc]`
|
44
|
+
#
|
45
|
+
# Therefore, for our implementation, we substitute out the non-namespace producing portions of the filename to count the number of namespaces.
|
46
|
+
# Note this will *not work* properly in applications that have different assumptions about autoloading.
|
47
|
+
|
48
|
+
path_without_package_base = relative_filename.gsub(%r{#{package_name}/app/}, '')
|
49
|
+
if path_without_package_base.include?('concerns')
|
50
|
+
autoload_folder_name = path_without_package_base.split('/').first(2).join('/')
|
51
|
+
else
|
52
|
+
autoload_folder_name = path_without_package_base.split('/').first
|
53
|
+
end
|
54
|
+
|
55
|
+
remaining_file_path = path_without_package_base.gsub(%r{\A#{autoload_folder_name}/}, '')
|
56
|
+
actual_namespace = get_actual_namespace(remaining_file_path, package_name)
|
57
|
+
|
58
|
+
if relative_filename.include?('app/')
|
59
|
+
app_or_lib = 'app'
|
60
|
+
elsif relative_filename.include?('lib/')
|
61
|
+
app_or_lib = 'lib'
|
62
|
+
end
|
63
|
+
|
64
|
+
absolute_desired_path = root_pathname.join(
|
65
|
+
package_name,
|
66
|
+
T.must(app_or_lib),
|
67
|
+
T.must(autoload_folder_name),
|
68
|
+
get_package_last_name(package_for_path),
|
69
|
+
remaining_file_path
|
70
|
+
)
|
71
|
+
|
72
|
+
relative_desired_path = absolute_desired_path.relative_path_from(root_pathname)
|
73
|
+
|
74
|
+
NamespaceContext.new(
|
75
|
+
current_namespace: actual_namespace,
|
76
|
+
expected_namespace: get_pack_based_namespace(package_for_path),
|
77
|
+
expected_filepath: relative_desired_path.to_s
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
sig { params(pack: ParsePackwerk::Package).returns(String) }
|
82
|
+
def get_pack_based_namespace(pack)
|
83
|
+
get_package_last_name(pack).camelize
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
sig { returns(Pathname) }
|
89
|
+
def root_pathname
|
90
|
+
Pathname.pwd
|
91
|
+
end
|
92
|
+
|
93
|
+
sig { params(pack: ParsePackwerk::Package).returns(String) }
|
94
|
+
def get_package_last_name(pack)
|
95
|
+
T.must(pack.name.split('/').last)
|
96
|
+
end
|
97
|
+
|
98
|
+
sig { params(remaining_file_path: String, package_name: String).returns(String) }
|
99
|
+
def get_actual_namespace(remaining_file_path, package_name)
|
100
|
+
# If the remaining file path is a ruby file (not a directory), then it establishes a global namespace
|
101
|
+
# Otherwise, per Zeitwerk's conventions as listed above, its a directory that establishes another global namespace
|
102
|
+
T.must(remaining_file_path.split('/').first).gsub('.rb', '').camelize
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private_constant :DesiredZeitwerkApi
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
# For String#camelize
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
5
|
+
require 'rubocop/cop/modularization/namespaced_under_package_name/desired_zeitwerk_api'
|
6
|
+
|
7
|
+
module RuboCop
|
8
|
+
module Cop
|
9
|
+
module Modularization
|
10
|
+
# This cop helps ensure that each pack exposes one namespace.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# # packs/foo/app/services/blah/bar.rb
|
16
|
+
# class Blah::Bar; end
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# # packs/foo/app/services/foo/blah/bar.rb
|
20
|
+
# class Foo::Blah::Bar; end
|
21
|
+
#
|
22
|
+
class NamespacedUnderPackageName < Base
|
23
|
+
extend T::Sig
|
24
|
+
|
25
|
+
include RangeHelp
|
26
|
+
|
27
|
+
sig { void }
|
28
|
+
def on_new_investigation
|
29
|
+
absolute_filepath = Pathname.new(processed_source.file_path)
|
30
|
+
relative_filepath = absolute_filepath.relative_path_from(Pathname.pwd)
|
31
|
+
relative_filename = relative_filepath.to_s
|
32
|
+
|
33
|
+
# This cop only works for files ruby files in `app`
|
34
|
+
return if !relative_filename.include?('app/') || relative_filepath.extname != '.rb'
|
35
|
+
|
36
|
+
relative_filename = relative_filepath.to_s
|
37
|
+
package_for_path = ParsePackwerk.package_from_path(relative_filename)
|
38
|
+
return if package_for_path.nil?
|
39
|
+
|
40
|
+
namespace_context = desired_zeitwerk_api.for_file(relative_filename, package_for_path)
|
41
|
+
return if namespace_context.nil?
|
42
|
+
|
43
|
+
allowed_global_namespaces = Set.new([
|
44
|
+
namespace_context.expected_namespace,
|
45
|
+
*cop_config['GloballyPermittedNamespaces']
|
46
|
+
])
|
47
|
+
|
48
|
+
package_name = package_for_path.name
|
49
|
+
actual_namespace = namespace_context.current_namespace
|
50
|
+
|
51
|
+
if allowed_global_namespaces.include?(actual_namespace)
|
52
|
+
# No problem!
|
53
|
+
else
|
54
|
+
package_enforces_namespaces = cop_config['IncludePacks'].include?(package_for_path.name)
|
55
|
+
expected_namespace = namespace_context.expected_namespace
|
56
|
+
relative_desired_path = namespace_context.expected_filepath
|
57
|
+
pack_owning_this_namespace = namespaces_to_packs[actual_namespace]
|
58
|
+
|
59
|
+
if package_enforces_namespaces
|
60
|
+
add_offense(
|
61
|
+
source_range(processed_source.buffer, 1, 0),
|
62
|
+
message: format(
|
63
|
+
'`%<package_name>s` prevents modules/classes that are not submodules of the package namespace. Should be namespaced under `%<expected_namespace>s` with path `%<expected_path>s`. See https://go/packwerk_cheatsheet_namespaces for more info.',
|
64
|
+
package_name: package_name,
|
65
|
+
expected_namespace: expected_namespace,
|
66
|
+
expected_path: relative_desired_path
|
67
|
+
)
|
68
|
+
)
|
69
|
+
elsif pack_owning_this_namespace
|
70
|
+
add_offense(
|
71
|
+
source_range(processed_source.buffer, 1, 0),
|
72
|
+
message: format(
|
73
|
+
'`%<pack_owning_this_namespace>s` prevents other packs from sitting in the `%<actual_namespace>s` namespace. This should be namespaced under `%<expected_namespace>s` with path `%<expected_path>s`. See https://go/packwerk_cheatsheet_namespaces for more info.',
|
74
|
+
package_name: package_name,
|
75
|
+
pack_owning_this_namespace: pack_owning_this_namespace,
|
76
|
+
expected_namespace: expected_namespace,
|
77
|
+
actual_namespace: actual_namespace,
|
78
|
+
expected_path: relative_desired_path
|
79
|
+
)
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# In the future, we'd love this to support auto-correct.
|
86
|
+
# Perhaps by automatically renamespacing the file and changing its location?
|
87
|
+
sig { returns(T::Boolean) }
|
88
|
+
def support_autocorrect?
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
sig { returns(DesiredZeitwerkApi) }
|
95
|
+
def desired_zeitwerk_api
|
96
|
+
@desired_zeitwerk_api ||= T.let(nil, T.nilable(DesiredZeitwerkApi))
|
97
|
+
@desired_zeitwerk_api ||= DesiredZeitwerkApi.new
|
98
|
+
end
|
99
|
+
|
100
|
+
sig { returns(T::Hash[String, String]) }
|
101
|
+
def namespaces_to_packs
|
102
|
+
@namespaces_to_packs = T.let(nil, T.nilable(T::Hash[String, String]))
|
103
|
+
@namespaces_to_packs ||= begin
|
104
|
+
all_packs_enforcing_namespaces = ParsePackwerk.all.select do |p|
|
105
|
+
cop_config['IncludePacks'].include?(p.name)
|
106
|
+
end
|
107
|
+
|
108
|
+
namespaces_to_packs = {}
|
109
|
+
all_packs_enforcing_namespaces.each do |package|
|
110
|
+
namespaces_to_packs[desired_zeitwerk_api.get_pack_based_namespace(package)] = package.name
|
111
|
+
end
|
112
|
+
|
113
|
+
namespaces_to_packs
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
require 'rubocop-sorbet'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Modularization
|
8
|
+
# This cop helps ensure that each pack's public API is strictly typed, enforcing strong boundaries.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# # packs/foo/app/public/foo.rb
|
14
|
+
# # typed: false
|
15
|
+
# module Foo; end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# # packs/foo/app/public/foo.rb
|
19
|
+
# # typed: strict
|
20
|
+
# module Foo; end
|
21
|
+
#
|
22
|
+
class TypedPublicApi < Sorbet::StrictSigil
|
23
|
+
#
|
24
|
+
# This inherits from `Sorbet::StrictSigil` and doesn't change any behavior of it.
|
25
|
+
# The only reason we do this is so that configuration for this cop can live under a different cop namespace.
|
26
|
+
# This prevents this cop's configuration from clashing with other configurations for the same cop.
|
27
|
+
# A concrete example of this would be if a user is using this package protection to make sure public APIs are typed,
|
28
|
+
# and separately the application as a whole requiring strict typing in certain parts of the application.
|
29
|
+
#
|
30
|
+
# To prevent problems associated with needing to manage identical configurations for the same cop, we simply call it
|
31
|
+
# something else in the context of this protection.
|
32
|
+
#
|
33
|
+
# We can apply this same pattern if we want to use other cops in the context of package protections and prevent clashing.
|
34
|
+
#
|
35
|
+
extend T::Sig
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: strict
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
# The original code is from https://github.com/rubocop/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
|
@@ -7,6 +8,9 @@ module RuboCop
|
|
7
8
|
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
8
9
|
# bit of our configuration.
|
9
10
|
module Inject
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { void }
|
10
14
|
def self.defaults!
|
11
15
|
path = CONFIG_DEFAULT.to_s
|
12
16
|
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
@@ -1,14 +1,18 @@
|
|
1
|
+
# typed: strict
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
4
|
+
require 'rubocop/modularization/private'
|
5
|
+
|
3
6
|
module RuboCop
|
4
7
|
module Modularization
|
5
8
|
class Error < StandardError; end
|
9
|
+
extend T::Sig
|
10
|
+
|
6
11
|
# Your code goes here...
|
7
|
-
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
8
|
-
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
|
9
|
-
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
|
12
|
+
PROJECT_ROOT = T.let(Pathname.new(__dir__).parent.parent.expand_path.freeze, Pathname)
|
13
|
+
CONFIG_DEFAULT = T.let(PROJECT_ROOT.join('config', 'default.yml').freeze, Pathname)
|
14
|
+
CONFIG = T.let(YAML.safe_load(CONFIG_DEFAULT.read).freeze, T.untyped)
|
10
15
|
|
11
16
|
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
12
17
|
end
|
13
18
|
end
|
14
|
-
|
@@ -1,10 +1,13 @@
|
|
1
|
+
# typed: strict
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'rubocop'
|
5
|
+
require 'parse_packwerk'
|
4
6
|
|
5
7
|
require_relative 'rubocop/modularization'
|
6
8
|
require_relative 'rubocop/modularization/inject'
|
7
9
|
|
8
|
-
|
10
|
+
require 'rubocop/cop/modularization/namespaced_under_package_name'
|
11
|
+
require 'rubocop/cop/modularization/typed_public_api'
|
9
12
|
|
10
|
-
|
13
|
+
RuboCop::Modularization::Inject.defaults!
|