rubocop-packs 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8dd71f6422be7332808603d1237a03e40a919fd9a49e7f5cc0e2e70ef1543f83
4
- data.tar.gz: f7ec591736305bbe8e8acff73c3abda3efdbf2afd53bfb9b9363182e2b8473bf
3
+ metadata.gz: c6fb879c4fde42e92de3719345a90fd8782cfd9239ec7845869df3ef942ed8b0
4
+ data.tar.gz: 1c2a8ad04b824ed3f5c4a5ea69032164c60057a12a45b8d2d1985b2baaa863c1
5
5
  SHA512:
6
- metadata.gz: 9502ccc3746e1ae9f6ee3801fe78330ece03aad0934729ab33c560c73a4ce226cb7f8e3e0726e8da9509b9495e7e06be991cd927d6709a15601c89dc47178fec
7
- data.tar.gz: e917ea12928f8cf3e8ab20496261fbb0f9672708b4114b0254fb3df96eb0735f6893d7413f19aaf6d181ae0089040e1356d5e6a49fb3190dd9cda7730599edd5
6
+ metadata.gz: 0f628b8204e0124712c8a760bc52c1f5a6b15dafe7f9fa48d6d05d9e40bc0b6e86c46f43441c535936e9182314718e27a4afc33d0a7eed33297f7a14d3317be8
7
+ data.tar.gz: 3d88bf6ee823725ba651add5983792096e59bd7ebe3229028edb03dbb1029002270f96a3cc64d3fa47e6963e7b2b97828f64b0583ff60ee0f1a65920971ff041
data/config/default.yml CHANGED
@@ -23,6 +23,8 @@ Packs/DocumentedPublicApis:
23
23
  Description: 'Requires that each public API method (in `app/public`) has a documentation comment.'
24
24
  Enabled: false
25
25
  VersionAdded: '0.0.2'
26
+ AllowedMethods: []
27
+ RequireForNonPublicMethods: false
26
28
 
27
29
  PackwerkLite/Privacy:
28
30
  Description: 'Detects references to the private implementation of another pack instead of its public API.'
@@ -29,9 +29,7 @@ module RuboCop
29
29
  # end
30
30
  #
31
31
  class ClassMethodsAsPublicApis < Base
32
- extend T::Sig
33
-
34
- sig { params(node: T.untyped).void }
32
+ #: (RuboCop::AST::DefNode node) -> void
35
33
  def on_def(node)
36
34
  # This cop only applies for ruby files in `app/public`
37
35
  return if !processed_source.file_path.include?('app/public/')
@@ -59,7 +57,7 @@ module RuboCop
59
57
 
60
58
  private
61
59
 
62
- sig { params(node: T.untyped).returns(T::Boolean) }
60
+ #: ((RuboCop::AST::ClassNode | RuboCop::AST::ModuleNode)? node) -> bool
63
61
  def node_includes_acceptable_mixin?(node)
64
62
  acceptable_mixins = cop_config['AcceptableMixins'] || []
65
63
  return false if node.nil?
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -30,22 +31,155 @@ module RuboCop
30
31
  # def bar; end
31
32
  # end
32
33
  #
