Giter Club home page Giter Club logo

rbi-central's Introduction

RBI Central

Build Status

Overview

RBI Central is a cumulative repository of RBI ("Ruby Interface") file annotations for public gems which can be imported by Tapioca. This repository can be used to annotate gem RBIs that Tapioca can’t represent fully and even fix type checking errors as a result.

Usage

The RBIs in this repository are used by Tapioca.

The rbi-central gem exists only to prevent name squatting - it should not be installed.

Annotations

Annotations are hand-written RBI files for commonly used gems that tell Sorbet information about the gem (e.g., constants, ancestors, methods) that isn't already generated by Tapioca. In other words, annotations are shareable shims.

In this repository, annotations are placed in the rbi/annotations folder.

Index

Each annotation from the rbi/annotations folder must be defined in the index.json file at the root of this repository:

{
    "gemA": { // gem name
        // optional: list of gems that need to be installed to test gemA RBI
        "dependencies": [
            "gemB",
            "gemC"
        ],
        // optional: list of files that need to be required to test gemA RBI
        "requires": [
            "file1",
            "file2",
        ]
    }
}

If you're copying this into your own index.json, make sure you strip out the comments.

See the index validation schema for more details.

Pulling annotations

To pull relevant gem annotations into your project, run Tapioca's annotations command inside your project:

$ bin/tapioca annotations

CI checks

The CI for this repository is written using GitHub Actions. Here is a list of currently available CI checks:

CLI Command Description
bundle exec repo check index Lint index.json and check entries match rbi/annotations/*.rbi files
bundle exec repo check rubygems Check new RBI files belong to public gems
bundle exec repo check rubocop Lint RBI files
bundle exec repo check runtime Check RBI annotations against runtime behavior
bundle exec repo check static Check RBI annotations against Tapioca generated RBIs and Sorbet

To avoid pushing a PR with errors, configure the pre-push git hook by running:

$ git config core.hooksPath gem/hooks

This git hook will run most of the CI checks and block the push if you don't pass all the tests.

Runtime checks

Ensure the constants (constants, classes, modules) and properties (methods, attribute accessors) exist at runtime.

For each gem the test works as follows:

  1. Create a temporary directory
  2. Add a Gemfile pointing to the gem (and possible dependencies, listed in index key dependencies)
  3. Add a Ruby script that:
    1. Requires the gem (and possible other requirements, listed in index key requires)
    2. Tries to const_get each constant defined in the RBI file
    3. Tries to call instance_method for each method and attribute accessor (or method for singleton methods) in the RBI file

It is possible to allow necessary shims for non-existing runtime definitions by using comment tags:

  • @missing_method to indicate that a method is delegated to another receiver using method_missing
  • @shim to indicate that a definition doesn't actually exist at runtime but is needed to allow type checking

Static checks

Ensure the constants (constants, classes, modules) and properties (methods, attribute accessors) exist are not duplicated from Tapioca generated RBIs and do not create type errors when running Sorbet.

For each gem the test works as follows:

  1. Create a temporary directory
  2. Add a Gemfile pointing to the gem (and possible dependencies, listed in index key dependencies)
  3. Generate the RBIs for gems using tapioca gems
  4. Check duplication with RBIs from gems using tapioca check-shims
  5. Check for type errors using srb tc

Contributing

If you working on the gem using VS Code, change into the gem/ directory then run code .. This ensures that Sorbet and vscode-rdbg will work correctly.

Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/rbi-central.

This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

rbi-central's People

Contributors

adisonlampert avatar amomchilov avatar andyw8 avatar bdewater avatar bdlangton avatar bradleybuda avatar connorshea avatar dependabot[bot] avatar dewyze avatar dirceu avatar egiurleo avatar fcheung avatar fsateler avatar gagocarrilloedgar avatar ghiculescu avatar jenshenny avatar johnernaut avatar kaanozkan avatar korri avatar leifg avatar mmenanno avatar morriar avatar olivier-thatch avatar paracycle avatar rafaelfranca avatar randyn avatar ryanbrushett avatar thomasmarshall avatar vinistock avatar wildmaples avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rbi-central's Issues

Latest actionpack main is incompatible with current annotations

Problem

We're seeing the following typecheck error in one of our projects that runs Rails main:

sorbet/rbi/gems/actionpack@7.2.0.alpha-6c9967f85ada90f8ca58e794a850e887ceb45132.rbi:5372: Malformed sig. Type not specified for argument block https://srb.help/5003
    5372 |  def merge!(other_hash, &block); end
                                    ^^^^^
    sorbet/rbi/annotations/actionpack.rbi:78: Signature
    78 |  sig { params(other_hash: T.untyped).returns(ActionController::Parameters) }
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Context

Sidekiq 7.0 incompatible with current sidekiq annotations

Problem

When running type on a project that uses the latest sidekiq version, I will get this type error:

sorbet/rbi/gems/[email protected]:2965: Cannot initialize the module Worker by constant assignment https://srb.help/4022
    2965 |Sidekiq::Worker = Sidekiq::Job
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    sorbet/rbi/annotations/sidekiq.rbi:79: Previously defined as a module here
    79 |module Sidekiq::Worker
        ^^^^^^^^^^^^^^^^^^^^^^
  Note:
    Sorbet does not allow treating constant assignments as class or module definitions,
    even if the initializer computes a Module object at runtime. See the docs for more.

At first glance this doesn't seem to an issue of annotations, but changing all references of Sidekiq::Worker to Sidekiq::Job in sorbet/rbi/annotations/sidekiq.rbi fixes the issue.

Weirdly enough, when changing the references in a project that uses sidekiq < 7.0.0 also causes an error:

Method sidekiq_options does not exist on T.class_of(MyJob) https://srb.help/7003

Seems like a good use case for versioning

Context

I'm using include Sidekiq::Job in all my workers (in 6.0. and 7.0)

Sidekiq aliases Sidekiq::Job to Sidekiq::Worker. Weirdly enough this has not been introduced in 7.0 and has been there before.

  • Gem name: sidekiq
  • Gem version: 7.0.0
  • Tapioca version: 0.10.2
  • Sorbet version: 0.5.10517

Conflict between lhm.rbi and lhm-shopify.rbi

Problem

The lhm.rbi and lhm-shopify.rbi annotations don't play nicely with each other. This error ends up raised during a typecheck:
image

Looks like these are the conflicting lines:

sig { params(lowest: T.nilable(Numeric), highest: T.nilable(Numeric)).void }
def notify(lowest = nil, highest = nil); end

sig { params(_arg0: T.untyped).void }
def notify(*_arg0); end

Context

graphql gem renamed an argument, making annotations incorrect

Cleanup root directory

It'd be cleaner to have a minimal root directory with things like Gemfile, Gemfile.lock, .rubocop.yml and dev.yml stored in a sub directory without hindering UX.

It's worth investing some time into it to see what are some possible options and go on from there if there's a suitable one.

sorbet/rbi/annotations/actionmailer.rbi:8: Unable to resolve constant Mail

Problem

> bundle exec srb tc
sorbet/rbi/annotations/actionmailer.rbi:8: Unable to resolve constant Mail https://srb.help/5002
     8 |  sig { params(headers: T.untyped, block: T.nilable(T.proc.void)).returns(Mail::Message) }
                                                                                  ^^^^
  Did you mean Spoom::Cli::Main? Use -a to autocorrect
    sorbet/rbi/annotations/actionmailer.rbi:8: Replace with Spoom::Cli::Main
     8 |  sig { params(headers: T.untyped, block: T.nilable(T.proc.void)).returns(Mail::Message) }
                                                                                  ^^^^
    sorbet/rbi/gems/[email protected]:217: Spoom::Cli::Main defined here
     217 |class Spoom::Cli::Main < ::Thor
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  Did you mean ActionMailer::Base? Use -a to autocorrect
    sorbet/rbi/annotations/actionmailer.rbi:8: Replace with ActionMailer::Base
     8 |  sig { params(headers: T.untyped, block: T.nilable(T.proc.void)).returns(Mail::Message) }
                                                                                  ^^^^
    sorbet/rbi/annotations/actionmailer.rbi:7: ActionMailer::Base defined here
     7 |class ActionMailer::Base
        ^^^^^^^^^^^^^^^^^^^^^^^^

Context

Rails latest 7.0.8, fresh project, fresh install of latest sorbet/tapioca. Ran bin/tapioca gem to generate from installed gems.

I checked and sorbet/rbi/annotations/actionmailer.rbi in my project is the same as in this repo:
https://github.com/Shopify/rbi-central/blob/main/rbi/annotations/actionmailer.rbi

sorbet/rbi/gems/[email protected] is empty however - is this because it's missing in thetapioca repo?

image

What should be done here? It seems like the only path is to add this constant to the todo - but that command is actively deprecating?

> bundle list | ack '(tapioca|sorbet)'
  * sorbet (0.5.11014)
  * sorbet-runtime (0.5.11014)
  * sorbet-static (0.5.11014)
  * sorbet-static-and-runtime (0.5.11014)
  * tapioca (0.11.9)
  * yard-sorbet (0.8.1)

Handle gem annotations versioning

Problem

Available constants, methods and signatures may vary depending on the version of the gem.

  • rbi-central should provide a way to annotates specific versions of a gem
  • tapioca should pull only relevant annotations for the considered version of a gem

Possible solution

Annotate the annotations with the gem version concerned when we need to make a distinction between two versions:

module Foo
  # This annotation is defined in all versions
  def foo; end

  # This annotation is only available in versions > 1.0
  # @version > 1.0
  def bar(x); end

  # This annotation is only available in versions <= 1.0
  # @version <= 1.0
  def bar; end
end

ActiveSupport `Array#extract!` missing block param

Problem

ActiveSupport Array#extract! accepts an optional block arg but the RBI does not include the block argument:

https://github.com/Shopify/rbi-central/blob/main/rbi/annotations/activesupport.rbi#L145-L146

Context

Validate signatures at runtime

Problem

Right now we only operate a few checks on the runtime validity of an annotations file:

  • Require can be done
  • Constants
  • Constants are of the right kind (ie. classes are classes)
  • Method exists (or can be delegated to method_missing

But we currently do not check if:

  • The method arity in the RBI is correct
  • The params are of the right type in the signature
  • The return type is of the right type in the signature

This would be another step in ensuring our annotations are correct.

Improve README

  • How to interact with the repo?
  • What are annotations?
  • What are some CI checks currently available?
  • Overall goal of the repo

Validate signatures statically

Problem

sorbet-typed was allowing users to attach a test file to each annotation so it could be checked with Sorbet.

In rbi-central, since we check the RBIs against Sorbet and Tapioca we already cover a large part of this.
What's is missing is the ability to exercise the signatures as sorbet-typed does.

Wrong signature for ActiveModel::Errors#details

Problem

I believe the signature here is too restrictive:

sig { returns(T::Hash[Symbol, T::Array[T::Hash[Symbol, Symbol]]]) }
def details; end

e.g.

[1] pry(main)> ae = ActiveModel::Errors.new(Object.new)
=> #<ActiveModel::Errors []>
[2] pry(main)> ae.add(:foo, "bar")
=> #<ActiveModel::Error attribute=foo, type=bar, options={}>
[3] pry(main)> ae.details
=> {:foo=>[{:error=>"bar"}]}

I think it should instead be:

sig { returns(T::Hash[Symbol, T::Array[T::Hash[Symbol, T.untyped]]]) }
def details; end

Context

n/a

Typecheck alongside tapioca generation

If we run tapioca gem before scripts/check_types we could reduce the number of suppressed errors in CI:

"--suppress-error-code=5002,5020,5035,5067"

This will potentially lead to surfacing more errors.

It'd be nice to have a tapioca gem foo --in-isolation flag that could create the gem RBI without a proper project that we can utilize in CI.

Ensure the gem is public

We need to make sure no annotations for private gems are being pushed. We can have a CI check that queries rubygems.org to confirm a gem is public.

An edge case to watch for is internal gems that are on rubygems.org but aren't actually public. Their version number is always 9001.0, ie. https://rubygems.org/gems/shopify-adt

Improve CI tests

  • Add a script that populates the next command with modified RBIs
  • Run CI only on modified RBIs
  • Lint index.json
  • Enforce index.json entries match rbi/annotations/*.rbi files

Add `dev.yml`

  • A step to do bundle install upon dev up
  • A step to run bundle exec rubocop upon dev style

Should we run rubocop on annotations?

Annotations don't have a final newline, which will trigger linting errors if they're imported to a project that uses Rubocop or another linter. I'm wondering if we should use do some sort of linting on annotation files so they don't cause linting errors in other projects.

Return type mismatch on ActionMailer::Base#mail annotation

Problem

When we use the type annotations for action_mailer we get this error Expected type ActionMailer::MessageDelivery, got type Mail::Message with value. From what I can tell the #mail method returns a Mail::Message type, see return here and instance variable set here.

Context

Validate delegation annotations

Problem

We're currently using @method_missing to represent method being delegated to another class:

class MyClass

  # This method is actually delegated
  # @method_missing: delegated to MyOtherClass
  def my_method; end
end

The goal of this annotation is making it easier for the maintainer to find where the implementation of the method is and to define the right signature.

I wonder if we could be smarter and also validate that the target class does indeed provide the said method?

error: Couldn't find delegated `my_method` in `MyOtherClass`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.