Checks and configuration
April 28, 2026 ยท View on GitHub
Table of content
Checks
This document describes all the checks done by wsl with examples of what's not
allowed and what's allowed.
after-block
Block statements (if, for, switch, etc.) should be followed by a blank
line to visually separate them from subsequent code.
Important
An exception is made for defer statements that follow an if err != nil
block when the defer references a variable assigned on the line above the if
statement. This is a common pattern for resource cleanup.
| Bad | Good |
|---|---|
|
|
|
1 Missing whitespace after block 2 Missing whitespace after block |
after-decl
Declaration statements (var, const, type) should be followed by a blank
line. Consecutive declarations of the same kind are allowed to cuddle, only the
last one in a run needs the blank line.
| Bad | Good |
|---|---|
|
|
|
1 Missing whitespace after declaration 2 Missing whitespace after declaration |
after-defer
defer statements should be followed by a blank line. Consecutive defers
are allowed to cuddle, only the last one in a run needs the blank line.
| Bad | Good |
|---|---|
|
|
|
1 Missing whitespace after defer |
after-expr
Expression statements (e.g. function calls used for their side effects) should be followed by a blank line. Consecutive expression statements are allowed to cuddle, only the last one in a run needs the blank line.
Exception: an expression statement that is immediately followed by a
defer referencing the same variable is exempt (e.g. mu.Lock() /
defer mu.Unlock()), since these two statements form a single logical unit.
| Bad | Good |
|---|---|
|
|
|
1 Missing whitespace after expression |
after-go
go statements should be followed by a blank line. Consecutive go
statements are allowed to cuddle, only the last one in a run needs the blank
line.
| Bad | Good |
|---|---|
|
|
|
1 Missing whitespace after go |
assign
Assign (foo := bar) or re-assignments (foo = bar) should only be cuddled
with other assignments or increment/decrement.
| Bad | Good |
|---|---|
|
|
|
1 Not an assign statement above 2 Not an assign statement above |
branch
Note
Configurable via branch-max-lines. See Configuration for
details.
Branch statement (break, continue, fallthrough, goto) should only be
cuddled if the block is less than n lines where n is the value of
branch-max-statements.
| Bad | Good |
|---|---|
|
|
|
1 Block is more than 2 lines so should be a blank line above |
decl
Declarations should never be cuddled. When grouping multiple declarations together they should be declared in the same group with parenthesis into a single statement. The benefit of this is that it also aligns the declaration or assignment increasing readability.
Important
The fixer can't do smart adjustments if there are comments on the same line as the declaration.
| Bad | Good |
|---|---|
|
|
|
1 Multiple declarations should be grouped to one 2 Multiple declarations should be grouped to one 3 Declaration should always have a whitespace above 4 Declaration should always have a whitespace above |
defer
Deferring execution should only be used directly in the context of what's being deferred and there should only be one statement above.
| Bad | Good |
|---|---|
|
|
|
1 More than a single statement between 2 3 More than a single statement between |
expr
Expressions can be multiple things and a big part of them are not handled by
wsl. However all function calls are expressions which can be verified.
Important
This is one of the few rules with non-configurable exceptions. Given the
idiomatic way to acquire and release mutex locks and the fact that the sync
mutex from the standard library is so widely used, any call to Lock,
RWLock, or TryLock can be cuddled above any other statement(s) and
similarly Unlock and RWUnlock can be cuddled below any other
statement(s).
| Bad | Good |
|---|---|
|
|
|
1 |
for
Note
Configurable via allow-first-in-block to allow cuddling if the variable is
used first in the block (enabled by default).
Configurable via allow-whole-block to allow cuddling if the variable is used
anywhere in the following block (disabled by default).
Configurable via cuddle-max-statements to change the maximum number of
cuddled statements allowed (default 1).
See Configuration for details.
| Bad | Good |
|---|---|
|
|
|
1 2 More than one variable above statement 3 No variable in expression |
go
| Bad | Good |
|---|---|
|
|
|
1 2 3 |
if
Note
Configurable via allow-first-in-block to allow cuddling if the variable is
used first in the block (enabled by default).
Configurable via allow-whole-block to allow cuddling if the variable is used
anywhere in the following block (disabled by default).
Configurable via cuddle-max-statements to change the maximum number of
cuddled statements allowed (default 1).
See Configuration for details.
if statements are one of several block statements (a statement with a block)
that can have some form of expression or condition. To make block context more
readable, only one variable is allowed immediately above the if statement and
the variable must be used in the condition (unless configured otherwise).
| Bad | Good |
|---|---|
|
|
|
1 2 More than one variable above statement 3 4 No variable in expression 5 More than one variable above statement |
inc-dec
| Bad | Good |
|---|---|
|
|
|
1 Not an assign or inc/dec statement above 2 Not an assign or inc/dec statement above |
label
Labels should never be cuddled. Labels in itself is often a symptom of big scope and split context and because of that should always have an empty line above.
| Bad | Good |
|---|---|
|
|
|
1 Labels should always have a whitespabe above |
range
Note
Configurable via allow-first-in-block to allow cuddling if the variable is
used first in the block (enabled by default).
Configurable via allow-whole-block to allow cuddling if the variable is used
anywhere in the following block (disabled by default).
Configurable via cuddle-max-statements to change the maximum number of
cuddled statements allowed (default 1).
See Configuration for details.
| Bad | Good |
|---|---|
|
|
|
1 2 3 More than one variable above statement |
return
Note
Configurable via branch-max-lines. See Configuration for
details.
Return statements is an important statement that is easiy to miss in larger code
blocks. To better visualize the return statement and that the method is
returning it should always be followed by a blank line unless the scope is as
small as branch-max-lines.
| Bad | Good |
|---|---|
|
|
|
1 Block is more than 2 lines so should be a blank line above |
select
Identifiers used in case arms of select statements are allowed to be cuddled.
Note
Configurable via allow-first-in-block to allow cuddling if the variable is
used first in the block (enabled by default).
Configurable via allow-whole-block to allow cuddling if the variable is used
anywhere in the following block (disabled by default).
Configurable via cuddle-max-statements to change the maximum number of
cuddled statements allowed (default 1).
See Configuration for details.
| Bad | Good |
|---|---|
|
|
|
1 |
send
Send statements should only be cuddled with a single variable that is used on the line above.
| Bad | Good |
|---|---|
|
|
|
1 2 |
switch
In addition to checking the switch condition, switch statements also checks identifiers in all case arms. If a variable is used in one or more of the case arms it's allowed to be cuddled.
Note
Configurable via allow-first-in-block to allow cuddling if the variable is
used first in the block (enabled by default).
Configurable via allow-whole-block to allow cuddling if the variable is used
anywhere in the following block (disabled by default).
Configurable via cuddle-max-statements to change the maximum number of
cuddled statements allowed (default 1).
See Configuration for details.
| Bad | Good |
|---|---|
|
|
|
1 2 More than one variable above statement |
type-switch
Note
Configurable via allow-first-in-block to allow cuddling if the variable is
used first in the block (enabled by default).
Configurable via allow-whole-block to allow cuddling if the variable is used
anywhere in the following block (disabled by default).
Configurable via cuddle-max-statements to change the maximum number of
cuddled statements allowed (default 1).
See Configuration for details.
| Bad | Good |
|---|---|
|
|
|
1 |
append
Append enables strict append checking where assignments that are
re-assignments with append (e.g. x = append(x, y)) is only allowed to be
cuddled with other assignments if the append uses the variable on the line
above.
| Bad | Good |
|---|---|
|
|
|
1 2 |
assign-exclusive
Assign exclusive does not allow mixing new assignments (:=) with
re-assignments (=).
| Bad | Good |
|---|---|
|
|
|
1 2 3 |
assign-expr
Assignments are allowed to be cuddled with expressions, primarily to support
mixing assignments and function calls which can often make sense in shorter
flows. By enabling this check wsl will ensure assignments are not cuddled with
expressions.
| Bad | Good |
|---|---|
|
|
|
1 Line above is not an assignment |
err
| Bad | Good |
|---|---|
|
|
|
1 Whitespace between error assignment and error checking |
cuddle-group
Treats the cuddled chain above a trigger statement (if, for, switch,
etc., go, defer, send) as a single unit. The chain stays cuddled with
the trigger only when every cuddled statement shares a variable with the
trigger and the number of sharing statements is within
cuddle-max-statements.
Without this check, the same violations are reported on a cuddled statement inside the chain, splitting the group between variables.
| Bad | Good |
|---|---|
|
|
|
1 Two cuddled statements share a variable with 2 Only one cuddled statement shares with |
leading-whitespace
| Bad | Good |
|---|---|
|
|
trailing-whitespace
| Bad | Good |
|---|---|
|
|
Configuration
One shared logic across different checks is the logic around statements
containing a block, i.e. a statement with a following {} (e.g. if, for,
switch etc).
wsl only allows one statement immediately above and that statement must also
be referenced in the expression in the statement with the block. E.g.
someVariable := true
if someVariable {
// Here `someVariable` used in the `if` expression is the only variable
// immediately above the statement.
}
This can be configured to be more "laxed" by also allowing a single statement immediately above if it's used either first in the following block or anywhere inside the following block.
allow-first-in-block
By setting this to true (default), the variable doesn't have to be used in the expression itself but is also allowed if it's the first statement in the block body.
someVariable := 1
if anotherVariable {
someVariable++
}
allow-whole-block
This is similar to allow-first-in-block but now allows the lack of whitespace
if it's used anywhere in the following block.
someVariable := 1
if anotherVariable {
someFn(yetAnotherVariable)
if stillNotSomeVariable {
someVariable++
}
}
branch-max-lines
When set to a value greater than 0, return, break, continue, fallthrough
and goto statements that appear in a block with more than this many lines will
require a blank line above them. The default is 2, meaning blocks of 3 or more
lines require a blank line above the branch statement.
| Bad | Good |
|---|---|
|
|
|
1 Block has more than 2 lines, blank line required above |
case-max-lines
When set to a value greater than 0, case clauses in switch and select
statements that exceed this number of lines will require a blank line before the
next case. Setting this to 1 will make it always enabled.
Comments between case clauses are handled based on their indentation:
- Indented comments (deeper than
case) are treated as trailing comments that belong to the current case body. - Left-aligned comments (at the same level as
case) are treated as leading comments that belong to the next case.
The blank line is placed at the transition point between trailing and leading content. This means:
- If all comments are indented, the blank line goes before the next
case. - If all comments are left-aligned, the blank line goes after the last statement.
- If comments transition from indented to left-aligned, the blank line goes at the transition point.
Additionally, left-aligned comments must be flush against the next case - no
blank line is allowed between them. This ensures consistent formatting where
leading comments are visually attached to the case they describe.
| Bad | Good |
|---|---|
|
|
|
1 Missing blank line after case body 2 Missing blank line after trailing comment 3 Missing blank line at transition (after trailing comment) 4 Unnecessary blank line before case (after leading comment) |
cuddle-max-statements
Controls the maximum number of consecutive statements that may be cuddled
(appear without a blank line) immediately above block statements (if, for,
switch, etc.), go, defer, and send. The default is 1. Every cuddled
statement must share at least one variable with the following block (respects
allow-first-in-block and allow-whole-block).
Setting it to 0 disallows any cuddling, the trigger always requires a blank
line above it, even when the variable on the line above is used by the block.
The recommended way to allow any number of statements is to set a really high
number such as 9999.
| Bad | Good |
|---|---|
|
|
|
1 Two statements cuddled above 2 Three statements cuddled above 3 One statement cuddled above |