34
+ # # bad - RBS signatures and Sorbet annotations are not documentation
35
+ # # packs/foo/app/public/foo.rb
36
+ # class Foo
37
+ # # @override
38
+ # #: -> void
39
+ # def bar; end
40
+ # end
41
+ #
42
+ # # good
43
+ # # packs/foo/app/public/foo.rb
44
+ # class Foo
45
+ # # This is a documentation comment.
46
+ # # @override
47
+ # #: -> void
48
+ # def bar; end
49
+ # end
50
+ #
51
+ # @example RequireForNonPublicMethods: false (default)
52
+ #
53
+ # # good
54
+ # # packs/foo/app/public/foo.rb
55
+ # class Foo
56
+ # private
57
+ #
58
+ # def bar; end
59
+ # end
60
+ #
61
+ # # good
62
+ # # packs/foo/app/public/foo.rb
63
+ # class Foo
64
+ # protected
65
+ #
66
+ # def bar; end
67
+ # end
68
+ #
69
+ # # good
70
+ # # packs/foo/app/public/foo.rb
71
+ # class Foo
72
+ # def self.bar; end
73
+ # private_class_method :bar
74
+ # end
75
+ #
76
+ # # bad - `private` does not apply to singleton methods, so `bar` is public
77
+ # # packs/foo/app/public/foo.rb
78
+ # class Foo
79
+ # private
80
+ #
81
+ # def self.bar; end
82
+ # end
83
+ #
84
+ # @example RequireForNonPublicMethods: true
85
+ #
86
+ # # bad
87
+ # # packs/foo/app/public/foo.rb
88
+ # class Foo
89
+ # private
90
+ #
91
+ # def bar; end
92
+ # end
93
+ #
94
+ # # bad
95
+ # # packs/foo/app/public/foo.rb
96
+ # class Foo
97
+ # protected
98
+ #
99
+ # def bar; end
100
+ # end
101
+ #
102
+ # # good
103
+ # # packs/foo/app/public/foo.rb
104
+ # class Foo
105
+ # private
106
+ #
107
+ # # This is a documentation comment.
108
+ # def bar; end
109
+ # end
110
+ #
111
+ # # good
112
+ # # packs/foo/app/public/foo.rb
113
+ # class Foo
114
+ # protected
115
+ #
116
+ # # This is a documentation comment.
117
+ # def bar; end
118
+ # end
119
+ #
120
+ # @example AllowedMethods: ['method_missing', 'respond_to_missing?']
121
+ #
122
+ # # good
123
+ # # packs/foo/app/public/foo.rb
124
+ # class Foo
125
+ # def method_missing(name, *args); end
126
+ #
127
+ # def respond_to_missing?(symbol, include_private); end
128
+ # end
129
+ #
130
+ # # bad
131
+ # # packs/foo/app/public/foo.rb
132
+ # class Foo
133
+ # def bar; end
134
+ # end
135
+ #
33
136
  class DocumentedPublicApis < Style::DocumentationMethod
34
137
  # This cop does two things:
35
138
  # 1) It only activates for things in the public folder
36
- # 2) It allows `Style/DocumentationMethod` to work with sigs as expected.
139
+ # 2) It allows `Style/DocumentationMethod` to work with sigs, RBS comment signatures and Sorbet annotations as expected.
37
140
  #
38
141
  # An alternate approach would be to monkey patch the existing cop, as `rubocop-sorbet` did here:
39
142
  # https://github.com/Shopify/rubocop-sorbet/blob/6634f033611604cd76eeb73eae6d8728ec82d504/lib/rubocop/cop/sorbet/mutable_constant_sorbet_aware_behaviour.rb
40
143
  # This monkey-patched cop could/should probably be upstreamed to `rubocop-sorbet`, and then `config/default.yml` could simply set `packs/*/app/public/**/*`
41
144
  # in the default include paths. However, that strategy has the downside of resulting in more configuration for the consumer if they only want to
42
145
  # support this for some packs.
43
- extend T::Sig
44
146
 
45
- sig { params(node: T.untyped).void }
147
+ # The lines of an RBS method signature as Sorbet reads them: `#:` starts one, and `#|` continues a
148
+ # multi-line one. https://sorbet.org/docs/rbs-support
149
+ RBS_SIGNATURE = /\A#[:|]/
150
+
151
+ # The comments Sorbet reads in place of a `sig`'s modifiers, such as `# @override` for `override`,
152
+ # plus `@without_runtime`, which `spoom srb sigs translate` writes for `T::Sig::WithoutRuntime.sig`.
153
+ SORBET_METHOD_ANNOTATIONS = [
154
+ '@abstract',
155
+ '@final',
156
+ '@overridable',
157
+ '@override',
158
+ '@override(allow_incompatible: true)',
159
+ '@override(allow_incompatible: false)',
160
+ '@override(allow_incompatible: :visibility)',
161
+ '@without_runtime',
162
+ ].freeze
163
+
164
+ # rubocop < 1.91 checks AllowedMethods inside `#check`, which this cop
165
+ # overrides. Drop when the gemspec floor is rubocop >= 1.91; until then the
166
+ # minimum-rubocop CI job covers it. Re-alias `on_defs` so it binds to this
167
+ # method, not the parent's.
168
+ #: (RuboCop::AST::DefNode node) -> void
169
+ def on_def(node)
170
+ return if allowed_methods.include?(node.method_name)
171
+
172
+ super
173
+ end
174
+ alias_method :on_defs, :on_def
175
+
176
+ # `node` is the enclosing send for a definition passed to `module_function` or
177
+ # `ruby2_keywords`, and the definition itself otherwise.
178
+ #: ((RuboCop::AST::DefNode | RuboCop::AST::SendNode) node) -> void
46
179
  def check(node)
47
180
  # This cop only applies for ruby files in `app/public`
48
181
  return if !processed_source.file_path.include?('app/public')
182
+ return if non_public_method?(node) && !require_for_non_public_methods?
49
183
 
50
184
  left_sibling = node.left_sibling
51
185
 
@@ -67,19 +201,77 @@ module RuboCop
67
201
  add_offense(node)
68
202
  end
69
203
 
70
- sig { params(node: T.untyped).returns(T::Boolean) }
204
+ # `DefNode#non_public?` treats a singleton method after a bare `private` or `protected`
205
+ # as non-public, but those only change the visibility of instance methods. A singleton
206
+ # method is non-public only when `private_class_method` wraps it or later names it.
207
+ #: ((RuboCop::AST::DefNode | RuboCop::AST::SendNode) node) -> bool
208
+ def non_public_method?(node)
209
+ if node.is_a?(RuboCop::AST::DefNode) && node.defs_type?
210
+ non_public_modifier?(node.parent) || made_private_after_definition?(node)
211
+ else
212
+ non_public?(node)
213
+ end
214
+ end
215
+
216
+ #: (RuboCop::AST::DefNode node) -> bool
217
+ def made_private_after_definition?(node)
218
+ node.right_siblings.any? do |sibling|
219
+ sibling.is_a?(RuboCop::AST::SendNode) &&
220
+ (sibling.receiver.nil? || sibling.receiver.self_type?) &&
221
+ sibling.method?(:private_class_method) &&
222
+ sibling.arguments.any? do |argument|
223
+ argument.is_a?(RuboCop::AST::SymbolNode) && argument.value == node.method_name
224
+ end
225
+ end
226
+ end
227
+
228
+ #: (top node) -> bool
71
229
  def node_is_sorbet_signature?(node)
72
- # A sibling is not necessarily an AST node. It is a `Symbol` when a method definition is
73
- # passed to a modifier, such as the `:private` in `private def foo`.
74
- return false if !node.is_a?(RuboCop::AST::Node)
230
+ case node
231
+ when RuboCop::AST::Node
232
+ # A node's `source` is `nil` when it has no source range. That is the case for the empty
233
+ # `args` node of a block written without parameters, as in `Struct.new(:a) do ... end`,
234
+ # which is the left sibling of a method defined as the block's only statement.
235
+ node_source = node.source
236
+
237
+ # Is there a better way to check if a node is a sorbet signature? Probably!
238
+ !!(node_source && (node_source.include?('sig do') || node_source.include?('sig {')))
239
+ else
240
+ # A sibling is not necessarily an AST node. It is a `Symbol` when a method definition is
241
+ # passed to a modifier, such as the `:private` in `private def foo`.
242
+ false
243
+ end
244
+ end
75
245
 
76
- # A node's `source` is `nil` when it has no source range. That is the case for the empty
77
- # `args` node of a block written without parameters, as in `Struct.new(:a) do ... end`,
78
- # which is the left sibling of a method defined as the block's only statement.
79
- node_source = node.source
246
+ # A copy of `RuboCop::Cop::DocumentationComment#documentation_comment?` with two changes. Like the
247
+ # original, it ignores annotation keywords (`# TODO:`) and directives (`# rubocop:disable`), and it
248
+ # also ignores RBS comments, which, like a `sig`, are not documentation. And it reads only the
249
+ # comments directly above the method: the original accepts any comment above a method once one is
250
+ # adjacent, which an RBS signature always is, so a section heading a blank line above would count.
251
+ #: (RuboCop::AST::Node node) -> bool
252
+ def documentation_comment?(node)
253
+ preceding_lines = preceding_lines(node)
254
+
255
+ return false unless preceding_comment?(node, preceding_lines.last)
256
+
257
+ adjacent_comments(preceding_lines).any? do |comment|
258
+ !AnnotationComment.new(comment, annotation_keywords).annotation? &&
259
+ !interpreter_directive_comment?(comment) &&
260
+ !rubocop_directive_comment?(comment) &&
261
+ !rbs_comment?(comment)
262
+ end
263
+ end
264
+
265
+ # The unbroken run of `comments` that ends with the last one, from the bottom up.
266
+ #: (Array[Parser::Source::Comment] comments) -> Array[Parser::Source::Comment]
267
+ def adjacent_comments(comments)
268
+ comments.reverse.chunk_while { |below, above| below.loc.line - above.loc.last_line == 1 }.first.to_a
269
+ end
80
270
 
