refactor: migrate to Go 1.22 slices/cmp, update linters

Replace usage of golang.org/x/exp/constraints with Go 1.22 cmp/slices.
Update .golangci.yml to new v2 format and enable gofmt/goimports.
Refactor imports and type constraints across codebase for consistency.
This commit is contained in:
Ruidy 2025-09-01 23:08:10 -04:00
parent 39be9420c4
commit c53d46816f
No known key found for this signature in database
GPG key ID: 705C24D202990805
14 changed files with 83 additions and 69 deletions

View file

@ -1,42 +1,54 @@
skip-dirs-use-default: true
run:
timeout: 5m
version: "2"
linters:
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- errcheck
- errorlint
- exportloopref
- gocritic
- gocyclo
- gofmt
- goimports
- goprintffuncname
- gosimple
- gosec
- govet
- ineffassign
- misspell
- noctx
- nolintlint
- prealloc
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
fast: true
linters-settings:
goimports:
local-prefixes: github.com/rjNemo/underscore
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
settings:
depguard:
rules:
main:
list-mode: lax
files:
- $all
allow:
- $gostd
- github.com/rjNemo/underscore
- github.com/rjNemo/underscore/...
- github.com/stretchr/testify/...
- golang.org/x/exp/constraints
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

9
any.go
View file

@ -1,12 +1,9 @@
package underscore
import "slices"
// Any returns true if any of the values in the slice pass the predicate truth test.
// Short-circuits and stops traversing the slice if a true element is found.
func Any[T any](values []T, predicate func(T) bool) bool {
for _, v := range values {
if predicate(v) {
return true
}
}
return false
return slices.ContainsFunc(values, predicate)
}

View file

@ -9,7 +9,6 @@ import (
)
func TestDrop(t *testing.T) {
nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5}
want := []int{1, 9, 2, 3, 7, 4, 6, 5}

View file

@ -3,8 +3,9 @@ package underscore_test
import (
"testing"
u "github.com/rjNemo/underscore"
"github.com/stretchr/testify/assert"
u "github.com/rjNemo/underscore"
)
func TestFind(t *testing.T) {

View file

@ -3,8 +3,9 @@ package underscore_test
import (
"testing"
u "github.com/rjNemo/underscore"
"github.com/stretchr/testify/assert"
u "github.com/rjNemo/underscore"
)
func TestFlatmap(t *testing.T) {

View file

@ -3,9 +3,9 @@ package underscore_test
import (
"testing"
u "github.com/rjNemo/underscore"
"github.com/stretchr/testify/assert"
u "github.com/rjNemo/underscore"
)
func TestIntersection(t *testing.T) {

14
join.go
View file

@ -6,12 +6,12 @@ func Join[T, P any, S comparable](
left []T,
right []P,
leftSelector func(T) S,
rightSelector func(P) S) []Tuple[T, []P] {
var results = make([]Tuple[T, []P], 0, len(left))
rightSelector func(P) S,
) []Tuple[T, []P] {
results := make([]Tuple[T, []P], 0, len(left))
for _, l := range left {
var matches = Filter(right, func(r P) bool { return leftSelector(l) == rightSelector(r) })
var tuple = Tuple[T, []P]{Left: l, Right: matches}
matches := Filter(right, func(r P) bool { return leftSelector(l) == rightSelector(r) })
tuple := Tuple[T, []P]{Left: l, Right: matches}
results = append(results, tuple)
}
@ -28,8 +28,8 @@ func JoinProject[L, R, O any, S comparable](
right []R,
leftSelector func(L) S,
rightSelector func(R) S,
projection func(Tuple[L, []R]) O) (results []O) {
projection func(Tuple[L, []R]) O,
) (results []O) {
for _, x := range Join(left, right, leftSelector, rightSelector) {
results = append(results, projection(x))
}

View file

@ -3,23 +3,26 @@ package underscore_test
import (
"testing"
u "github.com/rjNemo/underscore"
"github.com/stretchr/testify/assert"
u "github.com/rjNemo/underscore"
)
var zero = u.Tuple[int, string]{Left: 0, Right: "Zero"}
var one = u.Tuple[int, string]{Left: 1, Right: "One"}
var two = u.Tuple[int, string]{Left: 2, Right: "Two"}
var three = u.Tuple[int, string]{Left: 3, Right: "Three"}
var (
zero = u.Tuple[int, string]{Left: 0, Right: "Zero"}
one = u.Tuple[int, string]{Left: 1, Right: "One"}
two = u.Tuple[int, string]{Left: 2, Right: "Two"}
three = u.Tuple[int, string]{Left: 3, Right: "Three"}
)
func Test_Join_Can_Join_Two_Slices_Together(t *testing.T) {
var left = []u.Tuple[int, string]{zero, one, two, three}
var right = []u.Tuple[int, string]{one, three, two, three, two, three}
left := []u.Tuple[int, string]{zero, one, two, three}
right := []u.Tuple[int, string]{one, three, two, three, two, three}
selector := func(x u.Tuple[int, string]) int { return x.Left }
var joined = u.Join(left, right, selector, selector)
var want = []u.Tuple[u.Tuple[int, string], []u.Tuple[int, string]]{
joined := u.Join(left, right, selector, selector)
want := []u.Tuple[u.Tuple[int, string], []u.Tuple[int, string]]{
{Left: zero, Right: nil},
{Left: one, Right: []u.Tuple[int, string]{one}},
{Left: two, Right: []u.Tuple[int, string]{two, two}},
@ -30,16 +33,16 @@ func Test_Join_Can_Join_Two_Slices_Together(t *testing.T) {
}
func Test_Join_Can_Join_and_Project_Two_Slices_Together(t *testing.T) {
var left = []u.Tuple[int, string]{zero, one, two, three}
var right = []u.Tuple[int, string]{one, three, two, three, two, three}
left := []u.Tuple[int, string]{zero, one, two, three}
right := []u.Tuple[int, string]{one, three, two, three, two, three}
selector := func(x u.Tuple[int, string]) int { return x.Left }
project := func(x u.Tuple[u.Tuple[int, string], []u.Tuple[int, string]]) int {
return len(x.Right) // projecting to a could of how many
}
var joined = u.JoinProject(left, right, selector, selector, project)
var want = []int{0, 1, 2, 3}
joined := u.JoinProject(left, right, selector, selector, project)
want := []int{0, 1, 2, 3}
assert.Equal(t, want, joined)
}

4
max.go
View file

@ -1,11 +1,11 @@
package underscore
import "golang.org/x/exp/constraints"
import "cmp"
// Max returns the maximum value in the slice.
// This function can currently only compare numbers reliably.
// This function uses operator <.
func Max[T constraints.Ordered](values []T) T {
func Max[T cmp.Ordered](values []T) T {
max := values[0]
for _, v := range values {
if v > max {

4
min.go
View file

@ -1,11 +1,11 @@
package underscore
import "golang.org/x/exp/constraints"
import "cmp"
// Min returns the minimum value in the slice.
// This function can currently only compare numbers reliably.
// This function uses operator <.
func Min[T constraints.Ordered](values []T) T {
func Min[T cmp.Ordered](values []T) T {
min := values[0]
for _, v := range values {
if v < min {

View file

@ -1,10 +1,10 @@
package underscore
import (
"golang.org/x/exp/constraints"
"cmp"
)
type Pipe[T constraints.Ordered] struct {
type Pipe[T cmp.Ordered] struct {
Value []T
}
@ -12,7 +12,7 @@ type Pipe[T constraints.Ordered] struct {
// call Value to retrieve the final value.
//
// Methods not returning a slice such as Reduce, All, Any, will break the Pipe and return Value instantly.
func NewPipe[T constraints.Ordered](value []T) Pipe[T] {
func NewPipe[T cmp.Ordered](value []T) Pipe[T] {
return Pipe[T]{Value: value}
}

View file

@ -1,20 +1,19 @@
package underscore
import (
"cmp"
"sort"
"golang.org/x/exp/constraints"
)
// SortSliceASC sorts any slice ASCENDING
func SortSliceASC[T constraints.Ordered](s []T) {
func SortSliceASC[T cmp.Ordered](s []T) {
sort.SliceStable(s, func(i, j int) bool {
return s[i] < s[j]
})
}
// SortSliceDESC sorts any slice DESCENDING
func SortSliceDESC[T constraints.Ordered](s []T) {
func SortSliceDESC[T cmp.Ordered](s []T) {
sort.SliceStable(s, func(i, j int) bool {
return s[i] > s[j]
})

8
sum.go
View file

@ -1,9 +1,11 @@
package underscore
import "golang.org/x/exp/constraints"
import (
"cmp"
)
// Sum adds elements of the slice.
func Sum[T constraints.Ordered](values []T) (sum T) {
func Sum[T cmp.Ordered](values []T) (sum T) {
for _, v := range values {
sum += v
}
@ -12,7 +14,7 @@ func Sum[T constraints.Ordered](values []T) (sum T) {
// SumMap sums the values you select from your struct, basically a sort cut instead of
// having to perform a [Map] followed by a [Sum].
func SumMap[T any, R constraints.Ordered](list []T, selector func(T) R) (sum R) {
func SumMap[T any, R cmp.Ordered](list []T, selector func(T) R) (sum R) {
for _, v := range list {
sum += selector(v)
}