Whitespace Linter - Forces you to use empty lines!

Overview

WSL - Whitespace Linter

forthebadge forthebadge

Build Status Coverage Status

WSL is a linter that enforces a very non scientific vision of how to make code more readable by enforcing empty lines at the right places.

I think too much code out there is to cuddly and a bit too warm for it's own good, making it harder for other people to read and understand. The linter will warn about newlines in and around blocks, in the beginning of files and other places in the code.

I know this linter is aggressive and a lot of projects I've tested it on have failed miserably. For this linter to be useful at all I want to be open to new ideas, configurations and discussions! Also note that some of the warnings might be bugs or unintentional false positives so I would love an issue to fix, discuss, change or make something configurable!

Installation

By go get (local installation)

You can do that by using:

go get -u github.com/bombsimon/wsl/v3/cmd/...

By golangci-lint (CI automation)

wsl is already integrated with golangci-lint. Please refer to the instructions there.

Usage

How to use depends on how you install wsl.

With local binary

The general command format for wsl is:

$ wsl [flags] <file1> [files...]
$ wsl [flags] </path/to/package/...>

# Examples

$ wsl ./main.go
$ wsl --no-test ./main.go
$ wsl --allow-cuddle-declarations ./main.go
$ wsl --no-test --allow-cuddle-declaration ./main.go
$ wsl --no-test --allow-trailing-comment ./myProject/...

The "..." wildcard is not used like other go commands but instead can only be to a relative or absolute path.

By default, the linter will run on ./... which means all go files in the current path and all subsequent paths, including test files. To disable linting test files, use -n or --no-test.

By golangci-lint (CI automation)

The recommended command is:

golangci-lint run --disable-all --enable wsl

For more information, please refer to golangci-lint's documentation.

Issues and configuration

The linter suppers a few ways to configure it to satisfy more than one kind of code style. These settings could be set either with flags or with YAML configuration if used via golangci-lint.

The supported configuration can be found in the documentation.

Below are the available checklist for any hit from wsl. If you do not see any, feel free to raise an issue.

Note: this linter doesn't take in consideration the issues that will be fixed with go fmt -s so ensure that the code is properly formatted before use.

Comments
  • Producing Linter Hit List

    Producing Linter Hit List

    Can we produce a "hit" list for explaining each hits and how to amend them? E.g. https://go-critic.github.io/overview

    I do not mind contribute back. I see a lot of good potential for this linter. =)

    EDIT: added mind

    opened by hollowaykeanho 21
  • Treat short declarations as declarations, not assignments (enhancement)

    Treat short declarations as declarations, not assignments (enhancement)

    I'd like to see a configuration option that would prevent short declarations from cuddling with anything but themselves, e.g.

    a := 1
    b := 2
    c := 3
    

    would work, but this should fail with the option enabled:

    a := 1
    b = 2
    c := 3
    

    and it would override many other cuddle rules automatically, also preventing these sorts of things:

    result, err := someFunc()
    if err != nil {
        fmt.Errorf( . . . )
    }
    

    I'm apparently an even bigger fan of whitespace than most 😄

    I'd be happy to work on a PR for this if you're open to it

    golangci-only 
    opened by mholiday-nyt 11
  • Add option to allow cuddling of var declaration and an expression that uses that variable's reference

    Add option to allow cuddling of var declaration and an expression that uses that variable's reference

    Sorry, I'm not sure how to describe it better, so here goes an example:

    var config Configuration
    conf.Load(&config)
    

    Another that comes to my mind:

    var config Configuration
    err = json.Unmarshal(body, &config)
    

    When there is an empty line in between these two statements seem really disconnected, while I consider them more or less a single statement, which isn't possible due Go "limitations".

    enhancement configurable golangci-only 
    opened by grongor 11
  • Add a flag to allow blocks to start with a comment

    Add a flag to allow blocks to start with a comment

    Hi!

    I see that there exists a allow-trailing-comment flag to allow blocks to end with a comment. We would like to have a similar flag that would allow blocks to start with comments.

    Here is our use case: we are working on an API and we use https://github.com/go-swagger/go-swagger to generate swagger documentation for our API. The syntax that all routes are defined for the doc is a comment starting with swagger: route and we usually place the handler description right at the start of our handler functions. This does trigger an error (we are using golangci-lint) and we would like to allow such comments instead of applying nolint: wsl to the whole handler function.

    opened by ajpetersons 10
  • Avoid false positive on empty labels

    Avoid false positive on empty labels

    Here's a solution to avoid false positives on empty labels. Labels end position always falls into the next line, regardless if it is empty or not. So for empty labels we simply could compensate the end position to avoid the false positive.

    This solves #92

    hacktoberfest 
    opened by Oppodelldog 9
  • Enforce cuddling err checks

    Enforce cuddling err checks

    For #65

    This is the first time I've worked with an AST, it was pretty awesome... Sometimes frustrating.. but awesome :P

    I set the new feature to Off by default.

    opened by JDiPierro 9
  • Enforce cuddling of error checks

    Enforce cuddling of error checks

    I'd love to be able to enforce that error checking is cuddled with the error assignment.

    For example, right now this doesn't trigger the linter:

    thing, err := db.GetThing()
    
    if err != nil {
      return err
    }
    

    But I'd like it to :)

    Thanks for the awesome linter!

    opened by JDiPierro 9
  • Allow trailing whitespace in blocks

    Allow trailing whitespace in blocks

    I see some options like --no-test -allow-declaration, but I'm uncertain what they do. I was looking for a way to disable some of the warnings about the: block should not start/end with a whitespace but I'm not sure if there is any such option

    enhancement configurable 
    opened by marcel-aan-zee 9
  • Issue using golangci-lint due to breaking change in v1

    Issue using golangci-lint due to breaking change in v1

    ... I think. I am mighty confused by go modules.

    In golangci-lint I am getting the following problem with their v1.21.0 tag:

    # github.com/golangci/golangci-lint/pkg/golinters
    /go/pkg/mod/github.com/golangci/[email protected]/pkg/golinters/wsl.go:43:6: unknown field 'AllowCaseTrailingWhitespace' in struct literal of type wsl.Configuration
    

    This build worked before on the same commit of my code. I noticed my builds are using different versions of WSL even though they grab the same version of golintci-lint.. The build had worked with wsl v1.2.5. However, now by build is get v1.2.7 of wsl.

    I suspect that go modules believes this is fine, because v1.2.7 should be backwards compatible to v1.2.5 if you are not using any new fields according to semantic versioning.

    However, when I git diff v1.2.6 v1.2.7 wsl.go I see that the exported configuration property AllowCaseTrailingWhitespace was removed/renamed to CaseForceTrailingWhitespaceLimit, which is a breaking a change:

    diff --git a/wsl.go b/wsl.go
    index 8a1f45b..ea8d4eb 100644
    --- a/wsl.go
    +++ b/wsl.go
    @@ -50,21 +50,9 @@ type Configuration struct {
            //  }
            AllowMultiLineAssignCuddle bool
     ...
    -       AllowCaseTrailingWhitespace bool
    +       // If the number of lines in a case block is equal to or lager than this
    +       // number, the case *must* end white a newline.
    +       CaseForceTrailingWhitespaceLimit int
    

    So I believe that for Go modules, that change would have need to have been v2.x.x and using a new a package folder with v2 at the end of the folder path (or module declaration) as per https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher

    opened by kylebrandt 8
  • Label at the end of a block is not a whitespace (nor comment)

    Label at the end of a block is not a whitespace (nor comment)

    Simplified version of my code:

    for _, x := range a {
    	if x == y {
    		goto SKIP // do not append
    	}
    
    	clean = append(clean, x)
    SKIP:
    }       // block should not end with a whitespace (or comment)
    

    I think wsl considers the label SKIP as a whitespace (or comment)...

    golangci-only 
    opened by olibre 7
  • Allow cuddling an assignment and a variable declaration

    Allow cuddling an assignment and a variable declaration

    var err error
    x := 12345
    

    I consider these two basically the same, and it's annoying that I have to split them. It makes the code look weird at some places. It's also weird when you realize that this is a perfectly fine way to do the same thing, just more verbose:

    var (
        err error
        x	= 12345
    )
    
    opened by grongor 6
  • Read closing bracket(s) as empty lines

    Read closing bracket(s) as empty lines

    I see this as just fine:

    	// ...
    	}
    }
    return
    
    	// ...
    
    	if err != nil
    		return nil, err
    	}
    	return // "bad"
    }
    

    return statements should not be cuddled if block has more than two lines

    opened by jtagcat 2
  • Drop overlapping support for v4

    Drop overlapping support for v4

    This linter has been in a maintenance like mode for a while and never got the fixer implemented. One of the reasons the fixer never got added was that I had issues getting some of the rules to work properly. Both grouping of const/var and also due to comments.

    Since this linter was created we now have gofumpt which addresses (and fixes!) a lot of the issues wsl reports on. There's also whitespace which only focuses on the empty lines in the start and end of a function. This linter too has support for suggested fixes. Lastly we have nlreturn which checks if your return statement has a preceding newline and can fix that.

    So, to actually make this linter more resonable to use (less opinionated and more focused) and also make it easier to finally add a fixer, which I think is really important to make it useful, I want to drop support for all overlapping features and point anyone in need of those to the other alternatives listed above. This would mean that a lot of the rules wsl warns about would be removed. I also think it may help to make the error reporting more generic (similar to how "File is not gofumpt-ed").

    I don't really have a plan for when to start on this but I'm writing this down to make it visible.

    opened by bombsimon 2
  • Require new lines after multiline function signature

    Require new lines after multiline function signature

    The rule for a block should not start with a whitespace should not apply to a multiline function signature. Instead a no cuddle rule should be in place instead.

    Example

    func (c *Client) GetSegment(
    	ctx context.Context,
    	uri *url.URL,
    	out io.Writer,
    ) (written int64, err error) {
    
    	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), http.NoBody)
    	if err != nil {
    		return 0, errors.Wrap(err, "failed to create request for getting segment")
    	}
    ...
    }
    
    opened by thaney071 0
  • go routine support wait group on previous line

    go routine support wait group on previous line

    There is often a need to add a value to a wait group and then calling a go routine that will mark done on that wait group as soon as it finishes. Such as

    wg.Add(1)
    go goRoutineWithDone()
    
    wg.Add(1)
    go goRoutineWithDone2()
    
    // waiting for all go routines to finish
    wg.Wait()
    

    Currently WSL sees this as a problem with needing a whitespace before the go call. I think this should be encouraged. Thoughts?

    help wanted hacktoberfest 
    opened by bmayfi3ld 3
  • Passed literal anonymous function to function is not checked.

    Passed literal anonymous function to function is not checked.

    Is it by design, or in anyway intended that the following cuddled statements inside the anonymous function are not hit by wsl ?

    package main
    
    import "fmt"
    
    func main() {
            fmt.Println(func () error {
                    foo:="bar"
                    fmt.Println("Just a statement")
                    if foo == "bar" {
                            return fmt.Errorf("bar")
                    }
                    return nil
            }())
    }
    
    
    opened by hansbogert 2
  • Consider `i++` as an assignment used in the iteration

    Consider `i++` as an assignment used in the iteration

    My original function:

    func sortedKeys(m map[string]interface{}) sort.StringSlice {
    	keys := make(sort.StringSlice, len(m))
    
        i := 0
    	for k := range m { // ranges should only be cuddled with assignments used in the iteration
    		keys[i] = k
    		i++
    	}
    
    	sort.Sort(keys)
    
    	return keys
    }
    

    I have found three possible fixes:

    1. Isolate i := 0 but this is the index of the for loop

      	func sortedKeys(m map[string]interface{}) sort.StringSlice {
      		keys := make(sort.StringSlice, len(m))
      
      	    i := 0
      
      		for k := range m {
      			keys[i] = k
      			i++
      		}
      
      		sort.Sort(keys)
      
      		return keys
      	}
      
    2. Inverse both assignments i := 0 and keys := .. but this is wired :-/

      	func sortedKeys(m map[string]interface{}) sort.StringSlice {
      	    i := 0
      
      		keys := make(sort.StringSlice, len(m))
      		for k := range m {
      			keys[i] = k
      			i++
      		}
      
      		sort.Sort(keys)
      
      		return keys
      	}
      
    3. Putting both assignments in one line, but this is the least readable :-(

      	func sortedKeys(m map[string]interface{}) sort.StringSlice {
      		i, keys := 0, make(sort.StringSlice, len(m))
      		for k := range m {
      			keys[i] = k
      			i++
      		}
      
      		sort.Sort(keys)
      
      		return keys
      	}
      

    I thing wsl should consider i++ as an assignment used in the iteration. @bombsimon What about your opinion?

    opened by olibre 4
Releases(v3.3.0)
  • v3.3.0(Apr 20, 2021)

    • Allow forcing short declarations to cuddle only with themselves
    • Allow a blank line after each comment group at the start of a block (not just between groups)
    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(Feb 16, 2021)

    • Better support for defer
    • Support for empty labels
    • Don't force multiline error cuddling
    • Support for AllowAssignAndAnythingCuddle
    • Typos and fixes
    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Apr 17, 2020)

  • v3.0.0(Mar 4, 2020)

  • v2.2.0(Mar 4, 2020)

  • v2.1.0(Feb 12, 2020)

  • v2.0.0(Nov 14, 2019)

    • Removed field AllowCaseTrailingWhitespace - By default we always allow trailing comments in case blocks
    • Added CaseForceTrailingWhitespaceLimit - Support to enforce adding a whitespace at the end of case blocks
    Source code(tar.gz)
    Source code(zip)
  • v1.2.8(Nov 14, 2019)

    Addresses the issue in #60 due to me failing following semver properly and making breaking changes. This (and v1.2.7) should be seen as bad releases and properly bumped releases will be available soon.

    Please use the existing issue for related discussions.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.7(Nov 10, 2019)

    • Always support trailing comments in case blocks
    • Support to mix trailing newlines in case blocks
    • Support to configure a limit for when to force trailing newlines in case blocks
    Source code(tar.gz)
    Source code(zip)
  • v1.2.6(Nov 6, 2019)

  • v1.2.5(Oct 14, 2019)

  • v1.2.4(Oct 13, 2019)

    • Add option to allow whitespace in the end of case blocks. Default: false. Example:
    switch {
    case 1:
        fmt.Println("one")
    
    case 2:
        fmt.Println("two")
    
    case 3:
        fmt.Println("three")
    }
    
    • Add option to allow cuddle var declarations. Default: false. Example:
    var foo bool
    var err error
    
    • Support best practices for closing body after HTTP request. (#31). Always true. Example:
    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    
    Source code(tar.gz)
    Source code(zip)
  • v1.2.3(Oct 10, 2019)

  • v1.2.2(Oct 9, 2019)

    Fix false-positives for slice- and index xpressions.

    • Fix bug where you couldn't cuddle SliceExpr (e.g. aSlice[start:end])
    • Fix bug where you couldn't cuddle IndexExpr (e.g. aMap[key] or aSlice[idx])
    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Oct 7, 2019)

    Changed name for Configuration (and flags)

    • CheckAppend -> StrictAppend
    • AllowAssignAndCallsCuddle -> AllowAssignAndCallCuddle
    • AllowMultiLineAssignmentCuddled -> AllowMultiLineAssignCuddle
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Oct 7, 2019)

    • Allow multiline assignments to be cuddled (default, may still be turned off)
    err := SomeFunc(
        "spanning over",
        "multiple lines",
    )
    if err != nil {
        panic("these belong together")
    }
    

    If AllowMultiLineAssignmentCuddled (-allow-multi-line-assignment) is set to false, this will yield an error.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Oct 6, 2019)

    • Functions on one line should not be considered
    • Fix better token.Pos() for whitespaces
    • Fix variable names
    • Add stringer
    • Support configuration (not yet exposed properly in cmd)
    • Support to whitelist any RHS
    • Support to whitelist any calls one line above
    • Support to cuddle any assignment and call if any of the RHS/LHS is used
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Oct 4, 2019)

  • v1.0.0(Oct 2, 2019)

Owner
Simon Sawert
Simon Sawert
A golang formatter that fixes long lines

golines Golines is a golang formatter that shortens long lines, in addition to all of the formatting fixes done by gofmt. Motivation The standard gola

Segment 530 Jan 6, 2023
A little fast cloc(Count Lines Of Code)

gocloc A little fast cloc(Count Lines Of Code), written in Go. Inspired by tokei. Installation $ go get -u github.com/hhatto/gocloc/cmd/gocloc Usage

Hideo Hattori 635 Jan 6, 2023
The most opinionated Go source code linter for code audit.

go-critic Highly extensible Go source code linter providing checks currently missing from other linters. There is never too much static code analysis.

null 1.5k Jan 6, 2023
[mirror] This is a linter for Go source code.

Golint is a linter for Go source code. Installation Golint requires a supported release of Go. go get -u golang.org/x/lint/golint To find out where g

Go 4k Dec 23, 2022
Staticcheck - The advanced Go linter

The advanced Go linter Staticcheck is a state of the art linter for the Go programming language. Using static analysis, it finds bugs and performance

Dominik Honnef 5.1k Jan 1, 2023
A Go linter to check that errors from external packages are wrapped

Wrapcheck A simple Go linter to check that errors from external packages are wrapped during return to help identify the error source during debugging.

Tom Arrell 204 Dec 27, 2022
A linter that handles struct tags.

Tagliatelle A linter that handles struct tags. Supported string casing: camel pascal kebab snake goCamel Respects Go's common initialisms (e.g. HttpRe

Ludovic Fernandez 20 Dec 15, 2022
The Golang linter that checks that there is no simultaneous return of `nil` error and an invalid value.

nilnil Checks that there is no simultaneous return of nil error and an invalid value. Installation & usage $ go install github.com/Antonboom/[email protected]

Anton Telyshev 13 Dec 14, 2022
Go linter which checks for dangerous unicode character sequences

bidichk - checks for dangerous unicode character sequences bidichk finds dangerous unicode character sequences in Go source files. Considered dangerou

Lucas Bremgartner 27 Oct 5, 2022
Go linter that checks types that are json encoded - reports unsupported types and unnecessary error checks

Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omited.

Lucas Bremgartner 28 Oct 7, 2022
Linter for PostgreSQL

Использование Проверить миграции: oh-my-pg-linter check ./migrations/*.sql Добавить директории с дополнительными проверками (переопределение - кто пос

Denis Kayumov 0 Nov 25, 2021
containedctx detects is a linter that detects struct contained context.Context field

containedctx containedctx detects is a linter that detects struct contained context.Context field Instruction go install github.com/sivchari/contained

sivchari 12 Oct 22, 2022
World's spookiest linter

nosleep The world's spookiest linter nosleep is a golang-ci compatible linter which checks for and fails if it detects usages of time.Sleep. Why did y

Elliot Williams 1 Oct 15, 2022
Go linter to analyze expression groups: require 'import' declaration groups

grouper — a Go linter to analyze expression groups Installation

null 0 Jun 19, 2022
funcresult — a Go linter to analyze function result parameters

Go linter to analyze function result parameters: require named / unnamed function result parameters

null 0 Jan 27, 2022
nostdglobals is a simple Go linter that checks for usages of global variables defined in the go standard library

nostdglobals is a simple Go linter that checks for usages of global variables defined in the go standard library

Nassos Kat 1 Feb 17, 2022
Goalinter-v1: Goa framework (version1) linter

goavl: Goa framework (ver1) linter goavlは、goa version1(フォーク版)のlinterです。開発目的は、goa

CHIKAMATSU Naohiro 1 Jul 28, 2022
Linter for Go's fmt.Errorf message

wrapmsg wrapmsg is Go code linter. this enforces fmt.Errorf's message when you wrap error. Example // OK ???? if err := pkg.Cause(); err != nil { re

Shinnosuke Sawada 12 Dec 27, 2022
misspelled word linter for Go comments, string literals and embedded files

gospel The gospel program lints Go source files for misspellings in comments, strings and embedded files. It uses hunspell to identify misspellings an

Dan Kortschak 30 Aug 6, 2022