81
- # Is there a better way to check if a node is a sorbet signature? Probably!
82
- !!(node_source && (node_source.include?('sig do') || node_source.include?('sig {')))
271
+ #: (Parser::Source::Comment comment) -> bool
272
+ def rbs_comment?(comment)
273
+ comment.text.match?(RBS_SIGNATURE) ||
274
+ SORBET_METHOD_ANNOTATIONS.include?(comment.text.delete_prefix('#').strip)
83
275
  end
84
276
  end
85
277
  end
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -10,13 +11,26 @@ module RuboCop
10
11
  # that would need to be separated prior to proposing any API changes in zeitwerk.
11
12
  #
12
13
  class DesiredZeitwerkApi
13
- extend T::Sig
14
+ class NamespaceContext
15
+ #: String
16
+ attr_reader :current_namespace
14
17
 
15
- class NamespaceContext < T::Struct
16
- const :current_namespace, String
17
- const :current_fully_qualified_constant, String
18
- const :expected_namespace, String
19
- const :expected_filepath, String
18
+ #: String
19
+ attr_reader :current_fully_qualified_constant
20
+
21
+ #: String
22
+ attr_reader :expected_namespace
23
+
24
+ #: String
25
+ attr_reader :expected_filepath
26
+
27
+ #: (current_namespace: String, current_fully_qualified_constant: String, expected_namespace: String, expected_filepath: String) -> void
28
+ def initialize(current_namespace:, current_fully_qualified_constant:, expected_namespace:, expected_filepath:)
29
+ @current_namespace = current_namespace
30
+ @current_fully_qualified_constant = current_fully_qualified_constant
31
+ @expected_namespace = expected_namespace
32
+ @expected_filepath = expected_filepath
33
+ end
20
34
  end
21
35
 
22
36
  #
@@ -28,7 +42,7 @@ module RuboCop
28
42
  # Likely this means that our own cop should determine the desired namespace and pass that in
29
43
  # and this can determine actual namespace and how to get to expected.
30
44
  #
31
- sig { params(relative_filename: String, package_for_path: ::Packs::Pack).returns(T.nilable(NamespaceContext)) }
45
+ #: (String relative_filename, ::Packs::Pack package_for_path) -> NamespaceContext?
32
46
  def for_file(relative_filename, package_for_path)
33
47
  package_name = package_for_path.name
34
48
 
@@ -52,22 +66,25 @@ module RuboCop
52
66
  if path_without_package_base.include?('/concerns/')
53
67
  autoload_folder_name = path_without_package_base.split('/').first(2).join('/')
54
68
  else
55
- autoload_folder_name = path_without_package_base.split('/').first
69
+ autoload_folder_name = path_without_package_base.split('/').fetch(0)
56
70
  end
57
71
 
