rubocop-sorbet 0.3.2 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7baa291ded0aa343c64c841b2d03cf91d52ad07071883a680f8b725297d0d8e9
4
- data.tar.gz: 95e36584da91cccee6423d2d65fcc061ea74e1abfc51c4c5fb1a18f8b1878e62
3
+ metadata.gz: c8e5d981eb3753f8e4a5599105ffca85878383e8c9babe36126529d13408c578
4
+ data.tar.gz: 19162fbc227c9d40774bec276129f739ee885201bb688b74cd3a7901253770ac
5
5
  SHA512:
6
- metadata.gz: 2d3772bb095eed330fbab2f2ff723f932bc4b40a175738532e043c6fbb66c9c2116a9435b4b210cf2b0f59dc3b8be889da976293db38f6e42f583be9dd8ddb26
7
- data.tar.gz: 04a54d3d285223f71d48f4a164ec69124ce9b45d74eba3c7232abd6388e9638acb3e8fada94f2f88533432e51077d03952037d1828850261e623797dacd7b9a5
6
+ metadata.gz: fd590134345de1400d2c653b263d2b0936aa1f02f6e199fc5d2f65eca50b37aef77df4d4463afe403ca7ba3f795dd389a72164d62c796dc943fb108e4eef76df
7
+ data.tar.gz: 4b5caba384adc3a2b45e8532cd1dba357bf7404d577da3a24defb9279a903a7b1c02bb1efdd28571517cab33ba3fa01dde88b1319da8cd8d051ecb308cd9d8b5
@@ -6,7 +6,6 @@ inherit_from:
6
6
  AllCops:
7
7
  TargetRubyVersion: 2.5
8
8
  Exclude:
9
- - lib/waffle_cone/rbi_compilers/yard_type_parser.rb
10
9
  - vendor/**/*
11
10
 
12
11
  Naming/AccessorMethodName:
@@ -19,9 +18,6 @@ Naming/FileName:
19
18
  Exclude:
20
19
  - lib/rubocop-sorbet.rb
21
20
 
22
- Style/StringLiterals:
23
- EnforcedStyle: single_quotes
24
-
25
21
  Lint/HandleExceptions:
26
22
  Exclude:
