2024-01-30 22:48:36 -08:00
|
|
|
# typed: strict
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require "method_source"
|
|
|
|
require "rubocop"
|
|
|
|
require_relative "../../../rubocops"
|
|
|
|
|
|
|
|
module Tapioca
|
|
|
|
module Compilers
|
2024-02-04 11:46:03 -08:00
|
|
|
class RuboCop < Tapioca::Dsl::Compiler
|
|
|
|
# This should be a module whose singleton class contains RuboCop::AST::NodePattern::Macros,
|
|
|
|
# but I don't know how to express that in Sorbet.
|
|
|
|
ConstantType = type_member { { fixed: Module } }
|
2024-01-30 22:48:36 -08:00
|
|
|
sig { override.returns(T::Enumerable[Module]) }
|
|
|
|
def self.gather_constants
|
2024-02-04 11:46:03 -08:00
|
|
|
all_modules.select do |klass|
|
|
|
|
next unless klass.singleton_class < ::RuboCop::AST::NodePattern::Macros
|
|
|
|
|
|
|
|
path = T.must(Object.const_source_location(klass.to_s)).fetch(0).to_s
|
|
|
|
# exclude vendored code, to avoid contradicting their RBI files
|
2024-02-04 12:58:34 -08:00
|
|
|
!path.include?("/vendor/bundle/ruby/") &&
|
2024-02-04 11:46:03 -08:00
|
|
|
# exclude source code that already has an RBI file
|
2024-02-10 11:03:50 -08:00
|
|
|
!File.exist?("#{path}i") &&
|
2024-02-04 11:46:03 -08:00
|
|
|
# exclude source code that doesn't use the DSLs
|
2024-02-10 11:03:50 -08:00
|
|
|
File.readlines(path).any?(/def_node_/)
|
2024-02-04 11:46:03 -08:00
|
|
|
end
|
2024-01-30 22:48:36 -08:00
|
|
|
end
|
|
|
|
|
|
|
|
sig { override.void }
|
|
|
|
def decorate
|
|
|
|
root.create_path(constant) do |klass|
|
|
|
|
constant.instance_methods(false).each do |method_name|
|
|
|
|
source = constant.instance_method(method_name).source.lstrip
|
2024-02-04 11:46:03 -08:00
|
|
|
# For more info on these DSLs:
|
|
|
|
# https://www.rubydoc.info/gems/rubocop-ast/RuboCop/AST/NodePattern/Macros
|
|
|
|
# https://github.com/rubocop/rubocop-ast/blob/master/lib/rubocop/ast/node_pattern.rb
|
|
|
|
# https://github.com/rubocop/rubocop-ast/blob/master/lib/rubocop/ast/node_pattern/method_definer.rb
|
|
|
|
# The type signatures below could maybe be stronger, but I only wanted to avoid errors:
|
2024-02-10 11:03:50 -08:00
|
|
|
case source
|
|
|
|
when /\Adef_node_matcher/
|
2024-01-30 22:48:36 -08:00
|
|
|
# https://github.com/Shopify/tapioca/blob/3341a9b/lib/tapioca/rbi_ext/model.rb#L89
|
|
|
|
klass.create_method(
|
|
|
|
method_name.to_s,
|
|
|
|
parameters: [
|
2024-02-11 20:47:22 -08:00
|
|
|
create_param("node", type: "RuboCop::AST::Node"),
|
2024-01-30 22:48:36 -08:00
|
|
|
create_kw_rest_param("kwargs", type: "T.untyped"),
|
|
|
|
create_block_param("block", type: "T.untyped"),
|
|
|
|
],
|
|
|
|
return_type: "T.untyped",
|
|
|
|
)
|
2024-02-10 11:03:50 -08:00
|
|
|
when /\Adef_node_search/
|
2024-01-30 22:48:36 -08:00
|
|
|
klass.create_method(
|
|
|
|
method_name.to_s,
|
|
|
|
parameters: [
|
2024-02-11 20:47:22 -08:00
|
|
|
create_param("node", type: "RuboCop::AST::Node"),
|
|
|
|
create_rest_param("pattern", type: "T.any(String, Symbol)"),
|
|
|
|
create_kw_rest_param("kwargs", type: "T.untyped"),
|
2024-01-30 22:48:36 -08:00
|
|
|
create_block_param("block", type: "T.untyped"),
|
|
|
|
],
|
|
|
|
return_type: method_name.to_s.end_with?("?") ? "T::Boolean" : "T.untyped",
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|