Configuration file

Introduction

To avoid typing options every time and to ensure all uses of Jarl in a project are consistent, it is possible to store options in jarl.toml (or .jarl.toml).

This file could look like this:

[lint]
# Only report violations about performance or correctness.
select = ["PERF", "CORR"]
# If "--fix" is used, only apply automatic fixes to performance-related
# violations.
fixable = ["PERF"]
# Exclude one or several specific files.
exclude = ["R/my_custom_autogenerated_file.R"]
# Use the default set of excluded files (mostly files that are automatically
# generated by other tools).
default-exclude = true

These arguments (among others) are described below.

Interaction between CLI arguments and config file

Arguments in the command line always have the priority on those specified in jarl.toml. For example, if you have the following file:

[lint]
select = ["PERF", "length_test"]
ignore = []

then calling

jarl check . --ignore PERF

will only apply the rule length_test.

Config file detection

Jarl follows a hierarchical strategy to detect the closest config file relative to the current working directory (inspired by Ruff in Python).

Jarl follows these steps:

  1. look for jarl.toml or .jarl.toml in the current working directory;
  2. if not present, go to the parent folder until one of them is found;
  3. if none of the parent directories contain the config file, Jarl checks if one exists in the home config directory. For Unix users, it looks for ~/.config/jarl/jarl.toml (or ~/.config/jarl/.jarl.toml). For Windows users, it looks for ~/AppData/Roaming/jarl/jarl.toml.
  4. if the config file is not present there, then it stops looking for one.

Storing a default jarl.toml in the home config directory may be useful to apply some arguments by default on all R files.

Note that Jarl cannot handle multiple config files, it will use the first one it finds.

Top-level arguments

select

Select some rules by default.

This has the same capabilities as --select, so it is possible to pass rule names and names of groups of rules:

[lint]
select = ["PERF", "length_test"]

extend-select

Select some rules in addition to select.

This is useful when you want to use the default set of rules and some additional opt-in rules. In this scenario, you only need to add extend-select = ["<some_rule>"] instead of writing all default rule names.

This has the same constraints as select.

# Select all default rules and all `TESTTHAT` rules, which are disabled by
# default.
[lint]
extend-select = ["TESTTHAT"]

ignore

Ignore some rules by default.

This has the same capabilities as --ignore, so it is possible to pass rule names and names of groups of rules:

[lint]
ignore = ["PERF", "length_test"]

include

Files and/or directories that are checked. By default, Jarl checks all files with a .R, .qmd, .Rmd, or .rmd extension, but ignores files starting with a comment # Generated by.

When both include and exclude are specified, a file is checked only if it matches at least one include pattern and does not match any exclude pattern.

This takes a list relative paths to ignore:

[lint]
include = ["foo.R", "tests/"]

It also supports glob patterns:

[lint]
# Check only Rmd and qmd files
include = ["**/*{.Rmd,qmd}"]

exclude

Files and/or directories that are not checked.

This takes a list relative paths to ignore:

[lint]
exclude = ["excluded.R", "tests/"]

It also supports glob patterns:

[lint]
exclude = ["excluded-*.R"]

default-exclude

This takes a boolean argument indicating whether the default file exclude patterns are used.

By default, Jarl (just like the Air formatter) excludes a set of files and folders that are probably not worth checking, for instance because they are automatically generated by another program.

The complete list of default exclude patterns is:

  • .git/
  • renv/
  • revdep/
  • cpp11.R
  • RcppExports.R
  • extendr-wrappers.R
  • import-standalone-*.R
[lint]
default-exclude = true

per-file-ignores

This lets you ignore specific rules in specific files. It is a table mapping glob patterns to lists of rule names (or groups of rules, e.g. PERF).

Patterns are resolved relative to the directory containing jarl.toml, just like include and exclude.

[lint.per-file-ignores]
# Ignore `true_false_symbol` in `foo.R`.
"foo.R" = ["true_false_symbol"]
# Ignore all "PERF" rules under the `tests/` directory.
"tests/" = ["PERF"]

A pattern can be negated with a leading !, in which case its rules are ignored in every file that does not match the pattern:

[lint.per-file-ignores]
# Ignore `any_is_na` everywhere except in the `R/` directory.
"!R/**" = ["any_is_na"]

When several patterns match a file, the rules from all of them are ignored.

Because [lint.per-file-ignores] is a TOML table, every key written after its header belongs to that table. Any other [lint] option (such as default-exclude or select) must therefore appear before the [lint.per-file-ignores] header, otherwise it is read as a glob pattern instead of an option:

[lint]
# Correct: scalar options come first.
default-exclude = false

[lint.per-file-ignores]
"tests/" = ["PERF"]
[lint.per-file-ignores]
"tests/" = ["PERF"]
# Wrong: this is parsed as a pattern, not as the `default-exclude` option, and
# Jarl will report a configuration error.
default-exclude = false

fixable

This determines which rule violations will be fixed if --fix is passed. This can be useful if you only trust Jarl’s automatic fixes for some rules and want to avoid automatic fixes for other rules. It takes a list of rule names or names or groups of rules, and defaults to all rules if this argument is not specified.

If a rule appears in both fixable and unfixable, unfixable takes precedence (i.e. violations of this rule will not be fixed).

[lint]
# Only fix violations of rules in the "PERF" group.
fixable = ["PERF"]
[lint]
# Do not fix any violation.
fixable = []

unfixable

This determines which rule violations will be not fixed, even if --fix is passed. This can be useful if you only trust Jarl’s automatic fixes for some rules and want to avoid automatic fixes for other rules. It takes a list of rule names or names or groups of rules, and defaults no rules if this argument is not specified.

If a rule appears in both fixable and unfixable, unfixable takes precedence (i.e. violations of this rule will not be fixed).

[lint]
# Fix all violations, except those for rules in the "PERF" group.
unfixable = ["PERF"]
[lint]
# Fix all violations.
unfixable = []

check-roxygen

This takes a boolean argument indicating whether to check code in roxygen2 comments. This only checks code in @examples and @examplesIf sections, and only if the R file is part of an R package.

Default: true

[lint]
check-roxygen = true

fix-roxygen

This takes a boolean argument indicating whether to apply automatic fixes to code in roxygen2 comments. This fixes code if all following conditions are respected:

  • the code is in @examples or @examplesIf sections
  • the file is part of an R package
  • --fix is passed in the command line

Default: false

[lint]
fix-roxygen = false

Rule-specific arguments

The operation of some rules can be customised with arguments in the configuration file, see the relevant rule documentation page for details: