Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Directives

A directive is an ordinary # comment that tells arity to stand down. One grammar covers the formatter, the linter, and both at once:

# arity[-format|-lint] <verb> [<rule>][: <reason>]

The verb says how far it reaches, the prefix says who it addresses:

formatterlinterboth
next# arity-format skip: why# arity-lint skip <rule>: why# arity skip: why
from# arity-format off# arity-lint off <rule># arity off
to# arity-format on# arity-lint on# arity on
file# arity-format skip-file: why# arity-lint skip-file <rule>: why# arity skip-file: why

Only a lint directive names a rule. # arity-format has no lint half to scope, and # arity covers every rule by construction.

skip — the next statement

Applies to the next non-trivia sibling: the next piece of code after the comment, whatever that is. The attachment skips blank lines and other comments, so the directive can sit above a block of documentation and still land on the code below it.

# arity-lint skip unused-binding: part of the documented API
config <- list(width = 80)

A trailing comment attaches the same way — to the code that follows it, not the code on its own line:

x <- 1 # arity-lint skip browser: applies to the NEXT statement, not this one
browser()

For the formatter, skip hands the marked statement back byte for byte — its own column, its interior alignment, its blank lines. Nothing about its layout is decided, which is the whole point:

# arity-format skip: the rows are the matrix
m <- matrix(c(1, 0,
              0, 1), nrow = 2)

offon — a region

Everything between the two markers, or to the end of the file if the on never comes. The markers themselves are ordinary comments and are formatted normally.

# arity-format off: generated by tools/codegen.R
lookup <- c(
  "a" = 1,
    "bb"  = 22
)
# arity-format on

An on closes every region opened with the same prefix. # arity off and # arity-format off are separate regions, and one does not close the other; an on that closes nothing is reported by misplaced-suppression.

skip-file — the whole file

For a generated or vendored file. # arity-format skip-file makes arity format hand the file back unchanged, so --check reports it clean.

# arity-lint skip-file unused-binding: generated by tools/codegen.R

Every rule at once

Writing a : where the rule ID would go widens a lint directive to every rule, including every rule arity ships in the future:

# arity-lint skip-file: generated, do not lint

The # arity column does the same by construction. Both are rarely what you want at file or region scope; prefer the rule-scoped form, which blanket-suppression will not flag.

In DESCRIPTION

The lint directives work in a DESCRIPTION too, on a line of their own:

Package: mypkg
# arity-lint skip unused-dependency: loaded reflectively by the plugin registry
Imports: somepkg

DCF has no trailing comments — a # in the middle of a value is part of that value — so a directive must start at column zero, and one written after a field applies to the field that follows it. A # line between the continuation lines of a single field is the exception: R’s read.dcf skips it and resumes the value, so a directive there covers the whole field it interrupts.

Of the formatter directives, only # arity-format skip-file is honored there.

Reasons

The text after the : is free-form and arity never interprets it — but telling a tool to stand down is a standing claim that it is wrong here, and that claim outlives whoever wrote it. Recording why keeps the next reader from having to guess whether it was considered or expedient. unexplained-suppression enforces the convention; it is off by default, so enable it with select.

Directives are linted too

Directives fail silently by nature: when one goes wrong, the symptom is that nothing happens, which is exactly what success looks like. Six meta rules make those failures visible:

RuleFlags
misnamed-suppressiona rule ID or a verb that does not exist
misplaced-suppressiona directive that can never take effect
blanket-suppressiona directive that names no rule
unexplained-suppressiona directive with no reason (off by default)
outdated-suppressiona directive that no longer silences anything
deprecated-suppressionone of the spellings arity shipped with

They read the directives of .R files only; a directive in a DESCRIPTION is honored but not linted.

Limits

  • One rule per directive. There is no comma-separated list: # arity-lint skip a, b reads the rule ID as a, and suppresses neither. Write a separate comment per rule. misnamed-suppression catches the mistake.
  • The formatter acts on whole statements. A # arity-format directive is honored at the top level and in a block body — the places where whole lines can be handed back untouched. Between two call arguments it is inert; misplaced-suppression says so. A lint directive has no such limit: it attaches by node.
  • A format region does not leave its block. An unclosed # arity-format off inside { ... } ends at the closing brace. A lint region is a byte range and runs on until on or end of file.
  • Syntax errors cannot be suppressed. A file that does not parse is reported before any rule runs, so # arity-lint skip syntax-error has no effect (and is itself flagged as a misnamed rule).
  • meta findings need the file-wide form. A finding about a directive is spanned on a comment, and a skip attaches past comments to the next piece of code — so it can never land on the directive above it. Use # arity-lint skip-file <meta-rule>: <reason>, or turn the rule off in configuration with [lint] ignore.
  • A bare # arity needs a verb. # arity is great is prose, not a typo’d directive, so it is left alone rather than reported. The prefixed forms are unambiguous and are checked.
  • Roxygen lines are not directives. #' arity-lint … is documentation content, not a directive.

Deprecated spellings

# arity-ignore <rule>: <reason> and # arity-ignore-file <rule>: <reason> are what the linter shipped with. They still work, and mean exactly # arity-lint skip and # arity-lint skip-file — but they are deprecated, and deprecated-suppression flags them with a safe autofix, so arity lint --fix migrates a codebase in one pass:

arity lint --fix --select deprecated-suppression .

Mixing the two (# arity-ignore skip <rule>) is an error, and misnamed-suppression reports it.

Turning a rule off entirely

For a rule you never want, arity.toml is the better tool than a comment in every file:

[lint]
ignore = ["unused-binding"]

See Configuration.