rubocop-modularization 0.0.1 → 0.0.3
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/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!
|