58
72
  remaining_file_path = path_without_package_base.gsub(%r(\A#{autoload_folder_name}/), '')
59
73
  actual_namespace = get_actual_namespace(remaining_file_path, package_name)
60
74
 
61
- if relative_filename.include?('app/')
62
- app_or_lib = 'app'
63
- elsif relative_filename.include?('lib/')
64
- app_or_lib = 'lib'
65
- end
75
+ app_or_lib =
76
+ if relative_filename.include?('app/')
77
+ 'app'
78
+ elsif relative_filename.include?('lib/')
79
+ 'lib'
80
+ else
81
+ raise ArgumentError, "#{relative_filename} is in neither app/ nor lib/"
82
+ end
66
83
 
67
84
  absolute_desired_path = root_pathname.join(
68
85
  package_name,
69
- T.must(app_or_lib),
70
- T.must(autoload_folder_name),
86
+ app_or_lib,
87
+ autoload_folder_name,
71
88
  package_for_path.last_name,
72
89
  remaining_file_path
73
90
  )
@@ -75,26 +92,26 @@ module RuboCop
75
92
  relative_desired_path = absolute_desired_path.relative_path_from(root_pathname)
76
93
 
77
94
  NamespaceContext.new(
78
- current_namespace: T.must(actual_namespace.split('::').first),
95
+ current_namespace: actual_namespace.split('::').fetch(0),
79
96
  current_fully_qualified_constant: actual_namespace,
80
97
  expected_namespace: get_pack_based_namespace(package_for_path),
81
98
  expected_filepath: relative_desired_path.to_s
82
99
  )
83
100
  end
84
101
 
85
- sig { params(pack: ::Packs::Pack).returns(String) }
102
+ #: (::Packs::Pack pack) -> String
86
103
  def get_pack_based_namespace(pack)
87
104
  pack.last_name.camelize
88
105
  end
89
106
 
90
107
  private
91
108
 
92
- sig { returns(Pathname) }
109
+ #: -> Pathname
93
110
  def root_pathname
94
111
  Pathname.pwd
95
112
  end
96
113
 
97
- sig { params(remaining_file_path: String, package_name: String).returns(String) }
114
+ #: (String remaining_file_path, String package_name) -> String
98
115
  def get_actual_namespace(remaining_file_path, package_name)
99
116
  # If the remaining file path is a ruby file (not a directory), then it establishes a global namespace
100
117
  # Otherwise, per Zeitwerk's conventions as listed above, its a directory that establishes another global namespace
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  # For String#camelize
4
5
  require 'active_support/core_ext/string/inflections'
@@ -24,11 +25,9 @@ module RuboCop
24
25
  # class Foo::Blah::Bar; end
25
26
  #
26
27
  class RootNamespaceIsPackName < Base
27
- extend T::Sig
28
-
29
28
  include RangeHelp
30
29
 
31
- sig { void }
30
+ #: -> void
32
31
  def on_new_investigation
33
32
  absolute_filepath = Pathname.new(processed_source.file_path)
34
33
  relative_filepath = absolute_filepath.relative_path_from(Pathname.pwd)
@@ -83,10 +82,9 @@ module RuboCop
83
82
 
84
83
  private
85
84
 
86
- sig { returns(DesiredZeitwerkApi) }
85
+ #: -> DesiredZeitwerkApi
87
86
  def desired_zeitwerk_api
88
- @desired_zeitwerk_api ||= T.let(nil, T.nilable(DesiredZeitwerkApi))
89
- @desired_zeitwerk_api ||= DesiredZeitwerkApi.new
87
+ @desired_zeitwerk_api ||= DesiredZeitwerkApi.new #: DesiredZeitwerkApi?
90
88
  end
91
89
  end
92
90
  end
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'rubocop-sorbet'
4
5
 
@@ -32,9 +33,8 @@ module RuboCop
32
33
  #
33
34
  # We can apply this same pattern if we want to use other cops in the context of package protections and prevent clashing.
34
35
  #
35
- extend T::Sig
36
36
 
37
- sig { void }
37
+ #: -> void
38
38
  def on_new_investigation
39
39
  return unless processed_source.path.include?('app/public')
40
40
 
@@ -1,4 +1,8 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # For String#underscore
5
+ require 'active_support/core_ext/string/inflections'
2
6
 
3
7
  module RuboCop
4
8
  module Cop
@@ -9,23 +13,37 @@ module RuboCop
9
13
  # that would need to be separated prior to proposing any API changes in zeitwerk.
10
14
  #
11
15
  class ConstantResolver
12
- extend T::Sig
16
+ class ConstantReference
17
+ #: String
18
+ attr_reader :constant_name
19
+
20
+ #: String
21
+ attr_reader :global_namespace
22
+
23
+ #: ParsePackwerk::Package
24
+ attr_reader :source_package
13
25
 
14
- class ConstantReference < T::Struct
15
- extend T::Sig
26
+ #: Pathname
27
+ attr_reader :constant_definition_location
16
28
 
17
- const :constant_name, String
18
- const :global_namespace, String
19
- const :source_package, ParsePackwerk::Package
20
- const :constant_definition_location, Pathname
21
- const :referencing_file, Pathname
29
+ #: Pathname
30
+ attr_reader :referencing_file
31
+
32
+ #: (constant_name: String, global_namespace: String, source_package: ParsePackwerk::Package, constant_definition_location: Pathname, referencing_file: Pathname) -> void
33
+ def initialize(constant_name:, global_namespace:, source_package:, constant_definition_location:, referencing_file:)
34
+ @constant_name = constant_name
35
+ @global_namespace = global_namespace
36
+ @source_package = source_package
37
+ @constant_definition_location = constant_definition_location
38
+ @referencing_file = referencing_file
39
+ end
22
40
 
23
- sig { returns(ParsePackwerk::Package) }
41
+ #: -> ParsePackwerk::Package
24
42
  def referencing_package
25
43
  ParsePackwerk.package_from_path(referencing_file)
26
44
  end
27
45
 
28
- sig { returns(T::Boolean) }
46
+ #: -> bool
29
47
  def public_api?
30
48
  # PackwerkExtensions should have a method to take in a path and determine if the file is public.
31
49
  # For now, we put it here and only support the public folder (and not specific private constants).
@@ -33,7 +51,7 @@ module RuboCop
33
51
  constant_definition_location.to_s.include?('/public/')
34
52
  end
35
53
 
36
- sig { params(node: RuboCop::AST::ConstNode, processed_source: RuboCop::AST::ProcessedSource).returns(T.nilable(ConstantReference)) }
54
+ #: (RuboCop::AST::ConstNode node, RuboCop::AST::ProcessedSource processed_source) -> ConstantReference?
37
55
  def self.resolve(node, processed_source)
38
56
  constant_name = node.const_name
39
57
  namespaces = constant_name.split('::')
@@ -68,13 +86,13 @@ module RuboCop
68
86
 
69
87
  return if !expected_pack_contains_constant
70
88
 
71
- found_file = found_files.first
89
+ found_file = found_files.fetch(0)
72
90
 
73
91
  ConstantReference.new(
74
92
  constant_name:,
75
93
  global_namespace:,
76
94
  source_package: expected_containing_pack,
77
- constant_definition_location: T.must(found_file),
95
+ constant_definition_location: found_file,
78
96
  referencing_file: Pathname.new(processed_source.path).relative_path_from(Pathname.pwd)
79
97
  )
80
98
  end
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -37,9 +38,7 @@ module RuboCop
37
38
  # # - packs/bar
38
39
  #
39
40
  class Dependency < Base
40
- extend T::Sig
41
-
42
- sig { params(node: RuboCop::AST::ConstNode).void }
41
+ #: (RuboCop::AST::ConstNode node) -> void
43
42
  def on_const(node)
44
43
  return if Private.partial_const_reference?(node)
45
44
 
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -38,9 +39,7 @@ module RuboCop
38
39
  # end
39
40
  #
40
41
  class Privacy < Base
41
- extend T::Sig
42
-
43
- sig { params(node: RuboCop::AST::ConstNode).void }
42
+ #: (RuboCop::AST::ConstNode node) -> void
44
43
  def on_const(node)
45
44
  # See https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/lint/constant_resolution.rb source code as an example
46
45
  return if Private.partial_const_reference?(node)
@@ -1,12 +1,11 @@
1
1
  # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
5
6
  module PackwerkLite
6
7
  module Private
7
- extend T::Sig
8
-
9
- sig { params(node: RuboCop::AST::ConstNode).returns(T::Boolean) }
8
+ #: (RuboCop::AST::ConstNode node) -> bool
10
9
  def self.partial_const_reference?(node)
11
10
  # This is a bit whacky, but if I have a reference in the code like this: Foo::Bar::Baz.any_method, `on_const` will be called three times:
12
11
  # One with `Foo`, one with `Foo::Bar`, and one with `Foo::Bar::Baz`.
@@ -23,7 +22,7 @@ module RuboCop
23
22
  right_sibling.to_s[0].capitalize == right_sibling.to_s[0]
24
23
  end
25
24
 
26
- sig { params(constant_reference: ConstantResolver::ConstantReference, type: String).returns(T::Boolean) }
25
+ #: (ConstantResolver::ConstantReference constant_reference, ?type: String) -> bool
27
26
  def self.violation_in_package_todo_yml?(constant_reference, type: 'privacy')
28
27
  existing_violations = ParsePackwerk::PackageTodo.for(constant_reference.referencing_package).violations
29
28
  existing_violations.any? do |v|
@@ -7,9 +7,7 @@ module RuboCop
7
7
  module Packs
8
8
  # A plugin that integrates rubocop-packs with RuboCop's plugin system.
9
9
  class Plugin < LintRoller::Plugin
10
- extend T::Sig
11
-
12
- sig { returns(LintRoller::About) }
10
+ #: -> LintRoller::About
13
11
  def about
14
12
  LintRoller::About.new(
15
13
  name: 'rubocop-packs',
@@ -19,12 +17,12 @@ module RuboCop
19
17
  )
20
18
  end
21
19
 
22
- sig { params(context: LintRoller::Context).returns(T::Boolean) }
20
+ #: (LintRoller::Context context) -> bool
23
21
  def supported?(context)
24
22
  context.engine == :rubocop
25
23
  end
26
24
 
27
- sig { params(_context: LintRoller::Context).returns(LintRoller::Rules) }
25
+ #: (LintRoller::Context _context) -> LintRoller::Rules
28
26
  def rules(_context)
29
27
  LintRoller::Rules.new(
30
28
  type: :path,
@@ -5,17 +5,15 @@ module RuboCop
5
5
  module Packs
6
6
  module Private
7
7
  class Configuration
8
- extend T::Sig
9
-
10
- sig { returns(T::Array[String]) }
8
+ #: Array[String]
11
9
  attr_accessor :globally_permitted_namespaces
12
10
 
13
- sig { void }
11
+ #: -> void
14
12
  def initialize
15
- @globally_permitted_namespaces = T.let([], T::Array[String])
13
+ @globally_permitted_namespaces = [] #: Array[String]
16
14
  end
17
15
 
18
- sig { void }
16
+ #: -> void
19
17
  def bust_cache!
20
18
  @globally_permitted_namespaces = []
21
19
  end
@@ -2,21 +2,18 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'rubocop/packs/private/configuration'
5
- require 'rubocop/packs/private/offense'
6
5
 
7
6
  module RuboCop
8
7
  module Packs
9
8
  module Private
10
- extend T::Sig
11
-
12
- sig { void }
9
+ #: -> void
13
10
  def self.bust_cache!
14
11
  @loaded_client_configuration = nil
15
12
  end
16
13
 
17
- sig { void }
14
+ #: -> void
18
15
  def self.load_client_configuration
19
- @loaded_client_configuration ||= T.let(false, T.nilable(T::Boolean))
16
+ @loaded_client_configuration ||= false #: bool?
20
17
  return if @loaded_client_configuration
21
18
 
22
19
  @loaded_client_configuration = true
@@ -1,8 +1,8 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RuboCop
5
5
  module Packs
6
- VERSION = '0.1.0'
6
+ VERSION = '0.1.1'
7
7
  end
8
8
  end
data/lib/rubocop/packs.rb CHANGED
@@ -5,23 +5,21 @@ require 'rubocop/packs/private'
5
5
 
6
6
  module RuboCop
7
7
  module Packs
8
- extend T::Sig
9
-
10
- sig { void }
8
+ #: -> void
11
9
  def self.bust_cache!
12
10
  config.bust_cache!
13
11
  Private.bust_cache!
14
12
  end
15
13
 
16
- sig { params(blk: T.proc.params(arg0: Private::Configuration).void).void }
14
+ #: { (Private::Configuration arg0) -> void } -> void
17
15
  def self.configure(&blk)
18
16
  yield(config)
19
17
  end
20
18
 
21
- sig { returns(Private::Configuration) }
19
+ #: -> Private::Configuration
22
20
  def self.config
23
21
  Private.load_client_configuration
24
- @config ||= T.let(Private::Configuration.new, T.nilable(Private::Configuration))
22
+ @config ||= Private::Configuration.new #: Private::Configuration?
25
23
  end
26
24
  end
27
25
  end
@@ -11,6 +11,5 @@ module RuboCop
11
11
  # See docs/packwerk_lite.md
12
12
  module PackwerkLite
13
13
  class Error < StandardError; end
14
- extend T::Sig
15
14
  end
16
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-packs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gusto Engineers
@@ -15,54 +15,26 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0'
26
- - !ruby/object:Gem::Dependency
27
- name: base64
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '0'
18
+ version: '7.1'
33
19
  type: :runtime
34
20
  prerelease: false
35
21
  version_requirements: !ruby/object:Gem::Requirement
36
22
  requirements:
37
23
  - - ">="
38
24
  - !ruby/object:Gem::Version
39
- version: '0'
40
- - !ruby/object:Gem::Dependency
41
- name: bigdecimal
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: '0'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '0'
25
+ version: '7.1'
54
26
  - !ruby/object:Gem::Dependency
55
27
  name: lint_roller
56
28
  requirement: !ruby/object:Gem::Requirement
57
29
  requirements:
58
- - - "~>"
30
+ - - ">="
59
31
  - !ruby/object:Gem::Version
60
32
  version: '1.1'
61
33
  type: :runtime
62
34
  prerelease: false
63
35
  version_requirements: !ruby/object:Gem::Requirement
64
36
  requirements:
65
- - - "~>"
37
+ - - ">="
66
38
  - !ruby/object:Gem::Version
67
39
  version: '1.1'
68
40
  - !ruby/object:Gem::Dependency
@@ -97,14 +69,14 @@ dependencies:
97
69
  name: rubocop
98
70
  requirement: !ruby/object:Gem::Requirement
99
71
  requirements:
100
- - - "~>"
72
+ - - ">="
101
73
  - !ruby/object:Gem::Version
102
74
  version: '1.72'
103
75
  type: :runtime
104
76
  prerelease: false
105
77
  version_requirements: !ruby/object:Gem::Requirement
106
78
  requirements:
107
- - - "~>"
79
+ - - ">="
108
80
  - !ruby/object:Gem::Version
109
81
  version: '1.72'
110
82
  - !ruby/object:Gem::Dependency
@@ -121,20 +93,6 @@ dependencies:
121
93
  - - ">="
122
94
  - !ruby/object:Gem::Version
123
95
  version: 0.9.0
124
- - !ruby/object:Gem::Dependency
125
- name: sorbet-runtime
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - ">="
129
- - !ruby/object:Gem::Version
130
- version: '0'
131
- type: :runtime
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - ">="
136
- - !ruby/object:Gem::Version
137
- version: '0'
138
96
  - !ruby/object:Gem::Dependency
139
97
  name: bundler
140
98
  requirement: !ruby/object:Gem::Requirement
@@ -181,14 +139,14 @@ dependencies:
181
139
  name: rspec
182
140
  requirement: !ruby/object:Gem::Requirement
183
141
  requirements:
184
- - - "~>"
142
+ - - ">="
185
143
  - !ruby/object:Gem::Version
186
144
  version: '3.0'
187
145
  type: :development
188
146
  prerelease: false
189
147
  version_requirements: !ruby/object:Gem::Requirement
190
148
  requirements:
191
- - - "~>"
149
+ - - ">="
192
150
  - !ruby/object:Gem::Version
193
151
  version: '3.0'
194
152
  - !ruby/object:Gem::Dependency
@@ -298,7 +256,6 @@ files:
298
256
  - lib/rubocop/packs/plugin.rb
299
257
  - lib/rubocop/packs/private.rb
300
258
  - lib/rubocop/packs/private/configuration.rb
301
- - lib/rubocop/packs/private/offense.rb
302
259
  - lib/rubocop/packs/version.rb
303
260
  - lib/rubocop/packwerk_lite.rb
304
261
  homepage: https://github.com/rubyatscale/rubocop-packs
@@ -1,19 +0,0 @@
1
- # typed: strict
2
-
3
- module RuboCop
4
- module Packs
5
- module Private
6
- class Offense < T::Struct
7
- extend T::Sig
8
-
9
- const :cop_name, String
10
- const :filepath, String
11
-
12
- sig { returns(T.nilable(::Packs::Pack)) }
13
- def pack
14
- ::Packs.for_file(filepath)
15
- end
16
- end
17
- end
18
- end
19
- end