27
23
  - Rakefile
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorbet (0.3.2)
4
+ rubocop-sorbet (0.3.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,3 +1,3 @@
1
- Sorbet/ValidSorbetSigil:
1
+ Sorbet/ValidSigil:
2
2
  Enabled: true
3
3
  EnforcedStyle: typed_files
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require_relative 'has_sigil'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop makes the Sorbet `false` sigil mandatory in all files.
10
+ class FalseSigil < HasSigil
11
+ def minimum_strictness
12
+ 'false'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require_relative 'valid_sigil'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop makes the Sorbet typed sigil mandatory in all files.
10
+ #
11
+ # Options:
12
+ #
13
+ # * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
14
+ # * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
15
+ #
16
+ # If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
17
+ class HasSigil < ValidSigil
18
+ @registry = Cop.registry # So we can properly subclass this cop
19
+
20
+ def require_sigil_on_all_files?
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require_relative 'has_sigil'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop makes the Sorbet `ignore` sigil mandatory in all files.
10
+ class IgnoreSigil < HasSigil
11
+ def minimum_strictness
12
+ 'ignore'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require_relative 'has_sigil'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop makes the Sorbet `strict` sigil mandatory in all files.
10
+ class StrictSigil < HasSigil
11
+ def minimum_strictness
12
+ 'strict'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require_relative 'has_sigil'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop makes the Sorbet `strong` sigil mandatory in all files.
10
+ class StrongSigil < HasSigil
11
+ def minimum_strictness
12
+ 'strong'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require_relative 'has_sigil'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop makes the Sorbet `true` sigil mandatory in all files.
10
+ class TrueSigil < HasSigil
11
+ def minimum_strictness
12
+ 'true'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Sorbet
8
+ # This cop checks that every Ruby file contains a valid Sorbet sigil.
9
+ # Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52
10
+ #
11
+ # Options:
12
+ #
13
+ # * `RequireSigilOnAllFiles`: make offense if the Sorbet typed is not found in the file (default: false)
14
+ # * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
15
+ # * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
16
+ #
17
+ # If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
18
+ class ValidSigil < RuboCop::Cop::Cop
19
+ @registry = Cop.registry # So we can properly subclass this cop
20
+
21
+ def investigate(processed_source)
22
+ return if processed_source.tokens.empty?
23
+
24
+ sigil = extract_sigil(processed_source)
25
+ return unless check_sigil_present(sigil)
26
+
27
+ strictness = extract_strictness(sigil)
28
+ return unless check_strictness_not_empty(sigil, strictness)
29
+ return unless check_strictness_valid(sigil, strictness)
30
+ return unless check_strictness_level(sigil, strictness)
31
+ end
32
+
33
+ def autocorrect(_node)
34
+ lambda do |corrector|
35
+ return unless require_sigil_on_all_files?
36
+ return unless extract_sigil(processed_source).nil?
37
+
38
+ token = processed_source.tokens.first
39
+ corrector.insert_before(token.pos, "# typed: #{minimum_strictness || suggested_strictness}\n")
40
+ end
41
+ end
42
+
43
+ protected
44
+
45
+ STRICTNESS_LEVELS = %w(ignore false true strict strong)
46
+ SIGIL_REGEX = /#\s+typed:(?:\s+([\w]+))?/
47
+
48
+ # extraction
49
+
50
+ def extract_sigil(processed_source)
51
+ processed_source.tokens
52
+ .take_while { |token| token.type == :tCOMMENT }
53
+ .find { |token| SIGIL_REGEX.match?(token.text) }
54
+ end
55
+
56
+ def extract_strictness(sigil)
57
+ sigil.text.match(SIGIL_REGEX)&.captures&.first
58
+ end
59
+
60
+ # checks
61
+
62
+ def check_sigil_present(sigil)
63
+ return true unless sigil.nil?
64
+
65
+ token = processed_source.tokens.first
66
+ if require_sigil_on_all_files?
67
+ strictness = minimum_strictness || suggested_strictness
68
+ add_offense(
69
+ token,
70
+ location: token.pos,
71
+ message: 'No Sorbet sigil found in file. ' \
72
+ "Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this)."
73
+ )
74
+ end
75
+ false
76
+ end
77
+
78
+ def check_strictness_not_empty(sigil, strictness)
79
+ return true if strictness
80
+
81
+ add_offense(
82
+ sigil,
83
+ location: sigil.pos,
84
+ message: 'Sorbet sigil should not be empty.'
85
+ )
86
+ false
87
+ end
88
+
89
+ def check_strictness_valid(sigil, strictness)
90
+ return true if STRICTNESS_LEVELS.include?(strictness)
91
+
92
+ add_offense(
93
+ sigil,
94
+ location: sigil.pos,
95
+ message: "Invalid Sorbet sigil `#{strictness}`."
96
+ )
97
+ false
98
+ end
99
+
100
+ def check_strictness_level(sigil, strictness)
101
+ return true unless minimum_strictness
102
+
103
+ minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
104
+ current_level = STRICTNESS_LEVELS.index(strictness)
105
+ if current_level < minimum_level
106
+ add_offense(
107
+ sigil,
108
+ location: sigil.pos,
109
+ message: "Sorbet sigil should be at least `#{minimum_strictness}` got `#{strictness}`."
110
+ )
111
+ return false
112
+ end
113
+ true
114
+ end
115
+
116
+ # options
117
+
118
+ # Default is `false`
119
+ def require_sigil_on_all_files?
120
+ !!cop_config['RequireSigilOnAllFiles']
121
+ end
122
+
123
+ # Default is `'false'`
124
+ def suggested_strictness
125
+ cop_config['SuggestedStrictness'] || 'false'
126
+ end
127
+
128
+ # Default is `nil`
129
+ def minimum_strictness
130
+ cop_config['MinimumStrictness']
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -9,4 +9,11 @@ require_relative 'rubocop/cop/sorbet/forbid_superclass_const_literal'
9
9
  require_relative 'rubocop/cop/sorbet/forbid_include_const_literal'
10
10
  require_relative 'rubocop/cop/sorbet/parameters_ordering_in_signature'
11
11
  require_relative 'rubocop/cop/sorbet/keyword_argument_ordering'
12
- require_relative 'rubocop/cop/sorbet/valid_sorbet_sigil'
12
+
13
+ require_relative 'rubocop/cop/sorbet/sigils/valid_sigil'
14
+ require_relative 'rubocop/cop/sorbet/sigils/has_sigil'
15
+ require_relative 'rubocop/cop/sorbet/sigils/ignore_sigil'
16
+ require_relative 'rubocop/cop/sorbet/sigils/false_sigil'
17
+ require_relative 'rubocop/cop/sorbet/sigils/true_sigil'
18
+ require_relative 'rubocop/cop/sorbet/sigils/strict_sigil'
19
+ require_relative 'rubocop/cop/sorbet/sigils/strong_sigil'
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'rubocop-sorbet'
8
- spec.version = '0.3.2'
8
+ spec.version = '0.3.3'
9
9
  spec.authors = ['Ufuk Kayserilioglu', 'Alan Wu', 'Alexandre Terrasa', 'Peter Zhu']
10
10
  spec.email = ['ruby@shopify.com']
11
11
 
@@ -0,0 +1,6 @@
1
+ # https://services.shopify.io/services/rubocop-sorbet/production
2
+ owners:
3
+ - Shopify/sorbet
4
+ classification: library
5
+ slack_channels:
6
+ - sorbet
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-sorbet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2019-09-18 00:00:00.000000000 Z
14
+ date: 2019-10-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rspec
@@ -88,10 +88,17 @@ files:
88
88
  - lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb
89
89
  - lib/rubocop/cop/sorbet/keyword_argument_ordering.rb
90
90
  - lib/rubocop/cop/sorbet/parameters_ordering_in_signature.rb
91
+ - lib/rubocop/cop/sorbet/sigils/false_sigil.rb
92
+ - lib/rubocop/cop/sorbet/sigils/has_sigil.rb
93
+ - lib/rubocop/cop/sorbet/sigils/ignore_sigil.rb
94
+ - lib/rubocop/cop/sorbet/sigils/strict_sigil.rb
95
+ - lib/rubocop/cop/sorbet/sigils/strong_sigil.rb
96
+ - lib/rubocop/cop/sorbet/sigils/true_sigil.rb
97
+ - lib/rubocop/cop/sorbet/sigils/valid_sigil.rb
91
98
  - lib/rubocop/cop/sorbet/signature_build_order.rb
92
- - lib/rubocop/cop/sorbet/valid_sorbet_sigil.rb
93
99
  - lib/rubocop_sorbet.rb
94
100
  - rubocop-sorbet.gemspec
101
+ - service.yml
95
102
  - shipit.yml
96
103
  homepage: https://github.com/shopify/rubocop-sorbet
97
104
  licenses:
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rubocop'
4
-
5
- module RuboCop
6
- module Cop
7
- module Sorbet
8
- # This cop checks that every Ruby file contains a valid Sorbet sigil.
9
- # Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52
10
- #
11
- # @example RequireSigilOnAllFiles: false (default)
12
- #
13
- # # bad
14
- # # (start of file)
15
- # # typed: no
16
- #
17
- # # good
18
- # # (start of file)
19
- # class Foo; end
20
- #
21
- # # good
22
- # # (start of file)
23
- # # typed: true
24
- #
25
- # @example RequireSigilOnAllFiles: true
26
- #
27
- # # bad
28
- # # (start of file)
29
- # class Foo; end
30
- #
31
- # # bad
32
- # # (start of file)
33
- # # typed: no
34
- #
35
- # # good
36
- # # (start of file)
37
- # # typed: true
38
- class ValidSorbetSigil < RuboCop::Cop::Cop
39
- def investigate(processed_source)
40
- return if processed_source.tokens.empty?
41
-
42
- sorbet_sigil_line = sorbet_typed_sigil_comment(processed_source)
43
-
44
- if sorbet_sigil_line.nil?
45
- token = processed_source.tokens.first
46
-
47
- if require_sorbet_sigil_on_all_files?
48
- add_offense(
49
- token,
50
- location: token.pos,
51
- message: 'No Sorbet sigil found in file. ' \
52
- 'Try a `typed: false` to start (you can also use `rubocop -a` to automatically add this).'
53
- )
54
- end
55
- else
56
- strictness = sorbet_typed_strictness(sorbet_sigil_line)
57
- return if valid_sorbet_strictness?(strictness)
58
-
59
- add_offense(
60
- sorbet_sigil_line,
61
- location: sorbet_sigil_line.pos,
62
- message: "Invalid Sorbet sigil `#{strictness}`."
63
- )
64
- end
65
- end
66
-
67
- def autocorrect(_node)
68
- lambda do |corrector|
69
- return unless require_sorbet_sigil_on_all_files?
70
- return unless sorbet_typed_sigil_comment(processed_source).nil?
71
-
72
- token = processed_source.tokens.first
73
-
74
- corrector.insert_before(token.pos, "# typed: false\n")
75
- end
76
- end
77
-
78
- private
79
-
80
- def require_sorbet_sigil_on_all_files?
81
- !!cop_config['RequireSigilOnAllFiles']
82
- end
83
-
84
- SORBET_SIGIL_REGEX = /#\s+typed:\s+([\w]+)/
85
-
86
- def sorbet_typed_sigil_comment(processed_source)
87
- processed_source.tokens
88
- .take_while { |token| token.type == :tCOMMENT }
89
- .find { |token| SORBET_SIGIL_REGEX.match?(token.text) }
90
- end
91
-
92
- def valid_sorbet_strictness?(strictness)
93
- %w(ignore false true strict strong).include?(strictness)
94
- end
95
-
96
- def sorbet_typed_strictness(sigil_line)
97
- sigil_line.text.match(SORBET_SIGIL_REGEX)&.captures&.first
98
- end
99
- end
100
- end
101
- end
102
- end