Merge pull request #8781 from reitermarkus/rubocop-sorbet
Add and vendor `rubocop-sorbet` and `sorbet-runtime-stub`.
This commit is contained in:
commit
fb9aafbb08
3
.github/workflows/tests.yml
vendored
3
.github/workflows/tests.yml
vendored
@ -120,8 +120,7 @@ jobs:
|
|||||||
- name: Run brew audit --skip-style on all taps
|
- name: Run brew audit --skip-style on all taps
|
||||||
run: brew audit --skip-style
|
run: brew audit --skip-style
|
||||||
|
|
||||||
# TODO: remove --quiet when possible.
|
- run: brew typecheck
|
||||||
- run: brew typecheck --quiet
|
|
||||||
|
|
||||||
- name: Run vale for docs linting
|
- name: Run vale for docs linting
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -35,6 +35,7 @@
|
|||||||
!**/vendor/bundle/ruby/*/gems/*/lib
|
!**/vendor/bundle/ruby/*/gems/*/lib
|
||||||
!**/vendor/bundle/ruby/*/gems/rubocop-performance-*/config
|
!**/vendor/bundle/ruby/*/gems/rubocop-performance-*/config
|
||||||
!**/vendor/bundle/ruby/*/gems/rubocop-rspec-*/config
|
!**/vendor/bundle/ruby/*/gems/rubocop-rspec-*/config
|
||||||
|
!**/vendor/bundle/ruby/*/gems/rubocop-sorbet-*/config
|
||||||
|
|
||||||
# Ignore partially included gems where we don't need all files
|
# Ignore partially included gems where we don't need all files
|
||||||
**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support.rb
|
**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support.rb
|
||||||
@ -134,6 +135,7 @@
|
|||||||
**/vendor/bundle/ruby/*/gems/simplecov-html-*/
|
**/vendor/bundle/ruby/*/gems/simplecov-html-*/
|
||||||
**/vendor/bundle/ruby/*/gems/sorbet-*/
|
**/vendor/bundle/ruby/*/gems/sorbet-*/
|
||||||
**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/
|
**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/
|
||||||
|
!**/vendor/bundle/ruby/*/gems/sorbet-runtime-stub-*/
|
||||||
**/vendor/bundle/ruby/*/gems/spoom-*/
|
**/vendor/bundle/ruby/*/gems/spoom-*/
|
||||||
**/vendor/bundle/ruby/*/gems/stackprof-*/
|
**/vendor/bundle/ruby/*/gems/stackprof-*/
|
||||||
**/vendor/bundle/ruby/*/gems/strscan-*/
|
**/vendor/bundle/ruby/*/gems/strscan-*/
|
||||||
|
|||||||
@ -264,6 +264,14 @@ Layout/LineLength:
|
|||||||
' "~/Library/Application Support/', '"~/Library/Caches/', '"~/Application Support',
|
' "~/Library/Application Support/', '"~/Library/Caches/', '"~/Application Support',
|
||||||
' was verified as official when first introduced to the cask']
|
' was verified as official when first introduced to the cask']
|
||||||
|
|
||||||
|
# Enable once we are using `sorbet-runtime`.
|
||||||
|
Sorbet/FalseSigil:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Try getting rid of these.
|
||||||
|
Sorbet/ConstantsFromStrings:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
# Avoid false positives on modifiers used on symbols of methods
|
# Avoid false positives on modifiers used on symbols of methods
|
||||||
# See https://github.com/rubocop-hq/rubocop/issues/5953
|
# See https://github.com/rubocop-hq/rubocop/issues/5953
|
||||||
Style/AccessModifierDeclarations:
|
Style/AccessModifierDeclarations:
|
||||||
|
|||||||
@ -25,4 +25,6 @@ gem "patchelf"
|
|||||||
gem "plist"
|
gem "plist"
|
||||||
gem "rubocop-performance"
|
gem "rubocop-performance"
|
||||||
gem "rubocop-rspec"
|
gem "rubocop-rspec"
|
||||||
|
gem "rubocop-sorbet"
|
||||||
gem "ruby-macho"
|
gem "ruby-macho"
|
||||||
|
gem "sorbet-runtime-stub"
|
||||||
|
|||||||
@ -114,6 +114,8 @@ GEM
|
|||||||
rubocop-ast (>= 0.4.0)
|
rubocop-ast (>= 0.4.0)
|
||||||
rubocop-rspec (1.43.2)
|
rubocop-rspec (1.43.2)
|
||||||
rubocop (~> 0.87)
|
rubocop (~> 0.87)
|
||||||
|
rubocop-sorbet (0.5.1)
|
||||||
|
rubocop
|
||||||
ruby-macho (2.2.0)
|
ruby-macho (2.2.0)
|
||||||
ruby-progressbar (1.10.1)
|
ruby-progressbar (1.10.1)
|
||||||
simplecov (0.19.0)
|
simplecov (0.19.0)
|
||||||
@ -123,6 +125,7 @@ GEM
|
|||||||
sorbet (0.5.5942)
|
sorbet (0.5.5942)
|
||||||
sorbet-static (= 0.5.5942)
|
sorbet-static (= 0.5.5942)
|
||||||
sorbet-runtime (0.5.5942)
|
sorbet-runtime (0.5.5942)
|
||||||
|
sorbet-runtime-stub (0.2.0)
|
||||||
sorbet-static (0.5.5942-universal-darwin-14)
|
sorbet-static (0.5.5942-universal-darwin-14)
|
||||||
spoom (1.0.4)
|
spoom (1.0.4)
|
||||||
colorize
|
colorize
|
||||||
@ -167,10 +170,12 @@ DEPENDENCIES
|
|||||||
rubocop
|
rubocop
|
||||||
rubocop-performance
|
rubocop-performance
|
||||||
rubocop-rspec
|
rubocop-rspec
|
||||||
|
rubocop-sorbet
|
||||||
ruby-macho
|
ruby-macho
|
||||||
simplecov
|
simplecov
|
||||||
sorbet
|
sorbet
|
||||||
sorbet-runtime
|
sorbet-runtime
|
||||||
|
sorbet-runtime-stub
|
||||||
tapioca
|
tapioca
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "delegate"
|
||||||
|
|
||||||
require "extend/hash_validator"
|
require "extend/hash_validator"
|
||||||
using HashValidator
|
using HashValidator
|
||||||
|
|
||||||
@ -8,7 +10,7 @@ module Cask
|
|||||||
# Class corresponding to the `conflicts_with` stanza.
|
# Class corresponding to the `conflicts_with` stanza.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class ConflictsWith < DelegateClass(Hash)
|
class ConflictsWith < SimpleDelegator
|
||||||
VALID_KEYS = [
|
VALID_KEYS = [
|
||||||
:formula,
|
:formula,
|
||||||
:cask,
|
:cask,
|
||||||
@ -18,12 +20,13 @@ module Cask
|
|||||||
:java,
|
:java,
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
def initialize(**pairs)
|
def initialize(**options)
|
||||||
pairs.assert_valid_keys!(*VALID_KEYS)
|
options.assert_valid_keys!(*VALID_KEYS)
|
||||||
|
|
||||||
super(pairs.transform_values { |v| Set.new(Array(v)) })
|
conflicts = options.transform_values { |v| Set.new(Array(v)) }
|
||||||
|
conflicts.default = Set.new
|
||||||
|
|
||||||
self.default = Set.new
|
super(conflicts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_json(generator)
|
def to_json(generator)
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "delegate"
|
||||||
|
|
||||||
require "requirements/macos_requirement"
|
require "requirements/macos_requirement"
|
||||||
|
|
||||||
module Cask
|
module Cask
|
||||||
@ -7,7 +9,7 @@ module Cask
|
|||||||
# Class corresponding to the `depends_on` stanza.
|
# Class corresponding to the `depends_on` stanza.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class DependsOn < DelegateClass(Hash)
|
class DependsOn < SimpleDelegator
|
||||||
VALID_KEYS = Set.new([
|
VALID_KEYS = Set.new([
|
||||||
:formula,
|
:formula,
|
||||||
:cask,
|
:cask,
|
||||||
|
|||||||
@ -1,32 +1,63 @@
|
|||||||
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Class corresponding to the `url` stanza.
|
# Class corresponding to the `url` stanza.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class URL
|
class URL
|
||||||
ATTRIBUTES = [
|
extend T::Sig
|
||||||
|
|
||||||
|
attr_reader :uri, :specs,
|
||||||
:using,
|
:using,
|
||||||
:tag, :branch, :revisions, :revision,
|
:tag, :branch, :revisions, :revision,
|
||||||
:trust_cert, :cookies, :referer, :user_agent,
|
:trust_cert, :cookies, :referer, :user_agent,
|
||||||
:data
|
:data
|
||||||
].freeze
|
|
||||||
private_constant :ATTRIBUTES
|
|
||||||
|
|
||||||
attr_reader :uri, :specs, *ATTRIBUTES
|
|
||||||
|
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
def_delegators :uri, :path, :scheme, :to_s
|
def_delegators :uri, :path, :scheme, :to_s
|
||||||
|
|
||||||
def initialize(uri, **options)
|
sig do
|
||||||
|
params(
|
||||||
|
uri: T.any(URI::Generic, String),
|
||||||
|
using: T.nilable(Symbol),
|
||||||
|
tag: T.nilable(String),
|
||||||
|
branch: T.nilable(String),
|
||||||
|
revisions: T.nilable(T::Array[String]),
|
||||||
|
revision: T.nilable(String),
|
||||||
|
trust_cert: T.nilable(T::Boolean),
|
||||||
|
cookies: T.nilable(T::Hash[String, String]),
|
||||||
|
referer: T.nilable(T.any(URI::Generic, String)),
|
||||||
|
user_agent: T.nilable(T.any(Symbol, String)),
|
||||||
|
data: T.nilable(T::Hash[String, String]),
|
||||||
|
).returns(T.untyped)
|
||||||
|
end
|
||||||
|
def initialize(
|
||||||
|
uri,
|
||||||
|
using: nil,
|
||||||
|
tag: nil,
|
||||||
|
branch: nil,
|
||||||
|
revisions: nil,
|
||||||
|
revision: nil,
|
||||||
|
trust_cert: nil,
|
||||||
|
cookies: nil,
|
||||||
|
referer: nil,
|
||||||
|
user_agent: nil,
|
||||||
|
data: nil
|
||||||
|
)
|
||||||
@uri = URI(uri)
|
@uri = URI(uri)
|
||||||
@user_agent = :default
|
|
||||||
|
|
||||||
ATTRIBUTES.each do |attribute|
|
specs = {}
|
||||||
next unless options.key?(attribute)
|
specs[:using] = @using = using
|
||||||
|
specs[:tag] = @tag = tag
|
||||||
|
specs[:branch] = @branch = branch
|
||||||
|
specs[:revisions] = @revisions = revisions
|
||||||
|
specs[:revision] = @revision = revision
|
||||||
|
specs[:trust_cert] = @trust_cert = trust_cert
|
||||||
|
specs[:cookies] = @cookies = cookies
|
||||||
|
specs[:referer] = @referer = referer
|
||||||
|
specs[:user_agent] = @user_agent = user_agent || :default
|
||||||
|
specs[:data] = @data = data
|
||||||
|
|
||||||
instance_variable_set("@#{attribute}", options[attribute])
|
@specs = specs.compact
|
||||||
end
|
|
||||||
|
|
||||||
@specs = options
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -27,6 +27,7 @@ module Commands
|
|||||||
"environment" => "--env",
|
"environment" => "--env",
|
||||||
"--config" => "config",
|
"--config" => "config",
|
||||||
"-v" => "--version",
|
"-v" => "--version",
|
||||||
|
"tc" => "typecheck",
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def valid_internal_cmd?(cmd)
|
def valid_internal_cmd?(cmd)
|
||||||
|
|||||||
@ -4,12 +4,9 @@ require "irb"
|
|||||||
|
|
||||||
# @private
|
# @private
|
||||||
module IRB
|
module IRB
|
||||||
@setup_done = false
|
def self.parse_opts(argv: nil); end
|
||||||
|
|
||||||
extend Module.new {
|
def self.start_within(binding)
|
||||||
def parse_opts; end
|
|
||||||
|
|
||||||
def start_within(binding)
|
|
||||||
unless @setup_done
|
unless @setup_done
|
||||||
setup(nil, argv: [])
|
setup(nil, argv: [])
|
||||||
@setup_done = true
|
@setup_done = true
|
||||||
@ -33,5 +30,4 @@ module IRB
|
|||||||
irb_at_exit
|
irb_at_exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -6,7 +6,7 @@ require "cask_dependent"
|
|||||||
# A collection of dependencies.
|
# A collection of dependencies.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class Dependencies < DelegateClass(Array)
|
class Dependencies < SimpleDelegator
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super(args)
|
super(args)
|
||||||
end
|
end
|
||||||
@ -41,7 +41,7 @@ end
|
|||||||
# A collection of requirements.
|
# A collection of requirements.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class Requirements < DelegateClass(Set)
|
class Requirements < SimpleDelegator
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super(Set.new(args))
|
super(Set.new(args))
|
||||||
end
|
end
|
||||||
|
|||||||
@ -58,6 +58,7 @@ module Homebrew
|
|||||||
ENV["HOMEBREW_NO_COMPAT"] = "1" if args.no_compat?
|
ENV["HOMEBREW_NO_COMPAT"] = "1" if args.no_compat?
|
||||||
ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if args.generic?
|
ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if args.generic?
|
||||||
ENV["HOMEBREW_TEST_ONLINE"] = "1" if args.online?
|
ENV["HOMEBREW_TEST_ONLINE"] = "1" if args.online?
|
||||||
|
ENV["HOMEBREW_SORBET_RUNTIME"] = "1"
|
||||||
|
|
||||||
ENV["USER"] ||= system_command!("id", args: ["-nu"]).stdout.chomp
|
ENV["USER"] ||= system_command!("id", args: ["-nu"]).stdout.chomp
|
||||||
|
|
||||||
|
|||||||
@ -251,6 +251,10 @@ module Homebrew
|
|||||||
"of macOS. This is useful in development on new macOS versions.",
|
"of macOS. This is useful in development on new macOS versions.",
|
||||||
boolean: true,
|
boolean: true,
|
||||||
},
|
},
|
||||||
|
HOMEBREW_SORBET_RUNTIME: {
|
||||||
|
description: "Enable runtime typechecking using Sorbet.",
|
||||||
|
boolean: true,
|
||||||
|
},
|
||||||
HOMEBREW_SVN: {
|
HOMEBREW_SVN: {
|
||||||
description: "Use this as the `svn`(1) binary.",
|
description: "Use this as the `svn`(1) binary.",
|
||||||
default_text: "A Homebrew-built Subversion (if installed), or the system-provided binary.",
|
default_text: "A Homebrew-built Subversion (if installed), or the system-provided binary.",
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module UnpackStrategy
|
module UnpackStrategy
|
||||||
class Zip
|
class Zip
|
||||||
prepend Module.new {
|
module MacOSZipExtension
|
||||||
def extract_to_dir(unpack_dir, basename:, verbose:)
|
def extract_to_dir(unpack_dir, basename:, verbose:)
|
||||||
if merge_xattrs && contains_extended_attributes?(path)
|
if merge_xattrs && contains_extended_attributes?(path)
|
||||||
# We use ditto directly, because dot_clean has issues if the __MACOSX
|
# We use ditto directly, because dot_clean has issues if the __MACOSX
|
||||||
@ -46,6 +46,9 @@ module UnpackStrategy
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
end
|
||||||
|
private_constant :MacOSZipExtension
|
||||||
|
|
||||||
|
prepend MacOSZipExtension
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -31,6 +31,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|||||||
inflect.irregular "it", "they"
|
inflect.irregular "it", "they"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require "utils/sorbet"
|
||||||
|
|
||||||
HOMEBREW_BOTTLE_DEFAULT_DOMAIN = ENV["HOMEBREW_BOTTLE_DEFAULT_DOMAIN"]
|
HOMEBREW_BOTTLE_DEFAULT_DOMAIN = ENV["HOMEBREW_BOTTLE_DEFAULT_DOMAIN"]
|
||||||
HOMEBREW_BREW_DEFAULT_GIT_REMOTE = ENV["HOMEBREW_BREW_DEFAULT_GIT_REMOTE"]
|
HOMEBREW_BREW_DEFAULT_GIT_REMOTE = ENV["HOMEBREW_BREW_DEFAULT_GIT_REMOTE"]
|
||||||
HOMEBREW_CORE_DEFAULT_GIT_REMOTE = ENV["HOMEBREW_CORE_DEFAULT_GIT_REMOTE"]
|
HOMEBREW_CORE_DEFAULT_GIT_REMOTE = ENV["HOMEBREW_CORE_DEFAULT_GIT_REMOTE"]
|
||||||
|
|||||||
@ -4,6 +4,8 @@ require_relative "load_path"
|
|||||||
|
|
||||||
require "rubocop-performance"
|
require "rubocop-performance"
|
||||||
require "rubocop-rspec"
|
require "rubocop-rspec"
|
||||||
|
require "rubocop-sorbet"
|
||||||
|
|
||||||
require "rubocops/formula_desc"
|
require "rubocops/formula_desc"
|
||||||
require "rubocops/components_order"
|
require "rubocops/components_order"
|
||||||
require "rubocops/components_redundancy"
|
require "rubocops/components_redundancy"
|
||||||
|
|||||||
@ -3,3 +3,6 @@
|
|||||||
|
|
||||||
--ignore
|
--ignore
|
||||||
/vendor
|
/vendor
|
||||||
|
|
||||||
|
--ignore
|
||||||
|
/test/.gem
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
# typed: strict
|
# typed: strict
|
||||||
|
|
||||||
class User < String
|
class User < SimpleDelegator
|
||||||
def gui?
|
include Kernel
|
||||||
end
|
|
||||||
|
|
||||||
def self.current
|
sig { returns(T::Boolean) }
|
||||||
end
|
def gui?; end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(T.attached_class)) }
|
||||||
|
def self.current; end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
# typed: false
|
# typed: false
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Add your extra requires here
|
# Add your extra requires here
|
||||||
|
|||||||
10
Library/Homebrew/utils/sorbet.rb
Normal file
10
Library/Homebrew/utils/sorbet.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# typed: strict
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
if ENV["HOMEBREW_SORBET_RUNTIME"]
|
||||||
|
require "utils/gems"
|
||||||
|
Homebrew.install_bundler_gems!
|
||||||
|
require "sorbet-runtime"
|
||||||
|
else
|
||||||
|
require "sorbet-runtime-stub"
|
||||||
|
end
|
||||||
@ -8,7 +8,7 @@ require "system_command"
|
|||||||
# A system user.
|
# A system user.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class User < DelegateClass(String)
|
class User < SimpleDelegator
|
||||||
# Return whether the user has an active GUI session.
|
# Return whether the user has an active GUI session.
|
||||||
def gui?
|
def gui?
|
||||||
out, _, status = system_command "who"
|
out, _, status = system_command "who"
|
||||||
|
|||||||
@ -75,9 +75,11 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width
|
|||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.92.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.92.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.8.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.8.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.43.2/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.43.2/lib"
|
||||||
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.5.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5942-universal-darwin-19/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5942-universal-darwin-19/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5942/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5942/lib"
|
||||||
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-stub-0.2.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/spoom-1.0.4/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/spoom-1.0.4/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tapioca-0.4.7/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tapioca-0.4.7/lib"
|
||||||
|
|||||||
128
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/config/default.yml
vendored
Normal file
128
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/config/default.yml
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
inherit_mode:
|
||||||
|
merge:
|
||||||
|
- Exclude
|
||||||
|
|
||||||
|
Sorbet/AllowIncompatibleOverride:
|
||||||
|
Description: 'Disallows using `.override(allow_incompatible: true)`.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
|
||||||
|
Sorbet/BindingConstantWithoutTypeAlias:
|
||||||
|
Description: >-
|
||||||
|
Disallows binding the return value of `T.any`, `T.all`, `T.enum`
|
||||||
|
to a constant directly. To bind the value, one must use `T.type_alias`.
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
|
||||||
|
Sorbet/CheckedTrueInSignature:
|
||||||
|
Description: 'Disallows the usage of `checked(true)` in signatures.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
|
||||||
|
Sorbet/ConstantsFromStrings:
|
||||||
|
Description: >-
|
||||||
|
Forbids constant access through meta-programming.
|
||||||
|
|
||||||
|
For example, things like `constantize` or `const_get`
|
||||||
|
are forbidden.
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
|
||||||
|
Sorbet/EnforceSigilOrder:
|
||||||
|
Description: 'Ensures that Sorbet sigil comes first in a file.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.3.4
|
||||||
|
|
||||||
|
Sorbet/EnforceSignatures:
|
||||||
|
Description: 'Ensures all methods have a valid signature.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.3.4
|
||||||
|
|
||||||
|
Sorbet/FalseSigil:
|
||||||
|
Description: 'All files must be at least at strictness `false`.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.3.3
|
||||||
|
SuggestedStrictness: true
|
||||||
|
Include:
|
||||||
|
- "**/*.rb"
|
||||||
|
- "**/*.rbi"
|
||||||
|
- "**/*.rake"
|
||||||
|
- "**/*.ru"
|
||||||
|
Exclude:
|
||||||
|
- bin/**/*
|
||||||
|
- db/**/*.rb
|
||||||
|
- script/**/*
|
||||||
|
|
||||||
|
Sorbet/ForbidIncludeConstLiteral:
|
||||||
|
Description: 'Forbids include of non-literal constants.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
VersionChanged: 0.5.0
|
||||||
|
|
||||||
|
Sorbet/ForbidSuperclassConstLiteral:
|
||||||
|
Description: 'Forbid superclasses which are non-literal constants.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
VersionChanged: 0.5.0
|
||||||
|
|
||||||
|
Sorbet/ForbidUntypedStructProps:
|
||||||
|
Description: >-
|
||||||
|
Disallows use of `T.untyped` or `T.nilable(T.untyped)` as a
|
||||||
|
prop type for `T::Struct` subclasses.
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.4.0
|
||||||
|
|
||||||
|
Sorbet/HasSigil:
|
||||||
|
Description: 'Makes the Sorbet typed sigil mandatory in all files.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.3.3
|
||||||
|
|
||||||
|
Sorbet/IgnoreSigil:
|
||||||
|
Description: 'All files must be at least at strictness `ignore`.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.3.3
|
||||||
|
|
||||||
|
Sorbet/KeywordArgumentOrdering:
|
||||||
|
Description: >-
|
||||||
|
Enforces a compatible keyword arguments with Sorbet.
|
||||||
|
|
||||||
|
All keyword arguments must be at the end of the parameters
|
||||||
|
list, and all keyword arguments with a default value must be
|
||||||
|
after those without default values.
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
|
||||||
|
Sorbet/ParametersOrderingInSignature:
|
||||||
|
Description: 'Enforces same parameter order between a method and its signature.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.2.0
|
||||||
|
|
||||||
|
Sorbet/SignatureBuildOrder:
|
||||||
|
Description: >-
|
||||||
|
Enforces the order of parts in a signature.
|
||||||
|
|
||||||
|
The order is first inheritance related builders,
|
||||||
|
then params, then return and finally the modifier
|
||||||
|
such as: `abstract.params(...).returns(...).soft`.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.3.0
|
||||||
|
|
||||||
|
Sorbet/StrictSigil:
|
||||||
|
Description: 'All files must be at least at strictness `strict`.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.3.3
|
||||||
|
|
||||||
|
Sorbet/StrongSigil:
|
||||||
|
Description: 'All files must be at least at strictness `strong`.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.3.3
|
||||||
|
|
||||||
|
Sorbet/TrueSigil:
|
||||||
|
Description: 'All files must be at least at strictness `true`.'
|
||||||
|
Enabled: false
|
||||||
|
VersionAdded: 0.3.3
|
||||||
|
|
||||||
|
Sorbet/ValidSigil:
|
||||||
|
Description: 'All files must have a valid sigil.'
|
||||||
|
Enabled: true
|
||||||
|
VersionAdded: 0.3.3
|
||||||
11
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop-sorbet.rb
vendored
Normal file
11
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop-sorbet.rb
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
require_relative 'rubocop/sorbet'
|
||||||
|
require_relative 'rubocop/sorbet/version'
|
||||||
|
require_relative 'rubocop/sorbet/inject'
|
||||||
|
|
||||||
|
RuboCop::Sorbet::Inject.defaults!
|
||||||
|
|
||||||
|
require_relative 'rubocop/cop/sorbet_cops'
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop disallows binding the return value of `T.any`, `T.all`, `T.enum`
|
||||||
|
# to a constant directly. To bind the value, one must use `T.type_alias`.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# FooOrBar = T.any(Foo, Bar)
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# FooOrBar = T.type_alias { T.any(Foo, Bar) }
|
||||||
|
class BindingConstantWithoutTypeAlias < RuboCop::Cop::Cop
|
||||||
|
def_node_matcher(:binding_unaliased_type?, <<-PATTERN)
|
||||||
|
(casgn _ _ [#not_nil? #not_t_let? #not_dynamic_type_creation_with_block? #not_generic_parameter_decl? #method_needing_aliasing_on_t?])
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher(:using_type_alias?, <<-PATTERN)
|
||||||
|
(block
|
||||||
|
(send
|
||||||
|
(const nil? :T) :type_alias)
|
||||||
|
_
|
||||||
|
_
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher(:using_deprecated_type_alias_syntax?, <<-PATTERN)
|
||||||
|
(
|
||||||
|
send
|
||||||
|
(const nil? :T)
|
||||||
|
:type_alias
|
||||||
|
_
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher(:t_let?, <<-PATTERN)
|
||||||
|
(
|
||||||
|
send
|
||||||
|
(const nil? :T)
|
||||||
|
:let
|
||||||
|
_
|
||||||
|
_
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher(:dynamic_type_creation_with_block?, <<-PATTERN)
|
||||||
|
(block
|
||||||
|
(send
|
||||||
|
const :new ...)
|
||||||
|
_
|
||||||
|
_
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher(:generic_parameter_decl?, <<-PATTERN)
|
||||||
|
(
|
||||||
|
send nil? {:type_template :type_member} ...
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_search(:method_needing_aliasing_on_t?, <<-PATTERN)
|
||||||
|
(
|
||||||
|
send
|
||||||
|
(const nil? :T)
|
||||||
|
{:any :all :noreturn :class_of :untyped :nilable :self_type :enum :proc}
|
||||||
|
...
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def not_t_let?(node)
|
||||||
|
!t_let?(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_dynamic_type_creation_with_block?(node)
|
||||||
|
!dynamic_type_creation_with_block?(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_generic_parameter_decl?(node)
|
||||||
|
!generic_parameter_decl?(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_nil?(node)
|
||||||
|
!node.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_casgn(node)
|
||||||
|
return unless binding_unaliased_type?(node) && !using_type_alias?(node.children[2])
|
||||||
|
if using_deprecated_type_alias_syntax?(node.children[2])
|
||||||
|
add_offense(
|
||||||
|
node.children[2],
|
||||||
|
message: "It looks like you're using the old `T.type_alias` syntax. " \
|
||||||
|
'`T.type_alias` now expects a block.' \
|
||||||
|
'Run Sorbet with the options "--autocorrect --error-white-list=5043" ' \
|
||||||
|
'to automatically upgrade to the new syntax.'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
add_offense(
|
||||||
|
node.children[2],
|
||||||
|
message: "It looks like you're trying to bind a type to a constant. " \
|
||||||
|
'To do this, you must alias the type using `T.type_alias`.'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def autocorrect(node)
|
||||||
|
lambda do |corrector|
|
||||||
|
corrector.replace(
|
||||||
|
node.source_range,
|
||||||
|
"T.type_alias { #{node.source} }"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop disallows the calls that are used to get constants fom Strings
|
||||||
|
# such as +constantize+, +const_get+, and +constants+.
|
||||||
|
#
|
||||||
|
# The goal of this cop is to make the code easier to statically analyze,
|
||||||
|
# more IDE-friendly, and more predictable. It leads to code that clearly
|
||||||
|
# expresses which values the constant can have.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# class_name.constantize
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# constants.detect { |c| c.name == "User" }
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# const_get(class_name)
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# case class_name
|
||||||
|
# when "User"
|
||||||
|
# User
|
||||||
|
# else
|
||||||
|
# raise ArgumentError
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# { "User" => User }.fetch(class_name)
|
||||||
|
class ConstantsFromStrings < ::RuboCop::Cop::Cop
|
||||||
|
def_node_matcher(:constant_from_string?, <<-PATTERN)
|
||||||
|
(send _ {:constantize :constants :const_get} ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_send(node)
|
||||||
|
return unless constant_from_string?(node)
|
||||||
|
add_offense(
|
||||||
|
node,
|
||||||
|
location: :selector,
|
||||||
|
message: "Don't use `#{node.method_name}`, it makes the code harder to understand, less editor-friendly, " \
|
||||||
|
"and impossible to analyze. Replace `#{node.method_name}` with a case/when or a hash."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
# Correct `send` expressions in include statements by constant literals.
|
||||||
|
#
|
||||||
|
# Sorbet, the static checker, is not (yet) able to support constructs on the
|
||||||
|
# following form:
|
||||||
|
#
|
||||||
|
# ```ruby
|
||||||
|
# class MyClass
|
||||||
|
# include send_expr
|
||||||
|
# end
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Multiple occurences of this can be found in Shopify's code base like:
|
||||||
|
#
|
||||||
|
# ```ruby
|
||||||
|
# include Rails.application.routes.url_helpers
|
||||||
|
# ```
|
||||||
|
# or
|
||||||
|
# ```ruby
|
||||||
|
# include Polaris::Engine.helpers
|
||||||
|
# ```
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
class ForbidIncludeConstLiteral < RuboCop::Cop::Cop
|
||||||
|
MSG = 'Includes must only contain constant literals'
|
||||||
|
|
||||||
|
attr_accessor :used_names
|
||||||
|
|
||||||
|
def_node_matcher :not_lit_const_include?, <<-PATTERN
|
||||||
|
(send nil? {:include :extend :prepend}
|
||||||
|
$_
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def initialize(*)
|
||||||
|
super
|
||||||
|
self.used_names = Set.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_send(node)
|
||||||
|
return unless not_lit_const_include?(node) do |send_argument|
|
||||||
|
![:const, :self].include?(send_argument.type)
|
||||||
|
end
|
||||||
|
parent = node.parent
|
||||||
|
return unless parent
|
||||||
|
parent = parent.parent if [:begin, :block].include?(parent.type)
|
||||||
|
return unless [:module, :class, :sclass].include?(parent.type)
|
||||||
|
add_offense(node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
# Correct superclass `send` expressions by constant literals.
|
||||||
|
#
|
||||||
|
# Sorbet, the static checker, is not (yet) able to support constructs on the
|
||||||
|
# following form:
|
||||||
|
#
|
||||||
|
# ```ruby
|
||||||
|
# class Foo < send_expr; end
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Multiple occurences of this can be found in Shopify's code base like:
|
||||||
|
#
|
||||||
|
# ```ruby
|
||||||
|
# class ShopScope < Component::TrustedIdScope[ShopIdentity::ShopId]
|
||||||
|
# ```
|
||||||
|
# or
|
||||||
|
# ```ruby
|
||||||
|
# class ApiClientEligibility < Struct.new(:api_client, :match_results, :shop)
|
||||||
|
# ```
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
class ForbidSuperclassConstLiteral < RuboCop::Cop::Cop
|
||||||
|
MSG = 'Superclasses must only contain constant literals'
|
||||||
|
|
||||||
|
def_node_matcher :not_lit_const_superclass?, <<-PATTERN
|
||||||
|
(class
|
||||||
|
(const ...)
|
||||||
|
(send ...)
|
||||||
|
...
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_class(node)
|
||||||
|
return unless not_lit_const_superclass?(node)
|
||||||
|
add_offense(node.child_nodes[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop disallows use of `T.untyped` or `T.nilable(T.untyped)`
|
||||||
|
# as a prop type for `T::Struct`.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# class SomeClass
|
||||||
|
# const :foo, T.untyped
|
||||||
|
# prop :bar, T.nilable(T.untyped)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# class SomeClass
|
||||||
|
# const :foo, Integer
|
||||||
|
# prop :bar, T.nilable(String)
|
||||||
|
# end
|
||||||
|
class ForbidUntypedStructProps < RuboCop::Cop::Cop
|
||||||
|
MSG = 'Struct props cannot be T.untyped'
|
||||||
|
|
||||||
|
def_node_matcher :t_struct, <<~PATTERN
|
||||||
|
(const (const nil? :T) :Struct)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher :t_untyped, <<~PATTERN
|
||||||
|
(send (const nil? :T) :untyped)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher :t_nilable_untyped, <<~PATTERN
|
||||||
|
(send (const nil? :T) :nilable {#t_untyped #t_nilable_untyped})
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher :subclass_of_t_struct?, <<~PATTERN
|
||||||
|
(class (const ...) #t_struct ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_search :untyped_props, <<~PATTERN
|
||||||
|
(send nil? {:prop :const} _ {#t_untyped #t_nilable_untyped} ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_class(node)
|
||||||
|
return unless subclass_of_t_struct?(node)
|
||||||
|
|
||||||
|
untyped_props(node).each do |untyped_prop|
|
||||||
|
add_offense(untyped_prop.child_nodes[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop checks that the Sorbet sigil comes as the first magic comment in the file.
|
||||||
|
#
|
||||||
|
# The expected order for magic comments is: typed, (en)?coding, warn_indent then frozen_string_literal.
|
||||||
|
#
|
||||||
|
# For example, the following bad ordering:
|
||||||
|
#
|
||||||
|
# ```ruby
|
||||||
|
# # frozen_string_literal: true
|
||||||
|
# # typed: true
|
||||||
|
# class Foo; end
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Will be corrected as:
|
||||||
|
#
|
||||||
|
# ```ruby
|
||||||
|
# # typed: true
|
||||||
|
# # frozen_string_literal: true
|
||||||
|
# class Foo; end
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Only `typed`, `(en)?coding`, `warn_indent` and `frozen_string_literal` magic comments are considered,
|
||||||
|
# other comments or magic comments are left in the same place.
|
||||||
|
class EnforceSigilOrder < ValidSigil
|
||||||
|
include RangeHelp
|
||||||
|
|
||||||
|
def investigate(processed_source)
|
||||||
|
return if processed_source.tokens.empty?
|
||||||
|
|
||||||
|
tokens = extract_magic_comments(processed_source)
|
||||||
|
return if tokens.empty?
|
||||||
|
|
||||||
|
check_magic_comments_order(tokens)
|
||||||
|
end
|
||||||
|
|
||||||
|
def autocorrect(_node)
|
||||||
|
lambda do |corrector|
|
||||||
|
tokens = extract_magic_comments(processed_source)
|
||||||
|
|
||||||
|
# Get the magic comments tokens in their expected order
|
||||||
|
expected = PREFERRED_ORDER.keys.map do |re|
|
||||||
|
tokens.select { |token| re.match?(token.text) }
|
||||||
|
end.flatten
|
||||||
|
|
||||||
|
tokens.each_with_index do |token, index|
|
||||||
|
corrector.replace(token.pos, expected[index].text)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Remove blank lines between the magic comments
|
||||||
|
lines = tokens.map(&:line).to_set
|
||||||
|
(lines.min...lines.max).each do |line|
|
||||||
|
next if lines.include?(line)
|
||||||
|
next unless processed_source[line - 1].empty?
|
||||||
|
corrector.remove(source_range(processed_source.buffer, line, 0))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
CODING_REGEX = /#\s+(en)?coding:(?:\s+([\w]+))?/
|
||||||
|
INDENT_REGEX = /#\s+warn_indent:(?:\s+([\w]+))?/
|
||||||
|
FROZEN_REGEX = /#\s+frozen_string_literal:(?:\s+([\w]+))?/
|
||||||
|
|
||||||
|
PREFERRED_ORDER = {
|
||||||
|
CODING_REGEX => 'encoding',
|
||||||
|
SIGIL_REGEX => 'typed',
|
||||||
|
INDENT_REGEX => 'warn_indent',
|
||||||
|
FROZEN_REGEX => 'frozen_string_literal',
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
MAGIC_REGEX = Regexp.union(*PREFERRED_ORDER.keys)
|
||||||
|
|
||||||
|
# extraction
|
||||||
|
|
||||||
|
# Get all the tokens in `processed_source` that match `MAGIC_REGEX`
|
||||||
|
def extract_magic_comments(processed_source)
|
||||||
|
processed_source.tokens
|
||||||
|
.take_while { |token| token.type == :tCOMMENT }
|
||||||
|
.select { |token| MAGIC_REGEX.match?(token.text) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# checks
|
||||||
|
|
||||||
|
def check_magic_comments_order(tokens)
|
||||||
|
# Get the current magic comments order
|
||||||
|
order = tokens.map do |token|
|
||||||
|
PREFERRED_ORDER.keys.find { |re| re.match?(token.text) }
|
||||||
|
end.compact.uniq
|
||||||
|
|
||||||
|
# Get the expected magic comments order based on the one used in the actual source
|
||||||
|
expected = PREFERRED_ORDER.keys.select do |re|
|
||||||
|
tokens.any? { |token| re.match?(token.text) }
|
||||||
|
end.uniq
|
||||||
|
|
||||||
|
if order != expected
|
||||||
|
tokens.each do |token|
|
||||||
|
add_offense(
|
||||||
|
token,
|
||||||
|
location: token.pos,
|
||||||
|
message: "Magic comments should be in the following order: #{PREFERRED_ORDER.values.join(', ')}."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'has_sigil'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop makes the Sorbet `false` sigil mandatory in all files.
|
||||||
|
class FalseSigil < HasSigil
|
||||||
|
def minimum_strictness
|
||||||
|
'false'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'valid_sigil'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop makes the Sorbet typed sigil mandatory in all files.
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
# * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
|
||||||
|
# * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
|
||||||
|
#
|
||||||
|
# If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
||||||
|
class HasSigil < ValidSigil
|
||||||
|
@registry = Cop.registry # So we can properly subclass this cop
|
||||||
|
|
||||||
|
def require_sigil_on_all_files?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'has_sigil'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop makes the Sorbet `ignore` sigil mandatory in all files.
|
||||||
|
class IgnoreSigil < HasSigil
|
||||||
|
def minimum_strictness
|
||||||
|
'ignore'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'has_sigil'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop makes the Sorbet `strict` sigil mandatory in all files.
|
||||||
|
class StrictSigil < HasSigil
|
||||||
|
def minimum_strictness
|
||||||
|
'strict'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'has_sigil'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop makes the Sorbet `strong` sigil mandatory in all files.
|
||||||
|
class StrongSigil < HasSigil
|
||||||
|
def minimum_strictness
|
||||||
|
'strong'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'has_sigil'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop makes the Sorbet `true` sigil mandatory in all files.
|
||||||
|
class TrueSigil < HasSigil
|
||||||
|
def minimum_strictness
|
||||||
|
'true'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop checks that every Ruby file contains a valid Sorbet sigil.
|
||||||
|
# Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
# * `RequireSigilOnAllFiles`: make offense if the Sorbet typed is not found in the file (default: false)
|
||||||
|
# * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
|
||||||
|
# * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
|
||||||
|
#
|
||||||
|
# If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
||||||
|
class ValidSigil < RuboCop::Cop::Cop
|
||||||
|
@registry = Cop.registry # So we can properly subclass this cop
|
||||||
|
|
||||||
|
def investigate(processed_source)
|
||||||
|
return if processed_source.tokens.empty?
|
||||||
|
|
||||||
|
sigil = extract_sigil(processed_source)
|
||||||
|
return unless check_sigil_present(sigil)
|
||||||
|
|
||||||
|
strictness = extract_strictness(sigil)
|
||||||
|
return unless check_strictness_not_empty(sigil, strictness)
|
||||||
|
return unless check_strictness_valid(sigil, strictness)
|
||||||
|
return unless check_strictness_level(sigil, strictness)
|
||||||
|
end
|
||||||
|
|
||||||
|
def autocorrect(_node)
|
||||||
|
lambda do |corrector|
|
||||||
|
return unless require_sigil_on_all_files?
|
||||||
|
return unless extract_sigil(processed_source).nil?
|
||||||
|
|
||||||
|
token = processed_source.tokens.first
|
||||||
|
replace_with = suggested_strictness_level(minimum_strictness, suggested_strictness)
|
||||||
|
sigil = "# typed: #{replace_with}"
|
||||||
|
if token.text.start_with?("#!") # shebang line
|
||||||
|
corrector.insert_after(token.pos, "\n#{sigil}")
|
||||||
|
else
|
||||||
|
corrector.insert_before(token.pos, "#{sigil}\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
STRICTNESS_LEVELS = %w(ignore false true strict strong)
|
||||||
|
SIGIL_REGEX = /#\s+typed:(?:\s+([\w]+))?/
|
||||||
|
|
||||||
|
# extraction
|
||||||
|
|
||||||
|
def extract_sigil(processed_source)
|
||||||
|
processed_source.tokens
|
||||||
|
.take_while { |token| token.type == :tCOMMENT }
|
||||||
|
.find { |token| SIGIL_REGEX.match?(token.text) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_strictness(sigil)
|
||||||
|
sigil.text.match(SIGIL_REGEX)&.captures&.first
|
||||||
|
end
|
||||||
|
|
||||||
|
# checks
|
||||||
|
|
||||||
|
def check_sigil_present(sigil)
|
||||||
|
return true unless sigil.nil?
|
||||||
|
|
||||||
|
token = processed_source.tokens.first
|
||||||
|
if require_sigil_on_all_files?
|
||||||
|
strictness = suggested_strictness_level(minimum_strictness, suggested_strictness)
|
||||||
|
add_offense(
|
||||||
|
token,
|
||||||
|
location: token.pos,
|
||||||
|
message: 'No Sorbet sigil found in file. ' \
|
||||||
|
"Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this)."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def suggested_strictness_level(minimum_strictness, suggested_strictness)
|
||||||
|
# if no minimum strictness is set (eg. using Sorbet/HasSigil without config) then
|
||||||
|
# we always use the suggested strictness which defaults to `false`
|
||||||
|
return suggested_strictness unless minimum_strictness
|
||||||
|
|
||||||
|
# special case: if you're using Sorbet/IgnoreSigil without config, we should recommend `ignore`
|
||||||
|
return "ignore" if minimum_strictness == "ignore" && cop_config['SuggestedStrictness'].nil?
|
||||||
|
|
||||||
|
# if a minimum strictness is set (eg. you're using Sorbet/FalseSigil)
|
||||||
|
# we want to compare the minimum strictness and suggested strictness. this is because
|
||||||
|
# the suggested strictness might be higher than the minimum (eg. if you want all new files
|
||||||
|
# at a higher strictness level, without having to migrate existing files at lower levels).
|
||||||
|
|
||||||
|
suggested_level = STRICTNESS_LEVELS.index(suggested_strictness)
|
||||||
|
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
|
||||||
|
|
||||||
|
suggested_level > minimum_level ? suggested_strictness : minimum_strictness
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_strictness_not_empty(sigil, strictness)
|
||||||
|
return true if strictness
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
sigil,
|
||||||
|
location: sigil.pos,
|
||||||
|
message: 'Sorbet sigil should not be empty.'
|
||||||
|
)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_strictness_valid(sigil, strictness)
|
||||||
|
return true if STRICTNESS_LEVELS.include?(strictness)
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
sigil,
|
||||||
|
location: sigil.pos,
|
||||||
|
message: "Invalid Sorbet sigil `#{strictness}`."
|
||||||
|
)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_strictness_level(sigil, strictness)
|
||||||
|
return true unless minimum_strictness
|
||||||
|
|
||||||
|
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
|
||||||
|
current_level = STRICTNESS_LEVELS.index(strictness)
|
||||||
|
if current_level < minimum_level
|
||||||
|
add_offense(
|
||||||
|
sigil,
|
||||||
|
location: sigil.pos,
|
||||||
|
message: "Sorbet sigil should be at least `#{minimum_strictness}` got `#{strictness}`."
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
# options
|
||||||
|
|
||||||
|
# Default is `false`
|
||||||
|
def require_sigil_on_all_files?
|
||||||
|
!!cop_config['RequireSigilOnAllFiles']
|
||||||
|
end
|
||||||
|
|
||||||
|
# Default is `'false'`
|
||||||
|
def suggested_strictness
|
||||||
|
STRICTNESS_LEVELS.include?(cop_config['SuggestedStrictness']) ? cop_config['SuggestedStrictness'] : 'false'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Default is `nil`
|
||||||
|
def minimum_strictness
|
||||||
|
cop_config['MinimumStrictness'] if STRICTNESS_LEVELS.include?(cop_config['MinimumStrictness'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop disallows using `.override(allow_incompatible: true)`.
|
||||||
|
# Using `allow_incompatible` suggests a violation of the Liskov
|
||||||
|
# Substitution Principle, meaning that a subclass is not a valid
|
||||||
|
# subtype of it's superclass. This Cop prevents these design smells
|
||||||
|
# from occurring.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# sig.override(allow_incompatible: true)
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# sig.override
|
||||||
|
class AllowIncompatibleOverride < RuboCop::Cop::Cop
|
||||||
|
def_node_search(:sig?, <<-PATTERN)
|
||||||
|
(
|
||||||
|
send
|
||||||
|
nil?
|
||||||
|
:sig
|
||||||
|
...
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def not_nil?(node)
|
||||||
|
!node.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def_node_search(:allow_incompatible?, <<-PATTERN)
|
||||||
|
(pair (sym :allow_incompatible) (true))
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher(:allow_incompatible_override?, <<-PATTERN)
|
||||||
|
(
|
||||||
|
send
|
||||||
|
[#not_nil? #sig?]
|
||||||
|
:override
|
||||||
|
[#not_nil? #allow_incompatible?]
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_send(node)
|
||||||
|
return unless allow_incompatible_override?(node)
|
||||||
|
add_offense(
|
||||||
|
node.children[2],
|
||||||
|
message: 'Usage of `allow_incompatible` suggests a violation of the Liskov Substitution Principle. '\
|
||||||
|
'Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`',
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'signature_cop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop disallows the usage of `checked(true)`. This usage could cause
|
||||||
|
# confusion; it could lead some people to believe that a method would be checked
|
||||||
|
# even if runtime checks have not been enabled on the class or globally.
|
||||||
|
# Additionally, in the event where checks are enabled, `checked(true)` would
|
||||||
|
# be redundant; only `checked(false)` or `soft` would change the behaviour.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# sig { void.checked(true) }
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# sig { void }
|
||||||
|
class CheckedTrueInSignature < SignatureCop
|
||||||
|
include(RuboCop::Cop::RangeHelp)
|
||||||
|
|
||||||
|
def_node_search(:offending_node, <<~PATTERN)
|
||||||
|
(send _ :checked (true))
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
MESSAGE =
|
||||||
|
'Using `checked(true)` in a method signature definition is not allowed. ' \
|
||||||
|
'`checked(true)` is the default behavior for modules/classes with runtime checks enabled. ' \
|
||||||
|
'To enable typechecking at runtime for this module, regardless of global settings, ' \
|
||||||
|
'`include(WaffleCone::RuntimeChecks)` to this module and set other methods to `checked(false)`.'
|
||||||
|
private_constant(:MESSAGE)
|
||||||
|
|
||||||
|
def on_signature(node)
|
||||||
|
error = offending_node(node).first
|
||||||
|
return unless error
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
error,
|
||||||
|
location: source_range(
|
||||||
|
processed_source.buffer,
|
||||||
|
error.location.line,
|
||||||
|
(error.location.selector.begin_pos)..(error.location.end.begin_pos),
|
||||||
|
),
|
||||||
|
message: MESSAGE
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require 'stringio'
|
||||||
|
require_relative 'signature_cop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop checks that every method definition and attribute accessor has a Sorbet signature.
|
||||||
|
#
|
||||||
|
# It also suggest an autocorrect with placeholders so the following code:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# def foo(a, b, c); end
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Will be corrected as:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# sig { params(a: T.untyped, b: T.untyped, c: T.untyped).returns(T.untyped)
|
||||||
|
# def foo(a, b, c); end
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# You can configure the placeholders used by changing the following options:
|
||||||
|
#
|
||||||
|
# * `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped')
|
||||||
|
# * `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped')
|
||||||
|
class EnforceSignatures < SignatureCop
|
||||||
|
def_node_matcher(:accessor?, <<-PATTERN)
|
||||||
|
(send nil? {:attr_reader :attr_writer :attr_accessor} ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_def(node)
|
||||||
|
check_node(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_defs(node)
|
||||||
|
check_node(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_send(node)
|
||||||
|
return unless accessor?(node)
|
||||||
|
check_node(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def autocorrect(node)
|
||||||
|
lambda do |corrector|
|
||||||
|
suggest = SigSuggestion.new(node.loc.column, param_type_placeholder, return_type_placeholder)
|
||||||
|
|
||||||
|
if node.is_a?(RuboCop::AST::DefNode) # def something
|
||||||
|
node.arguments.each do |arg|
|
||||||
|
suggest.params << arg.children.first
|
||||||
|
end
|
||||||
|
elsif accessor?(node) # attr reader, writer, accessor
|
||||||
|
method = node.children[1]
|
||||||
|
symbol = node.children[2]
|
||||||
|
suggest.params << symbol.value if symbol && (method == :attr_writer || method == :attr_accessor)
|
||||||
|
suggest.returns = 'void' if method == :attr_writer
|
||||||
|
end
|
||||||
|
|
||||||
|
corrector.insert_before(node.loc.expression, suggest.to_autocorrect)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_node(node)
|
||||||
|
prev = previous_node(node)
|
||||||
|
unless signature?(prev)
|
||||||
|
add_offense(
|
||||||
|
node,
|
||||||
|
message: "Each method is required to have a signature."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def previous_node(node)
|
||||||
|
parent = node.parent
|
||||||
|
return nil unless parent
|
||||||
|
parent.children[node.sibling_index - 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def param_type_placeholder
|
||||||
|
cop_config['ParameterTypePlaceholder'] || 'T.untyped'
|
||||||
|
end
|
||||||
|
|
||||||
|
def return_type_placeholder
|
||||||
|
cop_config['ReturnTypePlaceholder'] || 'T.untyped'
|
||||||
|
end
|
||||||
|
|
||||||
|
class SigSuggestion
|
||||||
|
attr_accessor :params, :returns
|
||||||
|
|
||||||
|
def initialize(indent, param_placeholder, return_placeholder)
|
||||||
|
@params = []
|
||||||
|
@returns = nil
|
||||||
|
@indent = indent
|
||||||
|
@param_placeholder = param_placeholder
|
||||||
|
@return_placeholder = return_placeholder
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_autocorrect
|
||||||
|
out = StringIO.new
|
||||||
|
out << 'sig { '
|
||||||
|
out << generate_params
|
||||||
|
out << generate_return
|
||||||
|
out << " }\n"
|
||||||
|
out << ' ' * @indent # preserve indent for the next line
|
||||||
|
out.string
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def generate_params
|
||||||
|
return if @params.empty?
|
||||||
|
out = StringIO.new
|
||||||
|
out << 'params('
|
||||||
|
out << @params.map do |param|
|
||||||
|
"#{param}: #{@param_placeholder}"
|
||||||
|
end.join(", ")
|
||||||
|
out << ').'
|
||||||
|
out.string
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_return
|
||||||
|
return "returns(#{@return_placeholder})" if @returns.nil?
|
||||||
|
return @returns if @returns == 'void'
|
||||||
|
"returns(#{@returns})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'signature_cop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop checks for the ordering of keyword arguments required by
|
||||||
|
# sorbet-runtime. The ordering requires that all keyword arguments
|
||||||
|
# are at the end of the parameters list, and all keyword arguments
|
||||||
|
# with a default value must be after those without default values.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# sig { params(a: Integer, b: String).void }
|
||||||
|
# def foo(a: 1, b:); end
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# sig { params(b: String, a: Integer).void }
|
||||||
|
# def foo(b:, a: 1); end
|
||||||
|
class KeywordArgumentOrdering < SignatureCop
|
||||||
|
def on_signature(node)
|
||||||
|
method_node = node.parent.children[node.sibling_index + 1]
|
||||||
|
return if method_node.nil?
|
||||||
|
method_parameters = method_node.arguments
|
||||||
|
|
||||||
|
check_order_for_kwoptargs(method_parameters)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_order_for_kwoptargs(parameters)
|
||||||
|
out_of_kwoptarg = false
|
||||||
|
|
||||||
|
parameters.reverse.each do |param|
|
||||||
|
out_of_kwoptarg = true unless param.type == :kwoptarg || param.type == :blockarg || param.type == :kwrestarg
|
||||||
|
|
||||||
|
next unless param.type == :kwoptarg && out_of_kwoptarg
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
param,
|
||||||
|
message: 'Optional keyword arguments must be at the end of the parameter list.'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'signature_cop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# This cop checks for inconsistent ordering of parameters between the
|
||||||
|
# signature and the method definition. The sorbet-runtime gem raises
|
||||||
|
# when such inconsistency occurs.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
#
|
||||||
|
# # bad
|
||||||
|
# sig { params(a: Integer, b: String).void }
|
||||||
|
# def foo(b:, a:); end
|
||||||
|
#
|
||||||
|
# # good
|
||||||
|
# sig { params(a: Integer, b: String).void }
|
||||||
|
# def foo(a:, b:); end
|
||||||
|
class ParametersOrderingInSignature < SignatureCop
|
||||||
|
def_node_search(:signature_params, <<-PATTERN)
|
||||||
|
(send _ :params ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_signature(node)
|
||||||
|
sig_params = signature_params(node).first
|
||||||
|
|
||||||
|
sig_params_order = extract_parameters(sig_params)
|
||||||
|
return if sig_params_order.nil?
|
||||||
|
method_node = node.parent.children[node.sibling_index + 1]
|
||||||
|
return if method_node.nil? || method_node.type != :def
|
||||||
|
method_parameters = method_node.arguments
|
||||||
|
|
||||||
|
check_for_inconsistent_param_ordering(sig_params_order, method_parameters)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def extract_parameters(sig_params)
|
||||||
|
return [] if sig_params.nil?
|
||||||
|
|
||||||
|
arguments = sig_params.arguments.first
|
||||||
|
return arguments.keys.map(&:value) if RuboCop::AST::HashNode === arguments
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
sig_params,
|
||||||
|
message: "Invalid signature."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_for_inconsistent_param_ordering(sig_params_order, parameters)
|
||||||
|
parameters.each_with_index do |param, index|
|
||||||
|
param_name = param.children[0]
|
||||||
|
sig_param_name = sig_params_order[index]
|
||||||
|
|
||||||
|
next if param_name == sig_param_name
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
param,
|
||||||
|
message: "Inconsistent ordering of arguments at index #{index}. " \
|
||||||
|
"Expected `#{sig_param_name}` from sig above."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
require_relative 'signature_cop'
|
||||||
|
|
||||||
|
begin
|
||||||
|
require 'unparser'
|
||||||
|
rescue LoadError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
class SignatureBuildOrder < SignatureCop
|
||||||
|
ORDER =
|
||||||
|
[
|
||||||
|
:abstract,
|
||||||
|
:override,
|
||||||
|
:overridable,
|
||||||
|
:type_parameters,
|
||||||
|
:params,
|
||||||
|
:returns,
|
||||||
|
:void,
|
||||||
|
:soft,
|
||||||
|
:checked,
|
||||||
|
:on_failure,
|
||||||
|
].each_with_index.to_h.freeze
|
||||||
|
|
||||||
|
def_node_search(:root_call, <<~PATTERN)
|
||||||
|
(send nil? {#{ORDER.keys.map(&:inspect).join(' ')}} ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_signature(node)
|
||||||
|
calls = call_chain(node.children[2]).map(&:method_name)
|
||||||
|
return unless calls.any?
|
||||||
|
|
||||||
|
expected_order = calls.sort_by { |call| ORDER[call] }
|
||||||
|
return if expected_order == calls
|
||||||
|
|
||||||
|
message = "Sig builders must be invoked in the following order: #{expected_order.join(', ')}."
|
||||||
|
|
||||||
|
unless can_autocorrect?
|
||||||
|
message += ' For autocorrection, add the `unparser` gem to your project.'
|
||||||
|
end
|
||||||
|
|
||||||
|
add_offense(
|
||||||
|
node.children[2],
|
||||||
|
message: message,
|
||||||
|
)
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def autocorrect(node)
|
||||||
|
return nil unless can_autocorrect?
|
||||||
|
|
||||||
|
lambda do |corrector|
|
||||||
|
tree = call_chain(node_with_index_sends(node))
|
||||||
|
.sort_by { |call| ORDER[call.method_name] }
|
||||||
|
.reduce(nil) do |receiver, caller|
|
||||||
|
caller.updated(nil, [receiver] + caller.children.drop(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
corrector.replace(
|
||||||
|
node.source_range,
|
||||||
|
Unparser.unparse(tree),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def node_with_index_sends(node)
|
||||||
|
# This is really dirty hack to reparse the current node with index send
|
||||||
|
# emitting enabled, which is necessary to unparse them back as index accessors.
|
||||||
|
emit_index_value = RuboCop::AST::Builder.emit_index
|
||||||
|
RuboCop::AST::Builder.emit_index = true
|
||||||
|
RuboCop::AST::ProcessedSource.new(node.source, target_ruby_version, processed_source.path).ast
|
||||||
|
ensure
|
||||||
|
RuboCop::AST::Builder.emit_index = emit_index_value
|
||||||
|
end
|
||||||
|
|
||||||
|
def can_autocorrect?
|
||||||
|
defined?(::Unparser)
|
||||||
|
end
|
||||||
|
|
||||||
|
def call_chain(sig_child_node)
|
||||||
|
call_node = root_call(sig_child_node).first
|
||||||
|
return [] unless call_node
|
||||||
|
|
||||||
|
calls = []
|
||||||
|
while call_node != sig_child_node
|
||||||
|
calls << call_node
|
||||||
|
call_node = call_node.parent
|
||||||
|
end
|
||||||
|
|
||||||
|
calls << sig_child_node
|
||||||
|
|
||||||
|
calls
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubocop'
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module Sorbet
|
||||||
|
# Abstract cop specific to Sorbet signatures
|
||||||
|
#
|
||||||
|
# You can subclass it to use the `on_signature` trigger and the `signature?` node matcher.
|
||||||
|
class SignatureCop < RuboCop::Cop::Cop
|
||||||
|
@registry = Cop.registry # So we can properly subclass this cop
|
||||||
|
|
||||||
|
def_node_matcher(:signature?, <<~PATTERN)
|
||||||
|
(block (send nil? :sig) (args) ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_block(node)
|
||||||
|
on_signature(node) if signature?(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_signature(_)
|
||||||
|
# To be defined in subclasses
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require_relative 'sorbet/binding_constants_without_type_alias'
|
||||||
|
require_relative 'sorbet/constants_from_strings'
|
||||||
|
require_relative 'sorbet/forbid_superclass_const_literal'
|
||||||
|
require_relative 'sorbet/forbid_include_const_literal'
|
||||||
|
require_relative 'sorbet/forbid_untyped_struct_props'
|
||||||
|
|
||||||
|
require_relative 'sorbet/signatures/allow_incompatible_override'
|
||||||
|
require_relative 'sorbet/signatures/checked_true_in_signature'
|
||||||
|
require_relative 'sorbet/signatures/keyword_argument_ordering'
|
||||||
|
require_relative 'sorbet/signatures/parameters_ordering_in_signature'
|
||||||
|
require_relative 'sorbet/signatures/signature_build_order'
|
||||||
|
require_relative 'sorbet/signatures/enforce_signatures'
|
||||||
|
|
||||||
|
require_relative 'sorbet/sigils/valid_sigil'
|
||||||
|
require_relative 'sorbet/sigils/has_sigil'
|
||||||
|
require_relative 'sorbet/sigils/ignore_sigil'
|
||||||
|
require_relative 'sorbet/sigils/false_sigil'
|
||||||
|
require_relative 'sorbet/sigils/true_sigil'
|
||||||
|
require_relative 'sorbet/sigils/strict_sigil'
|
||||||
|
require_relative 'sorbet/sigils/strong_sigil'
|
||||||
|
require_relative 'sorbet/sigils/enforce_sigil_order'
|
||||||
15
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet.rb
vendored
Normal file
15
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet.rb
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require "rubocop/sorbet/version"
|
||||||
|
require "yaml"
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Sorbet
|
||||||
|
class Error < StandardError; end
|
||||||
|
|
||||||
|
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
||||||
|
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
|
||||||
|
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
|
||||||
|
|
||||||
|
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
||||||
|
end
|
||||||
|
end
|
||||||
20
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/inject.rb
vendored
Normal file
20
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-sorbet-0.5.1/lib/rubocop/sorbet/inject.rb
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# The original code is from https://github.com/rubocop-hq/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
|
||||||
|
# See https://github.com/rubocop-hq/rubocop-rspec/blob/master/MIT-LICENSE.md
|
||||||
|
module RuboCop
|
||||||
|
module Sorbet
|
||||||
|
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
||||||
|
# bit of our configuration.
|
||||||
|
module Inject
|
||||||
|
def self.defaults!
|
||||||
|
path = CONFIG_DEFAULT.to_s
|
||||||
|
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
||||||
|
config = Config.new(hash, path).tap(&:make_excludes_absolute)
|
||||||
|
puts "configuration from #{path}" if ConfigLoader.debug?
|
||||||
|
config = ConfigLoader.merge_with_default(config, path)
|
||||||
|
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
module RuboCop
|
||||||
|
module Sorbet
|
||||||
|
VERSION = "0.5.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
146
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-stub-0.2.0/lib/sorbet-runtime-stub.rb
vendored
Normal file
146
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-stub-0.2.0/lib/sorbet-runtime-stub.rb
vendored
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
# typed: ignore
|
||||||
|
|
||||||
|
begin
|
||||||
|
gem "sorbet-runtime"
|
||||||
|
return
|
||||||
|
rescue Gem::LoadError
|
||||||
|
end
|
||||||
|
|
||||||
|
module T
|
||||||
|
class << self
|
||||||
|
def absurd(value); end
|
||||||
|
def all(type_a, type_b, *types); end
|
||||||
|
def any(type_a, type_b, *types); end
|
||||||
|
def attached_class; end
|
||||||
|
def class_of(klass); end
|
||||||
|
def enum(values); end
|
||||||
|
def nilable(type); end
|
||||||
|
def noreturn; end
|
||||||
|
def self_type; end
|
||||||
|
def type_alias(type=nil, &_blk); end
|
||||||
|
def type_parameter(name); end
|
||||||
|
def untyped; end
|
||||||
|
|
||||||
|
def assert_type!(value, _type, _checked: true)
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast(value, _type, _checked: true)
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
def let(value, _type, _checked: true)
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
def must(arg, _msg = nil)
|
||||||
|
arg
|
||||||
|
end
|
||||||
|
|
||||||
|
def proc
|
||||||
|
T::Proc.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def reveal_type(value)
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
def unsafe(value)
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Sig
|
||||||
|
def sig(arg0=nil, &blk); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Helpers
|
||||||
|
def abstract!; end
|
||||||
|
def interface!; end
|
||||||
|
def final!; end
|
||||||
|
def sealed!; end
|
||||||
|
def mixes_in_class_methods(mod); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Generic
|
||||||
|
include T::Helpers
|
||||||
|
|
||||||
|
def type_parameters(*params); end
|
||||||
|
def type_member(variance=:invariant, fixed: nil, lower: nil, upper: BasicObject); end
|
||||||
|
def type_template(variance=:invariant, fixed: nil, lower: nil, upper: BasicObject); end
|
||||||
|
|
||||||
|
def [](*types)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Array
|
||||||
|
def self.[](type); end
|
||||||
|
end
|
||||||
|
|
||||||
|
Boolean = Object.new.freeze
|
||||||
|
|
||||||
|
module Configuration
|
||||||
|
def self.call_validation_error_handler(signature, opts); end
|
||||||
|
def self.call_validation_error_handler=(value); end
|
||||||
|
def self.default_checked_level=(default_checked_level); end
|
||||||
|
def self.enable_checking_for_sigs_marked_checked_tests; end
|
||||||
|
def self.enable_final_checks_on_hooks; end
|
||||||
|
def self.enable_legacy_t_enum_migration_mode; end
|
||||||
|
def self.reset_final_checks_on_hooks; end
|
||||||
|
def self.hard_assert_handler(str, extra); end
|
||||||
|
def self.hard_assert_handler=(value); end
|
||||||
|
def self.inline_type_error_handler(error); end
|
||||||
|
def self.inline_type_error_handler=(value); end
|
||||||
|
def self.log_info_handler(str, extra); end
|
||||||
|
def self.log_info_handler=(value); end
|
||||||
|
def self.scalar_types; end
|
||||||
|
def self.scalar_types=(values); end
|
||||||
|
def self.sealed_violation_whitelist; end
|
||||||
|
def self.sealed_violation_whitelist=(sealed_violation_whitelist); end
|
||||||
|
def self.sig_builder_error_handler(error, location); end
|
||||||
|
def self.sig_builder_error_handler=(value); end
|
||||||
|
def self.sig_validation_error_handler(error, opts); end
|
||||||
|
def self.sig_validation_error_handler=(value); end
|
||||||
|
def self.soft_assert_handler(str, extra); end
|
||||||
|
def self.soft_assert_handler=(value); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Enumerable
|
||||||
|
def self.[](type); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Enumerator
|
||||||
|
def self.[](type); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Hash
|
||||||
|
def self.[](keys, values); end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Proc
|
||||||
|
def bind(*_)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def params(*_param)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def void
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def returns(_type)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Range
|
||||||
|
def self.[](type); end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Set
|
||||||
|
def self.[](type); end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -81,6 +81,7 @@ switch
|
|||||||
tap
|
tap
|
||||||
tap-info
|
tap-info
|
||||||
tap-new
|
tap-new
|
||||||
|
tc
|
||||||
test
|
test
|
||||||
tests
|
tests
|
||||||
typecheck
|
typecheck
|
||||||
|
|||||||
@ -1770,6 +1770,9 @@ For example, you might add something like the following to your ~/.profile, ~/.b
|
|||||||
* `HOMEBREW_SKIP_OR_LATER_BOTTLES`:
|
* `HOMEBREW_SKIP_OR_LATER_BOTTLES`:
|
||||||
If set with `HOMEBREW_DEVELOPER`, do not use bottles from older versions of macOS. This is useful in development on new macOS versions.
|
If set with `HOMEBREW_DEVELOPER`, do not use bottles from older versions of macOS. This is useful in development on new macOS versions.
|
||||||
|
|
||||||
|
* `HOMEBREW_SORBET_RUNTIME`:
|
||||||
|
Enable runtime typechecking using Sorbet.
|
||||||
|
|
||||||
* `HOMEBREW_SVN`:
|
* `HOMEBREW_SVN`:
|
||||||
Use this as the `svn`(1) binary.
|
Use this as the `svn`(1) binary.
|
||||||
|
|
||||||
|
|||||||
@ -2446,6 +2446,10 @@ If set, use Pry for the \fBbrew irb\fR command\.
|
|||||||
If set with \fBHOMEBREW_DEVELOPER\fR, do not use bottles from older versions of macOS\. This is useful in development on new macOS versions\.
|
If set with \fBHOMEBREW_DEVELOPER\fR, do not use bottles from older versions of macOS\. This is useful in development on new macOS versions\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
|
\fBHOMEBREW_SORBET_RUNTIME\fR
|
||||||
|
Enable runtime typechecking using Sorbet\.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
\fBHOMEBREW_SVN\fR
|
\fBHOMEBREW_SVN\fR
|
||||||
Use this as the \fBsvn\fR(1) binary\.
|
Use this as the \fBsvn\fR(1) binary\.
|
||||||
.
|
.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user