wsl

package module
v5.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 22, 2026 License: MIT Imports: 12 Imported by: 2

README

wsl - whitespace linter

GitHub Actions Coverage Status

wsl (whitespace linter) is a linter that wants you to use empty lines to separate grouping of different types to increase readability. There are also a few places where it encourages you to remove whitespaces which is at the start and the end of blocks or between assigning and error checking.

Checks and configuration

Each check can be disabled or enabled individually to the point where no checks can be run. The idea with this is to attract more users. Some checks have configuration that affect how they work but most of them can only be turned on or off.

Checks

This is an exhaustive list of all the checks that can be enabled or disabled and their default value. The names are the same as the Go AST type name for built-ins.

The base rule is that statements that has a block (e.g. for, range, switch, if etc) should always only be directly adjacent with a single variable and only if it's used in the expression in the block itself.

For more details and examples, see CHECKS.

✅ = enabled by default, ❌ = disabled by default

Built-ins and keywords
  • assign - Assignments should only be cuddled with other assignments, or increment/decrement
  • branch - 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-lines
  • decl - Declarations should never be cuddled
  • defer - Defer should only be cuddled with other defer, after error checking or with a single variable used on the line above
  • expr - Expressions are e.g. function calls or index expressions, they should only be cuddled with variables used on the line above
  • for - For loops should only be cuddled with a single variable used on the line above
  • go - Go should only be cuddled with other go or a single variable used on the line above
  • if - If should only be cuddled with a single variable used on the line above
  • inc-dec - Increment/decrement (++/--) has the same rules as assign
  • label - Labels should never be cuddled
  • range - Range should only be cuddled with a single variable used on the line above
  • return - Return should only be cuddled if the block is less than n lines where n is the value of branch-max-lines
  • select - Select should only be cuddled with a single variable used on the line above
  • send - Send should only be cuddled with a single variable used on the line above
  • switch - Switch should only be cuddled with a single variable used on the line above
  • type-switch - Type switch should only be cuddled with a single variable used on the line above
Specific wsl cases
  • after-block - Require empty line after block statements
  • append - Only allow re-assigning with append if the value being appended exist on the line above
  • assign-exclusive - Only allow cuddling either new variables or re-assigning of existing ones
  • assign-expr - Don't allow assignments to be cuddled with expressions, e.g. function calls
  • err - Error checking must follow immediately after the error variable is assigned
  • leading-whitespace - Disallow leading empty lines in blocks
  • trailing-whitespace - Disallow trailing empty lines in blocks
Configuration

Other than enabling or disabling specific checks some checks can be configured in more details.

  • allow-first-in-block - Allow cuddling a variable if it's used first in the immediate following block, even if the statement with the block doesn't use the variable (see Configuration for details)
  • allow-whole-block - Same as above, but allows cuddling if the variable is used anywhere in the following (or nested) block (see Configuration for details)
  • branch-max-lines - If a block contains more than this number of lines the branch statement (e.g. return, break, continue) need to be separated by a whitespace (default 2)
  • case-max-lines - If set to a non negative number, case blocks needs to end with a whitespace if exceeding this number (default 0, 0 = off, 1 = always)
  • include-generated - Include generated files when checking

Installation

# Latest release
go install github.com/bombsimon/wsl/v5/cmd/wsl@latest

# Main branch
go install github.com/bombsimon/wsl/v5/cmd/wsl@main

Usage

Note: This linter provides a fixer that can fix most issues with the --fix flag.

wsl uses the analysis package meaning it will operate on package level with the default analysis flags and way of working.

wsl --help
wsl [flags] </path/to/package/...>

wsl --default none --enable branch,return --fix ./...

wsl is also integrated in golangci-lint but since v5 which had a bunch of breaking changes it's renamed to wsl_v5. The previous version of wsl is deprecated and will be removed from golangci-lint eventually.

golangci-lint run --no-config --enable-only wsl_v5 --fix

This is an exhaustive, default, configuration for wsl_v5 in golangci-lint.

linters:
  default: none
  enable:
    - wsl_v5

  settings:
    wsl_v5:
      allow-first-in-block: true
      allow-whole-block: false
      branch-max-lines: 2
      case-max-lines: 0
      default: ~ # Can be `all`, `none`, `default` or empty
      enable:
        - append
        - assign
        - branch
        - decl
        - defer
        - err
        - expr
        - for
        - go
        - if
        - inc-dec
        - label
        - range
        - return
        - select
        - send
        - switch
        - type-switch
        - leading-whitespace
        - trailing-whitespace
      disable:
        - after-block
        - assign-exclusive
        - assign-expr

