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.

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 in the current working directory;
  2. if not present, go to the parent folder until a jarl.toml 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. 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.

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

assignment

This argument is deprecated. Use the rule-specific argument [lint.assignment] instead (see below).

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

assignment

This takes a single value ("<-" or "=") indicating the preferred assignment operator in the files to check. If assignment = "<-" and if the "assignment" rule is enabled, then any use of the "=" operator to assign values will be reported, and vice-versa.

This option doesn’t have a default value.

[lint]
...

[lint.assignment]
operator = "<-" # or "="

duplicated_arguments

Use skipped-functions to fully replace the default list of functions that are allowed to have duplicated arguments. Use extend-skipped-functions to add to the default list. Specifying both is an error.

Function names in skipped-functions or extend-skipped-functions also match namespaced calls, e.g. skipped-functions = ["list2"] will ignore list2() and rlang::list2().

Default: skipped-functions = ["c", "mutate", "summarize", "transmute"]

[lint]
...

[lint.duplicated_arguments]
# Ignore duplicated arguments in `list()` only.
skipped-functions = ["list"]

implicit_assignment

Use skipped-functions to fully replace the default list of functions that are allowed to contain implicit assignment. Use extend-skipped-functions to add to the default list. Specifying both is an error.

Function names in skipped-functions or extend-skipped-functions also match namespaced calls, e.g. skipped-functions = ["list2"] will ignore list2() and rlang::list2().

Default: skipped-functions = ["expect_error", "expect_warning", "expect_message", "expect_snapshot", "quote", "suppressMessages", "suppressWarnings"]

[lint]
...

[lint.implicit_assignment]
# Ignore implicit assignment in `list()` only.
skipped-functions = ["list"]

quotes

This takes a single value ("single" or "double") indicating the preferred quote style in the files to check. If quote = "double" and if the "quotes" rule is enabled, then any use of single quotes ' will be reported, and vice-versa.

Default: double

[lint]
...

[lint.quotes]
quote = "single" # or "double"

unreachable_code

Use stopping-functions to fully replace the default list of functions that are considered to stop execution (never return). Use extend-stopping-functions to add to the default list. Specifying both is an error.

Function names in stopping-functions or extend-stopping-functions also match namespaced calls, e.g. stopping-functions = ["abort"] will consider abort() and rlang::abort() as stopping functions.

Default: stopping-functions = ["stop", ".Defunct", "abort", "cli_abort", "q", "quit"].

[lint]
...

[lint.unreachable_code]
# Add a custom function to the list of stopping functions
extend-stopping-functions = ["my_custom_stop"]

unused_function

Use skipped-functions to fully replace the default list of functions that are allowed to be unused in the R package. Function names in skipped-functions are parsed as regular expressions (this differs from other rules that have a skipped-functions argument).

unused_function might return false positives because Jarl cannot statically determine whether a function is used. By default, Jarl will hide unused_function diagnostics if there are more than 50, as this would suggest that the package has some internal mechanism to use those functions. This number can be changed with the threshold-ignore argument.

Defaults:

  • skipped-functions = []
  • threshold-ignore = 50
[lint]
...

[lint.unused_function]
# Ignore all functions that start with "pl_" or "cs_", and the function
# "my.function"
skipped-functions = ["^cs_", "^pl_", "my\\.function"]
# Set a custom threshold above which diagnostics for this rule aren't reported
# (this is basically equivalent to never hiding unused functions).
threshold-ignore = 10000