diff --git a/pkg/core/command.go b/pkg/core/command.go index f5a7a23..0751092 100644 --- a/pkg/core/command.go +++ b/pkg/core/command.go @@ -184,7 +184,7 @@ func (c *Core) Command(args ...any) any { // Build parent chain — "deploy/to/homelab" creates "deploy" and "deploy/to" if missing parts := Split(path, "/") for i := len(parts) - 1; i > 0; i-- { - parentPath := StringJoin(parts[:i], "/") + parentPath := JoinPath(parts[:i]...) if _, exists := c.commands.commands[parentPath]; !exists { c.commands.commands[parentPath] = &Command{ name: parts[i-1], diff --git a/pkg/core/error.go b/pkg/core/error.go index 8cca2c6..925c444 100644 --- a/pkg/core/error.go +++ b/pkg/core/error.go @@ -138,9 +138,10 @@ func NewError(text string) error { return errors.New(text) } -// Join combines multiple errors into one. -// Wrapper around errors.Join for convenience. -func Join(errs ...error) error { +// ErrorJoin combines multiple errors into one. +// +// core.ErrorJoin(err1, err2, err3) +func ErrorJoin(errs ...error) error { return errors.Join(errs...) } diff --git a/pkg/core/string.go b/pkg/core/string.go index fb9c36d..af51948 100644 --- a/pkg/core/string.go +++ b/pkg/core/string.go @@ -60,11 +60,19 @@ func SplitN(s, sep string, n int) []string { return strings.SplitN(s, sep, n) } -// StringJoin joins segments with separator. +// Join joins parts with a separator, building via Concat. // -// core.StringJoin([]string{"a", "b", "c"}, "/") // "a/b/c" -func StringJoin(elems []string, sep string) string { - return strings.Join(elems, sep) +// core.Join("/", "deploy", "to", "homelab") // "deploy/to/homelab" +// core.Join(".", "cmd", "deploy", "description") // "cmd.deploy.description" +func Join(sep string, parts ...string) string { + if len(parts) == 0 { + return "" + } + result := parts[0] + for _, p := range parts[1:] { + result = Concat(result, sep, p) + } + return result } // Replace replaces all occurrences of old with new in s. diff --git a/pkg/core/utils.go b/pkg/core/utils.go index c89bc62..bf6edc7 100644 --- a/pkg/core/utils.go +++ b/pkg/core/utils.go @@ -26,7 +26,7 @@ func Print(w io.Writer, format string, args ...any) { // // core.JoinPath("deploy", "to", "homelab") // → "deploy/to/homelab" func JoinPath(segments ...string) string { - return StringJoin(segments, "/") + return Join("/", segments...) } // IsFlag returns true if the argument starts with a dash. diff --git a/tests/error_test.go b/tests/error_test.go index cb59635..de536d4 100644 --- a/tests/error_test.go +++ b/tests/error_test.go @@ -187,10 +187,10 @@ func TestNewError_Good(t *testing.T) { assert.Equal(t, "simple error", err.Error()) } -func TestJoin_Good(t *testing.T) { +func TestErrorJoin_Good(t *testing.T) { e1 := errors.New("first") e2 := errors.New("second") - joined := Join(e1, e2) + joined := ErrorJoin(e1, e2) assert.ErrorIs(t, joined, e1) assert.ErrorIs(t, joined, e2) } diff --git a/tests/string_test.go b/tests/string_test.go index 99b2ee0..c2e9f34 100644 --- a/tests/string_test.go +++ b/tests/string_test.go @@ -43,8 +43,8 @@ func TestSplitN_Good(t *testing.T) { assert.Equal(t, []string{"key", "value=extra"}, SplitN("key=value=extra", "=", 2)) } -func TestStringJoin_Good(t *testing.T) { - assert.Equal(t, "a/b/c", StringJoin([]string{"a", "b", "c"}, "/")) +func TestJoin_Good(t *testing.T) { + assert.Equal(t, "a/b/c", Join("/", "a", "b", "c")) } func TestReplace_Good(t *testing.T) {