Just another R linter
See the codeJarl is a fast linter for R: it does static code analysis to search for programming errors, bugs, and suspicious patterns of code.
lintr and flir1Jarl is built on Air, a fast formatter for R written in Rust.
See:
This shows what it looks like in the terminal:
test.R:
any(is.na(x))
if (all.equal(x, y)) {
print("x and y are equal")
}
# In the terminal:
$ jarl check test.R
warning: any_is_na
--> test.R:1:1
|
1 | any(is.na(x))
| ------------- `any(is.na(...))` is inefficient.
|
= help: Use `anyNA(...)` instead.
warning: all_equal
--> test.R:3:5
|
3 | if (all.equal(x, y)) {
| --------------- `all.equal()` can return a string instead of FALSE.
|
= help: Wrap `all.equal()` in `isTRUE()`, or replace it by `identical()` if
no tolerance is required.
Found 2 errors.
1 fixable with the `--fix` option (1 hidden fix can be enabled with the
`--unsafe-fixes` option).
Use --fix to automatically fix rule violations when possible:
$ jarl check test.R --fix
test.R:
anyNA(x)
if (all.equal(x, y)) {
print("x and y are equal")
}
This details how to install Jarl via the command line.
Note that the VS Code and Positron extensions contain a bundled version of Jarl, so you don't need to install it via the command line if you plan to use it via those extensions only. See the Editor support page for more information.
Either get binaries from the Releases page or install Jarl from the existing installer scripts below.
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/etiennebacher/jarl/releases/latest/download/jarl-installer.sh | sh
powershell Set-ExecutionPolicy Bypass -Scope Process -Force; `
iwr https://github.com/etiennebacher/jarl/releases/latest/download/jarl-installer.ps1 | iex
If you use Scoop, you can also install or update Jarl with these commands:
scoop bucket add r-bucket https://github.com/cderv/r-bucket.git
# install
scoop install jarl
# update
scoop update jarl
Jarl is published on PyPI under the name jarl-linter.
Therefore, it can be installed via uv and pipx:
# One-time run, not a global install:
uvx --from jarl-linter jarl check .
# Global install:
uv tool install jarl-linter
# or
pipx install jarl-linter
You can use Pixi to install Jarl from conda-forge:
# Add to a project
pixi add jarl
pixi run jarl check .
# Install globally
pixi global install jarl
# Run one-off command
pixi exec jarl check .
If you use Arch Linux, you can install Jarl from the Arch User Repository with yay or paru:
# With yay
yay -S jarl-bin
# With paru
paru -S jarl-bin
You can use mise to install Jarl from conda-forge:
# Add to a project
mise use conda:jarl
jarl check .
# Install globally
mise use --global conda:jarl
# Run one-off command
mise exec conda:jarl -- jarl check .
You can use Jarl with Nix and nixpkgs:
# Temporary shell
nix-shell -p jarl
jarl check .
# Run one-off command (with flakes enabled)
nix run nixpkgs#jarl -- check .
# One-off command with comma (https://github.com/nix-community/comma)
, jarl check .
# Add to NixOS configuration (permanent install)
environment.systemPackages = [
pkgs.jarl
];
# Add to home-manager
home.packages = [
pkgs.jarl
];
Modifying the user profile with nix-env or nix profile add is not recommended.
Some pre-releases may be available from the Releases page (the version usually contains alpha, see the installation instructions there).
Alternatively, if you have Rust installed, you should be able to get the development version with:
cargo install --git https://github.com/etiennebacher/jarl jarl --profile=release
cargoUsing the pre-built binaries will install Jarl in $HOME/.local/bin, e.g. /home/etienne/.local/bin/jarl.
Using cargo will install Jarl in $HOME/.cargo/bin, e.g. /home/etienne/.cargo/bin/jarl.
If you have both installed, the .local/bin one will take precedence.
Therefore, to run the version compiled with cargo, you must either delete the one in .local/bin or use the absolute path, e.g. /home/etienne/.cargo/bin/jarl check ..
lintr is the most famous R linter.
It provides dozens of rules related to performance, readibility, formatting, and more.
Jarl is heavily influenced by lintr since most rule definitions come from it.
However, lintr doesn't provide automatic fixes for rule violations, which makes it harder to use.
Its performance also noticeably degrades as the number of files and their length increase.
flir is a relatively novel package.
It uses ast-grep in the background to search and replace code patterns.
It is therefore quite flexible and easy to extend by users who may want more custom rules.
While both Jarl and ast-grep use tree-sitter in the background to parse R files, their structure is completely different.
Jarl is faster and also easier to link to the Language Server Protocol, which enables its use via VS Code or Positron extensions for instance.
lintr authors and contributors: while the infrastructure is completely different, all the rule definitions and a large part of the tests are inspired or taken from lintr.
Using 20 rules on the dplyr package (~25k lines of R code), Jarl took 0.131s, flir took 4.5s, and lintr took 18.5s (9s with caching enabled). ↩
Rust
97.8%
TypeScript
2.0%
Just another R linter
See the codeJarl is a fast linter for R: it does static code analysis to search for programming errors, bugs, and suspicious patterns of code.
lintr and flir1Jarl is built on Air, a fast formatter for R written in Rust.
See:
This shows what it looks like in the terminal:
test.R:
any(is.na(x))
if (all.equal(x, y)) {
print("x and y are equal")
}
# In the terminal:
$ jarl check test.R
warning: any_is_na
--> test.R:1:1
|
1 | any(is.na(x))
| ------------- `any(is.na(...))` is inefficient.
|
= help: Use `anyNA(...)` instead.
warning: all_equal
--> test.R:3:5
|
3 | if (all.equal(x, y)) {
| --------------- `all.equal()` can return a string instead of FALSE.
|
= help: Wrap `all.equal()` in `isTRUE()`, or replace it by `identical()` if
no tolerance is required.
Found 2 errors.
1 fixable with the `--fix` option (1 hidden fix can be enabled with the
`--unsafe-fixes` option).
Use --fix to automatically fix rule violations when possible:
$ jarl check test.R --fix
test.R:
anyNA(x)
if (all.equal(x, y)) {
print("x and y are equal")
}
This details how to install Jarl via the command line.
Note that the VS Code and Positron extensions contain a bundled version of Jarl, so you don't need to install it via the command line if you plan to use it via those extensions only. See the Editor support page for more information.
Either get binaries from the Releases page or install Jarl from the existing installer scripts below.
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/etiennebacher/jarl/releases/latest/download/jarl-installer.sh | sh
powershell Set-ExecutionPolicy Bypass -Scope Process -Force; `
iwr https://github.com/etiennebacher/jarl/releases/latest/download/jarl-installer.ps1 | iex
If you use Scoop, you can also install or update Jarl with these commands:
scoop bucket add r-bucket https://github.com/cderv/r-bucket.git
# install
scoop install jarl
# update
scoop update jarl
Jarl is published on PyPI under the name jarl-linter.
Therefore, it can be installed via uv and pipx:
# One-time run, not a global install:
uvx --from jarl-linter jarl check .
# Global install:
uv tool install jarl-linter
# or
pipx install jarl-linter
You can use Pixi to install Jarl from conda-forge:
# Add to a project
pixi add jarl
pixi run jarl check .
# Install globally
pixi global install jarl
# Run one-off command
pixi exec jarl check .
If you use Arch Linux, you can install Jarl from the Arch User Repository with yay or paru:
# With yay
yay -S jarl-bin
# With paru
paru -S jarl-bin
You can use mise to install Jarl from conda-forge:
# Add to a project
mise use conda:jarl
jarl check .
# Install globally
mise use --global conda:jarl
# Run one-off command
mise exec conda:jarl -- jarl check .
You can use Jarl with Nix and nixpkgs:
# Temporary shell
nix-shell -p jarl
jarl check .
# Run one-off command (with flakes enabled)
nix run nixpkgs#jarl -- check .
# One-off command with comma (https://github.com/nix-community/comma)
, jarl check .
# Add to NixOS configuration (permanent install)
environment.systemPackages = [
pkgs.jarl
];
# Add to home-manager
home.packages = [
pkgs.jarl
];
Modifying the user profile with nix-env or nix profile add is not recommended.
Some pre-releases may be available from the Releases page (the version usually contains alpha, see the installation instructions there).
Alternatively, if you have Rust installed, you should be able to get the development version with:
cargo install --git https://github.com/etiennebacher/jarl jarl --profile=release
cargoUsing the pre-built binaries will install Jarl in $HOME/.local/bin, e.g. /home/etienne/.local/bin/jarl.
Using cargo will install Jarl in $HOME/.cargo/bin, e.g. /home/etienne/.cargo/bin/jarl.
If you have both installed, the .local/bin one will take precedence.
Therefore, to run the version compiled with cargo, you must either delete the one in .local/bin or use the absolute path, e.g. /home/etienne/.cargo/bin/jarl check ..
lintr is the most famous R linter.
It provides dozens of rules related to performance, readibility, formatting, and more.
Jarl is heavily influenced by lintr since most rule definitions come from it.
However, lintr doesn't provide automatic fixes for rule violations, which makes it harder to use.
Its performance also noticeably degrades as the number of files and their length increase.
flir is a relatively novel package.
It uses ast-grep in the background to search and replace code patterns.
It is therefore quite flexible and easy to extend by users who may want more custom rules.
While both Jarl and ast-grep use tree-sitter in the background to parse R files, their structure is completely different.
Jarl is faster and also easier to link to the Language Server Protocol, which enables its use via VS Code or Positron extensions for instance.
lintr authors and contributors: while the infrastructure is completely different, all the rule definitions and a large part of the tests are inspired or taken from lintr.
Using 20 rules on the dplyr package (~25k lines of R code), Jarl took 0.131s, flir took 4.5s, and lintr took 18.5s (9s with caching enabled). ↩
Rust
97.8%
TypeScript
2.0%