See also

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewAnalyzer

func NewAnalyzer(config *Configuration) *analysis.Analyzer

Types

type CheckSet

type CheckSet map[CheckType]struct{}

CheckSet is a set of checks to run.

func AllChecks

func AllChecks() CheckSet

func DefaultChecks

func DefaultChecks() CheckSet

func NewCheckSet

func NewCheckSet(
	defaultChecks string,
	enable []string,
	disable []string,
) (CheckSet, error)

func NoChecks

func NoChecks() CheckSet

func (CheckSet) Add

func (c CheckSet) Add(check CheckType)

func (CheckSet) Remove

func (c CheckSet) Remove(check CheckType)

type CheckType

type CheckType int

CheckType is a type that represents a checker to run.

const (
	CheckInvalid CheckType = iota
	CheckAssign
	CheckBranch
	CheckDecl
	CheckDefer
	CheckExpr
	CheckFor
	CheckGo
	CheckIf
	CheckIncDec
	CheckLabel
	CheckRange
	CheckReturn
	CheckSelect
	CheckSend
	CheckSwitch
	CheckTypeSwitch

	// CheckAfterBlock ensures there's a newline after each block.
	CheckAfterBlock
	// CheckAppend only allows assignments of `append` to be cuddled with other
	// assignments if it's a variable used in the append statement, e.g.
	//
	// a := 1
	// x = append(x, a)
	// .
	CheckAppend
	// CheckAssignExclusive only allows assignments of either new variables or
	// re-assignment of existing ones, e.g.
	//
	// a := 1
	// b := 2
	//
	// a = 1
	// b = 2
	// .
	CheckAssignExclusive
	// CheckAssignExpr will check so assignments are not cuddled with expression
	// nodes, e.g.
	//
	// t1.Fn1()
	//
	// x := t1.Fn2()
	// t1.Fn3()
	// .
	CheckAssignExpr
	// CheckErr force error checking to follow immediately after an error
	// variable is assigned, e.g.
	//
	// _, err := someFn()
	// if err != nil {
	//     panic(err)
	// }
	// .
	CheckErr
	CheckLeadingWhitespace
	CheckTrailingWhitespace

	//nolint:godoclint // No need to document
	// CheckTypes only used for reporting.
	CheckCaseTrailingNewline
)

Each checker is represented by a CheckType that is used to enable or disable the check. A check can either be of a specific built-in keyword or custom checks.

func CheckFromString

func CheckFromString(s string) (CheckType, error)

func (CheckType) String

func (c CheckType) String() string

type Configuration

type Configuration struct {
	IncludeGenerated  bool
	AllowFirstInBlock bool
	AllowWholeBlock   bool
	BranchMaxLines    int
	CaseMaxLines      int
	Checks            CheckSet
}

func NewConfig

func NewConfig() *Configuration

func NewWithChecks

func NewWithChecks(
	defaultChecks string,
	enable []string,
	disable []string,
) (*Configuration, error)

type Cursor

type Cursor struct {
	// contains filtered or unexported fields
}

Cursor holds a list of statements and a pointer to where in the list we are. Each block gets a new cursor and can be used to check previous or coming statements.

func NewCursor

func NewCursor(statements []ast.Stmt) *Cursor

NewCursor creates a new cursor with a given list of statements.

func (*Cursor) Len

func (c *Cursor) Len() int

func (*Cursor) Next

func (c *Cursor) Next() bool

func (*Cursor) NextNode

func (c *Cursor) NextNode() ast.Node

func (*Cursor) Nth

func (c *Cursor) Nth(n int) ast.Stmt

func (*Cursor) Previous

func (c *Cursor) Previous() bool

func (*Cursor) PreviousNode

func (c *Cursor) PreviousNode() ast.Node

func (*Cursor) Save

func (c *Cursor) Save() func()

func (*Cursor) SetChecker

func (c *Cursor) SetChecker(ct CheckType)

func (*Cursor) Stmt

func (c *Cursor) Stmt() ast.Stmt

type WSL

type WSL struct {
	// contains filtered or unexported fields
}

func New

func New(file *ast.File, pass *analysis.Pass, cfg *Configuration) *WSL

func (*WSL) Run

func (w *WSL) Run()

Run will run analysis on the file and pass passed to the constructor. It's typically only supposed to be used by analysis.Analyzer.

Directories

Path Synopsis
cmd
wsl command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL