diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a79c221..b3819c0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,3 +30,7 @@ jobs: uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} + + - name: Golangci-lint + uses: golangci/golangci-lint-action@v6.0.1 + diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..55c9e8c --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,156 @@ +--- +# golangci-lint configuration file made by @ccoVeille +# Source: https://github.com/ccoVeille/golangci-lint-config-examples/ +# Author: @ccoVeille +# License: MIT +# Variant: 03-safe +# Version: v1.0.0 +# +linters: + # some linters are enabled by default + # https://golangci-lint.run/usage/linters/ + # + # enable some extra linters + enable: + # Errcheck is a program for checking for unchecked errors in Go code. + - errcheck + + # Linter for Go source code that specializes in simplifying code. + - gosimple + + # Vet examines Go source code and reports suspicious constructs. + - govet + + # Detects when assignments to existing variables are not used. + - ineffassign + + # It's a set of rules from staticcheck. See https://staticcheck.io/ + - staticcheck + + # Fast, configurable, extensible, flexible, and beautiful linter for Go. + # Drop-in replacement of golint. + - revive + + # check imports order and makes it always deterministic. + - gci + + # make sure to use t.Helper() when needed + - thelper + + # mirror suggests rewrites to avoid unnecessary []byte/string conversion + - mirror + + # detect the possibility to use variables/constants from the Go standard library. + - usestdlibvars + + # Finds commonly misspelled English words. + - misspell + + # Checks for duplicate words in the source code. + - dupword + +linters-settings: + gci: # define the section orders for imports + sections: + # Standard section: captures all standard packages. + - standard + # Default section: catchall that is not standard or custom + - default + # linters that related to local tool, so they should be separated + - localmodule + + revive: + rules: + # these are the default revive rules + # you can remove the whole "rules" node if you want + # BUT + # ! /!\ they all need to be present when you want to add more rules than the default ones + # otherwise, you won't have the default rules, but only the ones you define in the "rules" node + + # Blank import should be only in a main or test package, or have a comment justifying it. + - name: blank-imports + + # context.Context() should be the first parameter of a function when provided as argument. + - name: context-as-argument + arguments: + - allowTypesBefore: "*testing.T" + + # Basic types should not be used as a key in `context.WithValue` + - name: context-keys-type + + # Importing with `.` makes the programs much harder to understand + - name: dot-imports + + # Empty blocks make code less readable and could be a symptom of a bug or unfinished refactoring. + - name: empty-block + + # for better readability, variables of type `error` must be named with the prefix `err`. + - name: error-naming + + # for better readability, the errors should be last in the list of returned values by a function. + - name: error-return + + # for better readability, error messages should not be capitalized or end with punctuation or a newline. + - name: error-strings + + # report when replacing `errors.New(fmt.Sprintf())` with `fmt.Errorf()` is possible + - name: errorf + + # incrementing an integer variable by 1 is recommended to be done using the `++` operator + - name: increment-decrement + + # highlights redundant else-blocks that can be eliminated from the code + - name: indent-error-flow + + # This rule suggests a shorter way of writing ranges that do not use the second value. + - name: range + + # receiver names in a method should reflect the struct name (p for Person, for example) + - name: receiver-naming + + # redefining built in names (true, false, append, make) can lead to bugs very difficult to detect. + - name: redefines-builtin-id + + # redundant else-blocks that can be eliminated from the code. + - name: superfluous-else + + # prevent confusing name for variables when using `time` package + - name: time-naming + + # warns when an exported function or method returns a value of an un-exported type. + - name: unexported-return + + # spots and proposes to remove unreachable code. also helps to spot errors + - name: unreachable-code + + # Functions or methods with unused parameters can be a symptom of an unfinished refactoring or a bug. + - name: unused-parameter + + # report when a variable declaration can be simplified + - name: var-declaration + + # warns when initialism, variable or package naming conventions are not followed. + - name: var-naming + + dupword: + # Keywords used to ignore detection. + # Default: [] + ignore: + # - "blah" # this will accept "blah blah …" as a valid duplicate word + + misspell: + # Correct spellings using locale preferences for US or UK. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + # Default ("") is to use a neutral variety of English. + locale: US + + # List of words to ignore + # among the one defined in https://github.com/golangci/misspell/blob/master/words.go + ignore-words: + # - valor + # - and + + # Extra word corrections. + extra-words: + # - typo: "whattever" + # correction: "whatever" diff --git a/dumper.go b/dumper.go index 68c8d10..e768fa9 100644 --- a/dumper.go +++ b/dumper.go @@ -14,6 +14,7 @@ type Style interface { Apply(string) string } +//nolint:revive // this name is uncommon, but why not func __(s Style, v string) string { if s == nil { return v @@ -178,8 +179,8 @@ func (d *Dumper) init() { } } -func (d *Dumper) dump(val reflect.Value, ignore_depth ...bool) { - if len(ignore_depth) <= 0 || !ignore_depth[0] { +func (d *Dumper) dump(val reflect.Value, ignoreDepth ...bool) { + if len(ignoreDepth) <= 0 || !ignoreDepth[0] { d.indent() } @@ -198,8 +199,8 @@ func (d *Dumper) dump(val reflect.Value, ignore_depth ...bool) { d.buf.WriteString(__(d.Theme.Func, val.Type().String())) case reflect.Chan: d.buf.WriteString(__(d.Theme.Chan, val.Type().String())) - if cap := val.Cap(); cap > 0 { - d.buf.WriteString(__(d.Theme.Chan, fmt.Sprintf("<%d>", cap))) + if vCap := val.Cap(); vCap > 0 { + d.buf.WriteString(__(d.Theme.Chan, fmt.Sprintf("<%d>", vCap))) } case reflect.Struct: d.dumpStruct(val) @@ -324,7 +325,7 @@ func (d *Dumper) dumpStruct(v reflect.Value) { d.buf.WriteString(__(d.Theme.Braces, " {")) d.buf.WriteString(__(d.Theme.PointerTag, tag)) - var has_fields bool + var hasFields bool d.depth++ for i := 0; i < v.NumField(); i++ { @@ -333,7 +334,7 @@ func (d *Dumper) dumpStruct(v reflect.Value) { continue } - has_fields = true + hasFields = true d.buf.WriteString("\n") d.indent() @@ -345,7 +346,7 @@ func (d *Dumper) dumpStruct(v reflect.Value) { } d.depth-- - if has_fields { + if hasFields { d.buf.WriteString("\n") d.indent() } diff --git a/dumper_test.go b/dumper_test.go index 6d3f7e4..12b9270 100644 --- a/dumper_test.go +++ b/dumper_test.go @@ -11,7 +11,6 @@ import ( ) func TestCanDumpPrimitives(t *testing.T) { - type IntType int type Int8Type int8 type Int16Type int16 @@ -344,7 +343,6 @@ func TestCanDumpPrimitives(t *testing.T) { } func TestCanDumpStructs(t *testing.T) { - type Number int type Child1 struct { @@ -378,8 +376,8 @@ func TestCanDumpStructs(t *testing.T) { Ref *Node } - var num = 123 - var numaddr = &num + num := 123 + numaddr := &num node := Node{ Inline: struct { Field1 struct { @@ -429,7 +427,6 @@ func TestCanDumpStructs(t *testing.T) { } func TestCannotDumpPrivateStructsWhenHidingOptionIsEnabled(t *testing.T) { - type number int type child1 struct { @@ -515,7 +512,6 @@ func TestCannotDumpPrivateStructsWhenHidingOptionIsEnabled(t *testing.T) { } func TestCanDumpPrivateStructs(t *testing.T) { - type number int type child1 struct { @@ -597,12 +593,11 @@ func TestCanDumpPrivateStructs(t *testing.T) { } func TestCanDumpSlices(t *testing.T) { - type Slice []any - var foo = "foo" - var bar = "bar" - var baz = "baz" + foo := "foo" + bar := "bar" + baz := "baz" s := Slice{ 1, @@ -631,11 +626,10 @@ func TestCanDumpSlices(t *testing.T) { } func TestCanDumpMaps(t *testing.T) { - type SomeMap map[*SomeMap]*SomeMap - var sm = &SomeMap{} + sm := &SomeMap{} - var m = map[any]any{12: 34} + m := map[any]any{12: 34} maps := []any{ make(map[string]string), map[any]int{ @@ -656,7 +650,6 @@ func TestCanDumpMaps(t *testing.T) { } func TestCanCustomizeIndentation(t *testing.T) { - type User struct { Name string Age int @@ -676,7 +669,7 @@ func TestCanCustomizeIndentation(t *testing.T) { } me.bestFriend = &me - var d = godump.Dumper{ + d := godump.Dumper{ Indentation: " ", } result := d.Sprint(me) @@ -693,7 +686,6 @@ func (c CSSColor) Apply(s string) string { } func TestCanCustomizeTheme(t *testing.T) { - type User struct { Name string Age int @@ -792,12 +784,11 @@ func TestDumperPrint_Sprint_And_Fprint(t *testing.T) { type X int -func (X) Write(p []byte) (n int, err error) { +func (X) Write(_ []byte) (n int, err error) { return 0, fmt.Errorf("foobar") } func TestDumperFprintReturnsAWriteErrorIfEncountered(t *testing.T) { - var d godump.Dumper var x X @@ -813,29 +804,28 @@ func TestDumperFprintReturnsAWriteErrorIfEncountered(t *testing.T) { } else if err.Error() != "dumper error: encountered unexpected write error, foobar" { t.Fatalf("unexpected error by Dumper.Fprintln : `%s`", err.Error()) } - } -func checkFromFeed(t *testing.T, result []byte, feed_path string) { +func checkFromFeed(t *testing.T, result []byte, feedPath string) { t.Helper() - expectedOutput, err := os.ReadFile(feed_path) + expectedOutput, err := os.ReadFile(feedPath) if err != nil { t.Fatal(err) } - r_lines := bytes.Split(result, []byte("\n")) - e_lines := bytes.Split(expectedOutput, []byte("\n")) + resultLines := bytes.Split(result, []byte("\n")) + expectedLines := bytes.Split(expectedOutput, []byte("\n")) - if len(r_lines) != len(e_lines) { - t.Fatalf("expected %d lines, got %d", len(e_lines), len(r_lines)) + if len(resultLines) != len(expectedLines) { + t.Fatalf("expected %d lines, got %d", len(expectedLines), len(resultLines)) } - for i, line := range e_lines { - if string(line) != string(r_lines[i]) { + for i, line := range expectedLines { + if string(line) != string(resultLines[i]) { t.Fatalf(`mismatch at line %d: --- "%s" (%d) -+++ "%s" (%d)`, i+1, line, len(line), r_lines[i], len(r_lines[i])) ++++ "%s" (%d)`, i+1, line, len(line), resultLines[i], len(resultLines[i])) } } }