An open API service indexing awesome lists of open source software.

https://github.com/etiennebacher/flir

Find and Fix Lints in R Code
https://github.com/etiennebacher/flir

Last synced: 29 days ago
JSON representation

Find and Fix Lints in R Code

Awesome Lists containing this project

README

        

---
output: github_document
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```

# flir

(pronounced "fleer" as in "beer")

[![R-CMD-check](https://github.com/etiennebacher/flir/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/etiennebacher/flir/actions/workflows/R-CMD-check.yaml)

---

:information_source: Until v0.2.1 (included), this package was named `flint`. In v0.3.0, it was renamed `flir`.

---

`flir` is a small R package to find and replace lints in R code.

* Lints detection with `lint()`
* Automatic replacement of lints with `fix()`
* Compatibility with (some) `{lintr}` rules
* Fast

`flir` is powered by [`astgrepr`](https://github.com/etiennebacher/astgrepr/),
which is itself built on the Rust crate [`ast-grep`](https://ast-grep.github.io/).

## Installation

``` r
install.packages('flir', repos = c('https://etiennebacher.r-universe.dev', 'https://cloud.r-project.org'))
```

**Note:** using `remotes::install_github()`, `devtools::install_github()`,
or `pak::pak()` without specifying the R-universe repo will require you to
[setup Rust](https://www.rust-lang.org/tools/install) to build the package.

## Usage

Optional setup:

* `setup_flir()`: creates the folder `flir` and populates it with built-in rules
as well as a cache file. You can modify those rules or add new ones if you
want more control.

You can use `flir` as-is, without any setup. However, running `setup_flir()`
enables the use of caching, meaning that the subsequent runs will be faster. It
is also gives you a place where you can store custom rules for your
project/package.

The everyday usage consists of two functions:

* `lint()` looks for lints in R files;
* `fix()` looks for lints in R files and automatically applies their replacement
(if any).

One can also experiment with `flir::lint_text()` and `flir::fix_text()`:

```{r}
flir::lint_text(
"
any(is.na(x))
any(duplicated(y))
"
)
flir::fix_text(
"
any(is.na(x))
any(duplicated(y))
"
)
```

## Real-life examples

I tested `flir` on several packages while developing it. I proposed some pull
requests for those packages. Here are a few:

* `ggplot2`: [#6050](https://github.com/tidyverse/ggplot2/pull/6050/files) and [#6051](https://github.com/tidyverse/ggplot2/pull/6051/files)
* `marginaleffects`: [#1171](https://github.com/vincentarelbundock/marginaleffects/pull/1171/files) and [#1177](https://github.com/vincentarelbundock/marginaleffects/pull/1177/files)
* `targets`: [#1325](https://github.com/ropensci/targets/pull/1325/files)
* `tinytable`: [#325](https://github.com/vincentarelbundock/tinytable/pull/325/files)
* `usethis`: [#2048](https://github.com/r-lib/usethis/pull/2048/files)

Except for some manual tweaks when the replacement was wrong (I was testing
`flir` after all), all changes were generated by `flir::fix_package()` or
`flir::fix_dir()`.

## Comparison with existing tools

The most used tool for lints detection in R is `lintr`. However, `lintr`'s
performance is not optimal when it is applied on medium to large packages. Also,
`lintr` cannot perform automatic replacement of lints.

`styler` is a package to clean code by fixing indentation and other things, but
doesn't perform code replacement based on lints.

`flir` is quite performant. This is a small benchmark on 3.5k lines of code with
a few linters:

```{r}
file <- system.file("bench/test.R", package = "flir")

bench::mark(
lintr = lintr::lint(
file,
linters = list(
lintr::any_duplicated_linter(),
lintr::any_is_na_linter(),
lintr::matrix_apply_linter(),
lintr::function_return_linter(),
lintr::lengths_linter(),
lintr::T_and_F_symbol_linter(),
lintr::undesirable_function_linter(),
lintr::expect_length_linter()
)
),
flir = flir::lint(
file,
linters = list(
flir::any_duplicated_linter(),
flir::any_is_na_linter(),
flir::matrix_apply_linter(),
flir::function_return_linter(),
flir::lengths_linter(),
flir::T_and_F_symbol_linter(),
flir::undesirable_function_linter(),
flir::expect_length_linter()
),
verbose = FALSE,
open = FALSE
),
check = FALSE
)
```

## Why the name "flir"?

`flir` was originally named `flint` but I had to rename it to avoid conflicts with
a package named `flint` on CRAN.

`flir` stands for "**F**ix **L**ints **I**n **R**".

## Contributing

Did you find some bugs or some errors in the documentation? Do you want
`flir` to support more rules?

Take a look at the [contributing
guide](https://flir.etiennebacher.com/CONTRIBUTING.html) for
instructions on bug report and pull requests.

## Acknowledgements

The website theme was heavily inspired by Matthew Kay’s `ggblend`
package: .